Logo Search packages:      
Sourcecode: xdvik-ja version File versions  Download package

xaw_menu.c

/*
 * Copyright (c) 2001-2004 the xdvik development team
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * PAUL VOJTA OR ANY OTHER AUTHOR OF THIS SOFTWARE BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 */

/*
 * Menu bar implementation for the Athena widget set.
 */
#include "xdvi-config.h"
#include "xdvi.h"

#include "c-openmx.h"
#include "events.h"
#include "dvi-draw.h"
#include "dvi-init.h"
#include "statusline.h"
#include "pagesel.h"
#include "util.h"
#include "x_util.h"
#include "xaw_menu.h"
#include "message-window.h"
#include "my-snprintf.h"
#include "filehist.h"
#ifdef NEW_MENU_CREATION
#include "menu.h"
#endif /* NEW_MENU_CREATION */

#ifndef MOTIF /* entire file */

#include <ctype.h>

#include <X11/Intrinsic.h>
#include <X11/Xatom.h>
#include <X11/StringDefs.h>
#include <X11/Shell.h>  /* needed for def. of XtNiconX */

#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/SmeLine.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Text.h>
#include <X11/Xaw/Panner.h>   
#include <X11/Xaw/Porthole.h> 
#include <X11/Xaw/Command.h>

#ifndef     MAX
# define MAX(i, j)       ( (i) > (j) ? (i) : (j) )
#endif


#ifndef NEW_MENU_CREATION
#define SEP_CHAR ':' /* character separating entries in translations lines */
#endif

/* needed to count the callbacks */
static int destroy_count = 0;

/* width of button panel */
static int my_panel_width = 0;

/* access method for panel width */
int
get_panel_width(void)
{
    int retval = 0;
    if (resource.expert_mode & XPRT_SHOW_BUTTONS)
      retval = my_panel_width;
    TRACE_GUI((stderr, "get_panel_width: %d", retval));
    return retval;
}

#ifndef NEW_MENU_CREATION
typedef enum { INVALID, /* some error */
             NONE,      /* no new button created */
             MENU_SEPARATOR, MENU_BUTTON, MENU_ENTRY, COMMAND_BUTTON } buttonTypeT;

struct button_info {
    struct button_info *next;
    char *label;
    struct xdvi_action *action;
    Widget widget;
    buttonTypeT type;
};

static Widget panner = 0;
static struct button_info *b_head = NULL;

#define MAX_MENU_NUM 128
#define MAX_BUTTON_NUM 128

static struct menu_list_ {
    char *name;
    Widget button_widget;
    Widget popup_widget;
} menu_list[MAX_MENU_NUM];

#endif /* not NEW_MENU_CREATION */

#ifdef NEW_MENU_CREATION
/*
  ================================================================================
  Pixmaps indicating the state of menu buttons (radiobutton/checkbox
  on/off, cascading menu). Inspired by menu.c, `check_bits' in the xterm source.
  ================================================================================
*/
#include "xaw_bitmaps.h"
static Pixmap menu_check_on_bitmap;
static Pixmap menu_check_off_bitmap;
static Pixmap menu_radio_on_bitmap;
static Pixmap menu_radio_off_bitmap;
static Pixmap menu_arrow_bitmap;
#else
#include "xaw_bitmaps.h"
/* lifted from menu.c, check_bits in xterm */
static Pixmap menu_check_bitmap;
static Pixmap menu_arrow_bitmap;
#endif /* NEW_MENU_CREATION */

/*
  ============================================================
  Hack for pullright menus part I: data
  ============================================================
*/

/* There are a few custom widgets for pullright menus out there, but
 * these are old and potentially buggy, so just do it manually via an
 * event handler, similar to Motif tooltips.
 */
static XtIntervalId m_timeout = 0;
static Widget m_active_submenu = NULL;  /* if not NULL, the currently active pullright */
static Widget m_submenu = NULL;           /* parent of the currently active pullright
                                 (i.e. the menu label in the parent window) */

static void ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params);

/* to safely pop down the pullright, this callback is added to its parent menu */
static XtActionsRec menu_actions[] = {
    { "popdown-submenus", ActPopdownSubmenus }
};

static XtAccelerators menu_accels;

struct pullright_position_info {
    Position y;
    Dimension w;
    Dimension h;
    Dimension border_width;
    Widget menu;
};


#ifdef NEW_MENU_CREATION
/*
 * Set all pixmaps indicating the state of the wigdet pointed to by `elems'.
 */
void
xaw_set_button_state(struct button_elems *elems, Boolean on)
{
    static Arg args[] = {
      { XtNleftBitmap, (XtArgVal)0  },
      { XtNrightBitmap, (XtArgVal)0 }
    };

    if (elems->type == BT_CHECK)
      args[0].value = on ? menu_check_on_bitmap : menu_check_off_bitmap;
    else if (elems->type == BT_RADIO)
      args[0].value = on ? menu_radio_on_bitmap : menu_radio_off_bitmap;
    if (elems->submenu != NULL)
      args[1].value = menu_arrow_bitmap;

    XtSetValues(elems->widget, args, XtNumber(args));
}

/*
 * Initialize the bitmaps.
 */
void
xaw_initialize_menu_bitmaps(void)
{
    static Boolean initialized = False;
    if (!initialized) {
      initialized = True;
      menu_check_on_bitmap
          = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                            RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                            (char *)menu_check_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
      menu_check_off_bitmap
          = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                            RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                            (char *)menu_check_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
      menu_radio_on_bitmap
          = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                            RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                            (char *)menu_radio_on_bits, MENU_BITMAP_W, MENU_BITMAP_H);
      menu_radio_off_bitmap
          = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                            RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                            (char *)menu_radio_off_bits, MENU_BITMAP_W, MENU_BITMAP_H);
      menu_arrow_bitmap
          = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                            RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                            (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
    }
}

#else

/* toggle `checked' symbol on xaw menu w */
void
toggle_tick(Boolean val, Widget w)
{
    static Arg args = { XtNleftBitmap, (XtArgVal) 0 };
    if (val)
      args.value = (XtArgVal) menu_check_bitmap;
    else
      args.value = None;
    XtSetValues(w, &args, 1);
}

