view src/gui_motif.c @ 2378:85b7dc8da5eb vim73

Add the 'concealcursor' option to decide when the cursor line is to be concealed or not. Rename 'conc' to 'cole' as the short name for 'conceallevel'.
author Bram Moolenaar <bram@vim.org>
date Fri, 23 Jul 2010 22:10:27 +0200
parents cccb71c2c5c1
children 6768ebd0bc04
line wrap: on
line source

/* vi:set ts=8 sts=4 sw=4:
 *
 * VIM - Vi IMproved		by Bram Moolenaar
 *				GUI/Motif support by Robert Webb
 *
 * Do ":help uganda"  in Vim to read copying and usage conditions.
 * Do ":help credits" in Vim to see a list of people who contributed.
 * See README.txt for an overview of the Vim source code.
 */

#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/Text.h>
#include <Xm/TextF.h>
#include <Xm/Separator.h>
#include <Xm/Label.h>
#include <Xm/CascadeB.h>
#include <Xm/ScrollBar.h>
#include <Xm/MenuShell.h>
#include <Xm/DrawingA.h>
#if (XmVersion >= 1002)
# include <Xm/RepType.h>
#endif
#include <Xm/Frame.h>
#include <Xm/LabelG.h>
#include <Xm/ToggleBG.h>
#include <Xm/SeparatoG.h>
#include <Xm/XmP.h>

#include <X11/keysym.h>
#include <X11/Xatom.h>
#include <X11/StringDefs.h>
#include <X11/Intrinsic.h>

#include "vim.h"

#ifdef HAVE_X11_XPM_H
# include <X11/xpm.h>
#else
# ifdef HAVE_XM_XPMP_H
#  include <Xm/XpmP.h>
# endif
#endif
#ifdef HAVE_XM_NOTEBOOK_H
# include <Xm/Notebook.h>
#endif

#include "gui_xmebw.h"	/* for our Enhanced Button Widget */

#if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM)
# include "../pixmaps/alert.xpm"
# include "../pixmaps/error.xpm"
# include "../pixmaps/generic.xpm"
# include "../pixmaps/info.xpm"
# include "../pixmaps/quest.xpm"
#endif

#define MOTIF_POPUP

extern Widget vimShell;

static Widget vimForm;
static Widget textAreaForm;
Widget textArea;
#ifdef FEAT_TOOLBAR
static Widget toolBarFrame;
static Widget toolBar;
#endif
#ifdef FEAT_GUI_TABLINE
static Widget	tabLine;
static Widget	tabLine_menu = 0;
static int	showing_tabline = 0;
#endif
#ifdef FEAT_FOOTER
static Widget footer;
#endif
#ifdef FEAT_MENU
# if (XmVersion >= 1002)
/* remember the last set value for the tearoff item */
static int tearoff_val = (int)XmTEAR_OFF_ENABLED;
# endif
static Widget menuBar;
#endif

static void scroll_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
#ifdef FEAT_GUI_TABLINE
static void tabline_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void tabline_button_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void tabline_menu_cb __ARGS((Widget w, XtPointer	closure, XEvent	*e, Boolean *continue_dispatch));
static void tabline_balloon_cb __ARGS((BalloonEval *beval, int state));
#endif
#ifdef FEAT_TOOLBAR
# ifdef FEAT_FOOTER
static void toolbarbutton_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
static void toolbarbutton_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
# endif
static void reset_focus __ARGS((void));
#endif
#ifdef FEAT_FOOTER
static int gui_mch_compute_footer_height __ARGS((void));
#endif
#ifdef WSDEBUG
static void attachDump(Widget, char *);
#endif

static void gui_motif_menu_colors __ARGS((Widget id));
static void gui_motif_scroll_colors __ARGS((Widget id));

#if (XmVersion >= 1002)
# define STRING_TAG  XmFONTLIST_DEFAULT_TAG
#else
# define STRING_TAG  XmSTRING_DEFAULT_CHARSET
#endif

/*
 * Call-back routines.
 */

    static void
scroll_cb(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data, call_data;
{
    scrollbar_T *sb;
    long	value;
    int		dragging;

    sb = gui_find_scrollbar((long)client_data);

    value = ((XmScrollBarCallbackStruct *)call_data)->value;
    dragging = (((XmScrollBarCallbackStruct *)call_data)->reason ==
							      (int)XmCR_DRAG);
    gui_drag_scrollbar(sb, value, dragging);
}

#ifdef FEAT_GUI_TABLINE
    static void
tabline_cb(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data UNUSED;
    XtPointer	call_data;
{
    XmNotebookCallbackStruct *nptr;

    nptr = (XmNotebookCallbackStruct *)call_data;
    if (nptr->reason != (int)XmCR_NONE)
	send_tabline_event(nptr->page_number);
}

    static void
tabline_button_cb(w, client_data, call_data)
    Widget	w;
    XtPointer	client_data UNUSED;
    XtPointer	call_data UNUSED;
{
    int		cmd, tab_idx;

    XtVaGetValues(w, XmNuserData, &cmd, NULL);
    XtVaGetValues(tabLine_menu, XmNuserData, &tab_idx, NULL);

    send_tabline_menu_event(tab_idx, cmd);
}

/*
 * Tabline single mouse click timeout handler
 */
    static void
motif_tabline_timer_cb (timed_out, interval_id)
    XtPointer		timed_out;
    XtIntervalId	*interval_id UNUSED;
{
    *((int *)timed_out) = TRUE;
}

/*
 * check if the tabline tab scroller is clicked
 */
    static int
tabline_scroller_clicked(scroller_name, event)
    char		*scroller_name;
    XButtonPressedEvent *event;
{
    Widget	tab_scroll_w;
    Position	pos_x, pos_y;
    Dimension	width, height;

    tab_scroll_w = XtNameToWidget(tabLine, scroller_name);
    if (tab_scroll_w != (Widget)0) {
	XtVaGetValues(tab_scroll_w, XmNx, &pos_x, XmNy, &pos_y, XmNwidth,
		      &width, XmNheight, &height, NULL);
	if (pos_x >= 0) {
	    /* Tab scroller (next) is visible */
	    if ((event->x >= pos_x) && (event->x <= pos_x + width) &&
		(event->y >= pos_y) && (event->y <= pos_y + height)) {
		/* Clicked on the scroller */
		return TRUE;
	    }
	}
    }
    return FALSE;
}

    static void
tabline_menu_cb(w, closure, e, continue_dispatch)
    Widget	w;
    XtPointer	closure UNUSED;
    XEvent	*e;
    Boolean	*continue_dispatch UNUSED;
{
    Widget			tab_w;
    XButtonPressedEvent		*event;
    int				tab_idx = 0;
    WidgetList			children;
    Cardinal			numChildren;
    static XtIntervalId		timer = (XtIntervalId)0;
    static int			timed_out = TRUE;

    event = (XButtonPressedEvent *)e;

    if (event->button == Button1)
    {
	if (tabline_scroller_clicked("MajorTabScrollerNext", event)
	    || tabline_scroller_clicked("MajorTabScrollerPrevious", event))
	    return;

	if (!timed_out)
	{
	    XtRemoveTimeOut(timer);
	    timed_out = TRUE;

	    /*
	     * Double click on the tabline gutter, add a new tab
	     */
	    send_tabline_menu_event(0, TABLINE_MENU_NEW);
	}
	else
	{
	    /*
	     * Single click on the tabline gutter, start a timer to check
	     * for double clicks
	     */
	    timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
				    motif_tabline_timer_cb, &timed_out);
	    timed_out = FALSE;
	}
	return;
    }

    if (event->button != Button3)
	return;

    /* When ignoring events don't show the menu. */
    if (hold_gui_events
# ifdef FEAT_CMDWIN
	    || cmdwin_type != 0
# endif
       )
	return;

    if (event->subwindow != None)
    {
	tab_w = XtWindowToWidget(XtDisplay(w), event->subwindow);
	/* LINTED: avoid warning: dubious operation on enum */
	if (tab_w != (Widget)0 && XmIsPushButton(tab_w))
	    XtVaGetValues(tab_w, XmNpageNumber, &tab_idx, NULL);
    }

    XtVaSetValues(tabLine_menu, XmNuserData, tab_idx, NULL);
    XtVaGetValues(tabLine_menu, XmNchildren, &children, XmNnumChildren,
		  &numChildren, NULL);
    XtManageChildren(children, numChildren);
    XmMenuPosition(tabLine_menu, (XButtonPressedEvent *)e) ;
    XtManageChild(tabLine_menu);
}

    static void
tabline_balloon_cb(beval, state)
    BalloonEval	*beval;
    int		state UNUSED;
{
    int		nr;
    tabpage_T	*tp;

    if (beval->target == (Widget)0)
	return;

    XtVaGetValues(beval->target, XmNpageNumber, &nr, NULL);
    tp = find_tabpage(nr);
    if (tp == NULL)
	return;

    get_tabline_label(tp, TRUE);
    gui_mch_post_balloon(beval, NameBuff);
}

#endif

/*
 * End of call-back routines
 */

/*
 * Implement three dimensional shading of insensitive labels.
 * By Marcin Dalecki.
 */

#include <Xm/XmP.h>
#include <Xm/LabelP.h>

static XtExposeProc old_label_expose = NULL;

static void label_expose __ARGS((Widget _w, XEvent *_event, Region _region));

    static void
label_expose(_w, _event, _region)
    Widget	_w;
    XEvent	*_event;
    Region	_region;
{
    GC		    insensitiveGC;
    XmLabelWidget   lw = (XmLabelWidget)_w;
    unsigned char   label_type = (int)XmSTRING;

    XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0);

    if (XtIsSensitive(_w) || label_type != (int)XmSTRING)
	(*old_label_expose)(_w, _event, _region);
    else
    {
	XGCValues   values;
	XtGCMask    mask;
	XtGCMask    dynamic;
	XFontStruct *fs;

	_XmFontListGetDefaultFont(lw->label.font, &fs);

	/* FIXME: we should be doing the whole drawing ourself here. */
	insensitiveGC = lw->label.insensitive_GC;

	mask = GCForeground | GCBackground | GCGraphicsExposures;
	dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin;
	values.graphics_exposures = False;

	if (fs != 0)
	{
	    mask |= GCFont;
	    values.font = fs->fid;
	}

	if (lw->primitive.top_shadow_pixmap != None
		&& lw->primitive.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP)
	{
	    mask |= GCFillStyle | GCTile;
	    values.fill_style = FillTiled;
	    values.tile = lw->primitive.top_shadow_pixmap;
	}

	lw->label.TextRect.x += 1;
	lw->label.TextRect.y += 1;
	if (lw->label._acc_text != 0)
	{
	    lw->label.acc_TextRect.x += 1;
	    lw->label.acc_TextRect.y += 1;
	}

	values.foreground = lw->primitive.top_shadow_color;
	values.background = lw->core.background_pixel;

	lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask,
					       &values, dynamic, (XtGCMask)0);
	(*old_label_expose)(_w, _event, _region);
	XtReleaseGC(_w, lw->label.insensitive_GC);

	lw->label.TextRect.x -= 1;
	lw->label.TextRect.y -= 1;
	if (lw->label._acc_text != 0)
	{
	    lw->label.acc_TextRect.x -= 1;
	    lw->label.acc_TextRect.y -= 1;
	}

	values.foreground = lw->primitive.bottom_shadow_color;
	values.background = lw->core.background_pixel;

	lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask,
					       &values, dynamic, (XtGCMask)0);
	(*old_label_expose)(_w, _event, _region);
	XtReleaseGC(_w, lw->label.insensitive_GC);

	lw->label.insensitive_GC = insensitiveGC;
    }
}

/*
 * Create all the motif widgets necessary.
 */
    void
gui_x11_create_widgets()
{
#ifdef FEAT_GUI_TABLINE
    Widget	button, scroller;
    Arg		args[10];
    int		n;
    XmString	xms;
#endif

    /*
     * Install the 3D shade effect drawing routines.
     */
    if (old_label_expose == NULL)
    {
	old_label_expose = xmLabelWidgetClass->core_class.expose;
	xmLabelWidgetClass->core_class.expose = label_expose;
    }

    /*
     * Start out by adding the configured border width into the border offset
     */
    gui.border_offset = gui.border_width;

    /*
     * Install the tearOffModel resource converter.
     */
#if (XmVersion >= 1002)
    XmRepTypeInstallTearOffModelConverter();
#endif

    /* Make sure the "Quit" menu entry of the window manager is ignored */
    XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL);

    vimForm = XtVaCreateManagedWidget("vimForm",
	xmFormWidgetClass, vimShell,
	XmNborderWidth, 0,
	XmNhighlightThickness, 0,
	XmNshadowThickness, 0,
	XmNmarginWidth, 0,
	XmNmarginHeight, 0,
	XmNresizePolicy, XmRESIZE_ANY,
	NULL);
    gui_motif_menu_colors(vimForm);

#ifdef FEAT_MENU
    {
	Arg al[7]; /* Make sure there is enough room for arguments! */
	int ac = 0;

# if (XmVersion >= 1002)
	XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++;
# endif
	XtSetArg(al[ac], XmNleftAttachment,  XmATTACH_FORM); ac++;
	XtSetArg(al[ac], XmNtopAttachment,   XmATTACH_FORM); ac++;
	XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
# ifndef FEAT_TOOLBAR
	/* Always stick to right hand side. */
	XtSetArg(al[ac], XmNrightOffset, 0); ac++;
# endif
	XtSetArg(al[ac], XmNmarginHeight, 0); ac++;
	menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac);
	XtManageChild(menuBar);

	/* Remember the default colors, needed for ":hi clear". */
	XtVaGetValues(menuBar,
	    XmNbackground, &gui.menu_def_bg_pixel,
	    XmNforeground, &gui.menu_def_fg_pixel,
	    NULL);
	gui_motif_menu_colors(menuBar);
    }
#endif

