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