Logo Search packages:      
Sourcecode: vertex version File versions

guiutils.c

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

#include <gtk/gtk.h>
#include <gtk/gtkinvisible.h>
#include <gdk/gdkkeysyms.h>
#ifdef __MSW__
# include <gdk/gdkwin32.h>
#else
# include <gdk/gdkx.h>
#endif

#if defined(__SOLARIS__) || defined(__hpux)
# include "../include/os.h"
#endif

#include "guiutils.h"


#include "images/icon_browse_20x20.xpm"


/* Invisible GtkInvisible toplevel widget for grabbing. This is used to
 * block input for GUIBlockInput() on a given window.
 */
static GtkWidget *gui_invisible_blocker_widget = NULL;
static gint gui_block_input_level = 0;


/* GUI DND local callback data structure, this is used for passing
 * data for local DND callbacks such as GUIDNDDragMotionCB().
 */
typedef struct {

      GdkDragAction     default_action_same,    /* Action to use if same widget. */
                  default_action;         /* Action for all other cases. */

} gui_dnd_cb_struct;


/* DND icon widget, initialized on first call to GUIDNDSetDragIcon()
 * and used in GUIDNDDragBeginCB() and GUIDNDDragReceivedCB().
 */
typedef struct {

      GtkWidget *toplevel, *icon_pm;

      /* Hot spot and size. */
      gint x, y, width, height;

} gui_dnd_icon_struct;
static gui_dnd_icon_struct gui_dnd_icon;


/* Stored as object user data on any button or toggle button that we 
 * create. This is used for mapping or unmapping child widgets packed
 * into these buttons.
 */
typedef struct {

      GtkWidget   *button,
                  *main_box;

      GtkWidget   *label_normal,
                  *label_highlight,
                  *label_pressed;         /* Or toggled. */

      GtkWidget   *pixmap_normal,
                  *pixmap_highlight,
                  *pixmap_pressed;  /* Or toggled. */

} gui_button_data_struct;


/* Menu item record structure. */
typedef struct {

      GtkWidget   *menu_item,
                  *label_normal,
                  *pixmap_normal;

} gui_menu_item_data_struct;


/* Main tooltips group, note that this will never get deallocated but
 * isn't a big problem since we only need one and it'll be destroyed
 * when the application exits.
 */
static GtkTooltips *gui_tooltips = NULL;
/* Global record marking if tooltips are enabled or disabled. */
static gboolean gui_tooltips_state;


static gchar *GUIGetKeyName(gint key);
static void GUIDNDDragBeginCB(
      GtkWidget *widget, GdkDragContext *dc, gpointer data
);
static gboolean GUIDNDDragMotionCB(
      GtkWidget *widget, GdkDragContext *dc,
      gint x, gint y, guint t,
      gpointer data
);
static gboolean GUIDNDDragDropCB(
      GtkWidget *widget, GdkDragContext *dc,
        gint x, gint y, guint t,
        gpointer data
);
static void GUIDNDDragReceivedCB(
        GtkWidget *widget, GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
);
static void GUIDNDDragEndCB(
      GtkWidget *widget, GdkDragContext *dc,
      gpointer data
);
static void GUIButtonDestroyCB(GtkObject *object, gpointer data);

static gint GUIBannerExposeCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
);
static void GUIBannerDestroyCB(GtkObject *object, gpointer data);
static void GUIComboActivateCB(GtkWidget *widget, gpointer data);
static void GUIComboChangedCB(GtkWidget *widget, gpointer data);
static void GUIComboDestroyCB(GtkObject *object, gpointer data);
static void GUIMenuActivateCB(gpointer data);
static void GUIMenuDestroyCB(GtkObject *object, gpointer data);
static void GUIPullOutDestroyCB(GtkObject *object, gpointer data);
static void GUIPullOutDrawHandleDrawCB(
      GtkWidget *widget, GdkRectangle *area, gpointer data
);
static gint GUIPullOutDrawHandleCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
);
static gint GUIPullOutPullOutBtnCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
);
static gint GUIPullOutCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data);


void GUIResizeBuffer(
      gint bpp,
      const gpointer src,
      gint src_width, gint src_height, gint src_bpl,
      gpointer tar,
      gint tar_width, gint tar_height, gint tar_bpl
);
void GUIStyleDeallocUnref(GtkStyle *style);
void GUIRCStyleDeallocUnref(GtkRcStyle *rcstyle);

guint32 gdk_parse_geometry(
      const gchar *s,
      gint *x, gint *y, gint *width, gint *height
);
int GUICListGetCellGeometry(
      void *w, int column, int row,
      int *x, int *y, int *width, int *height
);
void GUIGetWindowRootPosition(
      void *w, int *x, int *y
);

GdkBitmap *GUICreateBitmapFromDataRGBA(
      gint width, gint height, gint bpl,
      const guint8 *rgba, guint8 threshold,
      GdkWindow *window
);
void *GUICreateCursorFromData(
      u_int8_t **cursor_data,
      double hot_x, double hot_y,
      int width, int height
);
void *GUICreateMenuItemIcon(u_int8_t **icon);
void GUISetWMIcon(GdkWindow *w, u_int8_t **icon);

void gtk_window_minimize(GtkWindow *window);

static void GUICreateGlobalTooltips(void);
void GUISetWidgetTip(GtkWidget *w, const gchar *tip);
void GUIShowTipsNow(GtkWidget *w);
void GUISetGlobalTipsState(gbool state);

void GUIButtonChangeLayout(void *button, int show_pixmap, int show_label);
void GUIButtonPixmapUpdate(void *button, u_int8_t **icon, const char *label);
void *GUIButtonPixmapLabelHV(
      u_int8_t **icon, const char *label, void **label_rtn,
        int orient
);
void *GUIButtonPixmapLabelH(
        u_int8_t **icon, const char *label, void **label_rtn
);
void *GUIButtonPixmapLabelV(
        u_int8_t **icon, const char *label, void **label_rtn
);
void *GUIButtonPixmap(u_int8_t **icon);

void *GUIToggleButtonPixmapLabelHV(
        u_int8_t **icon, const char *label, void **label_rtn,
        int orient   
);
void *GUIToggleButtonPixmapLabelH(
        u_int8_t **icon, const char *label, void **label_rtn
);
void *GUIToggleButtonPixmapLabelV(
        u_int8_t **icon, const char *label, void **label_rtn
);
void *GUIToggleButtonPixmap(u_int8_t **icon);

void *GUIPromptBarOrBrowse(
        u_int8_t **icon, const char *label,
        void **label_rtn, void **entry_rtn, void **browse_rtn
);
void *GUIPromptBarWithBrowse(
        u_int8_t **icon, const char *label,
        void **label_rtn, void **entry_rtn, void **browse_rtn,
        void *browse_client_data, void (*browse_cb)(void *, void *)
);
void *GUIPromptBar(
        u_int8_t **icon, const char *label,
        void **label_rtn, void **entry_rtn
);

void GUIDNDSetSrc(
      void *w, const void *drag_type, int ndrag_types,
      unsigned int actions, unsigned int buttons,
      void (*begin_cb)(GtkWidget *, GdkDragContext *, gpointer),
      void (*request_data_cb)(GtkWidget *, GdkDragContext *,
            GtkSelectionData *, guint, guint, gpointer),
      void (*delete_data_cb)(GtkWidget *, GdkDragContext *, gpointer),
      void (*end_cb)(GtkWidget *, GdkDragContext *, gpointer),
      gpointer client_data
);
void GUIDNDSetTar(
        void *w, const void *drag_type, int ndrag_types,
        unsigned int actions, unsigned int default_action_same,
      unsigned int default_action,
      void (*recieved_data_cb)(GtkWidget *, GdkDragContext *,
            gint, gint, GtkSelectionData *, guint, guint,
            gpointer
      ),
      gpointer client_data
);
void GUIDNDSetDragIcon(
        GdkPixmap *pixmap, GdkBitmap *mask, gint hot_x, gint hot_y
);

GtkWidget *GUIBannerCreate(
      const gchar *label, const gchar *font_name,
      GdkColor color_fg, GdkColor color_bg,
      gint align,       /* One of GTK_JUSTIFY_*. */
      gbool expand
);
void *GUIComboCreate(
        const char *label,
        const char *text,       /* Initial text. */
        void *list,             /* Initial glist of items for combo list. */
        int max_items,          /* Maximum items allowed. */
        void **combo_rtn,     /* Combo widget return. */
        void *client_data,
        void (*func_cb)(GtkWidget *w, void *),
        void (*list_change_cb)(GtkWidget *, void *, GList *)
);
void GUIComboActivateValue(void *w, const char *value);
void GUIComboAddItem(void *w, const char *value);
void *GUIComboGetList(void *w);
void GUIComboSetList(void *w, void *list);
void GUIComboClearAll(void *w);

void *GUIMenuBarCreate(void **accel_group);
void *GUIMenuCreateTearOff(void);
void *GUIMenuCreate(void);
void *GUIMenuItemCreate(
        void *menu, int type, /* One of GUI_MENU_ITEM_TYPE_*. */
        void *accel_group,
        u_int8_t **icon, const char *label,
        int accel_key, unsigned int accel_mods,
        void **functional_widget_rtn,
        void *client_data,
        void (*func_cb)(GtkWidget *w, void *)
);
void GUISetMenuItemCrossingCB(
        void *w,
        int (*enter_cb)(void *, void *, void *),
        void *enter_client_data,
        int (*leave_cb)(void *, void *, void *),
        void *leave_client_data
);
void *GUIMenuAddToMenuBar(
        void *menu_bar, void *menu,
        const char *menu_bar_item_label,
        int align /* One of GUI_MENU_BAR_ALIGN_*. */
);
void GUIMenuItemSetLabel(void *menu_item, const char *label);
void GUIMenuItemSetPixmap(void *menu_item, u_int8_t **icon_data);
void *GUIMenuAddToMenuBarPixmapH(
        void *menu_bar, void *menu,
        const char *menu_bar_item_label, const u_int8_t **icon,
        int align       /* One of GUI_MENU_BAR_ALIGN_*. */
);

void *GUIPullOutCreateH(
      void *parent_box,
        int homogeneous, int spacing,           /* Of client vbox. */
        int expand, int fill, int padding,      /* Of holder hbox. */
      int toplevel_width, int toplevel_height,
        void *pull_out_client_data,
        void (*pull_out_cb)(void *, void *),
        void *push_in_client_data,
        void (*push_in_cb)(void *, void *)
);
void *GUIPullOutGetToplevelWindow(  
        void *client_box,    
        int *x, int *y, int *width, int *height
);
void GUIPullOutPullOut(void *client_box);
void GUIPullOutPushIn(void *client_box); 


#ifndef ISBLANK
# define ISBLANK(c)     (((c) == ' ') || ((c) == '\t'))
#endif

#define MAX(a,b)        (((a) > (b)) ? (a) : (b))
#define MIN(a,b)        (((a) < (b)) ? (a) : (b))
#define CLIP(a,l,h)     (MIN(MAX((a),(l)),(h)))
#define STRDUP(s) (((s) != NULL) ? g_strdup(s) : NULL)


/*
 *    Returns a statically allocated string containing the name
 *    of the given key.
 */
static gchar *GUIGetKeyName(gint key)
{
      switch(key)
      {
          case GDK_BackSpace:
          return("BackSpace");
          case GDK_Tab:
            return("Tab");
          case GDK_Linefeed:
            return("LineFeed");
          case GDK_Clear:
            return("Clear");
          case GDK_Return:
            return("Return");
          case GDK_Pause:
            return("Pause");
          case GDK_Scroll_Lock:
            return("ScrollLock");
          case GDK_Sys_Req:
            return("SysReq");
          case GDK_Escape:
            return("Escape");
          case GDK_Delete:
            return("Delete");
          case GDK_Home:
            return("Home");
          case GDK_Left:
            return("Left");
          case GDK_Right:
            return("Right");
          case GDK_Down:
            return("Down");
          case GDK_Up:
            return("Up");
          case GDK_Page_Up:
            return("PageUp");
          case GDK_Page_Down:
            return("PageDown");
          case GDK_End:
            return("End");
          case GDK_Begin:
            return("Begin");
          case GDK_Select:
            return("Select");
          case GDK_Print:
            return("Print");
          case GDK_Execute:
          return("Execute");
          case GDK_Insert:
            return("Insert");
          case GDK_Undo:
            return("Undo");
          case GDK_Redo:
            return("Redo");
          case GDK_Menu:
            return("Menu");
        case GDK_Find:
            return("Find");
          case GDK_Cancel:
            return("Cancel");
          case GDK_Help:
            return("Help");
          case GDK_Break:
            return("Break");
          case GDK_Num_Lock:
            return("NumLock");

          case GDK_KP_Space:
            return("KPSpace");
          case GDK_KP_Tab:
            return("KBTab");
          case GDK_KP_Enter:
            return("KPEnter");
          case GDK_KP_F1:
            return("KPF1");
          case GDK_KP_F2:
            return("KPF2");
          case GDK_KP_F3:
            return("KPF3");
          case GDK_KP_F4:
            return("KPF4");
          case GDK_KP_Home:
            return("KPHome");
          case GDK_KP_Left:
            return("KPLeft");
          case GDK_KP_Up:
            return("KPUp");
          case GDK_KP_Right:
            return("KPRight");
          case GDK_KP_Down:
            return("KPDown");
          case GDK_KP_Page_Up:
            return("KPPageUp");
          case GDK_KP_Page_Down:
            return("KPPageDown");
          case GDK_KP_End:
            return("KPEnd");
          case GDK_KP_Begin:
            return("KPBegin");
          case GDK_KP_Insert:
            return("KPInsert");
          case GDK_KP_Delete:
            return("KPDelete");
          case GDK_KP_Equal:
            return("KPEqual");
          case GDK_KP_Multiply:
            return("KPMultiply");
          case GDK_KP_Add:
            return("KPAdd");
          case GDK_KP_Separator:
            return("KPSeparator");
          case GDK_KP_Subtract:
            return("KPSubtract");
          case GDK_KP_Decimal:
            return("KPDecimal");
          case GDK_KP_Divide:
            return("KPDivide");
          case GDK_KP_0:
            return("KP0");
          case GDK_KP_1:
            return("KP1");
          case GDK_KP_2:
            return("KP2");
          case GDK_KP_3:
            return("KP3");
          case GDK_KP_4:
            return("KP4");
          case GDK_KP_5:
            return("KP5");
          case GDK_KP_6:
            return("KP6");
          case GDK_KP_7:
            return("KP7");
          case GDK_KP_8:
            return("KP8");
          case GDK_KP_9:
            return("KP9");

          case GDK_F1:
            return("F1");
          case GDK_F2:
            return("F2");
          case GDK_F3:
            return("F3");
          case GDK_F4:
            return("F4");
          case GDK_F5:
            return("F5");
          case GDK_F6:
            return("F6");
          case GDK_F7:
            return("F7");
          case GDK_F8:
            return("F8");
          case GDK_F9:
            return("F9");
          case GDK_F10:
            return("F10");
          case GDK_F11:
            return("F11");
          case GDK_F12:
            return("F12");
          case GDK_F13:
            return("F13");
          case GDK_F14:
            return("F14");
          case GDK_F15:
            return("F15");
          case GDK_F16:
            return("F16");
          case GDK_F17:
            return("F17");
          case GDK_F18:
            return("F18");
          case GDK_F19:
            return("F19");
          case GDK_F20:
            return("F20");
          case GDK_F21:
            return("F21");
          case GDK_F22:
            return("F22");
          case GDK_F23:
            return("F23");
          case GDK_F24:
            return("F24");
          case GDK_F25:
            return("F25");
          case GDK_F26:
            return("F26");
          case GDK_F27:
            return("F27");
          case GDK_F28:
            return("F28");
          case GDK_F29:
            return("F29");
          case GDK_F30:
            return("F30");

          case GDK_Shift_L:
            return("ShiftL");
          case GDK_Shift_R:
            return("ShiftR");
          case GDK_Control_L:
            return("ControlL");
          case GDK_Control_R:
            return("ControlR");
          case GDK_Caps_Lock:
            return("CapsLock");
          case GDK_Shift_Lock:
            return("ShiftLock");
          case GDK_Meta_L:
            return("MetaL");
          case GDK_Meta_R:
            return("MetaR");
          case GDK_Alt_L: 
            return("AltL");
          case GDK_Alt_R:
            return("AltR");
          case GDK_Super_L:
            return("SuperL");
          case GDK_Super_R: 
            return("SuperR");
          case GDK_Hyper_L: 
            return("HyperL");
          case GDK_Hyper_R: 
            return("HyperR");
        default:
          return("Unknown");
      }
}


