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