summaryrefslogtreecommitdiffstats
path: root/src/gui_motif.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
committerBram Moolenaar <Bram@vim.org>2004-06-13 20:20:40 +0000
commit071d4279d6ab81b7187b48f3a0fc61e587b6db6c (patch)
tree221cbe3c40e043163c06f61c52a7ba2eb41e12ce /src/gui_motif.c
parentb4210b3bc14e2918f153a7307530fbe6eba659e1 (diff)
updated for version 7.0001v7.0001
Diffstat (limited to 'src/gui_motif.c')
-rw-r--r--src/gui_motif.c3090
1 files changed, 3090 insertions, 0 deletions
diff --git a/src/gui_motif.c b/src/gui_motif.c
new file mode 100644
index 0000000000..4fe26ec57b
--- /dev/null
+++ b/src/gui_motif.c
@@ -0,0 +1,3090 @@
+/* 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 <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
+
+#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_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_TOOLBAR
+# if 0
+static void toolbar_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
+static void toolbar_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *));
+# endif
+# 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 gui_mch_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));
+#ifdef FEAT_MENU
+static void gui_motif_menu_fontlist __ARGS((Widget id));
+#endif
+
+#if (XmVersion >= 1002)
+# define STRING_TAG XmFONTLIST_DEFAULT_TAG
+#else
+# define STRING_TAG XmSTRING_DEFAULT_CHARSET
+#endif
+
+/*
+ * Call-back routines.
+ */
+
+/* ARGSUSED */
+ static void
+scroll_cb(w, client_data, call_data)
+ Widget w;
+ 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);
+}
+
+
+/*
+ * End of call-back routines
+ */
+
+/*
+ * Create all the motif widgets necessary.
+ */
+ void
+gui_x11_create_widgets()
+{
+ /*
+ * 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
+ 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);
+
+# if 0 /* these don't work, because of the XmNtraversalOn above. */
+ XtAddEventHandler(toolBar, EnterWindowMask, False,
+ toolbar_enter_cb, NULL);
+ XtAddEventHandler(toolBar, LeaveWindowMask, False,
+ toolbar_leave_cb, NULL);
+# endif
+#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
+}
+
+/*ARGSUSED*/
+ void
+gui_mch_set_text_area_pos(x, y, w, h)
+ int x;
+ int y;
+ int w;
+ int h;
+{
+#ifdef FEAT_TOOLBAR
+ /* Give keyboard focus to the textArea instead of the toolbar. */
+ gui_mch_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.
+ */
+static void manage_centered __ARGS((Widget dialog_child));
+
+static 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, 0);
+ XtVaSetValues(shell, XmNmappedWhenManaged, False, 0);
+
+ 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, 0);
+}
+
+#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 gui_mch_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);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ 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);
+ XtVaSetValues(textAreaForm,
+ XmNtopAttachment, XmATTACH_WIDGET,
+ XmNtopWidget, XtParent(toolBar),
+ 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 accelrator 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;
+
+#ifdef LESSTIF_VERSION
+ /* 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);
+#endif
+}
+
+ 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, XmNO_LINE); n++;
+#endif
+ }
+ else
+ {
+ get_toolbar_pixmap(menu, &menu->image, &menu->image_ins);
+ /* 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++;
+
+#ifndef FEAT_SUN_WORKSHOP
+
+ /* Without shadows one can't sense whatever the button has been
+ * pressed or not! However we wan't to save a bit of space...
+ */
+ XtSetArg(args[n], XmNhighlightThickness, 0); n++;
+ XtSetArg(args[n], XmNhighlightOnEnter, True); n++;
+ XtSetArg(args[n], XmNmarginWidth, 0); n++;
+ XtSetArg(args[n], XmNmarginHeight, 0); n++;
+#endif
+ if (menu->image == 0)
+ {
+ XtSetArg(args[n], XmNlabelType, XmSTRING); n++;
+ XtSetArg(args[n], XmNlabelPixmap, 0); n++;
+ XtSetArg(args[n], XmNlabelInsensitivePixmap, 0); n++;
+ }
+ else
+ {
+ XtSetArg(args[n], XmNlabelPixmap, menu->image); n++;
+ XtSetArg(args[n], XmNlabelInsensitivePixmap, menu->image_ins); n++;
+ XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++;
+ }
+ type = xmPushButtonWidgetClass;
+ XtSetArg(args[n], XmNwidth, 80); n++;
+ }
+
+ 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 == xmPushButtonWidgetClass)
+ {
+ 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
+
+ gui_mch_submenu_change(root_menu, TRUE);
+}
+
+ void
+gui_mch_new_menu_font()
+{
+ if (menuBar == (Widget)0)
+ return;
+ gui_mch_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);
+ 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)
+ gui_mch_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)
+ gui_mch_submenu_change(toolbar, TRUE);
+# endif
+}
+#endif
+
+ static void
+gui_mch_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->image != (Pixmap)0)
+ {
+ XFreePixmap(gui.dpy, mp->image);
+ XFreePixmap(gui.dpy, mp->image_ins);
+ get_toolbar_pixmap(mp, &mp->image, &mp->image_ins);
+ if (mp->image != (Pixmap)0)
+ XtVaSetValues(mp->id,
+ XmNlabelPixmap, mp->image,
+ XmNlabelInsensitivePixmap, mp->image_ins,
+ NULL);
+ }
+# 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 */
+ gui_mch_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 (p