/*
 *    Blocks input for the given GtkWindow if block is set to TRUE
 *    or else allows input again if block is set to FALSE.
 */
void GUIBlockInput(GtkWidget *w, gbool block)
{
      GtkWidget *invis;


      if(w == NULL)
          return;

      if(!GTK_IS_WINDOW(w))
          return;

      /* Create the GtkInvisible blocker widget as needed. */
      invis = gui_invisible_blocker_widget;
      if(invis == NULL)
      {
          gui_invisible_blocker_widget = invis = gtk_invisible_new();
          if(invis == NULL)
            return;
      }

      /* Block input? */
      if(block)
      {
          /* Increase block input level and check if it is the first
           * blocking level.
           */
          gui_block_input_level++;
          if(gui_block_input_level == 1)
          {
            /* This is the first blocking level, so we need to map the
             * GtkInvisible and grab it so that input will be blocked.
             */
            gtk_widget_show(invis);
            if(gtk_grab_get_current() != invis)
                gtk_grab_add(invis);
          }
      }
      else
      {
          /* Decrease block input level and check if it is the last
           * blocking level.
           */
          gui_block_input_level--;
          if(gui_block_input_level == 0)
          {
            if(gtk_grab_get_current() == invis)
                gtk_grab_remove(invis);
            gtk_widget_hide(invis);
          }

          /* Sanitize block input level underflows. */
            if(gui_block_input_level < 0)
          {
                gui_block_input_level = 0;
            fprintf(
                stderr,
"GUIBlockInput(): Block level underflow to level %i.\n",
                gui_block_input_level
            );
          }
      }
}

/*
 *    DND drag begin callback, this function is called at the start
 *    of a drag.
 *
 *      The given data is always NULL for now.
 */
static void GUIDNDDragBeginCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
      gui_dnd_icon_struct *dnd_icon = &gui_dnd_icon;
      if((widget == NULL) || (dc == NULL))
          return;

      /* Set drag icon. */
      if(dnd_icon->toplevel != NULL)
          gtk_drag_set_icon_widget(
                dc,
            dnd_icon->toplevel,
            dnd_icon->x,
            dnd_icon->y
            );

      gtk_signal_emit_stop_by_name(
          GTK_OBJECT(widget), "drag_begin"
      );
}

/*
 *    DND drag motion callback, this function will basically
 *    handle the change of default action on the given destination
 *    widget.
 *
 *    The given data is assumed to be a gui_dnd_cb_struct *.
 */
static gboolean GUIDNDDragMotionCB(
        GtkWidget *widget, GdkDragContext *dc,
        gint x, gint y, guint t,   
        gpointer data
)
{
      gboolean same_widget;
      GtkWidget *src_widget, *tar_widget;
      GdkDragAction action;
      gui_dnd_cb_struct *cb_data = (gui_dnd_cb_struct *)data;
      if((dc == NULL) || (cb_data == NULL))
          return(FALSE);

      /* Get source widget and target widgets. */
      src_widget = gtk_drag_get_source_widget(dc);
      tar_widget = widget;
      /* Set marker for if the source and target widgets are the same. */
        same_widget = (src_widget == tar_widget) ? TRUE : FALSE;

      /* Get default action from cb_data structure, if source and
       * target are the same widget then use default_action_same
       * otherwise use default_action.
       */
      action = same_widget ?
          cb_data->default_action_same : cb_data->default_action;


      /* Respond with default drag action (status). First we check
       * the dc's list of actions. If the list only contains
       * move or copy then we select just that, otherwise we return
       * with our default suggested action.
       * If no valid actions are listed then we respond with 0.
       */

      /* Only move? */
      if(dc->actions == GDK_ACTION_MOVE)
          gdk_drag_status(dc, GDK_ACTION_MOVE, t);
      /* Only copy? */
      else if(dc->actions == GDK_ACTION_COPY)
          gdk_drag_status(dc, GDK_ACTION_COPY, t);
        /* Only link? */
        else if(dc->actions == GDK_ACTION_LINK)
            gdk_drag_status(dc, GDK_ACTION_LINK, t);
      /* Other action, check if listed in our actions list? */
        else if(dc->actions & action)
            gdk_drag_status(dc, action, t);
      /* All else respond with 0. */
      else
          gdk_drag_status(dc, 0, t);

      /* Is target widget valid and sensitive? */
      if((tar_widget != NULL) ? GTK_WIDGET_SENSITIVE(tar_widget) : FALSE)
      {
          /* Set target widget into focus as needed. */
          if(!GTK_WIDGET_HAS_FOCUS(tar_widget) &&
             GTK_WIDGET_CAN_FOCUS(tar_widget)
          )
            gtk_widget_grab_focus(tar_widget);

          /* Handle rest by the target widget's type. */
            /* Target widget is a GtkCTree? */
            if(GTK_IS_CTREE(tar_widget))
            {
            /* Referance it as a clist. */
                GtkCList *clist = (GtkCList *)tar_widget;
                gint row, column;


            /* Update flags as needed. */
            clist->flags |= GTK_CLIST_DRAW_DRAG_LINE;
                clist->flags |= GTK_CLIST_DRAW_DRAG_RECT;

            /* Calculate column row from x and y coordinates. */
                if(!gtk_clist_get_selection_info(
                    clist,
                x,
                    y - ((clist->flags & GTK_CLIST_SHOW_TITLES) ?
                        clist->column_title_area.height +
                        clist->column_title_area.y : 0),
                &row, &column
                ))
                {
                    row = -1;   
                    column = -1;
                }

/*
            i = 0;
            glist = clist->row_list;
            while(glist != NULL)
            {
                if(i == row)
                {
                  row_ptr = (GtkCListRow *)glist->data;
                  break;
                }
                i++;
                glist = glist->next;
            }

            if(row_ptr != NULL)
                gtk_signal_emit_by_name(
                  GTK_OBJECT(tar_widget), "draw_drag_highlight",
                  row_ptr,
                  row,
                  GTK_CLIST_DRAG_INTO
                );
 */
                /* Change in drag position? */
                if(row != clist->focus_row)      
                { 
                    clist->focus_row = row;
                    gtk_widget_queue_draw(tar_widget);
                }
            }
          /* Target widget is a GtkCList? */
          else if(GTK_IS_CLIST(tar_widget))
          {
            GtkCList *clist = (GtkCList *)tar_widget;
            gint row, column;


                /* Update flags as needed. */
            clist->flags |= GTK_CLIST_DRAW_DRAG_LINE;
                clist->flags |= GTK_CLIST_DRAW_DRAG_RECT;

                /* Calculate column row from x and y coordinates. */
                if(!gtk_clist_get_selection_info(   
                    clist,
                x,
                y - ((clist->flags & GTK_CLIST_SHOW_TITLES) ?
                  clist->column_title_area.height +
                  clist->column_title_area.y : 0),
                &row, &column
                ))
                {
                    row = -1;
                    column = -1;
                }

                /* Change in drag position? */
                if(row != clist->focus_row)
                {
                clist->focus_row = row;
                    gtk_widget_queue_draw(tar_widget);
                }
          }
      }

      return(FALSE);
}

/*
 *      DND drag drop callback.
 *
 *      The given data is assumed to be a gui_dnd_cb_struct *.
 */
static gboolean GUIDNDDragDropCB(
        GtkWidget *widget, GdkDragContext *dc,
        gint x, gint y, guint t,
        gpointer data
)
{
        gui_dnd_cb_struct *cb_data = (gui_dnd_cb_struct *)data;
        if((dc == NULL) || (cb_data == NULL))
            return(FALSE);

      return(FALSE);
}

/*
 *      DND drag data received callback.
 *
 *      The given data is assumed to be a gui_dnd_cb_struct *.
 */
static void GUIDNDDragReceivedCB(
        GtkWidget *widget, GdkDragContext *dc,
        gint x, gint y,
        GtkSelectionData *selection_data, guint info, guint t,
        gpointer data
)
{
      gui_dnd_cb_struct *cb_data = (gui_dnd_cb_struct *)data;
        if((dc == NULL) || (cb_data == NULL))
            return;

}

/*
 *      DND drag end callback, this function will reset the target
 *    widget as needed and clean up any additional resources.
 *
 *    The given data is always NULL for now.
 */
static void GUIDNDDragEndCB(
        GtkWidget *widget, GdkDragContext *dc, gpointer data
)
{
        gboolean same_widget;
        GtkWidget *src_widget, *tar_widget;
        if(dc == NULL)
            return;


        /* Get source widget and target widgets. */
        src_widget = gtk_drag_get_source_widget(dc);
        tar_widget = widget;
        /* Set marker for if the source and target widgets are the same. */
        same_widget = (src_widget == tar_widget) ? TRUE : FALSE;


        /* Is target widget valid and sensitive? */
        if((tar_widget != NULL) ? GTK_WIDGET_SENSITIVE(tar_widget) : FALSE)
        {
            /* Handle rest by the target widget's type. */
            /* Is target widget a ctree? */
            if(GTK_IS_CTREE(tar_widget))
            {
            GtkCList *clist = GTK_CLIST(tar_widget);

            clist->flags &= ~GTK_CLIST_DRAW_DRAG_LINE;
                clist->flags &= ~GTK_CLIST_DRAW_DRAG_RECT;
            gtk_widget_queue_draw(tar_widget);
          }
          /* Is target widget a clist? */
            else if(GTK_IS_CLIST(tar_widget))
            {
                GtkCList *clist = GTK_CLIST(tar_widget);

            clist->flags &= ~GTK_CLIST_DRAW_DRAG_LINE;
                clist->flags &= ~GTK_CLIST_DRAW_DRAG_RECT;
            gtk_widget_queue_draw(tar_widget);
            }
      }
}


/*
 *    Button (or toggle button) destroy callback.
 */
static void GUIButtonDestroyCB(GtkObject *object, gpointer data)
{
      gui_button_data_struct *btn_data = (gui_button_data_struct *)data;
      if(btn_data == NULL)
          return;

      /* No substructures to deallocate. */

      /* Deallocate structure itself. */
      g_free(btn_data);
}

/*
 *    Redraw banner widget callback.
 */
static gint GUIBannerExposeCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      gint status = FALSE;
      gint state, width, height;
        GdkFont *font;
        GdkWindow *window;
      GtkStyle *style;
        const gchar *label;
        gint align;
      gpointer *cb_data = (gpointer *)data;
        if((widget == NULL) || (cb_data == NULL))
            return(status);

      state = GTK_WIDGET_STATE(widget);
      window = widget->window;
      style = gtk_widget_get_style(widget);
        if((window == NULL) || (style == NULL))
            return(status);

      width = widget->allocation.width;
        height = widget->allocation.height;


      /* Get values from callback data. */
      label = (const gchar *)cb_data[0];
      align = (gint)cb_data[1];
      font = (GdkFont *)cb_data[2];


      /* Draw background to cover entire window. */
        gdk_draw_rectangle(
            (GdkDrawable *)window, style->bg_gc[state], TRUE,
            0, 0, width, height
        );

      /* Got font and label? */
      if((font != NULL) && (label != NULL))
      {
            gint lbearing, rbearing, width, ascent, descent;

            gdk_string_extents(
                font, label,
                &lbearing, &rbearing, &width, &ascent, &descent
            );

          switch(align)
          {
            case GTK_JUSTIFY_CENTER:
            gdk_draw_string(
                (GdkDrawable *)window,
                font, style->fg_gc[state],
                (widget->allocation.width / 2) - (width / 2),
                3 + ascent,
                (const gchar *)label
            );
            break;

              default:
                gdk_draw_string(
                    (GdkDrawable *)window,
                    font, style->fg_gc[state],
                    3,
                    3 + ascent,
                    (const gchar *)label
                );
                break;
          }
      }

        return(status);
}

/*
 *    Banner widget destroy callback.
 */
static void GUIBannerDestroyCB(GtkObject *object, gpointer data)
{
      gchar *label;
      gint align;
      GdkFont *font;
      gpointer *cb_data = (gpointer *)data;
      if(cb_data == NULL)
          return;

        /* Parse callback data. */
        label = (gchar *)cb_data[0];
        align = (gint)cb_data[1];
      font = (GdkFont *)cb_data[2];

      /* Free label. */
      cb_data[0] = NULL;
      g_free(label);
      label = NULL;

      /* Unref font. */
      cb_data[2] = NULL;
      if(font != NULL)
      {
          gdk_font_unref(font);
          font = NULL;
      }

      /* Free data pointer array. */
      g_free(cb_data);
}


/*
 *      GtkCombo "activate" signal callback.
 *
 *    First it will update the glist for the combo box and update
 *    the the combo's list. Then call (if not NULL) the specified
 *    activate callback function.
 */
static void GUIComboActivateCB(GtkWidget *widget, gpointer data)
{
      gint max_items;
      GtkWidget *parent, *wlabel;
      GtkCombo *combo;
      GList *glist_in;
      gpointer client_data;
      void (*func_cb)(GtkWidget *, gpointer);
        void (*list_change_cb)(GtkWidget *, gpointer, GList *);
      gchar *new_value;
      gpointer *cb_data = (gpointer *)data;
      if((widget == NULL) || (cb_data == NULL))
          return;

      /* Parse callback data, format is as follows;
       * table    Parent table that holds this combo and label.
       * label    Label (may be NULL).
       * combo    This combo widget.
       * GList    Contains list of strings in combo list.
       * max_items      Max items allowed in combo list.
       * client_data    Calling function set callback data.
       * func_cb  Calling function set callback function.
       * list_change_cb Calling function set list change function.
       * NULL
       */
      parent = (GtkWidget *)(cb_data[0]);
      wlabel = (GtkWidget *)(cb_data[1]);
      combo = (GtkCombo *)(cb_data[2]);
      glist_in = (GList *)(cb_data[3]);
      max_items = (gint)(cb_data[4]);
        client_data = (gpointer)(cb_data[5]);
        func_cb = cb_data[6];
      list_change_cb = cb_data[7];

      if(combo == NULL)
          return;

      /* Get new value string from combo's entry widget. */
      new_value = gtk_entry_get_text(GTK_ENTRY(combo->entry));

      /* Make a duplicate of the recieved value or NULL if it is not
       * available.
       */
      new_value = STRDUP(new_value);
      if(new_value == NULL)
          return;

      /* Add the new value to the combo box list, this will only
       * be added if value is not already in the list. Excess items
       * may be truncated if adding this item would cause items to
       * exceed the set max items on the combo box.
       *
       * List change callback will be called if the value was input
       * to the combo box's list.
       */
      GUIComboAddItem((gpointer)combo, new_value);

      /* Call activate function. */
      if(func_cb != NULL)
          func_cb(
            (GtkWidget *)combo,     /* Pass combo box as widget. */
                client_data         /* Client data. */
          );

      /* Free new_value which we duplicated. */
      g_free(new_value);
}

/*
 *      GtkCombo "changed" signal callback.
 */
static void GUIComboChangedCB(GtkWidget *widget, gpointer data)
{
        GList *glist;
      GtkCombo *combo;
        gpointer client_data;
        void (*list_change_cb)(GtkWidget *, gpointer, GList *);
        gpointer *cb_data = (gpointer *)data;
        if((widget == NULL) || (cb_data == NULL))
            return;

        /* Parse callback data, format is as follows;
         * table        Parent table that holds this combo and label.
         * label        Label (may be NULL).
         * combo        This combo widget.
         * GList        Contains list of strings in combo list.
         * max_items    Max items allowed in combo list.
         * client_data  Calling function set callback data.
         * func_cb      Calling function set callback function.
         * list_change_cb       Calling function set list change function.
         * NULL
         */
        combo = (GtkCombo *)(cb_data[2]);
        glist = (GList *)cb_data[3];
        client_data = cb_data[5];
        list_change_cb = cb_data[7];

        /* Call list change function. */
        if(list_change_cb != NULL)
            list_change_cb(
                (GtkWidget *)combo, /* Pass combo box as widget. */
                client_data,        /* Client data. */
            glist             /* List. */
            );
}

/*
 *      Local combo destroy callback, this function will free the given
 *      pointer data and it pointed to resources.
 */
