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