#ifdef FEAT_TOOLBAR
    /*
     * Create an empty ToolBar. We should get buttons defined from menu.vim.
     */
    toolBarFrame = XtVaCreateWidget("toolBarFrame",
	xmFrameWidgetClass, vimForm,
	XmNshadowThickness, 0,
	XmNmarginHeight, 0,
	XmNmarginWidth, 0,
	XmNleftAttachment, XmATTACH_FORM,
	XmNrightAttachment, XmATTACH_FORM,
	NULL);
    gui_motif_menu_colors(toolBarFrame);

    toolBar = XtVaCreateManagedWidget("toolBar",
	xmRowColumnWidgetClass, toolBarFrame,
	XmNchildType, XmFRAME_WORKAREA_CHILD,
	XmNrowColumnType, XmWORK_AREA,
	XmNorientation, XmHORIZONTAL,
	XmNtraversalOn, False,
	XmNisHomogeneous, False,
	XmNpacking, XmPACK_TIGHT,
	XmNspacing, 0,
	XmNshadowThickness, 0,
	XmNhighlightThickness, 0,
	XmNmarginHeight, 0,
	XmNmarginWidth, 0,
	XmNadjustLast, True,
	NULL);
    gui_motif_menu_colors(toolBar);

#endif

#ifdef FEAT_GUI_TABLINE
    /* Create the Vim GUI tabline */
    n = 0;
    XtSetArg(args[n], XmNbindingType, XmNONE); n++;
    XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
    XtSetArg(args[n], XmNbackPageSize, XmNONE); n++;
    XtSetArg(args[n], XmNbackPageNumber, 0); n++;
    XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++;
    XtSetArg(args[n], XmNmajorTabSpacing, 0); n++;
    XtSetArg(args[n], XmNshadowThickness, 0); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
    tabLine = XmCreateNotebook(vimForm, "Vim tabline", args, n);

    XtAddCallback(tabLine, XmNpageChangedCallback, (XtCallbackProc)tabline_cb,
			NULL);
    XtAddEventHandler(tabLine, ButtonPressMask, False,
			(XtEventHandler)tabline_menu_cb, NULL);

    gui.tabline_height = TABLINE_HEIGHT;

    /*
     * Set the size of the minor next/prev scrollers to zero, so
     * that they are not displayed. Due to a bug in OpenMotif 2.3,
     * even if these children widget are unmanaged, they are again
     * managed by the Notebook widget and the notebook widget geometry
     * is adjusted to account for the minor scroller widgets.
     */
    scroller = XtNameToWidget(tabLine, "MinorTabScrollerNext");
    XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
		  XmNtraversalOn, False, NULL);
    scroller = XtNameToWidget(tabLine, "MinorTabScrollerPrevious");
    XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False,
		  XmNtraversalOn, False, NULL);

    /* Create the tabline popup menu */
    tabLine_menu = XmCreatePopupMenu(tabLine, "tabline popup", NULL, 0);

    /* Add the buttons to the menu */
    n = 0;
    XtSetArg(args[n], XmNuserData, TABLINE_MENU_CLOSE); n++;
    xms = XmStringCreate((char *)"Close tab", STRING_TAG);
    XtSetArg(args[n], XmNlabelString, xms); n++;
    button = XmCreatePushButton(tabLine_menu, "Close", args, n);
    XtAddCallback(button, XmNactivateCallback,
		  (XtCallbackProc)tabline_button_cb, NULL);
    XmStringFree(xms);

    n = 0;
    XtSetArg(args[n], XmNuserData, TABLINE_MENU_NEW); n++;
    xms = XmStringCreate((char *)"New Tab", STRING_TAG);
    XtSetArg(args[n], XmNlabelString, xms); n++;
    button = XmCreatePushButton(tabLine_menu, "New Tab", args, n);
    XtAddCallback(button, XmNactivateCallback,
		  (XtCallbackProc)tabline_button_cb, NULL);
    XmStringFree(xms);

    n = 0;
    XtSetArg(args[n], XmNuserData, TABLINE_MENU_OPEN); n++;
    xms = XmStringCreate((char *)"Open tab...", STRING_TAG);
    XtSetArg(args[n], XmNlabelString, xms); n++;
    button = XmCreatePushButton(tabLine_menu, "Open tab...", args, n);
    XtAddCallback(button, XmNactivateCallback,
		  (XtCallbackProc)tabline_button_cb, NULL);
    XmStringFree(xms);
#endif

    textAreaForm = XtVaCreateManagedWidget("textAreaForm",
	xmFormWidgetClass, vimForm,
	XmNleftAttachment, XmATTACH_FORM,
	XmNrightAttachment, XmATTACH_FORM,
	XmNbottomAttachment, XmATTACH_FORM,
	XmNtopAttachment, XmATTACH_FORM,
	XmNmarginWidth, 0,
	XmNmarginHeight, 0,
	XmNresizePolicy, XmRESIZE_ANY,
	NULL);
    gui_motif_scroll_colors(textAreaForm);

    textArea = XtVaCreateManagedWidget("textArea",
	xmDrawingAreaWidgetClass, textAreaForm,
	XmNforeground, gui.norm_pixel,
	XmNbackground, gui.back_pixel,
	XmNleftAttachment, XmATTACH_FORM,
	XmNtopAttachment, XmATTACH_FORM,
	XmNrightAttachment, XmATTACH_FORM,
	XmNbottomAttachment, XmATTACH_FORM,

	/*
	 * These take some control away from the user, but avoids making them
	 * add resources to get a decent looking setup.
	 */
	XmNborderWidth, 0,
	XmNhighlightThickness, 0,
	XmNshadowThickness, 0,
	NULL);

#ifdef FEAT_FOOTER
    /*
     * Create the Footer.
     */
    footer = XtVaCreateWidget("footer",
	xmLabelGadgetClass, vimForm,
	XmNalignment, XmALIGNMENT_BEGINNING,
	XmNmarginHeight, 0,
	XmNmarginWidth, 0,
	XmNtraversalOn, False,
	XmNrecomputeSize, False,
	XmNleftAttachment, XmATTACH_FORM,
	XmNleftOffset, 5,
	XmNrightAttachment, XmATTACH_FORM,
	XmNbottomAttachment, XmATTACH_FORM,
	NULL);
    gui_mch_set_footer((char_u *) "");
#endif

    /*
     * Install the callbacks.
     */
    gui_x11_callbacks(textArea, vimForm);

    /* Pretend we don't have input focus, we will get an event if we do. */
    gui.in_focus = FALSE;
}

/*
 * Called when the GUI is not going to start after all.
 */
    void
gui_x11_destroy_widgets()
{
    textArea = NULL;
#ifdef FEAT_MENU
    menuBar = NULL;
#endif
}

    void
gui_mch_set_text_area_pos(x, y, w, h)
    int	    x UNUSED;
    int	    y UNUSED;
    int	    w UNUSED;
    int	    h UNUSED;
{
#ifdef FEAT_TOOLBAR
    /* Give keyboard focus to the textArea instead of the toolbar. */
    reset_focus();
#endif
}

    void
gui_x11_set_back_color()
{
    if (textArea != NULL)
#if (XmVersion >= 1002)
	XmChangeColor(textArea, gui.back_pixel);
#else
	XtVaSetValues(textArea,
		  XmNbackground, gui.back_pixel,
		  NULL);
#endif
}

/*
 * Manage dialog centered on pointer. This could be used by the Athena code as
 * well.
 */
    void
manage_centered(dialog_child)
    Widget dialog_child;
{
    Widget shell = XtParent(dialog_child);
    Window root, child;
    unsigned int mask;
    unsigned int width, height, border_width, depth;
    int x, y, win_x, win_y, maxX, maxY;
    Boolean mappedWhenManaged;

    /* Temporarily set value of XmNmappedWhenManaged
       to stop the dialog from popping up right away */
    XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, NULL);
    XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL);

    XtManageChild(dialog_child);

    /* Get the pointer position (x, y) */
    XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child,
		  &x, &y, &win_x, &win_y, &mask);

    /* Translate the pointer position (x, y) into a position for the new
       window that will place the pointer at its center */
    XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y,
		 &width, &height, &border_width, &depth);
    width += 2 * border_width;
    height += 2 * border_width;
    x -= width / 2;
    y -= height / 2;

    /* Ensure that the dialog remains on screen */
    maxX = XtScreen(shell)->width - width;
    maxY = XtScreen(shell)->height - height;
    if (x < 0)
	x = 0;
    if (x > maxX)
	x = maxX;
    if (y < 0)
	y = 0;
    if (y > maxY)
	y = maxY;

    /* Set desired window position in the DialogShell */
    XtVaSetValues(shell, XmNx, x, XmNy, y, NULL);

    /* Map the widget */
    XtMapWidget(shell);

    /* Restore the value of XmNmappedWhenManaged */
    XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, NULL);
}

#if defined(FEAT_MENU) || defined(FEAT_SUN_WORKSHOP) \
	|| defined(FEAT_GUI_DIALOG) || defined(PROTO)

/*
 * Encapsulate the way an XmFontList is created.
 */
    XmFontList
gui_motif_create_fontlist(font)
    XFontStruct    *font;
{
    XmFontList font_list;

# if (XmVersion <= 1001)
    /* Motif 1.1 method */
    font_list = XmFontListCreate(font, STRING_TAG);
# else
    /* Motif 1.2 method */
    XmFontListEntry font_list_entry;

    font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT,
					    (XtPointer)font);
    font_list = XmFontListAppendEntry(NULL, font_list_entry);
    XmFontListEntryFree(&font_list_entry);
# endif
    return font_list;
}

# if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO)
    XmFontList
gui_motif_fontset2fontlist(fontset)
    XFontSet	*fontset;
{
    XmFontList font_list;

    /* Motif 1.2 method */
    XmFontListEntry font_list_entry;

    font_list_entry = XmFontListEntryCreate(STRING_TAG,
					    XmFONT_IS_FONTSET,
					    (XtPointer)*fontset);
    font_list = XmFontListAppendEntry(NULL, font_list_entry);
    XmFontListEntryFree(&font_list_entry);
    return font_list;
}
# endif

#endif

#if defined(FEAT_MENU) || defined(PROTO)
/*
 * Menu stuff.
 */

static void gui_motif_add_actext __ARGS((vimmenu_T *menu));
#if (XmVersion >= 1002)
static void toggle_tearoff __ARGS((Widget wid));
static void gui_mch_recurse_tearoffs __ARGS((vimmenu_T *menu));
#endif
static void submenu_change __ARGS((vimmenu_T *mp, int colors));

static void do_set_mnemonics __ARGS((int enable));
static int menu_enabled = TRUE;

    void
gui_mch_enable_menu(flag)
    int	    flag;
{
    if (flag)
    {
	XtManageChild(menuBar);
#ifdef FEAT_TOOLBAR
	if (XtIsManaged(XtParent(toolBar)))
	{
	    /* toolBar is attached to top form */
	    XtVaSetValues(XtParent(toolBar),
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, menuBar,
		NULL);
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar),
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar),
			      NULL);
	}
	else
#endif
	{
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar,
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar,
			      NULL);
	}
    }
    else
    {
	XtUnmanageChild(menuBar);
#ifdef FEAT_TOOLBAR
	if (XtIsManaged(XtParent(toolBar)))
	{
	    XtVaSetValues(XtParent(toolBar),
		XmNtopAttachment, XmATTACH_FORM,
		NULL);
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar),
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar),
			      NULL);
	}
	else
#endif
	{
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_FORM,
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_FORM,
			      NULL);
	}
    }

}

/*
 * Enable or disable mnemonics for the toplevel menus.
 */
    void
gui_motif_set_mnemonics(enable)
    int		enable;
{
    /*
     * Don't enable menu mnemonics when the menu bar is disabled, LessTif
     * crashes when using a mnemonic then.
     */
    if (!menu_enabled)
	enable = FALSE;
    do_set_mnemonics(enable);
}

    static void
do_set_mnemonics(enable)
    int		enable;
{
    vimmenu_T	*menu;

    for (menu = root_menu; menu != NULL; menu = menu->next)
	if (menu->id != (Widget)0)
	    XtVaSetValues(menu->id,
		    XmNmnemonic, enable ? menu->mnemonic : NUL,
		    NULL);
}

    void
gui_mch_add_menu(menu, idx)
    vimmenu_T	*menu;
    int		idx;
{
    XmString	label;
    Widget	shell;
    vimmenu_T	*parent = menu->parent;

#ifdef MOTIF_POPUP
    if (menu_is_popup(menu->name))
    {
	Arg arg[2];
	int n = 0;

	/* Only create the popup menu when it's actually used, otherwise there
	 * is a delay when using the right mouse button. */
# if (XmVersion <= 1002)
	if (mouse_model_popup())
# endif
	{
	    if (gui.menu_bg_pixel != INVALCOLOR)
	    {
		XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++;
	    }
	    if (gui.menu_fg_pixel != INVALCOLOR)
	    {
		XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++;
	    }
	    menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu",
								      arg, n);
	    menu->id = (Widget)0;
	}
	return;
    }
#endif

    if (!menu_is_menubar(menu->name)
	    || (parent != NULL && parent->submenu_id == (Widget)0))
	return;

    label = XmStringCreate((char *)menu->dname, STRING_TAG);
    if (label == NULL)
	return;
    menu->id = XtVaCreateWidget("subMenu",
	    xmCascadeButtonWidgetClass,
	    (parent == NULL) ? menuBar : parent->submenu_id,
	    XmNlabelString, label,
	    XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic,
#if (XmVersion >= 1002)
	    /* submenu: count the tearoff item (needed for LessTif) */
	    XmNpositionIndex, idx + (parent != NULL
			   && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0),
#endif
	    NULL);
    gui_motif_menu_colors(menu->id);
    gui_motif_menu_fontlist(menu->id);
    XmStringFree(label);

    if (menu->id == (Widget)0)		/* failed */
	return;

    /* add accelerator text */
    gui_motif_add_actext(menu);

    shell = XtVaCreateWidget("subMenuShell",
	xmMenuShellWidgetClass, menu->id,
	XmNwidth, 1,
	XmNheight, 1,
	NULL);
    gui_motif_menu_colors(shell);
    menu->submenu_id = XtVaCreateWidget("rowColumnMenu",
	xmRowColumnWidgetClass, shell,
	XmNrowColumnType, XmMENU_PULLDOWN,
	NULL);
    gui_motif_menu_colors(menu->submenu_id);

    if (menu->submenu_id == (Widget)0)		/* failed */
	return;

#if (XmVersion >= 1002)
    /* Set the colors for the tear off widget */
    toggle_tearoff(menu->submenu_id);
#endif

    XtVaSetValues(menu->id,
	XmNsubMenuId, menu->submenu_id,
	NULL);

    /*
     * The "Help" menu is a special case, and should be placed at the far
     * right hand side of the menu-bar.  It's recognized by its high priority.
     */
    if (parent == NULL && menu->priority >= 9999)
	XtVaSetValues(menuBar,
		XmNmenuHelpWidget, menu->id,
		NULL);

    /*
     * When we add a top-level item to the menu bar, we can figure out how
     * high the menu bar should be.
     */
    if (parent == NULL)
	gui_mch_compute_menu_height(menu->id);
}