static void GUIComboDestroyCB(GtkObject *object, gpointer data)
{
      GtkWidget *parent, *wlabel;
      GtkCombo *combo;
      GList *glist_in;
      gint max_items;
        gpointer client_data;
        void (*func_cb)(GtkWidget *, gpointer);
        void (*list_change_cb)(GtkWidget *, gpointer, GList *);
        gpointer *cb_data = (gpointer *)data;


      if(cb_data == NULL)
          return;

        /* Parse callback data, format is as follows;
         * table        Parent table that holds this combo and label.
         * label        Label (may be NULL).
         * combo        This combo widget.
         * GList        Contains list of strings in combo list.
         * max_items    Max items allowed in combo list.
         * client_data  Calling function set callback data.
         * func_cb      Calling function set callback function.
         * list_change_cb       Calling function set list change function.
         * NULL
         */
        parent = (GtkWidget *)(cb_data[0]);
        wlabel = (GtkWidget *)(cb_data[1]);
        combo = (GtkCombo *)(cb_data[2]);
        glist_in = (GList *)(cb_data[3]);
        max_items = (gint)(cb_data[4]);
        client_data = (gpointer)(cb_data[5]);
        func_cb = cb_data[6];
        list_change_cb = cb_data[7];


      /* Do not call list change callback function on destroy. */

      /* Begin deallocating data referenced on callback data. */

        /* Deallocate glist. */
        if(glist_in != NULL)
        {
            g_list_foreach(glist_in, (GFunc)g_free, NULL);
            g_list_free(glist_in);
            glist_in = NULL;
        }

      /* Free callback data pointer array itself. */
      g_free(data);
}


/*
 *    Local menu item activate callback, this function will
 *    take the given data pointer as a dynamically allocated
 *    (void **).
 */
static void GUIMenuActivateCB(gpointer data)
{
      gint argc = 3;
      GtkWidget *functional_widget;
      gpointer client_data;
      void (*func_cb)(GtkWidget *, gpointer);
      gpointer *cb_data = (gpointer *)data;
      if(cb_data == NULL)
          return;


      /* Parse callback data, there should be four pointers in
       * the (void **)cb_data array. The pointers point to as follows;
       * w              functional_widget.
       * client_data          client_data set by calling function.
       * void *func_cb(GtkWidget *, gpointer)         Calling function's function.
       * NULL
       */
      functional_widget = ((argc > 0) ? cb_data[0] : NULL);
      client_data = ((argc > 1) ? cb_data[1] : NULL);
      func_cb = ((argc > 2) ? cb_data[2] : NULL);

      if(func_cb != NULL)
          func_cb(
            functional_widget,
            client_data
          );
}

/*
 *      Local menu item destroy callback, this function will
 *      deallocate the given client data.
 *
 *    Note that the client data may be of any type but no substructures
 *    need to be deallocated, see GUIMenuItemCreate().
 */
static void GUIMenuDestroyCB(GtkObject *object, gpointer data)
{
      g_free(data);
}

/*
 *    Local pull out widget destroy callback, this function will
 *    free the given pointer data and the destroy the toplevel
 *    GtkWindow.
 */
static void GUIPullOutDestroyCB(GtkObject *object, gpointer data)
{
      GtkWidget *client_hbox, *holder_hbox, *toplevel;
      gpointer *cb_data = (gpointer *)data;

      if(cb_data != NULL)
      {
            /* Format is as follows (12 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb
             */
            client_hbox = (GtkWidget *)cb_data[0];
            holder_hbox = (GtkWidget *)cb_data[1];
          toplevel = (GtkWidget *)cb_data[2];

          /* Get given object should be the holder hbox. */
          if((gpointer)holder_hbox != (gpointer)object)
          {
            fprintf(stderr,
 "GUIPullOutDestroyCB(): Invalid object, not holder_hbox.\n"
            );
          }

          /* Destroy the toplevel window. */
          if(toplevel != NULL)
          {
            gtk_widget_destroy(toplevel);
            cb_data[2] = toplevel = NULL;
          }
      }

      g_free(cb_data);
}

/*
 *    Pull out draw handle for signal "draw".
 */
static void GUIPullOutDrawHandleDrawCB(
        GtkWidget *widget, GdkRectangle *area, gpointer data  
)
{
        GdkWindow *window;
        GtkStyle *style_ptr;

        if((widget != NULL) ? GTK_WIDGET_NO_WINDOW(widget) : TRUE)
            return;

        window = widget->window;
        if(window == NULL)
            return;

        /* Get widget's style structure. */
        style_ptr = gtk_widget_get_style(widget);
        /* If none then fall back to global style. */
        if(style_ptr == NULL)
            style_ptr = gtk_widget_get_default_style();
        /* No style available, give up. */
        if(style_ptr == NULL)
            return;

        gdk_window_clear(window);
#ifndef __MSW__
        gtk_draw_handle(
            style_ptr, window,
            GTK_STATE_NORMAL,           /* State type. */
            GTK_SHADOW_OUT,             /* Shadow type. */
            0, 0,
            widget->allocation.width,
            widget->allocation.height,
            GTK_ORIENTATION_HORIZONTAL
        );
#endif
}

/*
 *    Pull out draw handle callback for signal "expose_event".
 *
 *    This redraws the handle graphics on the given widget.
 */
static gint GUIPullOutDrawHandleCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      if((widget != NULL) ? GTK_WIDGET_NO_WINDOW(widget) : TRUE)
          return(TRUE);
      gtk_widget_queue_draw(widget);
      return(TRUE);
}

/*
 *    Pull out button callback.
 */
static gint GUIPullOutPullOutBtnCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
        GtkWidget *client_hbox, *holder_hbox, *toplevel;
        gpointer *cb_data = (gpointer *)data;
      gint holder_window_width, holder_window_height;
      gpointer pull_out_client_data;
        void (*pull_out_cb)(gpointer, gpointer);

        if(cb_data != NULL)
        {
            /* Format is as follows (12 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb
             */
            client_hbox = (GtkWidget *)cb_data[0];
            holder_hbox = (GtkWidget *)cb_data[1];
            toplevel = (GtkWidget *)cb_data[2];

          holder_window_width = (gint)cb_data[5];
          holder_window_height = (gint)cb_data[6];

          pull_out_client_data = cb_data[8];
          pull_out_cb = cb_data[9];

          /* Create toplevel window as needed. */
            if(toplevel == NULL)
            {
            GtkWidget *w;

            toplevel = w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
            cb_data[2] = (void *)w;
                gtk_widget_realize(w);
                gtk_widget_set_usize(
                w,
                (holder_window_width <= 0) ? -1 : holder_window_width,
                (holder_window_height <= 0) ? -1 : holder_window_height
            );
            gtk_window_set_policy(
                GTK_WINDOW(w),
                TRUE, TRUE, FALSE
            );
            gtk_signal_connect(
                GTK_OBJECT(w), "delete_event",
                GTK_SIGNAL_FUNC(GUIPullOutCloseCB),
                (gpointer)cb_data
            );
          }

          /* Reparent client_hbox to toplevel window. */
          if((client_hbox != NULL) && (toplevel != NULL))
          {
            gtk_widget_show(toplevel);

            if((GTK_WIDGET_FLAGS(client_hbox) & GTK_NO_REPARENT))
                fprintf(stderr, "Cannot reparent.\n");
            else
                gtk_widget_reparent(client_hbox, toplevel);
          }

          /* Hide holder hbox. */
          if(holder_hbox != NULL)
            gtk_widget_hide(holder_hbox);

          /* Mark in callback data that its been `pulled out'. */
          cb_data[7] = (void *)0;

            /* Call pull out callback? */
            if(pull_out_cb != NULL)
                pull_out_cb(client_hbox, pull_out_client_data);
        }

        return(TRUE);
}

/*
 *    Close (push in) callback.
 */
static gint GUIPullOutCloseCB(GtkWidget *widget, GdkEvent *event, gpointer data)
{
        GtkWidget *client_hbox, *holder_hbox, *toplevel;
      gpointer *cb_data = (gpointer *)data;
        gpointer push_in_client_data;
        void (*push_in_cb)(gpointer, gpointer);

        if(cb_data != NULL)
        {
            /* Format is as follows (12 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb
             */
            client_hbox = (GtkWidget *)cb_data[0];
            holder_hbox = (GtkWidget *)cb_data[1];
            toplevel = (GtkWidget *)cb_data[2];

          push_in_client_data = cb_data[10];
          push_in_cb = cb_data[11];


            /* Reparent client_hbox to holder_hbox. */
            if((client_hbox != NULL) && (holder_hbox != NULL))
            {
            gtk_widget_show(holder_hbox);

                if((GTK_WIDGET_FLAGS(client_hbox) & GTK_NO_REPARENT))
                    fprintf(stderr, "Cannot reparent.\n");
                else
                    gtk_widget_reparent(client_hbox, holder_hbox);
            }

          /* Hide toplevel. */
          if(toplevel != NULL)
            gtk_widget_hide(toplevel);

            /* Mark in callback data that its been `pushed in'. */
            cb_data[7] = (void *)1;

          /* Call push in callback? */
          if(push_in_cb != NULL)
            push_in_cb(client_hbox, push_in_client_data);
        }

      return(TRUE);
}

/*
 *    Coppies the source image buffer to the target image buffer.
 */
void GUIResizeBuffer(
        gint bpp,
        const gpointer src,
        gint src_width, gint src_height, gint src_bpl,
        gpointer tar,
        gint tar_width, gint tar_height, gint tar_bpl
)
{
      
      guint8 *tar_buf = (guint8 *)tar;
      const guint8 *src_buf = (const guint8 *)src;
        u_int8_t *src_buf_ptr8, *tar_buf_ptr8;
        u_int16_t *src_buf_ptr16, *tar_buf_ptr16;
        u_int32_t *src_buf_ptr32, *tar_buf_ptr32;

      /* Current positions. */
      gint tar_x_col, tar_y_row;
      gint src_x_col, src_y_row;    /* In units of 256. */

      /* Increments, in units of 256. */
      gint src_dh_x_col_inc, src_dh_y_row_inc;
      gint src_dh_width, src_dh_height;


        if((tar_width < 1) || (tar_height < 1) ||
           (src_width < 1) || (src_height < 1) ||
           (tar_buf == NULL) || (src_buf == NULL) ||
           (bpp < 1)
        )
            return;

      /* Auto calculate bytes per lines as needed. */
      if(src_bpl <= 0)
          src_bpl = src_width * bpp;
      if(tar_bpl <= 0)
          tar_bpl = tar_width * bpp;

        /* 8 bits. */
        if(bpp == 1)
        {
            src_dh_x_col_inc = (gint)(src_width * 256) / tar_width;
            src_dh_y_row_inc = (gint)(src_height * 256) / tar_height;

            src_dh_width = src_width * 256;
            src_dh_height = src_height * 256;

            tar_x_col = 0;
            tar_y_row = 0;
            src_x_col = 0 * 256;
            src_y_row = 0 * 256;

            /* Begin copying source buffer to target buffer. */
            while((tar_y_row < tar_height) &&
                  (src_y_row < src_dh_height)
            )
            {
                /* Get buffer position. */
                src_buf_ptr8 = (u_int8_t *)(&src_buf[
                    ((src_y_row >> 8) * src_bpl) +
                    ((src_x_col >> 8) * bpp)
                ]);
                tar_buf_ptr8 = (u_int8_t *)(&tar_buf[
                    (tar_y_row * tar_bpl) +
                    (tar_x_col * bpp)
                ]);
                *tar_buf_ptr8 = *src_buf_ptr8;


                /* Increment colum positions. */
                tar_x_col += 1;
                src_x_col += src_dh_x_col_inc;

                /* Go to next line? */
                if((tar_x_col >= tar_width) ||
                   (src_x_col >= src_dh_width)
                )
                {
                    tar_x_col = 0;
                    src_x_col = 0;

                    tar_y_row += 1;
                    src_y_row += src_dh_y_row_inc;
                }
            }
        }
        /* 16 bits. */
        else if(bpp == 2)
        {
            src_dh_x_col_inc = (gint)(src_width * 256) / tar_width;
            src_dh_y_row_inc = (gint)(src_height * 256) / tar_height;

            src_dh_width = src_width * 256;
            src_dh_height = src_height * 256;

            tar_x_col = 0;
            tar_y_row = 0;
            src_x_col = 0 * 256;
            src_y_row = 0 * 256;

            /* Begin copying source buffer to target buffer. */
            while((tar_y_row < tar_height) &&
                  (src_y_row < src_dh_height)
            )
            {
                /* Get buffer position. */
                src_buf_ptr16 = (u_int16_t *)(&src_buf[
                    ((src_y_row >> 8) * src_bpl) +
                    ((src_x_col >> 8) * bpp)
                ]);
                tar_buf_ptr16 = (u_int16_t *)(&tar_buf[
                    (tar_y_row * tar_bpl) +
                    (tar_x_col * bpp)
                ]);
                *tar_buf_ptr16 = *src_buf_ptr16;


                /* Increment colum positions. */
                tar_x_col += 1;
                src_x_col += src_dh_x_col_inc;

                /* Go to next line? */
                if((tar_x_col >= tar_width) ||
                   (src_x_col >= src_dh_width)
                )
                {
                    tar_x_col = 0;
                    src_x_col = 0;

                    tar_y_row += 1;
                    src_y_row += src_dh_y_row_inc;
                }
            }
        }
        /* 32 bits. */
        else if(bpp == 4)
        {
            src_dh_x_col_inc = (gint)(src_width * 256) / tar_width;
            src_dh_y_row_inc = (gint)(src_height * 256) / tar_height;

            src_dh_width = src_width * 256;
            src_dh_height = src_height * 256;

            tar_x_col = 0;
            tar_y_row = 0;
            src_x_col = 0 * 256;
            src_y_row = 0 * 256;

            /* Begin copying source buffer to target buffer. */
            while((tar_y_row < tar_height) &&
                  (src_y_row < src_dh_height)
            )
            {
                /* Get buffer position. */
                src_buf_ptr32 = (u_int32_t *)(&src_buf[
                    ((src_y_row >> 8) * src_bpl) +
                    ((src_x_col >> 8) * bpp)
                ]);
                tar_buf_ptr32 = (u_int32_t *)(&tar_buf[
                    (tar_y_row * tar_bpl) +
                    (tar_x_col * bpp)
                ]);
                *tar_buf_ptr32 = *src_buf_ptr32;


                /* Increment colum positions. */
                tar_x_col += 1;
                src_x_col += src_dh_x_col_inc;

                /* Go to next line? */
                if((tar_x_col >= tar_width) ||
                   (src_x_col >= src_dh_width)
                )
                {
                    tar_x_col = 0;
                    src_x_col = 0;

                    tar_y_row += 1;
                    src_y_row += src_dh_y_row_inc;
                }
            }
        }
}


/*
 *      Deallocates and unrefs all resources on the given GtkStyle and
 *      detaches and unrefs the structure itself.
 */
void GUIStyleDeallocUnref(GtkStyle *style)
{
        GtkStyle *s = style;
        if(s != NULL)
            gtk_style_detach(s);    /* Detach and unref style. */
}

/*
 *    Deallocates and unrefs all resources on the given GtkRcStyle and
 *    unrefs the structure itself.
 */
void GUIRCStyleDeallocUnref(GtkRcStyle *rcstyle)
{
      GtkRcStyle *rcs = rcstyle;
      if(rcs != NULL)
      {
          gint i;

          g_free(rcs->name);
          rcs->name = NULL;

          g_free(rcs->font_name);
          rcs->font_name = NULL;

          g_free(rcs->fontset_name);
          rcs->fontset_name = NULL;

          for(i = 0; i < 5; i++)
          {
            g_free(rcs->bg_pixmap_name[i]);
            rcs->bg_pixmap_name[i] = NULL;
          }

          gtk_rc_style_unref(rcs);
      }
}


/*
 *    Parses the geometry string s.
 *
 *    Currently this just returns 0xffffffff on success or 0x00000000
 *    on failure.
 */
guint32 gdk_parse_geometry(
        const gchar *s,
        gint *x, gint *y, gint *width, gint *height
)
{
      if(x != NULL)
          *x = 0;
      if(y != NULL)
          *y = 0;
      if(width != NULL)
          *width = 0;
      if(height != NULL)
          *height = 0;

      if(s == NULL)
          return(0x00000000);

      /* Seek past initial spaces and '=' deliminator (if any). */
      while(ISBLANK(*s))
          s++;
      while(*s == '=')
            s++;
        while(ISBLANK(*s))
            s++;

      /* String at width and height arguments? */
      if((*s != '+') && (*s != '-'))
        {
          /* Parse width value. */
          if((width != NULL) && (*s != '\0'))
                *width = atoi(s);

          /* Begin seeking to next argument. */
            if(*s != '\0')
                s++;
            while((toupper(*s) != 'X') && (*s != '\0'))
                s++;
          while((toupper(*s) == 'X') || ISBLANK(*s))
            s++;

            /* Parse height value. */
            if((height != NULL) && (*s != '\0'))
                *height = atoi(s);

            /* Begin seeking to next argument (probably an offset
           * value).
           */
            if(*s != '\0')
                s++;
            while((*s != '+') && (*s != '-') && (*s != '\0'))
                s++;
      }


      /* String seeked to the offsets arguments? */
      if((*s == '+') || (*s == '-'))
      {
          /* Seek past '+' character as needed and get x offset
           * value.
           */
          if(*s == '+')
            s++;
          if((x != NULL) && (*s != '\0'))
            *x = atoi(s);

          /* Begin seeking to next argument. */
          if(*s != '\0')
            s++;
          while((*s != '+') && (*s != '-') && (*s != '\0'))
            s++;

            /* Seek past '+' character as needed and get y offset
             * value.
             */
          if(*s == '+')
                s++;
          if((y != NULL) && (*s != '\0'))
                *y = atoi(s);
      }

      return(0xffffffff);
}