void
toggle_menu(int val, XtActionProc proc)
{
    struct button_info *bp;

    for (bp = b_head; bp != NULL; bp = bp->next) {
      if (bp->action != NULL && bp->action->proc == proc && bp->action->param != NULL) {
          TRACE_GUI((stderr, "found proc; param: |%s|", bp->action->param));
          if (strcmp(bp->action->param, "toggle") == 0) {
            if (val != 0)
                toggle_tick(True, bp->widget);
            else
                toggle_tick(False, bp->widget);
          }
          else if (strcmp(bp->action->param, "a") == 0) {
            if (val == shrink_to_fit())
                toggle_tick(True, bp->widget);
            else
                toggle_tick(False, bp->widget);
          }
          else {
            int testval = strtoul(bp->action->param, (char **)NULL, 10);
            if (testval == val) {
                TRACE_GUI((stderr, "enabling param |%s|", bp->action->param));
                toggle_tick(True, bp->widget);
            }
            else
                toggle_tick(False, bp->widget);
          }
      }
    }
}

/* initialize `checked' symbol on xaw menu w */
static void
initialize_tick_marks(void)
{
    int use_gs;
    if (menu_check_bitmap == None) {
      int check_width = 9;
      int check_height = 8;
      unsigned char check_bits[] = {
          0x00, 0x01, 0x80, 0x01, 0xc0, 0x00, 0x60, 0x00,
          0x31, 0x00, 0x1b, 0x00, 0x0e, 0x00, 0x04, 0x00
      };

      menu_check_bitmap = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                                      RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                                      (char *)check_bits, check_width, check_height);
    }
    
    /* initialize tickmarks for all possible actions */
     use_gs = resource.postscript;
#ifdef PS_GS
    if (!resource.useGS)
      use_gs = 0;
#endif

    toggle_menu(use_gs, Act_set_ps);
    toggle_menu(resource.gs_alpha, Act_set_gs_alpha);
    toggle_menu(resource.keep_flag, Act_set_keep_flag);
    toggle_menu(resource.pixels_per_inch / mane.shrinkfactor, Act_shrink_to_dpi);
    toggle_menu(mane.shrinkfactor, Act_set_shrink_factor);
    toggle_menu(resource.use_tex_pages, Act_use_tex_pages);
    toggle_menu(resource.mouse_mode, Act_switch_mode);
}
#endif /* NEW_MENU_CREATION */

/* ================================================================================
   ================================================================================
*/

static Widget line_widget, panel_widget;

/* used for communication with the pagelist in xaw_create_pagelist */
static int my_y_pos;

/* access function: panel, height of buttons etc. */
void
xaw_create_pagelist(void)
{
    Dimension height, width;
    int button_width = get_panel_width() - 2 * (resource.btn_side_spacing + resource.btn_border_width);
    
    XtVaGetValues(globals.widgets.clip_widget, XtNheight, &height, NULL);
    width = MAX(button_width, xaw_get_pagelist_size());
    height -= resource.btn_top_spacing + resource.btn_border_width + my_y_pos;
    xaw_create_pagelist_widgets(height, width, my_y_pos, panel_widget);
}


static XtCallbackRec command_call[] = {
    {handle_command, NULL},
    {NULL, NULL},
};

#ifdef NEW_MENU_CREATION
void xaw_create_menu(struct button_info *items, Widget parent, int menu_depth, int *ret_width)
{
    
}

Widget
xaw_create_menu_widgets(Widget parent)
{
    /* hack to disable the magnifier in the panel: */
    XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");
    
    line_widget = XtVaCreateWidget("line", widgetClass, parent,
                           XtNbackground, (XtArgVal)resource.fore_Pixel,
                           XtNwidth, (XtArgVal)1,
                           XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
                           XtNborderWidth, (XtArgVal)0,
                           XtNtop, (XtArgVal)XtChainTop,
                           XtNbottom, (XtArgVal)XtChainBottom,
                           XtNleft, (XtArgVal)XtChainRight,
                           XtNright, (XtArgVal)XtChainRight,
                           NULL);
    panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, parent,
                            XtNborderWidth, (XtArgVal)0,
                            XtNfromHoriz, (XtArgVal)line_widget,
                            XtNtranslations, (XtArgVal)panel_translations,
                            XtNtop, (XtArgVal)XtChainTop,
                            XtNbottom, (XtArgVal)XtChainBottom,
                            XtNleft, (XtArgVal)XtChainRight,
                            XtNright, (XtArgVal)XtChainRight,
                            NULL);
    return panel_widget;
}

#else /* NEW_MENU_CREATION */


static void
filehist_select_cb(Widget w, XtPointer client_data, XtPointer call_data)
{
    char *label, *ptr;
    int idx;

    UNUSED(client_data);
    UNUSED(call_data);
    
    XtVaGetValues(w, XtNlabel, &label, NULL);

    idx = strtol(label, &ptr, 10) - 1;
    while (isspace(*ptr))
      ptr++;
    TRACE_GUI((stderr, "User selected: %d, `%s'", idx, ptr));
    if (idx == 0) {
      globals.ev.flags |= EV_RELOAD;
      return;
    }
    file_history_open(ptr);
}

static void
update_menu_labels(Widget menu)
{
    WidgetList children;
    int num_children;
    int i;

    static char *buf = NULL;
    static size_t buf_len = 0;
    size_t new_len;
    
    XtVaGetValues(menu,
              XtNnumChildren, &num_children,
              XtNchildren, &children,
              NULL);
    for (i = 0; i < (int)file_history_size(); i++) {
      int dummy_page;
      char *filename;
      
      if ((filename = file_history_get_elem(i, &dummy_page)) == NULL) {
          XDVI_ERROR((stderr, "Error accessing element %d of file history", i));
          continue;
      }

      new_len = LENGTH_OF_INT + strlen(filename) + 1;
      if (new_len > buf_len) {
          buf = xrealloc(buf, new_len);
          buf_len = new_len;
      }
      
      sprintf(buf, "%d %s", i + 1, filename);
      XtVaSetValues(children[i], XtNlabel, buf, NULL);
      TRACE_GUI((stderr, "child %d: `%s'", i, buf));
    }

    /* if history size < number of menu entries, destroy excess menu entries */
    for (; i < num_children; i++) {
      XtDestroyWidget(children[i]);
    }
}