/*
 * Add mnemonic and accelerator text to a menu button.
 */
    static void
gui_motif_add_actext(menu)
    vimmenu_T	*menu;
{
    XmString	label;

    /* Add accelerator text, if there is one */
    if (menu->actext != NULL && menu->id != (Widget)0)
    {
	label = XmStringCreate((char *)menu->actext, STRING_TAG);
	if (label == NULL)
	    return;
	XtVaSetValues(menu->id, XmNacceleratorText, label, NULL);
	XmStringFree(label);
    }
}

    void
gui_mch_toggle_tearoffs(enable)
    int		enable;
{
#if (XmVersion >= 1002)
    if (enable)
	tearoff_val = (int)XmTEAR_OFF_ENABLED;
    else
	tearoff_val = (int)XmTEAR_OFF_DISABLED;
    toggle_tearoff(menuBar);
    gui_mch_recurse_tearoffs(root_menu);
#endif
}

#if (XmVersion >= 1002)
/*
 * Set the tearoff for one menu widget on or off, and set the color of the
 * tearoff widget.
 */
    static void
toggle_tearoff(wid)
    Widget	wid;
{
    Widget	w;

    XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL);
    if (tearoff_val == (int)XmTEAR_OFF_ENABLED
	    && (w = XmGetTearOffControl(wid)) != (Widget)0)
	gui_motif_menu_colors(w);
}

    static void
gui_mch_recurse_tearoffs(menu)
    vimmenu_T	*menu;
{
    while (menu != NULL)
    {
	if (!menu_is_popup(menu->name))
	{
	    if (menu->submenu_id != (Widget)0)
		toggle_tearoff(menu->submenu_id);
	    gui_mch_recurse_tearoffs(menu->children);
	}
	menu = menu->next;
    }
}
#endif

    int
gui_mch_text_area_extra_height()
{
    Dimension	shadowHeight;

    XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL);
    return shadowHeight;
}

/*
 * Compute the height of the menu bar.
 * We need to check all the items for their position and height, for the case
 * there are several rows, and/or some characters extend higher or lower.
 */
    void
gui_mch_compute_menu_height(id)
    Widget	id;		    /* can be NULL when deleting menu */
{
    Dimension	y, maxy;
    Dimension	margin, shadow;
    vimmenu_T	*mp;
    static Dimension	height = 21;	/* normal height of a menu item */

    /*
     * Get the height of the new item, before managing it, because it will
     * still reflect the font size.  After managing it depends on the menu
     * height, which is what we just wanted to get!.
     */
    if (id != (Widget)0)
	XtVaGetValues(id, XmNheight, &height, NULL);

    /* Find any menu Widget, to be able to call XtManageChild() */
    else
	for (mp = root_menu; mp != NULL; mp = mp->next)
	    if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
	    {
		id = mp->id;
		break;
	    }

    /*
     * Now manage the menu item, to make them all be positioned (makes an
     * extra row when needed, removes it when not needed).
     */
    if (id != (Widget)0)
	XtManageChild(id);

    /*
     * Now find the menu item that is the furthest down, and get it's position.
     */
    maxy = 0;
    for (mp = root_menu; mp != NULL; mp = mp->next)
    {
	if (mp->id != (Widget)0 && menu_is_menubar(mp->name))
	{
	    XtVaGetValues(mp->id, XmNy, &y, NULL);
	    if (y > maxy)
		maxy = y;
	}
    }

    XtVaGetValues(menuBar,
	XmNmarginHeight, &margin,
	XmNshadowThickness, &shadow,
	NULL);

    /*
     * This computation is the result of trial-and-error:
     * maxy =	The maximum position of an item; required for when there are
     *		two or more rows
     * height = height of an item, before managing it;	Hopefully this will
     *		change with the font height.  Includes shadow-border.
     * shadow =	shadow-border; must be subtracted from the height.
     * margin = margin around the menu buttons;  Must be added.
     * Add 4 for the underlining of shortcut keys.
     */
    gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4;

    /* Somehow the menu bar doesn't resize automatically.  Set it here,
     * even though this is a catch 22.  Don't do this when starting up,
     * somehow the menu gets very high then. */
    if (gui.shell_created)
	XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL);
}

#ifdef FEAT_TOOLBAR

/*
 * Icons used by the toolbar code.
 */
#include "gui_x11_pm.h"

static int check_xpm __ARGS((char_u *path));
static char **get_toolbar_pixmap __ARGS((vimmenu_T *menu, char **fname));
static int add_pixmap_args __ARGS((vimmenu_T *menu, Arg *args, int n));

/*
 * Read an Xpm file.  Return OK or FAIL.
 */
    static int
check_xpm(path)
    char_u	*path;
{
    XpmAttributes attrs;
    int		status;
    Pixmap	mask;
    Pixmap	map;

    attrs.valuemask = 0;

    /* Create the "sensitive" pixmap */
    status = XpmReadFileToPixmap(gui.dpy,
	    RootWindow(gui.dpy, DefaultScreen(gui.dpy)),
	    (char *)path, &map, &mask, &attrs);
    XpmFreeAttributes(&attrs);

    if (status == XpmSuccess)
	return OK;
    return FAIL;
}


/*
 * Allocated a pixmap for toolbar menu "menu".
 * When it's to be read from a file, "fname" is set to the file name
 * (in allocated memory).
 * Return a blank pixmap if it fails.
 */
    static char **
get_toolbar_pixmap(menu, fname)
    vimmenu_T	*menu;
    char	**fname;
{
    char_u	buf[MAXPATHL];		/* buffer storing expanded pathname */
    char	**xpm = NULL;		/* xpm array */
    int		res;

    *fname = NULL;
    buf[0] = NUL;			/* start with NULL path */

    if (menu->iconfile != NULL)
    {
	/* Use the "icon="  argument. */
	gui_find_iconfile(menu->iconfile, buf, "xpm");
	res = check_xpm(buf);

	/* If it failed, try using the menu name. */
	if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK)
	    res = check_xpm(buf);
	if (res == OK)
	{
	    *fname = (char *)vim_strsave(buf);
	    return tb_blank_xpm;
	}
    }

    if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
    {
	if (menu->iconidx >= 0 && menu->iconidx
	       < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
	    xpm = built_in_pixmaps[menu->iconidx];
	else
	    xpm = tb_blank_xpm;
    }

    return xpm;
}

/*
 * Add arguments for the toolbar pixmap to a menu item.
 */
    static int
add_pixmap_args(menu, args, n)
    vimmenu_T	*menu;
    Arg		*args;
    int		n;
{
    vim_free(menu->xpm_fname);
    menu->xpm = get_toolbar_pixmap(menu, &menu->xpm_fname);
    if (menu->xpm == NULL)
    {
	XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
    }
    else
    {
	if (menu->xpm_fname != NULL)
	{
	    XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++;
	}
	XtSetArg(args[n], XmNpixmapData, menu->xpm); n++;
	XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++;
    }
    return n;
}
#endif /* FEAT_TOOLBAR */

    void
gui_mch_add_menu_item(menu, idx)
    vimmenu_T	*menu;
    int		idx;
{
    XmString	label;
    vimmenu_T	*parent = menu->parent;

# ifdef EBCDIC
    menu->mnemonic = 0;
# endif

# if (XmVersion <= 1002)
    /* Don't add Popup menu items when the popup menu isn't used. */
    if (menu_is_child_of_popup(menu) && !mouse_model_popup())
	return;
# endif

# ifdef FEAT_TOOLBAR
    if (menu_is_toolbar(parent->name))
    {
	WidgetClass	type;
	XmString	xms = NULL;    /* fallback label if pixmap not found */
	int		n;
	Arg		args[18];

	n = 0;
	if (menu_is_separator(menu->name))
	{
	    char	*cp;
	    Dimension	wid;

	    /*
	     * A separator has the format "-sep%d[:%d]-". The optional :%d is
	     * a width specifier. If no width is specified then we choose one.
	     */
	    cp = (char *)vim_strchr(menu->name, ':');
	    if (cp != NULL)
		wid = (Dimension)atoi(++cp);
	    else
		wid = 4;

#if 0
	    /* We better use a FormWidget here, since it's far more
	     * flexible in terms of size.  */
	    type = xmFormWidgetClass;
	    XtSetArg(args[n], XmNwidth, wid); n++;
#else
	    type = xmSeparatorWidgetClass;
	    XtSetArg(args[n], XmNwidth, wid); n++;
	    XtSetArg(args[n], XmNminWidth, wid); n++;
	    XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
	    XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++;
#endif
	}
	else
	{
	    /* Without shadows one can't sense whatever the button has been
	     * pressed or not! However we wan't to save a bit of space...
	     * Need the highlightThickness to see the focus.
	     */
	    XtSetArg(args[n], XmNhighlightThickness, 1); n++;
	    XtSetArg(args[n], XmNhighlightOnEnter, True); n++;
	    XtSetArg(args[n], XmNmarginWidth, 0); n++;
	    XtSetArg(args[n], XmNmarginHeight, 0); n++;
	    XtSetArg(args[n], XmNtraversalOn, False); n++;
	    /* Set the label here, so that we can switch between icons/text
	     * by changing the XmNlabelType resource. */
	    xms = XmStringCreate((char *)menu->dname, STRING_TAG);
	    XtSetArg(args[n], XmNlabelString, xms); n++;

	    n = add_pixmap_args(menu, args, n);

	    type = xmEnhancedButtonWidgetClass;
	}

	XtSetArg(args[n], XmNpositionIndex, idx); n++;
	if (menu->id == NULL)
	{
	    menu->id = XtCreateManagedWidget((char *)menu->dname,
			type, toolBar, args, n);
	    if (menu->id != NULL && type == xmEnhancedButtonWidgetClass)
	    {
		XtAddCallback(menu->id,
			XmNactivateCallback, gui_x11_menu_cb, menu);
# ifdef FEAT_FOOTER
		XtAddEventHandler(menu->id, EnterWindowMask, False,
			toolbarbutton_enter_cb, menu);
		XtAddEventHandler(menu->id, LeaveWindowMask, False,
			toolbarbutton_leave_cb, menu);
# endif
	    }
	}
	else
	    XtSetValues(menu->id, args, n);
	if (xms != NULL)
	    XmStringFree(xms);

# ifdef FEAT_BEVAL
	gui_mch_menu_set_tip(menu);
# endif

	menu->parent = parent;
	menu->submenu_id = NULL;
	/* When adding first item to toolbar it might have to be enabled .*/
	if (!XtIsManaged(XtParent(toolBar))
		    && vim_strchr(p_go, GO_TOOLBAR) != NULL)
	    gui_mch_show_toolbar(TRUE);
	gui.toolbar_height = gui_mch_compute_toolbar_height();
	return;
    } /* toolbar menu item */
# endif

    /* No parent, must be a non-menubar menu */
    if (parent->submenu_id == (Widget)0)
	return;

    menu->submenu_id = (Widget)0;

    /* Add menu separator */
    if (menu_is_separator(menu->name))
    {
	menu->id = XtVaCreateWidget("subMenu",
		xmSeparatorGadgetClass, parent->submenu_id,
#if (XmVersion >= 1002)
		/* count the tearoff item (needed for LessTif) */
		XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
								     ? 1 : 0),
#endif
		NULL);
	gui_motif_menu_colors(menu->id);
	return;
    }

    label = XmStringCreate((char *)menu->dname, STRING_TAG);
    if (label == NULL)
	return;
    menu->id = XtVaCreateWidget("subMenu",
	xmPushButtonWidgetClass, parent->submenu_id,
	XmNlabelString, label,
	XmNmnemonic, menu->mnemonic,
#if (XmVersion >= 1002)
	/* count the tearoff item (needed for LessTif) */
	XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED
								     ? 1 : 0),
#endif
	NULL);
    gui_motif_menu_colors(menu->id);
    gui_motif_menu_fontlist(menu->id);
    XmStringFree(label);

    if (menu->id != (Widget)0)
    {
	XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb,
		(XtPointer)menu);
	/* add accelerator text */
	gui_motif_add_actext(menu);
    }
}

#if (XmVersion <= 1002) || defined(PROTO)
/*
 * This function will destroy/create the popup menus dynamically,
 * according to the value of 'mousemodel'.
 * This will fix the "right mouse button freeze" that occurs when
 * there exists a popup menu but it isn't managed.
 */
    void
gui_motif_update_mousemodel(menu)
    vimmenu_T	*menu;
{
    int		idx = 0;

    /* When GUI hasn't started the menus have not been created. */
    if (!gui.in_use)
      return;

    while (menu)
    {
      if (menu->children != NULL)
      {
	  if (menu_is_popup(menu->name))
	  {
	      if (mouse_model_popup())
	      {
		  /* Popup menu will be used.  Create the popup menus. */
		  gui_mch_add_menu(menu, idx);
		  gui_motif_update_mousemodel(menu->children);
	      }
	      else
	      {
		  /* Popup menu will not be used.  Destroy the popup menus. */
		  gui_motif_update_mousemodel(menu->children);
		  gui_mch_destroy_menu(menu);
	      }
	  }
      }
      else if (menu_is_child_of_popup(menu))
      {
	  if (mouse_model_popup())
	      gui_mch_add_menu_item(menu, idx);
	  else
	      gui_mch_destroy_menu(menu);
      }
      menu = menu->next;
      ++idx;
    }
}
#endif

    void
gui_mch_new_menu_colors()
{
    if (menuBar == (Widget)0)
	return;
    gui_motif_menu_colors(menuBar);
#ifdef FEAT_TOOLBAR
    gui_motif_menu_colors(toolBarFrame);
    gui_motif_menu_colors(toolBar);
#endif

    submenu_change(root_menu, TRUE);
}

    void
gui_mch_new_menu_font()
{
    if (menuBar == (Widget)0)
	return;
    submenu_change(root_menu, FALSE);
    {
	Dimension   height;
	Position w, h;

	XtVaGetValues(menuBar, XmNheight, &height, NULL);
	gui.menu_height = height;

	XtVaGetValues(vimShell, XtNwidth, &w, XtNheight, &h, NULL);
	gui_resize_shell(w, h
#ifdef FEAT_XIM
		- xim_get_status_area_height()
#endif
		     );
    }
    gui_set_shellsize(FALSE, TRUE, RESIZE_VERT);
    ui_new_shellsize();
}

