Logo Search packages:      
Sourcecode: vertex version File versions

stacklist.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>
#include "guiutils.h"
#include "stacklist.h"

#include "images/icon_add_20x20.xpm"
#include "images/icon_remove_20x20.xpm"

static void StackListAddCB(GtkWidget *widget, gpointer data);
static void StackListRemoveCB(GtkWidget *widget, gpointer data);
static void StackListShiftUpCB(GtkWidget *widget, gpointer data);
static void StackListShiftDownCB(GtkWidget *widget, gpointer data);
static gint StackListCListEventCB(
        GtkWidget *widget, GdkEvent *event, gpointer data
);
static void StackListSelectRowCB(
        GtkCList *clist, gint row, gint column, GdkEvent *event,
        gpointer data
);
static void StackListUnselectRowCB(
        GtkCList *clist, gint row, gint column, GdkEvent *event,
        gpointer data
);


static stack_list_item_struct *StackListMatchItemByID(
        stack_list_struct *slist, gint id
);

void StackListAppend(
      stack_list_struct *slist,
      const gchar *name,
      const gchar *description,
      guint8 **icon_data,
      gpointer client_data,
      gint id,
      gbool allow_multiple, gbool stay_on_target
);
void StackListClear(stack_list_struct *slist);

void StackListItemAppendSrc(stack_list_struct *slist, gint id);
void StackListItemAppendTar(stack_list_struct *slist, gint id);
void StackListItemSetAllFromCacheSrc(stack_list_struct *slist);

void StackListItemRemoveByIDSrc(
      stack_list_struct *slist, gint id,
      gbool exclude_allowed_multiples
);
void StackListItemRemoveByIDTar(
      stack_list_struct *slist, gint id,
      gbool exclude_allowed_multiples
);

void StackListItemClearSrc(stack_list_struct *slist);
void StackListItemClearTar(stack_list_struct *slist);

gint *StackListItemGetSrc(stack_list_struct *slist, gint *total);
gint *StackListItemGetTar(stack_list_struct *slist, gint *total);


stack_list_struct *StackListNew(
        GtkWidget *parent,      /* A vbox. */
        const gchar *src_title, const gchar *tar_title,
        void (*changed_cb)(gpointer, gpointer),
        gpointer client_data
);
void StackListUpdateMenus(stack_list_struct *slist);
void StackListMap(stack_list_struct *slist);
void StackListUnmap(stack_list_struct *slist);
void StackListDelete(stack_list_struct *slist);


#define STACK_LIST_ROW_SPACING      20

#define STACK_LIST_ARROW_WIDTH      20
#define STACK_LIST_ARROW_HEIGHT     20



/*
 *    Stack list add item from source to target list callback.
 */
static void StackListAddCB(GtkWidget *widget, gpointer data)
{
      gint i;
      gchar **strv;
      gint src_row, tar_row;
      GList *src_sel_glist, *tar_sel_glist;
      GtkCList *src_clist, *tar_clist;
      stack_list_item_struct *item_ptr;
        stack_list_struct *slist = STACK_LIST(data);
        if(slist == NULL)
            return;

      /* Get source and target clists. */
      src_clist = (GtkCList *)slist->src_clist;
      tar_clist = (GtkCList *)slist->tar_clist;
      if((src_clist == NULL) || (tar_clist == NULL))
          return;


      /* Allocate row cell text array for target clist. */
      strv = (gchar **)g_malloc0(tar_clist->columns * sizeof(gchar *));
      if(strv == NULL)
          return;
      for(i = 0; i < tar_clist->columns; i++)
          strv[i] = g_strdup("");


      /* Get target row to insert after. */
      tar_sel_glist = tar_clist->selection_end;
      tar_row = (tar_sel_glist != NULL) ?
          (gint)tar_sel_glist->data : -1;


        gtk_clist_freeze(src_clist);
        gtk_clist_freeze(tar_clist);


      /* Iterate through selected rows on the source clist. */
      src_sel_glist = src_clist->selection;
      while(src_sel_glist != NULL)
      {
          /* Get this selected row. */
          src_row = (gint)src_sel_glist->data;

          item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
            src_clist, src_row
          ));
          if(item_ptr != NULL)
          {
            gint new_row;


            /* Create a new row on the target clist that matches the
             * current item.
             */
            if(tar_row > -1)
                new_row = gtk_clist_insert(tar_clist, tar_row, strv);
            else
                new_row = gtk_clist_append(tar_clist, strv);
            if(new_row > -1)
            {
                    if((item_ptr->icon_pixmap != NULL) &&
                       (item_ptr->name != NULL)
                )
                        gtk_clist_set_pixtext(
                            tar_clist, new_row, 0,
                            (item_ptr->name != NULL) ? item_ptr->name : "",
                            2,
                            item_ptr->icon_pixmap, item_ptr->icon_mask
                        );
                    else if(item_ptr->icon_pixmap != NULL)
                        gtk_clist_set_pixmap(
                            tar_clist, new_row, 0,
                            item_ptr->icon_pixmap, item_ptr->icon_mask
                        );
                    else if(item_ptr->name != NULL)
                        gtk_clist_set_text(
                            tar_clist, new_row, 0, item_ptr->name
                        );

                    /* Set row data, but no destroy function since the row data
                     * is shared and not suppose to be deallocated when the clist
                     * row is destroyed.
                     */
                    gtk_clist_set_row_data(tar_clist, new_row, item_ptr);

                gtk_clist_select_row(tar_clist, new_row, 0);
            }

            /* If multiple occurances of the item is not allowed then
             * remove item from the source clist.
             */
            if(!item_ptr->allow_multiple)
                gtk_clist_remove(src_clist, src_row);
          }

/* Do not continue, next selected row may not be correct. */
break;

          /* Get next selected row on the source clist. */
          src_sel_glist = src_sel_glist->next;
      }

      gtk_clist_thaw(src_clist);
      gtk_clist_thaw(tar_clist);


      /* Deallocate row cell data. */
      for(i = 0; i < tar_clist->columns; i++)
          g_free(strv[i]);
      g_free(strv);
      strv = NULL;

        StackListUpdateMenus(slist);
}