void
filehist_menu_add_entry(const char *filename)
{
    static char *buf = NULL;
    static size_t buf_len = 0;
    size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
    
    Widget menu;
    /* Don't report an error here, since "filehist_pullright" is only created on-demand
       when user clicks on menu, but this may be called before from the event loop.
       (The menu will still contain this entry when it's created later.) */
    if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
      int num_children;
      Widget w;

      if (new_len > buf_len) {
          buf = xrealloc(buf, new_len);
          buf_len = new_len;
      }
      
      XtVaGetValues(menu, XtNnumChildren, &num_children, NULL);
      sprintf(buf, "%d %s", num_children + 1, filename);
      
      w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
                            XtNlabel, buf,
                            XtNleftMargin, 10,
                            NULL);
      XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
      update_menu_labels(menu);
    }
}

void
filehist_menu_refresh(void)
{
    Widget menu;

    /* Don't report an error here, since "filehist_pullright" is only created on-demand
       when user clicks on menu, but this may be called before from the event loop.
       (The menu will still contain this entry when it's created later.) */
    if (get_widget_by_name(&menu, globals.widgets.top_level, "filehist_pullright", False)) {
      update_menu_labels(menu);
    }
}


static void
filehist_insert_submenu(int idx, const char *filename, int pageno, void *data)
{
    Widget menu = (Widget)data;
    Widget w;
    static char *buf = NULL;
    static size_t buf_len = 0;
    size_t new_len = LENGTH_OF_INT + strlen(filename) + 1;
    
    UNUSED(pageno);

    if (new_len > buf_len) {
      buf = xrealloc(buf, new_len);
      buf_len = new_len;
    }

    sprintf(buf, "%d %s", idx + 1, filename);
    TRACE_GUI((stderr, "Creating menu `%s'", buf));
    w = XtVaCreateManagedWidget("_filehist", smeBSBObjectClass, menu,
                        XtNlabel, buf,
                        XtNleftMargin, 10,
                        NULL);
    XtAddCallback(w, XtNcallback, filehist_select_cb, NULL);
}


/*
  ============================================================
  Hack for pullright menus part II: callbacks and functions
  ============================================================
*/

/* callback to pop down the currently active pullright */
static void
ActPopdownSubmenus(Widget w, XEvent *event, String *params, Cardinal *num_params)
{
    UNUSED(w);
    UNUSED(event);
    UNUSED(params);
    UNUSED(num_params);
    
    if (m_timeout != 0)
      XtRemoveTimeOut(m_timeout);
    m_timeout = 0;
    if (m_active_submenu != NULL)
      XtPopdown(m_active_submenu);
}
/* create a parent shell for the pullright menu entries */
static Widget
create_files_submenu(void)
{
    Widget popup = XtCreatePopupShell("filehist_pullright", simpleMenuWidgetClass, globals.widgets.top_level,
                              NULL, 0);
    file_history_enumerate(filehist_insert_submenu, popup);
    return popup;
}

/* Acutally pop up the pullright menu */
static void 
popup_pullright(XtPointer client_data, XtIntervalId *id)
{
    int pos_x, pos_y;
    Dimension w1;
    Window dummy;
    static Widget files_submenu = NULL;
    struct pullright_position_info *info = (struct pullright_position_info *)client_data;
    
    UNUSED(id);

    if (files_submenu == NULL)
      files_submenu = create_files_submenu();
    /*                XtManageChild(files_submenu); */
    XTranslateCoordinates(DISP, XtWindow(XtParent(m_submenu)), RootWindowOfScreen(SCRN),
                    info->w, info->y, &pos_x, &pos_y, &dummy);
    XtRealizeWidget(files_submenu);
    XtVaGetValues(files_submenu, XtNwidth, &w1, NULL);
    TRACE_GUI((stderr, "Popping up at %d, %d, %d, %d", pos_x, pos_y, w1, WidthOfScreen(SCRN)));
    
    /* if not sufficient place on the right, pop it up on the left */
    /*  fprintf(stderr, "border_width: %d\n", info->border_width); */
    if (pos_x + w1 > WidthOfScreen(SCRN)) {
      /*  fprintf(stderr, "%d > %d!\n", pos_x + w1, WidthOfScreen(SCRN)); */
      pos_x -= (w1 + info->w + 3 * info->border_width);
      /*  fprintf(stderr, "new x: %d\n", pos_x); */
    }
    else {
      pos_x += info->border_width;
    }
    XtVaSetValues(files_submenu,
              XtNx, pos_x,
              XtNy, pos_y,
              NULL);
    /* use XtPopupSpringLoaded() instead of XtPopup() since it does a few things
       that make the pullright behave like a proper menu, like highlighting the
       current selection, setting the cursor shape etc. */
    XtPopupSpringLoaded(files_submenu);
    m_active_submenu = files_submenu;
}