#if defined(FEAT_BEVAL) || defined(PROTO)
    void
gui_mch_new_tooltip_font()
{
# ifdef FEAT_TOOLBAR
    vimmenu_T   *menu;

    if (toolBar == (Widget)0)
	return;

    menu = gui_find_menu((char_u *)"ToolBar");
    if (menu != NULL)
	submenu_change(menu, FALSE);
# endif
}

    void
gui_mch_new_tooltip_colors()
{
# ifdef FEAT_TOOLBAR
    vimmenu_T   *toolbar;

    if (toolBar == (Widget)0)
	return;

    toolbar = gui_find_menu((char_u *)"ToolBar");
    if (toolbar != NULL)
	submenu_change(toolbar, TRUE);
# endif
}
#endif

    static void
submenu_change(menu, colors)
    vimmenu_T	*menu;
    int		colors;		/* TRUE for colors, FALSE for font */
{
    vimmenu_T	*mp;

    for (mp = menu; mp != NULL; mp = mp->next)
    {
	if (mp->id != (Widget)0)
	{
	    if (colors)
	    {
		gui_motif_menu_colors(mp->id);
#ifdef FEAT_TOOLBAR
		/* For a toolbar item: Free the pixmap and allocate a new one,
		 * so that the background color is right. */
		if (mp->xpm != NULL)
		{
		    int		n = 0;
		    Arg		args[18];

		    n = add_pixmap_args(mp, args, n);
		    XtSetValues(mp->id, args, n);
		}
# ifdef FEAT_BEVAL
		/* If we have a tooltip, then we need to change it's font */
		if (mp->tip != NULL)
		{
		    Arg args[2];

		    args[0].name = XmNbackground;
		    args[0].value = gui.tooltip_bg_pixel;
		    args[1].name = XmNforeground;
		    args[1].value = gui.tooltip_fg_pixel;
		    XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
		}
# endif
#endif
	    }
	    else
	    {
		gui_motif_menu_fontlist(mp->id);
#ifdef FEAT_BEVAL
		/* If we have a tooltip, then we need to change it's font */
		if (mp->tip != NULL)
		{
		    Arg args[1];

		    args[0].name = XmNfontList;
		    args[0].value = (XtArgVal)gui_motif_fontset2fontlist(
						    &gui.tooltip_fontset);
		    XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
		}
#endif
	    }
	}

	if (mp->children != NULL)
	{
#if (XmVersion >= 1002)
	    /* Set the colors/font for the tear off widget */
	    if (mp->submenu_id != (Widget)0)
	    {
		if (colors)
		    gui_motif_menu_colors(mp->submenu_id);
		else
		    gui_motif_menu_fontlist(mp->submenu_id);
		toggle_tearoff(mp->submenu_id);
	    }
#endif
	    /* Set the colors for the children */
	    submenu_change(mp->children, colors);
	}
    }
}

/*
 * Destroy the machine specific menu widget.
 */
    void
gui_mch_destroy_menu(menu)
    vimmenu_T	*menu;
{
    /* Please be sure to destroy the parent widget first (i.e. menu->id).
     * On the other hand, problems have been reported that the submenu must be
     * deleted first...
     *
     * This code should be basically identical to that in the file gui_athena.c
     * because they are both Xt based.
     */
    if (menu->submenu_id != (Widget)0)
    {
	XtDestroyWidget(menu->submenu_id);
	menu->submenu_id = (Widget)0;
    }

    if (menu->id != (Widget)0)
    {
	Widget	    parent;

	parent = XtParent(menu->id);
#if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
	if (parent == toolBar && menu->tip != NULL)
	{
	    /* We try to destroy this before the actual menu, because there are
	     * callbacks, etc. that will be unregistered during the tooltip
	     * destruction.
	     *
	     * If you call "gui_mch_destroy_beval_area()" after destroying
	     * menu->id, then the tooltip's window will have already been
	     * deallocated by Xt, and unknown behaviour will ensue (probably
	     * a core dump).
	     */
	    gui_mch_destroy_beval_area(menu->tip);
	    menu->tip = NULL;
	}
#endif
	XtDestroyWidget(menu->id);
	menu->id = (Widget)0;
	if (parent == menuBar)
	    gui_mch_compute_menu_height((Widget)0);
#ifdef FEAT_TOOLBAR
	else if (parent == toolBar)
	{
	    Cardinal    num_children;

	    /* When removing last toolbar item, don't display the toolbar. */
	    XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL);
	    if (num_children == 0)
		gui_mch_show_toolbar(FALSE);
	    else
		gui.toolbar_height = gui_mch_compute_toolbar_height();
	}
#endif
    }
}

    void
gui_mch_show_popupmenu(menu)
    vimmenu_T *menu UNUSED;
{
#ifdef MOTIF_POPUP
    XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event());
    XtManageChild(menu->submenu_id);
#endif
}

#endif /* FEAT_MENU */

/*
 * Set the menu and scrollbar colors to their default values.
 */
    void
gui_mch_def_colors()
{
    if (gui.in_use)
    {
	/* Use the values saved when starting up.  These should come from the
	 * window manager or a resources file. */
	gui.menu_fg_pixel = gui.menu_def_fg_pixel;
	gui.menu_bg_pixel = gui.menu_def_bg_pixel;
	gui.scroll_fg_pixel = gui.scroll_def_fg_pixel;
	gui.scroll_bg_pixel = gui.scroll_def_bg_pixel;
#ifdef FEAT_BEVAL
	gui.tooltip_fg_pixel =
			gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
	gui.tooltip_bg_pixel =
			gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
#endif
    }
}


/*
 * Scrollbar stuff.
 */

    void
gui_mch_set_scrollbar_thumb(sb, val, size, max)
    scrollbar_T *sb;
    long	val;
    long	size;
    long	max;
{
    if (sb->id != (Widget)0)
	XtVaSetValues(sb->id,
		  XmNvalue, val,
		  XmNsliderSize, size,
		  XmNpageIncrement, (size > 2 ? size - 2 : 1),
		  XmNmaximum, max + 1,	    /* Motif has max one past the end */
		  NULL);
}

    void
gui_mch_set_scrollbar_pos(sb, x, y, w, h)
    scrollbar_T *sb;
    int		x;
    int		y;
    int		w;
    int		h;
{
    if (sb->id != (Widget)0)
    {
	if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT)
	{
	    if (y == 0)
		h -= gui.border_offset;
	    else
		y -= gui.border_offset;
	    XtVaSetValues(sb->id,
			  XmNtopOffset, y,
			  XmNbottomOffset, -y - h,
			  XmNwidth, w,
			  NULL);
	}
	else
	    XtVaSetValues(sb->id,
			  XmNtopOffset, y,
			  XmNleftOffset, x,
			  XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT]
						    ? gui.scrollbar_width : 0,
			  XmNheight, h,
			  NULL);
	XtManageChild(sb->id);
    }
}

    void
gui_mch_enable_scrollbar(sb, flag)
    scrollbar_T *sb;
    int		flag;
{
    Arg		args[16];
    int		n;

    if (sb->id != (Widget)0)
    {
	n = 0;
	if (flag)
	{
	    switch (sb->type)
	    {
		case SBAR_LEFT:
		    XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++;
		    break;

		case SBAR_RIGHT:
		    XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++;
		    break;

		case SBAR_BOTTOM:
		    XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++;
		    break;
	    }
	    XtSetValues(textArea, args, n);
	    XtManageChild(sb->id);
	}
	else
	{
	    if (!gui.which_scrollbars[sb->type])
	    {
		/* The scrollbars of this type are all disabled, adjust the
		 * textArea attachment offset. */
		switch (sb->type)
		{
		    case SBAR_LEFT:
			XtSetArg(args[n], XmNleftOffset, 0); n++;
			break;

		    case SBAR_RIGHT:
			XtSetArg(args[n], XmNrightOffset, 0); n++;
			break;

		    case SBAR_BOTTOM:
			XtSetArg(args[n], XmNbottomOffset, 0);n++;
			break;
		}
		XtSetValues(textArea, args, n);
	    }
	    XtUnmanageChild(sb->id);
	}
    }
}

    void
gui_mch_create_scrollbar(sb, orient)
    scrollbar_T *sb;
    int		orient;	/* SBAR_VERT or SBAR_HORIZ */
{
    Arg		args[16];
    int		n;

    n = 0;
    XtSetArg(args[n], XmNminimum, 0); n++;
    XtSetArg(args[n], XmNorientation,
	    (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++;

    switch (sb->type)
    {
	case SBAR_LEFT:
	    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
	    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
	    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
	    break;

	case SBAR_RIGHT:
	    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
	    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++;
	    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
	    break;

	case SBAR_BOTTOM:
	    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
	    XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
	    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
	    break;
    }

    sb->id = XtCreateWidget("scrollBar",
	    xmScrollBarWidgetClass, textAreaForm, args, n);

    /* Remember the default colors, needed for ":hi clear". */
    if (gui.scroll_def_bg_pixel == (guicolor_T)0
	    && gui.scroll_def_fg_pixel == (guicolor_T)0)
	XtVaGetValues(sb->id,
		XmNbackground, &gui.scroll_def_bg_pixel,
		XmNforeground, &gui.scroll_def_fg_pixel,
		NULL);

    if (sb->id != (Widget)0)
    {
	gui_mch_set_scrollbar_colors(sb);
	XtAddCallback(sb->id, XmNvalueChangedCallback,
		      scroll_cb, (XtPointer)sb->ident);
	XtAddCallback(sb->id, XmNdragCallback,
		      scroll_cb, (XtPointer)sb->ident);
	XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb,
	    (XtPointer)0);
    }
}

#if defined(FEAT_WINDOWS) || defined(PROTO)
    void
gui_mch_destroy_scrollbar(sb)
    scrollbar_T *sb;
{
    if (sb->id != (Widget)0)
	XtDestroyWidget(sb->id);
}
#endif

    void
gui_mch_set_scrollbar_colors(sb)
    scrollbar_T *sb;
{
    if (sb->id != (Widget)0)
    {
	if (gui.scroll_bg_pixel != INVALCOLOR)
	{
#if (XmVersion>=1002)
	    XmChangeColor(sb->id, gui.scroll_bg_pixel);
#else
	    XtVaSetValues(sb->id,
		    XmNtroughColor, gui.scroll_bg_pixel,
		    NULL);
#endif
	}

	if (gui.scroll_fg_pixel != INVALCOLOR)
	    XtVaSetValues(sb->id,
		    XmNforeground, gui.scroll_fg_pixel,
#if (XmVersion<1002)
		    XmNbackground, gui.scroll_fg_pixel,
#endif
		    NULL);
    }

    /* This is needed for the rectangle below the vertical scrollbars. */
    if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0)
	gui_motif_scroll_colors(textAreaForm);
}

/*
 * Miscellaneous stuff:
 */

    Window
gui_x11_get_wid()
{
    return(XtWindow(textArea));
}

/*
 * Look for a widget in the widget tree w, with a mnemonic matching keycode.
 * When one is found, simulate a button press on that widget and give it the
 * keyboard focus.  If the mnemonic is on a label, look in the userData field
 * of the label to see if it points to another widget, and give that the focus.
 */
    static void
do_mnemonic(Widget w, unsigned int keycode)
{
    WidgetList	    children;
    int		    numChildren, i;
    Boolean	    isMenu;
    KeySym	    mnemonic = '\0';
    char	    mneString[2];
    Widget	    userData;
    unsigned char   rowColType;

    if (XtIsComposite(w))
    {
	if (XtClass(w) == xmRowColumnWidgetClass)
	{
	    XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
	    isMenu = (rowColType != (unsigned char)XmWORK_AREA);
	}
	else
	    isMenu = False;
	if (!isMenu)
	{
	    XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
			  &numChildren, NULL);
	    for (i = 0; i < numChildren; i++)
		do_mnemonic(children[i], keycode);
	}
    }
    else
    {
	XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
	if (mnemonic != '\0')
	{
	    mneString[0] = mnemonic;
	    mneString[1] = '\0';
	    if (XKeysymToKeycode(XtDisplay(XtParent(w)),
				       XStringToKeysym(mneString)) == keycode)
	    {
		if (XtClass(w) == xmLabelWidgetClass
			|| XtClass(w) == xmLabelGadgetClass)
		{
		    XtVaGetValues(w, XmNuserData, &userData, NULL);
		    if (userData != NULL && XtIsWidget(userData))
			XmProcessTraversal(userData, XmTRAVERSE_CURRENT);
		}
		else
		{
		    XKeyPressedEvent keyEvent;

		    XmProcessTraversal(w, XmTRAVERSE_CURRENT);

		    vim_memset((char *) &keyEvent, 0, sizeof(XKeyPressedEvent));
		    keyEvent.type = KeyPress;
		    keyEvent.serial = 1;
		    keyEvent.send_event = True;
		    keyEvent.display = XtDisplay(w);
		    keyEvent.window = XtWindow(w);
		    XtCallActionProc(w, "Activate", (XEvent *) & keyEvent,
								     NULL, 0);
		}
	    }
	}
    }
}

/*
 * Callback routine for dialog mnemonic processing.
 */
    static void
mnemonic_event(Widget w, XtPointer call_data UNUSED, XKeyEvent *event)
{
    do_mnemonic(w, event->keycode);
}


/*
 * Search the widget tree under w for widgets with mnemonics.  When found, add
 * a passive grab to the dialog widget for the mnemonic character, thus
 * directing mnemonic events to the dialog widget.
 */
    static void
add_mnemonic_grabs(Widget dialog, Widget w)
{
    char	    mneString[2];
    WidgetList	    children;
    int		    numChildren, i;
    Boolean	    isMenu;
    KeySym	    mnemonic = '\0';
    unsigned char   rowColType;

    if (XtIsComposite(w))
    {
	if (XtClass(w) == xmRowColumnWidgetClass)
	{
	    XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL);
	    isMenu = (rowColType != (unsigned char)XmWORK_AREA);
	}
	else
	    isMenu = False;
	if (!isMenu)
	{
	    XtVaGetValues(w, XmNchildren, &children, XmNnumChildren,
							  &numChildren, NULL);
	    for (i = 0; i < numChildren; i++)
		add_mnemonic_grabs(dialog, children[i]);
	}
    }
    else
    {
	XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL);
	if (mnemonic != '\0')
	{
	    mneString[0] = mnemonic;
	    mneString[1] = '\0';
	    XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog),
						  XStringToKeysym(mneString)),
		    Mod1Mask, True, GrabModeAsync, GrabModeAsync);
	}
    }
}