/*
 *    Returns the geometry of the given cell if it is valid on
 *    the given clist w. Geometry is relative to the clist's 
 *    clist_window.
 *
 *    Returns non-zero on error.
 */
int GUICListGetCellGeometry(
        void *w, int column, int row,
        int *x, int *y, int *width, int *height
)
{
      GtkAdjustment *hadj, *vadj;
      GdkWindow *clist_window;
      GtkCList *clist;
      GList *glist;
      GtkCListRow *row_ptr;
      gint i, cx, cy, cwidth, cheight;
      GtkCListColumn *column_ptr;


      if(x != NULL)
          *x = 0;
      if(y != NULL)
            *y = 0;
        if(width != NULL)
            *width = 0;
        if(height != NULL)
            *height = 0;


      if(w == NULL)
          return(-1);

      if(!GTK_IS_CLIST((GtkWidget *)w))
          return(-1);

      clist = GTK_CLIST((GtkWidget *)w);
      hadj = clist->hadjustment;
      vadj = clist->vadjustment;
      clist_window = clist->clist_window;
      if(clist_window == NULL)
          return(-1);

      /* Given row and column in bounds? */
      if((column < 0) || (column >= clist->columns))
          return(-1);
      if((row < 0) || (row >= clist->rows))
          return(-1);

      /* Get cy and cheight. */
      cy = 0;
      cheight = 0;
      glist = clist->row_list;
      for(i = 0; glist != NULL; i++)
      {
          row_ptr = (GtkCListRow *)glist->data;
          if(row_ptr != NULL)
          {
            GtkCellText *cell_text_ptr;
                GtkCellPixmap *cell_pixmap_ptr;
                GtkCellPixText *cell_pixtext_ptr;
                GtkCellWidget *cell_widget_ptr;

            GtkCell *cell_ptr = row_ptr->cell;
            cheight = clist->row_height;
            if(cell_ptr != NULL)
            {
                switch((gint)cell_ptr->type)
                {
                  case GTK_CELL_TEXT:
                  cell_text_ptr = (GtkCellText *)cell_ptr;
                  cheight = MAX(cell_text_ptr->vertical, cheight);
                  break;

                      case GTK_CELL_PIXMAP:
                        cell_pixmap_ptr = (GtkCellPixmap *)cell_ptr;
                  cheight = MAX(cell_pixmap_ptr->vertical, cheight);
                        break;

                      case GTK_CELL_PIXTEXT:
                        cell_pixtext_ptr = (GtkCellPixText *)cell_ptr;
                        cheight = MAX(cell_pixtext_ptr->vertical, cheight);
                        break;

                      case GTK_CELL_WIDGET:
                        cell_widget_ptr = (GtkCellWidget *)cell_ptr;
                        cheight = MAX(cell_widget_ptr->vertical, cheight);
                        break;
                }
            }
            cheight += 1;     /* Need to add 1 pixel for cell borders. */

                if(i == row)
                    break;

            cy += cheight;
          }

          glist = glist->next;
      }

      /* Get cx and cwidth. */
      cx = 0;
      cwidth = 0;
      if(clist->column != NULL)
      {
          for(i = 0; i < clist->columns; i++)
          {
            column_ptr = &clist->column[i];
            if(column_ptr == NULL)
                continue;

            /* Get width of this column plus margins. */
            cwidth = column_ptr->width + 7;

                if(i == column)
                    break;

            cx += cwidth;
          }
      }

      /* Offset cx and cy with scroll adjustments. */
      if(hadj != NULL)
          cx = cx - (gint)(hadj->value - hadj->lower);
        if(vadj != NULL)
            cy = cy - (gint)(vadj->value - vadj->lower);

      /* Update returns. */
        if(x != NULL)
            *x = cx;
        if(y != NULL)
            *y = cy;
        if(width != NULL)
            *width = cwidth;
        if(height != NULL)
            *height = cheight;

      return(0);
}

/*
 *    Returns the coordinate position for GdkWindow w relative to the
 *    root (desktop) window.
 */
void GUIGetWindowRootPosition(
        void *w, int *x, int *y
)
{
      GdkWindow *cur_w = (GdkWindow *)w;
      GdkWindow *root_w;
      gint cx, cy;


      if(x != NULL)
          *x = 0;
      if(y != NULL)
          *y = 0;

        if(cur_w == NULL)
            return;

      root_w = (GdkWindow *)GDK_ROOT_PARENT();
        if(root_w == NULL)
            return;

      while(cur_w != root_w)
      {
          gdk_window_get_position(cur_w, &cx, &cy);
          if(x != NULL)
            *x += cx;
            if(y != NULL)
                *y += cy;
          cur_w = gdk_window_get_parent(cur_w);
      }
}

/*
 *    Converts the coordinates x and y relative to GdkWindow w to
 *    be relative to the root (desktop) window.
 */
void GUIGetPositionRoot(
        void *w, int x, int y, int *rx, int *ry
)
{
        GdkWindow *cur_w = (GdkWindow *)w;
        GdkWindow *root_w;
      gint cx, cy;


        if(rx != NULL)
            *rx = 0;
        if(ry != NULL)
            *ry = 0;

        if(cur_w == NULL)
            return;

        root_w = (GdkWindow *)GDK_ROOT_PARENT();
      if(root_w == NULL)
          return;

        while((cur_w != root_w) && (cur_w != NULL))
        {
            gdk_window_get_position(cur_w, &cx, &cy);
          x += cx;
          y += cy;
            cur_w = gdk_window_get_parent(cur_w);
        }

        if(rx != NULL)
            *rx = x;
        if(ry != NULL)
            *ry = y;
}

/*
 *    Creates a GDK bitmap from the given RGBA data, only the
 *    alpha byte will be used to create the bitmap. An alpha
 *    byte value greater than or equal to the value specified by
 *    threshold will set a 1 bit in the bitmap and a value less will
 *    set a 0.
 *
 *    If the given bpl is -1, then the bpl will be automatically
 *    calculated.
 */
GdkBitmap *GUICreateBitmapFromDataRGBA(
      gint width, gint height, gint bpl,
      const guint8 *rgba, guint8 threshold,
      GdkWindow *window
)
{
      gint bpp = 4;
      gint xbm_bpl;
      guint8 *xbm_data;
      const guint8 *src_ptr;
      gint x, y;
      GdkBitmap *bitmap = NULL;


      if((rgba == NULL) || (width <= 0) || (height <= 0))
          return(bitmap);

      /* Calculate bytes per line, the number of bytes to be able to
       * hold one whole line of bits.
       */
      xbm_bpl = (width / 8) + ((width % 8) ? 1 : 0);

      if(bpl < 0)
          bpl = width * bpp;
      if(bpl <= 0)
          return(bitmap);

      /* Allocate tempory xbm data. */
      xbm_data = (guint8 *)g_malloc0(
          xbm_bpl * height * sizeof(guint8)
      );
      if(xbm_data == NULL)
          return(bitmap);

      for(y = 0; y < height; y++)
      {
          for(x = 0; x < width; x++)
          {
            src_ptr = &rgba[
                (y * bpl) + (x * bpp)
            ];
            /* Alpha byte value greater or equal to threshold? */
            if(src_ptr[3] >= threshold)
                xbm_data[
                  (y * xbm_bpl) + (x / 8)
                ] |= (guint8)(1 << (x % 8));
          }
      }

      /* Create bitmap from xbm data and then deallocate xbm data
       * (since it is no longer needed).
       */
      bitmap = gdk_bitmap_create_from_data(
          window, xbm_data,
          width, height
      );
      g_free(xbm_data);

      return(bitmap);
}


/*
 *    Create a cursor (GdkCursor) from xpm data.
 *This function problem dosen't really work, so don't use it just yet!!
 */
void *GUICreateCursorFromData(
      u_int8_t **cursor_data,
      double hot_x, double hot_y,
      int width, int height   /* Both can be 0. */
)
{
      GdkCursor *cur;
      GdkWindow *window;
      GdkPixmap *pixmap;
      GdkBitmap *mask;
      GtkStyle *style;
      gint w, h;


      if(cursor_data == NULL)
          return(NULL);

      window = (GdkWindow *)GDK_ROOT_PARENT();
        if(window == NULL)  
            return(NULL);

        style = gtk_widget_get_default_style();
      mask = NULL;
        pixmap = gdk_pixmap_create_from_xpm_d(
            window, &mask,
            &style->bg[GTK_STATE_NORMAL],
            (gchar **)cursor_data
        );

        gdk_window_get_size((GdkWindow *)pixmap, &w, &h);

      cur = gdk_cursor_new_from_pixmap(
          pixmap,
          (GdkPixmap *)mask,
          &style->fg[GTK_STATE_NORMAL],
          &style->bg[GTK_STATE_NORMAL],
          (gint)(hot_x * MAX(w - 1, 0)),
          (gint)(hot_y * MAX(h - 1, 0))
      );

      return(cur);                                          
}

/*
 *      Sets the specified window manager icon data to window w.
 *
 *    Window w must be realized first.
 */
void GUISetWMIcon(GdkWindow *w, u_int8_t **icon)
{
        GdkBitmap *mask;
        GdkPixmap *pixmap;
        GtkStyle *style = gtk_widget_get_default_style();


      if((w == NULL) || (icon == NULL))
          return;

        pixmap = gdk_pixmap_create_from_xpm_d(
          w, &mask,
          (style != NULL) ? &style->bg[GTK_STATE_NORMAL] : NULL,
          (gchar **)icon
      );
      if(pixmap != NULL)
          gdk_window_set_icon(w, NULL, pixmap, mask);
}


/*
 *    Creates a GtkPixmap containing the given data or NULL on error.
 */
void *GUICreateMenuItemIcon(u_int8_t **icon)
{
        gint width = 0, height = 0;
      GdkWindow *window;
        GdkPixmap *pixmap = NULL;
        GdkBitmap *mask = NULL;
        GtkStyle *style;
        GtkWidget *w = NULL;


        window = (GdkWindow *)GDK_ROOT_PARENT();
        if(window == NULL)
            return(NULL);

        style = gtk_widget_get_default_style();

        /* If no icon data specified, then use default empty icon. */
      if(icon == NULL)
      {
          gchar *bitmap_data;

          /* Set width and height of blank icon. */
          width = GUI_MENU_ITEM_DEF_HEIGHT;
          height = width;

          /* Allocate tempory bitmap data and create the GdkBitmap mask. */
          bitmap_data = (gchar *)g_malloc0(
            (((width / 8) + 1) * height) * sizeof(gchar)
          );
          if(bitmap_data != NULL)
            mask = gdk_bitmap_create_from_data(
                window, bitmap_data,
                width, height
            );
          else
            mask = NULL;
          /* Deallocate tempory bitmap data, it is no longer needed. */
          g_free(bitmap_data);

          /* Create blank GdkPixmap. */
          pixmap = gdk_pixmap_new(
            window, width, height, -1
          );

          /* Pixmap created successfully? */
          if(pixmap != NULL)
          {
            /* Create a GtkPixmap based on new pixmap and mask pair. */
            w = gtk_pixmap_new(pixmap, mask);
          }
      }
      else
      {
          /* Create pixmap and mask pair from given data. */
            pixmap = gdk_pixmap_create_from_xpm_d(
              window, &mask,
            (style != NULL) ?
                &style->bg[GTK_STATE_NORMAL] : NULL,
              (gchar **)icon
          );

          /* Pixmap created successfully? */
          if(pixmap != NULL)
          {
            /* Create a GtkPixmap based on new pixmap and mask pair. */
            w = gtk_pixmap_new(pixmap, mask);

            /* Get size of newly loaded pixmap. */
            gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
          }
      }

      /* Unref pixmap and mask pair, they are no longer needed. */
      if(pixmap != NULL)
          gdk_pixmap_unref(pixmap);
      if(mask != NULL)
          gdk_bitmap_unref(mask);

        return(w);
}

/*
 *    Minimizes (iconifies) the given window.
 */
void gtk_window_minimize(GtkWindow *window)
{
#ifdef _XLIB_H_
      Display *dpy;
      Window xwin;
      GdkWindow *win;
      gint scr_num;

      if(window == NULL)
          return;

      if(!GTK_WIDGET_REALIZED(GTK_WIDGET(window)))
          return;

      win = GTK_WIDGET(window)->window;
      if(win == NULL)
          return;

      dpy = GDK_WINDOW_XDISPLAY(win);
      xwin = GDK_WINDOW_XWINDOW(win);
      if((dpy == NULL) || (xwin == None))
          return;

      scr_num = DefaultScreen(dpy);
      XIconifyWindow(dpy, xwin, scr_num);

#endif      /* _XLIB_H_ */
}

/*
 *    Creates the global gui_tooltips widget for controlling the
 *    enabled/disabled state of all tooltips set by these functions.
 *
 *    When the global gui_tooltips widget is first created, the
 *    tooltips will be enabled and gui_tooltips_state will be reset
 *    to TRUE.
 */
static void GUICreateGlobalTooltips(void)
{
      /* Need to create global gui_tooltips widget? */
        if(gui_tooltips == NULL)
        {
          GtkWidget *w = (GtkWidget *)gtk_tooltips_new();
          gui_tooltips = (GtkTooltips *)w;
          if(w != NULL)
            {
                gtk_tooltips_enable(GTK_TOOLTIPS(w));
                gui_tooltips_state = TRUE;
            }
        }
}

/*
 *    Sets the tip for the given widget w, if the widget w already
 *    has a tip set then it will be changed to the new value.
 *
 *    If tip is NULL then no tip will be set on the given widget.
 */
void GUISetWidgetTip(GtkWidget *w, const gchar *tip)
{
      if(w == NULL)
          return;

      /* Create global tooltips as needed. */
      GUICreateGlobalTooltips();
        if(gui_tooltips == NULL)
            return;

      if(tip != NULL)
      {
          gtk_tooltips_set_tip(
            gui_tooltips,           /* Our tooltips group. */
            w,
            tip, NULL
          );
      }
      else
      {
            gtk_tooltips_set_tip(
                gui_tooltips,           /* Our tooltips group. */
                w,
                NULL, NULL
            );
      }
}

/*
 *    Makes the tooltip associated with the given widget shown
 *    immediatly if the widget has a tip defined. Also requires
 *    that the global gui_tooltips_state be TRUE, otherwise
 *    this function does nothing.
 */
void GUIShowTipsNow(GtkWidget *w)
{
      GdkEventCrossing e;
      GdkWindow *window;


      if((w == NULL) || !gui_tooltips_state)
          return;

      if(GTK_WIDGET_NO_WINDOW(w))
          return;
      else
          window = w->window;
      if(window == NULL)
          return;

      /* Send a fake enter notify event to make widget think
       * its time to show the tooltips. Note that the widget
       * should be watching for the enter_notify_event.
       */
      e.type = GDK_ENTER_NOTIFY;
      e.window = window;
      e.send_event = 1;       /* True if we're sending event. */
      e.subwindow = window;
      e.time = GDK_CURRENT_TIME;
      e.x = 0.0;
      e.y = 0.0;
      e.x_root = 0.0;
      e.y_root = 0.0;
      e.mode = GDK_CROSSING_NORMAL;
      e.detail = GDK_NOTIFY_ANCESTOR;
      e.focus = TRUE;               /* Focus. */
      e.state = 0;                  /* Key modifiers. */
      gdk_event_put((GdkEvent *)&e);
}

/*
 *    Enables/disables global tooltips state.
 */
void GUISetGlobalTipsState(gbool state)
{
        /* Create global tooltips as needed. */
        GUICreateGlobalTooltips();
        if(gui_tooltips == NULL)
          return;

      if(state)
          gtk_tooltips_enable(gui_tooltips);
      else
          gtk_tooltips_disable(gui_tooltips);

      /* Update global tool tips state. */
      gui_tooltips_state = (state) ? TRUE : FALSE;
}