/*
 * This event handler (to be called by read_events(), the main event handling loop)
 * creates a timeout for the pullright to pop up.
*/
void
SubMenuHandleEvent(XtAppContext app, XEvent *event)
{
    static int flag = 0;
    static struct pullright_position_info info = { -1, 0, 0, 0, NULL };
    
    UNUSED(app);

    if (m_submenu == NULL)
      return;
    
    if (event->type == EnterNotify
      || event->type == MotionNotify
      || event->type == LeaveNotify
      || event->type == ButtonPress) {

/*    fprintf(stderr, "SubMenuHandleEvent: 0x%lx, 0x%lx\n", event->xany.window, XtWindow(m_submenu)); */
      
      /* Could also loop through a list of windows here ...
         We need to check for the parent of the menu item, since smeBSBObject is not
         a real window, and then manually check whether the pointer is inside the menu
         item.
       */
      if (XtParent(m_submenu) != NULL &&
          event->xany.window == XtWindow(XtParent(m_submenu))) {
          /* don't need to check for x coordinates since we already
             know that pointer is inside the parent */
          if (info.y == -1) { /* initialize info */
            XtVaGetValues(m_submenu,
                        XtNy, &(info.y),
                        XtNwidth, &(info.w),
                        XtNheight, &(info.h),
                        NULL);
            XtVaGetValues(XtParent(m_submenu),
                        XtNborderWidth, &(info.border_width),
                        NULL);

            info.menu = m_submenu;
          }
          if (info.y < event->xbutton.y && info.y + info.h > event->xbutton.y) {
            if (flag == 0) {
                /* Create a timeout of 200ms to pop up the menu, so that it doesn't
                   pop up always when the cursor is only moved over the pulldown menu.
                   I think this is about the same delay as the one used by Motif.
                 */
                flag = 1;
                TRACE_GUI((stderr, "ENTER: %d, %d, %d; %d, %d",
                         info.y, info.w, info.h, event->xbutton.x, event->xbutton.y));
                m_timeout = XtAppAddTimeOut(app, 200, popup_pullright, &info);
                return;
            }
          }
          else if (flag == 1) {
            flag = 0;
            TRACE_GUI((stderr, "LEAVE!"));
            if (m_timeout != 0)
                XtRemoveTimeOut(m_timeout);
            m_timeout = 0;
            if (m_active_submenu != NULL)
                XtPopdown(m_active_submenu);
            m_active_submenu = NULL;
          }
      }
    }
}

static Widget
create_pulldown_entry(const char *menu_name,
                  Widget parent,
                  const char *item_name,
                  const char *accelerator, /* accelerator, or NULL */
                  struct xdvi_action *action,
                  buttonTypeT *type)
{
    Widget w;
    char buf[1024];
    char *m_name = xstrdup(menu_name);
    m_name = xstrcat(m_name, item_name);

#ifdef SHOW_ACCELERATORS
    if (accelerator != NULL && *accelerator != '\0')
      SNPRINTF(buf, 1024, "%s  [%s]", item_name, accelerator);
    else
      strncpy(buf, item_name, 1024);
#else
    UNUSED(accelerator);
    strncpy(buf, item_name, 1024);
#endif

/*      fprintf(stderr, "creating pulldown for parent %p: `%s', `%s'\n", */
/*        (void *)parent, menu_name, item_name); */
    
    if (strcmp(item_name, "SEP") == 0) { /* it's a separator */
      *type = MENU_SEPARATOR;
      w = XtCreateManagedWidget(m_name, smeLineObjectClass, parent, NULL, 0);
    }
    else if (action->proc != NULL && action->proc == Act_recent_files) { /* special case: submenu with recent files */
/*    w = recent_files_submenu(m_name, parent, buf); */
/*    *type = MENU_ENTRY; */
      w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
                            XtNlabel, buf,
                            XtNleftMargin, 20,
                            XtNrightMargin, 16,
                            XtNrightBitmap, menu_arrow_bitmap,
                            NULL);
      m_submenu = w;
      /*  fprintf(stderr, "setting translations for %p\n", (void *)XtParent(parent)); */
      XtOverrideTranslations(parent, menu_accels);
      /*    XtOverrideTranslations(XtParent(parent), menu_accels); */
                         
      *type = MENU_ENTRY;
    }
    else { /* normal menu item */
      w = XtVaCreateManagedWidget(m_name, smeBSBObjectClass, parent,
                            XtNlabel, buf,
                            XtNleftMargin, 20,
                            NULL);
      *type = MENU_ENTRY;
      XtAddCallback(w, XtNcallback, handle_command, action);
    }
    free(m_name);
    return w;
}

static Widget
create_pulldown_menu(const char *menu_name,
                 Dimension *width,
                 int *index,
                 Dimension *y_pos,
                 buttonTypeT *type,
                 int *menu_number)
{
    int i;
    
    /* check whether a pulldown menu with this name already exists,
       and if yes, return its position in index: */
    for (i = 0; i < *menu_number; i++) {
      if (menu_list[i].name != NULL && (strcmp(menu_list[i].name, menu_name)) == 0) {
          *index = i;
          break;
      }
    }
    if (i == *menu_number) { /* doesn't exist, create one */
      Dimension w, h;
      Widget n_button_widget, n_popup_widget;
      char *button_widget_name = NULL;

      (*menu_number)++;
      if (*menu_number > MAX_MENU_NUM) {
          XDVI_WARNING((stderr, "Too many menus (max=%d), skipping all from \"%s\"",
                    MAX_MENU_NUM, menu_name));
          *type = INVALID;
          return 0;
      }
      
      /* save menu_name to list for later comparison */
      menu_list[i].name = xrealloc(menu_list[i].name, strlen(menu_name) + 1);
      strcpy(menu_list[i].name, menu_name);

      button_widget_name = xstrdup(menu_name);
      button_widget_name = xstrcat(button_widget_name, "B"); /* make it unique */

      if (globals.debug & DBG_ALL) {
          fprintf(stderr, "ypos: %d; h: %d; between: %d; border: %d\n",
                *y_pos,
                h,
                resource.btn_between_spacing,
                resource.btn_border_width);
      }

      n_button_widget = XtVaCreateWidget(menu_list[i].name, menuButtonWidgetClass, panel_widget,
                                 XtNmenuName, button_widget_name,
                                 XtNx, resource.btn_side_spacing,
                                 XtNy, *y_pos,
                                 XtNborderWidth, resource.btn_border_width,
                                 NULL);
      n_popup_widget = XtVaCreatePopupShell(button_widget_name, simpleMenuWidgetClass, n_button_widget,
                                    NULL);
      /* Mustn't free this one?? */
/*    free(button_widget_name); */
      menu_list[i].button_widget = n_button_widget;
      menu_list[i].popup_widget = n_popup_widget;
      XtVaGetValues(n_button_widget, XtNwidth, &w, XtNheight, &h, NULL);
      *width = w;
      *index = i;
      *y_pos += h + resource.btn_between_spacing + 2 * resource.btn_border_width;
      *type = MENU_BUTTON;
      return n_button_widget;
    }
    *type = NONE;
    return 0;
}

