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