/*
 *    Changes the layout, showing or hiding the pixmap and label.
 *    The given button must be one returned from GUIButtonPixmap*()
 *    or GUIToggleButtonPixmap*().
 */
void GUIButtonChangeLayout(void *button, int show_pixmap, int show_label)
{
      GtkWidget *w;
      gui_button_data_struct *btn_data;


      if(button == NULL)
          return;

      btn_data = (gui_button_data_struct *)gtk_object_get_user_data(
          (GtkObject *)button
      );
      if(btn_data == NULL)
          return;

      w = (GtkWidget *)btn_data->label_normal;
      if(w != NULL)
      {
          if(show_label)
            gtk_widget_show(w);
          else
            gtk_widget_hide(w);
      }

        w = (GtkWidget *)btn_data->pixmap_normal;
        if(w != NULL)
        {
            if(show_pixmap)
                gtk_widget_show(w); 
            else
                gtk_widget_hide(w);
        }
}

/*
 *      Changes the icon and/or label text. If any value is NULL then it
 *    will not be modified.
 *
 *      The given button must be one returned from GUIButtonPixmap*()
 *      or GUIToggleButtonPixmap*().
 */
void GUIButtonPixmapUpdate(void *button, u_int8_t **icon, const char *label)
{
      gboolean need_redraw = FALSE;
        GtkWidget *w, *parent;
        gui_button_data_struct *btn_data;


        if(button == NULL)
            return;

        btn_data = (gui_button_data_struct *)gtk_object_get_user_data(
            (GtkObject *)button
        );
        if(btn_data == NULL)
            return;

      parent = btn_data->main_box;
      if(parent == NULL)
          return;

        /* Update icon? */
        if(icon != NULL)
        {
            GtkStyle *style = gtk_widget_get_style((GtkWidget *)button);
            GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();

            if((style != NULL) && (window != NULL))
            {
                GdkBitmap *mask;
                GdkPixmap *pixmap;

            /* Load new icon pixmap and mask pair from the given data. */
                pixmap = gdk_pixmap_create_from_xpm_d(
                    window, &mask,
                    &style->bg[GTK_STATE_NORMAL],
                    (gchar **)icon
                );
            /* Loaded successfully? */
            if(pixmap != NULL)
            {
                /* Get GtkPixmap widget and update it with the newly
                 * loaded pixmap and mask pair.
                 */
                w = btn_data->pixmap_normal;
                if(w == NULL)
                {
                  btn_data->pixmap_normal = w =
                      gtk_pixmap_new(pixmap, mask);
                  gtk_box_pack_start(GTK_BOX(parent), w, TRUE, FALSE, 0);
                  gtk_widget_show(w);
                }
                else
                {
                  gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
                }

                /* Unref the loaded pixmap and mask pair, they are no
                 * longer needed.
                 */
                gdk_pixmap_unref(pixmap);
                if(mask != NULL)
                  gdk_bitmap_unref(mask);
            }
            }
      }

      /* Update text? */
      if(label != NULL)
      {
          w = btn_data->label_normal;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), label);
      }

      /* Redraw button as needed. */
      if(need_redraw && (btn_data->button != NULL))
          gtk_widget_queue_draw(btn_data->button);
}


/*
 *      Creates a push button widget with the specified icon
 *      data created as a pixmap placed into it and the label.
 *
 *    If orient is set to 1 then the orientation will be horizontal,
 *    otherwise vertical.
 */
void *GUIButtonPixmapLabelHV(
      u_int8_t **icon, const char *label, void **label_rtn,
      int orient
)
{
        GtkWidget *w, *parent, *labelwid = NULL, *pixmapwid = NULL;
        GtkWidget *button = gtk_button_new();
      gint width = 0, height = 0;
      gui_button_data_struct *btn_data;


      if(label_rtn != NULL)
          *label_rtn = NULL;

      if(button == NULL)
          return(button);

      /* Allocate button data. */
      btn_data = (gui_button_data_struct *)g_malloc0(
          sizeof(gui_button_data_struct)
      );
      if(btn_data != NULL)
          btn_data->button = button;

      /* Store button data as user data on button as object. */
      gtk_object_set_user_data(GTK_OBJECT(button), (gpointer)btn_data);

      /* Connect destroy event to button so that the button data can be
       * deallocated.
       */
      gtk_signal_connect(
          GTK_OBJECT(button), "destroy",
          GTK_SIGNAL_FUNC(GUIButtonDestroyCB), btn_data
      );


      /* Box in button for parenting. */
      if(orient == 1)
          w = gtk_hbox_new(FALSE, 0);
      else
          w = gtk_vbox_new(FALSE, 0);
      gtk_container_add(GTK_CONTAINER(button), w);
        gtk_widget_show(w);
      parent = w;

        if(btn_data != NULL)
            btn_data->main_box = parent;


      /* Create icon pixmap? */
      if(icon != NULL)
      {
          GtkStyle *style;
          GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();


          /* Get style of button or default style. */
          style = gtk_widget_get_style(button);
          if(style == NULL)
            style = gtk_widget_get_default_style();

          if((style != NULL) && (window != NULL))
          {
            GdkBitmap *mask;
            GdkPixmap *pixmap;

                /* Load new icon pixmap and mask pair from the given data. */
              pixmap = gdk_pixmap_create_from_xpm_d(
                window, &mask,
                &style->bg[GTK_STATE_NORMAL], (gchar **)icon
            );
            /* Loaded successfully? */
            if(pixmap != NULL)
            {
                pixmapwid = w = gtk_pixmap_new(pixmap, mask);
                if(btn_data != NULL)
                  btn_data->pixmap_normal = w;
                gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
                gtk_box_pack_start(GTK_BOX(parent), w, TRUE, FALSE, 0);
                gtk_widget_show(w);

                    /* Unref the loaded pixmap and mask pair, they are no
                     * longer needed.
                     */
                gdk_pixmap_unref(pixmap);
                if(mask != NULL)
                  gdk_bitmap_unref(mask);
            }
          }
      }

      /* Create label? */
      if(label != NULL)
      {
          labelwid = w = gtk_label_new(label);
            if(btn_data != NULL)
                btn_data->label_normal = w;
            if(label_rtn != NULL)
                *label_rtn = w;
          gtk_label_set_justify(
            GTK_LABEL(w),
                (orient == 1) ? GTK_JUSTIFY_LEFT : GTK_JUSTIFY_CENTER
          );
            gtk_box_pack_start(GTK_BOX(parent), w, TRUE, FALSE, 0);
            gtk_widget_show(w);
      }
      else
      {
          /* If label is NULL then match size of button to exact
           * size of pixmap.
           */
          if((width != 0) && (height != 0))
          {
            gtk_widget_set_usize(button, width + 2, height + 2);
          }
      }

      return(button);
}

/*              
 *      Creates a push button widget with the specified icon
 *      data created as a pixmap placed into it and the label          
 *      separated horizontally.
 */
void *GUIButtonPixmapLabelH(
      u_int8_t **icon, const char *label, void **label_rtn
)
{
      return(GUIButtonPixmapLabelHV(icon, label, label_rtn, 1));
}

/*      
 *      Creates a push button widget with the specified icon
 *      data created as a pixmap placed into it and the label
 *      separated vertically.
 */
void *GUIButtonPixmapLabelV(
      u_int8_t **icon, const char *label, void **label_rtn
)
{
        return(GUIButtonPixmapLabelHV(icon, label, label_rtn, 0));
}

/*
 *      Creates a push button widget with the specified icon
 *      data created as a pixmap placed into it.
 */
void *GUIButtonPixmap(u_int8_t **icon)
{
        return(
            GUIButtonPixmapLabelH(icon, NULL, NULL)
        );
}


/*
 *      Creates a toggle button widget with the specified icon
 *      data created as a pixmap placed into it and the label.
 *
 *      If orient is set to 1 then the orientation will be horizontal,
 *      otherwise vertical.
 */
void *GUIToggleButtonPixmapLabelHV(
      u_int8_t **icon, const char *label, void **label_rtn, int orient
)
{
        GtkWidget *w, *parent, *labelwid = NULL, *pixmapwid = NULL;
        GtkWidget *button = gtk_toggle_button_new();
        gint width = 0, height = 0;
      gui_button_data_struct *btn_data;


        if(label_rtn != NULL)
            *label_rtn = NULL;

        if(button == NULL)
            return(button);

        /* Allocate button data. */
        btn_data = (gui_button_data_struct *)g_malloc0(
          sizeof(gui_button_data_struct)
        );
        if(btn_data != NULL)
            btn_data->button = button;
 
        /* Store button data as user data on button as object. */
        gtk_object_set_user_data(GTK_OBJECT(button), (gpointer)btn_data);

        /* Connect destroy event to button so that the button data can be
         * deallocated. 
         */
        gtk_signal_connect(
            GTK_OBJECT(button), "destroy",
            GTK_SIGNAL_FUNC(GUIButtonDestroyCB), btn_data
        );


        /* Box in button for parenting. */
        if(orient == 1)
            w = gtk_hbox_new(FALSE, 0);
        else
            w = gtk_vbox_new(FALSE, 0);
        gtk_container_add(GTK_CONTAINER(button), w);
        gtk_widget_show(w);
      parent = w;

        if(btn_data != NULL)
            btn_data->main_box = parent;

        /* Create icon pixmap? */
        if(icon != NULL)
        {
            GtkStyle *style = gtk_widget_get_style(button);
            GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();

            if((style != NULL) && (window != NULL))
            {
                GdkBitmap *mask;
                GdkPixmap *pixmap;

                pixmap = gdk_pixmap_create_from_xpm_d(
                    window, &mask,
                    &style->bg[GTK_STATE_NORMAL], (gchar **)icon
                );
            if(pixmap != NULL)
            {
                pixmapwid = w = gtk_pixmap_new(pixmap, mask);
                if(btn_data != NULL)
                  btn_data->pixmap_normal = w;
                gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
                gtk_box_pack_start(
                  GTK_BOX(parent), w, TRUE, FALSE, 0
                );
                gtk_widget_show(w);

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

      /* Create label? */
        if(label != NULL)
        {
            labelwid = w = gtk_label_new(label);
          if(btn_data != NULL)
            btn_data->label_normal = w;
            if(label_rtn != NULL)
                (*label_rtn) = w;
            gtk_label_set_justify(
            GTK_LABEL(w),
            (orient == 1) ? GTK_JUSTIFY_LEFT : GTK_JUSTIFY_CENTER
          );
            gtk_box_pack_start(
                GTK_BOX(parent), w, TRUE, FALSE, 0
            );
            gtk_widget_show(w);
        }
        else
        {
            /* If label is NULL then match size of button to exact
             * size of pixmap.
             */
            if((width != 0) && (height != 0))
            {
                gtk_widget_set_usize(button, width + 2, height + 2);
            }
        }

        return(button);
}

/*
 *      Creates a toggle button widget with the specified icon
 *      data created as a pixmap placed into it and the label
 *    oriented horizontally.
 */
void *GUIToggleButtonPixmapLabelH(
      u_int8_t **icon, const char *label, void **label_rtn
)
{
        return(GUIToggleButtonPixmapLabelHV(icon, label, label_rtn, 1));
}

/*
 *      Creates a toggle button widget with the specified icon
 *      data created as a pixmap placed into it and the label
 *      oriented vertically.
 */
void *GUIToggleButtonPixmapLabelV(
      u_int8_t **icon, const char *label, void **label_rtn
)
{
        return(GUIToggleButtonPixmapLabelHV(icon, label, label_rtn, 0));
}

/*
 *      Creates a toggle button widget with the specified icon
 *      data created as a pixmap placed into it.
 */             
void *GUIToggleButtonPixmap(u_int8_t **icon)
{
        return(GUIToggleButtonPixmapLabelHV(icon, NULL, NULL, 0)); 
}


/*
 *    Creates a prompt bar, consisting of an icon, label and text
 *    entry widgets.
 *
 *    If browse_rtn is not NULL then a browse button will be created
 *    as well.
 */
void *GUIPromptBarOrBrowse(
        u_int8_t **icon, const char *label,
      void **label_rtn, void **entry_rtn, void **browse_rtn
)
{
      gint border_minor = 2;
      GtkWidget *parent, *w;


      /* Reset returns. */
        if(label_rtn != NULL)
            *label_rtn = NULL;
      if(entry_rtn != NULL)
          *entry_rtn = NULL;
      if(browse_rtn != NULL)
          *browse_rtn = NULL;

      /* Create prompt bar parent. */
      w = gtk_table_new(
          1,
          ((icon != NULL) ? 1 : 0) +
          ((label != NULL) ? 1 : 0) +
            1 +
          ((browse_rtn != NULL) ? 1 : 0),
          FALSE
      );
      /* Do not show parent to prompt bar. */
      parent = w;

      /* Create icon. */
      if(icon != NULL)
      {
          gint attach_x = 0;
          gint width, height;
            GtkStyle *style = gtk_widget_get_style(parent);
            GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();
          GtkWidget *pixmapwid;

          w = gtk_fixed_new();
            gtk_table_attach(
            GTK_TABLE(parent), w,
                attach_x, attach_x + 1,
                0, 1,
                0,
                0,
                border_minor / 2, 0
            );
          gtk_widget_show(w);

            if((style != NULL) && (window != NULL))
            {
                GdkBitmap *mask;
                GdkPixmap *pixmap;

                pixmap = gdk_pixmap_create_from_xpm_d(
                    window, &mask,
                    &style->bg[GTK_STATE_NORMAL], (gchar **)icon
                );
            if(pixmap != NULL)
            {
                pixmapwid = gtk_pixmap_new(pixmap, mask);
                gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
                gtk_fixed_put(GTK_FIXED(w), pixmapwid, 0, 0);
                gtk_widget_set_usize(w, width, height);
                gtk_widget_show(pixmapwid);

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

      /* Create label? */
      if(label != NULL)
      {
            gint attach_x = (icon != NULL) ? 1 : 0;
          GtkWidget *parent2;

          w = gtk_hbox_new(FALSE, 0);
          gtk_table_attach(
                GTK_TABLE(parent), w,  
                attach_x, attach_x + 1,
                0, 1,
                GTK_FILL,
                0,  
                border_minor / 2, 0
            );
          gtk_widget_show(w);
          parent2 = w;

          w = gtk_label_new(label);
          if(label_rtn != NULL)
            *label_rtn = w;
          gtk_box_pack_end(GTK_BOX(parent2), w, TRUE, TRUE, 0);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
          gtk_widget_show(w);
      }

      /* Create text entry? */
      if(TRUE)
      {
            gint attach_x = ((icon != NULL) ? 1 : 0) +
            ((label != NULL) ? 1 : 0);

          w = gtk_entry_new();
          if(entry_rtn != NULL)
            *entry_rtn = w;
          gtk_table_attach(
            GTK_TABLE(parent), w,
                attach_x, attach_x + 1,
                0, 1,
                GTK_SHRINK | GTK_EXPAND | GTK_FILL,
                0,
                border_minor / 2, 0
            );
            gtk_widget_show(w);
      }

      /* Create browse button? */
      if(browse_rtn != NULL)
      {
            gint attach_x = ((icon != NULL) ? 1 : 0) +
                ((label != NULL) ? 1 : 0) +
            1;

          w = (GtkWidget *)GUIButtonPixmap(
            (u_int8_t **)icon_browse_20x20_xpm
          );
          if(w != NULL)
          {
            *browse_rtn = w;
            gtk_widget_set_usize(w, 20 + 2, 20 + 2);
                gtk_table_attach(
                GTK_TABLE(parent), w,
                    attach_x, attach_x + 1,
                    0, 1,
                    0,
                    0,
                    border_minor / 2, 0
                );
                gtk_widget_show(w);
          }
      }

      return(parent);
}

/*
 *    Creates prompt bar with browse button.
 */
void *GUIPromptBarWithBrowse(
        u_int8_t **icon, const char *label,
        void **label_rtn, void **entry_rtn, void **browse_rtn,
      void *browse_client_data, void (*browse_cb)(void *, void *)
)
{
      GtkWidget *parent;

      parent = GUIPromptBarOrBrowse(
          icon, label, label_rtn, entry_rtn, browse_rtn
      );

      /* Set signal callback for the browse button. */
      if((browse_rtn != NULL) && (browse_cb != NULL))
      {
          GtkWidget *w = (GtkWidget *)*browse_rtn;
          if(w != NULL)
                gtk_signal_connect(
                    GTK_OBJECT(w), "clicked",
                    GTK_SIGNAL_FUNC(browse_cb),
                    (gpointer)browse_client_data
                );
      }

      return(parent);
}

/*
 *    Creates a new prompt bar.
 */
void *GUIPromptBar(
        u_int8_t **icon, const char *label,
        void **label_rtn, void **entry_rtn
)
{
      return(GUIPromptBarOrBrowse(
            icon, label, label_rtn, entry_rtn, NULL
        ));
}


/*
 *    Sets up widget as a DND drag source.
 */
void GUIDNDSetSrc(
        void *w, const void *drag_type, int ndrag_types,
        unsigned int actions, unsigned int buttons,
        void (*begin_cb)(GtkWidget *, GdkDragContext *, gpointer),
        void (*request_data_cb)(GtkWidget *, GdkDragContext *,
                GtkSelectionData *, guint, guint, gpointer),
        void (*delete_data_cb)(GtkWidget *, GdkDragContext *, gpointer),
        void (*end_cb)(GtkWidget *, GdkDragContext *, gpointer),
        gpointer client_data
)
{
      GtkWidget *widget = (GtkWidget *)w;
      const GtkTargetEntry *target_entry = (const GtkTargetEntry *)drag_type;
      gint total_target_entries = (gint)ndrag_types;


      if((widget == NULL) ||
           (target_entry == NULL) ||
           (total_target_entries <= 0)
      )
          return;

      /* Widget must have window. */
      if(GTK_WIDGET_NO_WINDOW(widget))
      {
          fprintf(stderr,
 "GUIDNDSetSrc(): Widget does not have window.\n"
          );
          return;
      }

      /* Set this widget as a DND drag source. */
      gtk_drag_source_set(
          widget,
          buttons,
          target_entry, total_target_entries,
          actions
      );

      /* Set drag begin callback, our local callback must be connected
       * before GTK internal drag begin callbacks.
       */
        gtk_signal_connect(
            GTK_OBJECT(widget), "drag_begin",
            GTK_SIGNAL_FUNC(GUIDNDDragBeginCB), NULL
        );
      if(begin_cb != NULL)
          gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_begin",
            GTK_SIGNAL_FUNC(begin_cb), client_data
          );

      /* Set drag data request/get callback. */
      if(request_data_cb != NULL)
          gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_data_get",
            GTK_SIGNAL_FUNC(request_data_cb), client_data
          );

      /* Set drag data delete callback. */
      if(delete_data_cb != NULL)
          gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_data_delete",
            GTK_SIGNAL_FUNC(delete_data_cb), client_data
          );

      /* Set drag end callback. */
        if(end_cb != NULL)
            gtk_signal_connect_after(
                GTK_OBJECT(widget), "drag_end",
                GTK_SIGNAL_FUNC(end_cb), client_data
            );

      /* Set our own drag_end callback to be called after the one for
       * the client function.
       */
        gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_end",
            GTK_SIGNAL_FUNC(GUIDNDDragEndCB), NULL
        );
}

/*
 *    Sets up a widget as DND drop target.
 */
void GUIDNDSetTar(
        void *w, const void *drag_type, int ndrag_types,
        unsigned int actions, unsigned int default_action_same,
      unsigned int default_action,
        void (*recieved_data_cb)(GtkWidget *, GdkDragContext *,  
                gint, gint, GtkSelectionData *, guint, guint,  
                gpointer     
        ),
        gpointer client_data
)
{
      static gboolean init_cb_structs = TRUE;
        GtkWidget *widget = (GtkWidget *)w;
        const GtkTargetEntry *target_entry = (const GtkTargetEntry *)drag_type;
        gint total_target_entries = (gint)ndrag_types;
      static gui_dnd_cb_struct      move_same_cb_data,
                              move_cb_data,
                              copy_cb_data;
      gui_dnd_cb_struct *cb_data_ptr = NULL;


        if((widget == NULL) || 
           (target_entry == NULL) ||
           (total_target_entries <= 0)
        )
            return;

        /* Widget must have window. */
        if(GTK_WIDGET_NO_WINDOW(widget))
        {   
            fprintf(
            stderr,
 "GUIDNDSetTar(): Widget does not have window.\n"
            );
            return;
        }

      /* Set widget as a DND drop target. */
      gtk_drag_dest_set(
          widget,
          GTK_DEST_DEFAULT_MOTION |
          GTK_DEST_DEFAULT_HIGHLIGHT |
          GTK_DEST_DEFAULT_DROP,
            target_entry, total_target_entries,
            actions
        );


      /* Need to initialize DND callback data structures? */
      if(init_cb_structs)
      {
          move_same_cb_data.default_action_same = GDK_ACTION_MOVE;
          move_same_cb_data.default_action = GDK_ACTION_COPY;

            move_cb_data.default_action_same = GDK_ACTION_MOVE;
            move_cb_data.default_action = GDK_ACTION_MOVE;

            copy_cb_data.default_action_same = GDK_ACTION_COPY;
          copy_cb_data.default_action = GDK_ACTION_COPY;

          init_cb_structs = FALSE;  /* Mark as no longer needing init. */
      }

      /* Set local drag motion callback data. */
      /* Move only on same? */
      if((default_action_same == GDK_ACTION_MOVE) &&
           (default_action == GDK_ACTION_COPY)
      )
          cb_data_ptr = &move_same_cb_data;
      /* Always move? */
      else if((default_action_same == GDK_ACTION_MOVE) &&
                (default_action == GDK_ACTION_MOVE)
        )
            cb_data_ptr = &move_cb_data;
      /* Always copy? */
      else if((default_action_same == GDK_ACTION_COPY) &&
                (default_action == GDK_ACTION_COPY)
      )
          cb_data_ptr = &copy_cb_data;


      /* Set this target widget to highlight when a drag goes over it. */
/*    gtk_drag_highlight(widget); */


      /* Set our local drag motion callback. */
      gtk_signal_connect_after(
          GTK_OBJECT(widget), "drag_motion",
          GTK_SIGNAL_FUNC(GUIDNDDragMotionCB),
          (gpointer)cb_data_ptr
      );
        gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_drop",
            GTK_SIGNAL_FUNC(GUIDNDDragDropCB),
            (gpointer)cb_data_ptr
        );

        /* Set data received callback for local and calling functions. */
        gtk_signal_connect_after(
            GTK_OBJECT(widget), "drag_data_received",
            GTK_SIGNAL_FUNC(GUIDNDDragReceivedCB),
            (gpointer)cb_data_ptr
        );
        if(recieved_data_cb != NULL)
            gtk_signal_connect_after(
                GTK_OBJECT(widget), "drag_data_received",
                GTK_SIGNAL_FUNC(recieved_data_cb), client_data
            );
}

/*
 *    Sets the next drag icon to be used from the given pixmap and
 *    mask pair.
 */
void GUIDNDSetDragIcon(
      GdkPixmap *pixmap, GdkBitmap *mask, gint hot_x, gint hot_y
)
{
      gboolean is_pixmap_set = FALSE;
      GdkWindow *window;
      GtkWidget *w;
      gui_dnd_icon_struct *dnd_icon = &gui_dnd_icon;


      if(pixmap == NULL)
          return;

      /* Initialize drag icon widgets? */
      w = dnd_icon->toplevel;
      if(w == NULL)
      {
          GtkWidget *parent;


          dnd_icon->toplevel = w = gtk_window_new(GTK_WINDOW_POPUP);
          gtk_widget_realize(w);
          parent = w;

          dnd_icon->icon_pm = w = gtk_pixmap_new(pixmap, mask);
          gtk_container_add(GTK_CONTAINER(parent), w);
          gtk_widget_show(w);
          is_pixmap_set = TRUE;
      }
      w = dnd_icon->toplevel;
      if(w == NULL)
          return;

      window = w->window;
      if(window == NULL)
          return;

      /* Set up dnd icon structure. */
      dnd_icon->x = hot_x;
      dnd_icon->y = hot_y;

      gdk_window_get_size(
          (GdkWindow *)pixmap,
          &dnd_icon->width, &dnd_icon->height
      );

      /* Adjust size and shape of the drag icon's toplevel window. */
      gtk_widget_set_usize(w, dnd_icon->width, dnd_icon->height);
        gdk_window_set_back_pixmap(window, pixmap, 0);
      gtk_widget_shape_combine_mask(w, mask, 0, 0);


      /* Set up icon GtkPixmap. */
      w = dnd_icon->icon_pm;
      if((w != NULL) && !is_pixmap_set)
      {
          gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);
      }
}