static struct button_info *
create_button_info(const char *label, struct xdvi_action *action, Widget w, buttonTypeT type)
{
    struct button_info *info = xmalloc(sizeof *info);
    info->label = xstrdup(label);
    info->action = action;
    info->widget = w;
    info->type = type;
    return info;
}

typedef enum shrinkArgT_ { NO_SHRINK_ARG, HASH, PERCENT, UNDERSCORE } shrinkArgT;

static shrinkArgT
test_for_shrink_arg(const char *item, int *idx)
{
    const char *ptr = item;
    size_t i;
    for (i = 0; ptr[i] != '\0'; i++) {
      if (ptr[i] == '$') {
          i++;
          if (ptr[i]  == '#') {
            *idx = i;
            return HASH;
          }
          else if (ptr[i]  == '%') {
            *idx = i;
            return PERCENT;
          }
          else if (ptr[i]  == '_') {
            *idx = i;
            return UNDERSCORE;
          }
      }
    }
    *idx = 0;
    return NO_SHRINK_ARG;
}

static Boolean
create_shrink_button(char **label, int offset, shrinkArgT type, struct xdvi_action *action)
{
    int shrink_arg = 0;
#define TEMPSTR_LEN 128 /* enough for printing a number into */
    char tempstr[TEMPSTR_LEN];
    char *new_label = NULL;
    
    for (;; action = action->next) {
      if (action == NULL) {
          return False;
      }
      if (action->proc == Act_set_shrink_factor || action->proc == Act_shrink_to_dpi) {
          /* NOTE: the shrinkbutton[] resource isn't implemented. It probably makes
             less sense with the pulldown menu resources??
          */
          if (action->num_params > 0) {
            shrink_arg = atoi(action->param);
            if (action->proc == Act_shrink_to_dpi)
                shrink_arg = (double)resource.pixels_per_inch / shrink_arg + 0.5;
            if (shrink_arg < 1)
                shrink_arg = 1;
            else if (shrink_arg > 99)
                shrink_arg = 99;
          }
          break; /* found shrink action */
      }
    }

    if (type == HASH)
      SNPRINTF(tempstr, TEMPSTR_LEN, "%d", shrink_arg);
    else if (type == PERCENT) {
      if (shrink_arg <= 15)
          SNPRINTF(tempstr, TEMPSTR_LEN, "%d", (int)(100.0 / shrink_arg + .5));
      else
          SNPRINTF(tempstr, TEMPSTR_LEN, "%.2f", 100.0 / shrink_arg);
    }
    /* NOTE: I think UNDERSCORE is related to the shrinkbutton[] resource,
       which is not implemented */

    /* return resized label */
    new_label = xmalloc(offset - 1  + strlen(tempstr) + strlen(*label + offset + 1) + 1);
    memcpy(new_label, *label, offset - 1);
    strcpy(new_label + offset - 1, tempstr); /* now it's null-terminated */
    strcat(new_label, *label + offset + 1);
    free(*label);
    *label = new_label;

#undef TEMPSTR_LEN
    return True;
}

static Dimension
create_button(int button_number,    /* number of this button */
            int *menu_num,          /* number of submenus in this button */
            char **items,           /* description of label and action strings */
            size_t item_count,      /* number of items in description */
            Widget parent,          /* parent of widget to create */
            struct button_info ***bipp,   /* button info to insert new button into */
            Dimension *y_pos,       /* vertical position after creating button */
            const char *c_ptr,      /* entire rest of resource string, for error messages */
            size_t len)       /* length of current line in resource string, for error messages*/
{
    int menu_idx = -1, label_idx = -1, accelerator_idx = -1, action_idx = -1;
#define NAME_LEN 16
    char name[NAME_LEN];
    struct button_info *bp;
    shrinkArgT shrink_arg_type;
    struct xdvi_action *action;
    Widget widget;
    buttonTypeT b_type;
/*     static int menu_num = 0; /\* count number of created menus *\/ */
    Dimension width = 0;

    ASSERT(item_count >= 2, "Too few items");
    
    if (item_count == 4) { /* submenu for a button */
      menu_idx = 0;
      label_idx = 1;
      accelerator_idx = 2;
      action_idx = 3;
    }
    else if (item_count == 3) { /* command button */
      label_idx = 0;
      accelerator_idx = 1;
      action_idx = 2;
    }
    else { /* separator */
      if (strcmp(items[1], "SEP") == 0) { /* separator */
          menu_idx = 0;
          label_idx = 1;
      }
      else {
          XDVI_WARNING((stderr, "Wrong number of items (%d) in translations line:\n\"%.*s\" (skipping this line).",
                    item_count, (int)len, c_ptr));
          return 0;
      }
    }

    if (action_idx != -1) {
      int offset;
      shrink_arg_type = test_for_shrink_arg(items[label_idx], &offset);

/*    fprintf(stderr, "compiling action: |%s|\n", items[action_idx]); */
      if ((action = compile_action(items[action_idx])) == NULL) {
          XDVI_WARNING((stderr, "Invalid action \"%s\" in translations line:\n\"%.*s\" (skipping this line).",
                    items[action_idx], (int)len, c_ptr));
          return 0;
      }
    
      if (shrink_arg_type != NO_SHRINK_ARG) { /* search for corresponding shrink action */
          if (!create_shrink_button(&(items[label_idx]), offset, shrink_arg_type, action)) {
            XDVI_WARNING((stderr, "Non-existent shrink action \"%s\" in translations line:\n\"%.*s\"",
                        items[action_idx], (int)len, c_ptr));
            return 0;
          }
      }
    }
    else {
      action = NULL;
    }
    
    command_call[0].closure = (XtPointer) action;
    SNPRINTF(name, NAME_LEN, "button%d", button_number);

    if (menu_idx != -1) { /* it's a pulldown menu */
      int index;

      /* create a new pulldown menu if it doesn't exist yet */
      widget = create_pulldown_menu(items[menu_idx], &width, &index, y_pos, &b_type, menu_num);
      if (b_type == INVALID)
          return 0;
      if (b_type != NONE) { /* it didn't exist yet */
          bp = create_button_info(items[label_idx], NULL, widget, b_type);
          **bipp = bp;
          *bipp = &bp->next;
      }

      /* create an entry for this item */
      widget = create_pulldown_entry(menu_list[index].name,
                               menu_list[index].popup_widget,
                               items[label_idx],
                               accelerator_idx > 0 ? items[accelerator_idx] : NULL,
                               action,
                               &b_type);
      bp = create_button_info(items[label_idx], action, widget, b_type);
      **bipp = bp;
      *bipp = &bp->next;
    }
    else {  /* not a pulldown menu, but a simple command button */
      command_call[0].closure = (XtPointer) action;
      widget = XtVaCreateWidget(name, commandWidgetClass, parent,
                          XtNlabel, (XtArgVal)items[label_idx],
                          XtNx, resource.btn_side_spacing,
                          XtNy, (XtArgVal)*y_pos,
                          XtNborderWidth, resource.btn_border_width,
                          XtNcallback, (XtArgVal)command_call,
                          NULL);
      bp = create_button_info(items[label_idx], action, widget, COMMAND_BUTTON);
      **bipp = bp;
      *bipp = &bp->next;
    }
#undef NAME_LEN
    return width;
}

