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