home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / gui_athena.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-25  |  53.3 KB  |  2,231 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved        by Bram Moolenaar
  4.  *                GUI/Motif support by Robert Webb
  5.  *                Athena port by Bill Foster
  6.  *
  7.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  8.  * Do ":help credits" in Vim to see a list of people who contributed.
  9.  * See README.txt for an overview of the Vim source code.
  10.  */
  11.  
  12. #include <X11/StringDefs.h>
  13. #include <X11/Intrinsic.h>
  14. #ifdef FEAT_GUI_NEXTAW
  15. # include <X11/neXtaw/Form.h>
  16. # include <X11/neXtaw/SimpleMenu.h>
  17. # include <X11/neXtaw/MenuButton.h>
  18. # include <X11/neXtaw/SmeBSB.h>
  19. # include <X11/neXtaw/SmeLine.h>
  20. # include <X11/neXtaw/Box.h>
  21. # include <X11/neXtaw/Dialog.h>
  22. # include <X11/neXtaw/Text.h>
  23. # include <X11/neXtaw/AsciiText.h>
  24. # include <X11/neXtaw/Scrollbar.h>
  25. #else
  26. # include <X11/Xaw/Form.h>
  27. # include <X11/Xaw/SimpleMenu.h>
  28. # include <X11/Xaw/MenuButton.h>
  29. # include <X11/Xaw/SmeBSB.h>
  30. # include <X11/Xaw/SmeLine.h>
  31. # include <X11/Xaw/Box.h>
  32. # include <X11/Xaw/Dialog.h>
  33. # include <X11/Xaw/Text.h>
  34. # include <X11/Xaw/AsciiText.h>
  35. #endif /* FEAT_GUI_NEXTAW */
  36.  
  37. #include "vim.h"
  38. #ifndef FEAT_GUI_NEXTAW
  39. # include "gui_at_sb.h"
  40. #endif
  41.  
  42. extern Widget vimShell;
  43.  
  44. static Widget vimForm = (Widget)0;
  45. static Widget textArea = (Widget)0;
  46. #ifdef FEAT_MENU
  47. static Widget menuBar = (Widget)0;
  48. static XtIntervalId timer = 0;        /* 0 = expired, otherwise active */
  49.  
  50. /* Used to figure out menu ordering */
  51. static vimmenu_T *a_cur_menu = NULL;
  52. static Cardinal    athena_calculate_ins_pos __ARGS((Widget));
  53.  
  54. static Pixmap gui_athena_create_pullright_pixmap __ARGS((Widget));
  55. static void gui_athena_menu_timeout __ARGS((XtPointer, XtIntervalId *));
  56. static void gui_athena_popup_callback __ARGS((Widget, XtPointer, XtPointer));
  57. static void gui_athena_delayed_arm_action __ARGS((Widget, XEvent *, String *,
  58.                          Cardinal *));
  59. static void gui_athena_popdown_submenus_action __ARGS((Widget, XEvent *,
  60.                               String *, Cardinal *));
  61. static XtActionsRec    pullAction[2] = {
  62.     { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action},
  63.     { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action}
  64. };
  65. #endif
  66.  
  67. #ifdef FEAT_TOOLBAR
  68. static void gui_mch_reset_focus __ARGS((void));
  69. static Widget toolBar = (Widget)0;
  70. #endif
  71.  
  72. static void gui_athena_scroll_cb_jump    __ARGS((Widget, XtPointer, XtPointer));
  73. static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
  74. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
  75. static void gui_athena_menu_colors __ARGS((Widget id));
  76. #endif
  77. static void gui_athena_scroll_colors __ARGS((Widget id));
  78.  
  79. #ifdef FEAT_MENU
  80. static XtTranslations    popupTrans, parentTrans, menuTrans, supermenuTrans;
  81. static Pixmap        pullerBitmap = None;
  82. static int        puller_width = 0;
  83. #endif
  84.  
  85. /*
  86.  * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
  87.  * left or middle mouse button.
  88.  */
  89. /* ARGSUSED */
  90.     static void
  91. gui_athena_scroll_cb_jump(w, client_data, call_data)
  92.     Widget    w;
  93.     XtPointer    client_data, call_data;
  94. {
  95.     scrollbar_T *sb, *sb_info;
  96.     long    value;
  97.  
  98.     sb = gui_find_scrollbar((long)client_data);
  99.  
  100.     if (sb == NULL)
  101.     return;
  102.     else if (sb->wp != NULL)        /* Left or right scrollbar */
  103.     {
  104.     /*
  105.      * Careful: need to get scrollbar info out of first (left) scrollbar
  106.      * for window, but keep real scrollbar too because we must pass it to
  107.      * gui_drag_scrollbar().
  108.      */
  109.     sb_info = &sb->wp->w_scrollbars[0];
  110.     }
  111.     else        /* Bottom scrollbar */
  112.     sb_info = sb;
  113.  
  114.     value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001);
  115.     if (value > sb_info->max)
  116.     value = sb_info->max;
  117.  
  118.     gui_drag_scrollbar(sb, value, TRUE);
  119. }
  120.  
  121. /*
  122.  * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
  123.  * right mouse buttons.
  124.  */
  125. /* ARGSUSED */
  126.     static void
  127. gui_athena_scroll_cb_scroll(w, client_data, call_data)
  128.     Widget    w;
  129.     XtPointer    client_data, call_data;
  130. {
  131.     scrollbar_T *sb, *sb_info;
  132.     long    value;
  133.     int        data = (int)(long)call_data;
  134.     int        page;
  135.  
  136.     sb = gui_find_scrollbar((long)client_data);
  137.  
  138.     if (sb == NULL)
  139.     return;
  140.     if (sb->wp != NULL)        /* Left or right scrollbar */
  141.     {
  142.     /*
  143.      * Careful: need to get scrollbar info out of first (left) scrollbar
  144.      * for window, but keep real scrollbar too because we must pass it to
  145.      * gui_drag_scrollbar().
  146.      */
  147.     sb_info = &sb->wp->w_scrollbars[0];
  148.  
  149.     if (sb_info->size > 5)
  150.         page = sb_info->size - 2;        /* use two lines of context */
  151.     else
  152.         page = sb_info->size;
  153. #ifdef FEAT_GUI_NEXTAW
  154.     if (data < 0)
  155.     {
  156.         data = (data - gui.char_height + 1) / gui.char_height;
  157.         if (data > -sb_info->size)
  158.         data = -1;
  159.         else
  160.         data = -page;
  161.     }
  162.     else if (data > 0)
  163.     {
  164.         data = (data + gui.char_height - 1) / gui.char_height;
  165.         if (data < sb_info->size)
  166.         data = 1;
  167.         else
  168.         data = page;
  169.     }
  170. #else
  171.     switch (data)
  172.     {
  173.         case  ONE_LINE_DATA: data = 1; break;
  174.         case -ONE_LINE_DATA: data = -1; break;
  175.         case  ONE_PAGE_DATA: data = page; break;
  176.         case -ONE_PAGE_DATA: data = -page; break;
  177.         case  END_PAGE_DATA: data = sb_info->max; break;
  178.         case -END_PAGE_DATA: data = -sb_info->max; break;
  179.             default: data = 0; break;
  180.     }
  181. #endif
  182.     }
  183.     else            /* Bottom scrollbar */
  184.     {
  185.     sb_info = sb;
  186. #ifdef FEAT_GUI_NEXTAW
  187.     if (data < 0)
  188.     {
  189.         data = (data - gui.char_width + 1) / gui.char_width;
  190.         if (data > -sb->size)
  191.         data = -1;
  192.     }
  193.     else if (data > 0)
  194.     {
  195.         data = (data + gui.char_width - 1) / gui.char_width;
  196.         if (data < sb->size)
  197.         data = 1;
  198.     }
  199. #endif
  200.     if (data < -1)        /* page-width left */
  201.     {
  202.         if (sb->size > 8)
  203.         data = -(sb->size - 5);
  204.         else
  205.         data = -sb->size;
  206.     }
  207.     else if (data > 1)    /* page-width right */
  208.     {
  209.         if (sb->size > 8)
  210.         data = (sb->size - 5);
  211.         else
  212.         data = sb->size;
  213.     }
  214.     }
  215.  
  216.     value = sb_info->value + data;
  217.     if (value > sb_info->max)
  218.     value = sb_info->max;
  219.     else if (value < 0)
  220.     value = 0;
  221.  
  222.     /* Update the bottom scrollbar an extra time (why is this needed?? */
  223.     if (sb->wp == NULL)        /* Bottom scrollbar */
  224.     gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max);
  225.  
  226.     gui_drag_scrollbar(sb, value, FALSE);
  227. }
  228.  
  229. /*
  230.  * Create all the Athena widgets necessary.
  231.  */
  232.     void
  233. gui_x11_create_widgets()
  234. {
  235.     /*
  236.      * We don't have any borders handled internally by the textArea to worry
  237.      * about so only skip over the configured border width.
  238.      */
  239.     gui.border_offset = gui.border_width;
  240.  
  241. #if 0 /* not needed? */
  242.     XtInitializeWidgetClass(formWidgetClass);
  243.     XtInitializeWidgetClass(boxWidgetClass);
  244.     XtInitializeWidgetClass(coreWidgetClass);
  245. #ifdef FEAT_MENU
  246.     XtInitializeWidgetClass(menuButtonWidgetClass);
  247. #endif
  248.     XtInitializeWidgetClass(simpleMenuWidgetClass);
  249. #ifdef FEAT_GUI_NEXTAW
  250.     XtInitializeWidgetClass(scrollbarWidgetClass);
  251. #else
  252.     XtInitializeWidgetClass(vim_scrollbarWidgetClass);
  253. #endif
  254. #endif
  255.  
  256.     /* The form containing all the other widgets */
  257.     vimForm = XtVaCreateManagedWidget("vimForm",
  258.     formWidgetClass,    vimShell,
  259.     XtNborderWidth,        0,
  260.     NULL);
  261.     gui_athena_scroll_colors(vimForm);
  262.  
  263. #ifdef FEAT_MENU
  264.     /* The top menu bar */
  265.     menuBar = XtVaCreateManagedWidget("menuBar",
  266.     boxWidgetClass,        vimForm,
  267.     XtNresizable,        True,
  268.     XtNtop,            XtChainTop,
  269.     XtNbottom,        XtChainTop,
  270.     XtNleft,        XtChainLeft,
  271.     XtNright,        XtChainRight,
  272.     XtNinsertPosition,    athena_calculate_ins_pos,
  273.     NULL);
  274.     gui_athena_menu_colors(menuBar);
  275.     if (gui.menu_fg_pixel != INVALCOLOR)
  276.     XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
  277. #endif
  278.  
  279. #ifdef FEAT_TOOLBAR
  280.     /* Don't create it Managed, it will be managed when creating the first
  281.      * item.  Otherwise an empty toolbar shows up. */
  282.     toolBar = XtVaCreateWidget("toolBar",
  283.     boxWidgetClass,        vimForm,
  284.     XtNresizable,        True,
  285.     XtNtop,            XtChainTop,
  286.     XtNbottom,        XtChainTop,
  287.     XtNleft,        XtChainLeft,
  288.     XtNright,        XtChainRight,
  289.     XtNorientation,        XtorientHorizontal,
  290.     XtNhSpace,        1,
  291.     XtNvSpace,        3,
  292.     XtNinsertPosition,    athena_calculate_ins_pos,
  293.     NULL);
  294.     gui_athena_menu_colors(toolBar);
  295. #endif
  296.  
  297.     /* The text area. */
  298.     textArea = XtVaCreateManagedWidget("textArea",
  299.     coreWidgetClass,    vimForm,
  300.     XtNresizable,        True,
  301.     XtNtop,            XtChainTop,
  302.     XtNbottom,        XtChainTop,
  303.     XtNleft,        XtChainLeft,
  304.     XtNright,        XtChainLeft,
  305.     XtNbackground,        gui.back_pixel,
  306.     XtNborderWidth,        0,
  307.     NULL);
  308.  
  309.     /*
  310.      * Install the callbacks.
  311.      */
  312.     gui_x11_callbacks(textArea, vimForm);
  313.  
  314. #ifdef FEAT_MENU
  315.     popupTrans = XtParseTranslationTable(
  316.         "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
  317.         "<LeaveWindow>: unhighlight()\n"
  318.         "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
  319.         "<Motion>: highlight() menu-delayedpopup()");
  320.     parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()");
  321.     menuTrans = XtParseTranslationTable(
  322.         "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
  323.         "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n"
  324.         "<BtnUp>: notify() unhighlight()\n"
  325.         "<BtnMotion>: highlight() menu-delayedpopup()");
  326.     supermenuTrans = XtParseTranslationTable(
  327.         "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
  328.         "<LeaveWindow>: unhighlight()\n"
  329.         "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
  330.         "<BtnMotion>: highlight() menu-delayedpopup()");
  331.  
  332.     XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction,
  333.             XtNumber(pullAction));
  334. #endif
  335.  
  336.     /* Pretend we don't have input focus, we will get an event if we do. */
  337.     gui.in_focus = FALSE;
  338. }
  339.  
  340. #ifdef FEAT_MENU
  341. /*
  342.  * Calculates the Pixmap based on the size of the current menu font.
  343.  */
  344.     static Pixmap
  345. gui_athena_create_pullright_pixmap(w)
  346.     Widget  w;
  347. {
  348.     Pixmap  retval;
  349. #ifdef FONTSET_ALWAYS
  350.     XFontSet    font = None;
  351. #else
  352.     XFontStruct    *font = NULL;
  353. #endif
  354.  
  355. #ifdef FONTSET_ALWAYS
  356.     if (gui.menu_fontset == NOFONTSET)
  357. #else
  358.     if (gui.menu_font == NOFONT)
  359. #endif
  360.     {
  361.     XrmValue from, to;
  362.     WidgetList  children;
  363.     Cardinal    num_children;
  364.  
  365. #ifdef FONTSET_ALWAYS
  366.     from.size = strlen(from.addr = XtDefaultFontSet);
  367.     to.addr = (XtPointer)&font;
  368.     to.size = sizeof(XFontSet);
  369. #else
  370.     from.size = strlen(from.addr = XtDefaultFont);
  371.     to.addr = (XtPointer)&font;
  372.     to.size = sizeof(XFontStruct *);
  373. #endif
  374.     /* Assumption: The menuBar children will use the same font as the
  375.      *           pulldown menu items AND they will all be of type
  376.      *           XtNfont.
  377.      */
  378.     XtVaGetValues(menuBar, XtNchildren, &children,
  379.                    XtNnumChildren, &num_children,
  380.                    NULL);
  381.     if (XtConvertAndStore(w ? w :
  382.                 (num_children > 0) ? children[0] : menuBar,
  383.                   XtRString, &from,
  384. #ifdef FONTSET_ALWAYS
  385.                   XtRFontSet, &to
  386. #else
  387.                   XtRFontStruct, &to
  388. #endif
  389.             ) == False)
  390.         return None;
  391.     /* "font" should now contain data */
  392.     }
  393.     else
  394. #ifdef FONTSET_ALWAYS
  395.     font = (XFontSet)gui.menu_fontset;
  396. #else
  397.     font = (XFontStruct *)gui.menu_font;
  398. #endif
  399.  
  400.     {
  401.     int        width, height;
  402.     GC        draw_gc, undraw_gc;
  403.     XGCValues   gc_values;
  404.     XPoint        points[3];
  405.  
  406. #ifdef FONTSET_ALWAYS
  407.     height = fontset_height2(font);
  408. #else
  409.     height = font->max_bounds.ascent + font->max_bounds.descent;
  410. #endif
  411.     width = height - 2;
  412.     puller_width = width + 4;
  413.     retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width,
  414.                    height, 1);
  415.     gc_values.foreground = 1;
  416.     gc_values.background = 0;
  417.     draw_gc = XCreateGC(gui.dpy, retval,
  418.             GCForeground | GCBackground,
  419.             &gc_values);
  420.     gc_values.foreground = 0;
  421.     gc_values.background = 1;
  422.     undraw_gc = XCreateGC(gui.dpy, retval,
  423.                   GCForeground | GCBackground,
  424.                   &gc_values);
  425.     points[0].x = 0;
  426.     points[0].y = 0;
  427.     points[1].x = width - 1;
  428.     points[1].y = (height - 1) / 2;
  429.     points[2].x = 0;
  430.     points[2].y = height - 1;
  431.     XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height);
  432.     XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points),
  433.              Convex, CoordModeOrigin);
  434.     XFreeGC(gui.dpy, draw_gc);
  435.     XFreeGC(gui.dpy, undraw_gc);
  436.     }
  437.     return retval;
  438. }
  439. #endif
  440.  
  441. /*
  442.  * Called when the GUI is not going to start after all.
  443.  */
  444.     void
  445. gui_x11_destroy_widgets()
  446. {
  447.     textArea = NULL;
  448. #ifdef FEAT_MENU
  449.     menuBar = NULL;
  450. #endif
  451. #ifdef FEAT_TOOLBAR
  452.     toolBar = NULL;
  453. #endif
  454. }
  455.  
  456. #if defined(FEAT_TOOLBAR) || defined(PROTO)
  457.     void
  458. gui_mch_set_toolbar_pos(x, y, w, h)
  459.     int        x;
  460.     int        y;
  461.     int        w;
  462.     int        h;
  463. {
  464.     Dimension    border;
  465.     int        height;
  466.  
  467.     if (!XtIsManaged(toolBar))    /* nothing to do */
  468.     return;
  469.     XtUnmanageChild(toolBar);
  470.     XtVaGetValues(toolBar,
  471.         XtNborderWidth, &border,
  472.         NULL);
  473.     height = h - 2 * border;
  474.     if (height < 0)
  475.     height = 1;
  476.     XtVaSetValues(toolBar,
  477.           XtNhorizDistance, x,
  478.           XtNvertDistance, y,
  479.           XtNwidth, w - 2 * border,
  480.           XtNheight,    height,
  481.           NULL);
  482.     XtManageChild(toolBar);
  483. }
  484. #endif
  485.  
  486.     void
  487. gui_mch_set_text_area_pos(x, y, w, h)
  488.     int        x;
  489.     int        y;
  490.     int        w;
  491.     int        h;
  492. {
  493.     XtUnmanageChild(textArea);
  494.     XtVaSetValues(textArea,
  495.           XtNhorizDistance, x,
  496.           XtNvertDistance, y,
  497.           XtNwidth, w,
  498.           XtNheight, h,
  499.           NULL);
  500.     XtManageChild(textArea);
  501. #ifdef FEAT_TOOLBAR
  502.     /* Give keyboard focus to the textArea instead of the toolbar. */
  503.     gui_mch_reset_focus();
  504. #endif
  505. }
  506.  
  507. #ifdef FEAT_TOOLBAR
  508. /*
  509.  * A toolbar button has been pushed; now reset the input focus
  510.  * such that the user can type page up/down etc. and have the
  511.  * input go to the editor window, not the button
  512.  */
  513.     static void
  514. gui_mch_reset_focus()
  515. {
  516.     XtSetKeyboardFocus(vimForm, textArea);
  517. }
  518. #endif
  519.  
  520.  
  521.     void
  522. gui_x11_set_back_color()
  523. {
  524.     if (textArea != NULL)
  525.     XtVaSetValues(textArea,
  526.           XtNbackground, gui.back_pixel,
  527.           NULL);
  528. }
  529.  
  530. #if defined(FEAT_MENU) || defined(PROTO)
  531. /*
  532.  * Menu stuff.
  533.  */
  534.  
  535. static char_u    *make_pull_name __ARGS((char_u * name));
  536. static Widget    get_popup_entry __ARGS((Widget w));
  537. static Widget    submenu_widget __ARGS((Widget));
  538. static Boolean    has_submenu __ARGS((Widget));
  539. static void gui_mch_submenu_change __ARGS((vimmenu_T *mp, int colors));
  540. static void gui_athena_menu_font __ARGS((Widget id));
  541. static Boolean    gui_athena_menu_has_submenus __ARGS((Widget, Widget));
  542.  
  543.     void
  544. gui_mch_enable_menu(flag)
  545.     int        flag;
  546. {
  547.     if (flag)
  548.     {
  549.     XtManageChild(menuBar);
  550. # ifdef FEAT_TOOLBAR
  551.     if (XtIsManaged(toolBar))
  552.     {
  553.         XtVaSetValues(toolBar,
  554.         XtNvertDistance,    gui.menu_height,
  555.         NULL);
  556.         XtVaSetValues(textArea,
  557.         XtNvertDistance,    gui.menu_height + gui.toolbar_height,
  558.         NULL);
  559.     }
  560. # endif
  561.     }
  562.     else
  563.     {
  564.     XtUnmanageChild(menuBar);
  565. # ifdef FEAT_TOOLBAR
  566.     if (XtIsManaged(toolBar))
  567.     {
  568.         XtVaSetValues(toolBar,
  569.         XtNvertDistance,    0,
  570.         NULL);
  571.     }
  572. # endif
  573.     }
  574. }
  575.  
  576.     void
  577. gui_mch_set_menu_pos(x, y, w, h)
  578.     int        x;
  579.     int        y;
  580.     int        w;
  581.     int        h;
  582. {
  583.     Dimension    border;
  584.     int        height;
  585.  
  586.     XtUnmanageChild(menuBar);
  587.     XtVaGetValues(menuBar, XtNborderWidth, &border, NULL);
  588.     /* avoid trouble when there are no menu items, and h is 1 */
  589.     height = h - 2 * border;
  590.     if (height < 0)
  591.     height = 1;
  592.     XtVaSetValues(menuBar,
  593.         XtNhorizDistance, x,
  594.         XtNvertDistance, y,
  595.         XtNwidth, w - 2 * border,
  596.         XtNheight, height,
  597.         NULL);
  598.     XtManageChild(menuBar);
  599. }
  600.  
  601. /*
  602.  * Used to calculate the insertion position of a widget with respect to its
  603.  * neighbors.
  604.  *
  605.  * Valid range of return values is: 0 (beginning of children) to
  606.  *                    numChildren (end of children).
  607.  */
  608.     static Cardinal
  609. athena_calculate_ins_pos(widget)
  610.     Widget    widget;
  611. {
  612.     /* Assume that if the parent of the vimmenu_T is NULL, then we can get
  613.      * to this menu by traversing "next", starting at "root_menu".
  614.      *
  615.      * This holds true for popup menus, toolbar, and toplevel menu items.
  616.      */
  617.  
  618.     /* Popup menus:  "id" is NULL. Only submenu_id is valid */
  619.  
  620.     /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
  621.      * "submenu_id" will be non-NULL.
  622.      */
  623.  
  624.     /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
  625.  
  626.     WidgetList    children;
  627.     Cardinal    num_children = 0;
  628.     int        retval;
  629.     Arg        args[2];
  630.     int        n = 0;
  631.     int        i;
  632.  
  633.     XtSetArg(args[n], XtNchildren, &children); n++;
  634.     XtSetArg(args[n], XtNnumChildren, &num_children); n++;
  635.     XtGetValues(XtParent(widget), args, n);
  636.  
  637.     retval = num_children;
  638.     for (i = 0; i < num_children; ++i)
  639.     {
  640.     Widget    current = children[i];
  641.     vimmenu_T    *menu = NULL;
  642.  
  643.     for (menu = (a_cur_menu->parent == NULL)
  644.                    ? root_menu : a_cur_menu->parent->children;
  645.                    menu != NULL;
  646.                    menu = menu->next)
  647.         if (current == menu->id
  648.             && a_cur_menu->priority < menu->priority
  649.             && i < retval)
  650.         retval = i;
  651.     }
  652.     return retval;
  653. }
  654.  
  655. /* ARGSUSED */
  656.     void
  657. gui_mch_add_menu(menu, idx)
  658.     vimmenu_T    *menu;
  659.     int        idx;
  660. {
  661.     char_u    *pullright_name;
  662.     Dimension    height, space, border;
  663.     vimmenu_T    *parent = menu->parent;
  664.  
  665.     a_cur_menu = menu;
  666.     if (parent == NULL)
  667.     {
  668.     if (menu_is_popup(menu->dname))
  669.     {
  670.         menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
  671.         simpleMenuWidgetClass,    vimShell,
  672.         XtNinsertPosition,    athena_calculate_ins_pos,
  673.         XtNtranslations,    popupTrans,
  674.         NULL);
  675.         gui_athena_menu_colors(menu->submenu_id);
  676.     }
  677.     else if (menu_is_menubar(menu->dname))
  678.     {
  679.         menu->id = XtVaCreateManagedWidget((char *)menu->dname,
  680.         menuButtonWidgetClass, menuBar,
  681.         XtNmenuName,        menu->dname,
  682. #ifdef FONTSET_ALWAYS
  683.         XtNinternational,   True,
  684. #endif
  685.         NULL);
  686.         if (menu->id == (Widget)0)
  687.         return;
  688.         gui_athena_menu_colors(menu->id);
  689.         gui_athena_menu_font(menu->id);
  690.  
  691.         menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
  692.         simpleMenuWidgetClass, menu->id,
  693.         XtNinsertPosition,    athena_calculate_ins_pos,
  694.         XtNtranslations,    supermenuTrans,
  695.         NULL);
  696.         gui_athena_menu_colors(menu->submenu_id);
  697.         gui_athena_menu_font(menu->submenu_id);
  698.  
  699.         /* Don't update the menu height when it was set at a fixed value */
  700.         if (!gui.menu_height_fixed)
  701.         {
  702.         /*
  703.          * When we add a top-level item to the menu bar, we can figure
  704.          * out how high the menu bar should be.
  705.          */
  706.         XtVaGetValues(menuBar,
  707.             XtNvSpace,    &space,
  708.             XtNborderWidth, &border,
  709.             NULL);
  710.         XtVaGetValues(menu->id,
  711.             XtNheight,    &height,
  712.             NULL);
  713.         gui.menu_height = height + 2 * (space + border);
  714.         }
  715.     }
  716.     }
  717.     else if (parent->submenu_id != (Widget)0)
  718.     {
  719.     menu->id = XtVaCreateManagedWidget((char *)menu->dname,
  720.         smeBSBObjectClass, parent->submenu_id,
  721.         XtNlabel, menu->dname,
  722. #ifdef FONTSET_ALWAYS
  723.         XtNinternational,    True,
  724. #endif
  725.         NULL);
  726.     if (menu->id == (Widget)0)
  727.         return;
  728.     if (pullerBitmap == None)
  729.         pullerBitmap = gui_athena_create_pullright_pixmap(menu->id);
  730.  
  731.     XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap,
  732.                 NULL);
  733.     /* If there are other menu items that are not pulldown menus,
  734.      * we need to adjust the right margins of those, too.
  735.      */
  736.     {
  737.         WidgetList    children;
  738.         Cardinal    num_children;
  739.         int        i;
  740.  
  741.         XtVaGetValues(parent->submenu_id, XtNchildren, &children,
  742.                           XtNnumChildren, &num_children,
  743.                           NULL);
  744.         for (i = 0; i < num_children; ++i)
  745.         {
  746.         XtVaSetValues(children[i],
  747.                   XtNrightMargin, puller_width,
  748.                   NULL);
  749.         }
  750.     }
  751.     gui_athena_menu_colors(menu->id);
  752.     gui_athena_menu_font(menu->id);
  753.  
  754.     pullright_name = make_pull_name(menu->dname);
  755.     menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name,
  756.         simpleMenuWidgetClass, parent->submenu_id,
  757.         XtNtranslations, menuTrans,
  758.         NULL);
  759.     gui_athena_menu_colors(menu->submenu_id);
  760.     gui_athena_menu_font(menu->submenu_id);
  761.     vim_free(pullright_name);
  762.     XtAddCallback(menu->submenu_id, XtNpopupCallback,
  763.               gui_athena_popup_callback, (XtPointer)menu);
  764.  
  765.     if (parent->parent != NULL)
  766.         XtOverrideTranslations(parent->submenu_id, parentTrans);
  767.     }
  768.     a_cur_menu = NULL;
  769. }
  770.  
  771. /* Used to determine whether a SimpleMenu has pulldown entries.
  772.  *
  773.  * "id" is the parent of the menu items.
  774.  * Ignore widget "ignore" in the pane.
  775.  */
  776.     static Boolean
  777. gui_athena_menu_has_submenus(id, ignore)
  778.     Widget    id;
  779.     Widget    ignore;
  780. {
  781.     WidgetList    children;
  782.     Cardinal    num_children;
  783.     int        i;
  784.  
  785.     XtVaGetValues(id, XtNchildren, &children,
  786.               XtNnumChildren, &num_children,
  787.               NULL);
  788.     for (i = 0; i < num_children; ++i)
  789.     {
  790.     if (children[i] == ignore)
  791.         continue;
  792.     if (has_submenu(children[i]))
  793.         return True;
  794.     }
  795.     return False;
  796. }
  797.  
  798.     static void
  799. gui_athena_menu_font(id)
  800.     Widget    id;
  801. {
  802. #ifdef FONTSET_ALWAYS
  803.     if (gui.menu_fontset != NOFONTSET)
  804.     {
  805.     if (XtIsManaged(id))
  806.     {
  807.         XtUnmanageChild(id);
  808.         XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
  809.         /* We should force the widget to recalculate it's
  810.          * geometry now. */
  811.         XtManageChild(id);
  812.     }
  813.     else
  814.         XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
  815.     if (has_submenu(id))
  816.         XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
  817.     }
  818. #else
  819.     int        managed = FALSE;
  820.  
  821.     if (gui.menu_font != NOFONT)
  822.     {
  823.     if (XtIsManaged(id))
  824.     {
  825.         XtUnmanageChild(id);
  826.         managed = TRUE;
  827.     }
  828.  
  829. # ifdef FEAT_XFONTSET
  830.     if (gui.fontset != NOFONTSET)
  831.         XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL);
  832.     else
  833. # endif
  834.         XtVaSetValues(id, XtNfont, gui.menu_font, NULL);
  835.     if (has_submenu(id))
  836.         XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
  837.  
  838.     /* Force the widget to recalculate it's geometry now. */
  839.     if (managed)
  840.         XtManageChild(id);
  841.     }
  842. #endif
  843. }
  844.  
  845.  
  846.     void
  847. gui_mch_new_menu_font()
  848. {
  849.     Pixmap oldpuller = None;
  850.  
  851.     if (menuBar == (Widget)0)
  852.     return;
  853.  
  854.     if (pullerBitmap != None)
  855.     {
  856.     oldpuller = pullerBitmap;
  857.     pullerBitmap = gui_athena_create_pullright_pixmap(NULL);
  858.     }
  859.     gui_mch_submenu_change(root_menu, FALSE);
  860.  
  861.     {
  862.     /* Iterate through the menubar menu items and get the height of
  863.      * each one.  The menu bar height is set to the maximum of all
  864.      * the heights.
  865.      */
  866.     vimmenu_T *mp;
  867.     int max_height = 9999;
  868.  
  869.     for (mp = root_menu; mp != NULL; mp = mp->next)
  870.     {
  871.         if (menu_is_menubar(mp->dname))
  872.         {
  873.         Dimension height;
  874.  
  875.         XtVaGetValues(mp->id,
  876.             XtNheight,(XtArgVal *)&height,
  877.             NULL);
  878.         if (height < max_height)
  879.             max_height = height;
  880.         }
  881.     }
  882.     if (max_height != 9999)
  883.     {
  884.         /* Don't update the menu height when it was set at a fixed value */
  885.         if (!gui.menu_height_fixed)
  886.         {
  887.         Dimension   space, border;
  888.  
  889.         XtVaGetValues(menuBar,
  890.             XtNvSpace,    &space,
  891.             XtNborderWidth, &border,
  892.             NULL);
  893.         gui.menu_height = max_height + 2 * (space + border);
  894.         }
  895.     }
  896.     }
  897.     /* Now, to simulate the window being resized.  Only, this
  898.      * will resize the window to it's current state.
  899.      *
  900.      * There has to be a better way, but I do not see one at this time.
  901.      * (David Harrison)
  902.      */
  903.     {
  904.     Position w, h;
  905.  
  906.     XtVaGetValues(vimShell,
  907.         XtNwidth, &w,
  908.         XtNheight, &h,
  909.         NULL);
  910.     gui_resize_shell(w, h
  911. #ifdef FEAT_XIM
  912.                         - xim_get_status_area_height()
  913. #endif
  914.              );
  915.     }
  916.     gui_set_shellsize(FALSE, TRUE);
  917.     ui_new_shellsize();
  918.     if (oldpuller != None)
  919.     XFreePixmap(gui.dpy, oldpuller);
  920. }
  921.  
  922. #if defined(FEAT_BEVAL) || defined(PROTO)
  923.     void
  924. gui_mch_new_tooltip_font()
  925. {
  926. #  ifdef FEAT_TOOLBAR
  927.     vimmenu_T   *menu;
  928.  
  929.     if (toolBar == (Widget)0)
  930.     return;
  931.  
  932.     menu = gui_find_menu((char_u *)"ToolBar");
  933.     if (menu != NULL)
  934.     gui_mch_submenu_change(menu, FALSE);
  935. #  endif
  936. }
  937.  
  938.     void
  939. gui_mch_new_tooltip_colors()
  940. {
  941. # ifdef FEAT_TOOLBAR
  942.     vimmenu_T   *menu;
  943.  
  944.     if (toolBar == (Widget)0)
  945.     return;
  946.  
  947.     menu = gui_find_menu((char_u *)"ToolBar");
  948.     if (menu != NULL)
  949.     gui_mch_submenu_change(menu, TRUE);
  950. # endif
  951. }
  952. #endif
  953.  
  954.     static void
  955. gui_mch_submenu_change(menu, colors)
  956.     vimmenu_T    *menu;
  957.     int        colors;        /* TRUE for colors, FALSE for font */
  958. {
  959.     vimmenu_T    *mp;
  960.  
  961.     for (mp = menu; mp != NULL; mp = mp->next)
  962.     {
  963.     if (mp->id != (Widget)0)
  964.     {
  965.         if (colors)
  966.         {
  967.         gui_athena_menu_colors(mp->id);
  968. #ifdef FEAT_TOOLBAR
  969.         /* For a toolbar item: Free the pixmap and allocate a new one,
  970.          * so that the background color is right. */
  971.         if (mp->image != (Pixmap)0)
  972.         {
  973.             XFreePixmap(gui.dpy, mp->image);
  974.             get_toolbar_pixmap(mp, &mp->image, NULL);
  975.             if (mp->image != (Pixmap)0)
  976.             XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL);
  977.         }
  978.  
  979. # ifdef FEAT_BEVAL
  980.         /* If we have a tooltip, then we need to change it's colors */
  981.         if (mp->tip != NULL)
  982.         {
  983.             Arg args[2];
  984.  
  985.             args[0].name = XtNbackground;
  986.             args[0].value = gui.tooltip_bg_pixel;
  987.             args[1].name = XtNforeground;
  988.             args[1].value = gui.tooltip_fg_pixel;
  989.             XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
  990.         }
  991. # endif
  992. #endif
  993.         }
  994.         else
  995.         {
  996.         gui_athena_menu_font(mp->id);
  997. #ifdef FEAT_BEVAL
  998.         /* If we have a tooltip, then we need to change it's font */
  999.         /* Assume XtNinternational == True (in createBalloonEvalWindow)
  1000.          */
  1001.         if (mp->tip != NULL)
  1002.         {
  1003.             Arg args[1];
  1004.  
  1005.             args[0].name = XtNfontSet;
  1006.             args[0].value = (XtArgVal)gui.tooltip_fontset;
  1007.             XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
  1008.         }
  1009. #endif
  1010.         }
  1011.     }
  1012.  
  1013.     if (mp->children != NULL)
  1014.     {
  1015.         /* Set the colors/font for the tear off widget */
  1016.         if (mp->submenu_id != (Widget)0)
  1017.         {
  1018.         if (colors)
  1019.             gui_athena_menu_colors(mp->submenu_id);
  1020.         else
  1021.             gui_athena_menu_font(mp->submenu_id);
  1022.         }
  1023.         /* Set the colors for the children */
  1024.         gui_mch_submenu_change(mp->children, colors);
  1025.     }
  1026.     }
  1027. }
  1028.  
  1029. /*
  1030.  * Make a submenu name into a pullright name.
  1031.  * Replace '.' by '_', can't include '.' in the submenu name.
  1032.  */
  1033.     static char_u *
  1034. make_pull_name(name)
  1035.     char_u * name;
  1036. {
  1037.     char_u  *pname;
  1038.     char_u  *p;
  1039.  
  1040.     pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright"));
  1041.     if (pname != NULL)
  1042.     {
  1043.     strcat((char *)pname, "-pullright");
  1044.     while ((p = vim_strchr(pname, '.')) != NULL)
  1045.         *p = '_';
  1046.     }
  1047.     return pname;
  1048. }
  1049.  
  1050. /* ARGSUSED */
  1051.     void
  1052. gui_mch_add_menu_item(menu, idx)
  1053.     vimmenu_T    *menu;
  1054.     int        idx;
  1055. {
  1056.     vimmenu_T    *parent = menu->parent;
  1057.  
  1058.     a_cur_menu = menu;
  1059. # ifdef FEAT_TOOLBAR
  1060.     if (menu_is_toolbar(parent->name))
  1061.     {
  1062.     WidgetClass    type;
  1063.     int        n;
  1064.     Arg        args[21];
  1065.  
  1066.     n = 0;
  1067.     if (menu_is_separator(menu->name))
  1068.     {
  1069.         XtSetArg(args[n], XtNlabel, ""); n++;
  1070.         XtSetArg(args[n], XtNborderWidth, 0); n++;
  1071.     }
  1072.     else
  1073.     {
  1074.         get_toolbar_pixmap(menu, &menu->image, NULL);
  1075.         XtSetArg(args[n], XtNlabel, menu->dname); n++;
  1076.         XtSetArg(args[n], XtNinternalHeight, 1); n++;
  1077.         XtSetArg(args[n], XtNinternalWidth, 1); n++;
  1078.         XtSetArg(args[n], XtNborderWidth, 1); n++;
  1079.         if (menu->image != 0)
  1080.         XtSetArg(args[n], XtNbitmap, menu->image); n++;
  1081.     }
  1082.     XtSetArg(args[n], XtNhighlightThickness, 0); n++;
  1083.     type = commandWidgetClass;
  1084.     /* TODO: figure out the position in the toolbar?
  1085.      *       This currently works fine for the default toolbar, but
  1086.      *       what if we add/remove items during later runtime?
  1087.      */
  1088.  
  1089.     /* NOTE: "idx" isn't used here.  The position is calculated by
  1090.      *       athena_calculate_ins_pos().  The position it calculates
  1091.      *       should be equal to "idx".
  1092.      */
  1093.     /* TODO: Could we just store "idx" and use that as the child
  1094.      * placement?
  1095.      */
  1096.  
  1097.     if (menu->id == NULL)
  1098.     {
  1099.         menu->id = XtCreateManagedWidget((char *)menu->dname,
  1100.             type, toolBar, args, n);
  1101.         XtAddCallback(menu->id,
  1102.             XtNcallback, gui_x11_menu_cb, menu);
  1103.     }
  1104.     else
  1105.         XtSetValues(menu->id, args, n);
  1106.     gui_athena_menu_colors(menu->id);
  1107.  
  1108. #ifdef FEAT_BEVAL
  1109.     gui_mch_menu_set_tip(menu);
  1110. #endif
  1111.  
  1112.     menu->parent = parent;
  1113.     menu->submenu_id = NULL;
  1114.     if (!XtIsManaged(toolBar)
  1115.             && vim_strchr(p_go, GO_TOOLBAR) != NULL)
  1116.         gui_mch_show_toolbar(TRUE);
  1117.     gui.toolbar_height = gui_mch_compute_toolbar_height();
  1118.     return;
  1119.     } /* toolbar menu item */
  1120. # endif
  1121.  
  1122.     /* Add menu separator */
  1123.     if (menu_is_separator(menu->name))
  1124.     {
  1125.     menu->submenu_id = (Widget)0;
  1126.     menu->id = XtVaCreateManagedWidget((char *)menu->dname,
  1127.         smeLineObjectClass, parent->submenu_id,
  1128.         NULL);
  1129.     if (menu->id == (Widget)0)
  1130.         return;
  1131.     gui_athena_menu_colors(menu->id);
  1132.     }
  1133.     else
  1134.     {
  1135.     if (parent != NULL && parent->submenu_id != (Widget)0)
  1136.     {
  1137.         menu->submenu_id = (Widget)0;
  1138.         menu->id = XtVaCreateManagedWidget((char *)menu->dname,
  1139.             smeBSBObjectClass, parent->submenu_id,
  1140.             XtNlabel, menu->dname,
  1141. #ifdef FONTSET_ALWAYS
  1142.             XtNinternational,    True,
  1143. #endif
  1144.             NULL);
  1145.         if (menu->id == (Widget)0)
  1146.         return;
  1147.  
  1148.         /* If there are other "pulldown" items in this pane, then adjust
  1149.          * the right margin to accomodate the arrow pixmap, otherwise
  1150.          * the right margin will be the same as the left margin.
  1151.          */
  1152.         {
  1153.         Dimension   left_margin;
  1154.  
  1155.         XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL);
  1156.         XtVaSetValues(menu->id, XtNrightMargin,
  1157.             gui_athena_menu_has_submenus(parent->submenu_id, NULL) ?
  1158.                 puller_width :
  1159.                 left_margin,
  1160.             NULL);
  1161.         }
  1162.  
  1163.         gui_athena_menu_colors(menu->id);
  1164.         gui_athena_menu_font(menu->id);
  1165.         XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
  1166.             (XtPointer)menu);
  1167.     }
  1168.     }
  1169.     a_cur_menu = NULL;
  1170. }
  1171.  
  1172. #if defined(FEAT_TOOLBAR) || defined(PROTO)
  1173.     void
  1174. gui_mch_show_toolbar(int showit)
  1175. {
  1176.     Cardinal    numChildren;        /* how many children toolBar has */
  1177.  
  1178.     if (toolBar == (Widget)0)
  1179.     return;
  1180.     XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL);
  1181.     if (showit && numChildren > 0)
  1182.     {
  1183.     /* Assume that we want to show the toolbar if p_toolbar contains valid
  1184.      * option settings, therefore p_toolbar must not be NULL.
  1185.      */
  1186.     WidgetList  children;
  1187.  
  1188.     XtVaGetValues(toolBar, XtNchildren, &children, NULL);
  1189.     {
  1190.         void    (*action)(BalloonEval *);
  1191.         int        text = 0;
  1192.  
  1193.         if (strstr((const char *)p_toolbar, "tooltips"))
  1194.         action = &gui_mch_enable_beval_area;
  1195.         else
  1196.         action = &gui_mch_disable_beval_area;
  1197.         if (strstr((const char *)p_toolbar, "text"))
  1198.         text = 1;
  1199.         else if (strstr((const char *)p_toolbar, "icons"))
  1200.         text = -1;
  1201.         if (text != 0)
  1202.         {
  1203.         vimmenu_T   *toolbar;
  1204.         vimmenu_T   *cur;
  1205.  
  1206.         for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
  1207.             if (menu_is_toolbar(toolbar->dname))
  1208.             break;
  1209.         /* Assumption: toolbar is NULL if there is no toolbar,
  1210.          *           otherwise it contains the toolbar menu structure.
  1211.          *
  1212.          * Assumption: "numChildren" == the number of items in the list
  1213.          *           of items beginning with toolbar->children.
  1214.          */
  1215.         if (toolbar)
  1216.         {
  1217.             for (cur = toolbar->children; cur; cur = cur->next)
  1218.             {
  1219.             Arg        args[2];
  1220.             int        n = 0;
  1221.  
  1222.             /* Enable/Disable tooltip (OK to enable while currently
  1223.              * enabled)
  1224.              */
  1225.             if (cur->tip != NULL)
  1226.                 (*action)(cur->tip);
  1227.             if (text == 1)
  1228.             {
  1229.                 XtSetArg(args[n], XtNbitmap, None);
  1230.                 n++;
  1231.                 XtSetArg(args[n], XtNlabel,
  1232.                     menu_is_separator(cur->name) ? "" :
  1233.                     (char *)cur->dname);
  1234.                 n++;
  1235.             }
  1236.             else
  1237.             {
  1238.                 XtSetArg(args[n], XtNbitmap, cur->image);
  1239.                 n++;
  1240.                 XtSetArg(args[n], XtNlabel, (cur->image == None) ?
  1241.                     menu_is_separator(cur->name) ?
  1242.                     "" :
  1243.                     (char *)cur->dname
  1244.                     :
  1245.                     (char *)None);
  1246.                 n++;
  1247.             }
  1248.             if (cur->id != NULL)
  1249.             {
  1250.                 XtUnmanageChild(cur->id);
  1251.                 XtSetValues(cur->id, args, n);
  1252.                 XtManageChild(cur->id);
  1253.             }
  1254.             }
  1255.         }
  1256.         }
  1257.     }
  1258.     gui.toolbar_height = gui_mch_compute_toolbar_height();
  1259.     XtManageChild(toolBar);
  1260.     if (XtIsManaged(menuBar))
  1261.     {
  1262.         XtVaSetValues(textArea,
  1263.             XtNvertDistance,    gui.toolbar_height + gui.menu_height,
  1264.             NULL);
  1265.         XtVaSetValues(toolBar,
  1266.             XtNvertDistance,    gui.menu_height,
  1267.             NULL);
  1268.     }
  1269.     else
  1270.     {
  1271.         XtVaSetValues(textArea,
  1272.             XtNvertDistance,    gui.toolbar_height,
  1273.             NULL);
  1274.         XtVaSetValues(toolBar,
  1275.             XtNvertDistance,    0,
  1276.             NULL);
  1277.     }
  1278.     }
  1279.     else
  1280.     {
  1281.     gui.toolbar_height = 0;
  1282.     if (XtIsManaged(menuBar))
  1283.         XtVaSetValues(textArea,
  1284.         XtNvertDistance,    gui.menu_height,
  1285.         NULL);
  1286.     else
  1287.         XtVaSetValues(textArea,
  1288.         XtNvertDistance,    0,
  1289.         NULL);
  1290.  
  1291.     XtUnmanageChild(toolBar);
  1292.     }
  1293.     gui_set_shellsize(FALSE, FALSE);
  1294. }
  1295.  
  1296.  
  1297.     int
  1298. gui_mch_compute_toolbar_height()
  1299. {
  1300.     Dimension    height;            /* total Toolbar height */
  1301.     Dimension    whgt;            /* height of each widget */
  1302.     Dimension    marginHeight;        /* XmNmarginHeight of toolBar */
  1303.     Dimension    shadowThickness;    /* thickness of Xtparent(toolBar) */
  1304.     WidgetList    children;        /* list of toolBar's children */
  1305.     Cardinal    numChildren;        /* how many children toolBar has */
  1306.     int        i;
  1307.  
  1308.     height = 0;
  1309.     shadowThickness = 0;
  1310.     marginHeight = 0;
  1311.     if (toolBar != (Widget)0)
  1312.     {
  1313.     XtVaGetValues(toolBar,
  1314.         XtNborderWidth,        &shadowThickness,
  1315.         XtNvSpace,        &marginHeight,
  1316.         XtNchildren,        &children,
  1317.         XtNnumChildren,        &numChildren,
  1318.         NULL);
  1319.     for (i = 0; i < numChildren; i++)
  1320.     {
  1321.         whgt = 0;
  1322.  
  1323.         XtVaGetValues(children[i], XtNheight, &whgt, NULL);
  1324.         if (height < whgt)
  1325.         height = whgt;
  1326.     }
  1327.     }
  1328.  
  1329.     return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
  1330. }
  1331.  
  1332.     void
  1333. gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp)
  1334.     Pixel    *bgp;
  1335.     Pixel    *fgp;
  1336.     Pixel       *bsp;
  1337.     Pixel    *tsp;
  1338.     Pixel    *hsp;
  1339. {
  1340.     XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL);
  1341.     *bsp = *bgp;
  1342.     *tsp = *fgp;
  1343.     *hsp = *tsp;
  1344. }
  1345. #endif
  1346.  
  1347.  
  1348. /* ARGSUSED */
  1349.     void
  1350. gui_mch_toggle_tearoffs(enable)
  1351.     int        enable;
  1352. {
  1353.     /* no tearoff menus */
  1354. }
  1355.  
  1356.     void
  1357. gui_mch_new_menu_colors()
  1358. {
  1359.     if (menuBar == (Widget)0)
  1360.     return;
  1361.     if (gui.menu_fg_pixel != INVALCOLOR)
  1362.     XtVaSetValues(menuBar, XtNborderColor,    gui.menu_fg_pixel, NULL);
  1363.     gui_athena_menu_colors(menuBar);
  1364. #ifdef FEAT_TOOLBAR
  1365.     gui_athena_menu_colors(toolBar);
  1366. #endif
  1367.  
  1368.     gui_mch_submenu_change(root_menu, TRUE);
  1369. }
  1370.  
  1371. /*
  1372.  * Destroy the machine specific menu widget.
  1373.  */
  1374.     void
  1375. gui_mch_destroy_menu(menu)
  1376.     vimmenu_T *menu;
  1377. {
  1378.     Widget    parent;
  1379.  
  1380.     /* There is no item for the toolbar. */
  1381.     if (menu->id == (Widget)0)
  1382.     return;
  1383.  
  1384.     parent = XtParent(menu->id);
  1385.  
  1386.     /* When removing the last "pulldown" menu item from a pane, adjust the
  1387.      * right margins of the remaining widgets.
  1388.      */
  1389.     if (menu->submenu_id != (Widget)0)
  1390.     {
  1391.     /* Go through the menu items in the parent of this item and
  1392.      * adjust their margins, if necessary.
  1393.      * This takes care of the case when we delete the last menu item in a
  1394.      * pane that has a submenu.  In this case, there will be no arrow
  1395.      * pixmaps shown anymore.
  1396.      */
  1397.     {
  1398.         WidgetList  children;
  1399.         Cardinal    num_children;
  1400.         int        i;
  1401.         Dimension    right_margin = 0;
  1402.         Boolean    get_left_margin = False;
  1403.  
  1404.         XtVaGetValues(parent, XtNchildren, &children,
  1405.                   XtNnumChildren, &num_children,
  1406.                   NULL);
  1407.         if (gui_athena_menu_has_submenus(parent, menu->id))
  1408.         right_margin = puller_width;
  1409.         else
  1410.         get_left_margin = True;
  1411.  
  1412.         for (i = 0; i < num_children; ++i)
  1413.         {
  1414.         if (children[i] == menu->id)
  1415.             continue;
  1416.         if (get_left_margin == True)
  1417.         {
  1418.             Dimension left_margin;
  1419.  
  1420.             XtVaGetValues(children[i], XtNleftMargin, &left_margin,
  1421.                   NULL);
  1422.             XtVaSetValues(children[i], XtNrightMargin, left_margin,
  1423.                   NULL);
  1424.         }
  1425.         else
  1426.             XtVaSetValues(children[i], XtNrightMargin, right_margin,
  1427.                   NULL);
  1428.         }
  1429.     }
  1430.     }
  1431.     /* Please be sure to destroy the parent widget first (i.e. menu->id).
  1432.      *
  1433.      * This code should be basically identical to that in the file gui_motif.c
  1434.      * because they are both Xt based.
  1435.      */
  1436.     if (menu->id != (Widget)0)
  1437.     {
  1438.     Cardinal    num_children;
  1439.     Dimension   height, space, border;
  1440.  
  1441.     XtVaGetValues(menuBar,
  1442.         XtNvSpace,    &space,
  1443.         XtNborderWidth, &border,
  1444.         NULL);
  1445.     XtVaGetValues(menu->id,
  1446.         XtNheight,    &height,
  1447.         NULL);
  1448. #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
  1449.     if (parent == toolBar && menu->tip != NULL)
  1450.     {
  1451.         /* We try to destroy this before the actual menu, because there are
  1452.          * callbacks, etc. that will be unregistered during the tooltip
  1453.          * destruction.
  1454.          *
  1455.          * If you call "gui_mch_destroy_beval_area()" after destroying
  1456.          * menu->id, then the tooltip's window will have already been
  1457.          * deallocated by Xt, and unknown behaviour will ensue (probably
  1458.          * a core dump).
  1459.          */
  1460.         gui_mch_destroy_beval_area(menu->tip);
  1461.         menu->tip = NULL;
  1462.     }
  1463. #endif
  1464.     /*
  1465.      * This is a hack to stop the Athena simpleMenuWidget from getting a
  1466.      * BadValue error when a menu's last child is destroyed. We check to
  1467.      * see if this is the last child and if so, don't delete it. The parent
  1468.      * will be deleted soon anyway, and it will delete it's children like
  1469.      * all good widgets do.
  1470.      */
  1471.     /* NOTE: The cause of the BadValue X Protocol Error is because when the
  1472.      * last child is destroyed, it is first unmanaged, thus causing a
  1473.      * geometry resize request from the parent Shell widget.
  1474.      * Since the Shell widget has no more children, it is resized to have
  1475.      * width/height of 0.  XConfigureWindow() is then called with the
  1476.      * width/height of 0, which generates the BadValue.
  1477.      *
  1478.      * This happens in phase two of the widget destruction process.
  1479.      */
  1480.     {
  1481.         if (parent != menuBar
  1482. #ifdef FEAT_TOOLBAR
  1483.             && parent != toolBar
  1484. #endif
  1485.             )
  1486.         {
  1487.         XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
  1488.         if (num_children > 1)
  1489.             XtDestroyWidget(menu->id);
  1490.         }
  1491.         else
  1492.         XtDestroyWidget(menu->id);
  1493.         menu->id = (Widget)0;
  1494.     }
  1495.  
  1496.     if (parent == menuBar)
  1497.     {
  1498.         if (!gui.menu_height_fixed)
  1499.         gui.menu_height = height + 2 * (space + border);
  1500.     }
  1501. #ifdef FEAT_TOOLBAR
  1502.     else if (parent == toolBar)
  1503.     {
  1504.         /* When removing last toolbar item, don't display the toolbar. */
  1505.         XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL);
  1506.         if (num_children == 0)
  1507.         gui_mch_show_toolbar(FALSE);
  1508.         else
  1509.         gui.toolbar_height = gui_mch_compute_toolbar_height();
  1510.     }
  1511. #endif
  1512.     }
  1513.     if (menu->submenu_id != (Widget)0)
  1514.     {
  1515.     XtDestroyWidget(menu->submenu_id);
  1516.     menu->submenu_id = (Widget)0;
  1517.     }
  1518. }
  1519.  
  1520. /*ARGSUSED*/
  1521.     static void
  1522. gui_athena_menu_timeout(client_data, id)
  1523.     XtPointer        client_data;
  1524.     XtIntervalId    *id;
  1525. {
  1526.     Widget  w = (Widget)client_data;
  1527.     Widget  popup;
  1528.  
  1529.     timer = 0;
  1530.     if (XtIsSubclass(w,smeBSBObjectClass))
  1531.     {
  1532.     Pixmap p;
  1533.  
  1534.     XtVaGetValues(w, XtNrightBitmap, &p, NULL);
  1535.     if ((p != None) && (p != XtUnspecifiedPixmap))
  1536.     {
  1537.         /* We are dealing with an item that has a submenu */
  1538.         popup = get_popup_entry(XtParent(w));
  1539.         if (popup == (Widget)0)
  1540.         return;
  1541.         XtPopup(popup, XtGrabNonexclusive);
  1542.     }
  1543.     }
  1544. }
  1545.  
  1546. /* This routine is used to calculate the position (in screen coordinates)
  1547.  * where a submenu should appear relative to the menu entry that popped it
  1548.  * up.  It should appear even with and just slightly to the left of the
  1549.  * rightmost end of the menu entry that caused the popup.
  1550.  *
  1551.  * This is called when XtPopup() is called.
  1552.  */
  1553. /*ARGSUSED*/
  1554.     static void
  1555. gui_athena_popup_callback(w, client_data, call_data)
  1556.     Widget    w;
  1557.     XtPointer    client_data;
  1558.     XtPointer    call_data;
  1559. {
  1560.     /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
  1561.     vimmenu_T    *menu = (vimmenu_T *)client_data;
  1562.     Dimension    width;
  1563.     Position    root_x, root_y;
  1564.  
  1565.     /* First, popdown any siblings that may have menus popped up */
  1566.     {
  1567.     vimmenu_T *i;
  1568.  
  1569.     for (i = menu->parent->children; i != NULL; i = i->next)
  1570.     {
  1571.         if (i->submenu_id != NULL && XtIsManaged(i->submenu_id))
  1572.         XtPopdown(i->submenu_id);
  1573.     }
  1574.     }
  1575.     XtVaGetValues(XtParent(w),
  1576.           XtNwidth,   &width,
  1577.           NULL);
  1578.     /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */
  1579.     /* i.e. This IS the active entry */
  1580.     XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y);
  1581.     XtVaSetValues(w, XtNx, root_x,
  1582.              XtNy, root_y,
  1583.              NULL);
  1584. }
  1585.  
  1586. /* ARGSUSED */
  1587.     static void
  1588. gui_athena_popdown_submenus_action(w, event, args, nargs)
  1589.     Widget    w;
  1590.     XEvent    *event;
  1591.     String    *args;
  1592.     Cardinal    *nargs;
  1593. {
  1594.     WidgetList    children;
  1595.     Cardinal    num_children;
  1596.  
  1597.     XtVaGetValues(w, XtNchildren, &children,
  1598.              XtNnumChildren, &num_children,
  1599.              NULL);
  1600.     for (; num_children > 0; --num_children)
  1601.     {
  1602.     Widget child = children[num_children - 1];
  1603.  
  1604.     if (has_submenu(child))
  1605.     {
  1606.         Widget temp_w;
  1607.  
  1608.         temp_w = submenu_widget(child);
  1609.         gui_athena_popdown_submenus_action(temp_w,event,args,nargs);
  1610.         XtPopdown(temp_w);
  1611.     }
  1612.     }
  1613. }
  1614.  
  1615. /* Used to determine if the given widget has a submenu that can be popped up. */
  1616.     static Boolean
  1617. has_submenu(widget)
  1618.     Widget  widget;
  1619. {
  1620.     if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass))
  1621.     {
  1622.     Pixmap p;
  1623.  
  1624.     XtVaGetValues(widget, XtNrightBitmap, &p, NULL);
  1625.     if ((p != None) && (p != XtUnspecifiedPixmap))
  1626.         return True;
  1627.     }
  1628.     return False;
  1629. }
  1630.  
  1631. /* ARGSUSED */
  1632.     static void
  1633. gui_athena_delayed_arm_action(w, event, args, nargs)
  1634.     Widget    w;
  1635.     XEvent    *event;
  1636.     String    *args;
  1637.     Cardinal    *nargs;
  1638. {
  1639.     Dimension    width, height;
  1640.  
  1641.     if (event->type != MotionNotify)
  1642.     return;
  1643.  
  1644.     XtVaGetValues(w,
  1645.     XtNwidth,   &width,
  1646.     XtNheight,  &height,
  1647.     NULL);
  1648.  
  1649.     if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
  1650.     return;
  1651.  
  1652.     {
  1653.     static Widget        previous_active_widget = NULL;
  1654.     Widget            current;
  1655.  
  1656.     current = XawSimpleMenuGetActiveEntry(w);
  1657.     if (current != previous_active_widget)
  1658.     {
  1659.         if (timer)
  1660.         {
  1661.         /* If the timeout hasn't been triggered, remove it */
  1662.         XtRemoveTimeOut(timer);
  1663.         }
  1664.         gui_athena_popdown_submenus_action(w,event,args,nargs);
  1665.         if (has_submenu(current))
  1666.         {
  1667.         XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L,
  1668.                 gui_athena_menu_timeout,
  1669.                 (XtPointer)current);
  1670.         }
  1671.         previous_active_widget = current;
  1672.     }
  1673.     }
  1674. }
  1675.  
  1676.     static Widget
  1677. get_popup_entry(w)
  1678.     Widget  w;
  1679. {
  1680.     Widget    menuw;
  1681.  
  1682.     /* Get the active entry for the current menu */
  1683.     if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0)
  1684.     return NULL;
  1685.  
  1686.     return submenu_widget(menuw);
  1687. }
  1688.  
  1689. /* Given the widget that has been determined to have a submenu, return the submenu widget
  1690.  * that is to be popped up.
  1691.  */
  1692.     static Widget
  1693. submenu_widget(widget)
  1694.     Widget  widget;
  1695. {
  1696.     /* Precondition: has_submenu(widget) == True
  1697.      *        XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
  1698.      */
  1699.  
  1700.     char_u    *pullright_name;
  1701.     Widget    popup;
  1702.  
  1703.     pullright_name = make_pull_name((char_u *)XtName(widget));
  1704.     popup = XtNameToWidget(XtParent(widget), (char *)pullright_name);
  1705.     vim_free(pullright_name);
  1706.  
  1707.     return popup;
  1708.     /* Postcondition: (popup != NULL) implies
  1709.      * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
  1710. }
  1711.  
  1712. /* ARGSUSED */
  1713.     void
  1714. gui_mch_show_popupmenu(menu)
  1715.     vimmenu_T *menu;
  1716. {
  1717.     int        rootx, rooty, winx, winy;
  1718.     Window    root, child;
  1719.     unsigned int mask;
  1720.  
  1721.     if (menu->submenu_id == (Widget)0)
  1722.     return;
  1723.  
  1724.     /* Position the popup menu at the pointer */
  1725.     if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child,
  1726.         &rootx, &rooty, &winx, &winy, &mask))
  1727.     {
  1728.     rootx -= 30;
  1729.     if (rootx < 0)
  1730.         rootx = 0;
  1731.     rooty -= 5;
  1732.     if (rooty < 0)
  1733.         rooty = 0;
  1734.     XtVaSetValues(menu->submenu_id,
  1735.         XtNx, rootx,
  1736.         XtNy, rooty,
  1737.         NULL);
  1738.     }
  1739.  
  1740.     XtOverrideTranslations(menu->submenu_id, popupTrans);
  1741.     XtPopupSpringLoaded(menu->submenu_id);
  1742. }
  1743.  
  1744. #endif /* FEAT_MENU */
  1745.  
  1746. /*
  1747.  * Set the menu and scrollbar colors to their default values.
  1748.  */
  1749.     void
  1750. gui_mch_def_colors()
  1751. {
  1752.     /*
  1753.      * Get the colors ourselves.  Using the automatic conversion doesn't
  1754.      * handle looking for approximate colors.
  1755.      */
  1756.     if (gui.in_use)
  1757.     {
  1758.     gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
  1759.     gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
  1760.     gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
  1761.     gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
  1762. #ifdef FEAT_BEVAL
  1763.     gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
  1764.     gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
  1765. #endif
  1766.     }
  1767. }
  1768.  
  1769.  
  1770. /*
  1771.  * Scrollbar stuff.
  1772.  */
  1773.  
  1774.     void
  1775. gui_mch_set_scrollbar_thumb(sb, val, size, max)
  1776.     scrollbar_T    *sb;
  1777.     long    val;
  1778.     long    size;
  1779.     long    max;
  1780. {
  1781.     double    v, s;
  1782.  
  1783.     if (sb->id == (Widget)0)
  1784.     return;
  1785.  
  1786.     /*
  1787.      * Athena scrollbar must go from 0.0 to 1.0.
  1788.      */
  1789.     if (max == 0)
  1790.     {
  1791.     /* So you can't scroll it at all (normally it scrolls past end) */
  1792. #ifdef FEAT_GUI_NEXTAW
  1793.     XawScrollbarSetThumb(sb->id, 0.0, 1.0);
  1794. #else
  1795.     vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
  1796. #endif
  1797.     }
  1798.     else
  1799.     {
  1800.     v = (double)val / (double)(max + 1);
  1801.     s = (double)size / (double)(max + 1);
  1802. #ifdef FEAT_GUI_NEXTAW
  1803.     XawScrollbarSetThumb(sb->id, v, s);
  1804. #else
  1805.     vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
  1806. #endif
  1807.     }
  1808. }
  1809.  
  1810.     void
  1811. gui_mch_set_scrollbar_pos(sb, x, y, w, h)
  1812.     scrollbar_T *sb;
  1813.     int        x;
  1814.     int        y;
  1815.     int        w;
  1816.     int        h;
  1817. {
  1818.     if (sb->id == (Widget)0)
  1819.     return;
  1820.  
  1821.     XtUnmanageChild(sb->id);
  1822.     XtVaSetValues(sb->id,
  1823.           XtNhorizDistance, x,
  1824.           XtNvertDistance, y,
  1825.           XtNwidth, w,
  1826.           XtNheight, h,
  1827.           NULL);
  1828.     XtManageChild(sb->id);
  1829. }
  1830.  
  1831.     void
  1832. gui_mch_enable_scrollbar(sb, flag)
  1833.     scrollbar_T    *sb;
  1834.     int        flag;
  1835. {
  1836.     if (sb->id != (Widget)0)
  1837.     {
  1838.     if (flag)
  1839.         XtManageChild(sb->id);
  1840.     else
  1841.         XtUnmanageChild(sb->id);
  1842.     }
  1843. }
  1844.  
  1845.     void
  1846. gui_mch_create_scrollbar(sb, orient)
  1847.     scrollbar_T *sb;
  1848.     int        orient;    /* SBAR_VERT or SBAR_HORIZ */
  1849. {
  1850.     sb->id = XtVaCreateWidget("scrollBar",
  1851. #ifdef FEAT_GUI_NEXTAW
  1852.         scrollbarWidgetClass, vimForm,
  1853. #else
  1854.         vim_scrollbarWidgetClass, vimForm,
  1855. #endif
  1856.         XtNresizable,   True,
  1857.         XtNtop,        XtChainTop,
  1858.         XtNbottom,        XtChainTop,
  1859.         XtNleft,        XtChainLeft,
  1860.         XtNright,        XtChainLeft,
  1861.         XtNborderWidth, 0,
  1862.         XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
  1863.                           : XtorientHorizontal,
  1864.         XtNforeground, gui.scroll_fg_pixel,
  1865.         XtNbackground, gui.scroll_bg_pixel,
  1866.         NULL);
  1867.     if (sb->id == (Widget)0)
  1868.     return;
  1869.  
  1870.     XtAddCallback(sb->id, XtNjumpProc,
  1871.           gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
  1872.     XtAddCallback(sb->id, XtNscrollProc,
  1873.           gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
  1874.  
  1875. #ifdef FEAT_GUI_NEXTAW
  1876.     XawScrollbarSetThumb(sb->id, 0.0, 1.0);
  1877. #else
  1878.     vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
  1879. #endif
  1880. }
  1881.  
  1882. #if defined(FEAT_WINDOWS) || defined(PROTO)
  1883.     void
  1884. gui_mch_destroy_scrollbar(sb)
  1885.     scrollbar_T *sb;
  1886. {
  1887.     if (sb->id != (Widget)0)
  1888.     XtDestroyWidget(sb->id);
  1889. }
  1890. #endif
  1891.  
  1892.     void
  1893. gui_mch_set_scrollbar_colors(sb)
  1894.     scrollbar_T *sb;
  1895. {
  1896.     if (sb->id != (Widget)0)
  1897.     XtVaSetValues(sb->id,
  1898.         XtNforeground, gui.scroll_fg_pixel,
  1899.         XtNbackground, gui.scroll_bg_pixel,
  1900.         NULL);
  1901.  
  1902.     /* This is needed for the rectangle below the vertical scrollbars. */
  1903.     if (sb == &gui.bottom_sbar && vimForm != (Widget)0)
  1904.     gui_athena_scroll_colors(vimForm);
  1905. }
  1906.  
  1907. /*
  1908.  * Miscellaneous stuff:
  1909.  */
  1910.     Window
  1911. gui_x11_get_wid()
  1912. {
  1913.     return XtWindow(textArea);
  1914. }
  1915.  
  1916. #if defined(FEAT_BROWSE) || defined(PROTO)
  1917. /*
  1918.  * Put up a file requester.
  1919.  * Returns the selected name in allocated memory, or NULL for Cancel.
  1920.  */
  1921. /* ARGSUSED */
  1922.     char_u *
  1923. gui_mch_browse(saving, title, dflt, ext, initdir, filter)
  1924.     int        saving;        /* select file to write */
  1925.     char_u    *title;        /* not used (title for the window) */
  1926.     char_u    *dflt;        /* not used (default name) */
  1927.     char_u    *ext;        /* not used (extension added) */
  1928.     char_u    *initdir;    /* initial directory, NULL for current dir */
  1929.     char_u    *filter;    /* not used (file name filter) */
  1930. {
  1931.     Position x, y;
  1932.     char_u    dirbuf[MAXPATHL];
  1933.  
  1934.     /* Concatenate "initdir" and "dflt". */
  1935.     if (initdir == NULL || *initdir == NUL)
  1936.     mch_dirname(dirbuf, MAXPATHL);
  1937.     else if (STRLEN(initdir) + 2 < MAXPATHL)
  1938.     STRCPY(dirbuf, initdir);
  1939.     else
  1940.     dirbuf[0] = NUL;
  1941.     if (dflt != NULL && *dflt != NUL
  1942.                   && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
  1943.     {
  1944.     add_pathsep(dirbuf);
  1945.     STRCAT(dirbuf, dflt);
  1946.     }
  1947.  
  1948.     /* Position the file selector just below the menubar */
  1949.     XtTranslateCoords(vimShell, (Position)0, (Position)
  1950. #ifdef FEAT_MENU
  1951.         gui.menu_height
  1952. #else
  1953.         0
  1954. #endif
  1955.         , &x, &y);
  1956.     return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf,
  1957.           NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel,
  1958.           gui.scroll_fg_pixel, gui.scroll_bg_pixel);
  1959. }
  1960. #endif
  1961.  
  1962. #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
  1963.  
  1964. static int    dialogStatus;
  1965. static Atom    dialogatom;
  1966.  
  1967. static void keyhit_callback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
  1968. static void butproc __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
  1969. static void dialog_wm_handler __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *dum));
  1970.  
  1971. /*
  1972.  * Callback function for the textfield.  When CR is hit this works like
  1973.  * hitting the "OK" button, ESC like "Cancel".
  1974.  */
  1975. /* ARGSUSED */
  1976.     static void
  1977. keyhit_callback(w, client_data, event, cont)
  1978.     Widget        w;
  1979.     XtPointer        client_data;
  1980.     XEvent        *event;
  1981.     Boolean        *cont;
  1982. {
  1983.     char    buf[2];
  1984.  
  1985.     if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1)
  1986.     {
  1987.     if (*buf == CR)
  1988.         dialogStatus = 1;
  1989.     else if (*buf == ESC)
  1990.         dialogStatus = 0;
  1991.     }
  1992. }
  1993.  
  1994. /* ARGSUSED */
  1995.     static void
  1996. butproc(w, client_data, call_data)
  1997.     Widget    w;
  1998.     XtPointer    client_data;
  1999.     XtPointer    call_data;
  2000. {
  2001.     dialogStatus = (int)(long)client_data + 1;
  2002. }
  2003.  
  2004. /*
  2005.  * Function called when dialog window closed.
  2006.  */
  2007. /*ARGSUSED*/
  2008.     static void
  2009. dialog_wm_handler(w, client_data, event, dum)
  2010.     Widget    w;
  2011.     XtPointer    client_data;
  2012.     XEvent    *event;
  2013.     Boolean    *dum;
  2014. {
  2015.     if (event->type == ClientMessage
  2016.         && ((XClientMessageEvent *)event)->data.l[0] == dialogatom)
  2017.     dialogStatus = 0;
  2018. }
  2019.  
  2020. /* ARGSUSED */
  2021.     int
  2022. gui_mch_dialog(type, title, message, buttons, dfltbutton, textfield)
  2023.     int        type;
  2024.     char_u    *title;
  2025.     char_u    *message;
  2026.     char_u    *buttons;
  2027.     int        dfltbutton;
  2028.     char_u    *textfield;
  2029. {
  2030.     char_u        *buts;
  2031.     char_u        *p, *next;
  2032.     XtAppContext    app;
  2033.     XEvent        event;
  2034.     Position        wd, hd;
  2035.     Position        wv, hv;
  2036.     Position        x, y;
  2037.     Widget        dialog;
  2038.     Widget        dialogshell;
  2039.     Widget        dialogmessage;
  2040.     Widget        dialogtextfield = 0;
  2041.     Widget        dialogButton;
  2042.     Widget        prev_dialogButton = NULL;
  2043.     int            butcount;
  2044.     int            vertical;
  2045.  
  2046.     if (title == NULL)
  2047.     title = (char_u *)_("Vim dialog");
  2048.     dialogStatus = -1;
  2049.  
  2050.     /* if our pointer is currently hidden, then we should show it. */
  2051.     gui_mch_mousehide(FALSE);
  2052.  
  2053.     /* Check 'v' flag in 'guioptions': vertical button placement. */
  2054.     vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
  2055.  
  2056.     /* The shell is created each time, to make sure it is resized properly */
  2057.     dialogshell = XtVaCreatePopupShell("dialogShell",
  2058.         transientShellWidgetClass, vimShell,
  2059.         XtNtitle, title,
  2060.         NULL);
  2061.     if (dialogshell == (Widget)0)
  2062.     goto error;
  2063.  
  2064.     dialog = XtVaCreateManagedWidget("dialog",
  2065.         formWidgetClass, dialogshell,
  2066.         XtNdefaultDistance, 20,
  2067.         NULL);
  2068.     if (dialog == (Widget)0)
  2069.     goto error;
  2070.     gui_athena_menu_colors(dialog);
  2071.     dialogmessage = XtVaCreateManagedWidget("dialogMessage",
  2072.         labelWidgetClass, dialog,
  2073.         XtNlabel, message,
  2074.         XtNtop, XtChainTop,
  2075.         XtNbottom, XtChainTop,
  2076.         XtNleft, XtChainLeft,
  2077.         XtNright, XtChainLeft,
  2078.         XtNresizable, True,
  2079.         XtNborderWidth, 0,
  2080.         NULL);
  2081.     gui_athena_menu_colors(dialogmessage);
  2082.  
  2083.     if (textfield != NULL)
  2084.     {
  2085.     dialogtextfield = XtVaCreateManagedWidget("textfield",
  2086.         asciiTextWidgetClass, dialog,
  2087.         XtNwidth, 400,
  2088.         XtNtop, XtChainTop,
  2089.         XtNbottom, XtChainTop,
  2090.         XtNleft, XtChainLeft,
  2091.         XtNright, XtChainRight,
  2092.         XtNfromVert, dialogmessage,
  2093.         XtNresizable, True,
  2094.         XtNstring, textfield,
  2095.         XtNlength, IOSIZE,
  2096.         XtNuseStringInPlace, True,
  2097.         XtNeditType, XawtextEdit,
  2098.         XtNwrap, XawtextWrapNever,
  2099.         XtNresize, XawtextResizeHeight,
  2100.         NULL);
  2101.     XtManageChild(dialogtextfield);
  2102.     XtAddEventHandler(dialogtextfield, KeyPressMask, False,
  2103.                 (XtEventHandler)keyhit_callback, (XtPointer)NULL);
  2104.     XawTextSetInsertionPoint(dialogtextfield,
  2105.                       (XawTextPosition)STRLEN(textfield));
  2106.     XtSetKeyboardFocus(dialog, dialogtextfield);
  2107.     }
  2108.  
  2109.     /* make a copy, so that we can insert NULs */
  2110.     buts = vim_strsave(buttons);
  2111.     if (buts == NULL)
  2112.     return -1;
  2113.  
  2114.     p = buts;
  2115.     for (butcount = 0; *p; ++butcount)
  2116.     {
  2117.     for (next = p; *next; ++next)
  2118.     {
  2119.         if (*next == DLG_HOTKEY_CHAR)
  2120.         mch_memmove(next, next + 1, STRLEN(next));
  2121.         if (*next == DLG_BUTTON_SEP)
  2122.         {
  2123.         *next++ = NUL;
  2124.         break;
  2125.         }
  2126.     }
  2127.     dialogButton = XtVaCreateManagedWidget("button",
  2128.         commandWidgetClass, dialog,
  2129.         XtNlabel, p,
  2130.         XtNtop, XtChainBottom,
  2131.         XtNbottom, XtChainBottom,
  2132.         XtNleft, XtChainLeft,
  2133.         XtNright, XtChainLeft,
  2134.         XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield,
  2135.         XtNvertDistance, vertical ? 4 : 20,
  2136.         XtNresizable, False,
  2137.         NULL);
  2138.     gui_athena_menu_colors(dialogButton);
  2139.     if (butcount > 0)
  2140.         XtVaSetValues(dialogButton,
  2141.             vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton,
  2142.             NULL);
  2143.  
  2144.     XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)butcount);
  2145.     p = next;
  2146.     prev_dialogButton = dialogButton;
  2147.     }
  2148.     vim_free(buts);
  2149.  
  2150.     XtRealizeWidget(dialogshell);
  2151.  
  2152.     /* Setup for catching the close-window event, don't let it close Vim! */
  2153.     dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
  2154.     XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1);
  2155.     XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL);
  2156.  
  2157.     XtVaGetValues(dialogshell,
  2158.         XtNwidth, &wd,
  2159.         XtNheight, &hd,
  2160.         NULL);
  2161.     XtVaGetValues(vimShell,
  2162.         XtNwidth, &wv,
  2163.         XtNheight, &hv,
  2164.         NULL);
  2165.     XtTranslateCoords(vimShell,
  2166.         (Position)((wv - wd) / 2),
  2167.         (Position)((hv - hd) / 2),
  2168.         &x, &y);
  2169.     if (x < 0)
  2170.     x = 0;
  2171.     if (y < 0)
  2172.     y = 0;
  2173.     XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL);
  2174.  
  2175.     /* Position the mouse pointer in the dialog, required for when focus
  2176.      * follows mouse. */
  2177.     XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40);
  2178.  
  2179.  
  2180.     app = XtWidgetToApplicationContext(dialogshell);
  2181.  
  2182.     XtPopup(dialogshell, XtGrabNonexclusive);
  2183.  
  2184.     while (1)
  2185.     {
  2186.     XtAppNextEvent(app, &event);
  2187.     XtDispatchEvent(&event);
  2188.     if (dialogStatus >= 0)
  2189.         break;
  2190.     }
  2191.  
  2192.     XtPopdown(dialogshell);
  2193.  
  2194.     if (textfield != NULL && dialogStatus < 0)
  2195.     *textfield = NUL;
  2196.  
  2197. error:
  2198.     XtDestroyWidget(dialogshell);
  2199.  
  2200.     return dialogStatus;
  2201. }
  2202. #endif
  2203.  
  2204. #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
  2205. /*
  2206.  * Set the colors of Widget "id" to the menu colors.
  2207.  */
  2208.     static void
  2209. gui_athena_menu_colors(id)
  2210.     Widget  id;
  2211. {
  2212.     if (gui.menu_bg_pixel != INVALCOLOR)
  2213.     XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL);
  2214.     if (gui.menu_fg_pixel != INVALCOLOR)
  2215.     XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL);
  2216. }
  2217. #endif
  2218.  
  2219. /*
  2220.  * Set the colors of Widget "id" to the scroll colors.
  2221.  */
  2222.     static void
  2223. gui_athena_scroll_colors(id)
  2224.     Widget  id;
  2225. {
  2226.     if (gui.scroll_bg_pixel != INVALCOLOR)
  2227.     XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL);
  2228.     if (gui.scroll_fg_pixel != INVALCOLOR)
  2229.     XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL);
  2230. }
  2231.