void
scroll_x_panner(int x)
{
    static int old_x = 0;
    if (panner != 0 && ABS(x - old_x) > 8) {
      XtVaSetValues(panner, XtNsliderX, x, NULL);
      old_x = x;
    }
}

void
scroll_y_panner(int y)
{
    static int old_y = 0;
    if (panner != 0 && ABS(y - old_y) > 8) {
      XtVaSetValues(panner, XtNsliderY, y, NULL);
      old_y = y;
    }
}

#ifdef USE_PANNER
static void 
panner_cb(Widget widget, XtPointer closure, XtPointer report_ptr)
{
    XawPannerReport *report = (XawPannerReport *)report_ptr;
    static int orig_x = 0, orig_y = 0;
    int x = report->slider_x;
    int y = report->slider_y;
    static Dimension w, h;
    static Arg arg_wh_clip[] = {
      {XtNwidth, (XtArgVal) &w},
      {XtNheight, (XtArgVal) &h},
    };
    
    UNUSED(closure);

    XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));
    
    fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
          w, h, globals.page.w, globals.page.h);
    XtVaSetValues(widget,
              XtNsliderWidth, w, XtNsliderHeight, h,
              XtNcanvasWidth, globals.page.w, XtNcanvasHeight, globals.page.h,
              NULL);
    
    fprintf(stderr, "panner moved: %d, %d\n", report->slider_x, report->slider_y);
    if (globals.widgets.x_bar != NULL)
      XtCallCallbacks(globals.widgets.x_bar, XtNscrollProc, (XtPointer)(x - orig_x));
    if (globals.widgets.y_bar != NULL)
      XtCallCallbacks(globals.widgets.y_bar, XtNscrollProc, (XtPointer)(y - orig_y));
    orig_x = x;
    orig_y = y;
}
#endif /* USE_PANNER */

void
create_menu_buttons(Widget form, int *ret_panel_width)
{
    Dimension max_button_width = 0, curr_width;
    Dimension y_pos;
    struct button_info **bipp;
    struct button_info *bp;
    const char *c_ptr, *e_ptr;
    int max_size;
    int button_number = 0;
    int menu_number = 0; /* number of menus created; passed through to create_pulldown_menu */
    
    /* disable the magnifier in the panel: */
    XtTranslations panel_translations = XtParseTranslationTable("#augment <ButtonPress>:");

    XtAppAddActions(XtWidgetToApplicationContext(form), menu_actions, XtNumber(menu_actions));
    /* add our own popdown-submenus() action to the default translations of this menu */
    menu_accels = XtParseAcceleratorTable("<BtnUp>:MenuPopdown()notify()unhighlight()popdown-submenus()");
    
    line_widget = XtVaCreateWidget("line", widgetClass, form,
                           XtNbackground, (XtArgVal)resource.fore_Pixel,
                           XtNwidth, (XtArgVal) 1,
                           XtNfromHoriz, (XtArgVal)globals.widgets.vport_widget,
                           XtNborderWidth, (XtArgVal)0,
                           XtNtop, (XtArgVal)XtChainTop,
                           XtNbottom, (XtArgVal)XtChainBottom,
                           XtNleft, (XtArgVal)XtChainRight,
                           XtNright, (XtArgVal)XtChainRight,
                           NULL);
    panel_widget = XtVaCreateWidget("panel", compositeWidgetClass, form,
                            XtNborderWidth, (XtArgVal)0,
                            XtNfromHoriz, (XtArgVal)line_widget,
                            XtNtranslations, (XtArgVal)panel_translations,
                            XtNtop, (XtArgVal)XtChainTop,
                            XtNbottom, (XtArgVal)XtChainBottom,
                            XtNleft, (XtArgVal)XtChainRight,
                            XtNright, (XtArgVal)XtChainRight,
                            NULL);
    menu_arrow_bitmap
      = XCreateBitmapFromData(XtDisplay(globals.widgets.top_level),
                        RootWindowOfScreen(XtScreen(globals.widgets.top_level)),
                        (char *)menu_arrow_bits, MENU_ARROW_W, MENU_ARROW_H);
    
    b_head = NULL;
    bipp = &b_head;

    *ret_panel_width = 0;
    y_pos = resource.btn_top_spacing;

#define FREE_LINE_ITEMS do { \
          for (curr = 0; curr < item_count; curr++) { \
              free(line_items[curr]); \
          } \
          free(line_items); \
      } while (0)
    
    for (c_ptr = resource.menu_translations;
       c_ptr != NULL && *c_ptr != '\0';
       c_ptr = e_ptr + 1) {
      e_ptr = strchr(c_ptr, '\n');
      if (e_ptr != NULL) {
          char **line_items = NULL;
          size_t len, curr, item_count = 0;

          if (e_ptr == c_ptr) { /* single '\n' marks additional space between buttons */
            y_pos += resource.btn_between_extra;
            continue;
          }
          len = e_ptr - c_ptr;

          if (++button_number > MAX_BUTTON_NUM) {
            XDVI_WARNING((stderr, "Too many buttons (max=%d), skipping all from:\n\"%.*s\"",
                        MAX_BUTTON_NUM, (int)len, c_ptr));
            break;
          }
          
          line_items = split_line(c_ptr, SEP_CHAR, 0, len, &item_count);
          if (item_count < 3 && !(item_count > 1 && strcmp(line_items[1], "SEP") == 0)) {
            XDVI_WARNING((stderr, "Too few separators \"%c\" in translations line:\n\"%.*s\" (skipping this line).\n",
                        SEP_CHAR, (int)len, c_ptr));
            FREE_LINE_ITEMS;
            continue;
          }
          curr_width = create_button(button_number,
                               &menu_number,
                               line_items,
                               item_count,
                               panel_widget,
                               &bipp,
                               &y_pos,
                               c_ptr, len);
          if (curr_width == 0) { /* no button created */
            FREE_LINE_ITEMS;
            continue;
          }
          /* adjust max_button_width to this new entry */
          if (curr_width > max_button_width)
            max_button_width = curr_width;

          FREE_LINE_ITEMS;
      }
    }