/*
 * Add a handler for mnemonics in a dialog.  Motif itself only handles
 * mnemonics in menus. Mnemonics added or changed after this call will be
 * ignored.
 *
 * To add a mnemonic to a text field or list, set the XmNmnemonic resource on
 * the appropriate label and set the XmNuserData resource of the label to the
 * widget to get the focus when the mnemonic is typed.
 */
    static void
activate_dialog_mnemonics(Widget dialog)
{
    if (!dialog)
	return;

    XtAddEventHandler(dialog, KeyPressMask, False,
			   (XtEventHandler) mnemonic_event, (XtPointer) NULL);
    add_mnemonic_grabs(dialog, dialog);
}

/*
 * Removes the event handler and key-grabs for dialog mnemonic handling.
 */
    static void
suppress_dialog_mnemonics(Widget dialog)
{
    if (!dialog)
	return;

    XtUngrabKey(dialog, AnyKey, Mod1Mask);
    XtRemoveEventHandler(dialog, KeyPressMask, False,
			   (XtEventHandler) mnemonic_event, (XtPointer) NULL);
}

#if defined(FEAT_BROWSE) || defined(FEAT_GUI_DIALOG)
static void set_fontlist __ARGS((Widget wg));

/*
 * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget.
 */
    static void
set_fontlist(id)
    Widget id;
{
    XmFontList fl;

#ifdef FONTSET_ALWAYS
    if (gui.fontset != NOFONTSET)
    {
	fl = gui_motif_fontset2fontlist((XFontSet *)&gui.fontset);
	if (fl != NULL)
	{
	    if (XtIsManaged(id))
	    {
		XtUnmanageChild(id);
		XtVaSetValues(id, XmNfontList, fl, NULL);
		/* We should force the widget to recalculate it's
		 * geometry now. */
		XtManageChild(id);
	    }
	    else
		XtVaSetValues(id, XmNfontList, fl, NULL);
	    XmFontListFree(fl);
	}
    }
#else
    if (gui.norm_font != NOFONT)
    {
	fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_font);
	if (fl != NULL)
	{
	    if (XtIsManaged(id))
	    {
		XtUnmanageChild(id);
		XtVaSetValues(id, XmNfontList, fl, NULL);
		/* We should force the widget to recalculate it's
		 * geometry now. */
		XtManageChild(id);
	    }
	    else
		XtVaSetValues(id, XmNfontList, fl, NULL);
	    XmFontListFree(fl);
	}
    }
#endif
}
#endif

#if defined(FEAT_BROWSE) || defined(PROTO)

/*
 * file selector related stuff
 */

#include <Xm/FileSB.h>
#include <Xm/XmStrDefs.h>

typedef struct dialog_callback_arg
{
    char *  args;   /* not used right now */
    int	    id;
} dcbarg_T;

static Widget dialog_wgt;
static char *browse_fname = NULL;
static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET;
				/* used to set up XmStrings */

static void DialogCancelCB __ARGS((Widget, XtPointer, XtPointer));
static void DialogAcceptCB __ARGS((Widget, XtPointer, XtPointer));

/*
 * This function is used to translate the predefined label text of the
 * precomposed dialogs. We do this explicitly to allow:
 *
 * - usage of gettext for translation, as in all the other places.
 *
 * - equalize the messages between different GUI implementations as far as
 * possible.
 */
static void set_predefined_label __ARGS((Widget parent, String name, char *new_label));

static void
set_predefined_label(parent, name, new_label)
    Widget  parent;
    String  name;
    char    *new_label;
{
    XmString	str;
    Widget	w;
    char_u	*p, *next;
    KeySym	mnemonic = NUL;

    w = XtNameToWidget(parent, name);

    if (!w)
	return;

    p = vim_strsave((char_u *)new_label);
    if (p == NULL)
	return;
    for (next = p; *next; ++next)
    {
	if (*next == DLG_HOTKEY_CHAR)
	{
	    int len = STRLEN(next);

	    if (len > 0)
	    {
		mch_memmove(next, next + 1, len);
		mnemonic = next[0];
	    }
	}
    }

    str = XmStringCreate((char *)p, STRING_TAG);
    vim_free(p);

    if (str != NULL)
    {
	XtVaSetValues(w,
		XmNlabelString, str,
		XmNmnemonic, mnemonic,
		NULL);
	XmStringFree(str);
    }
    gui_motif_menu_fontlist(w);
}

static void
set_predefined_fontlist(parent, name)
    Widget parent;
    String name;
{
    Widget w;
    w = XtNameToWidget(parent, name);

    if (!w)
	return;

    set_fontlist(w);
}

/*
 * Put up a file requester.
 * Returns the selected name in allocated memory, or NULL for Cancel.
 */
    char_u *
gui_mch_browse(saving, title, dflt, ext, initdir, filter)
    int		saving UNUSED;	/* select file to write */
    char_u	*title;		/* title for the window */
    char_u	*dflt;		/* default name */
    char_u	*ext UNUSED;	/* not used (extension added) */
    char_u	*initdir;	/* initial directory, NULL for current dir */
    char_u	*filter;	/* file name filter */
{
    char_u	dirbuf[MAXPATHL];
    char_u	dfltbuf[MAXPATHL];
    char_u	*pattern;
    char_u	*tofree = NULL;

    /* There a difference between the resource name and value, Therefore, we
     * avoid to (ab-)use the (maybe internationalized!) dialog title as a
     * dialog name.
     */

    dialog_wgt = XmCreateFileSelectionDialog(vimShell, "browseDialog", NULL, 0);

    if (initdir == NULL || *initdir == NUL)
    {
	mch_dirname(dirbuf, MAXPATHL);
	initdir = dirbuf;
    }

    if (dflt == NULL)
	dflt = (char_u *)"";
    else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL)
    {
	/* The default selection should be the full path, "dflt" is only the
	 * file name. */
	STRCPY(dfltbuf, initdir);
	add_pathsep(dfltbuf);
	STRCAT(dfltbuf, dflt);
	dflt = dfltbuf;
    }

    /* Can only use one pattern for a file name.  Get the first pattern out of
     * the filter.  An empty pattern means everything matches. */
    if (filter == NULL)
	pattern = (char_u *)"";
    else
    {
	char_u	*s, *p;

	s = filter;
	for (p = filter; *p != NUL; ++p)
	{
	    if (*p == '\t')	/* end of description, start of pattern */
		s = p + 1;
	    if (*p == ';' || *p == '\n')	/* end of (first) pattern */
		break;
	}
	pattern = vim_strnsave(s, p - s);
	tofree = pattern;
	if (pattern == NULL)
	    pattern = (char_u *)"";
    }

    XtVaSetValues(dialog_wgt,
	XtVaTypedArg,
	    XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1,
	XtVaTypedArg,
	    XmNdirSpec,	XmRString, (char *)dflt, STRLEN(dflt) + 1,
	XtVaTypedArg,
	    XmNpattern,	XmRString, (char *)pattern, STRLEN(pattern) + 1,
	XtVaTypedArg,
	    XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1,
	NULL);

    set_predefined_label(dialog_wgt, "Apply", _("&Filter"));
    set_predefined_label(dialog_wgt, "Cancel", _("&Cancel"));
    set_predefined_label(dialog_wgt, "Dir", _("Directories"));
    set_predefined_label(dialog_wgt, "FilterLabel", _("Filter"));
    set_predefined_label(dialog_wgt, "Help", _("&Help"));
    set_predefined_label(dialog_wgt, "Items", _("Files"));
    set_predefined_label(dialog_wgt, "OK", _("&OK"));
    set_predefined_label(dialog_wgt, "Selection", _("Selection"));

    /* This is to save us from silly external settings using not fixed with
     * fonts for file selection.
     */
    set_predefined_fontlist(dialog_wgt, "DirListSW.DirList");
    set_predefined_fontlist(dialog_wgt, "ItemsListSW.ItemsList");

    gui_motif_menu_colors(dialog_wgt);
    if (gui.scroll_bg_pixel != INVALCOLOR)
	XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL);

    XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0);
    XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0);
    /* We have no help in this window, so hide help button */
    XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt,
					(unsigned char)XmDIALOG_HELP_BUTTON));

    manage_centered(dialog_wgt);
    activate_dialog_mnemonics(dialog_wgt);

    /* sit in a loop until the dialog box has gone away */
    do
    {
	XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt),
	    (XtInputMask)XtIMAll);
    } while (XtIsManaged(dialog_wgt));

    suppress_dialog_mnemonics(dialog_wgt);
    XtDestroyWidget(dialog_wgt);
    vim_free(tofree);

    if (browse_fname == NULL)
	return NULL;
    return vim_strsave((char_u *)browse_fname);
}

/*
 * The code below was originally taken from
 *	/usr/examples/motif/xmsamplers/xmeditor.c
 * on Digital Unix 4.0d, but heavily modified.
 */

/*
 * Process callback from Dialog cancel actions.
 */
    static void
DialogCancelCB(w, client_data, call_data)
    Widget	w UNUSED;		/*  widget id		*/
    XtPointer	client_data UNUSED;	/*  data from application   */
    XtPointer	call_data UNUSED;	/*  data from widget class  */
{
    if (browse_fname != NULL)
    {
	XtFree(browse_fname);
	browse_fname = NULL;
    }
    XtUnmanageChild(dialog_wgt);
}

/*
 * Process callback from Dialog actions.
 */
    static void
DialogAcceptCB(w, client_data, call_data)
    Widget	w UNUSED;		/*  widget id		*/
    XtPointer	client_data UNUSED;	/*  data from application   */
    XtPointer	call_data;		/*  data from widget class  */
{
    XmFileSelectionBoxCallbackStruct *fcb;

    if (browse_fname != NULL)
    {
	XtFree(browse_fname);
	browse_fname = NULL;
    }
    fcb = (XmFileSelectionBoxCallbackStruct *)call_data;

    /* get the filename from the file selection box */
    XmStringGetLtoR(fcb->value, charset, &browse_fname);

    /* popdown the file selection box */
    XtUnmanageChild(dialog_wgt);
}

#endif /* FEAT_BROWSE */

#if defined(FEAT_GUI_DIALOG) || defined(PROTO)

static int	dialogStatus;

static void keyhit_callback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
static void butproc __ARGS((Widget w, XtPointer client_data, XtPointer call_data));

/*
 * Callback function for the textfield.  When CR is hit this works like
 * hitting the "OK" button, ESC like "Cancel".
 */
    static void
keyhit_callback(w, client_data, event, cont)
    Widget		w;
    XtPointer		client_data UNUSED;
    XEvent		*event;
    Boolean		*cont UNUSED;
{
    char	buf[2];
    KeySym	key_sym;

    if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1)
    {
	if (*buf == CAR)
	    dialogStatus = 1;
	else if (*buf == ESC)
	    dialogStatus = 2;
    }
    if ((key_sym == XK_Left || key_sym == XK_Right)
	    && !(event->xkey.state & ShiftMask))
	XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy));
}

    static void
butproc(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data;
    XtPointer	call_data UNUSED;
{
    dialogStatus = (int)(long)client_data + 1;
}

#ifdef HAVE_XPM

static Widget create_pixmap_label(Widget parent, String name, char **data, ArgList args, Cardinal arg);

    static Widget
create_pixmap_label(parent, name, data, args, arg)
    Widget	parent;
    String	name;
    char	**data;
    ArgList	args;
    Cardinal	arg;
{
    Widget		label;
    Display		*dsp;
    Screen		*scr;
    int			depth;
    Pixmap		pixmap = 0;
    XpmAttributes	attr;
    Boolean		rs;
    XpmColorSymbol	color[5] =
    {
	{"none", NULL, 0},
	{"iconColor1", NULL, 0},
	{"bottomShadowColor", NULL, 0},
	{"topShadowColor", NULL, 0},
	{"selectColor", NULL, 0}
    };

    label = XmCreateLabelGadget(parent, name, args, arg);

    /*
     * We need to be careful here, since in case of gadgets, there is
     * no way to get the background color directly from the widget itself.
     * In such cases we get it from The Core part of his parent instead.
     */
    dsp = XtDisplayOfObject(label);
    scr = XtScreenOfObject(label);
    XtVaGetValues(XtIsSubclass(label, coreWidgetClass)
	    ?  label : XtParent(label),
		  XmNdepth, &depth,
		  XmNbackground, &color[0].pixel,
		  XmNforeground, &color[1].pixel,
		  XmNbottomShadowColor, &color[2].pixel,
		  XmNtopShadowColor, &color[3].pixel,
		  XmNhighlight, &color[4].pixel,
		  NULL);

    attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth;
    attr.colorsymbols = color;
    attr.numsymbols = 5;
    attr.closeness = 65535;
    attr.depth = depth;
    XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr),
		    data, &pixmap, NULL, &attr);

    XtVaGetValues(label, XmNrecomputeSize, &rs, NULL);
    XtVaSetValues(label, XmNrecomputeSize, True, NULL);
    XtVaSetValues(label,
	    XmNlabelType, XmPIXMAP,
	    XmNlabelPixmap, pixmap,
	    NULL);
    XtVaSetValues(label, XmNrecomputeSize, rs, NULL);

    return label;
}
#endif

    int
gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield)
    int		type UNUSED;
    char_u	*title;
    char_u	*message;
    char_u	*button_names;
    int		dfltbutton;
    char_u	*textfield;		/* buffer of size IOSIZE */
{
    char_u		*buts;
    char_u		*p, *next;
    XtAppContext	app;
    XmString		label;
    int			butcount;
    Widget		w;
    Widget		dialogform = NULL;
    Widget		form = NULL;
    Widget		dialogtextfield = NULL;
    Widget		*buttons;
    Widget		sep_form = NULL;
    Boolean		vertical;
    Widget		separator = NULL;
    int			n;
    Arg			args[6];
#ifdef HAVE_XPM
    char		**icon_data = NULL;
    Widget		dialogpixmap = NULL;
#endif

    if (title == NULL)
	title = (char_u *)_("Vim dialog");

    /* if our pointer is currently hidden, then we should show it. */
    gui_mch_mousehide(FALSE);

    dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0);

    /* Check 'v' flag in 'guioptions': vertical button placement. */
    vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);

    /* Set the title of the Dialog window */
    label = XmStringCreateSimple((char *)title);
    if (label == NULL)
	return -1;
    XtVaSetValues(dialogform,
	    XmNdialogTitle, label,
	    XmNhorizontalSpacing, 4,
	    XmNverticalSpacing, vertical ? 0 : 4,
	    NULL);
    XmStringFree(label);

    /* make a copy, so that we can insert NULs */
    buts = vim_strsave(button_names);
    if (buts == NULL)
	return -1;

    /* Count the number of buttons and allocate buttons[]. */
    butcount = 1;
    for (p = buts; *p; ++p)
	if (*p == DLG_BUTTON_SEP)
	    ++butcount;
    buttons = (Widget *)alloc((unsigned)(butcount * sizeof(Widget)));
    if (buttons == NULL)
    {
	vim_free(buts);
	return -1;
    }

    /*
     * Create the buttons.
     */
    sep_form = (Widget) 0;
    p = buts;
    for (butcount = 0; *p; ++butcount)
    {
	KeySym mnemonic = NUL;

	for (next = p; *next; ++next)
	{
	    if (*next == DLG_HOTKEY_CHAR)
	    {
		int len = STRLEN(next);

		if (len > 0)
		{
		    mch_memmove(next, next + 1, len);
		    mnemonic = next[0];
		}
	    }
	    if (*next == DLG_BUTTON_SEP)
	    {
		*next++ = NUL;
		break;
	    }
	}
	label = XmStringCreate(_((char *)p), STRING_TAG);
	if (label == NULL)
	    break;

	buttons[butcount] = XtVaCreateManagedWidget("button",
		xmPushButtonWidgetClass, dialogform,
		XmNlabelString, label,
		XmNmnemonic, mnemonic,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNbottomOffset, 4,
		XmNshowAsDefault, butcount == dfltbutton - 1,
		XmNdefaultButtonShadowThickness, 1,
		NULL);
	XmStringFree(label);
	gui_motif_menu_fontlist(buttons[butcount]);

	/* Layout properly. */

	if (butcount > 0)
	{
	    if (vertical)
		XtVaSetValues(buttons[butcount],
			XmNtopWidget, buttons[butcount - 1],
			NULL);
	    else
	    {
		if (*next == NUL)
		{
		    XtVaSetValues(buttons[butcount],
			    XmNrightAttachment, XmATTACH_FORM,
			    XmNrightOffset, 4,
			    NULL);

		    /* fill in a form as invisible separator */
		    sep_form = XtVaCreateWidget("separatorForm",
			    xmFormWidgetClass,	dialogform,
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, buttons[butcount - 1],
			    XmNrightAttachment, XmATTACH_WIDGET,
			    XmNrightWidget, buttons[butcount],
			    XmNbottomAttachment, XmATTACH_FORM,
			    XmNbottomOffset, 4,
			    NULL);
		    XtManageChild(sep_form);
		}
		else
		{
		    XtVaSetValues(buttons[butcount],
			    XmNleftAttachment, XmATTACH_WIDGET,
			    XmNleftWidget, buttons[butcount - 1],
			    NULL);
		}
	    }
	}
	else if (!vertical)
	{
	    if (*next == NUL)
	    {
		XtVaSetValues(buttons[0],
			XmNrightAttachment, XmATTACH_FORM,
			XmNrightOffset, 4,
			NULL);

		/* fill in a form as invisible separator */
		sep_form = XtVaCreateWidget("separatorForm",
			xmFormWidgetClass, dialogform,
			XmNleftAttachment, XmATTACH_FORM,
			XmNleftOffset, 4,
			XmNrightAttachment, XmATTACH_WIDGET,
			XmNrightWidget, buttons[0],
			XmNbottomAttachment, XmATTACH_FORM,
			XmNbottomOffset, 4,
			NULL);
		XtManageChild(sep_form);
	    }
	    else
		XtVaSetValues(buttons[0],
			XmNleftAttachment, XmATTACH_FORM,
			XmNleftOffset, 4,
			NULL);
	}

	XtAddCallback(buttons[butcount], XmNactivateCallback,
			  (XtCallbackProc)butproc, (XtPointer)(long)butcount);
	p = next;
    }
    vim_free(buts);

    separator = (Widget) 0;
    if (butcount > 0)
    {
	/* Create the separator for beauty. */
	n = 0;
	XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++;
	XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
	XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++;
	XtSetArg(args[n], XmNbottomOffset, 4); n++;
	XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
	XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
	separator = XmCreateSeparatorGadget(dialogform, "separator", args, n);
	XtManageChild(separator);
    }

    if (textfield != NULL)
    {
	dialogtextfield = XtVaCreateWidget("textField",
		xmTextFieldWidgetClass, dialogform,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	if (butcount > 0)
	    XtVaSetValues(dialogtextfield,
		    XmNbottomAttachment, XmATTACH_WIDGET,
		    XmNbottomWidget, separator,
		    NULL);
	else
	    XtVaSetValues(dialogtextfield,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);

	set_fontlist(dialogtextfield);
	XmTextFieldSetString(dialogtextfield, (char *)textfield);
	XtManageChild(dialogtextfield);
	XtAddEventHandler(dialogtextfield, KeyPressMask, False,
			    (XtEventHandler)keyhit_callback, (XtPointer)NULL);
    }

    /* Form holding both message and pixmap labels */
    form = XtVaCreateWidget("separatorForm",
	    xmFormWidgetClass, dialogform,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNrightAttachment, XmATTACH_FORM,
	    XmNtopAttachment, XmATTACH_FORM,
	    NULL);
    XtManageChild(form);

#ifdef HAVE_XPM
    /* Add a pixmap, left of the message. */
    switch (type)
    {
	case VIM_GENERIC:
	    icon_data = generic_xpm;
	    break;
	case VIM_ERROR:
	    icon_data = error_xpm;
	    break;
	case VIM_WARNING:
	    icon_data = alert_xpm;
	    break;
	case VIM_INFO:
	    icon_data = info_xpm;
	    break;
	case VIM_QUESTION:
	    icon_data = quest_xpm;
	    break;
	default:
	    icon_data = generic_xpm;
    }

    n = 0;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNtopOffset, 8); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomOffset, 8); n++;
    XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNleftOffset, 8); n++;

    dialogpixmap = create_pixmap_label(form, "dialogPixmap",
	    icon_data, args, n);
    XtManageChild(dialogpixmap);
#endif

    /* Create the dialog message.
     * Since LessTif is apparently having problems with the creation of
     * properly localized string, we use LtoR here. The symptom is that the
     * string sill not show properly in multiple lines as it does in native
     * Motif.
     */
    label = XmStringCreateLtoR((char *)message, STRING_TAG);
    if (label == NULL)
	return -1;
    w = XtVaCreateManagedWidget("dialogMessage",
				xmLabelGadgetClass, form,
				XmNlabelString, label,
				XmNalignment, XmALIGNMENT_BEGINNING,
				XmNtopAttachment, XmATTACH_FORM,
				XmNtopOffset, 8,
#ifdef HAVE_XPM
				XmNleftAttachment, XmATTACH_WIDGET,
				XmNleftWidget, dialogpixmap,
#else
				XmNleftAttachment, XmATTACH_FORM,
#endif
				XmNleftOffset, 8,
				XmNrightAttachment, XmATTACH_FORM,
				XmNrightOffset, 8,
				XmNbottomAttachment, XmATTACH_FORM,
				XmNbottomOffset, 8,
				NULL);
    XmStringFree(label);
    set_fontlist(w);

    if (textfield != NULL)
    {
	XtVaSetValues(form,
		XmNbottomAttachment, XmATTACH_WIDGET,
		XmNbottomWidget, dialogtextfield,
		NULL);
    }
    else
    {
	if (butcount > 0)
	    XtVaSetValues(form,
		    XmNbottomAttachment, XmATTACH_WIDGET,
		    XmNbottomWidget, separator,
		    NULL);
	else
	    XtVaSetValues(form,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);
    }

    if (dfltbutton < 1)
	dfltbutton = 1;
    if (dfltbutton > butcount)
	dfltbutton = butcount;
    XtVaSetValues(dialogform,
	    XmNdefaultButton, buttons[dfltbutton - 1], NULL);
    if (textfield != NULL)
	XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL);
    else
	XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1],
									NULL);

    manage_centered(dialogform);
    activate_dialog_mnemonics(dialogform);

    if (textfield != NULL && *textfield != NUL)
    {
	/* This only works after the textfield has been realised. */
	XmTextFieldSetSelection(dialogtextfield,
			 (XmTextPosition)0, (XmTextPosition)STRLEN(textfield),
					   XtLastTimestampProcessed(gui.dpy));
	XmTextFieldSetCursorPosition(dialogtextfield,
					   (XmTextPosition)STRLEN(textfield));
    }

    app = XtWidgetToApplicationContext(dialogform);

    /* Loop until a button is pressed or the dialog is killed somehow. */
    dialogStatus = -1;
    for (;;)
    {
	XtAppProcessEvent(app, (XtInputMask)XtIMAll);
	if (dialogStatus >= 0 || !XtIsManaged(dialogform))
	    break;
    }

    vim_free(buttons);

    if (textfield != NULL)
    {
	p = (char_u *)XmTextGetString(dialogtextfield);
	if (p == NULL || dialogStatus < 0)
	    *textfield = NUL;
	else
	    vim_strncpy(textfield, p, IOSIZE - 1);
	XtFree((char *)p);
    }

    suppress_dialog_mnemonics(dialogform);
    XtDestroyWidget(dialogform);

    return dialogStatus;
}
#endif /* FEAT_GUI_DIALOG */

#if defined(FEAT_FOOTER) || defined(PROTO)

    static int
gui_mch_compute_footer_height()
{
    Dimension	height;		    /* total Toolbar height */
    Dimension	top;		    /* XmNmarginTop */
    Dimension	bottom;		    /* XmNmarginBottom */
    Dimension	shadow;		    /* XmNshadowThickness */

    XtVaGetValues(footer,
	    XmNheight, &height,
	    XmNmarginTop, &top,
	    XmNmarginBottom, &bottom,
	    XmNshadowThickness, &shadow,
	    NULL);

    return (int) height + top + bottom + (shadow << 1);
}

#if 0	    /* not used */
    void
gui_mch_set_footer_pos(h)
    int	    h;			    /* textArea height */
{
    XtVaSetValues(footer,
		  XmNtopOffset, h + 7,
		  NULL);
}
#endif

    void
gui_mch_enable_footer(showit)
    int		showit;
{
    if (showit)
    {
	gui.footer_height = gui_mch_compute_footer_height();
	XtManageChild(footer);
    }
    else
    {
	gui.footer_height = 0;
	XtUnmanageChild(footer);
    }
    XtVaSetValues(textAreaForm, XmNbottomOffset, gui.footer_height, NULL);
}

    void
gui_mch_set_footer(s)
    char_u	*s;
{
    XmString	xms;

    xms = XmStringCreate((char *)s, STRING_TAG);
    if (xms != NULL)
    {
	XtVaSetValues(footer, XmNlabelString, xms, NULL);
	XmStringFree(xms);
    }
}

#endif


#if defined(FEAT_TOOLBAR) || defined(PROTO)
    void
gui_mch_show_toolbar(int showit)
{
    Cardinal	numChildren;	    /* how many children toolBar has */

    if (toolBar == (Widget)0)
	return;
    XtVaGetValues(toolBar, XmNnumChildren, &numChildren, NULL);
    if (showit && numChildren > 0)
    {
	/* Assume that we want to show the toolbar if p_toolbar contains
	 * valid option settings, therefore p_toolbar must not be NULL.
	 */
	WidgetList  children;

	XtVaGetValues(toolBar, XmNchildren, &children, NULL);
	{
	    void    (*action)(BalloonEval *);
	    int	    text = 0;

	    if (strstr((const char *)p_toolbar, "tooltips"))
		action = &gui_mch_enable_beval_area;
	    else
		action = &gui_mch_disable_beval_area;
	    if (strstr((const char *)p_toolbar, "text"))
		text = 1;
	    else if (strstr((const char *)p_toolbar, "icons"))
		text = -1;
	    if (text != 0)
	    {
		vimmenu_T   *toolbar;
		vimmenu_T   *cur;

		for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
		    if (menu_is_toolbar(toolbar->dname))
			break;
		/* Assumption: toolbar is NULL if there is no toolbar,
		 *	       otherwise it contains the toolbar menu structure.
		 *
		 * Assumption: "numChildren" == the number of items in the list
		 *	       of items beginning with toolbar->children.
		 */
		if (toolbar)
		{
		    for (cur = toolbar->children; cur; cur = cur->next)
		    {
			Arg	    args[1];
			int	    n = 0;

			/* Enable/Disable tooltip (OK to enable while
			 * currently enabled). */
			if (cur->tip != NULL)
			    (*action)(cur->tip);
			if (!menu_is_separator(cur->name))
			{
			    if (text == 1 || cur->xpm == NULL)
			    {
				XtSetArg(args[n], XmNlabelType, XmSTRING);
				++n;
			    }
			    if (cur->id != NULL)
			    {
				XtUnmanageChild(cur->id);
				XtSetValues(cur->id, args, n);
				XtManageChild(cur->id);
			    }
			}
		    }
		}
	    }
	}
	gui.toolbar_height = gui_mch_compute_toolbar_height();
	XtManageChild(XtParent(toolBar));
#ifdef FEAT_GUI_TABLINE
	if (showing_tabline)
	{
	    XtVaSetValues(tabLine,
			  XmNtopAttachment, XmATTACH_WIDGET,
			  XmNtopWidget, XtParent(toolBar),
			  NULL);
	    XtVaSetValues(textAreaForm,
			  XmNtopAttachment, XmATTACH_WIDGET,
			  XmNtopWidget, tabLine,
			  NULL);
	}
	else
#endif
	    XtVaSetValues(textAreaForm,
			  XmNtopAttachment, XmATTACH_WIDGET,
			  XmNtopWidget, XtParent(toolBar),
			  NULL);
	if (XtIsManaged(menuBar))
	    XtVaSetValues(XtParent(toolBar),
		    XmNtopAttachment, XmATTACH_WIDGET,
		    XmNtopWidget, menuBar,
		    NULL);
	else
	    XtVaSetValues(XtParent(toolBar),
		    XmNtopAttachment, XmATTACH_FORM,
		    NULL);
    }
    else
    {
	gui.toolbar_height = 0;
	if (XtIsManaged(menuBar))
	{
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar,
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar,
			      NULL);
	}
	else
	{
#ifdef FEAT_GUI_TABLINE
	    if (showing_tabline)
	    {
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_FORM,
			      NULL);
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, tabLine,
			      NULL);
	    }
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_FORM,
			      NULL);
	}

	XtUnmanageChild(XtParent(toolBar));
    }
    gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
}