/*
 *    Stack list remove item from target list and put back to source 
 *    list callback.
 */
static void StackListRemoveCB(GtkWidget *widget, gpointer data)
{
        gint i;
        gchar **strv;
        gint src_row, tar_row;
        GList *tar_sel_glist;
        GtkCList *src_clist, *tar_clist;
        stack_list_item_struct *item_ptr;
        stack_list_struct *slist = STACK_LIST(data);
        if(slist == NULL)
            return;

        /* Get source and target clists. */
        src_clist = (GtkCList *)slist->src_clist;
        tar_clist = (GtkCList *)slist->tar_clist;
        if((src_clist == NULL) || (tar_clist == NULL))
            return;


        /* Allocate row value strings. */
        strv = (gchar **)g_malloc0(src_clist->columns * sizeof(gchar *));
      if(strv == NULL)
          return;
      for(i = 0; i < src_clist->columns; i++)
          strv[i] = g_strdup("");


        gtk_clist_freeze(src_clist);
        gtk_clist_freeze(tar_clist);


        /* Iterate through selected rows on the target clist. */
        tar_sel_glist = tar_clist->selection;
        while(tar_sel_glist != NULL)
        {
            /* Get this selected row. */
            tar_row = (gint)tar_sel_glist->data;
            item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
                tar_clist, tar_row
            ));
            if((item_ptr != NULL) ? 
            (!item_ptr->allow_multiple && !item_ptr->stay_on_target) : FALSE
          )
            {
                gint new_row;
            stack_list_item_struct *src_item_ptr;

            /* Find the source row where the new row should be
             * inserted after. Iterate through main item cache on
             * the slist.
             */
            src_row = 0;
            for(i = 0; i < slist->total_items; i++)
            {
                src_item_ptr = slist->item[i];
                if(src_item_ptr == NULL)
                  continue;

                /* This item exists on one of the source clist's rows? */
                if(gtk_clist_find_row_from_data(src_clist, src_item_ptr)
                  > -1
                )
                  src_row++;

                /* Stop itterating when we encounter the current item
                 * in the main slist item cache.
                 */
                if(src_item_ptr->id == item_ptr->id)
                  break;
            }

            /* Insert or append new row into source clist. */
                if(src_row < src_clist->rows)
                    new_row = gtk_clist_insert(src_clist, src_row, strv);
                else
                    new_row = gtk_clist_append(src_clist, strv);
                if(new_row > -1)
                {
                    if((item_ptr->icon_pixmap != NULL) &&
                       (item_ptr->name != NULL)
                    )
                        gtk_clist_set_pixtext(
                            src_clist, new_row, 0,
                            (item_ptr->name != NULL) ? item_ptr->name : "",
                            2,
                            item_ptr->icon_pixmap, item_ptr->icon_mask
                        );
                    else if(item_ptr->icon_pixmap != NULL)
                        gtk_clist_set_pixmap(
                            src_clist, new_row, 0,
                            item_ptr->icon_pixmap, item_ptr->icon_mask
                        );
                    else if(item_ptr->name != NULL)
                        gtk_clist_set_text(
                            src_clist, new_row, 0, item_ptr->name
                        );

                    /* Set row data, but no destroy function since the row data
                     * is shared and not suppose to be deallocated when the clist
                     * row is destroyed.
                     */
                    gtk_clist_set_row_data(src_clist, new_row, item_ptr);

                gtk_clist_select_row(src_clist, new_row, 0);
                }
          }

          /* Remove selected row from target clist. */
          if((item_ptr != NULL) ?
                !item_ptr->stay_on_target : FALSE
            )
            gtk_clist_remove(tar_clist, tar_row);

/* Do not continue, next selected row may not be correct. */
break;

            /* Get next selected row on the source clist. */
            tar_sel_glist = tar_sel_glist->next;
        }

        gtk_clist_thaw(src_clist);
        gtk_clist_thaw(tar_clist);


        /* Deallocate row value strings. */
        for(i = 0; i < src_clist->columns; i++)
            g_free(strv[i]);
        g_free(strv);
        strv = NULL;

        StackListUpdateMenus(slist);
}

/*
 *    Shift last selected target item up callback.
 */
static void StackListShiftUpCB(GtkWidget *widget, gpointer data)
{
      gint row;
      GList *sel_glist;
        GtkCList *clist;
        stack_list_struct *slist = STACK_LIST(data);
        if(slist == NULL)
            return;

        /* Get target clist. */
        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;

      /* Get last selected row. */
      sel_glist = clist->selection_end;
      if(sel_glist != NULL)
          row = (gint)sel_glist->data;
      else
          return;

      /* Already at top? */
      if(row <= 0)
          return;

        gtk_clist_freeze(clist);
      gtk_clist_swap_rows(clist, row, row - 1);
        gtk_clist_thaw(clist);

        StackListUpdateMenus(slist);
}

/*
 *    Shift last selected target item down callback.
 */
static void StackListShiftDownCB(GtkWidget *widget, gpointer data)
{
        gint row;
        GList *sel_glist;
        GtkCList *clist;
        stack_list_struct *slist = STACK_LIST(data);
        if(slist == NULL)
            return;

        /* Get target clist. */
        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;

        /* Get last selected row. */
        sel_glist = clist->selection_end;
        if(sel_glist != NULL)
            row = (gint)sel_glist->data;
        else
            return;

        /* Already at bottom? */
        if(row >= (clist->rows - 1))
            return;

        gtk_clist_freeze(clist);
        gtk_clist_swap_rows(clist, row, row + 1);
        gtk_clist_thaw(clist);

      StackListUpdateMenus(slist);
}

/*
 *    GtkCList event signal callback.
 */