#undef FREE_LINE_ITEMS
    
    /* null-terminate button info */
    *bipp = NULL;

    max_size = xaw_get_pagelist_size();
    if (max_size > max_button_width) {
      max_button_width = max_size;
    }

    *ret_panel_width = max_button_width + 2 * (resource.btn_side_spacing + resource.btn_border_width);
    TRACE_GUI((stderr, "panel_widget: w: %d", *ret_panel_width));
    XtVaSetValues(panel_widget, XtNwidth, (XtArgVal)*ret_panel_width, NULL);
    ++(*ret_panel_width);
    my_panel_width = *ret_panel_width; /* make it available */

    for (bp = b_head; bp != NULL; bp = bp->next) {
      if (bp->type == MENU_BUTTON || bp->type == COMMAND_BUTTON) {
          TRACE_GUI((stderr, "bp->widget: w: %d", max_button_width));
          XtVaSetValues(bp->widget, XtNwidth, (XtArgVal)max_button_width, NULL);
          XtManageChild(bp->widget);
      }
    }

    my_y_pos = y_pos - resource.btn_between_spacing + resource.btn_top_spacing + 2 * resource.btn_border_width;
    initialize_tick_marks();
#ifdef USE_PANNER
    {
      static Dimension w, h;
      static Arg arg_wh_clip[] = {
          {XtNwidth, (XtArgVal) &w},
          {XtNheight, (XtArgVal) &h},
      };
      XtGetValues(globals.widgets.clip_widget, arg_wh_clip, XtNumber(arg_wh_clip));

      fprintf(stderr, "w: %d, h: %d, globals.page.w: %d, globals.page.h: %d\n",
            w, h, globals.page.w, globals.page.h);
      if (w == 0)
          w = globals.page.w - 2;
      if (h == 0)
          h = globals.page.h - 2;
      panner = XtVaCreateManagedWidget("panner", pannerWidgetClass, panel_widget,
                               XtNx, resource.btn_side_spacing,
                               XtNy, my_y_pos,
                               XtNheight, 60,
                               XtNwidth, max_button_width,
                               XtNshadowThickness, 0,
                               XtNsliderWidth, w,
                               XtNsliderHeight, h,
                               XtNcanvasWidth, globals.page.w,
                               XtNcanvasHeight, globals.page.h,
                               XtNsliderX, 5,
                               XtNsliderY, 7,
                               XtNinternalSpace, 0,
                               NULL);
    }
    my_y_pos += 60 + resource.btn_top_spacing + 2 * resource.btn_border_width;
    XtAddCallback(panner, XtNreportCallback, panner_cb, (XtPointer)NULL);

#endif /* USE_PANNER */

}
#endif /* NEW_MENU_CREATION */


void
set_button_panel_height(XtArgVal h)
{
    TRACE_GUI((stderr, "line_widget: h %d", (int)h));
    XtVaSetValues(line_widget, XtNheight, h, NULL);
    XtManageChild(line_widget);

    XtVaSetValues(panel_widget, XtNheight, h, NULL);
    XtManageChild(panel_widget);
}

/****************************************************************************
 * Action handling code.
 */


static void
handle_destroy_buttons(Widget widget, XtPointer client_data, XtPointer call_data)
{
    int panel_width;
    Dimension window_w, window_h;
    
    UNUSED(widget);
    UNUSED(client_data);
    UNUSED(call_data);
    
    if (--destroy_count != 0) {
      return;
    }
    XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
    XtVaGetValues(globals.widgets.form_widget,
                  XtNwidth, &window_w,
                  XtNheight, &window_h,
                  NULL);
    
    if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
      /* destroy buttons */
      TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_w, window_h));
      XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
    }
    else {
      create_menu_buttons(globals.widgets.form_widget, &panel_width);
      window_w -= panel_width;
      TRACE_GUI((stderr, "globals.widgets.vport_widget: h %d, w %d", window_h, window_w));
      XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
      set_button_panel_height((XtArgVal) window_h);
    }
}


static void
reconfig_window(void) {
    Dimension x_top, y_top, h_top, w_top;
    XWindowChanges sizeconfigure;
    int sizeconfiguremask;
    
    /* brute-force method to bring the scrollbars back. Apparently a single XConfigureWindow()
       isn't enough to get the scrollbars back, we actually need to move the window a bit,
       and then move it back. */
    sizeconfiguremask = CWWidth | CWHeight;
    XtVaGetValues(globals.widgets.top_level, XtNx, &x_top, XtNy, &y_top, XtNheight, &h_top, XtNwidth, &w_top, NULL);
    sizeconfigure.width = w_top + 1;
    sizeconfigure.height = h_top + 1;
    XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
    sizeconfigure.width = w_top;
    sizeconfigure.height = h_top;
    XConfigureWindow(DISP, XtWindow(globals.widgets.top_level), sizeconfiguremask, &sizeconfigure);
}

