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
86Widget vimShell = (Widget)0;
87
88static 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 */
97static 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
126static int check_fontset_sanity __ARGS((XFontSet fs));
127static int fontset_width __ARGS((XFontSet fs));
128static int fontset_ascent __ARGS((XFontSet fs));
129#endif
130
131static guicolor_T	prev_fg_color = INVALCOLOR;
132static guicolor_T	prev_bg_color = INVALCOLOR;
133static guicolor_T	prev_sp_color = INVALCOLOR;
134
135#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
136static XButtonPressedEvent last_mouse_event;
137#endif
138
139static int find_closest_color __ARGS((Colormap colormap, XColor *colorPtr));
140static void gui_x11_timer_cb __ARGS((XtPointer timed_out, XtIntervalId *interval_id));
141static void gui_x11_visibility_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
142static void gui_x11_expose_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
143static void gui_x11_resize_window_cb __ARGS((Widget w, XtPointer dud, XEvent *event, Boolean *dum));
144static void gui_x11_focus_change_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
145static void gui_x11_enter_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
146static void gui_x11_leave_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
147static void gui_x11_mouse_cb __ARGS((Widget w, XtPointer data, XEvent *event, Boolean *dum));
148#ifdef FEAT_SNIFF
149static void gui_x11_sniff_request_cb __ARGS((XtPointer closure, int *source, XtInputId *id));
150#endif
151static void gui_x11_check_copy_area __ARGS((void));
152#ifdef FEAT_CLIENTSERVER
153static void gui_x11_send_event_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
154#endif
155static void gui_x11_wm_protocol_handler __ARGS((Widget, XtPointer, XEvent *, Boolean *));
156static void gui_x11_blink_cb __ARGS((XtPointer timed_out, XtIntervalId *interval_id));
157static Cursor gui_x11_create_blank_mouse __ARGS((void));
158static 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 */
166static 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 */
307static 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 */
529static 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
566static int gui_argc = 0;
567static char **gui_argv = NULL;
568
569/*
570 * Call-back routines.
571 */
572
573    static void
574gui_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
582gui_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
605gui_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
651shellRectangle(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
681gui_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
727gui_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
737gui_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
747gui_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
763gui_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
1065theend:
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
1074gui_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		case Button1:	button = MOUSE_LEFT;	break;
1131		case Button2:	button = MOUSE_MIDDLE;	break;
1132		case Button3:	button = MOUSE_RIGHT;	break;
1133		case Button4:	button = MOUSE_4;	break;
1134		case Button5:	button = MOUSE_5;	break;
1135		default:
1136		    return;	/* Unknown button */
1137	    }
1138	}
1139	else if (event->type == ButtonRelease)
1140	    button = MOUSE_RELEASE;
1141	else
1142	    return;	/* Unknown mouse event type */
1143
1144	x_modifiers = event->xbutton.state;
1145#if defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)
1146	last_mouse_event = event->xbutton;
1147#endif
1148    }
1149
1150    vim_modifiers = 0x0;
1151    if (x_modifiers & ShiftMask)
1152	vim_modifiers |= MOUSE_SHIFT;
1153    if (x_modifiers & ControlMask)
1154	vim_modifiers |= MOUSE_CTRL;
1155    if (x_modifiers & Mod1Mask)	    /* Alt or Meta key */
1156	vim_modifiers |= MOUSE_ALT;
1157
1158    gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
1159}
1160
1161#ifdef FEAT_SNIFF
1162/* ARGSUSED */
1163    static void
1164gui_x11_sniff_request_cb(closure, source, id)
1165    XtPointer	closure UNUSED;
1166    int		*source UNUSED;
1167    XtInputId	*id UNUSED;
1168{
1169    static char_u bytes[3] = {CSI, (int)KS_EXTRA, (int)KE_SNIFF};
1170
1171    add_to_input_buf(bytes, 3);
1172}
1173#endif
1174
1175/*
1176 * End of call-back routines
1177 */
1178
1179/*
1180 * Parse the GUI related command-line arguments.  Any arguments used are
1181 * deleted from argv, and *argc is decremented accordingly.  This is called
1182 * when vim is started, whether or not the GUI has been started.
1183 */
1184    void
1185gui_mch_prepare(argc, argv)
1186    int	    *argc;
1187    char    **argv;
1188{
1189    int	    arg;
1190    int	    i;
1191
1192    /*
1193     * Move all the entries in argv which are relevant to X into gui_argv.
1194     */
1195    gui_argc = 0;
1196    gui_argv = (char **)lalloc((long_u)(*argc * sizeof(char *)), FALSE);
1197    if (gui_argv == NULL)
1198	return;
1199    gui_argv[gui_argc++] = argv[0];
1200    arg = 1;
1201    while (arg < *argc)
1202    {
1203	/* Look for argv[arg] in cmdline_options[] table */
1204	for (i = 0; i < (int)XtNumber(cmdline_options); i++)
1205	    if (strcmp(argv[arg], cmdline_options[i].option) == 0)
1206		break;
1207
1208	if (i < (int)XtNumber(cmdline_options))
1209	{
1210	    /* Remember finding "-rv" or "-reverse" */
1211	    if (strcmp("-rv", argv[arg]) == 0
1212		    || strcmp("-reverse", argv[arg]) == 0)
1213		found_reverse_arg = TRUE;
1214	    else if ((strcmp("-fn", argv[arg]) == 0
1215			|| strcmp("-font", argv[arg]) == 0)
1216		    && arg + 1 < *argc)
1217		font_argument = argv[arg + 1];
1218
1219	    /* Found match in table, so move it into gui_argv */
1220	    gui_argv[gui_argc++] = argv[arg];
1221	    if (--*argc > arg)
1222	    {
1223		mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
1224						    * sizeof(char *));
1225		if (cmdline_options[i].argKind != XrmoptionNoArg)
1226		{
1227		    /* Move the options argument as well */
1228		    gui_argv[gui_argc++] = argv[arg];
1229		    if (--*argc > arg)
1230			mch_memmove(&argv[arg], &argv[arg + 1], (*argc - arg)
1231							    * sizeof(char *));
1232		}
1233	    }
1234	    argv[*argc] = NULL;
1235	}
1236	else
1237#ifdef FEAT_SUN_WORKSHOP
1238	    if (strcmp("-ws", argv[arg]) == 0)
1239	{
1240	    usingSunWorkShop++;
1241	    p_acd = TRUE;
1242	    gui.dofork = FALSE;	/* don't fork() when starting GUI */
1243	    mch_memmove(&argv[arg], &argv[arg + 1],
1244					    (--*argc - arg) * sizeof(char *));
1245	    argv[*argc] = NULL;
1246# ifdef WSDEBUG
1247	    wsdebug_wait(WT_ENV | WT_WAIT | WT_STOP, "SPRO_GVIM_WAIT", 20);
1248	    wsdebug_log_init("SPRO_GVIM_DEBUG", "SPRO_GVIM_DLEVEL");
1249# endif
1250	}
1251	else
1252#endif
1253#ifdef FEAT_NETBEANS_INTG
1254	    if (strncmp("-nb", argv[arg], 3) == 0)
1255	{
1256	    gui.dofork = FALSE;	/* don't fork() when starting GUI */
1257	    netbeansArg = argv[arg];
1258	    mch_memmove(&argv[arg], &argv[arg + 1],
1259					    (--*argc - arg) * sizeof(char *));
1260	    argv[*argc] = NULL;
1261	}
1262	else
1263#endif
1264	    arg++;
1265    }
1266}
1267
1268#ifndef XtSpecificationRelease
1269# define CARDINAL (Cardinal *)
1270#else
1271# if XtSpecificationRelease == 4
1272# define CARDINAL (Cardinal *)
1273# else
1274# define CARDINAL (int *)
1275# endif
1276#endif
1277
1278/*
1279 * Check if the GUI can be started.  Called before gvimrc is sourced.
1280 * Return OK or FAIL.
1281 */
1282    int
1283gui_mch_init_check()
1284{
1285#ifdef FEAT_XIM
1286    XtSetLanguageProc(NULL, NULL, NULL);
1287#endif
1288    open_app_context();
1289    if (app_context != NULL)
1290	gui.dpy = XtOpenDisplay(app_context, 0, VIM_NAME, VIM_CLASS,
1291		cmdline_options, XtNumber(cmdline_options),
1292		CARDINAL &gui_argc, gui_argv);
1293
1294    if (app_context == NULL || gui.dpy == NULL)
1295    {
1296	gui.dying = TRUE;
1297	EMSG(_(e_opendisp));
1298	return FAIL;
1299    }
1300    return OK;
1301}
1302
1303
1304#ifdef USE_XSMP
1305/*
1306 * Handle XSMP processing, de-registering the attachment upon error
1307 */
1308static XtInputId _xsmp_xtinputid;
1309
1310static void local_xsmp_handle_requests __ARGS((XtPointer c, int *s, XtInputId *i));
1311
1312    static void
1313local_xsmp_handle_requests(c, s, i)
1314    XtPointer	c UNUSED;
1315    int		*s UNUSED;
1316    XtInputId	*i UNUSED;
1317{
1318    if (xsmp_handle_requests() == FAIL)
1319	XtRemoveInput(_xsmp_xtinputid);
1320}
1321#endif
1322
1323
1324/*
1325 * Initialise the X GUI.  Create all the windows, set up all the call-backs etc.
1326 * Returns OK for success, FAIL when the GUI can't be started.
1327 */
1328    int
1329gui_mch_init()
1330{
1331    XtGCMask	gc_mask;
1332    XGCValues	gc_vals;
1333    int		x, y, mask;
1334    unsigned	w, h;
1335
1336#if 0
1337    /* Uncomment this to enable synchronous mode for debugging */
1338    XSynchronize(gui.dpy, True);
1339#endif
1340
1341    vimShell = XtVaAppCreateShell(VIM_NAME, VIM_CLASS,
1342	    applicationShellWidgetClass, gui.dpy, NULL);
1343
1344    /*
1345     * Get the application resources
1346     */
1347    XtVaGetApplicationResources(vimShell, (XtPointer)&gui,
1348	vim_resources, XtNumber(vim_resources), NULL);
1349
1350    gui.scrollbar_height = gui.scrollbar_width;
1351
1352    /*
1353     * Get the colors ourselves.  Using the automatic conversion doesn't
1354     * handle looking for approximate colors.
1355     */
1356    /* NOTE: These next few lines are an exact duplicate of gui_athena.c's
1357     * gui_mch_def_colors().  Why?
1358     */
1359    gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
1360    gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
1361    gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
1362    gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
1363#ifdef FEAT_BEVAL
1364    gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
1365    gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
1366#endif
1367
1368#if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
1369    /* If the menu height was set, don't change it at runtime */
1370    if (gui.menu_height != MENU_DEFAULT_HEIGHT)
1371	gui.menu_height_fixed = TRUE;
1372#endif
1373
1374    /* Set default foreground and background colours */
1375    gui.norm_pixel = gui.def_norm_pixel;
1376    gui.back_pixel = gui.def_back_pixel;
1377
1378    /* Check if reverse video needs to be applied (on Sun it's done by X) */
1379    if (gui.rsrc_rev_video && gui_get_lightness(gui.back_pixel)
1380					  > gui_get_lightness(gui.norm_pixel))
1381    {
1382	gui.norm_pixel = gui.def_back_pixel;
1383	gui.back_pixel = gui.def_norm_pixel;
1384	gui.def_norm_pixel = gui.norm_pixel;
1385	gui.def_back_pixel = gui.back_pixel;
1386    }
1387
1388    /* Get the colors from the "Normal", "Tooltip", "Scrollbar" and "Menu"
1389     * group (set in syntax.c or in a vimrc file) */
1390    set_normal_colors();
1391
1392    /*
1393     * Check that none of the colors are the same as the background color
1394     */
1395    gui_check_colors();
1396
1397    /*
1398     * Set up the GCs.	The font attributes will be set in gui_init_font().
1399     */
1400    gc_mask = GCForeground | GCBackground;
1401    gc_vals.foreground = gui.norm_pixel;
1402    gc_vals.background = gui.back_pixel;
1403    gui.text_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
1404
1405    gc_vals.foreground = gui.back_pixel;
1406    gc_vals.background = gui.norm_pixel;
1407    gui.back_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
1408
1409    gc_mask |= GCFunction;
1410    gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
1411    gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
1412    gc_vals.function   = GXxor;
1413    gui.invert_gc = XtGetGC(vimShell, gc_mask, &gc_vals);
1414
1415    gui.visibility = VisibilityUnobscured;
1416    x11_setup_atoms(gui.dpy);
1417
1418    if (gui_win_x != -1 && gui_win_y != -1)
1419	gui_mch_set_winpos(gui_win_x, gui_win_y);
1420
1421    /* Now adapt the supplied(?) geometry-settings */
1422    /* Added by Kjetil Jacobsen <kjetilja@stud.cs.uit.no> */
1423    if (gui.geom != NULL && *gui.geom != NUL)
1424    {
1425	mask = XParseGeometry((char *)gui.geom, &x, &y, &w, &h);
1426	if (mask & WidthValue)
1427	    Columns = w;
1428	if (mask & HeightValue)
1429	{
1430	    if (p_window > (long)h - 1 || !option_was_set((char_u *)"window"))
1431		p_window = h - 1;
1432	    Rows = h;
1433	}
1434	/*
1435	 * Set the (x,y) position of the main window only if specified in the
1436	 * users geometry, so we get good defaults when they don't. This needs
1437	 * to be done before the shell is popped up.
1438	 */
1439	if (mask & (XValue|YValue))
1440	    XtVaSetValues(vimShell, XtNgeometry, gui.geom, NULL);
1441    }
1442
1443    gui_x11_create_widgets();
1444
1445   /*
1446    * Add an icon to Vim (Marcel Douben: 11 May 1998).
1447    */
1448    if (vim_strchr(p_go, GO_ICON) != NULL)
1449    {
1450#ifndef HAVE_XPM
1451# include "vim_icon.xbm"
1452# include "vim_mask.xbm"
1453
1454	Arg	arg[2];
1455
1456	XtSetArg(arg[0], XtNiconPixmap,
1457		XCreateBitmapFromData(gui.dpy,
1458		    DefaultRootWindow(gui.dpy),
1459		    (char *)vim_icon_bits,
1460		    vim_icon_width,
1461		    vim_icon_height));
1462	XtSetArg(arg[1], XtNiconMask,
1463		XCreateBitmapFromData(gui.dpy,
1464		    DefaultRootWindow(gui.dpy),
1465		    (char *)vim_mask_icon_bits,
1466		    vim_mask_icon_width,
1467		    vim_mask_icon_height));
1468	XtSetValues(vimShell, arg, (Cardinal)2);
1469#else
1470/* Use Pixmaps, looking much nicer. */
1471
1472/* If you get an error message here, you still need to unpack the runtime
1473 * archive! */
1474# ifdef magick
1475#  undef magick
1476# endif
1477# define magick vim32x32
1478# include "../runtime/vim32x32.xpm"
1479# undef magick
1480# define magick vim16x16
1481# include "../runtime/vim16x16.xpm"
1482# undef magick
1483# define magick vim48x48
1484# include "../runtime/vim48x48.xpm"
1485# undef magick
1486
1487    static Pixmap	icon = 0;
1488    static Pixmap	icon_mask = 0;
1489    static char		**magick = vim32x32;
1490    Window		root_window;
1491    XIconSize		*size;
1492    int			number_sizes;
1493    Display		*dsp;
1494    Screen		*scr;
1495    XpmAttributes	attr;
1496    Colormap		cmap;
1497
1498    /*
1499     * Adjust the icon to the preferences of the actual window manager.
1500     */
1501    root_window = XRootWindowOfScreen(XtScreen(vimShell));
1502    if (XGetIconSizes(XtDisplay(vimShell), root_window,
1503						   &size, &number_sizes) != 0)
1504    {
1505
1506	if (number_sizes > 0)
1507	{
1508	    if (size->max_height >= 48 && size->max_height >= 48)
1509		magick = vim48x48;
1510	    else if (size->max_height >= 32 && size->max_height >= 32)
1511		magick = vim32x32;
1512	    else if (size->max_height >= 16 && size->max_height >= 16)
1513		magick = vim16x16;
1514	}
1515    }
1516
1517    dsp = XtDisplay(vimShell);
1518    scr = XtScreen(vimShell);
1519
1520    cmap = DefaultColormap(dsp, DefaultScreen(dsp));
1521    XtVaSetValues(vimShell, XtNcolormap, cmap, NULL);
1522
1523    attr.valuemask = 0L;
1524    attr.valuemask = XpmCloseness | XpmReturnPixels | XpmColormap | XpmDepth;
1525    attr.closeness = 65535;	/* accuracy isn't crucial */
1526    attr.colormap = cmap;
1527    attr.depth = DefaultDepthOfScreen(scr);
1528
1529    if (!icon)
1530    {
1531	XpmCreatePixmapFromData(dsp, root_window, magick, &icon,
1532							   &icon_mask, &attr);
1533	XpmFreeAttributes(&attr);
1534    }
1535
1536# ifdef FEAT_GUI_ATHENA
1537    XtVaSetValues(vimShell, XtNiconPixmap, icon, XtNiconMask, icon_mask, NULL);
1538# else
1539    XtVaSetValues(vimShell, XmNiconPixmap, icon, XmNiconMask, icon_mask, NULL);
1540# endif
1541#endif
1542    }
1543
1544    if (gui.color_approx)
1545	EMSG(_("Vim E458: Cannot allocate colormap entry, some colors may be incorrect"));
1546
1547#ifdef FEAT_SUN_WORKSHOP
1548    if (usingSunWorkShop)
1549	workshop_connect(app_context);
1550#endif
1551
1552#ifdef FEAT_BEVAL
1553    gui_init_tooltip_font();
1554#endif
1555#ifdef FEAT_MENU
1556    gui_init_menu_font();
1557#endif
1558
1559#ifdef USE_XSMP
1560    /* Attach listener on ICE connection */
1561    if (-1 != xsmp_icefd)
1562	_xsmp_xtinputid = XtAppAddInput(app_context, xsmp_icefd,
1563		(XtPointer)XtInputReadMask, local_xsmp_handle_requests, NULL);
1564#endif
1565
1566    return OK;
1567}
1568
1569/*
1570 * Called when starting the GUI fails after calling gui_mch_init().
1571 */
1572    void
1573gui_mch_uninit()
1574{
1575    gui_x11_destroy_widgets();
1576    XtCloseDisplay(gui.dpy);
1577    gui.dpy = NULL;
1578    vimShell = (Widget)0;
1579    vim_free(gui_argv);
1580    gui_argv = NULL;
1581}
1582
1583/*
1584 * Called when the foreground or background color has been changed.
1585 */
1586    void
1587gui_mch_new_colors()
1588{
1589    long_u	gc_mask;
1590    XGCValues	gc_vals;
1591
1592    gc_mask = GCForeground | GCBackground;
1593    gc_vals.foreground = gui.norm_pixel;
1594    gc_vals.background = gui.back_pixel;
1595    if (gui.text_gc != NULL)
1596	XChangeGC(gui.dpy, gui.text_gc, gc_mask, &gc_vals);
1597
1598    gc_vals.foreground = gui.back_pixel;
1599    gc_vals.background = gui.norm_pixel;
1600    if (gui.back_gc != NULL)
1601	XChangeGC(gui.dpy, gui.back_gc, gc_mask, &gc_vals);
1602
1603    gc_mask |= GCFunction;
1604    gc_vals.foreground = gui.norm_pixel ^ gui.back_pixel;
1605    gc_vals.background = gui.norm_pixel ^ gui.back_pixel;
1606    gc_vals.function   = GXxor;
1607    if (gui.invert_gc != NULL)
1608	XChangeGC(gui.dpy, gui.invert_gc, gc_mask, &gc_vals);
1609
1610    gui_x11_set_back_color();
1611}
1612
1613/*
1614 * Open the GUI window which was created by a call to gui_mch_init().
1615 */
1616    int
1617gui_mch_open()
1618{
1619    /* Actually open the window */
1620    XtRealizeWidget(vimShell);
1621    XtManageChild(XtNameToWidget(vimShell, "*vimForm"));
1622
1623    gui.wid = gui_x11_get_wid();
1624    gui.blank_pointer = gui_x11_create_blank_mouse();
1625
1626    /*
1627     * Add a callback for the Close item on the window managers menu, and the
1628     * save-yourself event.
1629     */
1630    wm_atoms[SAVE_YOURSELF_IDX] =
1631			      XInternAtom(gui.dpy, "WM_SAVE_YOURSELF", False);
1632    wm_atoms[DELETE_WINDOW_IDX] =
1633			      XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
1634    XSetWMProtocols(gui.dpy, XtWindow(vimShell), wm_atoms, 2);
1635    XtAddEventHandler(vimShell, NoEventMask, True, gui_x11_wm_protocol_handler,
1636							     NULL);
1637#ifdef HAVE_X11_XMU_EDITRES_H
1638    /*
1639     * Enable editres protocol (see "man editres").
1640     * Usually will need to add -lXmu to the linker line as well.
1641     */
1642    XtAddEventHandler(vimShell, (EventMask)0, True, _XEditResCheckMessages,
1643	    (XtPointer)NULL);
1644#endif
1645
1646#ifdef FEAT_CLIENTSERVER
1647    if (serverName == NULL && serverDelayedStartName != NULL)
1648    {
1649	/* This is a :gui command in a plain vim with no previous server */
1650	commWindow = XtWindow(vimShell);
1651	(void)serverRegisterName(gui.dpy, serverDelayedStartName);
1652    }
1653    else
1654    {
1655	/*
1656	 * Cannot handle "widget-less" windows with XtProcessEvent() we'll
1657	 * have to change the "server" registration to that of the main window
1658	 * If we have not registered a name yet, remember the window
1659	 */
1660	serverChangeRegisteredWindow(gui.dpy, XtWindow(vimShell));
1661    }
1662    XtAddEventHandler(vimShell, PropertyChangeMask, False,
1663		      gui_x11_send_event_handler, NULL);
1664#endif
1665
1666
1667#if defined(FEAT_MENU) && defined(FEAT_GUI_ATHENA)
1668    /* The Athena GUI needs this again after opening the window */
1669    gui_position_menu();
1670# ifdef FEAT_TOOLBAR
1671    gui_mch_set_toolbar_pos(0, gui.menu_height, gui.menu_width,
1672			    gui.toolbar_height);
1673# endif
1674#endif
1675
1676    /* Get the colors for the highlight groups (gui_check_colors() might have
1677     * changed them) */
1678    highlight_gui_started();		/* re-init colors and fonts */
1679
1680#ifdef FEAT_HANGULIN
1681    hangul_keyboard_set();
1682#endif
1683#ifdef FEAT_XIM
1684    xim_init();
1685#endif
1686#ifdef FEAT_SUN_WORKSHOP
1687    workshop_postinit();
1688#endif
1689
1690    return OK;
1691}
1692
1693#if defined(FEAT_BEVAL) || defined(PROTO)
1694/*
1695 * Convert the tooltip fontset name to an XFontSet.
1696 */
1697    void
1698gui_init_tooltip_font()
1699{
1700    XrmValue from, to;
1701
1702    from.addr = (char *)gui.rsrc_tooltip_font_name;
1703    from.size = strlen(from.addr);
1704    to.addr = (XtPointer)&gui.tooltip_fontset;
1705    to.size = sizeof(XFontSet);
1706
1707    if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
1708    {
1709	/* Failed. What to do? */
1710    }
1711}
1712#endif
1713
1714#if defined(FEAT_MENU) || defined(PROTO)
1715/* Convert the menu font/fontset name to an XFontStruct/XFontset */
1716    void
1717gui_init_menu_font()
1718{
1719    XrmValue from, to;
1720
1721#ifdef FONTSET_ALWAYS
1722    from.addr = (char *)gui.rsrc_menu_font_name;
1723    from.size = strlen(from.addr);
1724    to.addr = (XtPointer)&gui.menu_fontset;
1725    to.size = sizeof(GuiFontset);
1726
1727    if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontSet, &to) == False)
1728    {
1729	/* Failed. What to do? */
1730    }
1731#else
1732    from.addr = (char *)gui.rsrc_menu_font_name;
1733    from.size = strlen(from.addr);
1734    to.addr = (XtPointer)&gui.menu_font;
1735    to.size = sizeof(GuiFont);
1736
1737    if (XtConvertAndStore(vimShell, XtRString, &from, XtRFontStruct, &to) == False)
1738    {
1739	/* Failed. What to do? */
1740    }
1741#endif
1742}
1743#endif
1744
1745    void
1746gui_mch_exit(rc)
1747    int		rc UNUSED;
1748{
1749#if 0
1750    /* Lesstif gives an error message here, and so does Solaris.  The man page
1751     * says that this isn't needed when exiting, so just skip it. */
1752    XtCloseDisplay(gui.dpy);
1753#endif
1754    vim_free(gui_argv);
1755    gui_argv = NULL;
1756}
1757
1758/*
1759 * Get the position of the top left corner of the window.
1760 */
1761    int
1762gui_mch_get_winpos(x, y)
1763    int		*x, *y;
1764{
1765    Dimension	xpos, ypos;
1766
1767    XtVaGetValues(vimShell,
1768	XtNx,	&xpos,
1769	XtNy,	&ypos,
1770	NULL);
1771    *x = xpos;
1772    *y = ypos;
1773    return OK;
1774}
1775
1776/*
1777 * Set the position of the top left corner of the window to the given
1778 * coordinates.
1779 */
1780    void
1781gui_mch_set_winpos(x, y)
1782    int		x, y;
1783{
1784    XtVaSetValues(vimShell,
1785	XtNx,	x,
1786	XtNy,	y,
1787	NULL);
1788}
1789
1790    void
1791gui_mch_set_shellsize(width, height, min_width, min_height,
1792		    base_width, base_height, direction)
1793    int		width;
1794    int		height;
1795    int		min_width;
1796    int		min_height;
1797    int		base_width;
1798    int		base_height;
1799    int		direction UNUSED;
1800{
1801#ifdef FEAT_XIM
1802    height += xim_get_status_area_height(),
1803#endif
1804    XtVaSetValues(vimShell,
1805	XtNwidthInc,	gui.char_width,
1806	XtNheightInc,	gui.char_height,
1807#if defined(XtSpecificationRelease) && XtSpecificationRelease >= 4
1808	XtNbaseWidth,	base_width,
1809	XtNbaseHeight,	base_height,
1810#endif
1811	XtNminWidth,	min_width,
1812	XtNminHeight,	min_height,
1813	XtNwidth,	width,
1814	XtNheight,	height,
1815	NULL);
1816}
1817
1818/*
1819 * Allow 10 pixels for horizontal borders, 'guiheadroom' for vertical borders.
1820 * Is there no way in X to find out how wide the borders really are?
1821 */
1822    void
1823gui_mch_get_screen_dimensions(screen_w, screen_h)
1824    int	    *screen_w;
1825    int	    *screen_h;
1826{
1827    *screen_w = DisplayWidth(gui.dpy, DefaultScreen(gui.dpy)) - 10;
1828    *screen_h = DisplayHeight(gui.dpy, DefaultScreen(gui.dpy)) - p_ghr;
1829}
1830
1831/*
1832 * Initialise vim to use the font "font_name".  If it's NULL, pick a default
1833 * font.
1834 * If "fontset" is TRUE, load the "font_name" as a fontset.
1835 * Return FAIL if the font could not be loaded, OK otherwise.
1836 */
1837    int
1838gui_mch_init_font(font_name, do_fontset)
1839    char_u	*font_name;
1840    int		do_fontset UNUSED;
1841{
1842    XFontStruct	*font = NULL;
1843
1844#ifdef FEAT_XFONTSET
1845    XFontSet	fontset = NULL;
1846#endif
1847
1848#ifdef FEAT_GUI_MOTIF
1849    /* A font name equal "*" is indicating, that we should activate the font
1850     * selection dialogue to get a new font name. So let us do it here. */
1851    if (font_name != NULL && STRCMP(font_name, "*") == 0)
1852	font_name = gui_xm_select_font(hl_get_font_name());
1853#endif
1854
1855#ifdef FEAT_XFONTSET
1856    if (do_fontset)
1857    {
1858	/* If 'guifontset' is set, VIM treats all font specifications as if
1859	 * they were fontsets, and 'guifontset' becomes the default. */
1860	if (font_name != NULL)
1861	{
1862	    fontset = (XFontSet)gui_mch_get_fontset(font_name, FALSE, TRUE);
1863	    if (fontset == NULL)
1864		return FAIL;
1865	}
1866    }
1867    else
1868#endif
1869    {
1870	if (font_name == NULL)
1871	{
1872	    /*
1873	     * If none of the fonts in 'font' could be loaded, try the one set
1874	     * in the X resource, and finally just try using DFLT_FONT, which
1875	     * will hopefully always be there.
1876	     */
1877	    font_name = gui.rsrc_font_name;
1878	    font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
1879	    if (font == NULL)
1880		font_name = (char_u *)DFLT_FONT;
1881	}
1882	if (font == NULL)
1883	    font = (XFontStruct *)gui_mch_get_font(font_name, FALSE);
1884	if (font == NULL)
1885	    return FAIL;
1886    }
1887
1888    gui_mch_free_font(gui.norm_font);
1889#ifdef FEAT_XFONTSET
1890    gui_mch_free_fontset(gui.fontset);
1891
1892    if (fontset != NULL)
1893    {
1894	gui.norm_font = NOFONT;
1895	gui.fontset = (GuiFontset)fontset;
1896	gui.char_width = fontset_width(fontset);
1897	gui.char_height = fontset_height(fontset) + p_linespace;
1898	gui.char_ascent = fontset_ascent(fontset) + p_linespace / 2;
1899    }
1900    else
1901#endif
1902    {
1903	gui.norm_font = (GuiFont)font;
1904#ifdef FEAT_XFONTSET
1905	gui.fontset = NOFONTSET;
1906#endif
1907	gui.char_width = font->max_bounds.width;
1908	gui.char_height = font->ascent + font->descent + p_linespace;
1909	gui.char_ascent = font->ascent + p_linespace / 2;
1910    }
1911
1912    hl_set_font_name(font_name);
1913
1914    /*
1915     * Try to load other fonts for bold, italic, and bold-italic.
1916     * We should also try to work out what font to use for these when they are
1917     * not specified by X resources, but we don't yet.
1918     */
1919    if (font_name == gui.rsrc_font_name)
1920    {
1921	if (gui.bold_font == NOFONT
1922		&& gui.rsrc_bold_font_name != NULL
1923		&& *gui.rsrc_bold_font_name != NUL)
1924	    gui.bold_font = gui_mch_get_font(gui.rsrc_bold_font_name, FALSE);
1925	if (gui.ital_font == NOFONT
1926		&& gui.rsrc_ital_font_name != NULL
1927		&& *gui.rsrc_ital_font_name != NUL)
1928	    gui.ital_font = gui_mch_get_font(gui.rsrc_ital_font_name, FALSE);
1929	if (gui.boldital_font == NOFONT
1930		&& gui.rsrc_boldital_font_name != NULL
1931		&& *gui.rsrc_boldital_font_name != NUL)
1932	    gui.boldital_font = gui_mch_get_font(gui.rsrc_boldital_font_name,
1933								       FALSE);
1934    }
1935    else
1936    {
1937	/* When not using the font specified by the resources, also don't use
1938	 * the bold/italic fonts, otherwise setting 'guifont' will look very
1939	 * strange. */
1940	if (gui.bold_font != NOFONT)
1941	{
1942	    XFreeFont(gui.dpy, (XFontStruct *)gui.bold_font);
1943	    gui.bold_font = NOFONT;
1944	}
1945	if (gui.ital_font != NOFONT)
1946	{
1947	    XFreeFont(gui.dpy, (XFontStruct *)gui.ital_font);
1948	    gui.ital_font = NOFONT;
1949	}
1950	if (gui.boldital_font != NOFONT)
1951	{
1952	    XFreeFont(gui.dpy, (XFontStruct *)gui.boldital_font);
1953	    gui.boldital_font = NOFONT;
1954	}
1955    }
1956
1957#ifdef FEAT_GUI_MOTIF
1958    gui_motif_synch_fonts();
1959#endif
1960
1961    return OK;
1962}
1963
1964/*
1965 * Get a font structure for highlighting.
1966 */
1967    GuiFont
1968gui_mch_get_font(name, giveErrorIfMissing)
1969    char_u	*name;
1970    int		giveErrorIfMissing;
1971{
1972    XFontStruct	*font;
1973
1974    if (!gui.in_use || name == NULL)    /* can't do this when GUI not running */
1975	return NOFONT;
1976
1977    font = XLoadQueryFont(gui.dpy, (char *)name);
1978
1979    if (font == NULL)
1980    {
1981	if (giveErrorIfMissing)
1982	    EMSG2(_(e_font), name);
1983	return NOFONT;
1984    }
1985
1986#ifdef DEBUG
1987    printf("Font Information for '%s':\n", name);
1988    printf("  w = %d, h = %d, ascent = %d, descent = %d\n",
1989	   font->max_bounds.width, font->ascent + font->descent,
1990	   font->ascent, font->descent);
1991    printf("  max ascent = %d, max descent = %d, max h = %d\n",
1992	   font->max_bounds.ascent, font->max_bounds.descent,
1993	   font->max_bounds.ascent + font->max_bounds.descent);
1994    printf("  min lbearing = %d, min rbearing = %d\n",
1995	   font->min_bounds.lbearing, font->min_bounds.rbearing);
1996    printf("  max lbearing = %d, max rbearing = %d\n",
1997	   font->max_bounds.lbearing, font->max_bounds.rbearing);
1998    printf("  leftink = %d, rightink = %d\n",
1999	   (font->min_bounds.lbearing < 0),
2000	   (font->max_bounds.rbearing > font->max_bounds.width));
2001    printf("\n");
2002#endif
2003
2004    if (font->max_bounds.width != font->min_bounds.width)
2005    {
2006	EMSG2(_(e_fontwidth), name);
2007	XFreeFont(gui.dpy, font);
2008	return NOFONT;
2009    }
2010    return (GuiFont)font;
2011}
2012
2013#if defined(FEAT_EVAL) || defined(PROTO)
2014/*
2015 * Return the name of font "font" in allocated memory.
2016 * Don't know how to get the actual name, thus use the provided name.
2017 */
2018    char_u *
2019gui_mch_get_fontname(font, name)
2020    GuiFont font UNUSED;
2021    char_u  *name;
2022{
2023    if (name == NULL)
2024	return NULL;
2025    return vim_strsave(name);
2026}
2027#endif
2028
2029/*
2030 * Adjust gui.char_height (after 'linespace' was changed).
2031 */
2032    int
2033gui_mch_adjust_charheight()
2034{
2035#ifdef FEAT_XFONTSET
2036    if (gui.fontset != NOFONTSET)
2037    {
2038	gui.char_height = fontset_height((XFontSet)gui.fontset) + p_linespace;
2039	gui.char_ascent = fontset_ascent((XFontSet)gui.fontset)
2040							    + p_linespace / 2;
2041    }
2042    else
2043#endif
2044    {
2045	XFontStruct *font = (XFontStruct *)gui.norm_font;
2046
2047	gui.char_height = font->ascent + font->descent + p_linespace;
2048	gui.char_ascent = font->ascent + p_linespace / 2;
2049    }
2050    return OK;
2051}
2052
2053/*
2054 * Set the current text font.
2055 */
2056    void
2057gui_mch_set_font(font)
2058    GuiFont	font;
2059{
2060    static Font	prev_font = (Font)-1;
2061    Font	fid = ((XFontStruct *)font)->fid;
2062
2063    if (fid != prev_font)
2064    {
2065	XSetFont(gui.dpy, gui.text_gc, fid);
2066	XSetFont(gui.dpy, gui.back_gc, fid);
2067	prev_font = fid;
2068	gui.char_ascent = ((XFontStruct *)font)->ascent + p_linespace / 2;
2069    }
2070#ifdef FEAT_XFONTSET
2071    current_fontset = (XFontSet)NULL;
2072#endif
2073}
2074
2075#if defined(FEAT_XFONTSET) || defined(PROTO)
2076/*
2077 * Set the current text fontset.
2078 * Adjust the ascent, in case it's different.
2079 */
2080    void
2081gui_mch_set_fontset(fontset)
2082    GuiFontset	fontset;
2083{
2084    current_fontset = (XFontSet)fontset;
2085    gui.char_ascent = fontset_ascent(current_fontset) + p_linespace / 2;
2086}
2087#endif
2088
2089/*
2090 * If a font is not going to be used, free its structure.
2091 */
2092    void
2093gui_mch_free_font(font)
2094    GuiFont	font;
2095{
2096    if (font != NOFONT)
2097	XFreeFont(gui.dpy, (XFontStruct *)font);
2098}
2099
2100#if defined(FEAT_XFONTSET) || defined(PROTO)
2101/*
2102 * If a fontset is not going to be used, free its structure.
2103 */
2104    void
2105gui_mch_free_fontset(fontset)
2106    GuiFontset	fontset;
2107{
2108    if (fontset != NOFONTSET)
2109	XFreeFontSet(gui.dpy, (XFontSet)fontset);
2110}
2111
2112/*
2113 * Load the fontset "name".
2114 * Return a reference to the fontset, or NOFONTSET when failing.
2115 */
2116    GuiFontset
2117gui_mch_get_fontset(name, giveErrorIfMissing, fixed_width)
2118    char_u	*name;
2119    int		giveErrorIfMissing;
2120    int		fixed_width;
2121{
2122    XFontSet	fontset;
2123    char	**missing, *def_str;
2124    int		num_missing;
2125
2126    if (!gui.in_use || name == NULL)
2127	return NOFONTSET;
2128
2129    fontset = XCreateFontSet(gui.dpy, (char *)name, &missing, &num_missing,
2130			     &def_str);
2131    if (num_missing > 0)
2132    {
2133	int i;
2134
2135	if (giveErrorIfMissing)
2136	{
2137	    EMSG2(_("E250: Fonts for the following charsets are missing in fontset %s:"), name);
2138	    for (i = 0; i < num_missing; i++)
2139		EMSG2("%s", missing[i]);
2140	}
2141	XFreeStringList(missing);
2142    }
2143
2144    if (fontset == NULL)
2145    {
2146	if (giveErrorIfMissing)
2147	    EMSG2(_(e_fontset), name);
2148	return NOFONTSET;
2149    }
2150
2151    if (fixed_width && check_fontset_sanity(fontset) == FAIL)
2152    {
2153	XFreeFontSet(gui.dpy, fontset);
2154	return NOFONTSET;
2155    }
2156    return (GuiFontset)fontset;
2157}
2158
2159/*
2160 * Check if fontset "fs" is fixed width.
2161 */
2162    static int
2163check_fontset_sanity(fs)
2164    XFontSet fs;
2165{
2166    XFontStruct	**xfs;
2167    char	**font_name;
2168    int		fn;
2169    char	*base_name;
2170    int		i;
2171    int		min_width;
2172    int		min_font_idx = 0;
2173
2174    base_name = XBaseFontNameListOfFontSet(fs);
2175    fn = XFontsOfFontSet(fs, &xfs, &font_name);
2176    for (i = 0; i < fn; i++)
2177    {
2178	if (xfs[i]->max_bounds.width != xfs[i]->min_bounds.width)
2179	{
2180	    EMSG2(_("E252: Fontset name: %s"), base_name);
2181	    EMSG2(_("Font '%s' is not fixed-width"), font_name[i]);
2182	    return FAIL;
2183	}
2184    }
2185    /* scan base font width */
2186    min_width = 32767;
2187    for (i = 0; i < fn; i++)
2188    {
2189	if (xfs[i]->max_bounds.width<min_width)
2190	{
2191	    min_width = xfs[i]->max_bounds.width;
2192	    min_font_idx = i;
2193	}
2194    }
2195    for (i = 0; i < fn; i++)
2196    {
2197	if (	   xfs[i]->max_bounds.width != 2 * min_width
2198		&& xfs[i]->max_bounds.width != min_width)
2199	{
2200	    EMSG2(_("E253: Fontset name: %s\n"), base_name);
2201	    EMSG2(_("Font0: %s\n"), font_name[min_font_idx]);
2202	    EMSG2(_("Font1: %s\n"), font_name[i]);
2203	    EMSGN(_("Font%ld width is not twice that of font0\n"), i);
2204	    EMSGN(_("Font0 width: %ld\n"), xfs[min_font_idx]->max_bounds.width);
2205	    EMSGN(_("Font1 width: %ld\n\n"), xfs[i]->max_bounds.width);
2206	    return FAIL;
2207	}
2208    }
2209    /* it seems ok. Good Luck!! */
2210    return OK;
2211}
2212
2213    static int
2214fontset_width(fs)
2215    XFontSet fs;
2216{
2217    return XmbTextEscapement(fs, "Vim", 3) / 3;
2218}
2219
2220    int
2221fontset_height(fs)
2222    XFontSet fs;
2223{
2224    XFontSetExtents *extents;
2225
2226    extents = XExtentsOfFontSet(fs);
2227    return extents->max_logical_extent.height;
2228}
2229
2230#if (defined(FONTSET_ALWAYS) && defined(FEAT_GUI_ATHENA) \
2231	    && defined(FEAT_MENU)) || defined(PROTO)
2232/*
2233 * Returns the bounding box height around the actual glyph image of all
2234 * characters in all fonts of the fontset.
2235 */
2236    int
2237fontset_height2(fs)
2238    XFontSet fs;
2239{
2240    XFontSetExtents *extents;
2241
2242    extents = XExtentsOfFontSet(fs);
2243    return extents->max_ink_extent.height;
2244}
2245#endif
2246
2247/* NOT USED YET
2248    static int
2249fontset_descent(fs)
2250    XFontSet fs;
2251{
2252    XFontSetExtents *extents;
2253
2254    extents = XExtentsOfFontSet (fs);
2255    return extents->max_logical_extent.height + extents->max_logical_extent.y;
2256}
2257*/
2258
2259    static int
2260fontset_ascent(fs)
2261    XFontSet fs;
2262{
2263    XFontSetExtents *extents;
2264
2265    extents = XExtentsOfFontSet(fs);
2266    return -extents->max_logical_extent.y;
2267}
2268
2269#endif /* FEAT_XFONTSET */
2270
2271/*
2272 * Return the Pixel value (color) for the given color name.
2273 * Return INVALCOLOR for error.
2274 */
2275    guicolor_T
2276gui_mch_get_color(reqname)
2277    char_u *reqname;
2278{
2279    int		i;
2280    char_u	*name = reqname;
2281    Colormap	colormap;
2282    XColor      color;
2283    static char *(vimnames[][2]) =
2284    {
2285	/* A number of colors that some X11 systems don't have */
2286	{"LightRed",	"#FFBBBB"},
2287	{"LightGreen",	"#88FF88"},
2288	{"LightMagenta","#FFBBFF"},
2289	{"DarkCyan",	"#008888"},
2290	{"DarkBlue",	"#0000BB"},
2291	{"DarkRed",	"#BB0000"},
2292	{"DarkMagenta",	"#BB00BB"},
2293	{"DarkGrey",	"#BBBBBB"},
2294	{"DarkYellow",	"#BBBB00"},
2295	{"Gray10",	"#1A1A1A"},
2296	{"Grey10",	"#1A1A1A"},
2297	{"Gray20",	"#333333"},
2298	{"Grey20",	"#333333"},
2299	{"Gray30",	"#4D4D4D"},
2300	{"Grey30",	"#4D4D4D"},
2301	{"Gray40",	"#666666"},
2302	{"Grey40",	"#666666"},
2303	{"Gray50",	"#7F7F7F"},
2304	{"Grey50",	"#7F7F7F"},
2305	{"Gray60",	"#999999"},
2306	{"Grey60",	"#999999"},
2307	{"Gray70",	"#B3B3B3"},
2308	{"Grey70",	"#B3B3B3"},
2309	{"Gray80",	"#CCCCCC"},
2310	{"Grey80",	"#CCCCCC"},
2311	{"Gray90",	"#E5E5E5"},
2312	{"Grey90",	"#E5E5E5"},
2313	{NULL, NULL}
2314    };
2315
2316    /* can't do this when GUI not running */
2317    if (!gui.in_use || *reqname == NUL)
2318	return INVALCOLOR;
2319
2320    colormap = DefaultColormap(gui.dpy, XDefaultScreen(gui.dpy));
2321
2322    /* Do this twice if the name isn't recognized. */
2323    while (name != NULL)
2324    {
2325	i = XParseColor(gui.dpy, colormap, (char *)name, &color);
2326
2327#if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
2328	if (i == 0)
2329	{
2330	    char *old;
2331
2332	    /* The X11 system is trying to resolve named colors only by names
2333	     * corresponding to the current locale language.  But Vim scripts
2334	     * usually contain the English color names.  Therefore we have to
2335	     * try a second time here with the native "C" locale set.
2336	     * Hopefully, restoring the old locale this way works on all
2337	     * systems...
2338	     */
2339	    old = setlocale(LC_ALL, NULL);
2340	    if (old != NULL && STRCMP(old, "C") != 0)
2341	    {
2342		old = (char *)vim_strsave((char_u *)old);
2343		setlocale(LC_ALL, "C");
2344		i = XParseColor(gui.dpy, colormap, (char *)name, &color);
2345		setlocale(LC_ALL, old);
2346		vim_free(old);
2347	    }
2348	}
2349#endif
2350	if (i != 0 && (XAllocColor(gui.dpy, colormap, &color) != 0
2351		    || find_closest_color(colormap, &color) == OK))
2352	    return (guicolor_T)color.pixel;
2353
2354	/* check for a few builtin names */
2355	for (i = 0; ; ++i)
2356	{
2357	    if (vimnames[i][0] == NULL)
2358	    {
2359		name = NULL;
2360		break;
2361	    }
2362	    if (STRICMP(name, vimnames[i][0]) == 0)
2363	    {
2364		name = (char_u *)vimnames[i][1];
2365		break;
2366	    }
2367	}
2368    }
2369
2370    return INVALCOLOR;
2371}
2372
2373/*
2374 * Find closest color for "colorPtr" in "colormap".  set "colorPtr" to the
2375 * resulting color.
2376 * Based on a similar function in TCL.
2377 * Return FAIL if not able to find or allocate a color.
2378 */
2379    static int
2380find_closest_color(colormap, colorPtr)
2381    Colormap	colormap;
2382    XColor	*colorPtr;
2383{
2384    double	tmp, distance, closestDistance;
2385    int		i, closest, numFound, cmap_size;
2386    XColor	*colortable;
2387    XVisualInfo	template, *visInfoPtr;
2388
2389    template.visualid = XVisualIDFromVisual(DefaultVisual(gui.dpy,
2390						    XDefaultScreen(gui.dpy)));
2391    visInfoPtr = XGetVisualInfo(gui.dpy, (long)VisualIDMask,
2392							&template, &numFound);
2393    if (numFound < 1)
2394	/* FindClosestColor couldn't lookup visual */
2395	return FAIL;
2396
2397    cmap_size = visInfoPtr->colormap_size;
2398    XFree((char *)visInfoPtr);
2399    colortable = (XColor *)alloc((unsigned)(cmap_size * sizeof(XColor)));
2400    if (!colortable)
2401	return FAIL;  /* out of memory */
2402
2403    for (i = 0; i  < cmap_size; i++)
2404	colortable[i].pixel = (unsigned long)i;
2405    XQueryColors (gui.dpy, colormap, colortable, cmap_size);
2406
2407    /*
2408     * Find the color that best approximates the desired one, then
2409     * try to allocate that color.  If that fails, it must mean that
2410     * the color was read-write (so we can't use it, since it's owner
2411     * might change it) or else it was already freed.  Try again,
2412     * over and over again, until something succeeds.
2413     */
2414    closestDistance = 1e30;
2415    closest = 0;
2416    for (i = 0; i < cmap_size; i++)
2417    {
2418	/*
2419	 * Use Euclidean distance in RGB space, weighted by Y (of YIQ)
2420	 * as the objective function;  this accounts for differences
2421	 * in the color sensitivity of the eye.
2422	 */
2423	tmp = .30 * (((int)colorPtr->red) - (int)colortable[i].red);
2424	distance = tmp * tmp;
2425	tmp = .61 * (((int)colorPtr->green) - (int)colortable[i].green);
2426	distance += tmp * tmp;
2427	tmp = .11 * (((int)colorPtr->blue) - (int)colortable[i].blue);
2428	distance += tmp * tmp;
2429	if (distance < closestDistance)
2430	{
2431	    closest = i;
2432	    closestDistance = distance;
2433	}
2434    }
2435
2436    if (XAllocColor(gui.dpy, colormap, &colortable[closest]) != 0)
2437    {
2438	gui.color_approx = TRUE;
2439	*colorPtr = colortable[closest];
2440    }
2441
2442    vim_free(colortable);
2443    return OK;
2444}
2445
2446/*
2447 * Set the current text foreground color.
2448 */
2449    void
2450gui_mch_set_fg_color(color)
2451    guicolor_T	color;
2452{
2453    if (color != prev_fg_color)
2454    {
2455	XSetForeground(gui.dpy, gui.text_gc, (Pixel)color);
2456	prev_fg_color = color;
2457    }
2458}
2459
2460/*
2461 * Set the current text background color.
2462 */
2463    void
2464gui_mch_set_bg_color(color)
2465    guicolor_T	color;
2466{
2467    if (color != prev_bg_color)
2468    {
2469	XSetBackground(gui.dpy, gui.text_gc, (Pixel)color);
2470	prev_bg_color = color;
2471    }
2472}
2473
2474/*
2475 * Set the current text special color.
2476 */
2477    void
2478gui_mch_set_sp_color(color)
2479    guicolor_T	color;
2480{
2481    prev_sp_color = color;
2482}
2483
2484/*
2485 * create a mouse pointer that is blank
2486 */
2487    static Cursor
2488gui_x11_create_blank_mouse()
2489{
2490    Pixmap blank_pixmap = XCreatePixmap(gui.dpy, gui.wid, 1, 1, 1);
2491    GC gc = XCreateGC(gui.dpy, blank_pixmap, (unsigned long)0, (XGCValues*)0);
2492    XDrawPoint(gui.dpy, blank_pixmap, gc, 0, 0);
2493    XFreeGC(gui.dpy, gc);
2494    return XCreatePixmapCursor(gui.dpy, blank_pixmap, blank_pixmap,
2495	    (XColor*)&gui.norm_pixel, (XColor*)&gui.norm_pixel, 0, 0);
2496}
2497
2498/*
2499 * Draw a curled line at the bottom of the character cell.
2500 */
2501    static void
2502draw_curl(row, col, cells)
2503    int row;
2504    int col;
2505    int cells;
2506{
2507    int			i;
2508    int			offset;
2509    static const int	val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
2510
2511    XSetForeground(gui.dpy, gui.text_gc, prev_sp_color);
2512    for (i = FILL_X(col); i < FILL_X(col + cells); ++i)
2513    {
2514	offset = val[i % 8];
2515	XDrawPoint(gui.dpy, gui.wid, gui.text_gc, i,
2516						FILL_Y(row + 1) - 1 - offset);
2517    }
2518    XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
2519}
2520
2521    void
2522gui_mch_draw_string(row, col, s, len, flags)
2523    int		row;
2524    int		col;
2525    char_u	*s;
2526    int		len;
2527    int		flags;
2528{
2529    int			cells = len;
2530#ifdef FEAT_MBYTE
2531    static void		*buf = NULL;
2532    static int		buflen = 0;
2533    char_u		*p;
2534    int			wlen = 0;
2535    int			c;
2536
2537    if (enc_utf8)
2538    {
2539	/* Convert UTF-8 byte sequence to 16 bit characters for the X
2540	 * functions.  Need a buffer for the 16 bit characters.  Keep it
2541	 * between calls, because allocating it each time is slow. */
2542	if (buflen < len)
2543	{
2544	    XtFree((char *)buf);
2545	    buf = (void *)XtMalloc(len * (sizeof(XChar2b) < sizeof(wchar_t)
2546					? sizeof(wchar_t) : sizeof(XChar2b)));
2547	    buflen = len;
2548	}
2549	p = s;
2550	cells = 0;
2551	while (p < s + len)
2552	{
2553	    c = utf_ptr2char(p);
2554# ifdef FEAT_XFONTSET
2555	    if (current_fontset != NULL)
2556	    {
2557#  ifdef SMALL_WCHAR_T
2558		if (c >= 0x10000)
2559		    c = 0xbf;		/* show chars > 0xffff as ? */
2560#  endif
2561		((wchar_t *)buf)[wlen] = c;
2562	    }
2563	    else
2564# endif
2565	    {
2566		if (c >= 0x10000)
2567		    c = 0xbf;		/* show chars > 0xffff as ? */
2568		((XChar2b *)buf)[wlen].byte1 = (unsigned)c >> 8;
2569		((XChar2b *)buf)[wlen].byte2 = c;
2570	    }
2571	    ++wlen;
2572	    cells += utf_char2cells(c);
2573	    p += utf_ptr2len(p);
2574	}
2575    }
2576    else if (has_mbyte)
2577    {
2578	cells = 0;
2579	for (p = s; p < s + len; )
2580	{
2581	    cells += ptr2cells(p);
2582	    p += (*mb_ptr2len)(p);
2583	}
2584    }
2585
2586#endif
2587
2588#ifdef FEAT_XFONTSET
2589    if (current_fontset != NULL)
2590    {
2591	/* Setup a clip rectangle to avoid spilling over in the next or
2592	 * previous line.  This is apparently needed for some fonts which are
2593	 * used in a fontset. */
2594	XRectangle	clip;
2595
2596	clip.x = 0;
2597	clip.y = 0;
2598	clip.height = gui.char_height;
2599	clip.width = gui.char_width * cells + 1;
2600	XSetClipRectangles(gui.dpy, gui.text_gc, FILL_X(col), FILL_Y(row),
2601		&clip, 1, Unsorted);
2602    }
2603#endif
2604
2605    if (flags & DRAW_TRANSP)
2606    {
2607#ifdef FEAT_MBYTE
2608	if (enc_utf8)
2609	    XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2610		    TEXT_Y(row), buf, wlen);
2611	else
2612#endif
2613	    XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2614		    TEXT_Y(row), (char *)s, len);
2615    }
2616    else if (p_linespace != 0
2617#ifdef FEAT_XFONTSET
2618	    || current_fontset != NULL
2619#endif
2620	    )
2621    {
2622	XSetForeground(gui.dpy, gui.text_gc, prev_bg_color);
2623	XFillRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
2624		FILL_Y(row), gui.char_width * cells, gui.char_height);
2625	XSetForeground(gui.dpy, gui.text_gc, prev_fg_color);
2626
2627#ifdef FEAT_MBYTE
2628	if (enc_utf8)
2629	    XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2630		    TEXT_Y(row), buf, wlen);
2631	else
2632#endif
2633	    XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2634		    TEXT_Y(row), (char *)s, len);
2635    }
2636    else
2637    {
2638	/* XmbDrawImageString has bug, don't use it for fontset. */
2639#ifdef FEAT_MBYTE
2640	if (enc_utf8)
2641	    XDrawImageString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2642		    TEXT_Y(row), buf, wlen);
2643	else
2644#endif
2645	    XDrawImageString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col),
2646		    TEXT_Y(row), (char *)s, len);
2647    }
2648
2649    /* Bold trick: draw the text again with a one-pixel offset. */
2650    if (flags & DRAW_BOLD)
2651    {
2652#ifdef FEAT_MBYTE
2653	if (enc_utf8)
2654	    XDrawString16(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
2655		    TEXT_Y(row), buf, wlen);
2656	else
2657#endif
2658	    XDrawString(gui.dpy, gui.wid, gui.text_gc, TEXT_X(col) + 1,
2659		    TEXT_Y(row), (char *)s, len);
2660    }
2661
2662    /* Undercurl: draw curl at the bottom of the character cell. */
2663    if (flags & DRAW_UNDERC)
2664	draw_curl(row, col, cells);
2665
2666    /* Underline: draw a line at the bottom of the character cell. */
2667    if (flags & DRAW_UNDERL)
2668    {
2669	int	y = FILL_Y(row + 1) - 1;
2670
2671	/* When p_linespace is 0, overwrite the bottom row of pixels.
2672	 * Otherwise put the line just below the character. */
2673	if (p_linespace > 1)
2674	    y -= p_linespace - 1;
2675	XDrawLine(gui.dpy, gui.wid, gui.text_gc, FILL_X(col),
2676		y, FILL_X(col + cells) - 1, y);
2677    }
2678
2679#ifdef FEAT_XFONTSET
2680    if (current_fontset != NULL)
2681	XSetClipMask(gui.dpy, gui.text_gc, None);
2682#endif
2683}
2684
2685/*
2686 * Return OK if the key with the termcap name "name" is supported.
2687 */
2688    int
2689gui_mch_haskey(name)
2690    char_u  *name;
2691{
2692    int i;
2693
2694    for (i = 0; special_keys[i].key_sym != (KeySym)0; i++)
2695	if (name[0] == special_keys[i].vim_code0 &&
2696					 name[1] == special_keys[i].vim_code1)
2697	    return OK;
2698    return FAIL;
2699}
2700
2701/*
2702 * Return the text window-id and display.  Only required for X-based GUI's
2703 */
2704    int
2705gui_get_x11_windis(win, dis)
2706    Window  *win;
2707    Display **dis;
2708{
2709    *win = XtWindow(vimShell);
2710    *dis = gui.dpy;
2711    return OK;
2712}
2713
2714    void
2715gui_mch_beep()
2716{
2717    XBell(gui.dpy, 0);
2718}
2719
2720    void
2721gui_mch_flash(msec)
2722    int		msec;
2723{
2724    /* Do a visual beep by reversing the foreground and background colors */
2725    XFillRectangle(gui.dpy, gui.wid, gui.invert_gc, 0, 0,
2726	    FILL_X((int)Columns) + gui.border_offset,
2727	    FILL_Y((int)Rows) + gui.border_offset);
2728    XSync(gui.dpy, False);
2729    ui_delay((long)msec, TRUE);	/* wait for a few msec */
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}
2734
2735/*
2736 * Invert a rectangle from row r, column c, for nr rows and nc columns.
2737 */
2738    void
2739gui_mch_invert_rectangle(r, c, nr, nc)
2740    int	    r;
2741    int	    c;
2742    int	    nr;
2743    int	    nc;
2744{
2745    XFillRectangle(gui.dpy, gui.wid, gui.invert_gc,
2746	FILL_X(c), FILL_Y(r), (nc) * gui.char_width, (nr) * gui.char_height);
2747}
2748
2749/*
2750 * Iconify the GUI window.
2751 */
2752    void
2753gui_mch_iconify()
2754{
2755    XIconifyWindow(gui.dpy, XtWindow(vimShell), DefaultScreen(gui.dpy));
2756}
2757
2758#if defined(FEAT_EVAL) || defined(PROTO)
2759/*
2760 * Bring the Vim window to the foreground.
2761 */
2762    void
2763gui_mch_set_foreground()
2764{
2765    XMapRaised(gui.dpy, XtWindow(vimShell));
2766}
2767#endif
2768
2769/*
2770 * Draw a cursor without focus.
2771 */
2772    void
2773gui_mch_draw_hollow_cursor(color)
2774    guicolor_T color;
2775{
2776    int		w = 1;
2777
2778#ifdef FEAT_MBYTE
2779    if (mb_lefthalve(gui.row, gui.col))
2780	w = 2;
2781#endif
2782    gui_mch_set_fg_color(color);
2783    XDrawRectangle(gui.dpy, gui.wid, gui.text_gc, FILL_X(gui.col),
2784	    FILL_Y(gui.row), w * gui.char_width - 1, gui.char_height - 1);
2785}
2786
2787/*
2788 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
2789 * color "color".
2790 */
2791    void
2792gui_mch_draw_part_cursor(w, h, color)
2793    int		w;
2794    int		h;
2795    guicolor_T	color;
2796{
2797    gui_mch_set_fg_color(color);
2798
2799    XFillRectangle(gui.dpy, gui.wid, gui.text_gc,
2800#ifdef FEAT_RIGHTLEFT
2801	    /* vertical line should be on the right of current point */
2802	    CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
2803#endif
2804		FILL_X(gui.col),
2805	    FILL_Y(gui.row) + gui.char_height - h,
2806	    w, h);
2807}
2808
2809/*
2810 * Catch up with any queued X events.  This may put keyboard input into the
2811 * input buffer, call resize call-backs, trigger timers etc.  If there is
2812 * nothing in the X event queue (& no timers pending), then we return
2813 * immediately.
2814 */
2815    void
2816gui_mch_update()
2817{
2818    XtInputMask mask, desired;
2819
2820#ifdef ALT_X_INPUT
2821    if (suppress_alternate_input)
2822	desired = (XtIMXEvent | XtIMTimer);
2823    else
2824#endif
2825	desired = (XtIMAll);
2826    while ((mask = XtAppPending(app_context)) && (mask & desired)
2827	    && !vim_is_input_buf_full())
2828	XtAppProcessEvent(app_context, desired);
2829}
2830
2831/*
2832 * GUI input routine called by gui_wait_for_chars().  Waits for a character
2833 * from the keyboard.
2834 *  wtime == -1	    Wait forever.
2835 *  wtime == 0	    This should never happen.
2836 *  wtime > 0	    Wait wtime milliseconds for a character.
2837 * Returns OK if a character was found to be available within the given time,
2838 * or FAIL otherwise.
2839 */
2840    int
2841gui_mch_wait_for_chars(wtime)
2842    long    wtime;
2843{
2844    int		    focus;
2845
2846    /*
2847     * Make this static, in case gui_x11_timer_cb is called after leaving
2848     * this function (otherwise a random value on the stack may be changed).
2849     */
2850    static int	    timed_out;
2851    XtIntervalId    timer = (XtIntervalId)0;
2852    XtInputMask	    desired;
2853#ifdef FEAT_SNIFF
2854    static int	    sniff_on = 0;
2855    static XtInputId sniff_input_id = 0;
2856#endif
2857
2858    timed_out = FALSE;
2859
2860#ifdef FEAT_SNIFF
2861    if (sniff_on && !want_sniff_request)
2862    {
2863	if (sniff_input_id)
2864	    XtRemoveInput(sniff_input_id);
2865	sniff_on = 0;
2866    }
2867    else if (!sniff_on && want_sniff_request)
2868    {
2869	sniff_input_id = XtAppAddInput(app_context, fd_from_sniff,
2870		     (XtPointer)XtInputReadMask, gui_x11_sniff_request_cb, 0);
2871	sniff_on = 1;
2872    }
2873#endif
2874
2875    if (wtime > 0)
2876	timer = XtAppAddTimeOut(app_context, (long_u)wtime, gui_x11_timer_cb,
2877								  &timed_out);
2878
2879    focus = gui.in_focus;
2880#ifdef ALT_X_INPUT
2881    if (suppress_alternate_input)
2882	desired = (XtIMXEvent | XtIMTimer);
2883    else
2884#endif
2885	desired = (XtIMAll);
2886    while (!timed_out)
2887    {
2888	/* Stop or start blinking when focus changes */
2889	if (gui.in_focus != focus)
2890	{
2891	    if (gui.in_focus)
2892		gui_mch_start_blink();
2893	    else
2894		gui_mch_stop_blink();
2895	    focus = gui.in_focus;
2896	}
2897
2898	/*
2899	 * Don't use gui_mch_update() because then we will spin-lock until a
2900	 * char arrives, instead we use XtAppProcessEvent() to hang until an
2901	 * event arrives.  No need to check for input_buf_full because we are
2902	 * returning as soon as it contains a single char.  Note that
2903	 * XtAppNextEvent() may not be used because it will not return after a
2904	 * timer event has arrived -- webb
2905	 */
2906	XtAppProcessEvent(app_context, desired);
2907
2908	if (input_available())
2909	{
2910	    if (timer != (XtIntervalId)0 && !timed_out)
2911		XtRemoveTimeOut(timer);
2912	    return OK;
2913	}
2914    }
2915    return FAIL;
2916}
2917
2918/*
2919 * Output routines.
2920 */
2921
2922/* Flush any output to the screen */
2923    void
2924gui_mch_flush()
2925{
2926    XFlush(gui.dpy);
2927}
2928
2929/*
2930 * Clear a rectangular region of the screen from text pos (row1, col1) to
2931 * (row2, col2) inclusive.
2932 */
2933    void
2934gui_mch_clear_block(row1, col1, row2, col2)
2935    int		row1;
2936    int		col1;
2937    int		row2;
2938    int		col2;
2939{
2940    int		x;
2941
2942    x = FILL_X(col1);
2943
2944    /* Clear one extra pixel at the far right, for when bold characters have
2945     * spilled over to the next column. */
2946    XFillRectangle(gui.dpy, gui.wid, gui.back_gc, x, FILL_Y(row1),
2947	    (col2 - col1 + 1) * gui.char_width + (col2 == Columns - 1),
2948	    (row2 - row1 + 1) * gui.char_height);
2949}
2950
2951    void
2952gui_mch_clear_all()
2953{
2954    XClearArea(gui.dpy, gui.wid, 0, 0, 0, 0, False);
2955}
2956
2957/*
2958 * Delete the given number of lines from the given row, scrolling up any
2959 * text further down within the scroll region.
2960 */
2961    void
2962gui_mch_delete_lines(row, num_lines)
2963    int	    row;
2964    int	    num_lines;
2965{
2966    if (gui.visibility == VisibilityFullyObscured)
2967	return;	    /* Can't see the window */
2968
2969    /* copy one extra pixel at the far right, for when bold has spilled
2970     * over */
2971    XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
2972	FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines),
2973	gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
2974			       + (gui.scroll_region_right == Columns - 1),
2975	gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
2976	FILL_X(gui.scroll_region_left), FILL_Y(row));
2977
2978    gui_clear_block(gui.scroll_region_bot - num_lines + 1,
2979						       gui.scroll_region_left,
2980			  gui.scroll_region_bot, gui.scroll_region_right);
2981    gui_x11_check_copy_area();
2982}
2983
2984/*
2985 * Insert the given number of lines before the given row, scrolling down any
2986 * following text within the scroll region.
2987 */
2988    void
2989gui_mch_insert_lines(row, num_lines)
2990    int	    row;
2991    int	    num_lines;
2992{
2993    if (gui.visibility == VisibilityFullyObscured)
2994	return;	    /* Can't see the window */
2995
2996    /* copy one extra pixel at the far right, for when bold has spilled
2997     * over */
2998    XCopyArea(gui.dpy, gui.wid, gui.wid, gui.text_gc,
2999	FILL_X(gui.scroll_region_left), FILL_Y(row),
3000	gui.char_width * (gui.scroll_region_right - gui.scroll_region_left + 1)
3001			       + (gui.scroll_region_right == Columns - 1),
3002	gui.char_height * (gui.scroll_region_bot - row - num_lines + 1),
3003	FILL_X(gui.scroll_region_left), FILL_Y(row + num_lines));
3004
3005    gui_clear_block(row, gui.scroll_region_left,
3006				row + num_lines - 1, gui.scroll_region_right);
3007    gui_x11_check_copy_area();
3008}
3009
3010/*
3011 * Update the region revealed by scrolling up/down.
3012 */
3013    static void
3014gui_x11_check_copy_area()
3015{
3016    XEvent		    event;
3017    XGraphicsExposeEvent    *gevent;
3018
3019    if (gui.visibility != VisibilityPartiallyObscured)
3020	return;
3021
3022    XFlush(gui.dpy);
3023
3024    /* Wait to check whether the scroll worked or not */
3025    for (;;)
3026    {
3027	if (XCheckTypedEvent(gui.dpy, NoExpose, &event))
3028	    return;	/* The scroll worked. */
3029
3030	if (XCheckTypedEvent(gui.dpy, GraphicsExpose, &event))
3031	{
3032	    gevent = (XGraphicsExposeEvent *)&event;
3033	    gui_redraw(gevent->x, gevent->y, gevent->width, gevent->height);
3034	    if (gevent->count == 0)
3035		return;		/* This was the last expose event */
3036	}
3037	XSync(gui.dpy, False);
3038    }
3039}
3040
3041/*
3042 * X Selection stuff, for cutting and pasting text to other windows.
3043 */
3044
3045    void
3046clip_mch_lose_selection(cbd)
3047    VimClipboard	*cbd;
3048{
3049    clip_x11_lose_selection(vimShell, cbd);
3050}
3051
3052    int
3053clip_mch_own_selection(cbd)
3054    VimClipboard	*cbd;
3055{
3056    return clip_x11_own_selection(vimShell, cbd);
3057}
3058
3059    void
3060clip_mch_request_selection(cbd)
3061    VimClipboard	*cbd;
3062{
3063    clip_x11_request_selection(vimShell, gui.dpy, cbd);
3064}
3065
3066    void
3067clip_mch_set_selection(cbd)
3068    VimClipboard	*cbd;
3069{
3070    clip_x11_set_selection(cbd);
3071}
3072
3073#if defined(FEAT_MENU) || defined(PROTO)
3074/*
3075 * Menu stuff.
3076 */
3077
3078/*
3079 * Make a menu either grey or not grey.
3080 */
3081    void
3082gui_mch_menu_grey(menu, grey)
3083    vimmenu_T	*menu;
3084    int		grey;
3085{
3086    if (menu->id != (Widget)0)
3087    {
3088	gui_mch_menu_hidden(menu, False);
3089	if (grey
3090#ifdef FEAT_GUI_MOTIF
3091		|| !menu->sensitive
3092#endif
3093		)
3094	    XtSetSensitive(menu->id, False);
3095	else
3096	    XtSetSensitive(menu->id, True);
3097    }
3098}
3099
3100/*
3101 * Make menu item hidden or not hidden
3102 */
3103    void
3104gui_mch_menu_hidden(menu, hidden)
3105    vimmenu_T	*menu;
3106    int		hidden;
3107{
3108    if (menu->id != (Widget)0)
3109    {
3110	if (hidden)
3111	    XtUnmanageChild(menu->id);
3112	else
3113	    XtManageChild(menu->id);
3114    }
3115}
3116
3117/*
3118 * This is called after setting all the menus to grey/hidden or not.
3119 */
3120    void
3121gui_mch_draw_menubar()
3122{
3123    /* Nothing to do in X */
3124}
3125
3126    void
3127gui_x11_menu_cb(w, client_data, call_data)
3128    Widget	w UNUSED;
3129    XtPointer	client_data;
3130    XtPointer	call_data UNUSED;
3131{
3132    gui_menu_cb((vimmenu_T *)client_data);
3133}
3134
3135#endif /* FEAT_MENU */
3136
3137
3138
3139/*
3140 * Function called when window closed.	Works like ":qa".
3141 * Should put up a requester!
3142 */
3143    static void
3144gui_x11_wm_protocol_handler(w, client_data, event, dum)
3145    Widget	w UNUSED;
3146    XtPointer	client_data UNUSED;
3147    XEvent	*event;
3148    Boolean	*dum UNUSED;
3149{
3150    /*
3151     * Only deal with Client messages.
3152     */
3153    if (event->type != ClientMessage)
3154	return;
3155
3156    /*
3157     * The WM_SAVE_YOURSELF event arrives when the window manager wants to
3158     * exit.  That can be cancelled though, thus Vim shouldn't exit here.
3159     * Just sync our swap files.
3160     */
3161    if ((Atom)((XClientMessageEvent *)event)->data.l[0] ==
3162						  wm_atoms[SAVE_YOURSELF_IDX])
3163    {
3164	out_flush();
3165	ml_sync_all(FALSE, FALSE);	/* preserve all swap files */
3166
3167	/* Set the window's WM_COMMAND property, to let the window manager
3168	 * know we are done saving ourselves.  We don't want to be restarted,
3169	 * thus set argv to NULL. */
3170	XSetCommand(gui.dpy, XtWindow(vimShell), NULL, 0);
3171	return;
3172    }
3173
3174    if ((Atom)((XClientMessageEvent *)event)->data.l[0] !=
3175						  wm_atoms[DELETE_WINDOW_IDX])
3176	return;
3177
3178    gui_shell_closed();
3179}
3180
3181#ifdef FEAT_CLIENTSERVER
3182/*
3183 * Function called when property changed. Check for incoming commands
3184 */
3185    static void
3186gui_x11_send_event_handler(w, client_data, event, dum)
3187    Widget	w UNUSED;
3188    XtPointer	client_data UNUSED;
3189    XEvent	*event;
3190    Boolean	*dum UNUSED;
3191{
3192    XPropertyEvent *e = (XPropertyEvent *) event;
3193
3194    if (e->type == PropertyNotify && e->window == commWindow
3195	    && e->atom == commProperty &&  e->state == PropertyNewValue)
3196    {
3197	serverEventProc(gui.dpy, event);
3198    }
3199}
3200#endif
3201
3202/*
3203 * Cursor blink functions.
3204 *
3205 * This is a simple state machine:
3206 * BLINK_NONE	not blinking at all
3207 * BLINK_OFF	blinking, cursor is not shown
3208 * BLINK_ON	blinking, cursor is shown
3209 */
3210
3211#define BLINK_NONE  0
3212#define BLINK_OFF   1
3213#define BLINK_ON    2
3214
3215static int		blink_state = BLINK_NONE;
3216static long_u		blink_waittime = 700;
3217static long_u		blink_ontime = 400;
3218static long_u		blink_offtime = 250;
3219static XtIntervalId	blink_timer = (XtIntervalId)0;
3220
3221    void
3222gui_mch_set_blinking(waittime, on, off)
3223    long    waittime, on, off;
3224{
3225    blink_waittime = waittime;
3226    blink_ontime = on;
3227    blink_offtime = off;
3228}
3229
3230/*
3231 * Stop the cursor blinking.  Show the cursor if it wasn't shown.
3232 */
3233    void
3234gui_mch_stop_blink()
3235{
3236    if (blink_timer != (XtIntervalId)0)
3237    {
3238	XtRemoveTimeOut(blink_timer);
3239	blink_timer = (XtIntervalId)0;
3240    }
3241    if (blink_state == BLINK_OFF)
3242	gui_update_cursor(TRUE, FALSE);
3243    blink_state = BLINK_NONE;
3244}
3245
3246/*
3247 * Start the cursor blinking.  If it was already blinking, this restarts the
3248 * waiting time and shows the cursor.
3249 */
3250    void
3251gui_mch_start_blink()
3252{
3253    if (blink_timer != (XtIntervalId)0)
3254	XtRemoveTimeOut(blink_timer);
3255    /* Only switch blinking on if none of the times is zero */
3256    if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
3257    {
3258	blink_timer = XtAppAddTimeOut(app_context, blink_waittime,
3259						      gui_x11_blink_cb, NULL);
3260	blink_state = BLINK_ON;
3261	gui_update_cursor(TRUE, FALSE);
3262    }
3263}
3264
3265    static void
3266gui_x11_blink_cb(timed_out, interval_id)
3267    XtPointer	    timed_out UNUSED;
3268    XtIntervalId    *interval_id UNUSED;
3269{
3270    if (blink_state == BLINK_ON)
3271    {
3272	gui_undraw_cursor();
3273	blink_state = BLINK_OFF;
3274	blink_timer = XtAppAddTimeOut(app_context, blink_offtime,
3275						      gui_x11_blink_cb, NULL);
3276    }
3277    else
3278    {
3279	gui_update_cursor(TRUE, FALSE);
3280	blink_state = BLINK_ON;
3281	blink_timer = XtAppAddTimeOut(app_context, blink_ontime,
3282						      gui_x11_blink_cb, NULL);
3283    }
3284}
3285
3286/*
3287 * Return the RGB value of a pixel as a long.
3288 */
3289    long_u
3290gui_mch_get_rgb(pixel)
3291    guicolor_T	pixel;
3292{
3293    XColor	xc;
3294    Colormap	colormap;
3295
3296    colormap = DefaultColormap(gui.dpy, XDefaultScreen(gui.dpy));
3297    xc.pixel = pixel;
3298    XQueryColor(gui.dpy, colormap, &xc);
3299
3300    return ((xc.red & 0xff00) << 8) + (xc.green & 0xff00)
3301						   + ((unsigned)xc.blue >> 8);
3302}
3303
3304/*
3305 * Add the callback functions.
3306 */
3307    void
3308gui_x11_callbacks(textArea, vimForm)
3309    Widget textArea;
3310    Widget vimForm;
3311{
3312    XtAddEventHandler(textArea, VisibilityChangeMask, FALSE,
3313	gui_x11_visibility_cb, (XtPointer)0);
3314
3315    XtAddEventHandler(textArea, ExposureMask, FALSE, gui_x11_expose_cb,
3316	(XtPointer)0);
3317
3318    XtAddEventHandler(vimShell, StructureNotifyMask, FALSE,
3319	gui_x11_resize_window_cb, (XtPointer)0);
3320
3321    XtAddEventHandler(vimShell, FocusChangeMask, FALSE, gui_x11_focus_change_cb,
3322	(XtPointer)0);
3323    /*
3324     * Only install these enter/leave callbacks when 'p' in 'guioptions'.
3325     * Only needed for some window managers.
3326     */
3327    if (vim_strchr(p_go, GO_POINTER) != NULL)
3328    {
3329	XtAddEventHandler(vimShell, LeaveWindowMask, FALSE, gui_x11_leave_cb,
3330	    (XtPointer)0);
3331	XtAddEventHandler(textArea, LeaveWindowMask, FALSE, gui_x11_leave_cb,
3332	    (XtPointer)0);
3333	XtAddEventHandler(textArea, EnterWindowMask, FALSE, gui_x11_enter_cb,
3334	    (XtPointer)0);
3335	XtAddEventHandler(vimShell, EnterWindowMask, FALSE, gui_x11_enter_cb,
3336	    (XtPointer)0);
3337    }
3338
3339    XtAddEventHandler(vimForm, KeyPressMask, FALSE, gui_x11_key_hit_cb,
3340	(XtPointer)0);
3341    XtAddEventHandler(textArea, KeyPressMask, FALSE, gui_x11_key_hit_cb,
3342	(XtPointer)0);
3343
3344    /* get pointer moved events from scrollbar, needed for 'mousefocus' */
3345    XtAddEventHandler(vimForm, PointerMotionMask,
3346	FALSE, gui_x11_mouse_cb, (XtPointer)1);
3347    XtAddEventHandler(textArea, ButtonPressMask | ButtonReleaseMask |
3348					 ButtonMotionMask | PointerMotionMask,
3349	FALSE, gui_x11_mouse_cb, (XtPointer)0);
3350}
3351
3352/*
3353 * Get current mouse coordinates in text window.
3354 */
3355    void
3356gui_mch_getmouse(int *x, int *y)
3357{
3358    int		rootx, rooty, winx, winy;
3359    Window	root, child;
3360    unsigned int mask;
3361
3362    if (gui.wid && XQueryPointer(gui.dpy, gui.wid, &root, &child,
3363					 &rootx, &rooty, &winx, &winy, &mask)) {
3364	*x = winx;
3365	*y = winy;
3366    } else {
3367	*x = -1;
3368	*y = -1;
3369    }
3370}
3371
3372    void
3373gui_mch_setmouse(x, y)
3374    int		x;
3375    int		y;
3376{
3377    if (gui.wid)
3378	XWarpPointer(gui.dpy, (Window)0, gui.wid, 0, 0, 0, 0, x, y);
3379}
3380
3381#if (defined(FEAT_GUI_MOTIF) && defined(FEAT_MENU)) || defined(PROTO)
3382    XButtonPressedEvent *
3383gui_x11_get_last_mouse_event()
3384{
3385    return &last_mouse_event;
3386}
3387#endif
3388
3389#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
3390
3391/* Signs are currently always 2 chars wide.  Hopefully the font is big enough
3392 * to provide room for the bitmap! */
3393# define SIGN_WIDTH (gui.char_width * 2)
3394
3395    void
3396gui_mch_drawsign(row, col, typenr)
3397    int		row;
3398    int		col;
3399    int		typenr;
3400{
3401    XImage	*sign;
3402
3403    if (gui.in_use && (sign = (XImage *)sign_get_image(typenr)) != NULL)
3404    {
3405	XClearArea(gui.dpy, gui.wid, TEXT_X(col), TEXT_Y(row) - sign->height,
3406		SIGN_WIDTH, gui.char_height, FALSE);
3407	XPutImage(gui.dpy, gui.wid, gui.text_gc, sign, 0, 0,
3408		TEXT_X(col) + (SIGN_WIDTH - sign->width) / 2,
3409		TEXT_Y(row) - sign->height,
3410		sign->width, sign->height);
3411    }
3412}
3413
3414    void *
3415gui_mch_register_sign(signfile)
3416    char_u	    *signfile;
3417{
3418    XpmAttributes   attrs;
3419    XImage	    *sign = NULL;
3420    int		    status;
3421
3422    /*
3423     * Setup the color substitution table.
3424     */
3425    if (signfile[0] != NUL && signfile[0] != '-')
3426    {
3427	XpmColorSymbol color[5] =
3428	{
3429	    {"none", NULL, 0},
3430	    {"iconColor1", NULL, 0},
3431	    {"bottomShadowColor", NULL, 0},
3432	    {"topShadowColor", NULL, 0},
3433	    {"selectColor", NULL, 0}
3434	};
3435	attrs.valuemask = XpmColorSymbols;
3436	attrs.numsymbols = 2;
3437	attrs.colorsymbols = color;
3438	attrs.colorsymbols[0].pixel = gui.back_pixel;
3439	attrs.colorsymbols[1].pixel = gui.norm_pixel;
3440	status = XpmReadFileToImage(gui.dpy, (char *)signfile,
3441							 &sign, NULL, &attrs);
3442	if (status == 0)
3443	{
3444	    /* Sign width is fixed at two columns now.
3445	    if (sign->width > gui.sign_width)
3446		gui.sign_width = sign->width + 8; */
3447	}
3448	else
3449	    EMSG(_(e_signdata));
3450    }
3451
3452    return (void *)sign;
3453}
3454
3455    void
3456gui_mch_destroy_sign(sign)
3457    void *sign;
3458{
3459    XDestroyImage((XImage*)sign);
3460}
3461#endif
3462
3463
3464#ifdef FEAT_MOUSESHAPE
3465/* The last set mouse pointer shape is remembered, to be used when it goes
3466 * from hidden to not hidden. */
3467static int last_shape = 0;
3468#endif
3469
3470/*
3471 * Use the blank mouse pointer or not.
3472 */
3473    void
3474gui_mch_mousehide(hide)
3475    int		hide;	/* TRUE = use blank ptr, FALSE = use parent ptr */
3476{
3477    if (gui.pointer_hidden != hide)
3478    {
3479	gui.pointer_hidden = hide;
3480	if (hide)
3481	    XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
3482	else
3483#ifdef FEAT_MOUSESHAPE
3484	    mch_set_mouse_shape(last_shape);
3485#else
3486	    XUndefineCursor(gui.dpy, gui.wid);
3487#endif
3488    }
3489}
3490
3491#if defined(FEAT_MOUSESHAPE) || defined(PROTO)
3492
3493/* Table for shape IDs.  Keep in sync with the mshape_names[] table in
3494 * misc2.c! */
3495static int mshape_ids[] =
3496{
3497    XC_left_ptr,		/* arrow */
3498    0,				/* blank */
3499    XC_xterm,			/* beam */
3500    XC_sb_v_double_arrow,	/* updown */
3501    XC_sizing,			/* udsizing */
3502    XC_sb_h_double_arrow,	/* leftright */
3503    XC_sizing,			/* lrsizing */
3504    XC_watch,			/* busy */
3505    XC_X_cursor,		/* no */
3506    XC_crosshair,		/* crosshair */
3507    XC_hand1,			/* hand1 */
3508    XC_hand2,			/* hand2 */
3509    XC_pencil,			/* pencil */
3510    XC_question_arrow,		/* question */
3511    XC_right_ptr,		/* right-arrow */
3512    XC_center_ptr,		/* up-arrow */
3513    XC_left_ptr			/* last one */
3514};
3515
3516    void
3517mch_set_mouse_shape(shape)
3518    int	shape;
3519{
3520    int	    id;
3521
3522    if (!gui.in_use)
3523	return;
3524
3525    if (shape == MSHAPE_HIDE || gui.pointer_hidden)
3526	XDefineCursor(gui.dpy, gui.wid, gui.blank_pointer);
3527    else
3528    {
3529	if (shape >= MSHAPE_NUMBERED)
3530	{
3531	    id = shape - MSHAPE_NUMBERED;
3532	    if (id >= XC_num_glyphs)
3533		id = XC_left_ptr;
3534	    else
3535		id &= ~1;	/* they are always even (why?) */
3536	}
3537	else
3538	    id = mshape_ids[shape];
3539
3540	XDefineCursor(gui.dpy, gui.wid, XCreateFontCursor(gui.dpy, id));
3541    }
3542    if (shape != MSHAPE_HIDE)
3543	last_shape = shape;
3544}
3545#endif
3546
3547#if (defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)) || defined(PROTO)
3548/*
3549 * Set the balloon-eval used for the tooltip of a toolbar menu item.
3550 * The check for a non-toolbar item was added, because there is a crash when
3551 * passing a normal menu item here.  Can't explain that, but better avoid it.
3552 */
3553    void
3554gui_mch_menu_set_tip(menu)
3555    vimmenu_T	*menu;
3556{
3557    if (menu->id != NULL && menu->parent != NULL
3558				       && menu_is_toolbar(menu->parent->name))
3559    {
3560	/* Always destroy and create the balloon, in case the string was
3561	 * changed. */
3562	if (menu->tip != NULL)
3563	{
3564	    gui_mch_destroy_beval_area(menu->tip);
3565	    menu->tip = NULL;
3566	}
3567	if (menu->strings[MENU_INDEX_TIP] != NULL)
3568	    menu->tip = gui_mch_create_beval_area(
3569		    menu->id,
3570		    menu->strings[MENU_INDEX_TIP],
3571		    NULL,
3572		    NULL);
3573    }
3574}
3575#endif
3576