/*
 *    Creates a new banner widget.
 */
GtkWidget *GUIBannerCreate(
        const gchar *label, const gchar *font_name,
        GdkColor color_fg, GdkColor color_bg,
        gint align,             /* One of GTK_JUSTIFY_*. */
        gbool expand
)
{
      GdkFont *font = NULL;
      GtkRcStyle *rcstyle;
      GtkWidget *w = gtk_drawing_area_new();
      gpointer *cb_data = (gpointer *)g_malloc0(
          4 * sizeof(gpointer)
      );


#define ALPHABET_STR    "\
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"

      /* Set up callback data. */
      if(cb_data != NULL)
      {
          cb_data[0] = STRDUP(label);
          cb_data[1] = (gpointer)align;
          cb_data[2] = font = ((font_name != NULL) ?
            gdk_font_load(font_name) : NULL
          );
          cb_data[3] = NULL;
      }

      /* Connect expose_event signal for redrawing. */
        gtk_signal_connect(
            GTK_OBJECT(w), "expose_event",
            GTK_SIGNAL_FUNC(GUIBannerExposeCB),
          (gpointer)cb_data
        );
      gtk_widget_add_events(w, GDK_EXPOSURE_MASK);
      /* Destroy signal, for deallocaing coppied label. */
        gtk_signal_connect(
            GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(GUIBannerDestroyCB),
            (gpointer)cb_data
        );

      /* Set style. */
      rcstyle = gtk_rc_style_new();
      if(font_name != NULL)
      {
          g_free(rcstyle->font_name);
          rcstyle->font_name = STRDUP(font_name);
      }
        rcstyle->color_flags[GTK_STATE_NORMAL] = GTK_RC_FG | GTK_RC_BG;
      rcstyle->color_flags[GTK_STATE_INSENSITIVE] = GTK_RC_FG | GTK_RC_BG;
      memcpy(&rcstyle->fg[GTK_STATE_NORMAL], &color_fg, sizeof(GdkColor));
        memcpy(&rcstyle->bg[GTK_STATE_NORMAL], &color_bg, sizeof(GdkColor));
      /* Modify foreground and background colors for insensitive. */
#define LOWER_VALUE(c)  (gushort)((((gint)(c) - (gint)((guint16)-1 / 2)) * 0.75) + \
(gint)((guint16)-1 / 2))
      color_fg.red = LOWER_VALUE(color_fg.red);
      color_fg.green = LOWER_VALUE(color_fg.green);
      color_fg.blue = LOWER_VALUE(color_fg.blue);
        color_bg.red = LOWER_VALUE(color_bg.red);
        color_bg.green = LOWER_VALUE(color_bg.green);
        color_bg.blue = LOWER_VALUE(color_bg.blue);
#undef LOWER_VALUE
        memcpy(&rcstyle->fg[GTK_STATE_INSENSITIVE], &color_fg, sizeof(GdkColor));
        memcpy(&rcstyle->bg[GTK_STATE_INSENSITIVE], &color_bg, sizeof(GdkColor));

      gtk_widget_modify_style(w, rcstyle);

      GUIRCStyleDeallocUnref(rcstyle);
      rcstyle = NULL;


      /* Get new style values from widget. */
        if(font != NULL)
        {
          gint width, height;


          if(expand)
            width = -1;
          else if(font != NULL)
            width = gdk_string_width(
                font, (label == NULL) ? ALPHABET_STR : label
            );
          else
            width = -1;

          if(font != NULL)
            height = gdk_string_height(
                font, (label == NULL) ? ALPHABET_STR : label) + 6;
          else
            height = -1;
  
          gtk_widget_set_usize(w, width, height);
        }

#undef ALPHABET_STR

      return(w);
}

/*
 *    Creates a new combo box and label, the combo box and label
 *    will be placed inside of a table.
 *
 *    The return value wil be the table widget or NULL on failure.
 *
 *    The given GList of strings list will be duplicated and the one
 *    passed to this list will not be modified.
 */
void *GUIComboCreate(
        const char *label,
        const char *text,       /* Initial text. */
        void *list,             /* Initial glist of items for combo list. */
        int max_items,          /* Maximum items allowed. */
      void **combo_rtn, /* Combo widget return. */
        void *client_data,
        void (*func_cb)(GtkWidget *w, void *),
      void (*list_change_cb)(GtkWidget *, void *, GList *)
)
{
      GtkWidget *parent, *wlabel = NULL, *w;
        GtkCombo *combo;
      const gchar *cstrptr;
      gpointer *cb_data;


      /* Reset return values. */
      if(combo_rtn != NULL)
          *combo_rtn = NULL;

      /* Create parent table widget. */
      parent = gtk_table_new(
          1,
          ((label != NULL) ? 1 : 0) +
          1,
          FALSE
      );
      /* Do not show the table parent. */

      /* Create label? */
      if(label != NULL)
      {
          gint x = 0;

          wlabel = gtk_label_new(label);
            gtk_table_attach(
            GTK_TABLE(parent), wlabel,
                x, x + 1,
                0, 1,
                0,
                0,
                2, 2
            );
          gtk_label_set_justify(GTK_LABEL(wlabel), GTK_JUSTIFY_RIGHT);
          gtk_widget_show(wlabel);
      }

      /* Create combo. */
      if(TRUE)
      {
          gint i;
          gint x = (label != NULL) ? 1 : 0;
          GList *glist_in, *glist_out;
          GtkEntry *entry;


          w = gtk_combo_new();
          combo = GTK_COMBO(w);
          entry = GTK_ENTRY(combo->entry);
          if(combo_rtn != NULL)
            *combo_rtn = w;
            gtk_table_attach(
            GTK_TABLE(parent), w,
                x, x + 1,
                0, 1,
                GTK_SHRINK | GTK_EXPAND | GTK_FILL,
                0,
                2, 2
            );
          gtk_combo_disable_activate(combo);
          gtk_entry_set_text(entry, (text != NULL) ? text : "");
            gtk_entry_set_editable(entry, TRUE);
            gtk_combo_set_case_sensitive(combo, FALSE);


          /* Begin creating output glist, a duplicate input glist. */
          glist_out = NULL;
          glist_in = (GList *)list;

          /* Is input glist given? */
          if(glist_in == NULL)
          {
            /* Input glist is NULL so create a bunch of empty strings
             * totalling that specified by max_items for the output
             * glist.
             */
            for(i = 0; i < max_items; i++)
                glist_out = g_list_append(glist_out, STRDUP(""));
          }
          else
          {
            /* Input glist is given, make a duplicate of it as the
             * output glist.
             */
            i = 0;
            while((i < max_items) && (glist_in != NULL))
            {
                cstrptr = (const gchar *)glist_in->data;
                glist_out = g_list_append(
                  glist_out, STRDUP(cstrptr)
                );
                glist_in = glist_in->next;
                i++;
            }
          }
          glist_in = NULL;    /* Input glist should no longer be used. */

          /* Set new output glist to combo box. */
          if(glist_out != NULL)
            gtk_combo_set_popdown_strings(combo, glist_out);

          /* Do not delete the output glist, it will be passed to the
           * callback data below.
           */

          /* Allocate callback data, 9 pointers of format;
           * table            Parent table that holds this combo and label.
           * label            Label (may be NULL).
           * combo            This combo widget.
           * GList            Contains list of strings in combo list.
           * max_items  Max items allowed in combo list.
           * client_data      Calling function set callback data.
           * func_cb          Calling function set callback function.
           * list_change_cb   Calling function set list change function.
           * NULL
           */
          cb_data = (gpointer *)g_malloc0(9 * sizeof(gpointer));
          cb_data[0] = parent;
          cb_data[1] = wlabel;
          cb_data[2] = combo;
          cb_data[3] = glist_out;
          cb_data[4] = (gpointer)MAX(max_items, 0);
            cb_data[5] = client_data;
            cb_data[6] = (gpointer)func_cb;
          cb_data[7] = (gpointer)list_change_cb;
          cb_data[8] = NULL;

          /* Record pointer to cb_data pointer array in the
           * combo object's user data.
           */
          gtk_object_set_user_data(GTK_OBJECT(combo), cb_data);

          /* Set signal handlers for combo's entry widget to local
           * callbacks.
           */
            gtk_signal_connect(
                GTK_OBJECT(combo), "destroy",
                GTK_SIGNAL_FUNC(GUIComboDestroyCB), cb_data
            );
            gtk_signal_connect(
                GTK_OBJECT(entry), "activate",
                GTK_SIGNAL_FUNC(GUIComboActivateCB), cb_data
            );
            gtk_signal_connect(
                GTK_OBJECT(entry), "changed",
                GTK_SIGNAL_FUNC(GUIComboChangedCB), cb_data
            );

          gtk_widget_show(w);
      }

      return(parent);
}