static gint StackListCListEventCB(
      GtkWidget *widget, GdkEvent *event, gpointer data
)
{
      gbool status = FALSE;
      gint etype, x, y, row, column;
      GdkEventKey *key;
      GdkEventCrossing *crossing;
      GdkEventButton *button;
      GdkEventMotion *motion;
      GtkWidget *w;
      GtkCList *clist;
      stack_list_item_struct *item_ptr;
        stack_list_struct *slist = STACK_LIST(data);
        if((widget == NULL) || (event == NULL) || (slist == NULL))
            return(status);

      clist = GTK_CLIST(widget);
      if(clist->clist_window != ((GdkEventAny *)event)->window)
          return(status);

      etype = event->type;
      switch(etype)
      {
/* Macro to emit a signal stop for a key press or release depending
 * on the current event's type.
 */
#define DO_STOP_KEY_SIGNAL_EMIT     \
{ \
 gtk_signal_emit_stop_by_name( \
  GTK_OBJECT(widget), \
  (etype == GDK_KEY_PRESS) ? "key_press_event" : "key_release_event" \
 ); \
}
          case GDK_KEY_PRESS:
          key = (GdkEventKey *)event;
          switch(key->keyval)
          {
              case GDK_Return:
              case GDK_KP_Enter:
              case GDK_ISO_Enter:
              case GDK_3270_Enter:
                if(widget == slist->src_clist)
                    StackListAddCB(NULL, data);
                else if(widget == slist->tar_clist)
                    StackListRemoveCB(NULL, data);
            DO_STOP_KEY_SIGNAL_EMIT
            status = TRUE;
            break;
          }
          break;

          case GDK_KEY_RELEASE:
            key = (GdkEventKey *)event;
            switch(key->keyval)
            {
              case GDK_Return:
              case GDK_KP_Enter:
              case GDK_ISO_Enter:
              case GDK_3270_Enter:
                DO_STOP_KEY_SIGNAL_EMIT
                status = TRUE;
                break;
            }
            break;

#undef DO_STOP_KEY_SIGNAL_EMIT

          case GDK_ENTER_NOTIFY:
            crossing = (GdkEventCrossing *)event;

            /* Reset pointer to last item used for description. */
            slist->last_description_item = NULL;

            status = TRUE;
            break;

        case GDK_LEAVE_NOTIFY:
          crossing = (GdkEventCrossing *)event;

          /* Reset pointer to last item used for description. */
          slist->last_description_item = NULL;

          /* Clear description label. */
          w = slist->description_label;
          if(w != NULL)
            gtk_label_set_text(GTK_LABEL(w), "");

          status = TRUE;
          break;

        case GDK_BUTTON_PRESS:
          button = (GdkEventButton *)event;
          x = button->x;
          y = button->y;
            if(!gtk_clist_get_selection_info(
                clist, x, y, &row, &column
            ))
            {
                row = -1;
                column = 0;
            }
            /* Handle by button number. */
            switch(button->button)
            {
              case 3:
            gtk_clist_freeze(clist);
            if(!(button->state & GDK_CONTROL_MASK) &&
               !(button->state & GDK_SHIFT_MASK)
            )
                gtk_clist_unselect_all(clist);
            gtk_clist_select_row(clist, row, column);
            gtk_clist_thaw(clist);

            /* Map menu depending on which clist this event occured
             * on.
             */
                if(widget == slist->src_clist)
                    w = slist->src_menu;
            else if(widget == slist->tar_clist)
                w = slist->tar_menu;
            else
                w = NULL;
            if(w != NULL)
                gtk_menu_popup(
                  GTK_MENU(w), NULL, NULL,
                  NULL, NULL,
                  button->button, button->time
                );
            break;
          }
          status = TRUE;
          break;

        case GDK_MOTION_NOTIFY:
          motion = (GdkEventMotion *)event;
          x = motion->x;
          y = motion->y;
          /* Find matching row corresponding to the pointer motion on
           * this clist.
           */
            if(!gtk_clist_get_selection_info(
                clist, x, y, &row, &column
            ))
            {
                row = -1;
                column = 0;
            }

          /* Get row data (may be NULL). */
          item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
            clist, row
          ));

          /* Update description label if there is a change since the
           * last pointer used to the item description.
           */
            w = slist->description_label;
            if((w != NULL) && (item_ptr != slist->last_description_item))
          {
            if((item_ptr != NULL) ? (item_ptr->description != NULL) : FALSE)
                gtk_label_set_text(GTK_LABEL(w), item_ptr->description);
            else
                gtk_label_set_text(GTK_LABEL(w), "");
          }

            /* Update pointer to last item used for description. */
            slist->last_description_item = item_ptr;

            status = TRUE;
            break;
      }

      return(status);
}

/*
 *      GtkCList "select_row" signal callback.
 */
static void StackListSelectRowCB(
        GtkCList *clist, gint row, gint column, GdkEvent *event,
        gpointer data
)
{
      GdkEventButton *button;
      stack_list_struct *slist = STACK_LIST(data);
      if(slist == NULL)
          return;

      /* Check which clist this event occured for. */
      if(clist == (GtkCList *)slist->src_clist)
      {
            slist->src_last_selected = row;

          if(gtk_clist_row_is_visible(clist, row) !=
                GTK_VISIBILITY_FULL
            )
                gtk_clist_moveto(
                    clist,
                    row, -1,  /* Row, column. */
                    0.5, 0.0  /* Row, column. */
                );

          /* Check for double click. */
          if((event != NULL) ? (event->type == GDK_2BUTTON_PRESS) : FALSE)
          {
            button = (GdkEventButton *)event;
            switch(button->button)
            {
              case 1:
                StackListAddCB(NULL, slist);
                break;
            }
          }
      }
      else if(clist == (GtkCList *)slist->tar_clist)
        {
            slist->tar_last_selected = row;

            if(gtk_clist_row_is_visible(clist, row) !=
                GTK_VISIBILITY_FULL
            )
                gtk_clist_moveto(
                    clist,
                    row, -1,  /* Row, column. */
                    0.5, 0.0  /* Row, column. */
                );

            /* Check for double click. */
            if((event != NULL) ? (event->type == GDK_2BUTTON_PRESS) : FALSE)
            {
                button = (GdkEventButton *)event;
                switch(button->button)
                {
                  case 1:
                    StackListRemoveCB(NULL, slist);
                    break;
                }
            }
        }

      StackListUpdateMenus(slist);
}