/* toggle scrollbars to state `visible' */
void
toggle_scrollbars(void)
{
    Widget v_bar = XtNameToWidget(globals.widgets.vport_widget, "vertical");
    Widget h_bar = XtNameToWidget(globals.widgets.vport_widget, "horizontal");
    static Dimension bar_thick;
    static Boolean v_bar_mapped = False, h_bar_mapped = False;
    static Boolean initialized = False;

    Boolean make_v_bar_visible = False;
    Boolean make_v_bar_invisible = False;
    
    Boolean make_h_bar_visible = False;
    Boolean make_h_bar_invisible = False;

    if (v_bar != 0) {
      int test_v = 0;
      XtVaGetValues(v_bar, XtNwidth, &test_v, NULL);
      if (test_v > 1)
          v_bar_mapped = True;
    }
    if (h_bar != 0) {
      int test_h = 0;
      XtVaGetValues(h_bar, XtNheight, &test_h, NULL);
      if (test_h > 1)
          h_bar_mapped = True;
    }
    
    if (!initialized) {
      v_bar_mapped = h_bar_mapped = (resource.expert_mode & XPRT_SHOW_SCROLLBARS) != 0;
      initialized = True;
      if (v_bar != 0)
          XtVaGetValues(v_bar, XtNwidth, &bar_thick, NULL);
      else if (h_bar != 0)
          XtVaGetValues(h_bar, XtNheight, &bar_thick, NULL);
      else
          bar_thick = 15; /* FIXME */
    }

    if ((resource.expert_mode & XPRT_SHOW_SCROLLBARS) == 0) {
      if (v_bar_mapped)
          make_v_bar_invisible = True;
      if (h_bar_mapped)
          make_h_bar_invisible = True;
    }
    else {
      if (!v_bar_mapped)
          make_v_bar_visible = True;
      if (!h_bar_mapped)
          make_h_bar_visible = True;
    }

    if (make_h_bar_visible || make_v_bar_visible) {
      if (make_h_bar_visible && h_bar != 0) {
          TRACE_GUI((stderr, "h_bar: h %d", bar_thick));
          XtVaSetValues(h_bar, XtNheight, bar_thick, XtNx, bar_thick, XtNy, 0, XtNborderWidth, 1, NULL);
          XtManageChild(h_bar);
          h_bar_mapped = True;
      }
      if (make_v_bar_visible && v_bar != 0) {
          TRACE_GUI((stderr, "v_bar: w %d", bar_thick));
          XtVaSetValues(v_bar, XtNwidth, bar_thick, XtNx, 0, XtNy, bar_thick, XtNborderWidth, 1, NULL);
          XtManageChild(v_bar);
          v_bar_mapped = True;
      }
      if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
          reconfig_window();
      }
    }
    else if (make_h_bar_invisible || make_v_bar_invisible) {
      if (make_h_bar_invisible && h_bar != 0) {
          XtUnmanageChild(h_bar);
          XtVaSetValues(h_bar, XtNheight, 1, XtNx, 0, XtNy, 0, XtNborderWidth, 0, NULL);
          h_bar_mapped = False;
      }
      if (make_v_bar_invisible && v_bar != 0) {
          XtUnmanageChild(v_bar);
          XtVaSetValues(v_bar, XtNwidth, 1, XtNy, 0, XtNy, 0, XtNborderWidth, 0, NULL);
          v_bar_mapped = False;
      }
      if (h_bar != 0 || v_bar != 0) { /* need to reconfigure screen */
          reconfig_window();
      }
    }
    
}

void
toggle_buttons(void)
{
    static Boolean buttons_active = False;
    static Boolean initialized = False;
    Dimension window_w, window_h;


    Boolean make_buttons_visible = False;
    Boolean make_buttons_invisible = False;

    int panel_width;
    
    if (!initialized) {
      buttons_active = (resource.expert_mode & XPRT_SHOW_BUTTONS) != 0;
      initialized = True;
    }

    if ((resource.expert_mode & XPRT_SHOW_BUTTONS) == 0) {
      if (buttons_active)
          make_buttons_invisible = True;
    }
    else {
      if (!buttons_active)
          make_buttons_visible = True;
    }
          
    if (make_buttons_visible) {
      if (destroy_count != 0) {
          return;
      }

      create_menu_buttons(globals.widgets.form_widget, &panel_width);
      XtVaGetValues(globals.widgets.form_widget,
                  XtNwidth, &window_w,
                  XtNheight, &window_h,
                  NULL);
      XtVaSetValues(globals.widgets.vport_widget, XtNresizable, (XtArgVal)True, NULL);
      window_w -= panel_width;
      TRACE_GUI((stderr, "globals.widgets.vport_widget: w: %d, h: %d", window_w, window_h));
      XtVaSetValues(globals.widgets.vport_widget, XtNwidth, window_w, XtNheight, window_h, NULL);
      set_button_panel_height((XtArgVal) window_h);
      buttons_active = True;
    }
    else if (make_buttons_invisible) {
      if (destroy_count != 0) {
          return;
      }
      /* this counts the callback calls; 1 for the panel, 1 for the line */
      destroy_count = 2;

      XtAddCallback(panel_widget, XtNdestroyCallback,
                  handle_destroy_buttons, (XtPointer)0);
      XtAddCallback(panel_widget, XtNdestroyCallback,
                  handle_destroy_pagelist, (XtPointer)0);
      XtAddCallback(line_widget, XtNdestroyCallback,
                  handle_destroy_buttons, (XtPointer)0);
      XtDestroyWidget(panel_widget);
      XtDestroyWidget(line_widget);
      buttons_active = False;
/*    window_w += get_panel_width(); */

      while (b_head != NULL) {
          struct button_info *bp = b_head;
          struct xdvi_action *action;

          b_head = bp->next;
          free(bp->label);
          /* free bp->action */
          for (action = bp->action; action != NULL;) {
            struct xdvi_action *act2 = action;
            action = act2->next;
            if (act2->num_params > 0) {
                free(act2->param);
            }
            free(act2);
          }
          free(bp);
      }
    }
}

#else
/* silence `empty compilation unit' warnings */
static void bar(void); static void foo() { bar(); } static void bar(void) { foo(); }
#endif /* ifndef MOTIF */

Generated by  Doxygen 1.6.0   Back to index