/*
 * A toolbar button has been pushed; now reset the input focus
 * such that the user can type page up/down etc. and have the
 * input go to the editor window, not the button
 */
    static void
reset_focus()
{
    if (textArea != NULL)
	XmProcessTraversal(textArea, XmTRAVERSE_CURRENT);
}

    int
gui_mch_compute_toolbar_height()
{
    Dimension	borders;
    Dimension	height;		    /* total Toolbar height */
    Dimension	whgt;		    /* height of each widget */
    WidgetList	children;	    /* list of toolBar's children */
    Cardinal	numChildren;	    /* how many children toolBar has */
    int		i;

    borders = 0;
    height = 0;
    if (toolBar != (Widget)0 && toolBarFrame != (Widget)0)
    {				    /* get height of XmFrame parent */
	Dimension	fst;
	Dimension	fmh;
	Dimension	tst;
	Dimension	tmh;

	XtVaGetValues(toolBarFrame,
		XmNshadowThickness, &fst,
		XmNmarginHeight, &fmh,
		NULL);
	borders += fst + fmh;
	XtVaGetValues(toolBar,
		XmNshadowThickness, &tst,
		XmNmarginHeight, &tmh,
		XmNchildren, &children,
		XmNnumChildren, &numChildren, NULL);
	borders += tst + tmh;
	for (i = 0; i < (int)numChildren; i++)
	{
	    whgt = 0;
	    XtVaGetValues(children[i], XmNheight, &whgt, NULL);
	    if (height < whgt)
		height = whgt;
	}
    }
#ifdef LESSTIF_VERSION
    /* Hack: When starting up we get wrong dimensions. */
    if (height < 10)
	height = 24;
#endif

    return (int)(height + (borders << 1));
}

    void
motif_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp)
    Pixel       *bgp;
    Pixel       *fgp;
    Pixel       *bsp;
    Pixel       *tsp;
    Pixel       *hsp;
{
    XtVaGetValues(toolBar,
	    XmNbackground, bgp,
	    XmNforeground, fgp,
	    XmNbottomShadowColor, bsp,
	    XmNtopShadowColor, tsp,
	    XmNhighlightColor, hsp,
	    NULL);
}

# ifdef FEAT_FOOTER
/*
 * The next toolbar enter/leave callbacks should really do balloon help.  But
 * I have to use footer help for backwards compatability.  Hopefully both will
 * get implemented and the user will have a choice.
 */
    static void
toolbarbutton_enter_cb(w, client_data, event, cont)
    Widget	w UNUSED;
    XtPointer	client_data;
    XEvent	*event UNUSED;
    Boolean	*cont UNUSED;
{
    vimmenu_T	*menu = (vimmenu_T *) client_data;

    if (menu->strings[MENU_INDEX_TIP] != NULL)
    {
	if (vim_strchr(p_go, GO_FOOTER) != NULL)
	    gui_mch_set_footer(menu->strings[MENU_INDEX_TIP]);
    }
}

    static void
toolbarbutton_leave_cb(w, client_data, event, cont)
    Widget	w UNUSED;
    XtPointer	client_data UNUSED;
    XEvent	*event UNUSED;
    Boolean	*cont UNUSED;
{
    gui_mch_set_footer((char_u *) "");
}
# endif
#endif

#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
/*
 * Show or hide the tabline.
 */
    void
gui_mch_show_tabline(int showit)
{
    if (tabLine == (Widget)0)
	return;

    if (!showit != !showing_tabline)
    {
	if (showit)
	{
	    XtManageChild(tabLine);
	    XtUnmanageChild(XtNameToWidget(tabLine, "PageScroller"));
	    XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerNext"));
	    XtUnmanageChild(XtNameToWidget(tabLine,
					   "MinorTabScrollerPrevious"));
#ifdef FEAT_MENU
# ifdef FEAT_TOOLBAR
	    if (XtIsManaged(XtParent(toolBar)))
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar), NULL);
	    else
# endif
		if (XtIsManaged(menuBar))
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar, NULL);
	    else
#endif
		XtVaSetValues(tabLine,
			      XmNtopAttachment, XmATTACH_FORM, NULL);
	    XtVaSetValues(textAreaForm,
			  XmNtopAttachment, XmATTACH_WIDGET,
			  XmNtopWidget, tabLine,
			  NULL);
	}
	else
	{
	    XtUnmanageChild(tabLine);
#ifdef FEAT_MENU
# ifdef FEAT_TOOLBAR
	    if (XtIsManaged(XtParent(toolBar)))
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, XtParent(toolBar), NULL);
	    else
# endif
		if (XtIsManaged(menuBar))
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_WIDGET,
			      XmNtopWidget, menuBar, NULL);
	    else
#endif
		XtVaSetValues(textAreaForm,
			      XmNtopAttachment, XmATTACH_FORM, NULL);
	}
	showing_tabline = showit;
    }
}

/*
 * Return TRUE when tabline is displayed.
 */
    int
gui_mch_showing_tabline(void)
{
    return tabLine != (Widget)0 && showing_tabline;
}

/*
 * Update the labels of the tabline.
 */
    void
gui_mch_update_tabline(void)
{
    tabpage_T		*tp;
    int			nr = 1, n;
    Arg			args[10];
    int			curtabidx = 0, currentpage;
    Widget		tab;
    XmNotebookPageInfo	page_info;
    XmNotebookPageStatus page_status;
    int			last_page, tab_count;
    XmString		label_str;
    char		*label_cstr;
    BalloonEval		*beval;

    if (tabLine == (Widget)0)
	return;

    /* Add a label for each tab page.  They all contain the same text area. */
    for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
    {
	if (tp == curtab)
	    curtabidx = nr;

	page_status = XmNotebookGetPageInfo(tabLine, nr, &page_info);
	if (page_status == XmPAGE_INVALID
		|| page_info.major_tab_widget == (Widget)0)
	{
	    /* Add the tab */
	    n = 0;
	    XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++;
	    XtSetArg(args[n], XmNtraversalOn, False); n++;
	    XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
	    XtSetArg(args[n], XmNhighlightThickness, 1); n++;
	    XtSetArg(args[n], XmNshadowThickness , 1); n++;
	    tab = XmCreatePushButton(tabLine, "-Empty-", args, n);
	    XtManageChild(tab);
	    beval = gui_mch_create_beval_area(tab, NULL, tabline_balloon_cb,
									NULL);
	    XtVaSetValues(tab, XmNuserData, beval, NULL);
	}
	else
	    tab = page_info.major_tab_widget;

	XtVaSetValues(tab, XmNpageNumber, nr, NULL);

	/*
	 * Change the label text only if it is different
	 */
	XtVaGetValues(tab, XmNlabelString, &label_str, NULL);
	if (XmStringGetLtoR(label_str, XmSTRING_DEFAULT_CHARSET, &label_cstr))
	{
	    get_tabline_label(tp, FALSE);
	    if (STRCMP(label_cstr, NameBuff) != 0)
	    {
		XtVaSetValues(tab, XtVaTypedArg, XmNlabelString, XmRString,
			      NameBuff, STRLEN(NameBuff) + 1, NULL);
		/*
		 * Force a resize of the tab label button
		 */
		XtUnmanageChild(tab);
		XtManageChild(tab);
	    }
	    XtFree(label_cstr);
	}
    }

    tab_count = nr - 1;

    XtVaGetValues(tabLine, XmNlastPageNumber, &last_page, NULL);

    /* Remove any old labels. */
    while (nr <= last_page)
    {
	if (XmNotebookGetPageInfo(tabLine, nr, &page_info) != XmPAGE_INVALID
	    && page_info.page_number == nr
	    && page_info.major_tab_widget != (Widget)0)
	{
	    XtVaGetValues(page_info.major_tab_widget, XmNuserData, &beval, NULL);
	    if (beval != NULL)
		gui_mch_destroy_beval_area(beval);
	    XtUnmanageChild(page_info.major_tab_widget);
	    XtDestroyWidget(page_info.major_tab_widget);
	}
	nr++;
    }

    XtVaSetValues(tabLine, XmNlastPageNumber, tab_count, NULL);

    XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
    if (currentpage != curtabidx)
	XtVaSetValues(tabLine, XmNcurrentPageNumber, curtabidx, NULL);
}

/*
 * Set the current tab to "nr".  First tab is 1.
 */
    void
gui_mch_set_curtab(nr)
    int		nr;
{
    int		currentpage;

    if (tabLine == (Widget)0)
	return;

    XtVaGetValues(tabLine, XmNcurrentPageNumber, &currentpage, NULL);
    if (currentpage != nr)
	XtVaSetValues(tabLine, XmNcurrentPageNumber, nr, NULL);
}
#endif

/*
 * Set the colors of Widget "id" to the menu colors.
 */
    static void
gui_motif_menu_colors(id)
    Widget  id;
{
    if (gui.menu_bg_pixel != INVALCOLOR)
#if (XmVersion >= 1002)
	XmChangeColor(id, gui.menu_bg_pixel);
#else
	XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL);
#endif
    if (gui.menu_fg_pixel != INVALCOLOR)
	XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL);
}

/*
 * Set the colors of Widget "id" to the scrollbar colors.
 */
    static void
gui_motif_scroll_colors(id)
    Widget  id;
{
    if (gui.scroll_bg_pixel != INVALCOLOR)
#if (XmVersion >= 1002)
	XmChangeColor(id, gui.scroll_bg_pixel);
#else
	XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL);
#endif
    if (gui.scroll_fg_pixel != INVALCOLOR)
	XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL);
}

/*
 * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font.
 */
    void
gui_motif_menu_fontlist(id)
    Widget  id UNUSED;
{
#ifdef FEAT_MENU
#ifdef FONTSET_ALWAYS
    if (gui.menu_fontset != NOFONTSET)
    {
	XmFontList fl;

	fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset);
	if (fl != NULL)
	{
	    if (XtIsManaged(id))
	    {
		XtUnmanageChild(id);
		XtVaSetValues(id, XmNfontList, fl, NULL);
		/* We should force the widget to recalculate it's
		 * geometry now. */
		XtManageChild(id);
	    }
	    else
		XtVaSetValues(id, XmNfontList, fl, NULL);
	    XmFontListFree(fl);
	}
    }
#else
    if (gui.menu_font != NOFONT)
    {
	XmFontList fl;

	fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font);
	if (fl != NULL)
	{
	    if (XtIsManaged(id))
	    {
		XtUnmanageChild(id);
		XtVaSetValues(id, XmNfontList, fl, NULL);
		/* We should force the widget to recalculate it's
		 * geometry now. */
		XtManageChild(id);
	    }
	    else
		XtVaSetValues(id, XmNfontList, fl, NULL);
	    XmFontListFree(fl);
	}
    }
#endif
#endif
}


/*
 * We don't create it twice for the sake of speed.
 */

typedef struct _SharedFindReplace
{
    Widget dialog;	/* the main dialog widget */
    Widget wword;	/* 'Exact match' check button */
    Widget mcase;	/* 'match case' check button */
    Widget up;		/* search direction 'Up' radio button */
    Widget down;	/* search direction 'Down' radio button */
    Widget what;	/* 'Find what' entry text widget */
    Widget with;	/* 'Replace with' entry text widget */
    Widget find;	/* 'Find Next' action button */
    Widget replace;	/* 'Replace With' action button */
    Widget all;		/* 'Replace All' action button */
    Widget undo;	/* 'Undo' action button */

    Widget cancel;
} SharedFindReplace;

static SharedFindReplace find_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};

static void find_replace_destroy_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void find_replace_dismiss_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void entry_activate_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void find_replace_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
static void find_replace_keypress __ARGS((Widget w, SharedFindReplace * frdp, XKeyEvent * event));
static void find_replace_dialog_create __ARGS((char_u *entry_text, int do_replace));

    static void