/*
 *      GtkCList "unselect_row" signal callback.
 */
static void StackListUnselectRowCB(
        GtkCList *clist, gint row, gint column, GdkEvent *event,
        gpointer data
)
{
        stack_list_struct *slist = STACK_LIST(data);
        if(slist == NULL)
            return;

      /* Do nothing for unselected rows. */

      StackListUpdateMenus(slist);
}


/*
 *    Returns an item structure that matches the given id or NULL
 *    on failed match.
 */
static stack_list_item_struct *StackListMatchItemByID(
      stack_list_struct *slist, gint id
)
{
      gint i;
      stack_list_item_struct *item;


      if(slist == NULL)
          return(NULL);

      for(i = 0; i < slist->total_items; i++)
      {
          item = slist->item[i];
          if(item == NULL)
            continue;

          if(item->id == id)
            return(item);
      }

      return(NULL);
}

/*
 *    Appends the given item to the stack list's cache of items.
 */
void StackListAppend(
        stack_list_struct *slist,
        const gchar *name,
        const gchar *description,
        guint8 **icon_data,
        gpointer client_data,
        gint id,
        gbool allow_multiple, gbool stay_on_target
)
{
      gint i;
      stack_list_item_struct *item;


      if(slist == NULL)
          return;

      /* Sanitize total. */
      if(slist->total_items < 0)
          slist->total_items = 0;

      /* Allocate one more pointers. */
      i = slist->total_items;
      slist->total_items = i + 1;
      slist->item = (stack_list_item_struct **)g_realloc(
          slist->item,
          slist->total_items * sizeof(stack_list_item_struct *)
      );
      if(slist->item == NULL)
      {
          slist->total_items = 0;
          return;
      }

      /* Allocate a new item structure. */
      slist->item[i] = item = STACK_LIST_ITEM(g_malloc0(
          sizeof(stack_list_item_struct)
      ));
      if(item == NULL)
          return;


      /* Set up new item structure. */
      item->name = (name != NULL) ? g_strdup(name) : NULL;
      item->description = (description != NULL) ? g_strdup(description) : NULL;
      item->client_data = client_data;
      item->id = id;
      item->allow_multiple = allow_multiple;
      item->stay_on_target = stay_on_target;

      /* Load icon pixmap and mask pair if icon data is given. */
      if(icon_data != NULL)
      {
          GdkWindow *window = NULL;
          GdkBitmap *mask;
          GdkPixmap *pixmap;
          GtkWidget *w = slist->toplevel;

          if(w != NULL)
            window = w->window;
          if(window != NULL)
          {
                GtkStyle *style = gtk_widget_get_style(w);
                if(style == NULL)
                    style = gtk_widget_get_default_style();

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

/*
 *    Deletes all items in the stack lists's main cache of items.
 */
void StackListClear(stack_list_struct *slist)
{
      gint i;
      stack_list_item_struct *item;


      if(slist == NULL)
          return;

      for(i = 0; i < slist->total_items; i++)
      {
          item = slist->item[i];
          if(item == NULL)
            continue;

          g_free(item->name);
          g_free(item->description);

          if(item->icon_pixmap != NULL)
            gdk_pixmap_unref(item->icon_pixmap);
            if(item->icon_mask != NULL)
                gdk_bitmap_unref(item->icon_mask);

          g_free(item);
      }

      g_free(slist->item);
      slist->item = NULL;
      slist->total_items = 0;

      slist->last_description_item = NULL;
}


/*
 *    Appends a new item to the source list, the given id must
 *    match an id in the stack lists's cache of items.
 */
void StackListItemAppendSrc(stack_list_struct *slist, gint id)
{
      gint i, row;
      gchar **strv;
      GtkCList *clist;
      stack_list_item_struct *item;


      /* Get stack list item that matches the given id. */
      item = StackListMatchItemByID(slist, id);
      if(item == NULL)
          return;

      /* Get source clist. */
      clist = (GtkCList *)slist->src_clist;
      if(clist == NULL)
          return;


      /* Allocate cell text. */
      strv = (gchar **)g_malloc0(
          clist->columns * sizeof(gchar *)
      );
      for(i = 0; i < clist->columns; i++)
          strv[i] = g_strdup("");

      /* Append a new item to the clist. */
      row = gtk_clist_append(clist, strv);

      /* Deallocate cell text. */
      for(i = 0; i < clist->columns; i++)
            g_free(strv[i]);
      g_free(strv);
      strv = NULL;


      /* Set new row. */
      if(row > -1)
      {
          if((item->icon_pixmap != NULL) && (item->name != NULL))
            gtk_clist_set_pixtext(
                clist, row, 0,
                (item->name != NULL) ? item->name : "",
                2,
                item->icon_pixmap, item->icon_mask
            );
          else if(item->icon_pixmap != NULL)
            gtk_clist_set_pixmap(
                clist, row, 0,
                item->icon_pixmap, item->icon_mask
            );
          else if(item->name != NULL)
            gtk_clist_set_text(
                clist, row, 0, item->name
            );

          /* Set row data, but no destroy function since the row data
           * is shared and not suppose to be deallocated when the clist
           * row is destroyed.
           */
          gtk_clist_set_row_data(clist, row, item);
      }
}

/*
 *      Appends a new item to the target list, the given id must
 *      match an id in the stack lists's cache of items.
 */
void StackListItemAppendTar(stack_list_struct *slist, gint id)
{
        gint i, row;
        gchar **strv;
        GtkCList *clist;
        stack_list_item_struct *item;


        /* Get stack list item that matches the given id. */
        item = StackListMatchItemByID(slist, id);
        if(item == NULL)
            return;

        /* Get target clist. */
        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;


        /* Allocate cell text. */
        strv = (gchar **)g_malloc0(
            clist->columns * sizeof(gchar *)
        );
        for(i = 0; i < clist->columns; i++)
            strv[i] = g_strdup("");

        /* Append a new item to the clist. */
        row = gtk_clist_append(clist, strv);

        /* Deallocate cell text. */
        for(i = 0; i < clist->columns; i++)
            g_free(strv[i]);
        g_free(strv);
        strv = NULL;


        /* Set new row. */
        if(row > -1)
        {
            if((item->icon_pixmap != NULL) && (item->name != NULL))
                gtk_clist_set_pixtext(
                    clist, row, 0,
                    (item->name != NULL) ? item->name : "",
                    2,
                    item->icon_pixmap, item->icon_mask
                );
            else if(item->icon_pixmap != NULL)
                gtk_clist_set_pixmap(
                    clist, row, 0,
                    item->icon_pixmap, item->icon_mask
                );
            else if(item->name != NULL)
                gtk_clist_set_text(
                    clist, row, 0, item->name
                );

            /* Set row data, but no destroy function since the row data
             * is shared and not suppose to be deallocated when the clist
             * row is destroyed.
             */
            gtk_clist_set_row_data(clist, row, item);
        }
}

/*
 *    Creates items on the source clist based on all items in the
 *    stack list's main item cache.
 */
void StackListItemSetAllFromCacheSrc(stack_list_struct *slist)
{
      gint i;
      stack_list_item_struct *item;
      GtkCList *clist;


      if(slist == NULL)
          return;

        /* Get source clist. */
        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;

      gtk_clist_freeze(clist);

      /* Iterate through all items on the stack list's main cache
       * and set them to the source list.
       */
      for(i = 0; i < slist->total_items; i++)
      {
          item = slist->item[i];
          if(item == NULL)
            continue;

          StackListItemAppendSrc(slist, item->id);
      }

      gtk_clist_thaw(clist);
}


/*
 *    Removes all items who's id matches the given id from the
 *    source clist.
 *
 *      If exclude_allowed_multiples is TRUE than if the item allows
 *      multiple coppies of itself then it will not be removed.
 */
void StackListItemRemoveByIDSrc(
      stack_list_struct *slist, gint id,
      gbool exclude_allowed_multiples
)
{
      gint i;
      GtkCList *clist;
      stack_list_item_struct *item_ptr;


      if(slist == NULL)
          return;

      clist = (GtkCList *)slist->src_clist;
      if(clist == NULL)
          return;

      gtk_clist_freeze(clist);

      /* Iterate through all rows, checking each item structure's
       * id if it matches the given id.
       */
      for(i = 0; i < clist->rows; i++)
      {
          item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
            clist, i
          ));
          if(item_ptr == NULL)
            continue;

          /* Skip if we are to exclude items that allow multiples and
           * this item allows multiple coppies of itself.
           */
          if(exclude_allowed_multiples &&
               item_ptr->allow_multiple
          )
            continue;

          /* IDs match? */
          if(item_ptr->id == id)
          {
            /* Remove this row. */
            gtk_clist_remove(clist, i);
          }
      }

      gtk_clist_thaw(clist);
}

/*
 *      Removes all items who's id matches the given id from the
 *      source clist.
 *
 *    If exclude_allowed_multiples is TRUE than if the item allows
 *    multiple coppies of itself then it will not be removed.
 */
void StackListItemRemoveByIDTar(
      stack_list_struct *slist, gint id,
      gbool exclude_allowed_multiples
)
{
        gint i;
        GtkCList *clist;
        stack_list_item_struct *item_ptr;


        if(slist == NULL)
            return;

        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;

        gtk_clist_freeze(clist);

        /* Iterate through all rows, checking each item structure's
         * id if it matches the given id.
         */
        for(i = 0; i < clist->rows; i++)
        {
            item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
                clist, i
            ));
            if(item_ptr == NULL)
                continue;

            /* Skip if we are to exclude items that allow multiples and
             * this item allows multiple coppies of itself.
             */
            if(exclude_allowed_multiples &&
               item_ptr->allow_multiple
            )
                continue;

            /* IDs match? */
            if(item_ptr->id == id)
            {
                /* Remove this row. */
                gtk_clist_remove(clist, i);
            }
        }

        gtk_clist_thaw(clist);
}

