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