find_replace_destroy_callback(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data;
    XtPointer	call_data UNUSED;
{
    SharedFindReplace *cd = (SharedFindReplace *)client_data;

    if (cd != NULL)
       /* suppress_dialog_mnemonics(cd->dialog); */
	cd->dialog = (Widget)0;
}

    static void
find_replace_dismiss_callback(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data;
    XtPointer	call_data UNUSED;
{
    SharedFindReplace *cd = (SharedFindReplace *)client_data;

    if (cd != NULL)
	XtUnmanageChild(cd->dialog);
}

    static void
entry_activate_callback(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data;
    XtPointer	call_data UNUSED;
{
    XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT);
}

    static void
find_replace_callback(w, client_data, call_data)
    Widget	w UNUSED;
    XtPointer	client_data;
    XtPointer	call_data UNUSED;
{
    long_u	flags = (long_u)client_data;
    char	*find_text, *repl_text;
    Boolean	direction_down = TRUE;
    Boolean	wword;
    Boolean	mcase;
    SharedFindReplace *sfr;

    if (flags == FRD_UNDO)
    {
	char_u	*save_cpo = p_cpo;

	/* No need to be Vi compatible here. */
	p_cpo = (char_u *)"";
	u_undo(1);
	p_cpo = save_cpo;
	gui_update_screen();
	return;
    }

    /* Get the search/replace strings from the dialog */
    if (flags == FRD_FINDNEXT)
    {
	repl_text = NULL;
	sfr = &find_widgets;
    }
    else
    {
	repl_text = XmTextFieldGetString(repl_widgets.with);
	sfr = &repl_widgets;
    }
    find_text = XmTextFieldGetString(sfr->what);
    XtVaGetValues(sfr->down, XmNset, &direction_down, NULL);
    XtVaGetValues(sfr->wword, XmNset, &wword, NULL);
    XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL);
    if (wword)
	flags |= FRD_WHOLE_WORD;
    if (mcase)
	flags |= FRD_MATCH_CASE;

    (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text,
							      direction_down);

    if (find_text != NULL)
	XtFree(find_text);
    if (repl_text != NULL)
	XtFree(repl_text);
}

    static void
find_replace_keypress(w, frdp, event)
    Widget		w UNUSED;
    SharedFindReplace	*frdp;
    XKeyEvent		*event;
{
    KeySym keysym;

    if (frdp == NULL)
	return;

    keysym = XLookupKeysym(event, 0);

    /* the scape key pops the whole dialog down */
    if (keysym == XK_Escape)
	XtUnmanageChild(frdp->dialog);
}

    static void
set_label(w, label)
    Widget w;
    char_u *label;
{
    XmString	str;
    char_u	*p, *next;
    KeySym	mnemonic = NUL;

    if (!w)
	return;

    p = vim_strsave(label);
    if (p == NULL)
	return;
    for (next = p; *next; ++next)
    {
	if (*next == DLG_HOTKEY_CHAR)
	{
	    int len = STRLEN(next);

	    if (len > 0)
	    {
		mch_memmove(next, next + 1, len);
		mnemonic = next[0];
	    }
	}
    }

    str = XmStringCreateSimple((char *)p);
    vim_free(p);
    if (str)
    {
	XtVaSetValues(w,
		XmNlabelString, str,
		XmNmnemonic, mnemonic,
		NULL);
	XmStringFree(str);
    }
    gui_motif_menu_fontlist(w);
}

    static void
find_replace_dialog_create(arg, do_replace)
    char_u	*arg;
    int		do_replace;
{
    SharedFindReplace	*frdp;
    Widget		separator;
    Widget		input_form;
    Widget		button_form;
    Widget		toggle_form;
    Widget		frame;
    XmString		str;
    int			n;
    Arg			args[6];
    int			wword = FALSE;
    int			mcase = !p_ic;
    Dimension		width;
    Dimension		widest;
    char_u		*entry_text;

    frdp = do_replace ? &repl_widgets : &find_widgets;

    /* Get the search string to use. */
    entry_text = get_find_dialog_text(arg, &wword, &mcase);

    /* If the dialog already exists, just raise it. */
    if (frdp->dialog)
    {
	gui_motif_synch_fonts();

	/* If the window is already up, just pop it to the top */
	if (XtIsManaged(frdp->dialog))
	    XMapRaised(XtDisplay(frdp->dialog),
					    XtWindow(XtParent(frdp->dialog)));
	else
	    XtManageChild(frdp->dialog);
	XtPopup(XtParent(frdp->dialog), XtGrabNone);
	XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);

	if (entry_text != NULL)
	    XmTextFieldSetString(frdp->what, (char *)entry_text);
	vim_free(entry_text);

	XtVaSetValues(frdp->wword, XmNset, wword, NULL);
	return;
    }

    /* Create a fresh new dialog window */
    if (do_replace)
	 str = XmStringCreateSimple(_("VIM - Search and Replace..."));
    else
	 str = XmStringCreateSimple(_("VIM - Search..."));

    n = 0;
    XtSetArg(args[n], XmNautoUnmanage, False); n++;
    XtSetArg(args[n], XmNnoResize, True); n++;
    XtSetArg(args[n], XmNdialogTitle, str); n++;

    frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n);
    XmStringFree(str);
    XtAddCallback(frdp->dialog, XmNdestroyCallback,
	    find_replace_destroy_callback, frdp);

    button_form = XtVaCreateWidget("buttonForm",
	    xmFormWidgetClass,	frdp->dialog,
	    XmNrightAttachment, XmATTACH_FORM,
	    XmNrightOffset, 4,
	    XmNtopAttachment, XmATTACH_FORM,
	    XmNtopOffset, 4,
	    XmNbottomAttachment, XmATTACH_FORM,
	    XmNbottomOffset, 4,
	    NULL);

    frdp->find = XtVaCreateManagedWidget("findButton",
	    xmPushButtonWidgetClass, button_form,
	    XmNsensitive, True,
	    XmNtopAttachment, XmATTACH_FORM,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNrightAttachment, XmATTACH_FORM,
	    NULL);
    set_label(frdp->find, _("Find &Next"));

    XtAddCallback(frdp->find, XmNactivateCallback,
	    find_replace_callback,
	    (do_replace ? (XtPointer)FRD_R_FINDNEXT : (XtPointer)FRD_FINDNEXT));

    if (do_replace)
    {
	frdp->replace = XtVaCreateManagedWidget("replaceButton",
		xmPushButtonWidgetClass, button_form,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, frdp->find,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	set_label(frdp->replace, _("&Replace"));
	XtAddCallback(frdp->replace, XmNactivateCallback,
		find_replace_callback, (XtPointer)FRD_REPLACE);

	frdp->all = XtVaCreateManagedWidget("replaceAllButton",
		xmPushButtonWidgetClass, button_form,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, frdp->replace,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	set_label(frdp->all, _("Replace &All"));
	XtAddCallback(frdp->all, XmNactivateCallback,
		find_replace_callback, (XtPointer)FRD_REPLACEALL);

	frdp->undo = XtVaCreateManagedWidget("undoButton",
		xmPushButtonWidgetClass, button_form,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, frdp->all,
		XmNleftAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		NULL);
	set_label(frdp->undo, _("&Undo"));
	XtAddCallback(frdp->undo, XmNactivateCallback,
		find_replace_callback, (XtPointer)FRD_UNDO);
    }

    frdp->cancel = XtVaCreateManagedWidget("closeButton",
	    xmPushButtonWidgetClass, button_form,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNrightAttachment, XmATTACH_FORM,
	    XmNbottomAttachment, XmATTACH_FORM,
	    NULL);
    set_label(frdp->cancel, _("&Cancel"));
    XtAddCallback(frdp->cancel, XmNactivateCallback,
	    find_replace_dismiss_callback, frdp);
    gui_motif_menu_fontlist(frdp->cancel);

    XtManageChild(button_form);

    n = 0;
    XtSetArg(args[n], XmNorientation, XmVERTICAL); n++;
    XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++;
    XtSetArg(args[n], XmNrightWidget, button_form); n++;
    XtSetArg(args[n], XmNrightOffset, 4); n++;
    XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
    XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
    separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n);
    XtManageChild(separator);

    input_form = XtVaCreateWidget("inputForm",
	    xmFormWidgetClass,	frdp->dialog,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNleftOffset, 4,
	    XmNrightAttachment, XmATTACH_WIDGET,
	    XmNrightWidget, separator,
	    XmNrightOffset, 4,
	    XmNtopAttachment, XmATTACH_FORM,
	    XmNtopOffset, 4,
	    NULL);

    {
	Widget label_what;
	Widget label_with = (Widget)0;

	str = XmStringCreateSimple(_("Find what:"));
	label_what = XtVaCreateManagedWidget("whatLabel",
		xmLabelGadgetClass, input_form,
		XmNlabelString, str,
		XmNleftAttachment,	XmATTACH_FORM,
		XmNtopAttachment, XmATTACH_FORM,
		XmNtopOffset, 4,
		NULL);
	XmStringFree(str);
	gui_motif_menu_fontlist(label_what);

	frdp->what = XtVaCreateManagedWidget("whatText",
		xmTextFieldWidgetClass, input_form,
		XmNtopAttachment, XmATTACH_FORM,
		XmNrightAttachment, XmATTACH_FORM,
		XmNleftAttachment, XmATTACH_FORM,
		NULL);

	if (do_replace)
	{
	    frdp->with = XtVaCreateManagedWidget("withText",
		    xmTextFieldWidgetClass,	input_form,
		    XmNtopAttachment, XmATTACH_WIDGET,
		    XmNtopWidget, frdp->what,
		    XmNtopOffset, 4,
		    XmNleftAttachment, XmATTACH_FORM,
		    XmNrightAttachment, XmATTACH_FORM,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);

	    XtAddCallback(frdp->with, XmNactivateCallback,
		    find_replace_callback, (XtPointer) FRD_R_FINDNEXT);

	    str = XmStringCreateSimple(_("Replace with:"));
	    label_with = XtVaCreateManagedWidget("withLabel",
		    xmLabelGadgetClass, input_form,
		    XmNlabelString, str,
		    XmNleftAttachment, XmATTACH_FORM,
		    XmNtopAttachment, XmATTACH_WIDGET,
		    XmNtopWidget, frdp->what,
		    XmNtopOffset, 4,
		    XmNbottomAttachment, XmATTACH_FORM,
		    NULL);
	    XmStringFree(str);
	    gui_motif_menu_fontlist(label_with);

	    /*
	     * Make the entry activation only change the input focus onto the
	     * with item.
	     */
	    XtAddCallback(frdp->what, XmNactivateCallback,
		    entry_activate_callback, frdp->with);
	    XtAddEventHandler(frdp->with, KeyPressMask, False,
			    (XtEventHandler)find_replace_keypress,
			    (XtPointer) frdp);

	}
	else
	{
	    /*
	     * Make the entry activation do the search.
	     */
	    XtAddCallback(frdp->what, XmNactivateCallback,
		    find_replace_callback, (XtPointer)FRD_FINDNEXT);
	}
	XtAddEventHandler(frdp->what, KeyPressMask, False,
			    (XtEventHandler)find_replace_keypress,
			    (XtPointer)frdp);

	/* Get the maximum width between the label widgets and line them up.
	 */
	n = 0;
	XtSetArg(args[n], XmNwidth, &width); n++;
	XtGetValues(label_what, args, n);
	widest = width;
	if (do_replace)
	{
	    XtGetValues(label_with, args, n);
	    if (width > widest)
		widest = width;
	}

	XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL);
	if (do_replace)
	    XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL);

    }

    XtManageChild(input_form);

    {
	Widget radio_box;
	Widget w;

	frame = XtVaCreateWidget("directionFrame",
		xmFrameWidgetClass, frdp->dialog,
		XmNtopAttachment, XmATTACH_WIDGET,
		XmNtopWidget, input_form,
		XmNtopOffset, 4,
		XmNbottomAttachment, XmATTACH_FORM,
		XmNbottomOffset, 4,
		XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET,
		XmNrightWidget, input_form,
		NULL);

	str = XmStringCreateSimple(_("Direction"));
	w = XtVaCreateManagedWidget("directionFrameLabel",
		xmLabelGadgetClass, frame,
		XmNlabelString, str,
		XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING,
		XmNchildType, XmFRAME_TITLE_CHILD,
		NULL);
	XmStringFree(str);
	gui_motif_menu_fontlist(w);

	radio_box = XmCreateRadioBox(frame, "radioBox",
		(ArgList)NULL, 0);

	str = XmStringCreateSimple( _("Up"));
	frdp->up = XtVaCreateManagedWidget("upRadioButton",
		xmToggleButtonGadgetClass, radio_box,
		XmNlabelString, str,
		XmNset, False,
		NULL);
	XmStringFree(str);
	gui_motif_menu_fontlist(frdp->up);

	str = XmStringCreateSimple(_("Down"));
	frdp->down = XtVaCreateManagedWidget("downRadioButton",
		xmToggleButtonGadgetClass, radio_box,
		XmNlabelString, str,
		XmNset, True,
		NULL);
	XmStringFree(str);
	gui_motif_menu_fontlist(frdp->down);

	XtManageChild(radio_box);
	XtManageChild(frame);
    }

    toggle_form = XtVaCreateWidget("toggleForm",
	    xmFormWidgetClass,	frdp->dialog,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNleftOffset, 4,
	    XmNrightAttachment, XmATTACH_WIDGET,
	    XmNrightWidget, frame,
	    XmNrightOffset, 4,
	    XmNtopAttachment, XmATTACH_WIDGET,
	    XmNtopWidget, input_form,
	    XmNtopOffset, 4,
	    XmNbottomAttachment, XmATTACH_FORM,
	    XmNbottomOffset, 4,
	    NULL);

    str = XmStringCreateSimple(_("Match whole word only"));
    frdp->wword = XtVaCreateManagedWidget("wordToggle",
	    xmToggleButtonGadgetClass, toggle_form,
	    XmNlabelString, str,
	    XmNtopAttachment, XmATTACH_FORM,
	    XmNtopOffset, 4,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNleftOffset, 4,
	    XmNset, wword,
	    NULL);
    XmStringFree(str);

    str = XmStringCreateSimple(_("Match case"));
    frdp->mcase = XtVaCreateManagedWidget("caseToggle",
	    xmToggleButtonGadgetClass, toggle_form,
	    XmNlabelString, str,
	    XmNleftAttachment, XmATTACH_FORM,
	    XmNleftOffset, 4,
	    XmNtopAttachment, XmATTACH_WIDGET,
	    XmNtopWidget, frdp->wword,
	    XmNtopOffset, 4,
	    XmNset, mcase,
	    NULL);
    XmStringFree(str);
    gui_motif_menu_fontlist(frdp->wword);
    gui_motif_menu_fontlist(frdp->mcase);

    XtManageChild(toggle_form);

    if (entry_text != NULL)
	XmTextFieldSetString(frdp->what, (char *)entry_text);
    vim_free(entry_text);

    gui_motif_synch_fonts();

    manage_centered(frdp->dialog);
    activate_dialog_mnemonics(frdp->dialog);
    XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT);
}

   void
gui_mch_find_dialog(eap)
    exarg_T	*eap;
{
    if (!gui.in_use)
	return;

    find_replace_dialog_create(eap->arg, FALSE);
}


    void
gui_mch_replace_dialog(eap)
    exarg_T	*eap;
{
    if (!gui.in_use)
	return;

    find_replace_dialog_create(eap->arg, TRUE);
}

/*
 * Synchronize all gui elements, which are dependant upon the
 * main text font used. Those are in esp. the find/replace dialogs.
 * If you don't understand why this should be needed, please try to
 * search for "pięść" in iso8859-2.
 */
    void
gui_motif_synch_fonts(void)
{
    SharedFindReplace *frdp;
    int		    do_replace;
    XFontStruct	    *font;
    XmFontList	    font_list;

    /* FIXME: Unless we find out how to create a XmFontList from a XFontSet,
     * we just give up here on font synchronization. */
    font = (XFontStruct *)gui.norm_font;
    if (font == NULL)
	return;

    font_list = gui_motif_create_fontlist(font);

    /* OK this loop is a bit tricky... */
    for (do_replace = 0; do_replace <= 1; ++do_replace)
    {
	frdp = (do_replace) ? (&repl_widgets) : (&find_widgets);
	if (frdp->dialog)
	{
	    XtVaSetValues(frdp->what, XmNfontList, font_list, NULL);
	    if (do_replace)
		XtVaSetValues(frdp->with, XmNfontList, font_list, NULL);
	}
    }

    XmFontListFree(font_list);
}