/*
 *    Deletes all items in the stack lists's source list.
 */
void StackListItemClearSrc(stack_list_struct *slist)
{
      GtkCList *clist;


        if(slist == NULL)
            return;

      clist = (GtkCList *)slist->src_clist;
      if(clist == NULL)
          return;

      slist->src_last_selected = -1;

      gtk_clist_freeze(clist);
      gtk_clist_clear(clist);
      gtk_clist_thaw(clist);
}

/*
 *      Deletes all items in the stack lists's target list.
 */
void StackListItemClearTar(stack_list_struct *slist)
{
        GtkCList *clist;


        if(slist == NULL)
            return;

        clist = (GtkCList *)slist->tar_clist;
        if(clist == NULL)
            return;

        slist->tar_last_selected = -1;

        gtk_clist_freeze(clist);
        gtk_clist_clear(clist);
        gtk_clist_thaw(clist);
}


/*
 *    Returns a dynamically allocated array of gint's, each
 *    representing the id of the item currently in the source list.
 *    The calling function needs to deallocate the returned pointer.
 *
 *    Can return NULL on error or empty list.
 */
gint *StackListItemGetSrc(stack_list_struct *slist, gint *total)
{
        gint i;
        gint *list;
        stack_list_item_struct *item_ptr;
        GtkCList *clist;


        if((slist == NULL) || (total == NULL))
            return(NULL);

        clist = (GtkCList *)slist->src_clist;
        if(clist == NULL)
            return(NULL);


        /* Get total rows on clist. */
        *total = clist->rows;

        /* No rows on clist? */
        if(*total <= 0)
            return(NULL);

        /* Allocate gint array. */
        list = (gint *)g_malloc0((*total) * sizeof(gint));
        if(list == NULL)
        {
            *total = 0;
            return(NULL);
        }

        /* Iterate through each row. */
        for(i = 0; i < clist->rows; i++)
        {
            item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
                clist, i
            ));
            if(item_ptr == NULL)
                continue;

            /* Set item's id to the current index on the gint list. */
            list[i] = item_ptr->id;
        }

        return(list);
}

