Mercurial > vim
annotate src/gui_athena.c @ 7801:a1e71a01dbd6 v7.4.1197
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Author: Bram Moolenaar <Bram@vim.org>
Date: Fri Jan 29 22:13:30 2016 +0100
patch 7.4.1197
Problem: Still using __ARGS.
Solution: Remove __ARGS in several files. (script by Hirohito Higashi)
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Fri, 29 Jan 2016 22:15:05 +0100 |
parents | 04736b4030ec |
children | 81794242a275 |
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 * Athena port by Bill Foster | |
6 * | |
7 * Do ":help uganda" in Vim to read copying and usage conditions. | |
8 * Do ":help credits" in Vim to see a list of people who contributed. | |
9 * See README.txt for an overview of the Vim source code. | |
10 */ | |
11 | |
12 #include <X11/StringDefs.h> | |
13 #include <X11/Intrinsic.h> | |
14 #ifdef FEAT_GUI_NEXTAW | |
15 # include <X11/neXtaw/Form.h> | |
16 # include <X11/neXtaw/SimpleMenu.h> | |
17 # include <X11/neXtaw/MenuButton.h> | |
18 # include <X11/neXtaw/SmeBSB.h> | |
19 # include <X11/neXtaw/SmeLine.h> | |
20 # include <X11/neXtaw/Box.h> | |
21 # include <X11/neXtaw/Dialog.h> | |
22 # include <X11/neXtaw/Text.h> | |
23 # include <X11/neXtaw/AsciiText.h> | |
24 # include <X11/neXtaw/Scrollbar.h> | |
25 #else | |
26 # include <X11/Xaw/Form.h> | |
27 # include <X11/Xaw/SimpleMenu.h> | |
28 # include <X11/Xaw/MenuButton.h> | |
29 # include <X11/Xaw/SmeBSB.h> | |
30 # include <X11/Xaw/SmeLine.h> | |
31 # include <X11/Xaw/Box.h> | |
32 # include <X11/Xaw/Dialog.h> | |
33 # include <X11/Xaw/Text.h> | |
34 # include <X11/Xaw/AsciiText.h> | |
35 #endif /* FEAT_GUI_NEXTAW */ | |
36 | |
37 #include "vim.h" | |
38 #ifndef FEAT_GUI_NEXTAW | |
39 # include "gui_at_sb.h" | |
40 #endif | |
41 | |
42 extern Widget vimShell; | |
43 | |
44 static Widget vimForm = (Widget)0; | |
215 | 45 Widget textArea = (Widget)0; |
7 | 46 #ifdef FEAT_MENU |
47 static Widget menuBar = (Widget)0; | |
48 static XtIntervalId timer = 0; /* 0 = expired, otherwise active */ | |
49 | |
50 /* Used to figure out menu ordering */ | |
51 static vimmenu_T *a_cur_menu = NULL; | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
52 static Cardinal athena_calculate_ins_pos(Widget); |
7 | 53 |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
54 static Pixmap gui_athena_create_pullright_pixmap(Widget); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
55 static void gui_athena_menu_timeout(XtPointer, XtIntervalId *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
56 static void gui_athena_popup_callback(Widget, XtPointer, XtPointer); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
57 static void gui_athena_delayed_arm_action(Widget, XEvent *, String *, |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
58 Cardinal *); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
59 static void gui_athena_popdown_submenus_action(Widget, XEvent *, |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
60 String *, Cardinal *); |
7 | 61 static XtActionsRec pullAction[2] = { |
62 { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action}, | |
63 { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action} | |
64 }; | |
65 #endif | |
66 | |
67 #ifdef FEAT_TOOLBAR | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
68 static void gui_mch_reset_focus(void); |
7 | 69 static Widget toolBar = (Widget)0; |
70 #endif | |
71 | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
72 static void gui_athena_scroll_cb_jump(Widget, XtPointer, XtPointer); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
73 static void gui_athena_scroll_cb_scroll(Widget, XtPointer, XtPointer); |
7 | 74 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU) |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
75 static void gui_athena_menu_colors(Widget id); |
7 | 76 #endif |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
77 static void gui_athena_scroll_colors(Widget id); |
7 | 78 |
79 #ifdef FEAT_MENU | |
80 static XtTranslations popupTrans, parentTrans, menuTrans, supermenuTrans; | |
81 static Pixmap pullerBitmap = None; | |
82 static int puller_width = 0; | |
83 #endif | |
84 | |
85 /* | |
86 * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the | |
87 * left or middle mouse button. | |
88 */ | |
89 static void | |
90 gui_athena_scroll_cb_jump(w, client_data, call_data) | |
1887 | 91 Widget w UNUSED; |
7 | 92 XtPointer client_data, call_data; |
93 { | |
94 scrollbar_T *sb, *sb_info; | |
95 long value; | |
96 | |
97 sb = gui_find_scrollbar((long)client_data); | |
98 | |
99 if (sb == NULL) | |
100 return; | |
101 else if (sb->wp != NULL) /* Left or right scrollbar */ | |
102 { | |
103 /* | |
104 * Careful: need to get scrollbar info out of first (left) scrollbar | |
105 * for window, but keep real scrollbar too because we must pass it to | |
106 * gui_drag_scrollbar(). | |
107 */ | |
108 sb_info = &sb->wp->w_scrollbars[0]; | |
109 } | |
110 else /* Bottom scrollbar */ | |
111 sb_info = sb; | |
112 | |
113 value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001); | |
114 if (value > sb_info->max) | |
115 value = sb_info->max; | |
116 | |
117 gui_drag_scrollbar(sb, value, TRUE); | |
118 } | |
119 | |
120 /* | |
121 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or | |
122 * right mouse buttons. | |
123 */ | |
124 static void | |
125 gui_athena_scroll_cb_scroll(w, client_data, call_data) | |
1887 | 126 Widget w UNUSED; |
7 | 127 XtPointer client_data, call_data; |
128 { | |
129 scrollbar_T *sb, *sb_info; | |
130 long value; | |
131 int data = (int)(long)call_data; | |
132 int page; | |
133 | |
134 sb = gui_find_scrollbar((long)client_data); | |
135 | |
136 if (sb == NULL) | |
137 return; | |
138 if (sb->wp != NULL) /* Left or right scrollbar */ | |
139 { | |
140 /* | |
141 * Careful: need to get scrollbar info out of first (left) scrollbar | |
142 * for window, but keep real scrollbar too because we must pass it to | |
143 * gui_drag_scrollbar(). | |
144 */ | |
145 sb_info = &sb->wp->w_scrollbars[0]; | |
146 | |
147 if (sb_info->size > 5) | |
148 page = sb_info->size - 2; /* use two lines of context */ | |
149 else | |
150 page = sb_info->size; | |
151 #ifdef FEAT_GUI_NEXTAW | |
152 if (data < 0) | |
153 { | |
154 data = (data - gui.char_height + 1) / gui.char_height; | |
155 if (data > -sb_info->size) | |
156 data = -1; | |
157 else | |
158 data = -page; | |
159 } | |
160 else if (data > 0) | |
161 { | |
162 data = (data + gui.char_height - 1) / gui.char_height; | |
163 if (data < sb_info->size) | |
164 data = 1; | |
165 else | |
166 data = page; | |
167 } | |
168 #else | |
169 switch (data) | |
170 { | |
171 case ONE_LINE_DATA: data = 1; break; | |
172 case -ONE_LINE_DATA: data = -1; break; | |
173 case ONE_PAGE_DATA: data = page; break; | |
174 case -ONE_PAGE_DATA: data = -page; break; | |
175 case END_PAGE_DATA: data = sb_info->max; break; | |
176 case -END_PAGE_DATA: data = -sb_info->max; break; | |
177 default: data = 0; break; | |
178 } | |
179 #endif | |
180 } | |
181 else /* Bottom scrollbar */ | |
182 { | |
183 sb_info = sb; | |
184 #ifdef FEAT_GUI_NEXTAW | |
185 if (data < 0) | |
186 { | |
187 data = (data - gui.char_width + 1) / gui.char_width; | |
188 if (data > -sb->size) | |
189 data = -1; | |
190 } | |
191 else if (data > 0) | |
192 { | |
193 data = (data + gui.char_width - 1) / gui.char_width; | |
194 if (data < sb->size) | |
195 data = 1; | |
196 } | |
197 #endif | |
198 if (data < -1) /* page-width left */ | |
199 { | |
200 if (sb->size > 8) | |
201 data = -(sb->size - 5); | |
202 else | |
203 data = -sb->size; | |
204 } | |
205 else if (data > 1) /* page-width right */ | |
206 { | |
207 if (sb->size > 8) | |
208 data = (sb->size - 5); | |
209 else | |
210 data = sb->size; | |
211 } | |
212 } | |
213 | |
214 value = sb_info->value + data; | |
215 if (value > sb_info->max) | |
216 value = sb_info->max; | |
217 else if (value < 0) | |
218 value = 0; | |
219 | |
220 /* Update the bottom scrollbar an extra time (why is this needed?? */ | |
221 if (sb->wp == NULL) /* Bottom scrollbar */ | |
222 gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max); | |
223 | |
224 gui_drag_scrollbar(sb, value, FALSE); | |
225 } | |
226 | |
227 /* | |
228 * Create all the Athena widgets necessary. | |
229 */ | |
230 void | |
231 gui_x11_create_widgets() | |
232 { | |
233 /* | |
234 * We don't have any borders handled internally by the textArea to worry | |
235 * about so only skip over the configured border width. | |
236 */ | |
237 gui.border_offset = gui.border_width; | |
238 | |
239 /* The form containing all the other widgets */ | |
240 vimForm = XtVaCreateManagedWidget("vimForm", | |
241 formWidgetClass, vimShell, | |
242 XtNborderWidth, 0, | |
243 NULL); | |
244 gui_athena_scroll_colors(vimForm); | |
245 | |
246 #ifdef FEAT_MENU | |
247 /* The top menu bar */ | |
248 menuBar = XtVaCreateManagedWidget("menuBar", | |
249 boxWidgetClass, vimForm, | |
250 XtNresizable, True, | |
251 XtNtop, XtChainTop, | |
252 XtNbottom, XtChainTop, | |
253 XtNleft, XtChainLeft, | |
254 XtNright, XtChainRight, | |
255 XtNinsertPosition, athena_calculate_ins_pos, | |
256 NULL); | |
257 gui_athena_menu_colors(menuBar); | |
258 if (gui.menu_fg_pixel != INVALCOLOR) | |
259 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL); | |
260 #endif | |
261 | |
262 #ifdef FEAT_TOOLBAR | |
263 /* Don't create it Managed, it will be managed when creating the first | |
264 * item. Otherwise an empty toolbar shows up. */ | |
265 toolBar = XtVaCreateWidget("toolBar", | |
266 boxWidgetClass, vimForm, | |
267 XtNresizable, True, | |
268 XtNtop, XtChainTop, | |
269 XtNbottom, XtChainTop, | |
270 XtNleft, XtChainLeft, | |
271 XtNright, XtChainRight, | |
272 XtNorientation, XtorientHorizontal, | |
273 XtNhSpace, 1, | |
274 XtNvSpace, 3, | |
275 XtNinsertPosition, athena_calculate_ins_pos, | |
276 NULL); | |
277 gui_athena_menu_colors(toolBar); | |
278 #endif | |
279 | |
280 /* The text area. */ | |
281 textArea = XtVaCreateManagedWidget("textArea", | |
282 coreWidgetClass, vimForm, | |
283 XtNresizable, True, | |
284 XtNtop, XtChainTop, | |
285 XtNbottom, XtChainTop, | |
286 XtNleft, XtChainLeft, | |
287 XtNright, XtChainLeft, | |
288 XtNbackground, gui.back_pixel, | |
289 XtNborderWidth, 0, | |
290 NULL); | |
291 | |
292 /* | |
293 * Install the callbacks. | |
294 */ | |
295 gui_x11_callbacks(textArea, vimForm); | |
296 | |
297 #ifdef FEAT_MENU | |
298 popupTrans = XtParseTranslationTable( | |
299 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" | |
300 "<LeaveWindow>: unhighlight()\n" | |
301 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n" | |
302 "<Motion>: highlight() menu-delayedpopup()"); | |
303 parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()"); | |
304 menuTrans = XtParseTranslationTable( | |
305 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" | |
306 "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n" | |
307 "<BtnUp>: notify() unhighlight()\n" | |
308 "<BtnMotion>: highlight() menu-delayedpopup()"); | |
309 supermenuTrans = XtParseTranslationTable( | |
310 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n" | |
311 "<LeaveWindow>: unhighlight()\n" | |
312 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n" | |
313 "<BtnMotion>: highlight() menu-delayedpopup()"); | |
314 | |
315 XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction, | |
316 XtNumber(pullAction)); | |
317 #endif | |
318 | |
319 /* Pretend we don't have input focus, we will get an event if we do. */ | |
320 gui.in_focus = FALSE; | |
321 } | |
322 | |
323 #ifdef FEAT_MENU | |
324 /* | |
325 * Calculates the Pixmap based on the size of the current menu font. | |
326 */ | |
327 static Pixmap | |
328 gui_athena_create_pullright_pixmap(w) | |
329 Widget w; | |
330 { | |
331 Pixmap retval; | |
332 #ifdef FONTSET_ALWAYS | |
333 XFontSet font = None; | |
334 #else | |
335 XFontStruct *font = NULL; | |
336 #endif | |
337 | |
338 #ifdef FONTSET_ALWAYS | |
339 if (gui.menu_fontset == NOFONTSET) | |
340 #else | |
341 if (gui.menu_font == NOFONT) | |
342 #endif | |
343 { | |
344 XrmValue from, to; | |
345 WidgetList children; | |
346 Cardinal num_children; | |
347 | |
348 #ifdef FONTSET_ALWAYS | |
349 from.size = strlen(from.addr = XtDefaultFontSet); | |
350 to.addr = (XtPointer)&font; | |
351 to.size = sizeof(XFontSet); | |
352 #else | |
353 from.size = strlen(from.addr = XtDefaultFont); | |
354 to.addr = (XtPointer)&font; | |
355 to.size = sizeof(XFontStruct *); | |
356 #endif | |
357 /* Assumption: The menuBar children will use the same font as the | |
358 * pulldown menu items AND they will all be of type | |
359 * XtNfont. | |
360 */ | |
361 XtVaGetValues(menuBar, XtNchildren, &children, | |
362 XtNnumChildren, &num_children, | |
363 NULL); | |
364 if (XtConvertAndStore(w ? w : | |
365 (num_children > 0) ? children[0] : menuBar, | |
366 XtRString, &from, | |
367 #ifdef FONTSET_ALWAYS | |
368 XtRFontSet, &to | |
369 #else | |
370 XtRFontStruct, &to | |
371 #endif | |
372 ) == False) | |
373 return None; | |
374 /* "font" should now contain data */ | |
375 } | |
376 else | |
377 #ifdef FONTSET_ALWAYS | |
378 font = (XFontSet)gui.menu_fontset; | |
379 #else | |
380 font = (XFontStruct *)gui.menu_font; | |
381 #endif | |
382 | |
383 { | |
384 int width, height; | |
385 GC draw_gc, undraw_gc; | |
386 XGCValues gc_values; | |
387 XPoint points[3]; | |
388 | |
389 #ifdef FONTSET_ALWAYS | |
390 height = fontset_height2(font); | |
391 #else | |
392 height = font->max_bounds.ascent + font->max_bounds.descent; | |
393 #endif | |
394 width = height - 2; | |
395 puller_width = width + 4; | |
396 retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width, | |
397 height, 1); | |
398 gc_values.foreground = 1; | |
399 gc_values.background = 0; | |
400 draw_gc = XCreateGC(gui.dpy, retval, | |
401 GCForeground | GCBackground, | |
402 &gc_values); | |
403 gc_values.foreground = 0; | |
404 gc_values.background = 1; | |
405 undraw_gc = XCreateGC(gui.dpy, retval, | |
406 GCForeground | GCBackground, | |
407 &gc_values); | |
408 points[0].x = 0; | |
409 points[0].y = 0; | |
410 points[1].x = width - 1; | |
411 points[1].y = (height - 1) / 2; | |
412 points[2].x = 0; | |
413 points[2].y = height - 1; | |
414 XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height); | |
415 XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points), | |
416 Convex, CoordModeOrigin); | |
417 XFreeGC(gui.dpy, draw_gc); | |
418 XFreeGC(gui.dpy, undraw_gc); | |
419 } | |
420 return retval; | |
421 } | |
422 #endif | |
423 | |
424 /* | |
425 * Called when the GUI is not going to start after all. | |
426 */ | |
427 void | |
428 gui_x11_destroy_widgets() | |
429 { | |
430 textArea = NULL; | |
431 #ifdef FEAT_MENU | |
432 menuBar = NULL; | |
433 #endif | |
434 #ifdef FEAT_TOOLBAR | |
435 toolBar = NULL; | |
436 #endif | |
437 } | |
438 | |
439 #if defined(FEAT_TOOLBAR) || defined(PROTO) | |
47 | 440 # include "gui_x11_pm.h" |
441 # ifdef HAVE_X11_XPM_H | |
442 # include <X11/xpm.h> | |
443 # endif | |
444 | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
445 static void createXpmImages(char_u *path, char **xpm, Pixmap *sen); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
446 static void get_toolbar_pixmap(vimmenu_T *menu, Pixmap *sen); |
47 | 447 |
448 /* | |
449 * Allocated a pixmap for toolbar menu "menu". | |
450 * Return in "sen". | |
451 */ | |
452 static void | |
453 get_toolbar_pixmap(menu, sen) | |
454 vimmenu_T *menu; | |
455 Pixmap *sen; | |
456 { | |
457 char_u buf[MAXPATHL]; /* buffer storing expanded pathname */ | |
458 char **xpm = NULL; /* xpm array */ | |
459 | |
460 buf[0] = NUL; /* start with NULL path */ | |
461 | |
462 if (menu->iconfile != NULL) | |
463 { | |
464 /* Use the "icon=" argument. */ | |
465 gui_find_iconfile(menu->iconfile, buf, "xpm"); | |
466 createXpmImages(buf, NULL, sen); | |
467 | |
468 /* If it failed, try using the menu name. */ | |
469 if (*sen == (Pixmap)0 && gui_find_bitmap(menu->name, buf, "xpm") == OK) | |
470 createXpmImages(buf, NULL, sen); | |
471 if (*sen != (Pixmap)0) | |
472 return; | |
473 } | |
474 | |
475 if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) | |
476 { | |
477 if (menu->iconidx >= 0 && menu->iconidx | |
1887 | 478 < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) |
47 | 479 xpm = built_in_pixmaps[menu->iconidx]; |
480 else | |
481 xpm = tb_blank_xpm; | |
482 } | |
483 | |
484 if (xpm != NULL || buf[0] != NUL) | |
485 createXpmImages(buf, xpm, sen); | |
486 } | |
487 | |
488 /* | |
489 * Read an Xpm file, doing color substitutions for the foreground and | |
490 * background colors. If there is an error reading a color xpm file, | |
491 * drop back and read the monochrome file. If successful, create the | |
492 * insensitive Pixmap too. | |
493 */ | |
494 static void | |
495 createXpmImages(path, xpm, sen) | |
496 char_u *path; | |
497 char **xpm; | |
498 Pixmap *sen; | |
499 { | |
500 Window rootWindow; | |
501 XpmAttributes attrs; | |
502 XpmColorSymbol color[5] = | |
503 { | |
504 {"none", "none", 0}, | |
505 {"iconColor1", NULL, 0}, | |
506 {"bottomShadowColor", NULL, 0}, | |
507 {"topShadowColor", NULL, 0}, | |
508 {"selectColor", NULL, 0} | |
509 }; | |
510 int screenNum; | |
511 int status; | |
512 Pixmap mask; | |
513 Pixmap map; | |
514 | |
515 gui_mch_get_toolbar_colors( | |
516 &color[BACKGROUND].pixel, | |
517 &color[FOREGROUND].pixel, | |
518 &color[BOTTOM_SHADOW].pixel, | |
519 &color[TOP_SHADOW].pixel, | |
520 &color[HIGHLIGHT].pixel); | |
521 | |
4352 | 522 /* Setup the color substitution table */ |
47 | 523 attrs.valuemask = XpmColorSymbols; |
524 attrs.colorsymbols = color; | |
525 attrs.numsymbols = 5; | |
526 | |
527 screenNum = DefaultScreen(gui.dpy); | |
528 rootWindow = RootWindow(gui.dpy, screenNum); | |
529 | |
530 /* Create the "sensitive" pixmap */ | |
531 if (xpm != NULL) | |
532 status = XpmCreatePixmapFromData(gui.dpy, rootWindow, xpm, | |
533 &map, &mask, &attrs); | |
534 else | |
535 status = XpmReadFileToPixmap(gui.dpy, rootWindow, (char *)path, | |
536 &map, &mask, &attrs); | |
537 if (status == XpmSuccess && map != 0) | |
538 { | |
539 XGCValues gcvalues; | |
540 GC back_gc; | |
541 GC mask_gc; | |
542 | |
543 /* Need to create new Pixmaps with the mask applied. */ | |
544 gcvalues.foreground = color[BACKGROUND].pixel; | |
545 back_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues); | |
546 mask_gc = XCreateGC(gui.dpy, map, GCForeground, &gcvalues); | |
547 XSetClipMask(gui.dpy, mask_gc, mask); | |
548 | |
549 /* Create the "sensitive" pixmap. */ | |
550 *sen = XCreatePixmap(gui.dpy, rootWindow, | |
551 attrs.width, attrs.height, | |
552 DefaultDepth(gui.dpy, screenNum)); | |
553 XFillRectangle(gui.dpy, *sen, back_gc, 0, 0, | |
554 attrs.width, attrs.height); | |
555 XCopyArea(gui.dpy, map, *sen, mask_gc, 0, 0, | |
556 attrs.width, attrs.height, 0, 0); | |
557 | |
558 XFreeGC(gui.dpy, back_gc); | |
559 XFreeGC(gui.dpy, mask_gc); | |
560 XFreePixmap(gui.dpy, map); | |
561 } | |
562 else | |
563 *sen = 0; | |
564 | |
565 XpmFreeAttributes(&attrs); | |
566 } | |
567 | |
7 | 568 void |
569 gui_mch_set_toolbar_pos(x, y, w, h) | |
570 int x; | |
571 int y; | |
572 int w; | |
573 int h; | |
574 { | |
575 Dimension border; | |
576 int height; | |
577 | |
578 if (!XtIsManaged(toolBar)) /* nothing to do */ | |
579 return; | |
580 XtUnmanageChild(toolBar); | |
581 XtVaGetValues(toolBar, | |
582 XtNborderWidth, &border, | |
583 NULL); | |
584 height = h - 2 * border; | |
585 if (height < 0) | |
586 height = 1; | |
587 XtVaSetValues(toolBar, | |
588 XtNhorizDistance, x, | |
589 XtNvertDistance, y, | |
590 XtNwidth, w - 2 * border, | |
591 XtNheight, height, | |
592 NULL); | |
593 XtManageChild(toolBar); | |
594 } | |
595 #endif | |
596 | |
597 void | |
598 gui_mch_set_text_area_pos(x, y, w, h) | |
599 int x; | |
600 int y; | |
601 int w; | |
602 int h; | |
603 { | |
604 XtUnmanageChild(textArea); | |
605 XtVaSetValues(textArea, | |
606 XtNhorizDistance, x, | |
607 XtNvertDistance, y, | |
608 XtNwidth, w, | |
609 XtNheight, h, | |
610 NULL); | |
611 XtManageChild(textArea); | |
612 #ifdef FEAT_TOOLBAR | |
613 /* Give keyboard focus to the textArea instead of the toolbar. */ | |
614 gui_mch_reset_focus(); | |
615 #endif | |
616 } | |
617 | |
618 #ifdef FEAT_TOOLBAR | |
619 /* | |
620 * A toolbar button has been pushed; now reset the input focus | |
621 * such that the user can type page up/down etc. and have the | |
622 * input go to the editor window, not the button | |
623 */ | |
624 static void | |
625 gui_mch_reset_focus() | |
626 { | |
627 XtSetKeyboardFocus(vimForm, textArea); | |
628 } | |
629 #endif | |
630 | |
631 | |
632 void | |
633 gui_x11_set_back_color() | |
634 { | |
635 if (textArea != NULL) | |
636 XtVaSetValues(textArea, | |
637 XtNbackground, gui.back_pixel, | |
638 NULL); | |
639 } | |
640 | |
641 #if defined(FEAT_MENU) || defined(PROTO) | |
642 /* | |
643 * Menu stuff. | |
644 */ | |
645 | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
646 static char_u *make_pull_name(char_u * name); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
647 static Widget get_popup_entry(Widget w); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
648 static Widget submenu_widget(Widget); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
649 static Boolean has_submenu(Widget); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
650 static void gui_mch_submenu_change(vimmenu_T *mp, int colors); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
651 static void gui_athena_menu_font(Widget id); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
652 static Boolean gui_athena_menu_has_submenus(Widget, Widget); |
7 | 653 |
654 void | |
655 gui_mch_enable_menu(flag) | |
656 int flag; | |
657 { | |
658 if (flag) | |
659 { | |
660 XtManageChild(menuBar); | |
661 # ifdef FEAT_TOOLBAR | |
662 if (XtIsManaged(toolBar)) | |
663 { | |
664 XtVaSetValues(toolBar, | |
665 XtNvertDistance, gui.menu_height, | |
666 NULL); | |
667 XtVaSetValues(textArea, | |
668 XtNvertDistance, gui.menu_height + gui.toolbar_height, | |
669 NULL); | |
670 } | |
671 # endif | |
672 } | |
673 else | |
674 { | |
675 XtUnmanageChild(menuBar); | |
676 # ifdef FEAT_TOOLBAR | |
677 if (XtIsManaged(toolBar)) | |
678 { | |
679 XtVaSetValues(toolBar, | |
680 XtNvertDistance, 0, | |
681 NULL); | |
682 } | |
683 # endif | |
684 } | |
685 } | |
686 | |
687 void | |
688 gui_mch_set_menu_pos(x, y, w, h) | |
689 int x; | |
690 int y; | |
691 int w; | |
692 int h; | |
693 { | |
694 Dimension border; | |
695 int height; | |
696 | |
697 XtUnmanageChild(menuBar); | |
698 XtVaGetValues(menuBar, XtNborderWidth, &border, NULL); | |
699 /* avoid trouble when there are no menu items, and h is 1 */ | |
700 height = h - 2 * border; | |
701 if (height < 0) | |
702 height = 1; | |
703 XtVaSetValues(menuBar, | |
704 XtNhorizDistance, x, | |
705 XtNvertDistance, y, | |
706 XtNwidth, w - 2 * border, | |
707 XtNheight, height, | |
708 NULL); | |
709 XtManageChild(menuBar); | |
710 } | |
711 | |
712 /* | |
713 * Used to calculate the insertion position of a widget with respect to its | |
714 * neighbors. | |
715 * | |
716 * Valid range of return values is: 0 (beginning of children) to | |
717 * numChildren (end of children). | |
718 */ | |
719 static Cardinal | |
720 athena_calculate_ins_pos(widget) | |
721 Widget widget; | |
722 { | |
723 /* Assume that if the parent of the vimmenu_T is NULL, then we can get | |
724 * to this menu by traversing "next", starting at "root_menu". | |
725 * | |
726 * This holds true for popup menus, toolbar, and toplevel menu items. | |
727 */ | |
728 | |
729 /* Popup menus: "id" is NULL. Only submenu_id is valid */ | |
730 | |
731 /* Menus that are not toplevel: "parent" will be non-NULL, "id" & | |
732 * "submenu_id" will be non-NULL. | |
733 */ | |
734 | |
735 /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */ | |
736 | |
737 WidgetList children; | |
738 Cardinal num_children = 0; | |
739 int retval; | |
740 Arg args[2]; | |
741 int n = 0; | |
742 int i; | |
743 | |
744 XtSetArg(args[n], XtNchildren, &children); n++; | |
745 XtSetArg(args[n], XtNnumChildren, &num_children); n++; | |
746 XtGetValues(XtParent(widget), args, n); | |
747 | |
748 retval = num_children; | |
1887 | 749 for (i = 0; i < (int)num_children; ++i) |
7 | 750 { |
751 Widget current = children[i]; | |
752 vimmenu_T *menu = NULL; | |
753 | |
754 for (menu = (a_cur_menu->parent == NULL) | |
755 ? root_menu : a_cur_menu->parent->children; | |
756 menu != NULL; | |
757 menu = menu->next) | |
758 if (current == menu->id | |
759 && a_cur_menu->priority < menu->priority | |
760 && i < retval) | |
761 retval = i; | |
762 } | |
763 return retval; | |
764 } | |
765 | |
766 void | |
767 gui_mch_add_menu(menu, idx) | |
768 vimmenu_T *menu; | |
1887 | 769 int idx UNUSED; |
7 | 770 { |
771 char_u *pullright_name; | |
772 Dimension height, space, border; | |
773 vimmenu_T *parent = menu->parent; | |
774 | |
775 a_cur_menu = menu; | |
776 if (parent == NULL) | |
777 { | |
778 if (menu_is_popup(menu->dname)) | |
779 { | |
780 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname, | |
781 simpleMenuWidgetClass, vimShell, | |
782 XtNinsertPosition, athena_calculate_ins_pos, | |
783 XtNtranslations, popupTrans, | |
784 NULL); | |
785 gui_athena_menu_colors(menu->submenu_id); | |
786 } | |
787 else if (menu_is_menubar(menu->dname)) | |
788 { | |
789 menu->id = XtVaCreateManagedWidget((char *)menu->dname, | |
790 menuButtonWidgetClass, menuBar, | |
791 XtNmenuName, menu->dname, | |
792 #ifdef FONTSET_ALWAYS | |
793 XtNinternational, True, | |
794 #endif | |
795 NULL); | |
796 if (menu->id == (Widget)0) | |
797 return; | |
798 gui_athena_menu_colors(menu->id); | |
799 gui_athena_menu_font(menu->id); | |
800 | |
801 menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname, | |
802 simpleMenuWidgetClass, menu->id, | |
803 XtNinsertPosition, athena_calculate_ins_pos, | |
804 XtNtranslations, supermenuTrans, | |
805 NULL); | |
806 gui_athena_menu_colors(menu->submenu_id); | |
807 gui_athena_menu_font(menu->submenu_id); | |
808 | |
809 /* Don't update the menu height when it was set at a fixed value */ | |
810 if (!gui.menu_height_fixed) | |
811 { | |
812 /* | |
813 * When we add a top-level item to the menu bar, we can figure | |
814 * out how high the menu bar should be. | |
815 */ | |
816 XtVaGetValues(menuBar, | |
817 XtNvSpace, &space, | |
818 XtNborderWidth, &border, | |
819 NULL); | |
820 XtVaGetValues(menu->id, | |
821 XtNheight, &height, | |
822 NULL); | |
823 gui.menu_height = height + 2 * (space + border); | |
824 } | |
825 } | |
826 } | |
827 else if (parent->submenu_id != (Widget)0) | |
828 { | |
829 menu->id = XtVaCreateManagedWidget((char *)menu->dname, | |
830 smeBSBObjectClass, parent->submenu_id, | |
831 XtNlabel, menu->dname, | |
832 #ifdef FONTSET_ALWAYS | |
833 XtNinternational, True, | |
834 #endif | |
835 NULL); | |
836 if (menu->id == (Widget)0) | |
837 return; | |
838 if (pullerBitmap == None) | |
839 pullerBitmap = gui_athena_create_pullright_pixmap(menu->id); | |
840 | |
841 XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap, | |
842 NULL); | |
843 /* If there are other menu items that are not pulldown menus, | |
844 * we need to adjust the right margins of those, too. | |
845 */ | |
846 { | |
847 WidgetList children; | |
848 Cardinal num_children; | |
849 int i; | |
850 | |
851 XtVaGetValues(parent->submenu_id, XtNchildren, &children, | |
852 XtNnumChildren, &num_children, | |
853 NULL); | |
1887 | 854 for (i = 0; i < (int)num_children; ++i) |
7 | 855 { |
856 XtVaSetValues(children[i], | |
857 XtNrightMargin, puller_width, | |
858 NULL); | |
859 } | |
860 } | |
861 gui_athena_menu_colors(menu->id); | |
862 gui_athena_menu_font(menu->id); | |
863 | |
864 pullright_name = make_pull_name(menu->dname); | |
865 menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name, | |
866 simpleMenuWidgetClass, parent->submenu_id, | |
867 XtNtranslations, menuTrans, | |
868 NULL); | |
869 gui_athena_menu_colors(menu->submenu_id); | |
870 gui_athena_menu_font(menu->submenu_id); | |
871 vim_free(pullright_name); | |
872 XtAddCallback(menu->submenu_id, XtNpopupCallback, | |
873 gui_athena_popup_callback, (XtPointer)menu); | |
874 | |
875 if (parent->parent != NULL) | |
876 XtOverrideTranslations(parent->submenu_id, parentTrans); | |
877 } | |
878 a_cur_menu = NULL; | |
879 } | |
880 | |
881 /* Used to determine whether a SimpleMenu has pulldown entries. | |
882 * | |
883 * "id" is the parent of the menu items. | |
884 * Ignore widget "ignore" in the pane. | |
885 */ | |
886 static Boolean | |
887 gui_athena_menu_has_submenus(id, ignore) | |
888 Widget id; | |
889 Widget ignore; | |
890 { | |
891 WidgetList children; | |
892 Cardinal num_children; | |
893 int i; | |
894 | |
895 XtVaGetValues(id, XtNchildren, &children, | |
896 XtNnumChildren, &num_children, | |
897 NULL); | |
1887 | 898 for (i = 0; i < (int)num_children; ++i) |
7 | 899 { |
900 if (children[i] == ignore) | |
901 continue; | |
902 if (has_submenu(children[i])) | |
903 return True; | |
904 } | |
905 return False; | |
906 } | |
907 | |
908 static void | |
909 gui_athena_menu_font(id) | |
910 Widget id; | |
911 { | |
912 #ifdef FONTSET_ALWAYS | |
913 if (gui.menu_fontset != NOFONTSET) | |
914 { | |
915 if (XtIsManaged(id)) | |
916 { | |
917 XtUnmanageChild(id); | |
918 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL); | |
919 /* We should force the widget to recalculate it's | |
920 * geometry now. */ | |
921 XtManageChild(id); | |
922 } | |
923 else | |
924 XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL); | |
925 if (has_submenu(id)) | |
926 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL); | |
927 } | |
928 #else | |
929 int managed = FALSE; | |
930 | |
931 if (gui.menu_font != NOFONT) | |
932 { | |
933 if (XtIsManaged(id)) | |
934 { | |
935 XtUnmanageChild(id); | |
936 managed = TRUE; | |
937 } | |
938 | |
939 # ifdef FEAT_XFONTSET | |
940 if (gui.fontset != NOFONTSET) | |
941 XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL); | |
942 else | |
943 # endif | |
944 XtVaSetValues(id, XtNfont, gui.menu_font, NULL); | |
945 if (has_submenu(id)) | |
946 XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL); | |
947 | |
948 /* Force the widget to recalculate it's geometry now. */ | |
949 if (managed) | |
950 XtManageChild(id); | |
951 } | |
952 #endif | |
953 } | |
954 | |
955 | |
956 void | |
957 gui_mch_new_menu_font() | |
958 { | |
959 Pixmap oldpuller = None; | |
960 | |
961 if (menuBar == (Widget)0) | |
962 return; | |
963 | |
964 if (pullerBitmap != None) | |
965 { | |
966 oldpuller = pullerBitmap; | |
967 pullerBitmap = gui_athena_create_pullright_pixmap(NULL); | |
968 } | |
969 gui_mch_submenu_change(root_menu, FALSE); | |
970 | |
971 { | |
972 /* Iterate through the menubar menu items and get the height of | |
973 * each one. The menu bar height is set to the maximum of all | |
974 * the heights. | |
975 */ | |
976 vimmenu_T *mp; | |
977 int max_height = 9999; | |
978 | |
979 for (mp = root_menu; mp != NULL; mp = mp->next) | |
980 { | |
981 if (menu_is_menubar(mp->dname)) | |
982 { | |
983 Dimension height; | |
984 | |
985 XtVaGetValues(mp->id, | |
125 | 986 XtNheight, &height, |
7 | 987 NULL); |
988 if (height < max_height) | |
989 max_height = height; | |
990 } | |
991 } | |
992 if (max_height != 9999) | |
993 { | |
994 /* Don't update the menu height when it was set at a fixed value */ | |
995 if (!gui.menu_height_fixed) | |
996 { | |
997 Dimension space, border; | |
998 | |
999 XtVaGetValues(menuBar, | |
1000 XtNvSpace, &space, | |
1001 XtNborderWidth, &border, | |
1002 NULL); | |
1003 gui.menu_height = max_height + 2 * (space + border); | |
1004 } | |
1005 } | |
1006 } | |
1007 /* Now, to simulate the window being resized. Only, this | |
1008 * will resize the window to it's current state. | |
1009 * | |
1010 * There has to be a better way, but I do not see one at this time. | |
1011 * (David Harrison) | |
1012 */ | |
1013 { | |
1014 Position w, h; | |
1015 | |
1016 XtVaGetValues(vimShell, | |
1017 XtNwidth, &w, | |
1018 XtNheight, &h, | |
1019 NULL); | |
1020 gui_resize_shell(w, h | |
1021 #ifdef FEAT_XIM | |
1022 - xim_get_status_area_height() | |
1023 #endif | |
1024 ); | |
1025 } | |
811 | 1026 gui_set_shellsize(FALSE, TRUE, RESIZE_VERT); |
7 | 1027 ui_new_shellsize(); |
1028 if (oldpuller != None) | |
1029 XFreePixmap(gui.dpy, oldpuller); | |
1030 } | |
1031 | |
1032 #if defined(FEAT_BEVAL) || defined(PROTO) | |
1033 void | |
1034 gui_mch_new_tooltip_font() | |
1035 { | |
1036 # ifdef FEAT_TOOLBAR | |
1037 vimmenu_T *menu; | |
1038 | |
1039 if (toolBar == (Widget)0) | |
1040 return; | |
1041 | |
1042 menu = gui_find_menu((char_u *)"ToolBar"); | |
1043 if (menu != NULL) | |
1044 gui_mch_submenu_change(menu, FALSE); | |
1045 # endif | |
1046 } | |
1047 | |
1048 void | |
1049 gui_mch_new_tooltip_colors() | |
1050 { | |
1051 # ifdef FEAT_TOOLBAR | |
1052 vimmenu_T *menu; | |
1053 | |
1054 if (toolBar == (Widget)0) | |
1055 return; | |
1056 | |
1057 menu = gui_find_menu((char_u *)"ToolBar"); | |
1058 if (menu != NULL) | |
1059 gui_mch_submenu_change(menu, TRUE); | |
1060 # endif | |
1061 } | |
1062 #endif | |
1063 | |
1064 static void | |
1065 gui_mch_submenu_change(menu, colors) | |
1066 vimmenu_T *menu; | |
1067 int colors; /* TRUE for colors, FALSE for font */ | |
1068 { | |
1069 vimmenu_T *mp; | |
1070 | |
1071 for (mp = menu; mp != NULL; mp = mp->next) | |
1072 { | |
1073 if (mp->id != (Widget)0) | |
1074 { | |
1075 if (colors) | |
1076 { | |
1077 gui_athena_menu_colors(mp->id); | |
1078 #ifdef FEAT_TOOLBAR | |
1079 /* For a toolbar item: Free the pixmap and allocate a new one, | |
1080 * so that the background color is right. */ | |
1081 if (mp->image != (Pixmap)0) | |
1082 { | |
1083 XFreePixmap(gui.dpy, mp->image); | |
47 | 1084 get_toolbar_pixmap(mp, &mp->image); |
7 | 1085 if (mp->image != (Pixmap)0) |
1086 XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL); | |
1087 } | |
1088 | |
1089 # ifdef FEAT_BEVAL | |
1090 /* If we have a tooltip, then we need to change it's colors */ | |
1091 if (mp->tip != NULL) | |
1092 { | |
1093 Arg args[2]; | |
1094 | |
1095 args[0].name = XtNbackground; | |
1096 args[0].value = gui.tooltip_bg_pixel; | |
1097 args[1].name = XtNforeground; | |
1098 args[1].value = gui.tooltip_fg_pixel; | |
1099 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); | |
1100 } | |
1101 # endif | |
1102 #endif | |
1103 } | |
1104 else | |
1105 { | |
1106 gui_athena_menu_font(mp->id); | |
1107 #ifdef FEAT_BEVAL | |
1108 /* If we have a tooltip, then we need to change it's font */ | |
1109 /* Assume XtNinternational == True (in createBalloonEvalWindow) | |
1110 */ | |
1111 if (mp->tip != NULL) | |
1112 { | |
1113 Arg args[1]; | |
1114 | |
1115 args[0].name = XtNfontSet; | |
1116 args[0].value = (XtArgVal)gui.tooltip_fontset; | |
1117 XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); | |
1118 } | |
1119 #endif | |
1120 } | |
1121 } | |
1122 | |
1123 if (mp->children != NULL) | |
1124 { | |
1125 /* Set the colors/font for the tear off widget */ | |
1126 if (mp->submenu_id != (Widget)0) | |
1127 { | |
1128 if (colors) | |
1129 gui_athena_menu_colors(mp->submenu_id); | |
1130 else | |
1131 gui_athena_menu_font(mp->submenu_id); | |
1132 } | |
1133 /* Set the colors for the children */ | |
1134 gui_mch_submenu_change(mp->children, colors); | |
1135 } | |
1136 } | |
1137 } | |
1138 | |
1139 /* | |
1140 * Make a submenu name into a pullright name. | |
1141 * Replace '.' by '_', can't include '.' in the submenu name. | |
1142 */ | |
1143 static char_u * | |
1144 make_pull_name(name) | |
1145 char_u * name; | |
1146 { | |
1147 char_u *pname; | |
1148 char_u *p; | |
1149 | |
1150 pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright")); | |
1151 if (pname != NULL) | |
1152 { | |
1153 strcat((char *)pname, "-pullright"); | |
1154 while ((p = vim_strchr(pname, '.')) != NULL) | |
1155 *p = '_'; | |
1156 } | |
1157 return pname; | |
1158 } | |
1159 | |
1160 void | |
1161 gui_mch_add_menu_item(menu, idx) | |
1162 vimmenu_T *menu; | |
1887 | 1163 int idx UNUSED; |
7 | 1164 { |
1165 vimmenu_T *parent = menu->parent; | |
1166 | |
1167 a_cur_menu = menu; | |
1168 # ifdef FEAT_TOOLBAR | |
1169 if (menu_is_toolbar(parent->name)) | |
1170 { | |
1171 WidgetClass type; | |
1172 int n; | |
1173 Arg args[21]; | |
1174 | |
1175 n = 0; | |
1176 if (menu_is_separator(menu->name)) | |
1177 { | |
1178 XtSetArg(args[n], XtNlabel, ""); n++; | |
1179 XtSetArg(args[n], XtNborderWidth, 0); n++; | |
1180 } | |
1181 else | |
1182 { | |
47 | 1183 get_toolbar_pixmap(menu, &menu->image); |
7 | 1184 XtSetArg(args[n], XtNlabel, menu->dname); n++; |
1185 XtSetArg(args[n], XtNinternalHeight, 1); n++; | |
1186 XtSetArg(args[n], XtNinternalWidth, 1); n++; | |
1187 XtSetArg(args[n], XtNborderWidth, 1); n++; | |
1188 if (menu->image != 0) | |
1189 XtSetArg(args[n], XtNbitmap, menu->image); n++; | |
1190 } | |
1191 XtSetArg(args[n], XtNhighlightThickness, 0); n++; | |
1192 type = commandWidgetClass; | |
1193 /* TODO: figure out the position in the toolbar? | |
1194 * This currently works fine for the default toolbar, but | |
1195 * what if we add/remove items during later runtime? | |
1196 */ | |
1197 | |
1198 /* NOTE: "idx" isn't used here. The position is calculated by | |
1199 * athena_calculate_ins_pos(). The position it calculates | |
1200 * should be equal to "idx". | |
1201 */ | |
1202 /* TODO: Could we just store "idx" and use that as the child | |
1203 * placement? | |
1204 */ | |
1205 | |
1206 if (menu->id == NULL) | |
1207 { | |
1208 menu->id = XtCreateManagedWidget((char *)menu->dname, | |
1209 type, toolBar, args, n); | |
1210 XtAddCallback(menu->id, | |
1211 XtNcallback, gui_x11_menu_cb, menu); | |
1212 } | |
1213 else | |
1214 XtSetValues(menu->id, args, n); | |
1215 gui_athena_menu_colors(menu->id); | |
1216 | |
1217 #ifdef FEAT_BEVAL | |
1218 gui_mch_menu_set_tip(menu); | |
1219 #endif | |
1220 | |
1221 menu->parent = parent; | |
1222 menu->submenu_id = NULL; | |
1223 if (!XtIsManaged(toolBar) | |
1224 && vim_strchr(p_go, GO_TOOLBAR) != NULL) | |
1225 gui_mch_show_toolbar(TRUE); | |
1226 gui.toolbar_height = gui_mch_compute_toolbar_height(); | |
1227 return; | |
1228 } /* toolbar menu item */ | |
1229 # endif | |
1230 | |
1231 /* Add menu separator */ | |
1232 if (menu_is_separator(menu->name)) | |
1233 { | |
1234 menu->submenu_id = (Widget)0; | |
1235 menu->id = XtVaCreateManagedWidget((char *)menu->dname, | |
1236 smeLineObjectClass, parent->submenu_id, | |
1237 NULL); | |
1238 if (menu->id == (Widget)0) | |
1239 return; | |
1240 gui_athena_menu_colors(menu->id); | |
1241 } | |
1242 else | |
1243 { | |
1244 if (parent != NULL && parent->submenu_id != (Widget)0) | |
1245 { | |
1246 menu->submenu_id = (Widget)0; | |
1247 menu->id = XtVaCreateManagedWidget((char *)menu->dname, | |
1248 smeBSBObjectClass, parent->submenu_id, | |
1249 XtNlabel, menu->dname, | |
1250 #ifdef FONTSET_ALWAYS | |
1251 XtNinternational, True, | |
1252 #endif | |
1253 NULL); | |
1254 if (menu->id == (Widget)0) | |
1255 return; | |
1256 | |
1257 /* If there are other "pulldown" items in this pane, then adjust | |
2255 | 1258 * the right margin to accommodate the arrow pixmap, otherwise |
7 | 1259 * the right margin will be the same as the left margin. |
1260 */ | |
1261 { | |
1262 Dimension left_margin; | |
1263 | |
1264 XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL); | |
1265 XtVaSetValues(menu->id, XtNrightMargin, | |
1266 gui_athena_menu_has_submenus(parent->submenu_id, NULL) ? | |
1267 puller_width : | |
1268 left_margin, | |
1269 NULL); | |
1270 } | |
1271 | |
1272 gui_athena_menu_colors(menu->id); | |
1273 gui_athena_menu_font(menu->id); | |
1274 XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb, | |
1275 (XtPointer)menu); | |
1276 } | |
1277 } | |
1278 a_cur_menu = NULL; | |
1279 } | |
1280 | |
1281 #if defined(FEAT_TOOLBAR) || defined(PROTO) | |
1282 void | |
1283 gui_mch_show_toolbar(int showit) | |
1284 { | |
1285 Cardinal numChildren; /* how many children toolBar has */ | |
1286 | |
1287 if (toolBar == (Widget)0) | |
1288 return; | |
1289 XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL); | |
1290 if (showit && numChildren > 0) | |
1291 { | |
1292 /* Assume that we want to show the toolbar if p_toolbar contains valid | |
1293 * option settings, therefore p_toolbar must not be NULL. | |
1294 */ | |
1295 WidgetList children; | |
1296 | |
1297 XtVaGetValues(toolBar, XtNchildren, &children, NULL); | |
1298 { | |
1299 void (*action)(BalloonEval *); | |
1300 int text = 0; | |
1301 | |
1302 if (strstr((const char *)p_toolbar, "tooltips")) | |
1303 action = &gui_mch_enable_beval_area; | |
1304 else | |
1305 action = &gui_mch_disable_beval_area; | |
1306 if (strstr((const char *)p_toolbar, "text")) | |
1307 text = 1; | |
1308 else if (strstr((const char *)p_toolbar, "icons")) | |
1309 text = -1; | |
1310 if (text != 0) | |
1311 { | |
1312 vimmenu_T *toolbar; | |
1313 vimmenu_T *cur; | |
1314 | |
1315 for (toolbar = root_menu; toolbar; toolbar = toolbar->next) | |
1316 if (menu_is_toolbar(toolbar->dname)) | |
1317 break; | |
1318 /* Assumption: toolbar is NULL if there is no toolbar, | |
1319 * otherwise it contains the toolbar menu structure. | |
1320 * | |
1321 * Assumption: "numChildren" == the number of items in the list | |
1322 * of items beginning with toolbar->children. | |
1323 */ | |
1324 if (toolbar) | |
1325 { | |
1326 for (cur = toolbar->children; cur; cur = cur->next) | |
1327 { | |
1328 Arg args[2]; | |
1329 int n = 0; | |
1330 | |
1331 /* Enable/Disable tooltip (OK to enable while currently | |
1332 * enabled) | |
1333 */ | |
1334 if (cur->tip != NULL) | |
1335 (*action)(cur->tip); | |
1336 if (text == 1) | |
1337 { | |
1338 XtSetArg(args[n], XtNbitmap, None); | |
1339 n++; | |
1340 XtSetArg(args[n], XtNlabel, | |
1341 menu_is_separator(cur->name) ? "" : | |
1342 (char *)cur->dname); | |
1343 n++; | |
1344 } | |
1345 else | |
1346 { | |
1347 XtSetArg(args[n], XtNbitmap, cur->image); | |
1348 n++; | |
1349 XtSetArg(args[n], XtNlabel, (cur->image == None) ? | |
1350 menu_is_separator(cur->name) ? | |
1351 "" : | |
1352 (char *)cur->dname | |
1353 : | |
1354 (char *)None); | |
1355 n++; | |
1356 } | |
1357 if (cur->id != NULL) | |
1358 { | |
1359 XtUnmanageChild(cur->id); | |
1360 XtSetValues(cur->id, args, n); | |
1361 XtManageChild(cur->id); | |
1362 } | |
1363 } | |
1364 } | |
1365 } | |
1366 } | |
1367 gui.toolbar_height = gui_mch_compute_toolbar_height(); | |
1368 XtManageChild(toolBar); | |
1369 if (XtIsManaged(menuBar)) | |
1370 { | |
1371 XtVaSetValues(textArea, | |
1372 XtNvertDistance, gui.toolbar_height + gui.menu_height, | |
1373 NULL); | |
1374 XtVaSetValues(toolBar, | |
1375 XtNvertDistance, gui.menu_height, | |
1376 NULL); | |
1377 } | |
1378 else | |
1379 { | |
1380 XtVaSetValues(textArea, | |
1381 XtNvertDistance, gui.toolbar_height, | |
1382 NULL); | |
1383 XtVaSetValues(toolBar, | |
1384 XtNvertDistance, 0, | |
1385 NULL); | |
1386 } | |
1387 } | |
1388 else | |
1389 { | |
1390 gui.toolbar_height = 0; | |
1391 if (XtIsManaged(menuBar)) | |
1392 XtVaSetValues(textArea, | |
1393 XtNvertDistance, gui.menu_height, | |
1394 NULL); | |
1395 else | |
1396 XtVaSetValues(textArea, | |
1397 XtNvertDistance, 0, | |
1398 NULL); | |
1399 | |
1400 XtUnmanageChild(toolBar); | |
1401 } | |
811 | 1402 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); |
7 | 1403 } |
1404 | |
1405 | |
1406 int | |
1407 gui_mch_compute_toolbar_height() | |
1408 { | |
1409 Dimension height; /* total Toolbar height */ | |
1410 Dimension whgt; /* height of each widget */ | |
1411 Dimension marginHeight; /* XmNmarginHeight of toolBar */ | |
1412 Dimension shadowThickness; /* thickness of Xtparent(toolBar) */ | |
1413 WidgetList children; /* list of toolBar's children */ | |
1414 Cardinal numChildren; /* how many children toolBar has */ | |
1415 int i; | |
1416 | |
1417 height = 0; | |
1418 shadowThickness = 0; | |
1419 marginHeight = 0; | |
1420 if (toolBar != (Widget)0) | |
1421 { | |
1422 XtVaGetValues(toolBar, | |
1423 XtNborderWidth, &shadowThickness, | |
1424 XtNvSpace, &marginHeight, | |
1425 XtNchildren, &children, | |
1426 XtNnumChildren, &numChildren, | |
1427 NULL); | |
1887 | 1428 for (i = 0; i < (int)numChildren; i++) |
7 | 1429 { |
1430 whgt = 0; | |
1431 | |
1432 XtVaGetValues(children[i], XtNheight, &whgt, NULL); | |
1433 if (height < whgt) | |
1434 height = whgt; | |
1435 } | |
1436 } | |
1437 | |
1438 return (int)(height + (marginHeight << 1) + (shadowThickness << 1)); | |
1439 } | |
1440 | |
1441 void | |
1442 gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp) | |
1443 Pixel *bgp; | |
1444 Pixel *fgp; | |
1445 Pixel *bsp; | |
1446 Pixel *tsp; | |
1447 Pixel *hsp; | |
1448 { | |
1449 XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL); | |
1450 *bsp = *bgp; | |
1451 *tsp = *fgp; | |
1452 *hsp = *tsp; | |
1453 } | |
1454 #endif | |
1455 | |
1456 | |
1457 void | |
1458 gui_mch_toggle_tearoffs(enable) | |
1887 | 1459 int enable UNUSED; |
7 | 1460 { |
1461 /* no tearoff menus */ | |
1462 } | |
1463 | |
1464 void | |
1465 gui_mch_new_menu_colors() | |
1466 { | |
1467 if (menuBar == (Widget)0) | |
1468 return; | |
1469 if (gui.menu_fg_pixel != INVALCOLOR) | |
1470 XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL); | |
1471 gui_athena_menu_colors(menuBar); | |
1472 #ifdef FEAT_TOOLBAR | |
1473 gui_athena_menu_colors(toolBar); | |
1474 #endif | |
1475 | |
1476 gui_mch_submenu_change(root_menu, TRUE); | |
1477 } | |
1478 | |
1479 /* | |
1480 * Destroy the machine specific menu widget. | |
1481 */ | |
1482 void | |
1483 gui_mch_destroy_menu(menu) | |
1484 vimmenu_T *menu; | |
1485 { | |
1486 Widget parent; | |
1487 | |
1488 /* There is no item for the toolbar. */ | |
1489 if (menu->id == (Widget)0) | |
1490 return; | |
1491 | |
1492 parent = XtParent(menu->id); | |
1493 | |
1494 /* When removing the last "pulldown" menu item from a pane, adjust the | |
1495 * right margins of the remaining widgets. | |
1496 */ | |
1497 if (menu->submenu_id != (Widget)0) | |
1498 { | |
1499 /* Go through the menu items in the parent of this item and | |
1500 * adjust their margins, if necessary. | |
1501 * This takes care of the case when we delete the last menu item in a | |
1502 * pane that has a submenu. In this case, there will be no arrow | |
1503 * pixmaps shown anymore. | |
1504 */ | |
1505 { | |
1506 WidgetList children; | |
1507 Cardinal num_children; | |
1508 int i; | |
1509 Dimension right_margin = 0; | |
1510 Boolean get_left_margin = False; | |
1511 | |
1512 XtVaGetValues(parent, XtNchildren, &children, | |
1513 XtNnumChildren, &num_children, | |
1514 NULL); | |
1515 if (gui_athena_menu_has_submenus(parent, menu->id)) | |
1516 right_margin = puller_width; | |
1517 else | |
1518 get_left_margin = True; | |
1519 | |
1887 | 1520 for (i = 0; i < (int)num_children; ++i) |
7 | 1521 { |
1522 if (children[i] == menu->id) | |
1523 continue; | |
1524 if (get_left_margin == True) | |
1525 { | |
1526 Dimension left_margin; | |
1527 | |
1528 XtVaGetValues(children[i], XtNleftMargin, &left_margin, | |
1529 NULL); | |
1530 XtVaSetValues(children[i], XtNrightMargin, left_margin, | |
1531 NULL); | |
1532 } | |
1533 else | |
1534 XtVaSetValues(children[i], XtNrightMargin, right_margin, | |
1535 NULL); | |
1536 } | |
1537 } | |
1538 } | |
1539 /* Please be sure to destroy the parent widget first (i.e. menu->id). | |
1540 * | |
1541 * This code should be basically identical to that in the file gui_motif.c | |
1542 * because they are both Xt based. | |
1543 */ | |
1544 if (menu->id != (Widget)0) | |
1545 { | |
1546 Cardinal num_children; | |
1547 Dimension height, space, border; | |
1548 | |
1549 XtVaGetValues(menuBar, | |
1550 XtNvSpace, &space, | |
1551 XtNborderWidth, &border, | |
1552 NULL); | |
1553 XtVaGetValues(menu->id, | |
1554 XtNheight, &height, | |
1555 NULL); | |
1556 #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL) | |
1557 if (parent == toolBar && menu->tip != NULL) | |
1558 { | |
1559 /* We try to destroy this before the actual menu, because there are | |
1560 * callbacks, etc. that will be unregistered during the tooltip | |
1561 * destruction. | |
1562 * | |
1563 * If you call "gui_mch_destroy_beval_area()" after destroying | |
1564 * menu->id, then the tooltip's window will have already been | |
1565 * deallocated by Xt, and unknown behaviour will ensue (probably | |
1566 * a core dump). | |
1567 */ | |
1568 gui_mch_destroy_beval_area(menu->tip); | |
1569 menu->tip = NULL; | |
1570 } | |
1571 #endif | |
1572 /* | |
1573 * This is a hack to stop the Athena simpleMenuWidget from getting a | |
1574 * BadValue error when a menu's last child is destroyed. We check to | |
1575 * see if this is the last child and if so, don't delete it. The parent | |
1576 * will be deleted soon anyway, and it will delete it's children like | |
1577 * all good widgets do. | |
1578 */ | |
1579 /* NOTE: The cause of the BadValue X Protocol Error is because when the | |
1580 * last child is destroyed, it is first unmanaged, thus causing a | |
1581 * geometry resize request from the parent Shell widget. | |
1582 * Since the Shell widget has no more children, it is resized to have | |
1583 * width/height of 0. XConfigureWindow() is then called with the | |
1584 * width/height of 0, which generates the BadValue. | |
1585 * | |
1586 * This happens in phase two of the widget destruction process. | |
1587 */ | |
1588 { | |
1589 if (parent != menuBar | |
1590 #ifdef FEAT_TOOLBAR | |
1591 && parent != toolBar | |
1592 #endif | |
1593 ) | |
1594 { | |
1595 XtVaGetValues(parent, XtNnumChildren, &num_children, NULL); | |
1596 if (num_children > 1) | |
1597 XtDestroyWidget(menu->id); | |
1598 } | |
1599 else | |
1600 XtDestroyWidget(menu->id); | |
1601 menu->id = (Widget)0; | |
1602 } | |
1603 | |
1604 if (parent == menuBar) | |
1605 { | |
1606 if (!gui.menu_height_fixed) | |
1607 gui.menu_height = height + 2 * (space + border); | |
1608 } | |
1609 #ifdef FEAT_TOOLBAR | |
1610 else if (parent == toolBar) | |
1611 { | |
1612 /* When removing last toolbar item, don't display the toolbar. */ | |
1613 XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL); | |
1614 if (num_children == 0) | |
1615 gui_mch_show_toolbar(FALSE); | |
1616 else | |
1617 gui.toolbar_height = gui_mch_compute_toolbar_height(); | |
1618 } | |
1619 #endif | |
1620 } | |
1621 if (menu->submenu_id != (Widget)0) | |
1622 { | |
1623 XtDestroyWidget(menu->submenu_id); | |
1624 menu->submenu_id = (Widget)0; | |
1625 } | |
1626 } | |
1627 | |
1628 static void | |
1629 gui_athena_menu_timeout(client_data, id) | |
1630 XtPointer client_data; | |
1887 | 1631 XtIntervalId *id UNUSED; |
7 | 1632 { |
1633 Widget w = (Widget)client_data; | |
1634 Widget popup; | |
1635 | |
1636 timer = 0; | |
1637 if (XtIsSubclass(w,smeBSBObjectClass)) | |
1638 { | |
1639 Pixmap p; | |
1640 | |
1641 XtVaGetValues(w, XtNrightBitmap, &p, NULL); | |
1642 if ((p != None) && (p != XtUnspecifiedPixmap)) | |
1643 { | |
1644 /* We are dealing with an item that has a submenu */ | |
1645 popup = get_popup_entry(XtParent(w)); | |
1646 if (popup == (Widget)0) | |
1647 return; | |
1648 XtPopup(popup, XtGrabNonexclusive); | |
1649 } | |
1650 } | |
1651 } | |
1652 | |
1653 /* This routine is used to calculate the position (in screen coordinates) | |
1654 * where a submenu should appear relative to the menu entry that popped it | |
1655 * up. It should appear even with and just slightly to the left of the | |
1656 * rightmost end of the menu entry that caused the popup. | |
1657 * | |
1658 * This is called when XtPopup() is called. | |
1659 */ | |
1660 static void | |
1661 gui_athena_popup_callback(w, client_data, call_data) | |
1662 Widget w; | |
1663 XtPointer client_data; | |
1887 | 1664 XtPointer call_data UNUSED; |
7 | 1665 { |
1666 /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */ | |
1667 vimmenu_T *menu = (vimmenu_T *)client_data; | |
1668 Dimension width; | |
1669 Position root_x, root_y; | |
1670 | |
1671 /* First, popdown any siblings that may have menus popped up */ | |
1672 { | |
1673 vimmenu_T *i; | |
1674 | |
1675 for (i = menu->parent->children; i != NULL; i = i->next) | |
1676 { | |
1677 if (i->submenu_id != NULL && XtIsManaged(i->submenu_id)) | |
1678 XtPopdown(i->submenu_id); | |
1679 } | |
1680 } | |
1681 XtVaGetValues(XtParent(w), | |
1682 XtNwidth, &width, | |
1683 NULL); | |
1684 /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */ | |
1685 /* i.e. This IS the active entry */ | |
1686 XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y); | |
1687 XtVaSetValues(w, XtNx, root_x, | |
1688 XtNy, root_y, | |
1689 NULL); | |
1690 } | |
1691 | |
1692 static void | |
1693 gui_athena_popdown_submenus_action(w, event, args, nargs) | |
1694 Widget w; | |
1695 XEvent *event; | |
1696 String *args; | |
1697 Cardinal *nargs; | |
1698 { | |
1699 WidgetList children; | |
1700 Cardinal num_children; | |
1701 | |
1702 XtVaGetValues(w, XtNchildren, &children, | |
1703 XtNnumChildren, &num_children, | |
1704 NULL); | |
1705 for (; num_children > 0; --num_children) | |
1706 { | |
1707 Widget child = children[num_children - 1]; | |
1708 | |
1709 if (has_submenu(child)) | |
1710 { | |
1711 Widget temp_w; | |
1712 | |
1713 temp_w = submenu_widget(child); | |
1714 gui_athena_popdown_submenus_action(temp_w,event,args,nargs); | |
1715 XtPopdown(temp_w); | |
1716 } | |
1717 } | |
1718 } | |
1719 | |
1720 /* Used to determine if the given widget has a submenu that can be popped up. */ | |
1721 static Boolean | |
1722 has_submenu(widget) | |
1723 Widget widget; | |
1724 { | |
1725 if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass)) | |
1726 { | |
1727 Pixmap p; | |
1728 | |
1729 XtVaGetValues(widget, XtNrightBitmap, &p, NULL); | |
1730 if ((p != None) && (p != XtUnspecifiedPixmap)) | |
1731 return True; | |
1732 } | |
1733 return False; | |
1734 } | |
1735 | |
1736 static void | |
1737 gui_athena_delayed_arm_action(w, event, args, nargs) | |
1738 Widget w; | |
1739 XEvent *event; | |
1740 String *args; | |
1741 Cardinal *nargs; | |
1742 { | |
1743 Dimension width, height; | |
1744 | |
1745 if (event->type != MotionNotify) | |
1746 return; | |
1747 | |
1748 XtVaGetValues(w, | |
1749 XtNwidth, &width, | |
1750 XtNheight, &height, | |
1751 NULL); | |
1752 | |
1753 if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height) | |
1754 return; | |
1755 | |
1756 { | |
1757 static Widget previous_active_widget = NULL; | |
1758 Widget current; | |
1759 | |
1760 current = XawSimpleMenuGetActiveEntry(w); | |
1761 if (current != previous_active_widget) | |
1762 { | |
1763 if (timer) | |
1764 { | |
1765 /* If the timeout hasn't been triggered, remove it */ | |
1766 XtRemoveTimeOut(timer); | |
1767 } | |
1768 gui_athena_popdown_submenus_action(w,event,args,nargs); | |
1769 if (has_submenu(current)) | |
1770 { | |
1771 XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L, | |
1772 gui_athena_menu_timeout, | |
1773 (XtPointer)current); | |
1774 } | |
1775 previous_active_widget = current; | |
1776 } | |
1777 } | |
1778 } | |
1779 | |
1780 static Widget | |
1781 get_popup_entry(w) | |
1782 Widget w; | |
1783 { | |
1784 Widget menuw; | |
1785 | |
1786 /* Get the active entry for the current menu */ | |
1787 if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0) | |
1788 return NULL; | |
1789 | |
1790 return submenu_widget(menuw); | |
1791 } | |
1792 | |
1793 /* Given the widget that has been determined to have a submenu, return the submenu widget | |
1794 * that is to be popped up. | |
1795 */ | |
1796 static Widget | |
1797 submenu_widget(widget) | |
1798 Widget widget; | |
1799 { | |
1800 /* Precondition: has_submenu(widget) == True | |
1801 * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True | |
1802 */ | |
1803 | |
1804 char_u *pullright_name; | |
1805 Widget popup; | |
1806 | |
1807 pullright_name = make_pull_name((char_u *)XtName(widget)); | |
1808 popup = XtNameToWidget(XtParent(widget), (char *)pullright_name); | |
1809 vim_free(pullright_name); | |
1810 | |
1811 return popup; | |
1812 /* Postcondition: (popup != NULL) implies | |
1813 * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */ | |
1814 } | |
1815 | |
1816 void | |
1817 gui_mch_show_popupmenu(menu) | |
1818 vimmenu_T *menu; | |
1819 { | |
1820 int rootx, rooty, winx, winy; | |
1821 Window root, child; | |
1822 unsigned int mask; | |
1823 | |
1824 if (menu->submenu_id == (Widget)0) | |
1825 return; | |
1826 | |
1827 /* Position the popup menu at the pointer */ | |
1828 if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child, | |
1829 &rootx, &rooty, &winx, &winy, &mask)) | |
1830 { | |
1831 rootx -= 30; | |
1832 if (rootx < 0) | |
1833 rootx = 0; | |
1834 rooty -= 5; | |
1835 if (rooty < 0) | |
1836 rooty = 0; | |
1837 XtVaSetValues(menu->submenu_id, | |
1838 XtNx, rootx, | |
1839 XtNy, rooty, | |
1840 NULL); | |
1841 } | |
1842 | |
1843 XtOverrideTranslations(menu->submenu_id, popupTrans); | |
1844 XtPopupSpringLoaded(menu->submenu_id); | |
1845 } | |
1846 | |
1847 #endif /* FEAT_MENU */ | |
1848 | |
1849 /* | |
1850 * Set the menu and scrollbar colors to their default values. | |
1851 */ | |
1852 void | |
1853 gui_mch_def_colors() | |
1854 { | |
1855 /* | |
1856 * Get the colors ourselves. Using the automatic conversion doesn't | |
1857 * handle looking for approximate colors. | |
1858 */ | |
1859 if (gui.in_use) | |
1860 { | |
1861 gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name); | |
1862 gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name); | |
1863 gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name); | |
1864 gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name); | |
1865 #ifdef FEAT_BEVAL | |
1866 gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name); | |
1867 gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name); | |
1868 #endif | |
1869 } | |
1870 } | |
1871 | |
1872 | |
1873 /* | |
1874 * Scrollbar stuff. | |
1875 */ | |
1876 | |
1877 void | |
1878 gui_mch_set_scrollbar_thumb(sb, val, size, max) | |
1879 scrollbar_T *sb; | |
1880 long val; | |
1881 long size; | |
1882 long max; | |
1883 { | |
1884 double v, s; | |
1885 | |
1886 if (sb->id == (Widget)0) | |
1887 return; | |
1888 | |
1889 /* | |
1890 * Athena scrollbar must go from 0.0 to 1.0. | |
1891 */ | |
1892 if (max == 0) | |
1893 { | |
1894 /* So you can't scroll it at all (normally it scrolls past end) */ | |
1895 #ifdef FEAT_GUI_NEXTAW | |
1896 XawScrollbarSetThumb(sb->id, 0.0, 1.0); | |
1897 #else | |
1898 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0); | |
1899 #endif | |
1900 } | |
1901 else | |
1902 { | |
1903 v = (double)val / (double)(max + 1); | |
1904 s = (double)size / (double)(max + 1); | |
1905 #ifdef FEAT_GUI_NEXTAW | |
1906 XawScrollbarSetThumb(sb->id, v, s); | |
1907 #else | |
1908 vim_XawScrollbarSetThumb(sb->id, v, s, 1.0); | |
1909 #endif | |
1910 } | |
1911 } | |
1912 | |
1913 void | |
1914 gui_mch_set_scrollbar_pos(sb, x, y, w, h) | |
1915 scrollbar_T *sb; | |
1916 int x; | |
1917 int y; | |
1918 int w; | |
1919 int h; | |
1920 { | |
1921 if (sb->id == (Widget)0) | |
1922 return; | |
1923 | |
1924 XtUnmanageChild(sb->id); | |
1925 XtVaSetValues(sb->id, | |
1926 XtNhorizDistance, x, | |
1927 XtNvertDistance, y, | |
1928 XtNwidth, w, | |
1929 XtNheight, h, | |
1930 NULL); | |
1931 XtManageChild(sb->id); | |
1932 } | |
1933 | |
1934 void | |
1935 gui_mch_enable_scrollbar(sb, flag) | |
1936 scrollbar_T *sb; | |
1937 int flag; | |
1938 { | |
1939 if (sb->id != (Widget)0) | |
1940 { | |
1941 if (flag) | |
1942 XtManageChild(sb->id); | |
1943 else | |
1944 XtUnmanageChild(sb->id); | |
1945 } | |
1946 } | |
1947 | |
1948 void | |
1949 gui_mch_create_scrollbar(sb, orient) | |
1950 scrollbar_T *sb; | |
1951 int orient; /* SBAR_VERT or SBAR_HORIZ */ | |
1952 { | |
1953 sb->id = XtVaCreateWidget("scrollBar", | |
1954 #ifdef FEAT_GUI_NEXTAW | |
1955 scrollbarWidgetClass, vimForm, | |
1956 #else | |
1957 vim_scrollbarWidgetClass, vimForm, | |
1958 #endif | |
1959 XtNresizable, True, | |
1960 XtNtop, XtChainTop, | |
1961 XtNbottom, XtChainTop, | |
1962 XtNleft, XtChainLeft, | |
1963 XtNright, XtChainLeft, | |
1964 XtNborderWidth, 0, | |
1965 XtNorientation, (orient == SBAR_VERT) ? XtorientVertical | |
1966 : XtorientHorizontal, | |
1967 XtNforeground, gui.scroll_fg_pixel, | |
1968 XtNbackground, gui.scroll_bg_pixel, | |
1969 NULL); | |
1970 if (sb->id == (Widget)0) | |
1971 return; | |
1972 | |
1973 XtAddCallback(sb->id, XtNjumpProc, | |
1974 gui_athena_scroll_cb_jump, (XtPointer)sb->ident); | |
1975 XtAddCallback(sb->id, XtNscrollProc, | |
1976 gui_athena_scroll_cb_scroll, (XtPointer)sb->ident); | |
1977 | |
1978 #ifdef FEAT_GUI_NEXTAW | |
1979 XawScrollbarSetThumb(sb->id, 0.0, 1.0); | |
1980 #else | |
1981 vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0); | |
1982 #endif | |
1983 } | |
1984 | |
1985 #if defined(FEAT_WINDOWS) || defined(PROTO) | |
1986 void | |
1987 gui_mch_destroy_scrollbar(sb) | |
1988 scrollbar_T *sb; | |
1989 { | |
1990 if (sb->id != (Widget)0) | |
1991 XtDestroyWidget(sb->id); | |
1992 } | |
1993 #endif | |
1994 | |
1995 void | |
1996 gui_mch_set_scrollbar_colors(sb) | |
1997 scrollbar_T *sb; | |
1998 { | |
1999 if (sb->id != (Widget)0) | |
2000 XtVaSetValues(sb->id, | |
2001 XtNforeground, gui.scroll_fg_pixel, | |
2002 XtNbackground, gui.scroll_bg_pixel, | |
2003 NULL); | |
2004 | |
2005 /* This is needed for the rectangle below the vertical scrollbars. */ | |
2006 if (sb == &gui.bottom_sbar && vimForm != (Widget)0) | |
2007 gui_athena_scroll_colors(vimForm); | |
2008 } | |
2009 | |
2010 /* | |
2011 * Miscellaneous stuff: | |
2012 */ | |
2013 Window | |
2014 gui_x11_get_wid() | |
2015 { | |
2016 return XtWindow(textArea); | |
2017 } | |
2018 | |
2019 #if defined(FEAT_BROWSE) || defined(PROTO) | |
2020 /* | |
2021 * Put up a file requester. | |
2022 * Returns the selected name in allocated memory, or NULL for Cancel. | |
2023 */ | |
2024 char_u * | |
2025 gui_mch_browse(saving, title, dflt, ext, initdir, filter) | |
1887 | 2026 int saving UNUSED; /* select file to write */ |
2027 char_u *title; /* title for the window */ | |
2028 char_u *dflt; /* default name */ | |
2029 char_u *ext UNUSED; /* extension added */ | |
7 | 2030 char_u *initdir; /* initial directory, NULL for current dir */ |
1887 | 2031 char_u *filter UNUSED; /* file name filter */ |
7 | 2032 { |
2033 Position x, y; | |
2034 char_u dirbuf[MAXPATHL]; | |
2035 | |
2036 /* Concatenate "initdir" and "dflt". */ | |
2037 if (initdir == NULL || *initdir == NUL) | |
2038 mch_dirname(dirbuf, MAXPATHL); | |
2039 else if (STRLEN(initdir) + 2 < MAXPATHL) | |
2040 STRCPY(dirbuf, initdir); | |
2041 else | |
2042 dirbuf[0] = NUL; | |
2043 if (dflt != NULL && *dflt != NUL | |
2044 && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL) | |
2045 { | |
2046 add_pathsep(dirbuf); | |
2047 STRCAT(dirbuf, dflt); | |
2048 } | |
2049 | |
2050 /* Position the file selector just below the menubar */ | |
2051 XtTranslateCoords(vimShell, (Position)0, (Position) | |
2052 #ifdef FEAT_MENU | |
2053 gui.menu_height | |
2054 #else | |
2055 0 | |
2056 #endif | |
2057 , &x, &y); | |
2058 return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf, | |
2059 NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel, | |
2060 gui.scroll_fg_pixel, gui.scroll_bg_pixel); | |
2061 } | |
2062 #endif | |
2063 | |
2064 #if defined(FEAT_GUI_DIALOG) || defined(PROTO) | |
2065 | |
2066 static int dialogStatus; | |
2067 static Atom dialogatom; | |
2068 | |
7801
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
2069 static void keyhit_callback(Widget w, XtPointer client_data, XEvent *event, Boolean *cont); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
2070 static void butproc(Widget w, XtPointer client_data, XtPointer call_data); |
a1e71a01dbd6
commit https://github.com/vim/vim/commit/d25c16e2f2776d50245bf31d6e4d5364f12d188e
Christian Brabandt <cb@256bit.org>
parents:
4352
diff
changeset
|
2071 static void dialog_wm_handler(Widget w, XtPointer client_data, XEvent *event, Boolean *dum); |
7 | 2072 |
2073 /* | |
2074 * Callback function for the textfield. When CR is hit this works like | |
2075 * hitting the "OK" button, ESC like "Cancel". | |
2076 */ | |
2077 static void | |
2078 keyhit_callback(w, client_data, event, cont) | |
1887 | 2079 Widget w UNUSED; |
2080 XtPointer client_data UNUSED; | |
7 | 2081 XEvent *event; |
1887 | 2082 Boolean *cont UNUSED; |
7 | 2083 { |
2084 char buf[2]; | |
2085 | |
2086 if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1) | |
2087 { | |
2088 if (*buf == CAR) | |
2089 dialogStatus = 1; | |
2090 else if (*buf == ESC) | |
2091 dialogStatus = 0; | |
2092 } | |
2093 } | |
2094 | |
2095 static void | |
2096 butproc(w, client_data, call_data) | |
1887 | 2097 Widget w UNUSED; |
7 | 2098 XtPointer client_data; |
1887 | 2099 XtPointer call_data UNUSED; |
7 | 2100 { |
2101 dialogStatus = (int)(long)client_data + 1; | |
2102 } | |
2103 | |
2104 /* | |
2105 * Function called when dialog window closed. | |
2106 */ | |
2107 static void | |
2108 dialog_wm_handler(w, client_data, event, dum) | |
1887 | 2109 Widget w UNUSED; |
2110 XtPointer client_data UNUSED; | |
7 | 2111 XEvent *event; |
1887 | 2112 Boolean *dum UNUSED; |
7 | 2113 { |
2114 if (event->type == ClientMessage | |
1887 | 2115 && (Atom)((XClientMessageEvent *)event)->data.l[0] == dialogatom) |
7 | 2116 dialogStatus = 0; |
2117 } | |
2118 | |
2119 int | |
2684 | 2120 gui_mch_dialog(type, title, message, buttons, dfltbutton, textfield, ex_cmd) |
1887 | 2121 int type UNUSED; |
7 | 2122 char_u *title; |
2123 char_u *message; | |
2124 char_u *buttons; | |
1887 | 2125 int dfltbutton UNUSED; |
7 | 2126 char_u *textfield; |
2684 | 2127 int ex_cmd UNUSED; |
7 | 2128 { |
2129 char_u *buts; | |
2130 char_u *p, *next; | |
2131 XtAppContext app; | |
2132 XEvent event; | |
2133 Position wd, hd; | |
2134 Position wv, hv; | |
2135 Position x, y; | |
2136 Widget dialog; | |
2137 Widget dialogshell; | |
2138 Widget dialogmessage; | |
2139 Widget dialogtextfield = 0; | |
2140 Widget dialogButton; | |
2141 Widget prev_dialogButton = NULL; | |
2142 int butcount; | |
2143 int vertical; | |
2144 | |
2145 if (title == NULL) | |
2146 title = (char_u *)_("Vim dialog"); | |
2147 dialogStatus = -1; | |
2148 | |
2149 /* if our pointer is currently hidden, then we should show it. */ | |
2150 gui_mch_mousehide(FALSE); | |
2151 | |
2152 /* Check 'v' flag in 'guioptions': vertical button placement. */ | |
2153 vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); | |
2154 | |
2155 /* The shell is created each time, to make sure it is resized properly */ | |
2156 dialogshell = XtVaCreatePopupShell("dialogShell", | |
2157 transientShellWidgetClass, vimShell, | |
2158 XtNtitle, title, | |
2159 NULL); | |
2160 if (dialogshell == (Widget)0) | |
2161 goto error; | |
2162 | |
2163 dialog = XtVaCreateManagedWidget("dialog", | |
2164 formWidgetClass, dialogshell, | |
2165 XtNdefaultDistance, 20, | |
2166 NULL); | |
2167 if (dialog == (Widget)0) | |
2168 goto error; | |
2169 gui_athena_menu_colors(dialog); | |
2170 dialogmessage = XtVaCreateManagedWidget("dialogMessage", | |
2171 labelWidgetClass, dialog, | |
2172 XtNlabel, message, | |
2173 XtNtop, XtChainTop, | |
2174 XtNbottom, XtChainTop, | |
2175 XtNleft, XtChainLeft, | |
2176 XtNright, XtChainLeft, | |
2177 XtNresizable, True, | |
2178 XtNborderWidth, 0, | |
2179 NULL); | |
2180 gui_athena_menu_colors(dialogmessage); | |
2181 | |
2182 if (textfield != NULL) | |
2183 { | |
2184 dialogtextfield = XtVaCreateManagedWidget("textfield", | |
2185 asciiTextWidgetClass, dialog, | |
2186 XtNwidth, 400, | |
2187 XtNtop, XtChainTop, | |
2188 XtNbottom, XtChainTop, | |
2189 XtNleft, XtChainLeft, | |
2190 XtNright, XtChainRight, | |
2191 XtNfromVert, dialogmessage, | |
2192 XtNresizable, True, | |
2193 XtNstring, textfield, | |
2194 XtNlength, IOSIZE, | |
2195 XtNuseStringInPlace, True, | |
2196 XtNeditType, XawtextEdit, | |
2197 XtNwrap, XawtextWrapNever, | |
2198 XtNresize, XawtextResizeHeight, | |
2199 NULL); | |
2200 XtManageChild(dialogtextfield); | |
2201 XtAddEventHandler(dialogtextfield, KeyPressMask, False, | |
2202 (XtEventHandler)keyhit_callback, (XtPointer)NULL); | |
2203 XawTextSetInsertionPoint(dialogtextfield, | |
2204 (XawTextPosition)STRLEN(textfield)); | |
2205 XtSetKeyboardFocus(dialog, dialogtextfield); | |
2206 } | |
2207 | |
2208 /* make a copy, so that we can insert NULs */ | |
2209 buts = vim_strsave(buttons); | |
2210 if (buts == NULL) | |
2211 return -1; | |
2212 | |
2213 p = buts; | |
2214 for (butcount = 0; *p; ++butcount) | |
2215 { | |
2216 for (next = p; *next; ++next) | |
2217 { | |
2218 if (*next == DLG_HOTKEY_CHAR) | |
1620 | 2219 STRMOVE(next, next + 1); |
7 | 2220 if (*next == DLG_BUTTON_SEP) |
2221 { | |
2222 *next++ = NUL; | |
2223 break; | |
2224 } | |
2225 } | |
2226 dialogButton = XtVaCreateManagedWidget("button", | |
2227 commandWidgetClass, dialog, | |
2228 XtNlabel, p, | |
2229 XtNtop, XtChainBottom, | |
2230 XtNbottom, XtChainBottom, | |
2231 XtNleft, XtChainLeft, | |
2232 XtNright, XtChainLeft, | |
2233 XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield, | |
2234 XtNvertDistance, vertical ? 4 : 20, | |
2235 XtNresizable, False, | |
2236 NULL); | |
2237 gui_athena_menu_colors(dialogButton); | |
2238 if (butcount > 0) | |
2239 XtVaSetValues(dialogButton, | |
2240 vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton, | |
2241 NULL); | |
2242 | |
2255 | 2243 XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)(long_u)butcount); |
7 | 2244 p = next; |
2245 prev_dialogButton = dialogButton; | |
2246 } | |
2247 vim_free(buts); | |
2248 | |
2249 XtRealizeWidget(dialogshell); | |
2250 | |
2251 /* Setup for catching the close-window event, don't let it close Vim! */ | |
2252 dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False); | |
2253 XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1); | |
2254 XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL); | |
2255 | |
2256 XtVaGetValues(dialogshell, | |
2257 XtNwidth, &wd, | |
2258 XtNheight, &hd, | |
2259 NULL); | |
2260 XtVaGetValues(vimShell, | |
2261 XtNwidth, &wv, | |
2262 XtNheight, &hv, | |
2263 NULL); | |
2264 XtTranslateCoords(vimShell, | |
2265 (Position)((wv - wd) / 2), | |
2266 (Position)((hv - hd) / 2), | |
2267 &x, &y); | |
2268 if (x < 0) | |
2269 x = 0; | |
2270 if (y < 0) | |
2271 y = 0; | |
2272 XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL); | |
2273 | |
2274 /* Position the mouse pointer in the dialog, required for when focus | |
2275 * follows mouse. */ | |
2276 XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40); | |
2277 | |
2278 | |
2279 app = XtWidgetToApplicationContext(dialogshell); | |
2280 | |
2281 XtPopup(dialogshell, XtGrabNonexclusive); | |
2282 | |
405 | 2283 for (;;) |
7 | 2284 { |
2285 XtAppNextEvent(app, &event); | |
2286 XtDispatchEvent(&event); | |
2287 if (dialogStatus >= 0) | |
2288 break; | |
2289 } | |
2290 | |
2291 XtPopdown(dialogshell); | |
2292 | |
2293 if (textfield != NULL && dialogStatus < 0) | |
2294 *textfield = NUL; | |
2295 | |
2296 error: | |
2297 XtDestroyWidget(dialogshell); | |
2298 | |
2299 return dialogStatus; | |
2300 } | |
2301 #endif | |
2302 | |
2303 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU) | |
2304 /* | |
2305 * Set the colors of Widget "id" to the menu colors. | |
2306 */ | |
2307 static void | |
2308 gui_athena_menu_colors(id) | |
2309 Widget id; | |
2310 { | |
2311 if (gui.menu_bg_pixel != INVALCOLOR) | |
2312 XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL); | |
2313 if (gui.menu_fg_pixel != INVALCOLOR) | |
2314 XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL); | |
2315 } | |
2316 #endif | |
2317 | |
2318 /* | |
2319 * Set the colors of Widget "id" to the scroll colors. | |
2320 */ | |
2321 static void | |
2322 gui_athena_scroll_colors(id) | |
2323 Widget id; | |
2324 { | |
2325 if (gui.scroll_bg_pixel != INVALCOLOR) | |
2326 XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL); | |
2327 if (gui.scroll_fg_pixel != INVALCOLOR) | |
2328 XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL); | |
2329 } |