/*
 *    Adds the specified value to the combo widget w's list and current
 *    value for the combo widget's entry widget.
 *
 *    The item will only be added to the list if it is not NULL
 *    and does not already exist in the list.
 *
 *    Excess items may be truncated if adding this item would exceed
 *    the combo list's maximum allowed items.
 */
void GUIComboActivateValue(void *w, const char *value)
{
      gpointer *cb_data;
      GtkCombo *combo = (GtkCombo *)w;
      if((combo == NULL) || (value == NULL))
          return;

      cb_data = (gpointer *)gtk_object_get_user_data(GTK_OBJECT(combo));
      if(cb_data == NULL)
          return;

      /* Set new value on combo's entry widget. */
      gtk_entry_set_text(
          GTK_ENTRY(combo->entry), value
      );

      /* Call activate callback as if this was an actual activate
       * signal.
       */
      GUIComboActivateCB(GTK_WIDGET(combo), (gpointer)cb_data);
}

/*
 *    Adds the given value to the beginning of the glist for the
 *    combo box w. Older items in the list may be truncated if adding
 *    a new value would exceed the set maximum items for the combo box.
 *
 *    If value is already in the list then no operation will be
 *    performed.
 *
 *    The combo box's set list change callback will be called if it is
 *    not NULL and the new value was different and added succesfully.
 */
void GUIComboAddItem(void *w, const char *value)
{
      gint i, max_items;
        gboolean status;
      const gchar *cstrptr;
        GtkWidget *parent, *wlabel;
        GtkCombo *combo;
        GList *glist_in, *glist_next_in;
        gpointer client_data;
        void (*func_cb)(GtkWidget *, gpointer);
        void (*list_change_cb)(GtkWidget *, gpointer, GList *);
      gpointer *cb_data;


        if((w == NULL) || (value == NULL))
          return;

      combo = GTK_COMBO(w);


      /* Get object callback data. */
        cb_data = (gpointer *)gtk_object_get_user_data(GTK_OBJECT(combo));
        if(cb_data == NULL)
            return;

        /* Parse callback data, format is as follows;
         * table        Parent table that holds this combo and label.
         * label        Label (may be NULL).
         * combo        This combo widget.
         * GList        Contains list of strings in combo list.
         * max_items    Max items allowed in combo list.
         * client_data  Calling function set callback data.
         * func_cb      Calling function set callback function.
         * list_change_cb       Calling function set list change function.
         * NULL
         */
        parent = (GtkWidget *)(cb_data[0]);
        wlabel = (GtkWidget *)(cb_data[1]);
        combo = (GtkCombo *)(cb_data[2]);
        glist_in = (GList *)(cb_data[3]);
        max_items = (int)(cb_data[4]);
        client_data = (void *)(cb_data[5]);
        func_cb = cb_data[6];
        list_change_cb = cb_data[7];


        /* Check if new value is already in the input glist. */
        status = TRUE;
        i = 0;
        glist_next_in = glist_in;
      /* Iterate from 0 to max_items or when the input glist is
       * NULL (whichever occures first).
       */
        while((i < max_items) && (glist_next_in != NULL))
        {
            cstrptr = (gchar *)glist_next_in->data;
            if(cstrptr != NULL)
            {
 /* Check if case sensitive? */
                /* Compare list item value with given value. */
                if(!g_strcasecmp(cstrptr, value))
                {
                /* Given value matches a value in the list, so set
                 * status to FALSE indicating there is a value already
                 * in the list.
                 */
                    status = FALSE;
                    break;
                }
            }
            i++;
            glist_next_in = glist_next_in->next;
        }
      /* Variable status will be set to FALSE if the value is already
       * in the list.
       */

      /* Check if max_items allows us to add a new item to the list and
       * if status is TRUE (indicating value is not already in the
       * list).
       */
        if((max_items > 0) && status)
        { 
            /* Create new output glist. */
            GList *glist_out = NULL;

            /* Add first item in output glist to be the new value fetched
           * from the combo's entry.
             */
            glist_out = g_list_append(glist_out, STRDUP(value));
        
            /* Now copy old input glist items to output glist, starting
           * with i = 1 since we already have one item in the output
           * glist.
             */
            i = 1;
            glist_next_in = glist_in;
            while((i < max_items) && (glist_next_in != NULL)) 
            {
                cstrptr = (const char *)glist_next_in->data;
                glist_out = g_list_append(glist_out, STRDUP(cstrptr));
                glist_next_in = glist_next_in->next;
                i++;
            }

            /* Set new output glist to the combo box's list. */
            if(glist_out != NULL)
                gtk_combo_set_popdown_strings(combo, glist_out);

            /* Free old input glist since its no longer being used. */
            if(glist_in != NULL)
            {
                g_list_foreach(glist_in, (GFunc)g_free, NULL);
                g_list_free(glist_in);
                glist_in = NULL;
            }

            /* Update input glist to be that of the output glist. */
            glist_in = glist_out;

            /* Record new glist on callback data. */
            cb_data[3] = (void *)glist_in;

            /* Call list change function and pass the new glist. */
            if(list_change_cb != NULL)
            {
                list_change_cb(
                    (GtkWidget *)combo, /* Pass combo box as widget. */
                    client_data,        /* Client data. */
                    glist_in            /* New glist. */
                );
            }
        }
}

/*
 *    Returns the GList for the combo widget created by
 *    GUIComboCreate().
 */
void *GUIComboGetList(void *w)
{
      gpointer *cb_data;
      GtkCombo *combo = (GtkCombo *)w;
      if(combo == NULL)
          return(NULL);

      cb_data = (gpointer *)gtk_object_get_user_data(GTK_OBJECT(combo));
      if(cb_data == NULL)
          return(NULL);

        /* Parse callback data, format is as follows;
         * table            Parent table that holds this combo and label.
         * label            Label (may be NULL).
         * combo            This combo widget.
         * GList            Contains list of strings in combo list.
         * max_items        Max items allowed in combo list.
         * client_data      Calling function set callback data.
         * func_cb          Calling function set callback function.
         * list_change_cb   Calling function set list change function.
         * NULL
         */

      return(cb_data[3]);
}

/*
 *      Sets the new glist for the combo widget w.
 *
 *    If the pointers for the new list and old list base match
 *    then the new list will simply be updated to the combo with
 *    a call to gtk_combo_set_popdown_strings(). If the base pointers
 *    do not match then the new list will be added and the old list will
 *    be destroyed.
 *
 *    If the given list base pointer is NULL then the current list will
 *    be destroyed.
 *
 *    In any case the given list should no longer be referenced by
 *    the calling function after this call.
 */
void GUIComboSetList(void *w, void *list)
{
      GList *glist;
      const gchar *cstrptr;
      gpointer *cb_data;
        GtkCombo *combo = (GtkCombo *)w;
        if(combo == NULL)
            return;

        cb_data = (gpointer *)gtk_object_get_user_data(GTK_OBJECT(combo));

        /* Parse callback data, format is as follows;
         * table            Parent table that holds this combo and label.
         * label            Label (may be NULL).
         * combo            This combo widget.
         * GList            Contains list of strings in combo list.
         * max_items        Max items allowed in combo list.
         * client_data      Calling function set callback data.
         * func_cb          Calling function set callback function.
         * list_change_cb   Calling function set list change function.
         * NULL
         */
      glist = (GList *)cb_data[3];

      /* Is given list NULL? */
      if(list == NULL)
      {
            gint i, max_items = (gint)cb_data[4];
          GList   *glist_new,
                  *glist_old = glist;

          /* Create a new glist containing just empty strings. */
          glist_new = NULL;
          for(i = 0; i < max_items; i++)
                glist_new = g_list_append(glist_new, STRDUP(""));

            /* Was new glist created successfully? */
            if(glist_new != NULL)
          {
            /* Set new glist to combo. */
                gtk_combo_set_popdown_strings(combo, glist_new);

            /* If old glist exists, then delete it. */
            if(glist_old != NULL)
            {
                g_list_foreach(glist_old, (GFunc)g_free, NULL);
                g_list_free(glist_old);
                glist_old = NULL;
            }

            /* Update pointer to new glist. */
            cb_data[3] = (void *)glist_new;
            glist = glist_new;
          }
      }
      /* Given list matches current list's base pointer values? */
      else if((void *)list == (void *)glist)
      {
          /* Just update list on combo then. */
          gtk_combo_set_popdown_strings(combo, glist);

          /* No need to change pointer on callback data. */

          /* No need to deallocate given list. */
      }
      else
      {
          /* New and current list base pointers do not match and
           * current glist may be NULL.
           */
          gint i, max_items;
          GList   *glist_new, *glist_in,
                  *glist_old = glist;

          /* Make a copy the given list as glist_new and limit the
           * number of items to max_items.
           */
          i = 0;
          max_items = (gint)cb_data[4];
          glist_new = NULL;         /* New glist. */
          glist_in = (GList *)list; /* Input glist. */
          while((i < max_items) && (glist_in != NULL))
          {
            cstrptr = (const char *)glist_in->data;
            glist_new = g_list_append(glist_new, STRDUP(cstrptr));
            glist_in = glist_in->next;
            i++;
          }

          /* Destroy the given input list, it is no longer needed. */
          glist_in = (GList *)list; /* Input glist. */
          list = NULL;        /* Mark input list as NULL. */
          if(glist_in != NULL)
          {
                g_list_foreach(glist_in, (GFunc)g_free, NULL);
                g_list_free(glist_in);
                glist_in = NULL;
          }

          /* Is new coppied glist valid? */
          if(glist_new != NULL)
          {
                /* Set new glist to combo. */
                gtk_combo_set_popdown_strings(combo, glist_new);

                /* If old glist exists, then delete it. */
                if(glist_old != NULL)
                { 
                    g_list_foreach(glist_old, (GFunc)g_free, NULL);
                    g_list_free(glist_old);
                    glist_old = NULL;
                }

                /* Update pointer to new glist on callback data. */
                cb_data[3] = (void *)glist_new;
                glist = glist_new;
          }
      }
}

/*
 *    Resets all values in the combo widget.
 */
void GUIComboClearAll(void *w)
{
      GtkCombo *combo = (GtkCombo *)w;
      if(combo == NULL)
          return;

      /* Clear text entry. */
      gtk_entry_set_text(GTK_ENTRY(combo->entry), "");
      gtk_entry_set_position(GTK_ENTRY(combo->entry), 0);

      /* Clear combo's glist by setting a new one as NULL. */
      GUIComboSetList(combo, NULL);
}


/*
 *    Creates a new menu bar, and a GtkAccelGroup if accel_group is
 *    not NULL.
 */
void *GUIMenuBarCreate(void **accel_group)
{
      if(accel_group != NULL)
          *accel_group = gtk_accel_group_new();

      return(gtk_menu_bar_new());
}

/*
 *    Creates a new menu with the first item as a tear off menu item.
 */
void *GUIMenuCreateTearOff(void)
{
      GtkWidget *w, *menu;

      menu = w = gtk_menu_new();

      w = gtk_tearoff_menu_item_new();
      gtk_menu_append(GTK_MENU(menu), w);
      gtk_widget_show(w);

      return(menu);
}

/*
 *    Creates a new menu.
 */
void *GUIMenuCreate(void)
{
      return(gtk_menu_new());
}

/*
 *    Creates a new menu item and appends it to the menu.
 *    Returns to the pointer to the new menu item.
 *
 *    The functional_widget_rtn can be NULL, if it is not NULL
 *    it will point to the functinoal widget for the menu item.
 *
 *    For instance if the menu item type was GUI_MENU_ITEM_TYPE_LABEL
 *    then functional_widget_rtn will point to the label widget.
 */
void *GUIMenuItemCreate(
      void *menu, int type,   /* One of GUI_MENU_ITEM_TYPE_*. */
      void *accel_group,
      u_int8_t **icon, const char *label,
      int accel_key, unsigned int accel_mods,
      void **functional_widget_rtn,
      void *client_data,
      void (*func_cb)(GtkWidget *w, void *)
)
{
      GtkWidget *w, *menu_item = NULL, *parent, *parent2;
      gui_menu_item_data_struct *cb_data;


      if(menu == NULL)
          return(NULL);

      /* Reset functional widget ID. */
      if(functional_widget_rtn != NULL)
          *functional_widget_rtn = NULL;

      /* Allocate callback data. */
      cb_data = (gui_menu_item_data_struct *)g_malloc0(
          sizeof(gui_menu_item_data_struct)
      );
      if(cb_data == NULL)
          return(NULL);


      /* Create by type. */
      switch(type)
      {
        case GUI_MENU_ITEM_TYPE_LABEL:
        case GUI_MENU_ITEM_TYPE_SUBMENU:
            /* Create new menu item. */
            cb_data->menu_item = w = gtk_menu_item_new();
          if(!GTK_WIDGET_NO_WINDOW(w))
            gtk_widget_add_events(w, GDK_ENTER_NOTIFY_MASK);
            gtk_menu_append(GTK_MENU(menu), w);
          gtk_object_set_user_data(GTK_OBJECT(w), cb_data);
            gtk_signal_connect(
                GTK_OBJECT(w), "destroy",
            GTK_SIGNAL_FUNC(GUIMenuDestroyCB), cb_data
          );
            gtk_widget_show(w);
            menu_item = w;
            parent = w;

          /* Create a table to hold icon and label(s). */
          w = gtk_table_new(
            1,
            (accel_key) ? 3 : 2,
            FALSE
          );
          gtk_container_add(GTK_CONTAINER(parent), w);
#ifndef __MSW__
          gtk_table_set_col_spacing(GTK_TABLE(w), 0, 2);
            gtk_table_set_col_spacing(GTK_TABLE(w), 1, 15);
#endif
          gtk_widget_show(w);  
          parent = w;

          /* Create icon, if icon is NULL then an empty fixed
           * widget would have been returned.
           */
          cb_data->pixmap_normal = w = (GtkWidget *)GUICreateMenuItemIcon(icon);
          if(w != NULL)
          {
                gtk_table_attach(
                GTK_TABLE(parent), w,
                    0, 1,
                    0, 1,
                    GTK_SHRINK,
                    GTK_SHRINK,
                    0, 0
                );
            gtk_widget_show(w);
          }

          /* Create hbox for label. */
          w = gtk_hbox_new(FALSE, 0);
          gtk_table_attach(
            GTK_TABLE(parent), w,
                1, 2,
                0, 1,
                GTK_SHRINK | GTK_EXPAND | GTK_FILL,
                GTK_SHRINK,
                0, 0
            );
            gtk_widget_show(w);
          parent2 = w;
          /* Label. */
          cb_data->label_normal = w = gtk_label_new(
            (label != NULL) ? label : "(null)"
          );
          gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
          gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_LEFT);
          gtk_widget_show(w);

          /* Record label as functional widget. */
          if(functional_widget_rtn != NULL)
              *functional_widget_rtn = w;

          /* Set callback for menu item? */
          if(func_cb != NULL)
          {
                /* Allocate client callback data, this will be deallocated
                 * when the menu item is destroyed.
                 */
            gpointer *cb_data2 = (gpointer *)g_malloc0(
                4 * sizeof(gpointer)
            );
              if(cb_data2 != NULL)
            {
                cb_data2[0] = w;    /* Functional widget. */
                cb_data2[1] = client_data;
                cb_data2[2] = (gpointer)func_cb;
                cb_data2[3] = NULL;
            }
                gtk_signal_connect(
                    GTK_OBJECT(menu_item), "destroy",
                    GTK_SIGNAL_FUNC(GUIMenuDestroyCB), cb_data2
                );
            /* Must use gtk_signal_connect_object() for "activate"
             * signal.
             */
            gtk_signal_connect_object(
                GTK_OBJECT(menu_item), "activate",
                GTK_SIGNAL_FUNC(GUIMenuActivateCB), (gpointer)cb_data2
            );
          }

            /* Create accelerator label and add accelerator? */
          if(accel_key)
          {
            gchar text[256];
            gchar text2[80];

            text[0] = ' ';          /* Add one space. */
            text[1] = '\0';

            if(accel_mods & GDK_LOCK_MASK)
                    strcat(text, "Lock+");
            if(accel_mods & GDK_CONTROL_MASK)
                    strcat(text, "Ctrl+");
            if(accel_mods & GDK_SHIFT_MASK)
                strcat(text, "Shift+");
                if(accel_mods & GDK_MOD1_MASK)
                    strcat(text, "Mod1+");
                if(accel_mods & GDK_MOD2_MASK)
                    strcat(text, "Mod2+");
                if(accel_mods & GDK_MOD3_MASK)
                    strcat(text, "Mod3+");
                if(accel_mods & GDK_MOD4_MASK)
                    strcat(text, "Mod4+");
                if(accel_mods & GDK_MOD5_MASK)
                    strcat(text, "Mod5+");

            if(accel_key & 0xffffff00)
            {
                strcat(text, GUIGetKeyName(accel_key));
            }
            else
            {
                sprintf(text2, "%c", toupper(accel_key));
                strcat(text, text2);
            }

            w = gtk_label_new(text);
            gtk_table_attach(GTK_TABLE(parent),
                    w,
                    2, 3,
                    0, 1,
                    GTK_SHRINK,
                    GTK_SHRINK,
                    0, 0
                );
                gtk_label_set_justify(GTK_LABEL(w), GTK_JUSTIFY_RIGHT);
                gtk_widget_show(w);

            if(accel_group != NULL)
                gtk_widget_add_accelerator(
                  menu_item, "activate", (GtkAccelGroup *)accel_group,
                  accel_key, accel_mods,
                  GTK_ACCEL_VISIBLE
                );
          }
          break;

        case GUI_MENU_ITEM_TYPE_CHECK:
            /* Create new check menu item. */
            cb_data->menu_item = w = gtk_check_menu_item_new_with_label(
            (label != NULL) ? label : "(null)"
          );
            gtk_menu_append(GTK_MENU(menu), w);
            gtk_object_set_user_data(GTK_OBJECT(w), cb_data);
            gtk_signal_connect(
                GTK_OBJECT(w), "destroy",
                GTK_SIGNAL_FUNC(GUIMenuDestroyCB), cb_data
            );
            gtk_widget_show(w);
            menu_item = w;
            parent = w;

          /* Record check menu item as the functional widget. */
            if(functional_widget_rtn != NULL)
                *functional_widget_rtn = w;

            /* Set callback for the check menu item? */
            if(func_cb != NULL)
            {
                /* Allocate client callback data, this will be deallocated
                 * when the menu item is destroyed.
                 */
                gpointer *cb_data2 = (gpointer *)g_malloc(
                4 * sizeof(gpointer)
            );
                if(cb_data2 != NULL)
                {
                    cb_data2[0] = w;     /* Functional widget. */
                    cb_data2[1] = client_data;
                    cb_data2[2] = (gpointer)func_cb;
                    cb_data2[3] = NULL;
                }
                gtk_signal_connect(
                    GTK_OBJECT(menu_item), "destroy",
                    GTK_SIGNAL_FUNC(GUIMenuDestroyCB), cb_data2
                );
                /* Must use gtk_signal_connect_object() for "activate"
                 * signal.
                 */
            gtk_signal_connect_object(
                    GTK_OBJECT(menu_item), "activate",
                    GTK_SIGNAL_FUNC(GUIMenuActivateCB), (gpointer)cb_data2
                );
            }

            /* Add accelerator? */
            if(accel_key && (accel_group != NULL))
            {
                gtk_widget_add_accelerator(
                    menu_item, "activate", (GtkAccelGroup *)accel_group,
                    accel_key, accel_mods,
                    GTK_ACCEL_VISIBLE
                );
            }
            break;

        case GUI_MENU_ITEM_TYPE_SEPARATOR:
            /* Create new menu item. */
            cb_data->menu_item = w = gtk_menu_item_new();
            gtk_menu_append(GTK_MENU(menu), w);
            gtk_object_set_user_data(GTK_OBJECT(w), cb_data);
            gtk_signal_connect(
                GTK_OBJECT(w), "destroy",
                GTK_SIGNAL_FUNC(GUIMenuDestroyCB), cb_data
            );
            gtk_widget_show(w);
            menu_item = w;
            parent = w;

          /* Create horizontal separator. */
            w = gtk_hseparator_new();
            gtk_container_add(GTK_CONTAINER(parent), w);
          GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(menu_item), GTK_SENSITIVE);
            gtk_widget_show(w);

          /* Record horizontal separator as the functional widget. */
            if(functional_widget_rtn != NULL)
                *functional_widget_rtn = w;
          break;

        default:
          g_free(cb_data);
          cb_data = NULL;
          break;
      }


      return(menu_item);
}