/*
 *      Returns a dynamically allocated array of gint's, each
 *      representing the id of the item currently in the target list.
 *      The calling function needs to deallocate the returned pointer.
 *
 *      Can return NULL on error or empty list.
 */
gint *StackListItemGetTar(stack_list_struct *slist, gint *total)
{
      gint i;
      gint *list;
      stack_list_item_struct *item_ptr;
      GtkCList *clist;


        if((slist == NULL) || (total == NULL))
            return(NULL);

      clist = (GtkCList *)slist->tar_clist;
      if(clist == NULL)
          return(NULL);


      /* Get total rows on clist. */
      *total = clist->rows;

      /* No rows on clist? */
      if(*total <= 0)
          return(NULL);

      /* Allocate gint array. */
      list = (gint *)g_malloc0((*total) * sizeof(gint));
      if(list == NULL)
      {
          *total = 0;
          return(NULL);
      }

      /* Iterate through each row. */
      for(i = 0; i < clist->rows; i++)
      {
          item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
            clist, i
          ));
          if(item_ptr == NULL)
            continue;

          /* Set item's id to the current index on the gint list. */
          list[i] = item_ptr->id;
      }

        return(list);
}


/*
 *    Creates a new stack_list_struct and parents it to the given
 *    parent which must be a GtkVBox.
 */
