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_x11.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-24  |  88.3 KB  |  3,691 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.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  * See README.txt for an overview of the Vim source code.
  9.  */
  10. /*
  11.  * Common code for the Motif and Athena GUI.
  12.  * Not used for GTK.
  13.  */
  14.  
  15. #include <X11/keysym.h>
  16. #include <X11/Xatom.h>
  17. #include <X11/StringDefs.h>
  18. #include <X11/Intrinsic.h>
  19. #include <X11/Shell.h>
  20. #include <X11/cursorfont.h>
  21.  
  22. #include "vim.h"
  23.  
  24. /*
  25.  * For Workshop XpmP.h is preferred, because it makes the signs drawn with a
  26.  * transparent background instead of black.
  27.  */
  28. #if defined(HAVE_XM_XPMP_H) && defined(FEAT_GUI_MOTIF) \
  29.     && (!defined(HAVE_X11_XPM_H) || defined(FEAT_SUN_WORKSHOP))
  30. # include <Xm/XpmP.h>
  31. #else
  32. # ifdef HAVE_X11_XPM_H
  33. #  include <X11/xpm.h>
  34. # endif
  35. #endif
  36.  
  37. #ifdef FEAT_XFONTSET
  38. # ifdef X_LOCALE
  39. #  include <X11/Xlocale.h>
  40. # else
  41. #  include <locale.h>
  42. # endif
  43. #endif
  44.  
  45. #ifdef HAVE_X11_SUNKEYSYM_H
  46. # include <X11/Sunkeysym.h>
  47. #endif
  48.  
  49. #ifdef HAVE_X11_XMU_EDITRES_H
  50. # include <X11/Xmu/Editres.h>
  51. #endif
  52.  
  53. #ifdef FEAT_BEVAL_TIP
  54. # include "gui_beval.h"
  55. #endif
  56.  
  57. #define VIM_NAME    "vim"
  58. #define VIM_CLASS    "Vim"
  59.  
  60. /* Default resource values */
  61. #define DFLT_FONT        "7x13"
  62. #ifdef FONTSET_ALWAYS
  63. # define DFLT_MENU_FONT        XtDefaultFontSet
  64. #else
  65. # define DFLT_MENU_FONT        XtDefaultFont
  66. #endif
  67. #define DFLT_TOOLTIP_FONT    XtDefaultFontSet
  68.  
  69. #ifdef FEAT_GUI_ATHENA
  70. # define DFLT_MENU_BG_COLOR    "gray77"
  71. # define DFLT_MENU_FG_COLOR    "black"
  72. # define DFLT_SCROLL_BG_COLOR    "gray60"
  73. # define DFLT_SCROLL_FG_COLOR    "gray77"
  74. # define DFLT_TOOLTIP_BG_COLOR    "#ffffffff9191"
  75. # define DFLT_TOOLTIP_FG_COLOR    "#000000000000"
  76. #else
  77. /* use the default (CDE) colors */
  78. # define DFLT_MENU_BG_COLOR    ""
  79. # define DFLT_MENU_FG_COLOR    ""
  80. # define DFLT_SCROLL_BG_COLOR    ""
  81. # define DFLT_SCROLL_FG_COLOR    ""
  82. # define DFLT_TOOLTIP_BG_COLOR    "#ffffffff9191"
  83. # define DFLT_TOOLTIP_FG_COLOR    "#000000000000"
  84. #endif
  85.  
  86. Widget vimShell = (Widget)0;
  87.  
  88. static Atom   wm_atoms[2];    /* Window Manager Atoms */
  89. #define DELETE_WINDOW_IDX 0    /* index in wm_atoms[] for WM_DELETE_WINDOW */
  90. #define SAVE_YOURSELF_IDX 1    /* index in wm_atoms[] for WM_SAVE_YOURSELF */
  91.  
  92. #ifdef FEAT_XFONTSET
  93. /*
  94.  * We either draw with a fontset (when current_fontset != NULL) or with a
  95.  * normal font (current_fontset == NULL, use gui.text_gc and gui.back_gc).
  96.  */
  97. static XFontSet current_fontset = NULL;
  98.  
  99. #define XDrawString(dpy, win, gc, x, y, str, n) \
  100.     do \
  101.     { \
  102.         if (current_fontset != NULL) \
  103.         XmbDrawString(dpy, win, current_fontset, gc, x, y, str, n); \
  104.         else \
  105.         XDrawString(dpy, win, gc, x, y, str, n); \
  106.     } while (0)
  107.  
  108. #define XDrawString16(dpy, win, gc, x, y, str, n) \
  109.     do \
  110.     { \
  111.         if (current_fontset != NULL) \
  112.         XwcDrawString(dpy, win, current_fontset, gc, x, y, (wchar_t *)str, n); \
  113.         else \
  114.         XDrawString16(dpy, win, gc, x, y, str, n); \
  115.     } while (0)
  116.  
  117. static int check_fontset_sanity __ARGS((XFontSet fs));
  118. static int fontset_width __ARGS((XFontSet fs));
  119. static int fontset_ascent __ARGS((XFontSet fs));
  120. #endif
  121.  
  122. static guicolor_T    prev_fg_color = INVALCOLOR;
  123. static guicolor_T    prev_bg_color = INVALCOLOR;
  124.  
  125. #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  126. static XButtonPressedEvent last_mouse_event;
  127. #endif
  128.  
  129. static int find_closest_color __ARGS((Colormap colormap, XColor *colorPtr));
  130. static void gui_x11_timer_cb __ARGS((XtPointer timed_out, XtIntervalId *interval_id));
  131. static void gui_x11_visibility_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
  132. static void gui_x11_expose_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
  133. static void gui_x11_resize_window_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
  134. static void gui_x11_focus_change_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
  135. static void gui_x11_enter_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
  136. static void gui_x11_leave_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
  137. static void gui_x11_mouse_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
  138. #ifdef FEAT_SNIFF
  139. static void gui_x11_sniff_request_cb __ARGS((XtPointer closure, int *source, XtInputId *id));
  140. #endif
  141. static void gui_x11_check_copy_area __ARGS((void));
  142. #ifdef FEAT_CLIENTSERVER
  143. static void gui_x11_send_event_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
  144. #endif
  145. static void gui_x11_wm_protocol_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
  146. static void gui_x11_blink_cb __ARGS((XtPointer timed_out, XtIntervalId *interval_id));
  147. static Cursor gui_x11_create_blank_mouse __ARGS((void));
  148.  
  149.  
  150. /*
  151.  * Keycodes recognized by vim.
  152.  * NOTE: when changing this, the table in gui_gtk_x11.c probably needs the
  153.  * same change!
  154.  */
  155. static struct specialkey
  156. {
  157.     KeySym  key_sym;
  158.     char_u  vim_code0;
  159.     char_u  vim_code1;
  160. } special_keys[] =
  161. {
  162.     {XK_Up,        'k', 'u'},
  163.     {XK_Down,        'k', 'd'},
  164.     {XK_Left,        'k', 'l'},
  165.     {XK_Right,        'k', 'r'},
  166.  
  167.     {XK_F1,        'k', '1'},
  168.     {XK_F2,        'k', '2'},
  169.     {XK_F3,        'k', '3'},
  170.     {XK_F4,        'k', '4'},
  171.     {XK_F5,        'k', '5'},
  172.     {XK_F6,        'k', '6'},
  173.     {XK_F7,        'k', '7'},
  174.     {XK_F8,        'k', '8'},
  175.     {XK_F9,        'k', '9'},
  176.     {XK_F10,        'k', ';'},
  177.  
  178.     {XK_F11,        'F', '1'},
  179.     {XK_F12,        'F', '2'},
  180.     {XK_F13,        'F', '3'},
  181.     {XK_F14,        'F', '4'},
  182.     {XK_F15,        'F', '5'},
  183.     {XK_F16,        'F', '6'},
  184.     {XK_F17,        'F', '7'},
  185.     {XK_F18,        'F', '8'},
  186.     {XK_F19,        'F', '9'},
  187.     {XK_F20,        'F', 'A'},
  188.  
  189.     {XK_F21,        'F', 'B'},
  190.     {XK_F22,        'F', 'C'},
  191.     {XK_F23,        'F', 'D'},
  192.     {XK_F24,        'F', 'E'},
  193.     {XK_F25,        'F', 'F'},
  194.     {XK_F26,        'F', 'G'},
  195.     {XK_F27,        'F', 'H'},
  196.     {XK_F28,        'F', 'I'},
  197.     {XK_F29,        'F', 'J'},
  198.     {XK_F30,        'F', 'K'},
  199.  
  200.     {XK_F31,        'F', 'L'},
  201.     {XK_F32,        'F', 'M'},
  202.     {XK_F33,        'F', 'N'},
  203.     {XK_F34,        'F', 'O'},
  204.     {XK_F35,        'F', 'P'},    /* keysymdef.h defines up to F35 */
  205. #ifdef SunXK_F36
  206.     {SunXK_F36,        'F', 'Q'},
  207.     {SunXK_F37,        'F', 'R'},
  208. #endif
  209.  
  210.     {XK_Help,        '%', '1'},
  211.     {XK_Undo,        '&', '8'},
  212.     {XK_BackSpace,    'k', 'b'},
  213.     {XK_Insert,        'k', 'I'},
  214.     {XK_Delete,        'k', 'D'},
  215.     {XK_Home,        'k', 'h'},
  216.     {XK_End,        '@', '7'},
  217.     {XK_Prior,        'k', 'P'},
  218.     {XK_Next,        'k', 'N'},
  219.     {XK_Print,        '%', '9'},
  220.  
  221.     /* Keypad keys: */
  222. #ifdef XK_KP_Left
  223.     {XK_KP_Left,    'k', 'l'},
  224.     {XK_KP_Right,    'k', 'r'},
  225.     {XK_KP_Up,        'k', 'u'},
  226.     {XK_KP_Down,    'k', 'd'},
  227.     {XK_KP_Insert,    KS_EXTRA, (char_u)KE_KINS},
  228.     {XK_KP_Delete,    KS_EXTRA, (char_u)KE_KDEL},
  229.     {XK_KP_Home,    'K', '1'},
  230.     {XK_KP_End,        'K', '4'},
  231.     {XK_KP_Prior,    'K', '3'},
  232.     {XK_KP_Next,    'K', '5'},
  233.  
  234.     {XK_KP_Add,        'K', '6'},
  235.     {XK_KP_Subtract,    'K', '7'},
  236.     {XK_KP_Divide,    'K', '8'},
  237.     {XK_KP_Multiply,    'K', '9'},
  238.     {XK_KP_Enter,    'K', 'A'},
  239.     {XK_KP_Decimal,    'K', 'B'},
  240.  
  241.     {XK_KP_0,        'K', 'C'},
  242.     {XK_KP_1,        'K', 'D'},
  243.     {XK_KP_2,        'K', 'E'},
  244.     {XK_KP_3,        'K', 'F'},
  245.     {XK_KP_4,        'K', 'G'},
  246.     {XK_KP_5,        'K', 'H'},
  247.     {XK_KP_6,        'K', 'I'},
  248.     {XK_KP_7,        'K', 'J'},
  249.     {XK_KP_8,        'K', 'K'},
  250.     {XK_KP_9,        'K', 'L'},
  251. #endif
  252.  
  253.     /* End of list marker: */
  254.     {(KeySym)0,        0, 0}
  255. };
  256.  
  257. #define XtNboldFont        "boldFont"
  258. #define XtCBoldFont        "BoldFont"
  259. #define XtNitalicFont        "italicFont"
  260. #define XtCItalicFont        "ItalicFont"
  261. #define XtNboldItalicFont    "boldItalicFont"
  262. #define XtCBoldItalicFont    "BoldItalicFont"
  263. #define XtNscrollbarWidth    "scrollbarWidth"
  264. #define XtCScrollbarWidth    "ScrollbarWidth"
  265. #define XtNmenuHeight        "menuHeight"
  266. #define XtCMenuHeight        "MenuHeight"
  267. #define XtNmenuFont        "menuFont"
  268. #define XtCMenuFont        "MenuFont"
  269. #define XtNmenuFontSet        "menuFontSet"
  270. #define XtCMenuFontSet        "MenuFontSet"
  271.  
  272.  
  273. /* Resources for setting the foreground and background colors of menus */
  274. #define XtNmenuBackground    "menuBackground"
  275. #define XtCMenuBackground    "MenuBackground"
  276. #define XtNmenuForeground    "menuForeground"
  277. #define XtCMenuForeground    "MenuForeground"
  278.  
  279. /* Resources for setting the foreground and background colors of scrollbars */
  280. #define XtNscrollBackground    "scrollBackground"
  281. #define XtCScrollBackground    "ScrollBackground"
  282. #define XtNscrollForeground    "scrollForeground"
  283. #define XtCScrollForeground    "ScrollForeground"
  284.  
  285. /* Resources for setting the foreground and background colors of tooltip */
  286. #define XtNtooltipBackground    "tooltipBackground"
  287. #define XtCTooltipBackground    "TooltipBackground"
  288. #define XtNtooltipForeground    "tooltipForeground"
  289. #define XtCTooltipForeground    "TooltipForeground"
  290. #define XtNtooltipFont        "tooltipFont"
  291. #define XtCTooltipFont        "TooltipFont"
  292.  
  293. /*
  294.  * X Resources:
  295.  */
  296. static XtResource vim_resources[] =
  297. {
  298.     {
  299.     XtNforeground,
  300.     XtCForeground,
  301.     XtRPixel,
  302.     sizeof(Pixel),
  303.     XtOffsetOf(gui_T, def_norm_pixel),
  304.     XtRString,
  305.     XtDefaultForeground
  306.     },
  307.     {
  308.     XtNbackground,
  309.     XtCBackground,
  310.     XtRPixel,
  311.     sizeof(Pixel),
  312.     XtOffsetOf(gui_T, def_back_pixel),
  313.     XtRString,
  314.     XtDefaultBackground
  315.     },
  316.     {
  317.     XtNfont,
  318.     XtCFont,
  319.     XtRString,
  320.     sizeof(String *),
  321.     XtOffsetOf(gui_T, rsrc_font_name),
  322.     XtRImmediate,
  323.     XtDefaultFont
  324.     },
  325.     {
  326.     XtNboldFont,
  327.     XtCBoldFont,
  328.     XtRString,
  329.     sizeof(String *),
  330.     XtOffsetOf(gui_T, rsrc_bold_font_name),
  331.     XtRImmediate,
  332.     ""
  333.     },
  334.     {
  335.     XtNitalicFont,
  336.     XtCItalicFont,
  337.     XtRString,
  338.     sizeof(String *),
  339.     XtOffsetOf(gui_T, rsrc_ital_font_name),
  340.     XtRImmediate,
  341.     ""
  342.     },
  343.     {
  344.     XtNboldItalicFont,
  345.     XtCBoldItalicFont,
  346.     XtRString,
  347.     sizeof(String *),
  348.     XtOffsetOf(gui_T, rsrc_boldital_font_name),
  349.     XtRImmediate,
  350.     ""
  351.     },
  352.     {
  353.     XtNgeometry,
  354.     XtCGeometry,
  355.     XtRString,
  356.     sizeof(String *),
  357.     XtOffsetOf(gui_T, geom),
  358.     XtRImmediate,
  359.     ""
  360.     },
  361.     {
  362.     XtNreverseVideo,
  363.     XtCReverseVideo,
  364.     XtRBool,
  365.     sizeof(Bool),
  366.     XtOffsetOf(gui_T, rsrc_rev_video),
  367.     XtRImmediate,
  368.     (XtPointer)False
  369.     },
  370.     {
  371.     XtNborderWidth,
  372.     XtCBorderWidth,
  373.     XtRInt,
  374.     sizeof(int),
  375.     XtOffsetOf(gui_T, border_width),
  376.     XtRImmediate,
  377.     (XtPointer)2
  378.     },
  379.     {
  380.     XtNscrollbarWidth,
  381.     XtCScrollbarWidth,
  382.     XtRInt,
  383.     sizeof(int),
  384.     XtOffsetOf(gui_T, scrollbar_width),
  385.     XtRImmediate,
  386.     (XtPointer)SB_DEFAULT_WIDTH
  387.     },
  388. #ifdef FEAT_MENU
  389. # ifdef FEAT_GUI_ATHENA        /* with Motif the height is always computed */
  390.     {
  391.     XtNmenuHeight,
  392.     XtCMenuHeight,
  393.     XtRInt,
  394.     sizeof(int),
  395.     XtOffsetOf(gui_T, menu_height),
  396.     XtRImmediate,
  397.     (XtPointer)MENU_DEFAULT_HEIGHT        /* Should figure out at run time */
  398.     },
  399. # endif
  400.     {
  401. # ifdef FONTSET_ALWAYS
  402.     XtNmenuFontSet,
  403.     XtCMenuFontSet,
  404. #else
  405.     XtNmenuFont,
  406.     XtCMenuFont,
  407. #endif
  408.     XtRString,
  409.     sizeof(char *),
  410.     XtOffsetOf(gui_T, rsrc_menu_font_name),
  411.     XtRString,
  412.     DFLT_MENU_FONT
  413.     },
  414. #endif
  415.     {
  416.     XtNmenuForeground,
  417.     XtCMenuForeground,
  418.     XtRString,
  419.     sizeof(char *),
  420.     XtOffsetOf(gui_T, rsrc_menu_fg_name),
  421.     XtRString,
  422.     DFLT_MENU_FG_COLOR
  423.     },
  424.     {
  425.     XtNmenuBackground,
  426.     XtCMenuBackground,
  427.     XtRString,
  428.     sizeof(char *),
  429.     XtOffsetOf(gui_T, rsrc_menu_bg_name),
  430.     XtRString,
  431.     DFLT_MENU_BG_COLOR
  432.     },
  433.     {
  434.     XtNscrollForeground,
  435.     XtCScrollForeground,
  436.     XtRString,
  437.     sizeof(char *),
  438.     XtOffsetOf(gui_T, rsrc_scroll_fg_name),
  439.     XtRString,
  440.     DFLT_SCROLL_FG_COLOR
  441.     },
  442.     {
  443.     XtNscrollBackground,
  444.     XtCScrollBackground,
  445.     XtRString,
  446.     sizeof(char *),
  447.     XtOffsetOf(gui_T, rsrc_scroll_bg_name),
  448.     XtRString,
  449.     DFLT_SCROLL_BG_COLOR
  450.     },
  451. #ifdef FEAT_BEVAL
  452.     {
  453.     XtNtooltipForeground,
  454.     XtCTooltipForeground,
  455.     XtRString,
  456.     sizeof(char *),
  457.     XtOffsetOf(gui_T, rsrc_tooltip_fg_name),
  458.     XtRString,
  459.     DFLT_TOOLTIP_FG_COLOR
  460.     },
  461.     {
  462.     XtNtooltipBackground,
  463.     XtCTooltipBackground,
  464.     XtRString,
  465.     sizeof(char *),
  466.     XtOffsetOf(gui_T, rsrc_tooltip_bg_name),
  467.     XtRString,
  468.     DFLT_TOOLTIP_BG_COLOR
  469.     },
  470.     {
  471.     XtNtooltipFont,
  472.     XtCTooltipFont,
  473.     XtRString,
  474.     sizeof(char *),
  475.     XtOffsetOf(gui_T, rsrc_tooltip_font_name),
  476.     XtRString,
  477.     DFLT_TOOLTIP_FONT
  478.     },
  479.     /* This one isn't really needed, keep for Sun Workshop? */
  480.     {
  481.     "balloonEvalFontSet",
  482.     XtCFontSet,
  483.     XtRFontSet,
  484.     sizeof(XFontSet),
  485.     XtOffsetOf(gui_T, tooltip_fontset),
  486.     XtRImmediate,
  487.     (XtPointer)NOFONTSET
  488.     },
  489. #endif /* FEAT_BEVAL */
  490. #ifdef FEAT_XIM
  491.     {
  492.     "preeditType",
  493.     "PreeditType",
  494.     XtRString,
  495.     sizeof(char*),
  496.     XtOffsetOf(gui_T, rsrc_preedit_type_name),
  497.     XtRString,
  498.     (XtPointer)"OverTheSpot,OffTheSpot,Root"
  499.     },
  500.     {
  501.     "inputMethod",
  502.     "InputMethod",
  503.     XtRString,
  504.     sizeof(char*),
  505.     XtOffsetOf(gui_T, rsrc_input_method),
  506.     XtRString,
  507.     NULL
  508.     },
  509. #endif /* FEAT_XIM */
  510. };
  511.  
  512. /*
  513.  * This table holds all the X GUI command line options allowed.  This includes
  514.  * the standard ones so that we can skip them when vim is started without the
  515.  * GUI (but the GUI might start up later).
  516.  * When changing this, also update doc/vim_gui.txt and the usage message!!!
  517.  */
  518. static XrmOptionDescRec cmdline_options[] =
  519. {
  520.     /* We handle these options ourselves */
  521.     {"-bg",        ".background",        XrmoptionSepArg,    NULL},
  522.     {"-background",    ".background",        XrmoptionSepArg,    NULL},
  523.     {"-fg",        ".foreground",        XrmoptionSepArg,    NULL},
  524.     {"-foreground",    ".foreground",        XrmoptionSepArg,    NULL},
  525.     {"-fn",        ".font",        XrmoptionSepArg,    NULL},
  526.     {"-font",        ".font",        XrmoptionSepArg,    NULL},
  527.     {"-boldfont",    ".boldFont",        XrmoptionSepArg,    NULL},
  528.     {"-italicfont",    ".italicFont",        XrmoptionSepArg,    NULL},
  529.     {"-geom",        ".geometry",        XrmoptionSepArg,    NULL},
  530.     {"-geometry",    ".geometry",        XrmoptionSepArg,    NULL},
  531.     {"-reverse",    "*reverseVideo",    XrmoptionNoArg,    "True"},
  532.     {"-rv",        "*reverseVideo",    XrmoptionNoArg,    "True"},
  533.     {"+reverse",    "*reverseVideo",    XrmoptionNoArg,    "False"},
  534.     {"+rv",        "*reverseVideo",    XrmoptionNoArg,    "False"},
  535.     {"-display",    ".display",        XrmoptionSepArg,    NULL},
  536.     {"-iconic",        "*iconic",        XrmoptionNoArg,    "True"},
  537.     {"-name",        ".name",        XrmoptionSepArg,    NULL},
  538.     {"-bw",        ".borderWidth",        XrmoptionSepArg,    NULL},
  539.     {"-borderwidth",    ".borderWidth",        XrmoptionSepArg,    NULL},
  540.     {"-sw",        ".scrollbarWidth",  XrmoptionSepArg,    NULL},
  541.     {"-scrollbarwidth",    ".scrollbarWidth",  XrmoptionSepArg,    NULL},
  542.     {"-mh",        ".menuHeight",        XrmoptionSepArg,    NULL},
  543.     {"-menuheight",    ".menuHeight",        XrmoptionSepArg,    NULL},
  544. #ifdef FONTSET_ALWAYS
  545.     {"-mf",        ".menuFontSet",        XrmoptionSepArg,    NULL},
  546.     {"-menufont",    ".menuFontSet",        XrmoptionSepArg,    NULL},
  547.     {"-menufontset",    ".menuFontSet",        XrmoptionSepArg,    NULL},
  548. #else
  549.     {"-mf",        ".menuFont",        XrmoptionSepArg,    NULL},
  550.     {"-menufont",    ".menuFont",        XrmoptionSepArg,    NULL},
  551. #endif
  552.     {"-xrm",        NULL,            XrmoptionResArg,    NULL}
  553. };
  554.  
  555. static int gui_argc = 0;
  556. static char **gui_argv = NULL;
  557.  
  558. /*
  559.  * Call-back routines.
  560.  */
  561.  
  562. /* ARGSUSED */
  563.     static void
  564. gui_x11_timer_cb(timed_out, interval_id)
  565.     XtPointer        timed_out;
  566.     XtIntervalId    *interval_id;
  567. {
  568.     *((int *)timed_out) = TRUE;
  569. }
  570.  
  571. /* ARGSUSED */
  572.     static void
  573. gui_x11_visibility_cb(w, dud, event, dum)
  574.     Widget    w;
  575.     XtPointer    dud;
  576.     XEvent    *event;
  577.     Boolean    *dum;
  578. {
  579.     if (event->type != VisibilityNotify)
  580.     return;
  581.  
  582.     gui.visibility = event->xvisibility.state;
  583.  
  584.     /*
  585.      * When we do an XCopyArea(), and the window is partially obscured, we want
  586.      * to receive an event to tell us whether it worked or not.
  587.      */
  588.     XSetGraphicsExposures(gui.dpy, gui.text_gc,
  589.         gui.visibility != VisibilityUnobscured);
  590.  
  591.     /* This is needed for when redrawing is slow. */
  592.     gui_mch_update();
  593. }
  594.  
  595. /* ARGSUSED */
  596.     static void
  597. gui_x11_expose_cb(w, dud, event, dum)
  598.     Widget    w;
  599.     XtPointer    dud;
  600.     XEvent    *event;
  601.     Boolean    *dum;
  602. {
  603.     XExposeEvent    *gevent;
  604.     int            new_x;
  605.  
  606.     if (event->type != Expose)
  607.     return;
  608.  
  609.     out_flush();        /* make sure all output has been processed */
  610.  
  611.     gevent = (XExposeEvent *)event;
  612.     gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
  613.  
  614.     new_x = FILL_X(0);
  615.  
  616.     /* Clear the border areas if needed */
  617.     if (gevent->x < new_x)
  618.     XClearArea(gui.dpy, gui.wid, 0, 0, new_x, 0, False);
  619.     if (gevent->y < FILL_Y(0))
  620.     XClearArea(gui.dpy, gui.wid, 0, 0, 0, FILL_Y(0), False);
  621.     if (gevent->x > FILL_X(Columns))
  622.     XClearArea(gui.dpy, gui.wid, FILL_X((int)Columns), 0, 0, 0, False);
  623.     if (gevent->y > FILL_Y(Rows))
  624.     XClearArea(gui.dpy, gui.wid, 0, FILL_Y((int)Rows), 0, 0, False);
  625.  
  626.     /* This is needed for when redrawing is slow. */
  627.     gui_mch_update();
  628. }
  629.  
  630. /* ARGSUSED */
  631.     static void
  632. gui_x11_resize_window_cb(w, dud, event, dum)
  633.     Widget    w;
  634.     XtPointer    dud;
  635.     XEvent    *event;
  636.     Boolean    *dum;
  637. {
  638.     static int lastWidth, lastHeight;
  639.  
  640.     if (event->type != ConfigureNotify)
  641.     return;
  642.  
  643.     if (event->xconfigure.width != lastWidth
  644.         || event->xconfigure.height != lastHeight)
  645.     {
  646.     lastWidth = event->xconfigure.width;
  647.     lastHeight = event->xconfigure.height;
  648.     gui_resize_shell(event->xconfigure.width, event->xconfigure.height
  649. #ifdef FEAT_XIM
  650.                         - xim_get_status_area_height()
  651. #endif
  652.              );
  653.     }
  654. #ifdef FEAT_SUN_WORKSHOP
  655.     if (usingSunWorkShop)
  656.     {
  657.     XRectangle  rec;
  658.  
  659.     shellRectangle(w, &rec);
  660.     workshop_frame_moved(rec.x, rec.y, rec.width, rec.height);
  661.     }
  662. #endif
  663. #ifdef FEAT_NETBEANS_INTG
  664.     if (usingNetbeans)
  665.     {
  666.     XRectangle  rec;
  667.  
  668.     shellRectangle(w, &rec);
  669.     netbeans_frame_moved(rec.x, rec.y);
  670.     }
  671. #endif
  672. #ifdef FEAT_XIM
  673.     xim_set_preedit();
  674. #endif
  675. }
  676.  
  677. /* ARGSUSED */
  678.     static void
  679. gui_x11_focus_change_cb(w, data, event, dum)
  680.     Widget    w;
  681.     XtPointer    data;
  682.     XEvent    *event;
  683.     Boolean    *dum;
  684. {
  685.     gui_focus_change(event->type == FocusIn);
  686. }
  687.  
  688. /* ARGSUSED */
  689.     static void
  690. gui_x11_enter_cb(w, data, event, dum)
  691.     Widget    w;
  692.     XtPointer    data;
  693.     XEvent    *event;
  694.     Boolean    *dum;
  695. {
  696.     gui_focus_change(TRUE);
  697. }
  698.  
  699. /* ARGSUSED */
  700.     static void
  701. gui_x11_leave_cb(w, data, event, dum)
  702.     Widget    w;
  703.     XtPointer    data;
  704.     XEvent    *event;
  705.     Boolean    *dum;
  706. {
  707.     gui_focus_change(FALSE);
  708. }
  709.  
  710. #if defined(X_HAVE_UTF8_STRING) && defined(FEAT_MBYTE)
  711. # if X_HAVE_UTF8_STRING
  712. #  define USE_UTF8LOOKUP
  713. # endif
  714. #endif
  715.  
  716. /* ARGSUSED */
  717.     void
  718. gui_x11_key_hit_cb(w, dud, event, dum)
  719.     Widget    w;
  720.     XtPointer    dud;
  721.     XEvent    *event;
  722.     Boolean    *dum;
  723. {
  724.     XKeyPressedEvent    *ev_press;
  725. #ifdef FEAT_XIM
  726.     char_u        string2[256];
  727.     char_u        string_shortbuf[256];
  728.     char_u        *string = string_shortbuf;
  729.     Boolean        string_alloced = False;
  730.     Status        status;
  731. #else
  732.     char_u        string[4], string2[3];
  733. #endif
  734.     KeySym        key_sym, key_sym2;
  735.     int            len, len2;
  736.     int            i;
  737.     int            modifiers;
  738.     int            key;
  739.  
  740.     ev_press = (XKeyPressedEvent *)event;
  741.  
  742. #ifdef FEAT_XIM
  743.     if (xic)
  744.     {
  745. # ifdef USE_UTF8LOOKUP
  746.     /* XFree86 4.0.2 or newer: Be able to get UTF-8 characters even when
  747.      * the locale isn't utf-8. */
  748.     if (enc_utf8)
  749.         len = Xutf8LookupString(xic, ev_press, (char *)string,
  750.                   sizeof(string_shortbuf), &key_sym, &status);
  751.     else
  752. # endif
  753.         len = XmbLookupString(xic, ev_press, (char *)string,
  754.                   sizeof(string_shortbuf), &key_sym, &status);
  755.     if (status == XBufferOverflow)
  756.     {
  757.         string = (char_u *)XtMalloc(len + 1);
  758.         string_alloced = True;
  759. # ifdef USE_UTF8LOOKUP
  760.         /* XFree86 4.0.2 or newer: Be able to get UTF-8 characters even
  761.          * when the locale isn't utf-8.  */
  762.         if (enc_utf8)
  763.         len = Xutf8LookupString(xic, ev_press, (char *)string,
  764.                               len, &key_sym, &status);
  765.         else
  766. # endif
  767.         len = XmbLookupString(xic, ev_press, (char *)string,
  768.                               len, &key_sym, &status);
  769.     }
  770.     if (status == XLookupNone || status == XLookupChars)
  771.         key_sym = XK_VoidSymbol;
  772.  
  773. # ifdef FEAT_MBYTE
  774.     /* Do conversion from 'termencoding' to 'encoding'.  When using
  775.      * Xutf8LookupString() it has already been done. */
  776.     if (len > 0 && input_conv.vc_type != CONV_NONE
  777. #  ifdef USE_UTF8LOOKUP
  778.         && !enc_utf8
  779. #  endif
  780.         )
  781.     {
  782.         int        maxlen = len * 4 + 40;  /* guessed */
  783.         char_u    *p = (char_u *)XtMalloc(maxlen);
  784.  
  785.         mch_memmove(p, string, len);
  786.         if (string_alloced)
  787.         XtFree((char *)string);
  788.         string = p;
  789.         string_alloced = True;
  790.         len = convert_input(p, len, maxlen);
  791.     }
  792. # endif
  793.  
  794.     /* Translate CSI to K_CSI, otherwise it could be recognized as the
  795.      * start of a special key. */
  796.     for (i = 0; i < len; ++i)
  797.         if (string[i] == CSI)
  798.         {
  799.         char_u    *p = (char_u *)XtMalloc(len + 3);
  800.  
  801.         mch_memmove(p, string, i + 1);
  802.         p[i + 1] = KS_EXTRA;
  803.         p[i + 2] = (int)KE_CSI;
  804.         mch_memmove(p + i + 3, string + i + 1, len - i);
  805.         if (string_alloced)
  806.             XtFree((char *)string);
  807.         string = p;
  808.         string_alloced = True;
  809.         i += 2;
  810.         len += 2;
  811.         }
  812.     }
  813.     else
  814. #endif
  815.     len = XLookupString(ev_press, (char *)string, sizeof(string),
  816.         &key_sym, NULL);
  817.  
  818. #ifdef SunXK_F36
  819.     /*
  820.     * These keys have bogus lookup strings, and trapping them here is
  821.     * easier than trying to XRebindKeysym() on them with every possible
  822.     * combination of modifiers.
  823.     */
  824.     if (key_sym == SunXK_F36 || key_sym == SunXK_F37)
  825.     len = 0;
  826. #endif
  827.  
  828. #ifdef FEAT_HANGULIN
  829.     if ((key_sym == XK_space) && (ev_press->state & ShiftMask))
  830.     {
  831.     hangul_input_state_toggle();
  832.     goto theend;
  833.     }
  834. #endif
  835.  
  836.     if (key_sym == XK_space)
  837.     string[0] = ' ';    /* Otherwise Ctrl-Space doesn't work */
  838.  
  839.     /*
  840.      * Only on some machines ^_ requires Ctrl+Shift+minus.  For consistency,
  841.      * allow just Ctrl+minus too.
  842.      */
  843.     if (key_sym == XK_minus && (ev_press->state & ControlMask))
  844.     string[0] = Ctrl__;
  845.  
  846. #ifdef XK_ISO_Left_Tab
  847.     /* why do we get XK_ISO_Left_Tab instead of XK_Tab for shift-tab? */
  848.     if (key_sym == XK_ISO_Left_Tab)
  849.     {
  850.     key_sym = XK_Tab;
  851.     string[0] = TAB;
  852.     len = 1;
  853.     }
  854. #endif
  855.  
  856.     /* Check for Alt/Meta key (Mod1Mask), but not for a BS, DEL or character
  857.      * that already has the 8th bit set. */
  858.     if (len == 1
  859.         && (ev_press->state & Mod1Mask)
  860.         && !(key_sym == XK_BackSpace || key_sym == XK_Delete)
  861.         && (string[0] & 0x80) == 0)
  862.     {
  863. #if defined(FEAT_MENU) && defined(FEAT_GUI_MOTIF)
  864.     /* Ignore ALT keys when they are used for the menu only */
  865.     if (gui.menu_is_active
  866.         && (p_wak[0] == 'y'
  867.             || (p_wak[0] == 'm' && gui_is_menu_shortcut(string[0]))))
  868.         goto theend;
  869. #endif
  870.     /*
  871.      * Before we set the 8th bit, check to make sure the user doesn't
  872.      * already have a mapping defined for this sequence. We determine this
  873.      * by checking to see if the input would be the same without the
  874.      * Alt/Meta key.
  875.      * Don't do this for <S-M-Tab>, that should become K_S_TAB with ALT.
  876.      */
  877.     ev_press->state &= ~Mod1Mask;
  878.     len2 = XLookupString(ev_press, (char *)string2, sizeof(string2),
  879.                                  &key_sym2, NULL);
  880.     if (key_sym2 == XK_space)
  881.         string2[0] = ' ';        /* Otherwise Meta-Ctrl-Space doesn't work */
  882.     if (       len2 == 1
  883.         && string[0] == string2[0]
  884.         && !(key_sym == XK_Tab && (ev_press->state & ShiftMask)))
  885.     {
  886.         string[0] |= 0x80;
  887. #ifdef FEAT_MBYTE
  888.         if (enc_utf8) /* convert to utf-8 */
  889.         {
  890.         string[1] = string[0] & 0xbf;
  891.         string[0] = ((unsigned)string[0] >> 6) + 0xc0;
  892.         if (string[1] == CSI)
  893.         {
  894.             string[2] = KS_EXTRA;
  895.             string[3] = (int)KE_CSI;
  896.             len = 4;
  897.         }
  898.         else
  899.             len = 2;
  900.         }
  901. #endif
  902.     }
  903.     else
  904.         ev_press->state |= Mod1Mask;
  905.     }
  906.  
  907.     if (len == 1 && string[0] == CSI)
  908.     {
  909.     string[1] = KS_EXTRA;
  910.     string[2] = (int)KE_CSI;
  911.     len = -3;
  912.     }
  913.  
  914.     /* Check for special keys.  Also do this when len == 1 (key has an ASCII
  915.      * value) to detect backspace, delete and keypad keys. */
  916.     if (len == 0 || len == 1)
  917.     {
  918.     for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
  919.     {
  920.         if (special_keys[i].key_sym == key_sym)
  921.         {
  922.         string[0] = CSI;
  923.         string[1] = special_keys[i].vim_code0;
  924.         string[2] = special_keys[i].vim_code1;
  925.         len = -3;
  926.         break;
  927.         }
  928.     }
  929.     }
  930.  
  931.     /* Unrecognised key is ignored. */
  932.     if (len == 0)
  933.     goto theend;
  934.  
  935.     /* Special keys (and a few others) may have modifiers */
  936.     if (len == -3 || key_sym == XK_space || key_sym == XK_Tab
  937.     || key_sym == XK_Return || key_sym == XK_Linefeed
  938.     || key_sym == XK_Escape)
  939.     {
  940.     modifiers = 0;
  941.     if (ev_press->state & ShiftMask)
  942.         modifiers |= MOD_MASK_SHIFT;
  943.     if (ev_press->state & ControlMask)
  944.         modifiers |= MOD_MASK_CTRL;
  945.     if (ev_press->state & Mod1Mask)
  946.         modifiers |= MOD_MASK_ALT;
  947.  
  948.     /*
  949.      * For some keys a shift modifier is translated into another key
  950.      * code.
  951.      */
  952.     if (len == -3)
  953.         key = TO_SPECIAL(string[1], string[2]);
  954.     else
  955.         key = string[0];
  956.     key = simplify_key(key, &modifiers);
  957.     if (key == CSI)
  958.         key = K_CSI;
  959.     if (IS_SPECIAL(key))
  960.     {
  961.         string[0] = CSI;
  962.         string[1] = K_SECOND(key);
  963.         string[2] = K_THIRD(key);
  964.         len = 3;
  965.     }
  966.     else
  967.     {
  968.         string[0] = key;
  969.         len = 1;
  970.     }
  971.  
  972.     if (modifiers != 0)
  973.     {
  974.         string2[0] = CSI;
  975.         string2[1] = KS_MODIFIER;
  976.         string2[2] = modifiers;
  977.         add_to_input_buf(string2, 3);
  978.     }
  979.     }
  980.  
  981.     if (len == 1 && ((string[0] == Ctrl_C && ctrl_c_interrupts)
  982. #ifdef UNIX
  983.         || (intr_char != 0 && string[0] == intr_char)
  984. #endif
  985.         ))
  986.     {
  987.     trash_input_buf();
  988.     got_int = TRUE;
  989.     }
  990.  
  991.     add_to_input_buf(string, len);
  992.  
  993.     /*
  994.      * blank out the pointer if necessary
  995.      */
  996.     if (p_mh)
  997.     gui_mch_mousehide(TRUE);
  998.  
  999. #if defined(FEAT_BEVAL_TIP)
  1000.     {
  1001.     BalloonEval *be;
  1002.  
  1003.     if ((be = gui_mch_currently_showing_beval()) != NULL)
  1004.         gui_mch_unpost_balloon(be);
  1005.     }
  1006. #endif
  1007. theend:
  1008.     {}        /* some compilers need a statement here */
  1009. #ifdef FEAT_XIM
  1010.     if (string_alloced)
  1011.     XtFree((char *)string);
  1012. #endif
  1013. }
  1014.  
  1015. /* ARGSUSED */
  1016.     static void
  1017. gui_x11_mouse_cb(w, dud, event, dum)
  1018.     Widget    w;
  1019.     XtPointer    dud;
  1020.     XEvent    *event;
  1021.     Boolean    *dum;
  1022. {
  1023.     static XtIntervalId timer = (XtIntervalId)0;
  1024.     static int    timed_out = TRUE;
  1025.  
  1026.     int        button;
  1027.     int        repeated_click = FALSE;
  1028.     int        x, y;
  1029.     int_u    x_modifiers;
  1030.     int_u    vim_modifiers;
  1031.  
  1032.     if (event->type == MotionNotify)
  1033.     {
  1034.     /* Get the latest position, avoids lagging behind on a drag. */
  1035.     x = event->xmotion.x;
  1036.     y = event->xmotion.y;
  1037.     x_modifiers = event->xmotion.state;
  1038.     button = (x_modifiers & (Button1Mask | Button2Mask | Button3Mask))
  1039.         ? MOUSE_DRAG : ' ';
  1040.  
  1041.     /*
  1042.      * if our pointer is currently hidden, then we should show it.
  1043.      */
  1044.     gui_mch_mousehide(FALSE);
  1045.  
  1046.     if (button != MOUSE_DRAG)    /* just moving the rodent */
  1047.     {
  1048. #ifdef FEAT_MENU
  1049.         if (dud)            /* moved in vimForm */
  1050.         y -= gui.menu_height;
  1051. #endif
  1052.         gui_mouse_moved(x, y);
  1053.         return;
  1054.     }
  1055.     }
  1056.     else
  1057.     {
  1058.     x = event->xbutton.x;
  1059.     y = event->xbutton.y;
  1060.     if (event->type == ButtonPress)
  1061.     {
  1062.         /* Handle multiple clicks */
  1063.         if (!timed_out)
  1064.         {
  1065.         XtRemoveTimeOut(timer);
  1066.         repeated_click = TRUE;
  1067.         }
  1068.         timed_out = FALSE;
  1069.         timer = XtAppAddTimeOut(app_context, (long_u)p_mouset,
  1070.             gui_x11_timer_cb, &timed_out);
  1071.         switch (event->xbutton.button)
  1072.         {
  1073.         case Button1:    button = MOUSE_LEFT;    break;
  1074.         case Button2:    button = MOUSE_MIDDLE;    break;
  1075.         case Button3:    button = MOUSE_RIGHT;    break;
  1076.         case Button4:    button = MOUSE_4;    break;
  1077.         case Button5:    button = MOUSE_5;    break;
  1078.         default:
  1079.             return;    /* Unknown button */
  1080.         }
  1081.     }
  1082.     else if (event->type == ButtonRelease)
  1083.         button = MOUSE_RELEASE;
  1084.     else
  1085.         return;    /* Unknown mouse event type */
  1086.  
  1087.     x_modifiers = event->xbutton.state;
  1088. #if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
  1089.     last_mouse_event = event->xbutton;
  1090. #endif
  1091.     }
  1092.  
  1093.     vim_modifiers = 0x0;
  1094.     if (x_modifiers & ShiftMask)
  1095.     vim_modifiers |= MOUSE_SHIFT;
  1096.     if (x_modifiers & ControlMask)
  1097.     vim_modifiers |= MOUSE_CTRL;
  1098.     if (x_modifiers & Mod1Mask)        /* Alt or Meta key */
  1099.     vim_modifiers |= MOUSE_ALT;
  1100.  
  1101.     gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
  1102. }
  1103.  
  1104. #ifdef FEAT_SNIFF
  1105. /* ARGSUSED */
  1106.     static void
  1107. gui_x11_sniff_request_cb(closure, source, id)
  1108.     XtPointer    closure;
  1109.     int        *source;
  1110.     XtInputId    *id;
  1111. {
  1112.     static char_u bytes[3] = {CSI, (int)KS_EXTRA, (int)KE_SNIFF};
  1113.  
  1114.     add_to_input_buf(bytes, 3);
  1115. }
  1116. #endif
  1117.  
  1118. /*
  1119.  * End of call-back routines
  1120.  */
  1121.  
  1122. /*
  1123.  * Parse the GUI related command-line arguments.  Any arguments used are
  1124.  * deleted from argv, and *argc is decremented accordingly.  This is called
  1125.  * when vim is started, whether or not the GUI has been started.
  1126.  */
  1127.     void
  1128. gui_mch_prepare(argc, argv)
  1129.     int        *argc;
  1130.     char    **argv;
  1131. {
  1132.     int        arg;
  1133.     int        i;
  1134.  
  1135.     /*
  1136.      * Move all the entries in argv which are relevant to X into gui_argv.
  1137.      */
  1138.     gui_argc = 0;
  1139.     gui_argv = (char **)lalloc((long_u)(*argc * sizeof(char *)), FALSE);
  1140.     if (gui_argv == NULL)
  1141.     return;
  1142.     gui_argv[gui_argc++] = argv[0];
  1143.     arg = 1;
  1144.     while (arg < *argc)
  1145.     {
  1146.     /* Look for argv[arg] in cmdline_options[] table */
  1147.     for (i = 0; i < XtNumber(cmdline_options); i++)
  1148.         if (strcmp(argv[arg], cmdline_options[i].option) == 0)
  1149.         break;
  1150.  
  1151.     if (i < XtNumber(cmdline_options))
  1152.     {
  1153.         /* Remember finding "-rv" or "-reverse" */
  1154.         if (strcmp("-rv", argv[arg]) == 0
  1155.             || strcmp("-reverse", argv[arg]) == 0)
  1156.         found_reverse_arg = TRUE;
  1157.         else if ((strcmp("-fn", argv[arg]) == 0
  1158.             || strcmp("-font", argv[arg]) == 0)
  1159.             && arg + 1 < *argc)
  1160.         font_argument = argv[arg + 1];
  1161.  
  1162.         /* Found match in table, so move it into gui_argv */
  1163.         gui_argv[gui_argc++] = argv[arg];
  1164.         if (--*argc > arg)
  1165.         {
  1166.         mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
  1167.                             * sizeof(char *));
  1168.         if (cmdline_options[i].argKind != XrmoptionNoArg)
  1169.         {
  1170.             /* Move the options argument as well */
  1171.             gui_argv[gui_argc++] = argv[arg];
  1172.             if (--*argc > arg)
  1173.             mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
  1174.                                 * sizeof(char *));
  1175.         }
  1176.         }
  1177.     }
  1178.     else
  1179. #ifdef FEAT_SUN_WORKSHOP
  1180.         if (strcmp("-ws", argv[arg]) == 0)
  1181.     {
  1182.         usingSunWorkShop++;
  1183.         gui.dofork = FALSE;    /* don't fork() when starting GUI */
  1184.         mch_memmove(&argv[arg], &argv[arg + 1],
  1185.                         (--*argc - arg) * sizeof(char *));
  1186. # ifdef WSDEBUG
  1187.         wsdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20);
  1188.         wsdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL");
  1189. # endif
  1190.     }
  1191.     else
  1192. #endif
  1193. #ifdef FEAT_NETBEANS_INTG
  1194.         if (strncmp("-nb", argv[arg], 3) == 0)
  1195.     {
  1196.         usingNetbeans++;
  1197.         gui.dofork = FALSE;    /* don't fork() when starting GUI */
  1198.         netbeansArg = argv[arg];
  1199.         mch_memmove(&argv[arg], &argv[arg + 1],
  1200.                         (--*argc - arg) * sizeof(char *));
  1201.     }
  1202.     else
  1203. #endif
  1204.         arg++;
  1205.     }
  1206. }
  1207.  
  1208. #ifndef XtSpecificationRelease
  1209. # define CARDINAL (Cardinal *)
  1210. #else
  1211. # if XtSpecificationRelease == 4
  1212. # define CARDINAL (Cardinal *)
  1213. # else
  1214. # define CARDINAL (int *)
  1215. # endif
  1216. #endif
  1217.  
  1218. /*
  1219.  * Check if the GUI can be started.  Called before gvimrc is sourced.
  1220.  * Return OK or FAIL.
  1221.  */
  1222.     int
  1223. gui_mch_init_check()
  1224. {
  1225. #ifdef FEAT_XIM
  1226.     XtSetLanguageProc(NULL, NULL, NULL);
  1227. #endif
  1228.     open_app_context();
  1229.     if (app_context != NULL)
  1230.     gui.dpy = XtOpenDisplay(app_context, 0, VIM_NAME, VIM_CLASS,
  1231.         cmdline_options, XtNumber(cmdline_options),
  1232.         CARDINAL &gui_argc, gui_argv);
  1233.  
  1234.     if (app_context == NULL || gui.dpy == NULL)
  1235.     {
  1236.     gui.dying = TRUE;
  1237.     EMSG(_(e_opendisp));
  1238.     return FAIL;
  1239.     }
  1240.     return OK;
  1241. }
  1242.  
  1243.  
  1244. #ifdef USE_XSMP
  1245. /*
  1246.  * Handle XSMP processing, de-registering the attachment upon error
  1247.  */
  1248. static XtInputId _xsmp_xtinputid;
  1249.  
  1250. static void local_xsmp_handle_requests __ARGS((XtPointer c, int *s, XtInputId *i));
  1251.  
  1252. /*ARGSUSED*/
  1253.     static void
  1254. local_xsmp_handle_requests(c, s, i)
  1255.     XtPointer    c;
  1256.     int        *s;
  1257.     XtInputId    *i;
  1258. {
  1259.     if (xsmp_handle_requests() == FAIL)
  1260.     XtRemoveInput(_xsmp_xtinputid);
  1261. }
  1262. #endif
  1263.  
  1264.  
  1265. /*
  1266.  * Initialise the X GUI.  Create all the windows, set up all the call-backs etc.
  1267.  * Returns OK for success, FAIL when the GUI can't be started.
  1268.  */
  1269.     int
  1270. gui_mch_init()
  1271. {
  1272.     XtGCMask    gc_mask;
  1273.     XGCValues    gc_vals;
  1274.     int        x, y, mask;
  1275.     unsigned    w, h;
  1276.  
  1277. #if 0
  1278.     /* Uncomment this to enable synchronous mode for debugging */
  1279.     XSynchronize(gui.dpy, True);
  1280. #endif
  1281.  
  1282.     vimShell = XtVaAppCreateShell(VIM_NAME, VIM_CLASS,
  1283.         applicationShellWidgetClass, gui.dpy, NULL);
  1284.  
  1285.     /*
  1286.      * Get the application resources
  1287.      */
  1288.     XtVaGetApplicationResources(vimShell, (XtPointer)&gui,
  1289.     vim_resources, XtNumber(vim_resources), NULL);
  1290.  
  1291.     gui.scrollbar_height = gui.scrollbar_width;
  1292.  
  1293.     /*
  1294.      * Get the colors ourselves.  Using the automatic conversion doesn't
  1295.      * handle looking for approximate colors.
  1296.      */
  1297.     /* NOTE: These next few lines are an exact duplicate of gui_athena.c's
  1298.      * gui_mch_def_colors().  Why?
  1299.      */
  1300.     gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
  1301.     gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
  1302.     gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
  1303.     gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
  1304. #ifdef FEAT_BEVAL
  1305.     gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
  1306.     gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
  1307. #endif
  1308.  
  1309. #if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
  1310.     /* If the menu height was set, don't change it at runtime */
  1311.     if (gui.menu_height != MENU_DEFAULT_HEIGHT)
  1312.     gui.menu_height_fixed = TRUE;
  1313. #endif
  1314.  
  1315.     /* Set default foreground and background colours */
  1316.     gui.norm_pixel = gui.def_norm_pixel;
  1317.     gui.back_pixel = gui.def_back_pixel;
  1318.  
  1319.     /* Check if reverse video needs to be applied (on Sun it's done by X) */
  1320.     if (gui.rsrc_rev_video && gui_get_lightness(gui.back_pixel)
  1321.                       > gui_get_lightness(gui.norm_pixel))
  1322.     {
  1323.     gui.norm_pixel = gui.def_back_pixel;
  1324.     gui.back_pixel = gui.def_norm_pixel;
  1325.     gui.def_norm_pixel = gui.norm_pixel;
  1326.     gui.def_back_pixel = gui.back_pixel;
  1327.     }
  1328.  
  1329.     /* Get the colors from the "Normal", "Tooltip", "Scrollbar" and "Menu"
  1330.      * group (set in syntax.c or in a vimrc file) */
  1331.     set_normal_colors();
  1332.  
  1333.     /*
  1334.      * Check that none of the colors are the same as the background color
  1335.      */
  1336.     gui_check_colors();
  1337.  
  1338.     /*
  1339.      * Set up the GCs.    The font attributes will be set in gui_init_font().
  1340.      */
  1341.     gc_mask = GCForeground | GCBackground;
  1342.     gc_vals.foreground = gui.norm_pixel;
  1343.     gc_vals.background = gui.back_pixel;
  1344.     gui.text_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
  1345.  
  1346.     gc_vals.foreground = gui.back_pixel;
  1347.     gc_vals.background = gui.norm_pixel;
  1348.     gui.back_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
  1349.  
  1350.     gc_mask |= GCFunction;
  1351.     gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
  1352.     gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
  1353.     gc_vals.function   = GXxor;
  1354.     gui.invert_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
  1355.  
  1356.     gui.visibility = VisibilityUnobscured;
  1357.     x11_setup_atoms(gui.dpy);
  1358.  
  1359.     if (gui_win_x != -1 && gui_win_y != -1)
  1360.     gui_mch_set_winpos(gui_win_x, gui_win_y);
  1361.  
  1362.     /* Now adapt the supplied(?) geometry-settings */
  1363.     /* Added by Kjetil Jacobsen <kjetilja@stud.cs.uit.no> */
  1364.     if (gui.geom != NULL && *gui.geom != NUL)
  1365.     {
  1366.     mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
  1367.     if (mask & WidthValue)
  1368.         Columns = w;
  1369.     if (mask & HeightValue)
  1370.         Rows = h;
  1371.     /*
  1372.      * Set the (x,y) position of the main window only if specified in the
  1373.      * users geometry, so we get good defaults when they don't. This needs
  1374.      * to be done before the shell is popped up.
  1375.      */
  1376.     if (mask & (XValue|YValue))
  1377.         XtVaSetValues(vimShell, XtNgeometry, gui.geom, NULL);
  1378.     }
  1379.  
  1380.     gui_x11_create_widgets();
  1381.  
  1382.    /*
  1383.     * Add an icon to Vim (Marcel Douben: 11 May 1998).
  1384.     */
  1385.     if (vim_strchr(p_go, GO_ICON) != NULL)
  1386.     {
  1387. #ifndef HAVE_XPM
  1388. # include "vim_icon.xbm"
  1389. # include "vim_mask.xbm"
  1390.  
  1391.     Arg    arg[2];
  1392.  
  1393.     XtSetArg(arg[0], XtNiconPixmap,
  1394.         XCreateBitmapFromData(gui.dpy,
  1395.             DefaultRootWindow(gui.dpy),
  1396.             (char *)vim_icon_bits,
  1397.             vim_icon_width,
  1398.             vim_icon_height));
  1399.     XtSetArg(arg[1], XtNiconMask,
  1400.         XCreateBitmapFromData(gui.dpy,
  1401.             DefaultRootWindow(gui.dpy),
  1402.             (char *)vim_mask_icon_bits,
  1403.             vim_mask_icon_width,
  1404.             vim_mask_icon_height));
  1405.     XtSetValues(vimShell, arg, (Cardinal)2);
  1406. #else
  1407. /* Use Pixmaps, looking much nicer. */
  1408.  
  1409. /* If you get an error message here, you still need to unpack the runtime
  1410.  * archive! */
  1411. # ifdef magick
  1412. #  undef magick
  1413. # endif
  1414. # define magick vim32x32
  1415. # include "../runtime/vim32x32.xpm"
  1416. # undef magick
  1417. # define magick vim16x16
  1418. # include "../runtime/vim16x16.xpm"
  1419. # undef magick
  1420. # define magick vim48x48
  1421. # include "../runtime/vim48x48.xpm"
  1422. # undef magick
  1423.  
  1424.     static Pixmap    icon = 0;
  1425.     static Pixmap    icon_mask = 0;
  1426.     static char        **magick = vim32x32;
  1427.     Window        root_window;
  1428.     XIconSize        *size;
  1429.     int            number_sizes;
  1430.     Display        *dsp;
  1431.     Screen        *scr;
  1432.     XpmAttributes    attr;
  1433.     Colormap        cmap;
  1434.  
  1435.     /*
  1436.      * Adjust the icon to the preferences of the actual window manager.
  1437.      */
  1438.     root_window = XRootWindowOfScreen(XtScreen(vimShell));
  1439.     if (XGetIconSizes(XtDisplay(vimShell), root_window,
  1440.                            &size, &number_sizes) != 0)
  1441.     {
  1442.  
  1443.     if (number_sizes > 0)
  1444.     {
  1445.         if (size->max_height >= 48 && size->max_height >= 48)
  1446.         magick = vim48x48;
  1447.         else if (size->max_height >= 32 && size->max_height >= 32)
  1448.         magick = vim32x32;
  1449.         else if (size->max_height >= 16 && size->max_height >= 16)
  1450.         magick = vim16x16;
  1451.     }
  1452.     }
  1453.  
  1454.     dsp = XtDisplay(vimShell);
  1455.     scr = XtScreen(vimShell);
  1456.  
  1457.     cmap = DefaultColormap(dsp, DefaultScreen(dsp));
  1458.     XtVaSetValues(vimShell, XtNcolormap, cmap, NULL);
  1459.  
  1460.     attr.valuemask = 0L;
  1461.     attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth;
  1462.     attr.closeness = 65535;    /* accuracy isn't crucial */
  1463.     attr.colormap = cmap;
  1464.     attr.depth = DefaultDepthOfScreen(scr);
  1465.  
  1466.     if (!icon)
  1467.     XpmCreatePixmapFromData(dsp, root_window, magick, &icon,
  1468.                                &icon_mask, &attr);
  1469.  
  1470. # ifdef FEAT_GUI_ATHENA
  1471.     XtVaSetValues(vimShell, XtNiconPixmap, icon, XtNiconMask, icon_mask, NULL);
  1472. # else
  1473.     XtVaSetValues(vimShell, XmNiconPixmap, icon, XmNiconMask, icon_mask, NULL);
  1474. # endif
  1475. #endif
  1476.     }
  1477.  
  1478.     if (gui.color_approx)
  1479.     EMSG(_("Vim E458: Cannot allocate colormap entry, some colors may be incorrect"));
  1480.  
  1481. #ifdef FEAT_SUN_WORKSHOP
  1482.     if (usingSunWorkShop)
  1483.     workshop_connect(app_context);
  1484. #endif
  1485. #ifdef FEAT_NETBEANS_INTG
  1486.     if (usingNetbeans)
  1487.     netbeans_Xt_connect(app_context);
  1488. #endif
  1489.  
  1490. #ifdef FEAT_BEVAL
  1491.     gui_init_tooltip_font();
  1492. #endif
  1493. #ifdef FEAT_MENU
  1494.     gui_init_menu_font();
  1495. #endif
  1496.  
  1497. #ifdef USE_XSMP
  1498.     /* Attach listener on ICE connection */
  1499.     if (-1 != xsmp_icefd)
  1500.     _xsmp_xtinputid = XtAppAddInput(app_context, xsmp_icefd,
  1501.         (XtPointer)XtInputReadMask, local_xsmp_handle_requests, NULL);
  1502. #endif
  1503.  
  1504.     return OK;
  1505. }
  1506.  
  1507. /*
  1508.  * Called when starting the GUI fails after calling gui_mch_init().
  1509.  */
  1510.     void
  1511. gui_mch_uninit()
  1512. {
  1513.     gui_x11_destroy_widgets();
  1514. #ifndef LESSTIF_VERSION
  1515.     XtCloseDisplay(gui.dpy);
  1516. #endif
  1517.     gui.dpy = NULL;
  1518.     vimShell = (Widget)0;
  1519. }
  1520.  
  1521. /*
  1522.  * Called when the foreground or background color has been changed.
  1523.  */
  1524.     void
  1525. gui_mch_new_colors()
  1526. {
  1527.     long_u    gc_mask;
  1528.     XGCValues    gc_vals;
  1529.  
  1530.     gc_mask = GCForeground | GCBackground;
  1531.     gc_vals.foreground = gui.norm_pixel;
  1532.     gc_vals.background = gui.back_pixel;
  1533.     if (gui.text_gc != NULL)
  1534.     XChangeGC(gui.dpy, gui.text_gc, gc_mask, &gc_vals);
  1535.  
  1536.     gc_vals.foreground = gui.back_pixel;
  1537.     gc_vals.background = gui.norm_pixel;
  1538.     if (gui.back_gc != NULL)
  1539.     XChangeGC(gui.dpy, gui.back_gc, gc_mask, &gc_vals);
  1540.  
  1541.     gc_mask |= GCFunction;
  1542.     gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
  1543.     gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
  1544.     gc_vals.function   = GXxor;
  1545.     if (gui.invert_gc != NULL)
  1546.     XChangeGC(gui.dpy, gui.invert_gc, gc_mask, &gc_vals);
  1547.  
  1548.     gui_x11_set_back_color();
  1549. }
  1550.  
  1551. /*
  1552.  * Open the GUI window which was created by a call to gui_mch_init().
  1553.  */
  1554.     int
  1555. gui_mch_open()
  1556. {
  1557.     /* Actually open the window */
  1558.     XtPopup(vimShell, XtGrabNone);
  1559.  
  1560.     gui.wid = gui_x11_get_wid();
  1561.     gui.blank_pointer = gui_x11_create_blank_mouse();
  1562.  
  1563.     /*
  1564.      * Add a callback for the Close item on the window managers menu, and the
  1565.      * save-yourself event.
  1566.      */
  1567.     wm_atoms[SAVE_YOURSELF_IDX] =
  1568.                   XInternAtom(gui.dpy, "WM_SAVE_YOURSELF", False);
  1569.     wm_atoms[DELETE_WINDOW_IDX] =
  1570.                   XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
  1571.     XSetWMProtocols(gui.dpy, XtWindow(vimShell), wm_atoms, 2);
  1572.     XtAddEventHandler(vimShell, NoEventMask, True, gui_x11_wm_protocol_handler,
  1573.                                  NULL);
  1574. #ifdef HAVE_X11_XMU_EDITRES_H
  1575.     /*
  1576.      * Enable editres protocol (see "man editres").
  1577.      * Usually will need to add -lXmu to the linker line as well.
  1578.      */
  1579.     XtAddEventHandler(vimShell, (EventMask)0, True, _XEditResCheckMessages,
  1580.         (XtPointer)NULL);
  1581. #endif
  1582.  
  1583. #ifdef FEAT_CLIENTSERVER
  1584.     if (serverName == NULL && serverDelayedStartName != NULL)
  1585.     {
  1586.     /* This is a :gui command in a plain vim with no previous server */
  1587.     commWindow = XtWindow(vimShell);
  1588.     (void)serverRegisterName(gui.dpy, serverDelayedStartName);
  1589.     }
  1590.     else
  1591.     {
  1592.     /*
  1593.      * Cannot handle "widget-less" windows with XtProcessEvent() we'll
  1594.      * have to change the "server" registration to that of the main window
  1595.      * If we have not registered a name yet, remember the window
  1596.      */
  1597.     serverChangeRegisteredWindow(gui.dpy, XtWindow(vimShell));
  1598.     }
  1599.     XtAddEventHandler(vimShell, PropertyChangeMask, False,
  1600.               gui_x11_send_event_handler, NULL);
  1601. #endif
  1602.  
  1603.  
  1604. #if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
  1605.     /* The Athena GUI needs this again after opening the window */
  1606.     gui_position_menu();
  1607. # ifdef FEAT_TOOLBAR
  1608.     gui_mch_set_toolbar_pos(0, gui.menu_height, gui.menu_width,
  1609.                 gui.toolbar_height);
  1610. # endif
  1611. #endif
  1612.  
  1613.     /* Get the colors for the highlight groups (gui_check_colors() might have
  1614.      * changed them) */
  1615.     highlight_gui_started();        /* re-init colors and fonts */
  1616.  
  1617. #ifdef FEAT_HANGULIN
  1618.     hangul_keyboard_set();
  1619. #endif
  1620. #ifdef FEAT_XIM
  1621.     xim_init();
  1622. #endif
  1623. #ifdef FEAT_SUN_WORKSHOP
  1624.     workshop_postinit();
  1625. #endif
  1626.  
  1627.     return OK;
  1628. }
  1629.  
  1630. #if defined(FEAT_BEVAL) || defined(PROTO)
  1631. /*
  1632.  * Convert the tooltip fontset name to an XFontSet.
  1633.  */
  1634.     void
  1635. gui_init_tooltip_font()
  1636. {
  1637.     XrmValue from, to;
  1638.  
  1639.     from.addr = (char *)gui.rsrc_tooltip_font_name;
  1640.     from.size = strlen(from.addr);
  1641.     to.addr = (XtPointer)&gui.tooltip_fontset;
  1642.     to.size = sizeof(XFontSet);
  1643.  
  1644.     if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
  1645.     {
  1646.     /* Failed. What to do? */
  1647.     }
  1648. }
  1649. #endif
  1650.  
  1651. #if defined(FEAT_MENU) || defined(PROTO)
  1652. /* Convert the menu font/fontset name to an XFontStruct/XFontset */
  1653.     void
  1654. gui_init_menu_font()
  1655. {
  1656.     XrmValue from, to;
  1657.  
  1658. #ifdef FONTSET_ALWAYS
  1659.     from.addr = (char *)gui.rsrc_menu_font_name;
  1660.     from.size = strlen(from.addr);
  1661.     to.addr = (XtPointer)&gui.menu_fontset;
  1662.     to.size = sizeof(GuiFontset);
  1663.  
  1664.     if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
  1665.     {
  1666.     /* Failed. What to do? */
  1667.     }
  1668. #else
  1669.     from.addr = (char *)gui.rsrc_menu_font_name;
  1670.     from.size = strlen(from.addr);
  1671.     to.addr = (XtPointer)&gui.menu_font;
  1672.     to.size = sizeof(GuiFont);
  1673.  
  1674.     if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontStruct, &to) == False)
  1675.     {
  1676.     /* Failed. What to do? */
  1677.     }
  1678. #endif
  1679. }
  1680. #endif
  1681.  
  1682. /*ARGSUSED*/
  1683.     void
  1684. gui_mch_exit(rc)
  1685.     int        rc;
  1686. {
  1687. #if 0
  1688.     /* Lesstif gives an error message here, and so does Solaris.  The man page
  1689.      * says that this isn't needed when exiting, so just skip it. */
  1690.     XtCloseDisplay(gui.dpy);
  1691. #endif
  1692. }
  1693.  
  1694. /*
  1695.  * Get the position of the top left corner of the window.
  1696.  */
  1697.     int
  1698. gui_mch_get_winpos(x, y)
  1699.     int        *x, *y;
  1700. {
  1701.     Dimension    xpos, ypos;
  1702.  
  1703.     XtVaGetValues(vimShell,
  1704.     XtNx,    &xpos,
  1705.     XtNy,    &ypos,
  1706.     NULL);
  1707.     *x = xpos;
  1708.     *y = ypos;
  1709.     return OK;
  1710. }
  1711.  
  1712. /*
  1713.  * Set the position of the top left corner of the window to the given
  1714.  * coordinates.
  1715.  */
  1716.     void
  1717. gui_mch_set_winpos(x, y)
  1718.     int        x, y;
  1719. {
  1720.     XtVaSetValues(vimShell,
  1721.     XtNx,    x,
  1722.     XtNy,    y,
  1723.     NULL);
  1724. }
  1725.  
  1726.     void
  1727. gui_mch_set_shellsize(width, height, min_width, min_height,
  1728.             base_width, base_height)
  1729.     int        width;
  1730.     int        height;
  1731.     int        min_width;
  1732.     int        min_height;
  1733.     int        base_width;
  1734.     int        base_height;
  1735. {
  1736.     XtVaSetValues(vimShell,
  1737.     XtNwidthInc,    gui.char_width,
  1738.     XtNheightInc,    gui.char_height,
  1739. #if defined(XtSpecificationRelease) && XtSpecificationRelease >= 4
  1740.     XtNbaseWidth,    base_width,
  1741.     XtNbaseHeight,    base_height,
  1742. #endif
  1743.     XtNminWidth,    min_width,
  1744.     XtNminHeight,    min_height,
  1745.     XtNwidth,    width,
  1746. #ifdef FEAT_XIM
  1747.     XtNheight,    height + xim_get_status_area_height(),
  1748. #else
  1749.     XtNheight,    height,
  1750. #endif
  1751.     NULL);
  1752. }
  1753.  
  1754. /*
  1755.  * Allow 10 pixels for horizontal borders, 30 for vertical borders.
  1756.  * Is there no way in X to find out how wide the borders really are?
  1757.  */
  1758.     void
  1759. gui_mch_get_screen_dimensions(screen_w, screen_h)
  1760.     int        *screen_w;
  1761.     int        *screen_h;
  1762. {
  1763.     *screen_w = DisplayWidth(gui.dpy, DefaultScreen(gui.dpy)) - 10;
  1764.     *screen_h = DisplayHeight(gui.dpy, DefaultScreen(gui.dpy)) - p_ghr;
  1765. }
  1766.  
  1767. /*
  1768.  * Initialise vim to use the font "font_name".  If it's NULL, pick a default
  1769.  * font.
  1770.  * If "fontset" is TRUE, load the "font_name" as a fontset.
  1771.  * Return FAIL if the font could not be loaded, OK otherwise.
  1772.  */
  1773. /*ARGSUSED*/
  1774.     int
  1775. gui_mch_init_font(font_name, do_fontset)
  1776.     char_u    *font_name;
  1777.     int        do_fontset;
  1778. {
  1779.     XFontStruct    *font = NULL;
  1780.  
  1781. #ifdef FEAT_XFONTSET
  1782.     XFontSet    fontset = NULL;
  1783.  
  1784.     if (do_fontset)
  1785.     {
  1786.     /* If 'guifontset' is set, VIM treats all font specifications as if
  1787.      * they were fontsets, and 'guifontset' becomes the default. */
  1788.     if (font_name != NULL)
  1789.     {
  1790.         fontset = (XFontSet)gui_mch_get_fontset(font_name, FALSE, TRUE);
  1791.         if (fontset == NULL)
  1792.         return FAIL;
  1793.     }
  1794.     }
  1795.     else
  1796. #endif
  1797.     {
  1798.     if (font_name == NULL)
  1799.     {
  1800.         /*
  1801.          * If none of the fonts in 'font' could be loaded, try the one set
  1802.          * in the X resource, and finally just try using DFLT_FONT, which
  1803.          * will hopefully always be there.
  1804.          */
  1805.         font_name = gui.rsrc_font_name;
  1806.         font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
  1807.         if (font == NULL)
  1808.         font_name = (char_u *)DFLT_FONT;
  1809.     }
  1810.     if (font == NULL)
  1811.         font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
  1812.     if (font == NULL)
  1813.         return FAIL;
  1814.     }
  1815.  
  1816.     gui_mch_free_font(gui.norm_font);
  1817. #ifdef FEAT_XFONTSET
  1818.     gui_mch_free_fontset(gui.fontset);
  1819.  
  1820.     if (fontset != NULL)
  1821.     {
  1822.     gui.norm_font = NOFONT;
  1823.     gui.fontset = (GuiFontset)fontset;
  1824.     gui.char_width = fontset_width(fontset);
  1825.     gui.char_height = fontset_height(fontset) + p_linespace;
  1826.     gui.char_ascent = fontset_ascent(fontset) + p_linespace / 2;
  1827.     }
  1828.     else
  1829. #endif
  1830.     {
  1831.     gui.norm_font = (GuiFont)font;
  1832. #ifdef FEAT_XFONTSET
  1833.     gui.fontset = NOFONTSET;
  1834. #endif
  1835.     gui.char_width = font->max_bounds.width;
  1836.     gui.char_height = font->ascent + font->descent + p_linespace;
  1837.     gui.char_ascent = font->ascent + p_linespace / 2;
  1838.     }
  1839.  
  1840.     hl_set_font_name(font_name);
  1841.  
  1842.     /*
  1843.      * Try to load other fonts for bold, italic, and bold-italic.
  1844.      * We should also try to work out what font to use for these when they are
  1845.      * not specified by X resources, but we don't yet.
  1846.      */
  1847.     if (font_name == gui.rsrc_font_name)
  1848.     {
  1849.     if (gui.bold_font == NOFONT
  1850.         && gui.rsrc_bold_font_name != NULL
  1851.         && *gui.rsrc_bold_font_name != NUL)
  1852.         gui.bold_font = gui_mch_get_font(gui.rsrc_bold_font_name, FALSE);
  1853.     if (gui.ital_font == NOFONT
  1854.         && gui.rsrc_ital_font_name != NULL
  1855.         && *gui.rsrc_ital_font_name != NUL)
  1856.         gui.ital_font = gui_mch_get_font(gui.rsrc_ital_font_name, FALSE);
  1857.     if (gui.boldital_font == NOFONT
  1858.         && gui.rsrc_boldital_font_name != NULL
  1859.         && *gui.rsrc_boldital_font_name != NUL)
  1860.         gui.boldital_font = gui_mch_get_font(gui.rsrc_boldital_font_name,
  1861.                                        FALSE);
  1862.     }
  1863.     else
  1864.     {
  1865.     /* When not using the font specified by the resources, also don't use
  1866.      * the bold/italic fonts, otherwise setting 'guifont' will look very
  1867.      * strange. */
  1868.     if (gui.bold_font != NOFONT)
  1869.     {
  1870.         XFreeFont(gui.dpy, (XFontStruct *)gui.bold_font);
  1871.         gui.bold_font = NOFONT;
  1872.     }
  1873.     if (gui.ital_font != NOFONT)
  1874.     {
  1875.         XFreeFont(gui.dpy, (XFontStruct *)gui.ital_font);
  1876.         gui.ital_font = NOFONT;
  1877.     }
  1878.     if (gui.boldital_font != NOFONT)
  1879.     {
  1880.         XFreeFont(gui.dpy, (XFontStruct *)gui.boldital_font);
  1881.         gui.boldital_font = NOFONT;
  1882.     }
  1883.     }
  1884.  
  1885.     return OK;
  1886. }
  1887.  
  1888. /*
  1889.  * Get a font structure for highlighting.
  1890.  */
  1891.     GuiFont
  1892. gui_mch_get_font(name, giveErrorIfMissing)
  1893.     char_u    *name;
  1894.     int        giveErrorIfMissing;
  1895. {
  1896.     XFontStruct    *font;
  1897.  
  1898.     if (!gui.in_use || name == NULL)    /* can't do this when GUI not running */
  1899.     return NOFONT;
  1900.  
  1901.     font = XLoadQueryFont(gui.dpy, (char *)name);
  1902.  
  1903.     if (font == NULL)
  1904.     {
  1905.     if (giveErrorIfMissing)
  1906.         EMSG2(_(e_font), name);
  1907.     return NOFONT;
  1908.     }
  1909.  
  1910. #ifdef DEBUG
  1911.     printf("Font Information for '%s':\n", name);
  1912.     printf("  w = %d, h = %d, ascent = %d, descent = %d\n",
  1913.        font->max_bounds.width, font->ascent + font->descent,
  1914.        font->ascent, font->descent);
  1915.     printf("  max ascent = %d, max descent = %d, max h = %d\n",
  1916.        font->max_bounds.ascent, font->max_bounds.descent,
  1917.        font->max_bounds.ascent + font->max_bounds.descent);
  1918.     printf("  min lbearing = %d, min rbearing = %d\n",
  1919.        font->min_bounds.lbearing, font->min_bounds.rbearing);
  1920.     printf("  max lbearing = %d, max rbearing = %d\n",
  1921.        font->max_bounds.lbearing, font->max_bounds.rbearing);
  1922.     printf("  leftink = %d, rightink = %d\n",
  1923.        (font->min_bounds.lbearing < 0),
  1924.        (font->max_bounds.rbearing > font->max_bounds.width));
  1925.     printf("\n");
  1926. #endif
  1927.  
  1928.     if (font->max_bounds.width != font->min_bounds.width)
  1929.     {
  1930.     EMSG2(_(e_fontwidth), name);
  1931.     XFreeFont(gui.dpy, font);
  1932.     return NOFONT;
  1933.     }
  1934.     return (GuiFont)font;
  1935. }
  1936.  
  1937.     int
  1938. gui_mch_adjust_charsize()
  1939. {
  1940. #ifdef FEAT_XFONTSET
  1941.     if (gui.fontset != NOFONTSET)
  1942.     {
  1943.     gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
  1944.     gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
  1945.                                 + p_linespace / 2;
  1946.     }
  1947.     else
  1948. #endif
  1949.     {
  1950.     XFontStruct *font = (XFontStruct *)gui.norm_font;
  1951.  
  1952.     gui.char_height = font->ascent + font->descent + p_linespace;
  1953.     gui.char_ascent = font->ascent + p_linespace / 2;
  1954.     }
  1955.     return OK;
  1956. }
  1957.  
  1958. /*
  1959.  * Set the current text font.
  1960.  */
  1961.     void
  1962. gui_mch_set_font(font)
  1963.     GuiFont    font;
  1964. {
  1965.     static Font    prev_font = (Font)-1;
  1966.     Font    fid = ((XFontStruct *)font)->fid;
  1967.  
  1968.     if (fid != prev_font)
  1969.     {
  1970.     XSetFont(gui.dpy, gui.text_gc, fid);
  1971.     XSetFont(gui.dpy, gui.back_gc, fid);
  1972.     prev_font = fid;
  1973.     gui.char_ascent = ((XFontStruct *)font)->ascent + p_linespace / 2;
  1974.     }
  1975. #ifdef FEAT_XFONTSET
  1976.     current_fontset = (XFontSet)NULL;
  1977. #endif
  1978. }
  1979.  
  1980. #if defined(FEAT_XFONTSET) || defined(PROTO)
  1981. /*
  1982.  * Set the current text fontset.
  1983.  * Adjust the ascent, in case it's different.
  1984.  */
  1985.     void
  1986. gui_mch_set_fontset(fontset)
  1987.     GuiFontset    fontset;
  1988. {
  1989.     current_fontset = (XFontSet)fontset;
  1990.     gui.char_ascent = fontset_ascent(current_fontset) + p_linespace / 2;
  1991. }
  1992. #endif
  1993.  
  1994. #if 0 /* not used */
  1995. /*
  1996.  * Return TRUE if the two fonts given are equivalent.
  1997.  */
  1998.     int
  1999. gui_mch_same_font(f1, f2)
  2000.     GuiFont    f1;
  2001.     GuiFont    f2;
  2002. {
  2003. #ifdef FEAT_XFONTSET
  2004.     if (gui.fontset != NULL)
  2005.     return f1 == f2;
  2006.     else
  2007. #endif
  2008.     return ((XFontStruct *)f1)->fid == ((XFontStruct *)f2)->fid;
  2009. }
  2010. #endif
  2011.  
  2012. /*
  2013.  * If a font is not going to be used, free its structure.
  2014.  */
  2015.     void
  2016. gui_mch_free_font(font)
  2017.     GuiFont    font;
  2018. {
  2019.     if (font != NOFONT)
  2020.     XFreeFont(gui.dpy, (XFontStruct *)font);
  2021. }
  2022.  
  2023. #if defined(FEAT_XFONTSET) || defined(PROTO)
  2024. /*
  2025.  * If a fontset is not going to be used, free its structure.
  2026.  */
  2027.     void
  2028. gui_mch_free_fontset(fontset)
  2029.     GuiFontset    fontset;
  2030. {
  2031.     if (fontset != NOFONTSET)
  2032.     XFreeFontSet(gui.dpy, (XFontSet)fontset);
  2033. }
  2034.  
  2035. /*
  2036.  * Load the fontset "name".
  2037.  * Return a reference to the fontset, or NOFONTSET when failing.
  2038.  */
  2039.     GuiFontset
  2040. gui_mch_get_fontset(name, giveErrorIfMissing, fixed_width)
  2041.     char_u    *name;
  2042.     int        giveErrorIfMissing;
  2043.     int        fixed_width;
  2044. {
  2045.     XFontSet    fontset;
  2046.     char    **missing, *def_str;
  2047.     int        num_missing;
  2048.  
  2049.     if (!gui.in_use || name == NULL)
  2050.     return NOFONTSET;
  2051.  
  2052.     fontset = XCreateFontSet(gui.dpy, (char *)name, &missing, &num_missing,
  2053.                  &def_str);
  2054.     if (num_missing > 0)
  2055.     {
  2056.     int i;
  2057.  
  2058.     if (giveErrorIfMissing)
  2059.     {
  2060.         EMSG2(_("E250: Fonts for the following charsets are missing in fontset %s:"), name);
  2061.         for (i = 0; i < num_missing; i++)
  2062.         EMSG2("%s", missing[i]);
  2063.     }
  2064.     XFreeStringList(missing);
  2065.     }
  2066.  
  2067.     if (fontset == NULL)
  2068.     {
  2069.     if (giveErrorIfMissing)
  2070.         EMSG2(_(e_fontset), name);
  2071.     return NOFONTSET;
  2072.     }
  2073.  
  2074.     if (fixed_width && check_fontset_sanity(fontset) == FAIL)
  2075.     {
  2076.     XFreeFontSet(gui.dpy, fontset);
  2077.     return NOFONTSET;
  2078.     }
  2079.     return (GuiFontset)fontset;
  2080. }
  2081.  
  2082. /*
  2083.  * Check if fontset "fs" is fixed width.
  2084.  */
  2085.     static int
  2086. check_fontset_sanity(fs)
  2087.     XFontSet fs;
  2088. {
  2089.     XFontStruct    **xfs;
  2090.     char    **font_name;
  2091.     int        fn;
  2092.     char    *base_name;
  2093.     int        i;
  2094.     int        min_width;
  2095.     int        min_font_idx = 0;
  2096.  
  2097.     base_name = XBaseFontNameListOfFontSet(fs);
  2098.     fn = XFontsOfFontSet(fs, &xfs, &font_name);
  2099.     for (i = 0; i < fn; i++)
  2100.     {
  2101.     if (xfs[i]->max_bounds.width != xfs[i]->min_bounds.width)
  2102.     {
  2103.         EMSG2(_("E252: Fontset name: %s"), base_name);
  2104.         EMSG2(_("Font '%s' is not fixed-width"), font_name[i]);
  2105.         return FAIL;
  2106.     }
  2107.     }
  2108.     /* scan base font width */
  2109.     min_width = 32767;
  2110.     for (i = 0; i < fn; i++)
  2111.     {
  2112.     if (xfs[i]->max_bounds.width<min_width)
  2113.     {
  2114.         min_width = xfs[i]->max_bounds.width;
  2115.         min_font_idx = i;
  2116.     }
  2117.     }
  2118.     for (i = 0; i < fn; i++)
  2119.     {
  2120.     if (       xfs[i]->max_bounds.width != 2 * min_width
  2121.         && xfs[i]->max_bounds.width != min_width)
  2122.     {
  2123.         EMSG2(_("E253: Fontset name: %s\n"), base_name);
  2124.         EMSG2(_("Font0: %s\n"), font_name[min_font_idx]);
  2125.         EMSG2(_("Font1: %s\n"), font_name[i]);
  2126.         EMSGN(_("Font%d width is not twice that of font0\n"), i);
  2127.         EMSGN(_("Font0 width: %ld\n"), xfs[min_font_idx]->max_bounds.width);
  2128.         EMSGN(_("Font1 width: %ld\n\n"), xfs[i]->max_bounds.width);
  2129.         return FAIL;
  2130.     }
  2131.     }
  2132.     /* it seems ok. Good Luck!! */
  2133.     return OK;
  2134. }
  2135.  
  2136.     static int
  2137. fontset_width(fs)
  2138.     XFontSet fs;
  2139. {
  2140.     return XmbTextEscapement(fs, "Vim", 3) / 3;
  2141. }
  2142.  
  2143.     int
  2144. fontset_height(fs)
  2145.     XFontSet fs;
  2146. {
  2147.     XFontSetExtents *extents;
  2148.  
  2149.     extents = XExtentsOfFontSet(fs);
  2150.     return extents->max_logical_extent.height;
  2151. }
  2152.  
  2153. #if (defined(FONTSET_ALWAYS) && defined(FEAT_GUI_ATHENA) \
  2154.         && defined(FEAT_MENU)) || defined(PROTO)
  2155. /*
  2156.  * Returns the bounding box height around the actual glyph image of all
  2157.  * characters in all fonts of the fontset.
  2158.  */
  2159.     int
  2160. fontset_height2(fs)
  2161.     XFontSet fs;
  2162. {
  2163.     XFontSetExtents *extents;
  2164.  
  2165.     extents = XExtentsOfFontSet(fs);
  2166.     return extents->max_ink_extent.height;
  2167. }
  2168. #endif
  2169.  
  2170. /* NOT USED YET
  2171.     static int
  2172. fontset_descent(fs)
  2173.     XFontSet fs;
  2174. {
  2175.     XFontSetExtents *extents;
  2176.  
  2177.     extents = XExtentsOfFontSet (fs);
  2178.     return extents->max_logical_extent.height + extents->max_logical_extent.y;
  2179. }
  2180. */
  2181.  
  2182.     static int
  2183. fontset_ascent(fs)
  2184.     XFontSet fs;
  2185. {
  2186.     XFontSetExtents *extents;
  2187.  
  2188.     extents = XExtentsOfFontSet(fs);
  2189.     return -extents->max_logical_extent.y;
  2190. }
  2191.  
  2192. #endif /* FEAT_XFONTSET */
  2193.  
  2194. /*
  2195.  * Return the Pixel value (color) for the given color name.
  2196.  * Return INVALCOLOR for error.
  2197.  */
  2198.     guicolor_T
  2199. gui_mch_get_color(reqname)
  2200.     char_u *reqname;
  2201. {
  2202.     int        i;
  2203.     char_u    *name = reqname;
  2204.     Colormap    colormap;
  2205.     XColor      color;
  2206.     static char *(vimnames[][2]) =
  2207.     {
  2208.     /* A number of colors that some X11 systems don't have */
  2209.     {"LightRed",    "#FFBBBB"},
  2210.     {"LightGreen",    "#88FF88"},
  2211.     {"LightMagenta","#FFBBFF"},
  2212.     {"DarkCyan",    "#008888"},
  2213.     {"DarkBlue",    "#0000BB"},
  2214.     {"DarkRed",    "#BB0000"},
  2215.     {"DarkMagenta",    "#BB00BB"},
  2216.     {"DarkGrey",    "#BBBBBB"},
  2217.     {"DarkYellow",    "#BBBB00"},
  2218.     {NULL, NULL}
  2219.     };
  2220.  
  2221.     /* can't do this when GUI not running */
  2222.     if (!gui.in_use || *reqname == NUL)
  2223.     return INVALCOLOR;
  2224.  
  2225.     colormap = DefaultColormap(gui.dpy, XDefaultScreen(gui.dpy));
  2226.  
  2227.     /* Do this twice if the name isn't recognized. */
  2228.     while (name != NULL)
  2229.     {
  2230.     i = XParseColor(gui.dpy, colormap, (char *)name, &color);
  2231.  
  2232. #if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
  2233.     if (i == 0)
  2234.     {
  2235.         char *old;
  2236.  
  2237.         /* The X11 system is trying to resolve named colors only by names
  2238.          * corresponding to the current locale language.  But Vim scripts
  2239.          * usually contain the English color names.  Therefore we have to
  2240.          * try a second time here with the native "C" locale set.
  2241.          * Hopefully, restoring the old locale this way works on all
  2242.          * systems...
  2243.          */
  2244.         old = setlocale(LC_ALL, NULL);
  2245.         if (old != NULL && STRCMP(old, "C") != 0)
  2246.         {
  2247.         old = (char *)vim_strsave((char_u *)old);
  2248.         setlocale(LC_ALL, "C");
  2249.         i = XParseColor(gui.dpy, colormap, (char *)name, &color);
  2250.         setlocale(LC_ALL, old);
  2251.         vim_free(old);
  2252.         }
  2253.     }
  2254. #endif
  2255.     if (i != 0 && (XAllocColor(gui.dpy, colormap, &color) != 0
  2256.             || find_closest_color(colormap, &color) == OK))
  2257.         return (guicolor_T)color.pixel;
  2258.  
  2259.     /* check for a few builtin names */
  2260.     for (i = 0; ; ++i)
  2261.     {
  2262.         if (vimnames[i][0] == NULL)
  2263.         {
  2264.         name = NULL;
  2265.         break;
  2266.         }
  2267.         if (STRICMP(name, vimnames[i][0]) == 0)
  2268.         {
  2269.         name = (char_u *)vimnames[i][1];
  2270.         break;
  2271.         }
  2272.     }
  2273.     }
  2274.  
  2275.     return INVALCOLOR;
  2276. }
  2277.  
  2278. /*
  2279.  * Find closest color for "colorPtr" in "colormap".  set "colorPtr" to the
  2280.  * resulting color.
  2281.  * Based on a similar function in TCL.
  2282.  * Return FAIL if not able to find or allocate a color.
  2283.  */
  2284.     static int
  2285. find_closest_color(colormap, colorPtr)
  2286.     Colormap    colormap;
  2287.     XColor    *colorPtr;
  2288. {
  2289.     double    tmp, distance, closestDistance;
  2290.     int        i, closest, numFound, cmap_size;
  2291.     XColor    *colortable;
  2292.     XVisualInfo    template, *visInfoPtr;
  2293.  
  2294.     template.visualid = XVisualIDFromVisual(DefaultVisual(gui.dpy,
  2295.                             XDefaultScreen(gui.dpy)));
  2296.     visInfoPtr = XGetVisualInfo(gui.dpy, (long)VisualIDMask,
  2297.                             &template, &numFound);
  2298.     if (numFound < 1)
  2299.     /* FindClosestColor couldn't lookup visual */
  2300.     return FAIL;
  2301.  
  2302.     cmap_size = visInfoPtr->colormap_size;
  2303.     XFree((char *)visInfoPtr);
  2304.     colortable = (XColor *)alloc((unsigned)(cmap_size * sizeof(XColor)));
  2305.     if (!colortable)
  2306.     return FAIL;  /* out of memory */
  2307.  
  2308.     for (i = 0; i  < cmap_size; i++)
  2309.     colortable[i].pixel = (unsigned long)i;
  2310.     XQueryColors (gui.dpy, colormap, colortable, cmap_size);
  2311.  
  2312.     /*
  2313.      * Find the color that best approximates the desired one, then
  2314.      * try to allocate that color.  If that fails, it must mean that
  2315.      * the color was read-write (so we can't use it, since it's owner
  2316.      * might change it) or else it was already freed.  Try again,
  2317.      * over and over again, until something succeeds.
  2318.      */
  2319.     closestDistance = 1e30;
  2320.     closest = 0;
  2321.     for (i = 0; i < cmap_size; i++)
  2322.     {
  2323.     /*
  2324.      * Use Euclidean distance in RGB space, weighted by Y (of YIQ)
  2325.      * as the objective function;  this accounts for differences
  2326.      * in the color sensitivity of the eye.
  2327.      */
  2328.     tmp = .30 * (((int)colorPtr->red) - (int)colortable[i].red);
  2329.     distance = tmp * tmp;
  2330.     tmp = .61 * (((int)colorPtr->green) - (int)colortable[i].green);
  2331.     distance += tmp * tmp;
  2332.     tmp = .11 * (((int)colorPtr->blue) - (int)colortable[i].blue);
  2333.     distance += tmp * tmp;
  2334.     if (distance < closestDistance)
  2335.     {
  2336.         closest = i;
  2337.         closestDistance = distance;
  2338.     }
  2339.     }
  2340.  
  2341.     if (XAllocColor(gui.dpy, colormap, &colortable[closest]) != 0)
  2342.     {
  2343.     gui.color_approx = TRUE;
  2344.     *colorPtr = colortable[closest];
  2345.     }
  2346.  
  2347.     free(colortable);
  2348.     return OK;
  2349. }
  2350.  
  2351.     void
  2352. gui_mch_set_fg_color(color)
  2353.     guicolor_T    color;
  2354. {
  2355.     if (color != prev_fg_color)
  2356.     {
  2357.     XSetForeground(gui.dpy, gui.text_gc, (Pixel)color);
  2358.     prev_fg_color = color;
  2359.     }
  2360. }
  2361.  
  2362. /*
  2363.  * Set the current text background color.
  2364.  */
  2365.     void
  2366. gui_mch_set_bg_color(color)
  2367.     guicolor_T    color;
  2368. {
  2369.     if (color != prev_bg_color)
  2370.     {
  2371.     XSetBackground(gui.dpy, gui.text_gc, (Pixel)color);
  2372.     prev_bg_color = color;
  2373.     }
  2374. }
  2375.  
  2376. /*
  2377.  * create a mouse pointer that is blank
  2378.  */
  2379.     static Cursor
  2380. gui_x11_create_blank_mouse()
  2381. {
  2382.     Pixmap blank_pixmap = XCreatePixmap(gui.dpy, gui.wid, 1, 1, 1);
  2383.     GC gc = XCreateGC(gui.dpy, blank_pixmap, (unsigned long)0, (XGCValues*)0);
  2384.     XDrawPoint(gui.dpy, blank_pixmap, gc, 0, 0);
  2385.     XFreeGC(gui.dpy, gc);
  2386.     return XCreatePixmapCursor(gui.dpy, blank_pixmap, blank_pixmap,
  2387.         (XColor*)&gui.norm_pixel, (XColor*)&gui.norm_pixel, 0, 0);
  2388. }
  2389.  
  2390.     void
  2391. gui_mch_draw_string(row, col, s, len, flags)
  2392.     int        row;
  2393.     int        col;
  2394.     char_u    *s;
  2395.     int        len;
  2396.     int        flags;
  2397. {
  2398.     int            cells = len;
  2399. #ifdef FEAT_MBYTE
  2400.     static XChar2b    *buf = NULL;
  2401.     static int        buflen = 0;
  2402.     char_u        *p;
  2403.     int            wlen = 0;
  2404.     int            c;
  2405.  
  2406.     if (enc_utf8)
  2407.     {
  2408.     /* Convert UTF-8 byte sequence to 16 bit characters for the X
  2409.      * functions.  Need a buffer for the 16 bit characters.  Keep it
  2410.      * between calls, because allocating it each time is slow. */
  2411.     if (buflen < len)
  2412.     {
  2413.         XtFree((char *)buf);
  2414.         buf = (XChar2b *)XtMalloc(len * sizeof(XChar2b));
  2415.         buflen = len;
  2416.     }
  2417.     p = s;
  2418.     cells = 0;
  2419.     while (p < s + len)
  2420.     {
  2421.         c = utf_ptr2char(p);
  2422.         if (c >= 0x10000)    /* show chars > 0xffff as ? */
  2423.         c = 0xbf;
  2424.         buf[wlen].byte1 = (unsigned)c >> 8;
  2425.         buf[wlen].byte2 = c;
  2426.         ++wlen;
  2427.         cells += utf_char2cells(c);
  2428.         p += utf_ptr2len_check(p);
  2429.     }
  2430.     }
  2431.     else if (has_mbyte)
  2432.     {
  2433.     cells = 0;
  2434.     for (p = s; p < s + len; )
  2435.     {
  2436.         cells += ptr2cells(p);
  2437.         p += (*mb_ptr2len_check)(p);
  2438.     }
  2439.     }
  2440.  
  2441. #endif
  2442.  
  2443. #ifdef FEAT_XFONTSET
  2444.     if (current_fontset != NULL)
  2445.     {
  2446.     /* Setup a clip rectangle to avoid spilling over in the next or
  2447.      * previous line.  This is apparently needed for some fonts which are
  2448.      * used in a fontset. */
  2449.     XRectangle    clip;
  2450.  
  2451.     clip.x = 0;
  2452.     clip.y = 0;
  2453.     clip.height = gui.char_height;
  2454.     clip.width = gui.char_width * cells + 1;
  2455.     XSetClipRectangles(gui.dpy, gui.text_gc, FILL_X(col), FILL_Y(row),
  2456.         &clip, 1, Unsorted);
  2457.     }
  2458. #endif
  2459.  
  2460.     if (flags & DRAW_TRANSP)
  2461.     {
  2462. #ifdef FEAT_MBYTE
  2463.     if (enc_utf8)
  2464.         XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2465.             TEXT_Y(row), buf, wlen);
  2466.     else
  2467. #endif
  2468.         XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2469.             TEXT_Y(row), (char *)s, len);
  2470.     }
  2471.     else if (p_linespace != 0
  2472. #ifdef FEAT_XFONTSET
  2473.         || current_fontset != NULL
  2474. #endif
  2475.         )
  2476.     {
  2477.     XSetForeground(gui.dpy, gui.text_gc, prev_bg_color);
  2478.     XFillRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
  2479.         FILL_Y(row), gui.char_width * cells, gui.char_height);
  2480.     XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
  2481. #ifdef FEAT_MBYTE
  2482.     if (enc_utf8)
  2483.         XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2484.             TEXT_Y(row), buf, wlen);
  2485.     else
  2486. #endif
  2487.         XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2488.             TEXT_Y(row), (char *)s, len);
  2489.     }
  2490.     else
  2491.     {
  2492.     /* XmbDrawImageString has bug, don't use it for fontset. */
  2493. #ifdef FEAT_MBYTE
  2494.     if (enc_utf8)
  2495.         XDrawImageString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2496.             TEXT_Y(row), buf, wlen);
  2497.     else
  2498. #endif
  2499.         XDrawImageString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
  2500.             TEXT_Y(row), (char *)s, len);
  2501.     }
  2502.  
  2503.     /* Bold trick: draw the text again with a one-pixel offset. */
  2504.     if (flags & DRAW_BOLD)
  2505.     {
  2506. #ifdef FEAT_MBYTE
  2507.     if (enc_utf8)
  2508.         XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
  2509.             TEXT_Y(row), buf, wlen);
  2510.     else
  2511. #endif
  2512.         XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
  2513.             TEXT_Y(row), (char *)s, len);
  2514.     }
  2515.  
  2516.     /* Underline: draw a line at the bottom of the character cell. */
  2517.     if (flags & DRAW_UNDERL)
  2518.     XDrawLine(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
  2519.          FILL_Y(row + 1) - 1, FILL_X(col + cells) - 1, FILL_Y(row + 1) - 1);
  2520.  
  2521. #ifdef FEAT_XFONTSET
  2522.     if (current_fontset != NULL)
  2523.     XSetClipMask(gui.dpy, gui.text_gc, None);
  2524. #endif
  2525. }
  2526.  
  2527. /*
  2528.  * Return OK if the key with the termcap name "name" is supported.
  2529.  */
  2530.     int
  2531. gui_mch_haskey(name)
  2532.     char_u  *name;
  2533. {
  2534.     int i;
  2535.  
  2536.     for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
  2537.     if (name[0] == special_keys[i].vim_code0 &&
  2538.                      name[1] == special_keys[i].vim_code1)
  2539.         return OK;
  2540.     return FAIL;
  2541. }
  2542.  
  2543. /*
  2544.  * Return the text window-id and display.  Only required for X-based GUI's
  2545.  */
  2546.     int
  2547. gui_get_x11_windis(win, dis)
  2548.     Window  *win;
  2549.     Display **dis;
  2550. {
  2551.     *win = XtWindow(vimShell);
  2552.     *dis = gui.dpy;
  2553.     return OK;
  2554. }
  2555.  
  2556.     void
  2557. gui_mch_beep()
  2558. {
  2559.     XBell(gui.dpy, 0);
  2560. }
  2561.  
  2562.     void
  2563. gui_mch_flash(msec)
  2564.     int        msec;
  2565. {
  2566.     /* Do a visual beep by reversing the foreground and background colors */
  2567.     XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
  2568.         FILL_X((int)Columns) + gui.border_offset,
  2569.         FILL_Y((int)Rows) + gui.border_offset);
  2570.     XSync(gui.dpy, False);
  2571.     ui_delay((long)msec, TRUE);    /* wait for a few msec */
  2572.     XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
  2573.         FILL_X((int)Columns) + gui.border_offset,
  2574.         FILL_Y((int)Rows) + gui.border_offset);
  2575. }
  2576.  
  2577. /*
  2578.  * Invert a rectangle from row r, column c, for nr rows and nc columns.
  2579.  */
  2580.     void
  2581. gui_mch_invert_rectangle(r, c, nr, nc)
  2582.     int        r;
  2583.     int        c;
  2584.     int        nr;
  2585.     int        nc;
  2586. {
  2587.     XFillRectangle(gui.dpy, gui.wid, gui.invert_gc,
  2588.     FILL_X(c), FILL_Y(r), (nc) * gui.char_width, (nr) * gui.char_height);
  2589. }
  2590.  
  2591. /*
  2592.  * Iconify the GUI window.
  2593.  */
  2594.     void
  2595. gui_mch_iconify()
  2596. {
  2597.     XIconifyWindow(gui.dpy, XtWindow(vimShell), DefaultScreen(gui.dpy));
  2598. }
  2599.  
  2600. #if defined(FEAT_EVAL) || defined(PROTO)
  2601. /*
  2602.  * Bring the Vim window to the foreground.
  2603.  */
  2604.     void
  2605. gui_mch_set_foreground()
  2606. {
  2607.     XMapRaised(gui.dpy, XtWindow(vimShell));
  2608. }
  2609. #endif
  2610.  
  2611. /*
  2612.  * Draw a cursor without focus.
  2613.  */
  2614.     void
  2615. gui_mch_draw_hollow_cursor(color)
  2616.     guicolor_T color;
  2617. {
  2618.     int        w = 1;
  2619.  
  2620. #ifdef FEAT_MBYTE
  2621.     if (mb_lefthalve(gui.row, gui.col))
  2622.     w = 2;
  2623. #endif
  2624.     gui_mch_set_fg_color(color);
  2625.     XDrawRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(gui.col),
  2626.         FILL_Y(gui.row), w * gui.char_width - 1, gui.char_height - 1);
  2627. }
  2628.  
  2629. /*
  2630.  * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
  2631.  * color "color".
  2632.  */
  2633.     void
  2634. gui_mch_draw_part_cursor(w, h, color)
  2635.     int        w;
  2636.     int        h;
  2637.     guicolor_T    color;
  2638. {
  2639.     gui_mch_set_fg_color(color);
  2640.  
  2641.     XFillRectangle(gui.dpy, gui.wid, gui.text_gc,
  2642. #ifdef FEAT_RIGHTLEFT
  2643.         /* vertical line should be on the right of current point */
  2644.         CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
  2645. #endif
  2646.         FILL_X(gui.col),
  2647.         FILL_Y(gui.row) + gui.char_height - h,
  2648.         w, h);
  2649. }
  2650.  
  2651. /*
  2652.  * Catch up with any queued X events.  This may put keyboard input into the
  2653.  * input buffer, call resize call-backs, trigger timers etc.  If there is
  2654.  * nothing in the X event queue (& no timers pending), then we return
  2655.  * immediately.
  2656.  */
  2657.     void
  2658. gui_mch_update()
  2659. {
  2660.     XtInputMask mask, desired;
  2661.  
  2662. #ifdef ALT_X_INPUT
  2663.     if (suppress_alternate_input)
  2664.     desired = (XtIMXEvent | XtIMTimer);
  2665.     else
  2666. #endif
  2667.     desired = (XtIMAll);
  2668.     while ((mask = XtAppPending(app_context)) && (mask & desired)
  2669.         && !vim_is_input_buf_full())
  2670.     XtAppProcessEvent(app_context, desired);
  2671. }
  2672.  
  2673. /*
  2674.  * GUI input routine called by gui_wait_for_chars().  Waits for a character
  2675.  * from the keyboard.
  2676.  *  wtime == -1        Wait forever.
  2677.  *  wtime == 0        This should never happen.
  2678.  *  wtime > 0        Wait wtime milliseconds for a character.
  2679.  * Returns OK if a character was found to be available within the given time,
  2680.  * or FAIL otherwise.
  2681.  */
  2682.     int
  2683. gui_mch_wait_for_chars(wtime)
  2684.     long    wtime;
  2685. {
  2686.     int            focus;
  2687.  
  2688.     /*
  2689.      * Make this static, in case gui_x11_timer_cb is called after leaving
  2690.      * this function (otherwise a random value on the stack may be changed).
  2691.      */
  2692.     static int        timed_out;
  2693.     XtIntervalId    timer = (XtIntervalId)0;
  2694.     XtInputMask        desired;
  2695. #ifdef FEAT_SNIFF
  2696.     static int        sniff_on = 0;
  2697.     static XtInputId sniff_input_id = 0;
  2698. #endif
  2699.  
  2700.     timed_out = FALSE;
  2701.  
  2702. #ifdef FEAT_SNIFF
  2703.     if (sniff_on && !want_sniff_request)
  2704.     {
  2705.     if (sniff_input_id)
  2706.         XtRemoveInput(sniff_input_id);
  2707.     sniff_on = 0;
  2708.     }
  2709.     else if (!sniff_on && want_sniff_request)
  2710.     {
  2711.     sniff_input_id = XtAppAddInput(app_context, fd_from_sniff,
  2712.              (XtPointer)XtInputReadMask, gui_x11_sniff_request_cb, 0);
  2713.     sniff_on = 1;
  2714.     }
  2715. #endif
  2716.  
  2717.     if (wtime > 0)
  2718.     timer = XtAppAddTimeOut(app_context, (long_u)wtime, gui_x11_timer_cb,
  2719.                                   &timed_out);
  2720.  
  2721.     focus = gui.in_focus;
  2722. #ifdef ALT_X_INPUT
  2723.     if (suppress_alternate_input)
  2724.     desired = (XtIMXEvent | XtIMTimer);
  2725.     else
  2726. #endif
  2727.     desired = (XtIMAll);
  2728.     while (!timed_out)
  2729.     {
  2730.     /* Stop or start blinking when focus changes */
  2731.     if (gui.in_focus != focus)
  2732.     {
  2733.         if (gui.in_focus)
  2734.         gui_mch_start_blink();
  2735.         else
  2736.         gui_mch_stop_blink();
  2737.         focus = gui.in_focus;
  2738.     }
  2739.  
  2740.     /*
  2741.      * Don't use gui_mch_update() because then we will spin-lock until a
  2742.      * char arrives, instead we use XtAppProcessEvent() to hang until an
  2743.      * event arrives.  No need to check for input_buf_full because we are
  2744.      * returning as soon as it contains a single char.  Note that
  2745.      * XtAppNextEvent() may not be used because it will not return after a
  2746.      * timer event has arrived -- webb
  2747.      */
  2748.     XtAppProcessEvent(app_context, desired);
  2749.  
  2750.     if (input_available())
  2751.     {
  2752.         if (timer != (XtIntervalId)0 && !timed_out)
  2753.         XtRemoveTimeOut(timer);
  2754.         return OK;
  2755.     }
  2756.     }
  2757.     return FAIL;
  2758. }
  2759.  
  2760. /*
  2761.  * Output routines.
  2762.  */
  2763.  
  2764. /* Flush any output to the screen */
  2765.     void
  2766. gui_mch_flush()
  2767. {
  2768.     XFlush(gui.dpy);
  2769. }
  2770.  
  2771. /*
  2772.  * Clear a rectangular region of the screen from text pos (row1, col1) to
  2773.  * (row2, col2) inclusive.
  2774.  */
  2775.     void
  2776. gui_mch_clear_block(row1, col1, row2, col2)
  2777.     int        row1;
  2778.     int        col1;
  2779.     int        row2;
  2780.     int        col2;
  2781. {
  2782.     int        x;
  2783.  
  2784.     x = FILL_X(col1);
  2785.  
  2786.     /* Clear one extra pixel at the far right, for when bold characters have
  2787.      * spilled over to the next column. */
  2788.     XFillRectangle(gui.dpy, gui.wid, gui.back_gc, x, FILL_Y(row1),
  2789.         (col2 - col1 + 1) * gui.char_width + (col2 == Columns - 1),
  2790.         (row2 - row1 + 1) * gui.char_height);
  2791. }
  2792.  
  2793.     void
  2794. gui_mch_clear_all()
  2795. {
  2796.     XClearArea(gui.dpy, gui.wid, 0, 0, 0, 0, False);
  2797. }
  2798.  
  2799. /*
  2800.  * Delete the given number of lines from the given row, scrolling up any
  2801.  * text further down within the scroll region.
  2802.  */
  2803.     void
  2804. gui_mch_delete_lines(row, num_lines)
  2805.     int        row;
  2806.     int        num_lines;
  2807. {
  2808.     if (gui.visibility == VisibilityFullyObscured)
  2809.     return;        /* Can't see the window */
  2810.  
  2811.     /* copy one extra pixel at the far right, for when bold has spilled
  2812.      * over */
  2813.     XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
  2814.     FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
  2815.     gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
  2816.                    + (gui.scroll_region_right == Columns - 1),
  2817.     gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
  2818.     FILL_X(gui.scroll_region_left), FILL_Y(row));
  2819.  
  2820.     gui_clear_block(gui.scroll_region_bot - num_lines + 1,
  2821.                                gui.scroll_region_left,
  2822.               gui.scroll_region_bot, gui.scroll_region_right);
  2823.     gui_x11_check_copy_area();
  2824. }
  2825.  
  2826. /*
  2827.  * Insert the given number of lines before the given row, scrolling down any
  2828.  * following text within the scroll region.
  2829.  */
  2830.     void
  2831. gui_mch_insert_lines(row, num_lines)
  2832.     int        row;
  2833.     int        num_lines;
  2834. {
  2835.     if (gui.visibility == VisibilityFullyObscured)
  2836.     return;        /* Can't see the window */
  2837.  
  2838.     /* copy one extra pixel at the far right, for when bold has spilled
  2839.      * over */
  2840.     XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
  2841.     FILL_X(gui.scroll_region_left), FILL_Y(row),
  2842.     gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
  2843.                    + (gui.scroll_region_right == Columns - 1),
  2844.     gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
  2845.     FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines));
  2846.  
  2847.     gui_clear_block(row, gui.scroll_region_left,
  2848.                 row + num_lines - 1, gui.scroll_region_right);
  2849.     gui_x11_check_copy_area();
  2850. }
  2851.  
  2852. /*
  2853.  * Update the region revealed by scrolling up/down.
  2854.  */
  2855.     static void
  2856. gui_x11_check_copy_area()
  2857. {
  2858.     XEvent            event;
  2859.     XGraphicsExposeEvent    *gevent;
  2860.  
  2861.     if (gui.visibility != VisibilityPartiallyObscured)
  2862.     return;
  2863.  
  2864.     XFlush(gui.dpy);
  2865.  
  2866.     /* Wait to check whether the scroll worked or not */
  2867.     for (;;)
  2868.     {
  2869.     if (XCheckTypedEvent(gui.dpy, NoExpose, &event))
  2870.         return;    /* The scroll worked. */
  2871.  
  2872.     if (XCheckTypedEvent(gui.dpy, GraphicsExpose, &event))
  2873.     {
  2874.         gevent = (XGraphicsExposeEvent *)&event;
  2875.         gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
  2876.         if (gevent->count == 0)
  2877.         return;        /* This was the last expose event */
  2878.     }
  2879.     XSync(gui.dpy, False);
  2880.     }
  2881. }
  2882.  
  2883. /*
  2884.  * X Selection stuff, for cutting and pasting text to other windows.
  2885.  */
  2886.  
  2887.     void
  2888. clip_mch_lose_selection(cbd)
  2889.     VimClipboard    *cbd;
  2890. {
  2891.     clip_x11_lose_selection(vimShell, cbd);
  2892. }
  2893.  
  2894.     int
  2895. clip_mch_own_selection(cbd)
  2896.     VimClipboard    *cbd;
  2897. {
  2898.     return clip_x11_own_selection(vimShell, cbd);
  2899. }
  2900.  
  2901.     void
  2902. clip_mch_request_selection(cbd)
  2903.     VimClipboard    *cbd;
  2904. {
  2905.     clip_x11_request_selection(vimShell, gui.dpy, cbd);
  2906. }
  2907.  
  2908.     void
  2909. clip_mch_set_selection(cbd)
  2910.     VimClipboard    *cbd;
  2911. {
  2912.     clip_x11_set_selection(cbd);
  2913. }
  2914.  
  2915. #if defined(FEAT_MENU) || defined(PROTO)
  2916. /*
  2917.  * Menu stuff.
  2918.  */
  2919.  
  2920. /*
  2921.  * Make a menu either grey or not grey.
  2922.  */
  2923.     void
  2924. gui_mch_menu_grey(menu, grey)
  2925.     vimmenu_T    *menu;
  2926.     int        grey;
  2927. {
  2928.     if (menu->id != (Widget)0)
  2929.     {
  2930.     gui_mch_menu_hidden(menu, False);
  2931.     if (grey
  2932. #ifdef FEAT_GUI_MOTIF
  2933.         || !menu->sensitive
  2934. #endif
  2935.         )
  2936.         XtSetSensitive(menu->id, False);
  2937.     else
  2938.         XtSetSensitive(menu->id, True);
  2939.     }
  2940. }
  2941.  
  2942. /*
  2943.  * Make menu item hidden or not hidden
  2944.  */
  2945.     void
  2946. gui_mch_menu_hidden(menu, hidden)
  2947.     vimmenu_T    *menu;
  2948.     int        hidden;
  2949. {
  2950.     if (menu->id != (Widget)0)
  2951.     {
  2952.     if (hidden)
  2953.         XtUnmanageChild(menu->id);
  2954.     else
  2955.         XtManageChild(menu->id);
  2956.     }
  2957. }
  2958.  
  2959. /*
  2960.  * This is called after setting all the menus to grey/hidden or not.
  2961.  */
  2962.     void
  2963. gui_mch_draw_menubar()
  2964. {
  2965.     /* Nothing to do in X */
  2966. }
  2967.  
  2968. /* ARGSUSED */
  2969.     void
  2970. gui_x11_menu_cb(w, client_data, call_data)
  2971.     Widget    w;
  2972.     XtPointer    client_data, call_data;
  2973. {
  2974.     gui_menu_cb((vimmenu_T *)client_data);
  2975. }
  2976.  
  2977. #endif /* FEAT_MENU */
  2978.  
  2979.  
  2980.  
  2981. /*
  2982.  * Function called when window closed.    Works like ":qa".
  2983.  * Should put up a requester!
  2984.  */
  2985. /*ARGSUSED*/
  2986.     static void
  2987. gui_x11_wm_protocol_handler(w, client_data, event, dum)
  2988.     Widget    w;
  2989.     XtPointer    client_data;
  2990.     XEvent    *event;
  2991.     Boolean    *dum;
  2992. {
  2993.     /*
  2994.      * Only deal with Client messages.
  2995.      */
  2996.     if (event->type != ClientMessage)
  2997.     return;
  2998.  
  2999.     /*
  3000.      * The WM_SAVE_YOURSELF event arrives when the window manager wants to
  3001.      * exit.  That can be cancelled though, thus Vim shouldn't exit here.
  3002.      * Just sync our swap files.
  3003.      */
  3004.     if (((XClientMessageEvent *)event)->data.l[0] ==
  3005.                           wm_atoms[SAVE_YOURSELF_IDX])
  3006.     {
  3007.     out_flush();
  3008.     ml_sync_all(FALSE, FALSE);    /* preserve all swap files */
  3009.  
  3010.     /* Set the window's WM_COMMAND property, to let the window manager
  3011.      * know we are done saving ourselves.  We don't want to be restarted,
  3012.      * thus set argv to NULL. */
  3013.     XSetCommand(gui.dpy, XtWindow(vimShell), NULL, 0);
  3014.     return;
  3015.     }
  3016.  
  3017.     if (((XClientMessageEvent *)event)->data.l[0] !=
  3018.                           wm_atoms[DELETE_WINDOW_IDX])
  3019.     return;
  3020.  
  3021.     gui_shell_closed();
  3022. }
  3023.  
  3024. #ifdef FEAT_CLIENTSERVER
  3025. /*
  3026.  * Function called when property changed. Check for incoming commands
  3027.  */
  3028. /*ARGSUSED*/
  3029.     static void
  3030. gui_x11_send_event_handler(w, client_data, event, dum)
  3031.     Widget    w;
  3032.     XtPointer    client_data;
  3033.     XEvent    *event;
  3034.     Boolean    *dum;
  3035. {
  3036.     XPropertyEvent *e = (XPropertyEvent *) event;
  3037.  
  3038.     if (e->type == PropertyNotify && e->window == commWindow
  3039.         && e->atom == commProperty &&  e->state == PropertyNewValue)
  3040.     {
  3041.     serverEventProc(gui.dpy, event);
  3042.     }
  3043. }
  3044. #endif
  3045.  
  3046. /*
  3047.  * Cursor blink functions.
  3048.  *
  3049.  * This is a simple state machine:
  3050.  * BLINK_NONE    not blinking at all
  3051.  * BLINK_OFF    blinking, cursor is not shown
  3052.  * BLINK_ON    blinking, cursor is shown
  3053.  */
  3054.  
  3055. #define BLINK_NONE  0
  3056. #define BLINK_OFF   1
  3057. #define BLINK_ON    2
  3058.  
  3059. static int        blink_state = BLINK_NONE;
  3060. static long_u        blink_waittime = 700;
  3061. static long_u        blink_ontime = 400;
  3062. static long_u        blink_offtime = 250;
  3063. static XtIntervalId    blink_timer = (XtIntervalId)0;
  3064.  
  3065.     void
  3066. gui_mch_set_blinking(waittime, on, off)
  3067.     long    waittime, on, off;
  3068. {
  3069.     blink_waittime = waittime;
  3070.     blink_ontime = on;
  3071.     blink_offtime = off;
  3072. }
  3073.  
  3074. /*
  3075.  * Stop the cursor blinking.  Show the cursor if it wasn't shown.
  3076.  */
  3077.     void
  3078. gui_mch_stop_blink()
  3079. {
  3080.     if (blink_timer != (XtIntervalId)0)
  3081.     {
  3082.     XtRemoveTimeOut(blink_timer);
  3083.     blink_timer = (XtIntervalId)0;
  3084.     }
  3085.     if (blink_state == BLINK_OFF)
  3086.     gui_update_cursor(TRUE, FALSE);
  3087.     blink_state = BLINK_NONE;
  3088. }
  3089.  
  3090. /*
  3091.  * Start the cursor blinking.  If it was already blinking, this restarts the
  3092.  * waiting time and shows the cursor.
  3093.  */
  3094.     void
  3095. gui_mch_start_blink()
  3096. {
  3097.     if (blink_timer != (XtIntervalId)0)
  3098.     XtRemoveTimeOut(blink_timer);
  3099.     /* Only switch blinking on if none of the times is zero */
  3100.     if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
  3101.     {
  3102.     blink_timer = XtAppAddTimeOut(app_context, blink_waittime,
  3103.                               gui_x11_blink_cb, NULL);
  3104.     blink_state = BLINK_ON;
  3105.     gui_update_cursor(TRUE, FALSE);
  3106.     }
  3107. }
  3108.  
  3109. /* ARGSUSED */
  3110.     static void
  3111. gui_x11_blink_cb(timed_out, interval_id)
  3112.     XtPointer        timed_out;
  3113.     XtIntervalId    *interval_id;
  3114. {
  3115.     if (blink_state == BLINK_ON)
  3116.     {
  3117.     gui_undraw_cursor();
  3118.     blink_state = BLINK_OFF;
  3119.     blink_timer = XtAppAddTimeOut(app_context, blink_offtime,
  3120.                               gui_x11_blink_cb, NULL);
  3121.     }
  3122.     else
  3123.     {
  3124.     gui_update_cursor(TRUE, FALSE);
  3125.     blink_state = BLINK_ON;
  3126.     blink_timer = XtAppAddTimeOut(app_context, blink_ontime,
  3127.                               gui_x11_blink_cb, NULL);
  3128.     }
  3129. }
  3130.  
  3131. /*
  3132.  * Return the RGB value of a pixel as a long.
  3133.  */
  3134.     long_u
  3135. gui_mch_get_rgb(pixel)
  3136.     guicolor_T    pixel;
  3137. {
  3138.     XColor    xc;
  3139.     Colormap    colormap;
  3140.  
  3141.     colormap = DefaultColormap(gui.dpy, XDefaultScreen(gui.dpy));
  3142.     xc.pixel = pixel;
  3143.     XQueryColor(gui.dpy, colormap, &xc);
  3144.  
  3145.     return ((xc.red & 0xff00) << 8) + (xc.green & 0xff00)
  3146.                            + ((unsigned)xc.blue >> 8);
  3147. }
  3148.  
  3149. /*
  3150.  * Add the callback functions.
  3151.  */
  3152.     void
  3153. gui_x11_callbacks(textArea, vimForm)
  3154.     Widget textArea;
  3155.     Widget vimForm;
  3156. {
  3157.     XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
  3158.     gui_x11_visibility_cb, (XtPointer)0);
  3159.  
  3160.     XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
  3161.     (XtPointer)0);
  3162.  
  3163.     XtAddEventHandler(vimShell, StructureNotifyMask, FALSE,
  3164.     gui_x11_resize_window_cb, (XtPointer)0);
  3165.  
  3166.     XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
  3167.     (XtPointer)0);
  3168.     /*
  3169.      * Only install these enter/leave callbacks when 'p' in 'guioptions'.
  3170.      * Only needed for some window managers.
  3171.      */
  3172.     if (vim_strchr(p_go, GO_POINTER) != NULL)
  3173.     {
  3174.     XtAddEventHandler(vimShell, LeaveWindowMask, FALSE, gui_x11_leave_cb,
  3175.         (XtPointer)0);
  3176.     XtAddEventHandler(textArea, LeaveWindowMask, FALSE, gui_x11_leave_cb,
  3177.         (XtPointer)0);
  3178.     XtAddEventHandler(textArea, EnterWindowMask, FALSE, gui_x11_enter_cb,
  3179.         (XtPointer)0);
  3180.     XtAddEventHandler(vimShell, EnterWindowMask, FALSE, gui_x11_enter_cb,
  3181.         (XtPointer)0);
  3182.     }
  3183.  
  3184.     XtAddEventHandler(vimForm, KeyPressMask, FALSE, gui_x11_key_hit_cb,
  3185.     (XtPointer)0);
  3186.     XtAddEventHandler(textArea, KeyPressMask, FALSE, gui_x11_key_hit_cb,
  3187.     (XtPointer)0);
  3188.  
  3189.     /* get pointer moved events from scrollbar, needed for 'mousefocus' */
  3190.     XtAddEventHandler(vimForm, PointerMotionMask,
  3191.     FALSE, gui_x11_mouse_cb, (XtPointer)1);
  3192.     XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
  3193.                      ButtonMotionMask | PointerMotionMask,
  3194.     FALSE, gui_x11_mouse_cb, (XtPointer)0);
  3195. }
  3196.  
  3197. /*
  3198.  * Get current y mouse coordinate in text window.
  3199.  * Return -1 when unknown.
  3200.  */
  3201.     int
  3202. gui_mch_get_mouse_x()
  3203. {
  3204.     int        rootx, rooty, winx, winy;
  3205.     Window    root, child;
  3206.     unsigned int mask;
  3207.  
  3208.     if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
  3209.                      &rootx, &rooty, &winx, &winy, &mask))
  3210.     return winx;
  3211.     return -1;
  3212. }
  3213.  
  3214.     int
  3215. gui_mch_get_mouse_y()
  3216. {
  3217.     int        rootx, rooty, winx, winy;
  3218.     Window    root, child;
  3219.     unsigned int mask;
  3220.  
  3221.     if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
  3222.                      &rootx, &rooty, &winx, &winy, &mask))
  3223.     return winy;
  3224.     return -1;
  3225. }
  3226.  
  3227.     void
  3228. gui_mch_setmouse(x, y)
  3229.     int        x;
  3230.     int        y;
  3231. {
  3232.     if (gui.wid)
  3233.     XWarpPointer(gui.dpy, (Window)0, gui.wid, 0, 0, 0, 0, x, y);
  3234. }
  3235.  
  3236. #if (defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)) || defined(PROTO)
  3237.     XButtonPressedEvent *
  3238. gui_x11_get_last_mouse_event()
  3239. {
  3240.     return &last_mouse_event;
  3241. }
  3242. #endif
  3243.  
  3244. #if defined(FEAT_SIGN_ICONS) || defined(PROTO)
  3245.  
  3246. /* Signs are currently always 2 chars wide.  Hopefully the font is big enough
  3247.  * to provide room for the bitmap! */
  3248. # define SIGN_WIDTH (gui.char_width * 2)
  3249.  
  3250. #if 0    /* not used */
  3251.     void
  3252. gui_mch_clearsign(row)
  3253.     int        row;
  3254. {
  3255.     if (gui.in_use)
  3256.     XClearArea(gui.dpy, gui.wid, 0, TEXT_Y(row) - gui.char_height,
  3257.         SIGN_WIDTH, gui.char_height, FALSE);
  3258. }
  3259. #endif
  3260.  
  3261.     void
  3262. gui_mch_drawsign(row, col, typenr)
  3263.     int        row;
  3264.     int        col;
  3265.     int        typenr;
  3266. {
  3267.     XImage    *sign;
  3268.  
  3269.     if (gui.in_use && (sign = (XImage *)sign_get_image(typenr)) != NULL)
  3270.     {
  3271.     XClearArea(gui.dpy, gui.wid, TEXT_X(col), TEXT_Y(row) - sign->height,
  3272.         SIGN_WIDTH, gui.char_height, FALSE);
  3273.     XPutImage(gui.dpy, gui.wid, gui.text_gc, sign, 0, 0,
  3274.         TEXT_X(col) + (SIGN_WIDTH - sign->width) / 2,
  3275.         TEXT_Y(row) - sign->height,
  3276.         sign->width, sign->height);
  3277.     }
  3278. }
  3279.  
  3280.     void *
  3281. gui_mch_register_sign(signfile)
  3282.     char_u        *signfile;
  3283. {
  3284.     XpmAttributes   attrs;
  3285.     XImage        *sign;
  3286.     int            status;
  3287.  
  3288.     /*
  3289.      * Setup the color substitution table.
  3290.      */
  3291.     sign = NULL;
  3292.     if (signfile[0] != NUL && signfile[0] != '-')
  3293.     {
  3294.     sign = (XImage *)alloc(sizeof(XImage));
  3295.     if (sign != NULL)
  3296.     {
  3297.         XpmColorSymbol color[5] =
  3298.         {
  3299.         {"none", NULL, 0},
  3300.         {"iconColor1", NULL, 0},
  3301.         {"bottomShadowColor", NULL, 0},
  3302.         {"topShadowColor", NULL, 0},
  3303.         {"selectColor", NULL, 0}
  3304.         };
  3305.         attrs.valuemask = XpmColorSymbols;
  3306.         attrs.numsymbols = 2;
  3307.         attrs.colorsymbols = color;
  3308.         attrs.colorsymbols[0].pixel = gui.back_pixel;
  3309.         attrs.colorsymbols[1].pixel = gui.norm_pixel;
  3310.         status = XpmReadFileToImage(gui.dpy, (char *)signfile,
  3311.                              &sign, NULL, &attrs);
  3312.  
  3313.         if (status == 0)
  3314.         {
  3315.         /* Sign width is fixed at two columns now.
  3316.         if (sign->width > gui.sign_width)
  3317.             gui.sign_width = sign->width + 8; */
  3318.         }
  3319.         else
  3320.         {
  3321.         vim_free(sign);
  3322.         sign = NULL;
  3323.         EMSG(_(e_signdata));
  3324.         }
  3325.     }
  3326.     }
  3327.  
  3328.     return (void *)sign;
  3329. }
  3330.  
  3331.     void
  3332. gui_mch_destroy_sign(sign)
  3333.     void *sign;
  3334. {
  3335.     XFree(((XImage *)sign)->data);
  3336.     vim_free(sign);
  3337. }
  3338. #endif
  3339.  
  3340.  
  3341. #ifdef FEAT_MOUSESHAPE
  3342. /* The last set mouse pointer shape is remembered, to be used when it goes
  3343.  * from hidden to not hidden. */
  3344. static int last_shape = 0;
  3345. #endif
  3346.  
  3347. /*
  3348.  * Use the blank mouse pointer or not.
  3349.  */
  3350.     void
  3351. gui_mch_mousehide(hide)
  3352.     int        hide;    /* TRUE = use blank ptr, FALSE = use parent ptr */
  3353. {
  3354.     if (gui.pointer_hidden != hide)
  3355.     {
  3356.     gui.pointer_hidden = hide;
  3357.     if (hide)
  3358.         XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
  3359.     else
  3360. #ifdef FEAT_MOUSESHAPE
  3361.         mch_set_mouse_shape(last_shape);
  3362. #else
  3363.         XUndefineCursor(gui.dpy, gui.wid);
  3364. #endif
  3365.     }
  3366. }
  3367.  
  3368. #if defined(FEAT_MOUSESHAPE) || defined(PROTO)
  3369.  
  3370. /* Table for shape IDs.  Keep in sync with the mshape_names[] table in
  3371.  * misc2.c! */
  3372. static int mshape_ids[] =
  3373. {
  3374.     XC_left_ptr,        /* arrow */
  3375.     0,                /* blank */
  3376.     XC_xterm,            /* beam */
  3377.     XC_sb_v_double_arrow,    /* updown */
  3378.     XC_sizing,            /* udsizing */
  3379.     XC_sb_h_double_arrow,    /* leftright */
  3380.     XC_sizing,            /* lrsizing */
  3381.     XC_watch,            /* busy */
  3382.     XC_X_cursor,        /* no */
  3383.     XC_crosshair,        /* crosshair */
  3384.     XC_hand1,            /* hand1 */
  3385.     XC_hand2,            /* hand2 */
  3386.     XC_pencil,            /* pencil */
  3387.     XC_question_arrow,        /* question */
  3388.     XC_right_ptr,        /* right-arrow */
  3389.     XC_center_ptr,        /* up-arrow */
  3390.     XC_left_ptr            /* last one */
  3391. };
  3392.  
  3393.     void
  3394. mch_set_mouse_shape(shape)
  3395.     int    shape;
  3396. {
  3397.     int        id;
  3398.  
  3399.     if (!gui.in_use)
  3400.     return;
  3401.  
  3402.     if (shape == MSHAPE_HIDE || gui.pointer_hidden)
  3403.     XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
  3404.     else
  3405.     {
  3406.     if (shape >= MSHAPE_NUMBERED)
  3407.     {
  3408.         id = shape - MSHAPE_NUMBERED;
  3409.         if (id >= XC_num_glyphs)
  3410.         id = XC_left_ptr;
  3411.         else
  3412.         id &= ~1;    /* they are always even (why?) */
  3413.     }
  3414.     else
  3415.         id = mshape_ids[shape];
  3416.  
  3417.     XDefineCursor(gui.dpy, gui.wid, XCreateFontCursor(gui.dpy, id));
  3418.     }
  3419.     if (shape != MSHAPE_HIDE)
  3420.     last_shape = shape;
  3421. }
  3422. #endif
  3423.  
  3424. #if defined(FEAT_TOOLBAR) || defined(PROTO)
  3425. /*
  3426.  * Icons used by the toolbar code.
  3427.  */
  3428. #include "../pixmaps/tb_new.xpm"
  3429. #include "../pixmaps/tb_open.xpm"
  3430. #include "../pixmaps/tb_close.xpm"
  3431. #include "../pixmaps/tb_save.xpm"
  3432. #include "../pixmaps/tb_print.xpm"
  3433. #include "../pixmaps/tb_cut.xpm"
  3434. #include "../pixmaps/tb_copy.xpm"
  3435. #include "../pixmaps/tb_paste.xpm"
  3436. #include "../pixmaps/tb_find.xpm"
  3437. #include "../pixmaps/tb_find_next.xpm"
  3438. #include "../pixmaps/tb_find_prev.xpm"
  3439. #include "../pixmaps/tb_find_help.xpm"
  3440. #include "../pixmaps/tb_exit.xpm"
  3441. #include "../pixmaps/tb_undo.xpm"
  3442. #include "../pixmaps/tb_redo.xpm"
  3443. #include "../pixmaps/tb_help.xpm"
  3444. #include "../pixmaps/tb_macro.xpm"
  3445. #include "../pixmaps/tb_make.xpm"
  3446. #include "../pixmaps/tb_save_all.xpm"
  3447. #include "../pixmaps/tb_jump.xpm"
  3448. #include "../pixmaps/tb_ctags.xpm"
  3449. #include "../pixmaps/tb_load_session.xpm"
  3450. #include "../pixmaps/tb_save_session.xpm"
  3451. #include "../pixmaps/tb_new_session.xpm"
  3452. #include "../pixmaps/tb_blank.xpm"
  3453. #include "../pixmaps/tb_maximize.xpm"
  3454. #include "../pixmaps/tb_split.xpm"
  3455. #include "../pixmaps/tb_minimize.xpm"
  3456. #include "../pixmaps/tb_shell.xpm"
  3457. #include "../pixmaps/tb_replace.xpm"
  3458. #include "../pixmaps/tb_vsplit.xpm"
  3459. #include "../pixmaps/tb_maxwidth.xpm"
  3460. #include "../pixmaps/tb_minwidth.xpm"
  3461.  
  3462. /*
  3463.  * Those are the pixmaps used for the default buttons.
  3464.  */
  3465. static char **(built_in_pixmaps[]) =
  3466. {
  3467.     tb_new_xpm,
  3468.     tb_open_xpm,
  3469.     tb_save_xpm,
  3470.     tb_undo_xpm,
  3471.     tb_redo_xpm,
  3472.     tb_cut_xpm,
  3473.     tb_copy_xpm,
  3474.     tb_paste_xpm,
  3475.     tb_print_xpm,
  3476.     tb_help_xpm,
  3477.     tb_find_xpm,
  3478.     tb_save_all_xpm,
  3479.     tb_save_session_xpm,
  3480.     tb_new_session_xpm,
  3481.     tb_load_session_xpm,
  3482.     tb_macro_xpm,
  3483.     tb_replace_xpm,
  3484.     tb_close_xpm,
  3485.     tb_maximize_xpm,
  3486.     tb_minimize_xpm,
  3487.     tb_split_xpm,
  3488.     tb_shell_xpm,
  3489.     tb_find_prev_xpm,
  3490.     tb_find_next_xpm,
  3491.     tb_find_help_xpm,
  3492.     tb_make_xpm,
  3493.     tb_jump_xpm,
  3494.     tb_ctags_xpm,
  3495.     tb_vsplit_xpm,
  3496.     tb_maxwidth_xpm,
  3497.     tb_minwidth_xpm,
  3498.     tb_exit_xpm
  3499. };
  3500.  
  3501. static void createXpmImages __ARGS((char_u *path, char **xpm, Pixmap *sen, Pixmap *insen));
  3502.  
  3503. /*
  3504.  * Allocated a pixmap for toolbar menu "menu".
  3505.  * Return in "sen" and "insen".  "insen" can be NULL.
  3506.  */
  3507.     void
  3508. get_toolbar_pixmap(menu, sen, insen)
  3509.     vimmenu_T    *menu;
  3510.     Pixmap    *sen;
  3511.     Pixmap    *insen;
  3512. {
  3513.     char_u    buf[MAXPATHL];        /* buffer storing expanded pathname */
  3514.     char    **xpm = NULL;        /* xpm array */
  3515.  
  3516.     buf[0] = NUL;            /* start with NULL path */
  3517.  
  3518.     if (menu->iconfile != NULL)
  3519.     {
  3520.     /* Use the "icon="  argument. */
  3521.     gui_find_iconfile(menu->iconfile, buf, "xpm");
  3522.     createXpmImages(buf, NULL, sen, insen);
  3523.  
  3524.     /* If it failed, try using the menu name. */
  3525.     if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK)
  3526.         createXpmImages(buf, NULL, sen, insen);
  3527.     if (*sen != (Pixmap)0)
  3528.         return;
  3529.     }
  3530.  
  3531.     if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL)
  3532.     {
  3533.     if (menu->iconidx >= 0 && menu->iconidx
  3534.            < (sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0])))
  3535.         xpm = built_in_pixmaps[menu->iconidx];
  3536.     else
  3537.         xpm = tb_blank_xpm;
  3538.     }
  3539.  
  3540.     if (xpm != NULL || buf[0] != NUL)
  3541.     createXpmImages(buf, xpm, sen, insen);
  3542. }
  3543.  
  3544. /* Indices for named colors */
  3545. #define BACKGROUND    0
  3546. #define FOREGROUND    1
  3547. #define BOTTOM_SHADOW    2
  3548. #define TOP_SHADOW    3
  3549. #define HIGHLIGHT    4
  3550.  
  3551. /*
  3552.  * Read an Xpm file, doing color substitutions for the foreground and
  3553.  * background colors. If there is an error reading a color xpm file,
  3554.  * drop back and read the monochrome file. If successful, create the
  3555.  * insensitive Pixmap too.
  3556.  */
  3557.     static void
  3558. createXpmImages(path, xpm, sen, insen)
  3559.     char_u    *path;
  3560.     char    **xpm;
  3561.     Pixmap    *sen;
  3562.     Pixmap    *insen;        /* can be NULL */
  3563. {
  3564.     Window    rootWindow;
  3565.     XpmAttributes attrs;
  3566.     XpmColorSymbol color[5] =
  3567.     {
  3568.     {"none", "none", 0},
  3569.     {"iconColor1", NULL, 0},
  3570.     {"bottomShadowColor", NULL, 0},
  3571.     {"topShadowColor", NULL, 0},
  3572.     {"selectColor", NULL, 0}
  3573.     };
  3574.     int        screenNum;
  3575.     int        status;
  3576.     Pixmap    mask;
  3577.     Pixmap    map;
  3578.  
  3579.     gui_mch_get_toolbar_colors(
  3580.         &color[BACKGROUND].pixel,
  3581.         &color[FOREGROUND].pixel,
  3582.         &color[BOTTOM_SHADOW].pixel,
  3583.         &color[TOP_SHADOW].pixel,
  3584.         &color[HIGHLIGHT].pixel);
  3585.  
  3586.     /* Setup the color subsititution table */
  3587.     attrs.valuemask = XpmColorSymbols;
  3588.     attrs.colorsymbols = color;
  3589.     attrs.numsymbols = 5;
  3590.  
  3591.     screenNum = DefaultScreen(gui.dpy);
  3592.     rootWindow = RootWindow(gui.dpy, screenNum);
  3593.  
  3594.     /* Create the "sensitive" pixmap */
  3595.     if (xpm != NULL)
  3596.     status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm,
  3597.                              &map, &mask, &attrs);
  3598.     else
  3599.     status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path,
  3600.                              &map, &mask, &attrs);
  3601.     if (status == XpmSuccess && map != 0)
  3602.     {
  3603.     XGCValues   gcvalues;
  3604.     GC        back_gc;
  3605.     GC        mask_gc;
  3606.  
  3607.     /* Need to create new Pixmaps with the mask applied. */
  3608.     gcvalues.foreground = color[BACKGROUND].pixel;
  3609.     back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
  3610.     mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues);
  3611.     XSetClipMask(gui.dpy, mask_gc, mask);
  3612.  
  3613.     /* Create the "sensitive" pixmap. */
  3614.     *sen = XCreatePixmap(gui.dpy, rootWindow,
  3615.          attrs.width, attrs.height,
  3616.          DefaultDepth(gui.dpy, screenNum));
  3617.     XFillRectangle(gui.dpy, *sen, back_gc, 0, 0,
  3618.         attrs.width, attrs.height);
  3619.     XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0,
  3620.         attrs.width, attrs.height, 0, 0);
  3621.  
  3622. #ifdef FEAT_GUI_MOTIF    /* not used for Athena */
  3623.     if (insen != NULL)
  3624.     {
  3625.         int        x, y;
  3626.         int        startX;
  3627.  
  3628.         /* Create the "insensitive" pixmap.  It's a copy of the "sensitive"
  3629.          * pixmap with half the pixels set to the background color. */
  3630.         *insen = XCreatePixmap(gui.dpy, rootWindow,
  3631.             attrs.width, attrs.height,
  3632.             DefaultDepth(gui.dpy, screenNum));
  3633.         XCopyArea(gui.dpy, *sen, *insen, back_gc, 0, 0,
  3634.             attrs.width, attrs.height, 0, 0);
  3635.         for (y = 0; y < attrs.height; y++)
  3636.         {
  3637.         if (y % 2 == 0)
  3638.             startX = 0;
  3639.         else
  3640.             startX = 1;
  3641.         for (x = startX; x < attrs.width; x += 2)
  3642.             XDrawPoint(gui.dpy, *insen, back_gc, x, y);
  3643.         }
  3644.  
  3645.     }
  3646. #endif
  3647.     XFreeGC(gui.dpy, back_gc);
  3648.     XFreeGC(gui.dpy, mask_gc);
  3649.     XFreePixmap(gui.dpy, map);
  3650.     }
  3651.     else
  3652.     {
  3653.     *sen = 0;
  3654.     if (insen != NULL)
  3655.         *insen = 0;
  3656.     }
  3657.  
  3658.     XpmFreeAttributes(&attrs);
  3659. }
  3660. #endif
  3661.  
  3662. #if (defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)) || defined(PROTO)
  3663. /*
  3664.  * Set the balloon-eval used for the tooltip of a toolbar menu item.
  3665.  * The check for a non-toolbar item was added, because there is a crash when
  3666.  * passing a normal menu item here.  Can't explain that, but better avoid it.
  3667.  */
  3668.     void
  3669. gui_mch_menu_set_tip(menu)
  3670.     vimmenu_T    *menu;
  3671. {
  3672.     if (menu->id != NULL && menu->parent != NULL
  3673.                        && menu_is_toolbar(menu->parent->name))
  3674.     {
  3675.     /* Always destroy and create the balloon, in case the string was
  3676.      * changed. */
  3677.     if (menu->tip != NULL)
  3678.     {
  3679.         gui_mch_destroy_beval_area(menu->tip);
  3680.         menu->tip = NULL;
  3681.     }
  3682.     if (menu->strings[MENU_INDEX_TIP] != NULL)
  3683.         menu->tip = gui_mch_create_beval_area(
  3684.             menu->id,
  3685.             menu->strings[MENU_INDEX_TIP],
  3686.             NULL,
  3687.             NULL);
  3688.     }
  3689. }
  3690. #endif
  3691.