/*
 *    Sets the hint message for the given menu item widget.
 *
 *    Since menu item widgets can't have tooltips like other widgets,
 *    this one calls a callback when the pointer enters the menu
 *    item widget and the call back will decide on what to do.
 */
void GUISetMenuItemCrossingCB(
      void *w,
      int (*enter_cb)(void *, void *, void *),
      void *enter_client_data,
        int (*leave_cb)(void *, void *, void *),
        void *leave_client_data
)
{
      if(w == NULL)
          return;

      if(enter_cb != NULL)
          gtk_signal_connect(
            GTK_OBJECT((GtkWidget *)w), "enter_notify_event",
            GTK_SIGNAL_FUNC(enter_cb), enter_client_data
          );
      if(leave_cb != NULL)
            gtk_signal_connect(
                GTK_OBJECT((GtkWidget *)w), "leave_notify_event",
                GTK_SIGNAL_FUNC(leave_cb), leave_client_data
            );
}

/*
 *    Adds the menu to the menu_bar, giving it the label value of
 *    menu_bar_item_label. Returns the pointer to the menu bar label
 *    widget or NULL on error.
 */
void *GUIMenuAddToMenuBar(
      void *menu_bar, void *menu,
      const char *menu_bar_item_label,
      int align   /* One of GUI_MENU_BAR_ALIGN_*. */
)
{
      GtkWidget *w = NULL;

      if((menu_bar == NULL) || (menu == NULL))
          return(w);

      w = gtk_menu_item_new_with_label(
          (menu_bar_item_label != NULL) ?
            menu_bar_item_label : "(null)"
      );
        gtk_menu_item_set_submenu(GTK_MENU_ITEM(w), GTK_WIDGET(menu));
      gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), GTK_WIDGET(w));
      gtk_widget_show(w);

      if(align == GUI_MENU_BAR_ALIGN_RIGHT)
          gtk_menu_item_right_justify(GTK_MENU_ITEM(w));

      return(w);
}

/*
 *    Updates the label of the given menu item.
 */
void GUIMenuItemSetLabel(void *menu_item, const char *label)
{
      GtkWidget *w;
      gui_menu_item_data_struct *cb_data;


      if(menu_item == NULL)
          return;

      cb_data = (gui_menu_item_data_struct *)gtk_object_get_user_data(
          (GtkObject *)menu_item
      );
      if(cb_data == NULL)
          return;

      w = cb_data->label_normal;
      if((w != NULL) ? GTK_IS_LABEL(w) : FALSE)
          gtk_label_set_text(
            GTK_LABEL(w),
            (label != NULL) ? label : ""
          );
}

/*
 *      Updates the pixmap of the given menu item.
 */
void GUIMenuItemSetPixmap(void *menu_item, u_int8_t **icon_data)
{
        gui_menu_item_data_struct *cb_data;
        GdkWindow *window = (GdkWindow *)GDK_ROOT_PARENT();
        GtkStyle *style;
        GtkWidget *w;


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

      style = gtk_widget_get_default_style();
        if((window == NULL) || (style == NULL))
            return;

        cb_data = (gui_menu_item_data_struct *)gtk_object_get_user_data(
            (GtkObject *)menu_item
        );
        if(cb_data == NULL)
            return;

        w = cb_data->pixmap_normal;
        if((w != NULL) ? GTK_IS_PIXMAP(w) : FALSE)
      {
          gint width, height;
            GdkPixmap *pixmap;
            GdkBitmap *mask;

          mask = NULL;
            pixmap = gdk_pixmap_create_from_xpm_d(
                window, &mask,
                &style->bg[GTK_STATE_NORMAL],
                (gchar **)icon_data
            );

            /* Pixmap created successfully? */
            if(pixmap != NULL)
            {
                /* Update GtkPixmap. */
                gtk_pixmap_set(GTK_PIXMAP(w), pixmap, mask);

                /* Get size of newly loaded pixmap. */
                gdk_window_get_size((GdkWindow *)pixmap, &width, &height);
          }

            /* Unref pixmap and mask pair, they are no longer needed. */
            if(pixmap != NULL)
                gdk_pixmap_unref(pixmap);
            if(mask != NULL)
                gdk_bitmap_unref(mask);
      }
}

/*
 *    Same as GUIMenuAddToMenuBar() except a pixmap is placed to the
 *    left of the menu item on the menu bar.
 */
void *GUIMenuAddToMenuBarPixmapH(
        void *menu_bar, void *menu,
        const char *menu_bar_item_label, const u_int8_t **icon,
        int align /* One of GUI_MENU_BAR_ALIGN_*. */
)
{
      return(GUIMenuAddToMenuBar(
          menu_bar, menu, menu_bar_item_label, align
      ));
}


/*
 *    Links the menu item to the sub menu.
 */
void GUIMenuItemSetSubMenu(
        void *menu_item, void *sub_menu
)
{
      if(menu_item == NULL)
          return;

      if(sub_menu == NULL)
          gtk_menu_item_remove_submenu((GtkMenuItem *)menu_item);
      else
          gtk_menu_item_set_submenu(
            (GtkMenuItem *)menu_item,
            (GtkWidget *)sub_menu
          );
}

/*
 *    Creates a pull out widget horizontally, returning the hbox which
 *    the calling function can pack child widgets into.
 *
 *    The given parent must be a hbox or a vbox.
 *
 *    The toplevel_width and toplevel_height specify the size of the
 *    toplevel window that will be used when this widget is `pulled
 *    out'.
 *
 *    gtk_widget_show() will be called for you, the client function need
 *    not call it.
 */
void *GUIPullOutCreateH(  
        void *parent_box,
      int homogeneous, int spacing,       /* Of client vbox. */
      int expand, int fill, int padding,  /* Of holder hbox. */
        int toplevel_width, int toplevel_height,
      void *pull_out_client_data,
      void (*pull_out_cb)(void *, void *),
      void *push_in_client_data,
        void (*push_in_cb)(void *, void *)
)
{
      gpointer *cb_data;
      GtkWidget *pull_out_btn, *holder_hbox, *client_hbox;

      if(parent_box == NULL)
          return(NULL);

      /* Create a hbox to place into the given parent box. This hbox
       * will hold the parenting hbox plus some other widgets.
       */
      holder_hbox = gtk_hbox_new(FALSE, 0);
      gtk_box_pack_start(
          (GtkBox *)parent_box, holder_hbox,
          expand, fill, padding
      );
      gtk_widget_show(holder_hbox);

      /* Create pull out button and parent it to the holder hbox.
       * Note that this is not really a button but an event box.
       */
      pull_out_btn = gtk_event_box_new();
      gtk_box_pack_start(
            GTK_BOX(holder_hbox), pull_out_btn, FALSE, FALSE, 0
        );
      gtk_widget_set_usize(pull_out_btn, 10, -1);
        gtk_widget_show(pull_out_btn);


      /* Create the client hbox, which will be parented to the above
       * holder hbox when `placed in' and reparented to a toplevel
       * GtkWindow when `pulled out'.
       */
      client_hbox = gtk_hbox_new(homogeneous, spacing);
      gtk_box_pack_start(
          GTK_BOX(holder_hbox), client_hbox, TRUE, TRUE, 0
      );
        gtk_widget_show(client_hbox);


      /* Set callbacks and callback data. */

      /* Allocate and set up callback data. */
      cb_data = (gpointer *)g_malloc0(13 * sizeof(gpointer));
      if(cb_data != NULL)
      {
          /* Format is as follows (13 arguments):
           *
           *      client_hbox
           *      holder_hbox
           *      holder_window
           *      holder_window_x
           *      holder_window_y
           *      holder_window_width
           *      holder_window_height
           *      in_place          (1 if true).
           *  pull_out_client_data
           *      pull_out_cb
           *      push_in_client_data
           *      push_in_cb
           */
          cb_data[0] = (void *)client_hbox;
          cb_data[1] = (void *)holder_hbox;
          cb_data[2] = NULL;
          cb_data[3] = 0;
          cb_data[4] = 0;
          cb_data[5] = (void *)MAX(toplevel_width, 0);
          cb_data[6] = (void *)MAX(toplevel_height, 0);
          cb_data[7] = (void *)1;         /* Initially `pushed in'. */
          cb_data[8] = (void *)pull_out_client_data;
          cb_data[9] = (void *)pull_out_cb;
            cb_data[10] = (void *)push_in_client_data;
            cb_data[11] = (void *)push_in_cb;
          cb_data[12] = NULL;

          /* Set callback data pointer on the client hbox. */
          gtk_object_set_user_data(GTK_OBJECT(client_hbox), cb_data);
      }

        /* Connect destroy event to holder_hbox so the callback data
       * and related resources can be deallocated when the client
       * functions destroy the holder_hbox.
       */
        gtk_signal_connect(
            GTK_OBJECT(holder_hbox), "destroy",
            GTK_SIGNAL_FUNC(GUIPullOutDestroyCB), cb_data
        );

      gtk_signal_connect(
            GTK_OBJECT(pull_out_btn), "button_press_event",
            GTK_SIGNAL_FUNC(GUIPullOutPullOutBtnCB), cb_data
        );
        gtk_signal_connect_after(
            GTK_OBJECT(pull_out_btn), "expose_event",
            GTK_SIGNAL_FUNC(GUIPullOutDrawHandleCB), NULL
        );
        gtk_signal_connect(
            GTK_OBJECT(pull_out_btn), "draw",
            GTK_SIGNAL_FUNC(GUIPullOutDrawHandleDrawCB), NULL
        );

      return(client_hbox);
}

/*
 *    Returns the pointer to the toplevel window (if any) of the
 *    client_hbox and the geometry of that window.
 *
 *    The client box should be one created by GUIPullOutCreate*().
 */
void *GUIPullOutGetToplevelWindow(
        void *client_box,
      int *x, int *y, int *width, int *height
)
{
      gpointer *cb_data;
      GtkWidget *w = NULL;

      if(x != NULL)
          *x = 0;
      if(y != NULL)
          *y = 0;
      if(width != NULL)
          *width = 0;
      if(height != NULL)
          *height = 0;

      if(client_box == NULL)
          return(w);

        cb_data = (gpointer *)gtk_object_get_user_data((GtkObject *)client_box);
      if(cb_data != NULL)
      {
            /* Format is as follows (13 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb   
             */
            w = (GtkWidget *)cb_data[2];

          if((w != NULL) ? !GTK_WIDGET_NO_WINDOW(w) : FALSE)
          {
            GdkWindow *window = w->window;
            gint rx, ry, rwidth, rheight, rdepth;

            gdk_window_get_geometry(
                window,
                &rx, &ry, &rwidth, &rheight,
                &rdepth
            );

            if(x != NULL)
                *x = rx;
            if(y != NULL)
                *y = ry;
            if(width != NULL)
                *width = rwidth;
            if(height != NULL)
                *height = rheight;
          }
      }

      return(w);
}

/*
 *    Pulls out the pull out box.
 */
void GUIPullOutPullOut(void *client_box)
{
      gpointer *cb_data;

      if(client_box == NULL)
          return;

      cb_data = (gpointer *)gtk_object_get_user_data((GtkObject *)client_box);
      if(cb_data != NULL)
      {
            /* Format is as follows (13 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb
             */

          /* In place (pushed in)? */
          if((gint)cb_data[7])
          {
            GUIPullOutPullOutBtnCB(
                NULL,
                NULL,
                (gpointer)cb_data
            );
          }
      }
}

/*
 *      Pushes in the pull out box.
 */
void GUIPullOutPushIn(void *client_box)
{
      GtkWidget *w;
      gpointer *cb_data;

        if(client_box == NULL)
            return;

      cb_data = (gpointer *)gtk_object_get_user_data((GtkObject *)client_box);
      if(cb_data != NULL)
        {
            /* Format is as follows (13 arguments):
             *
             *  client_hbox
             *  holder_hbox
             *  holder_window
             *  holder_window_x
             *  holder_window_y
             *  holder_window_width
             *  holder_window_height
             *  in_place                (1 if true).
             *  pull_out_client_data
             *  pull_out_cb
             *  push_in_client_data
             *  push_in_cb
             */

          w = (GtkWidget *)cb_data[2];

            /* Not in place (pulled out)? */
            if(!((gint)cb_data[7]))
            {
            GUIPullOutCloseCB(
                (GtkWidget *)cb_data[2],
                NULL,
                (gpointer)cb_data
            );
            }
        }
}

Generated by  Doxygen 1.6.0   Back to index