stack_list_struct *StackListNew(
      GtkWidget *parent,      /* A vbox. */
        const gchar *src_title, const gchar *tar_title,
        void (*changed_cb)(gpointer, gpointer),
        gpointer client_data
)
{
      gint border_minor = 2;
      gint state;
      GdkColor *c;
      GtkRcStyle *rcstyle;
      GtkWidget *w, *parent2, *parent3, *parent4;
      GtkCList *clist;
/*
const gchar *rcstr = "\n\
style \"slist-tooltips-style\" { \n\
 bg[NORMAL] = \"#ffffc0\"\n\
 fg[NORMAL] = \"#000000\"\n\
}\n\
widget \"*slist-tooltips\" style \"slist-tooltips-style\"\n\
";
 */
      stack_list_struct *slist = STACK_LIST(g_malloc0(
          sizeof(stack_list_struct)
      ));
      if(slist == NULL)
          return(slist);


      /* Reset values. */
      slist->src_last_selected = -1;
      slist->tar_last_selected = -1;

      slist->item = NULL;
      slist->total_items = 0;

      slist->last_description_item = NULL;


      /* Create toplevel (main vbox). */
      slist->toplevel = w = gtk_vbox_new(FALSE, border_minor);
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
      parent = w;

      /* Hbox for source and target lists. */
      w = gtk_hbox_new(FALSE, border_minor);
        gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        parent = w;

      /* Scrolled window for source clist. */
        w = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(
            GTK_SCROLLED_WINDOW(w),
            GTK_POLICY_AUTOMATIC,
            GTK_POLICY_AUTOMATIC
        );
      gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        parent2 = w;

      /* Create source list. */
      if(src_title != NULL)
      {
          gchar *strv[1];
          strv[0] = g_strdup(src_title);
          slist->src_clist = w = gtk_clist_new_with_titles(
            1, strv
          );
          g_free(strv[0]);
      }
      else
      {
          slist->src_clist = w = gtk_clist_new(1);
      }
        clist = GTK_CLIST(w);
        gtk_clist_set_row_height(clist, STACK_LIST_ROW_SPACING);
      gtk_clist_set_column_width(clist, 0, 10);
        gtk_clist_set_selection_mode(clist, GTK_SELECTION_SINGLE);
      gtk_clist_column_titles_passive(clist);
        gtk_widget_add_events(
            w,
          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
            GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
          GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_press_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_release_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "enter_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "leave_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect_after(
            GTK_OBJECT(w), "button_press_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "motion_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "select_row",
            GTK_SIGNAL_FUNC(StackListSelectRowCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "unselect_row",
            GTK_SIGNAL_FUNC(StackListUnselectRowCB), slist
        );
        gtk_container_add(GTK_CONTAINER(parent2), w);
        gtk_widget_show(w);


        /* Island vbox to contain arrow buttons. */
        w = gtk_vbox_new(TRUE, 0);
        gtk_box_pack_start(GTK_BOX(parent), w, FALSE, FALSE, 0);
        gtk_widget_show(w);
        parent2 = w;


      /* Vbox for left and right arrow buttons. */
      w = gtk_vbox_new(FALSE, 0);
      gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
      parent3 = w;

      /* Right arrow button. */
      slist->right_arrow_btn = w = gtk_button_new();
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(StackListAddCB), slist
        );
      gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent4 = w;
      /* Arrow. */
      w = gtk_arrow_new(GTK_ARROW_RIGHT, GTK_SHADOW_OUT);
      gtk_widget_set_usize(
          w, STACK_LIST_ARROW_WIDTH, STACK_LIST_ARROW_HEIGHT
      );
      gtk_container_add(GTK_CONTAINER(parent4), w);
      gtk_widget_show(w);

        /* Left arrow button. */
        slist->left_arrow_btn = w = gtk_button_new();
      gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(StackListRemoveCB), slist
        );
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent4 = w;
        /* Arrow. */
        w = gtk_arrow_new(GTK_ARROW_LEFT, GTK_SHADOW_OUT);
        gtk_widget_set_usize(
            w, STACK_LIST_ARROW_WIDTH, STACK_LIST_ARROW_HEIGHT
        );
        gtk_container_add(GTK_CONTAINER(parent4), w);
        gtk_widget_show(w);


        /* Vbox for up and down arrow buttons. */
        w = gtk_vbox_new(FALSE, 0);
        gtk_box_pack_start(GTK_BOX(parent2), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent3 = w;

        /* Up arrow button. */
        slist->up_arrow_btn = w = gtk_button_new();
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(StackListShiftUpCB), slist
        );
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent4 = w;
        /* Arrow. */
        w = gtk_arrow_new(GTK_ARROW_UP, GTK_SHADOW_OUT);
        gtk_widget_set_usize(
            w, STACK_LIST_ARROW_WIDTH, STACK_LIST_ARROW_HEIGHT
        );
        gtk_container_add(GTK_CONTAINER(parent4), w);
        gtk_widget_show(w);

        /* Down arrow button. */
        slist->down_arrow_btn = w = gtk_button_new();
        gtk_signal_connect(
            GTK_OBJECT(w), "clicked",
            GTK_SIGNAL_FUNC(StackListShiftDownCB), slist
        );
        gtk_box_pack_start(GTK_BOX(parent3), w, TRUE, FALSE, 0);
        gtk_widget_show(w);
        parent4 = w;
        /* Arrow. */
        w = gtk_arrow_new(GTK_ARROW_DOWN, GTK_SHADOW_OUT);
        gtk_widget_set_usize(
            w, STACK_LIST_ARROW_WIDTH, STACK_LIST_ARROW_HEIGHT
        );
        gtk_container_add(GTK_CONTAINER(parent4), w);
        gtk_widget_show(w);




        /* Scrolled window for target clist. */
        w = gtk_scrolled_window_new(NULL, NULL);
        gtk_scrolled_window_set_policy(
            GTK_SCROLLED_WINDOW(w),
            GTK_POLICY_AUTOMATIC,
            GTK_POLICY_AUTOMATIC
        );
        gtk_box_pack_start(GTK_BOX(parent), w, TRUE, TRUE, 0);
        gtk_widget_show(w);
        parent2 = w;

        /* Create target list. */
        if(tar_title != NULL)
        {
            gchar *strv[1];
            strv[0] = g_strdup(tar_title);
            slist->tar_clist = w = gtk_clist_new_with_titles(
                1, strv
            );
            g_free(strv[0]);
        }
        else
        {
            slist->tar_clist = w = gtk_clist_new(1);
        }
        clist = GTK_CLIST(w);
        gtk_clist_set_row_height(clist, STACK_LIST_ROW_SPACING);
        gtk_clist_set_column_width(clist, 0, 10);
      gtk_clist_set_selection_mode(clist, GTK_SELECTION_SINGLE);
        gtk_clist_column_titles_passive(clist);
        gtk_widget_add_events(
            w,
            GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
          GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK |
          GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_press_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "key_release_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "enter_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "leave_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect_after(
            GTK_OBJECT(w), "button_press_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "motion_notify_event",
            GTK_SIGNAL_FUNC(StackListCListEventCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "select_row",
            GTK_SIGNAL_FUNC(StackListSelectRowCB), slist
        );
        gtk_signal_connect(
            GTK_OBJECT(w), "unselect_row",
            GTK_SIGNAL_FUNC(StackListUnselectRowCB), slist
        );
        gtk_container_add(GTK_CONTAINER(parent2), w);
        gtk_widget_show(w);



      /* Frame for description label. */
      w = gtk_frame_new(NULL);
      gtk_frame_set_shadow_type(GTK_FRAME(w), GTK_SHADOW_IN);
        gtk_box_pack_start(GTK_BOX(slist->toplevel), w, FALSE, FALSE, 0);
        gtk_widget_show(w);
        parent = w;

      /* Style for background. */
        rcstyle = gtk_rc_style_new();
        state = GTK_STATE_NORMAL;
        rcstyle->color_flags[state] = GTK_RC_BG /* | GTK_RC_BASE */;
        c = &rcstyle->bg[state];
        c->red = 1.0 * (guint16)-1;
        c->green = 1.0 * (guint16)-1;
        c->blue = 0.7529411 * (guint16)-1;
      /* Event box for background. */
      w = gtk_event_box_new();
      gtk_widget_modify_style(w, rcstyle);
      gtk_container_add(GTK_CONTAINER(parent), w);
      gtk_widget_show(w);
        parent2 = w;
      /* Unref style. */
        GUIRCStyleDeallocUnref(rcstyle);
      rcstyle = NULL;

      w = gtk_hbox_new(FALSE, 0);
      gtk_container_border_width(GTK_CONTAINER(w), border_minor);
        gtk_container_add(GTK_CONTAINER(parent2), w);
      gtk_widget_show(w);
      parent2 = w;

      /* Description label. */
      slist->description_label = w = gtk_label_new("");
      gtk_box_pack_start(GTK_BOX(parent2), w, FALSE, FALSE, 0);
        gtk_widget_show(w);


#define DO_ADD_MENU_ITEM_LABEL  \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_LABEL, accel_group, \
  icon, label, accel_key, accel_mods, (void **)&fw, \
  mclient_data, func_cb \
 ); \
}
#define DO_ADD_MENU_SEP         \
{ \
 w = GUIMenuItemCreate( \
  menu, GUI_MENU_ITEM_TYPE_SEPARATOR, NULL, \
  NULL, NULL, 0, 0, NULL, \
  NULL, NULL \
 ); \
}
      /* Source clist right-click menu. */
      if(1)
      {
            GtkWidget *menu = (GtkWidget *)GUIMenuCreate();
            u_int8_t **icon;
            const gchar *label;
            gint accel_key;
            guint accel_mods;
            gpointer accel_group = NULL;
            gpointer mclient_data = slist;
            void (*func_cb)(GtkWidget *w, gpointer);
            gpointer fw;

            icon = (u_int8_t **)icon_add_20x20_xpm;
            label = "Add";
            accel_key = 0;
            accel_mods = 0;
            func_cb = StackListAddCB;
            DO_ADD_MENU_ITEM_LABEL
            slist->src_add_mi = w;

          slist->src_menu = menu;
      }

      /* Target clist right-click menu. */
        if(1)
        {
            GtkWidget *menu = (GtkWidget *)GUIMenuCreate();
            u_int8_t **icon;
            const gchar *label;
            gint accel_key;
            guint accel_mods;
            gpointer accel_group = NULL;
            gpointer mclient_data = slist;
            void (*func_cb)(GtkWidget *w, gpointer);
            gpointer fw;

            icon = (u_int8_t **)icon_remove_20x20_xpm;
            label = "Remove";
            accel_key = 0;
            accel_mods = 0;
            func_cb = StackListRemoveCB;
            DO_ADD_MENU_ITEM_LABEL
            slist->tar_remove_mi = w;

          DO_ADD_MENU_SEP

            icon = NULL;
            label = "Shift Up";
            accel_key = 0;
            accel_mods = 0;
            func_cb = StackListShiftUpCB;
            DO_ADD_MENU_ITEM_LABEL
            slist->tar_up_mi = w;

            icon = NULL;
            label = "Shift Down";
            accel_key = 0;
            accel_mods = 0;
            func_cb = StackListShiftDownCB;
            DO_ADD_MENU_ITEM_LABEL
            slist->tar_down_mi = w;

            slist->tar_menu = menu;
        }
#undef DO_ADD_MENU_ITEM_LABEL
#undef DO_ADD_MENU_SEP

      return(slist);
}

/*
 *    Updates widgets on the given slist to reflect the current data
 *    represented.
 */
void StackListUpdateMenus(stack_list_struct *slist)
{
      gbool sensitive;
      GList *glist;
      GtkCList *clist;
      GtkWidget *w;


      if(slist == NULL)
          return;

#define DO_SET_WIDGET_SENSITIVE     \
{ \
 if(w != NULL) \
  gtk_widget_set_sensitive(w, sensitive); \
}

      /* Update widgets with respect to the target clist. */
      clist = (GtkCList *)slist->tar_clist;
      if(clist != NULL)
      {
          gint tar_sel_row;
          stack_list_item_struct *item_ptr;


          glist = clist->selection_end;
          tar_sel_row = (glist != NULL) ? (gint)glist->data : -1;
          item_ptr = STACK_LIST_ITEM(gtk_clist_get_row_data(
            clist, tar_sel_row
          ));

          w = slist->up_arrow_btn;
          sensitive = (tar_sel_row > 0) ? TRUE : FALSE;
          DO_SET_WIDGET_SENSITIVE
            w = slist->tar_up_mi;
            DO_SET_WIDGET_SENSITIVE

            w = slist->down_arrow_btn;
          if((tar_sel_row < (clist->rows - 1)) &&
               (tar_sel_row >= 0)
          )
                sensitive = TRUE;
          else
            sensitive = FALSE;
            DO_SET_WIDGET_SENSITIVE
            w = slist->tar_down_mi;
            DO_SET_WIDGET_SENSITIVE

            w = slist->left_arrow_btn;
            sensitive = (tar_sel_row > -1) ? TRUE : FALSE;
          if(sensitive)
            sensitive = (item_ptr != NULL) ?
                !item_ptr->stay_on_target : FALSE;
            DO_SET_WIDGET_SENSITIVE
            w = slist->tar_remove_mi;
            DO_SET_WIDGET_SENSITIVE
      }

        /* Update widgets with respect to the source clist. */
        clist = (GtkCList *)slist->src_clist;
        if(clist != NULL)
        {
            gint src_sel_row = -1;

            glist = clist->selection_end;
            if(glist != NULL)
                src_sel_row = (gint)glist->data;

            w = slist->right_arrow_btn;
            sensitive = (src_sel_row > -1) ? TRUE : FALSE;
            DO_SET_WIDGET_SENSITIVE
            w = slist->src_add_mi;
            DO_SET_WIDGET_SENSITIVE
      }

#undef DO_SET_WIDGET_SENSITIVE

}

/*
 *    Maps the stack list.
 */
void StackListMap(stack_list_struct *slist)
{
      GtkWidget *w;


      if(slist == NULL)
          return;

      w = slist->toplevel;
      if(w == NULL)
          return;

      gtk_widget_show(w);
}

/*
 *    Unmaps the stack list.
 */
void StackListUnmap(stack_list_struct *slist)
{
        GtkWidget *w;


        if(slist == NULL)
            return;

        w = slist->toplevel;
        if(w == NULL)
            return;

        gtk_widget_hide(w);
}

/*
 *    Deallocates all resources of the given stack list and deallocates
 *    the structure itself.
 */
void StackListDelete(stack_list_struct *slist)
{
      GtkWidget **w;


      if(slist == NULL)
          return;

      /* Clear source and target lists. */
      StackListItemClearSrc(slist);
      StackListItemClearTar(slist);

      /* Delete all cached items. */
      StackListClear(slist);

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

          w = &slist->src_menu;
          slist->src_add_mi = NULL;
          slist->src_remove_mi = NULL;
            DO_DESTROY_WIDGET

            w = &slist->tar_menu;
            slist->tar_add_mi = NULL;
            slist->tar_remove_mi = NULL;
            slist->tar_up_mi = NULL;
            slist->tar_down_mi = NULL;
            DO_DESTROY_WIDGET

          w = &slist->src_clist;
            DO_DESTROY_WIDGET
            w = &slist->tar_clist;
            DO_DESTROY_WIDGET

            w = &slist->left_arrow_btn;
            DO_DESTROY_WIDGET
            w = &slist->right_arrow_btn;
            DO_DESTROY_WIDGET

            w = &slist->up_arrow_btn;
            DO_DESTROY_WIDGET
            w = &slist->down_arrow_btn;
            DO_DESTROY_WIDGET

            w = &slist->description_label;
            DO_DESTROY_WIDGET

          w = &slist->toplevel;
          DO_DESTROY_WIDGET

#undef DO_DESTROY_WIDGET
      }

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

Generated by  Doxygen 1.6.0   Back to index