1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI/Motif support by Robert Webb
5 * Athena port by Bill Foster
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.
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>
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 */
38 #ifndef FEAT_GUI_NEXTAW
39 # include "gui_at_sb.h"
42 extern Widget vimShell
;
44 static Widget vimForm
= (Widget
)0;
45 Widget textArea
= (Widget
)0;
47 static Widget menuBar
= (Widget
)0;
48 static XtIntervalId timer
= 0; /* 0 = expired, otherwise active */
50 /* Used to figure out menu ordering */
51 static vimmenu_T
*a_cur_menu
= NULL
;
52 static Cardinal athena_calculate_ins_pos
__ARGS((Widget
));
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
*,
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
}
68 static void gui_mch_reset_focus
__ARGS((void));
69 static Widget toolBar
= (Widget
)0;
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
));
77 static void gui_athena_scroll_colors
__ARGS((Widget id
));
80 static XtTranslations popupTrans
, parentTrans
, menuTrans
, supermenuTrans
;
81 static Pixmap pullerBitmap
= None
;
82 static int puller_width
= 0;
86 * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
87 * left or middle mouse button.
91 gui_athena_scroll_cb_jump(w
, client_data
, call_data
)
93 XtPointer client_data
, call_data
;
95 scrollbar_T
*sb
, *sb_info
;
98 sb
= gui_find_scrollbar((long)client_data
);
102 else if (sb
->wp
!= NULL
) /* Left or right scrollbar */
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().
109 sb_info
= &sb
->wp
->w_scrollbars
[0];
111 else /* Bottom scrollbar */
114 value
= (long)(*((float *)call_data
) * (float)(sb_info
->max
+ 1) + 0.001);
115 if (value
> sb_info
->max
)
116 value
= sb_info
->max
;
118 gui_drag_scrollbar(sb
, value
, TRUE
);
122 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
123 * right mouse buttons.
127 gui_athena_scroll_cb_scroll(w
, client_data
, call_data
)
129 XtPointer client_data
, call_data
;
131 scrollbar_T
*sb
, *sb_info
;
133 int data
= (int)(long)call_data
;
136 sb
= gui_find_scrollbar((long)client_data
);
140 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
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().
147 sb_info
= &sb
->wp
->w_scrollbars
[0];
149 if (sb_info
->size
> 5)
150 page
= sb_info
->size
- 2; /* use two lines of context */
152 page
= sb_info
->size
;
153 #ifdef FEAT_GUI_NEXTAW
156 data
= (data
- gui
.char_height
+ 1) / gui
.char_height
;
157 if (data
> -sb_info
->size
)
164 data
= (data
+ gui
.char_height
- 1) / gui
.char_height
;
165 if (data
< sb_info
->size
)
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;
183 else /* Bottom scrollbar */
186 #ifdef FEAT_GUI_NEXTAW
189 data
= (data
- gui
.char_width
+ 1) / gui
.char_width
;
190 if (data
> -sb
->size
)
195 data
= (data
+ gui
.char_width
- 1) / gui
.char_width
;
200 if (data
< -1) /* page-width left */
203 data
= -(sb
->size
- 5);
207 else if (data
> 1) /* page-width right */
210 data
= (sb
->size
- 5);
216 value
= sb_info
->value
+ data
;
217 if (value
> sb_info
->max
)
218 value
= sb_info
->max
;
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
);
226 gui_drag_scrollbar(sb
, value
, FALSE
);
230 * Create all the Athena widgets necessary.
233 gui_x11_create_widgets()
236 * We don't have any borders handled internally by the textArea to worry
237 * about so only skip over the configured border width.
239 gui
.border_offset
= gui
.border_width
;
241 #if 0 /* not needed? */
242 XtInitializeWidgetClass(formWidgetClass
);
243 XtInitializeWidgetClass(boxWidgetClass
);
244 XtInitializeWidgetClass(coreWidgetClass
);
246 XtInitializeWidgetClass(menuButtonWidgetClass
);
248 XtInitializeWidgetClass(simpleMenuWidgetClass
);
249 #ifdef FEAT_GUI_NEXTAW
250 XtInitializeWidgetClass(scrollbarWidgetClass
);
252 XtInitializeWidgetClass(vim_scrollbarWidgetClass
);
256 /* The form containing all the other widgets */
257 vimForm
= XtVaCreateManagedWidget("vimForm",
258 formWidgetClass
, vimShell
,
261 gui_athena_scroll_colors(vimForm
);
264 /* The top menu bar */
265 menuBar
= XtVaCreateManagedWidget("menuBar",
266 boxWidgetClass
, vimForm
,
269 XtNbottom
, XtChainTop
,
270 XtNleft
, XtChainLeft
,
271 XtNright
, XtChainRight
,
272 XtNinsertPosition
, athena_calculate_ins_pos
,
274 gui_athena_menu_colors(menuBar
);
275 if (gui
.menu_fg_pixel
!= INVALCOLOR
)
276 XtVaSetValues(menuBar
, XtNborderColor
, gui
.menu_fg_pixel
, NULL
);
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
,
286 XtNbottom
, XtChainTop
,
287 XtNleft
, XtChainLeft
,
288 XtNright
, XtChainRight
,
289 XtNorientation
, XtorientHorizontal
,
292 XtNinsertPosition
, athena_calculate_ins_pos
,
294 gui_athena_menu_colors(toolBar
);
298 textArea
= XtVaCreateManagedWidget("textArea",
299 coreWidgetClass
, vimForm
,
302 XtNbottom
, XtChainTop
,
303 XtNleft
, XtChainLeft
,
304 XtNright
, XtChainLeft
,
305 XtNbackground
, gui
.back_pixel
,
310 * Install the callbacks.
312 gui_x11_callbacks(textArea
, vimForm
);
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()");
332 XtAppAddActions(XtWidgetToApplicationContext(vimForm
), pullAction
,
333 XtNumber(pullAction
));
336 /* Pretend we don't have input focus, we will get an event if we do. */
337 gui
.in_focus
= FALSE
;
342 * Calculates the Pixmap based on the size of the current menu font.
345 gui_athena_create_pullright_pixmap(w
)
349 #ifdef FONTSET_ALWAYS
350 XFontSet font
= None
;
352 XFontStruct
*font
= NULL
;
355 #ifdef FONTSET_ALWAYS
356 if (gui
.menu_fontset
== NOFONTSET
)
358 if (gui
.menu_font
== NOFONT
)
363 Cardinal num_children
;
365 #ifdef FONTSET_ALWAYS
366 from
.size
= strlen(from
.addr
= XtDefaultFontSet
);
367 to
.addr
= (XtPointer
)&font
;
368 to
.size
= sizeof(XFontSet
);
370 from
.size
= strlen(from
.addr
= XtDefaultFont
);
371 to
.addr
= (XtPointer
)&font
;
372 to
.size
= sizeof(XFontStruct
*);
374 /* Assumption: The menuBar children will use the same font as the
375 * pulldown menu items AND they will all be of type
378 XtVaGetValues(menuBar
, XtNchildren
, &children
,
379 XtNnumChildren
, &num_children
,
381 if (XtConvertAndStore(w
? w
:
382 (num_children
> 0) ? children
[0] : menuBar
,
384 #ifdef FONTSET_ALWAYS
391 /* "font" should now contain data */
394 #ifdef FONTSET_ALWAYS
395 font
= (XFontSet
)gui
.menu_fontset
;
397 font
= (XFontStruct
*)gui
.menu_font
;
402 GC draw_gc
, undraw_gc
;
406 #ifdef FONTSET_ALWAYS
407 height
= fontset_height2(font
);
409 height
= font
->max_bounds
.ascent
+ font
->max_bounds
.descent
;
412 puller_width
= width
+ 4;
413 retval
= XCreatePixmap(gui
.dpy
,DefaultRootWindow(gui
.dpy
),width
,
415 gc_values
.foreground
= 1;
416 gc_values
.background
= 0;
417 draw_gc
= XCreateGC(gui
.dpy
, retval
,
418 GCForeground
| GCBackground
,
420 gc_values
.foreground
= 0;
421 gc_values
.background
= 1;
422 undraw_gc
= XCreateGC(gui
.dpy
, retval
,
423 GCForeground
| GCBackground
,
427 points
[1].x
= width
- 1;
428 points
[1].y
= (height
- 1) / 2;
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
);
442 * Called when the GUI is not going to start after all.
445 gui_x11_destroy_widgets()
456 #if defined(FEAT_TOOLBAR) || defined(PROTO)
457 # include "gui_x11_pm.h"
458 # ifdef HAVE_X11_XPM_H
459 # include <X11/xpm.h>
462 static void createXpmImages
__ARGS((char_u
*path
, char **xpm
, Pixmap
*sen
));
463 static void get_toolbar_pixmap
__ARGS((vimmenu_T
*menu
, Pixmap
*sen
));
466 * Allocated a pixmap for toolbar menu "menu".
470 get_toolbar_pixmap(menu
, sen
)
474 char_u buf
[MAXPATHL
]; /* buffer storing expanded pathname */
475 char **xpm
= NULL
; /* xpm array */
477 buf
[0] = NUL
; /* start with NULL path */
479 if (menu
->iconfile
!= NULL
)
481 /* Use the "icon=" argument. */
482 gui_find_iconfile(menu
->iconfile
, buf
, "xpm");
483 createXpmImages(buf
, NULL
, sen
);
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)
492 if (menu
->icon_builtin
|| gui_find_bitmap(menu
->name
, buf
, "xpm") == FAIL
)
494 if (menu
->iconidx
>= 0 && menu
->iconidx
495 < (sizeof(built_in_pixmaps
) / sizeof(built_in_pixmaps
[0])))
496 xpm
= built_in_pixmaps
[menu
->iconidx
];
501 if (xpm
!= NULL
|| buf
[0] != NUL
)
502 createXpmImages(buf
, xpm
, sen
);
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.
512 createXpmImages(path
, xpm
, sen
)
519 XpmColorSymbol color
[5] =
522 {"iconColor1", NULL
, 0},
523 {"bottomShadowColor", NULL
, 0},
524 {"topShadowColor", NULL
, 0},
525 {"selectColor", NULL
, 0}
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
);
539 /* Setup the color subsititution table */
540 attrs
.valuemask
= XpmColorSymbols
;
541 attrs
.colorsymbols
= color
;
542 attrs
.numsymbols
= 5;
544 screenNum
= DefaultScreen(gui
.dpy
);
545 rootWindow
= RootWindow(gui
.dpy
, screenNum
);
547 /* Create the "sensitive" pixmap */
549 status
= XpmCreatePixmapFromData(gui
.dpy
, rootWindow
, xpm
,
550 &map
, &mask
, &attrs
);
552 status
= XpmReadFileToPixmap(gui
.dpy
, rootWindow
, (char *)path
,
553 &map
, &mask
, &attrs
);
554 if (status
== XpmSuccess
&& map
!= 0)
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
);
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);
575 XFreeGC(gui
.dpy
, back_gc
);
576 XFreeGC(gui
.dpy
, mask_gc
);
577 XFreePixmap(gui
.dpy
, map
);
582 XpmFreeAttributes(&attrs
);
586 gui_mch_set_toolbar_pos(x
, y
, w
, h
)
595 if (!XtIsManaged(toolBar
)) /* nothing to do */
597 XtUnmanageChild(toolBar
);
598 XtVaGetValues(toolBar
,
599 XtNborderWidth
, &border
,
601 height
= h
- 2 * border
;
604 XtVaSetValues(toolBar
,
607 XtNwidth
, w
- 2 * border
,
610 XtManageChild(toolBar
);
615 gui_mch_set_text_area_pos(x
, y
, w
, h
)
621 XtUnmanageChild(textArea
);
622 XtVaSetValues(textArea
,
628 XtManageChild(textArea
);
630 /* Give keyboard focus to the textArea instead of the toolbar. */
631 gui_mch_reset_focus();
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
642 gui_mch_reset_focus()
644 XtSetKeyboardFocus(vimForm
, textArea
);
650 gui_x11_set_back_color()
652 if (textArea
!= NULL
)
653 XtVaSetValues(textArea
,
654 XtNbackground
, gui
.back_pixel
,
658 #if defined(FEAT_MENU) || defined(PROTO)
663 static char_u
*make_pull_name
__ARGS((char_u
* name
));
664 static Widget get_popup_entry
__ARGS((Widget w
));
665 static Widget submenu_widget
__ARGS((Widget
));
666 static Boolean has_submenu
__ARGS((Widget
));
667 static void gui_mch_submenu_change
__ARGS((vimmenu_T
*mp
, int colors
));
668 static void gui_athena_menu_font
__ARGS((Widget id
));
669 static Boolean gui_athena_menu_has_submenus
__ARGS((Widget
, Widget
));
672 gui_mch_enable_menu(flag
)
677 XtManageChild(menuBar
);
679 if (XtIsManaged(toolBar
))
681 XtVaSetValues(toolBar
,
682 XtNvertDistance
, gui
.menu_height
,
684 XtVaSetValues(textArea
,
685 XtNvertDistance
, gui
.menu_height
+ gui
.toolbar_height
,
692 XtUnmanageChild(menuBar
);
694 if (XtIsManaged(toolBar
))
696 XtVaSetValues(toolBar
,
705 gui_mch_set_menu_pos(x
, y
, w
, h
)
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
;
720 XtVaSetValues(menuBar
,
723 XtNwidth
, w
- 2 * border
,
726 XtManageChild(menuBar
);
730 * Used to calculate the insertion position of a widget with respect to its
733 * Valid range of return values is: 0 (beginning of children) to
734 * numChildren (end of children).
737 athena_calculate_ins_pos(widget
)
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".
743 * This holds true for popup menus, toolbar, and toplevel menu items.
746 /* Popup menus: "id" is NULL. Only submenu_id is valid */
748 /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
749 * "submenu_id" will be non-NULL.
752 /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
755 Cardinal num_children
= 0;
761 XtSetArg(args
[n
], XtNchildren
, &children
); n
++;
762 XtSetArg(args
[n
], XtNnumChildren
, &num_children
); n
++;
763 XtGetValues(XtParent(widget
), args
, n
);
765 retval
= num_children
;
766 for (i
= 0; i
< num_children
; ++i
)
768 Widget current
= children
[i
];
769 vimmenu_T
*menu
= NULL
;
771 for (menu
= (a_cur_menu
->parent
== NULL
)
772 ? root_menu
: a_cur_menu
->parent
->children
;
775 if (current
== menu
->id
776 && a_cur_menu
->priority
< menu
->priority
785 gui_mch_add_menu(menu
, idx
)
789 char_u
*pullright_name
;
790 Dimension height
, space
, border
;
791 vimmenu_T
*parent
= menu
->parent
;
796 if (menu_is_popup(menu
->dname
))
798 menu
->submenu_id
= XtVaCreatePopupShell((char *)menu
->dname
,
799 simpleMenuWidgetClass
, vimShell
,
800 XtNinsertPosition
, athena_calculate_ins_pos
,
801 XtNtranslations
, popupTrans
,
803 gui_athena_menu_colors(menu
->submenu_id
);
805 else if (menu_is_menubar(menu
->dname
))
807 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
808 menuButtonWidgetClass
, menuBar
,
809 XtNmenuName
, menu
->dname
,
810 #ifdef FONTSET_ALWAYS
811 XtNinternational
, True
,
814 if (menu
->id
== (Widget
)0)
816 gui_athena_menu_colors(menu
->id
);
817 gui_athena_menu_font(menu
->id
);
819 menu
->submenu_id
= XtVaCreatePopupShell((char *)menu
->dname
,
820 simpleMenuWidgetClass
, menu
->id
,
821 XtNinsertPosition
, athena_calculate_ins_pos
,
822 XtNtranslations
, supermenuTrans
,
824 gui_athena_menu_colors(menu
->submenu_id
);
825 gui_athena_menu_font(menu
->submenu_id
);
827 /* Don't update the menu height when it was set at a fixed value */
828 if (!gui
.menu_height_fixed
)
831 * When we add a top-level item to the menu bar, we can figure
832 * out how high the menu bar should be.
834 XtVaGetValues(menuBar
,
836 XtNborderWidth
, &border
,
838 XtVaGetValues(menu
->id
,
841 gui
.menu_height
= height
+ 2 * (space
+ border
);
845 else if (parent
->submenu_id
!= (Widget
)0)
847 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
848 smeBSBObjectClass
, parent
->submenu_id
,
849 XtNlabel
, menu
->dname
,
850 #ifdef FONTSET_ALWAYS
851 XtNinternational
, True
,
854 if (menu
->id
== (Widget
)0)
856 if (pullerBitmap
== None
)
857 pullerBitmap
= gui_athena_create_pullright_pixmap(menu
->id
);
859 XtVaSetValues(menu
->id
, XtNrightBitmap
, pullerBitmap
,
861 /* If there are other menu items that are not pulldown menus,
862 * we need to adjust the right margins of those, too.
866 Cardinal num_children
;
869 XtVaGetValues(parent
->submenu_id
, XtNchildren
, &children
,
870 XtNnumChildren
, &num_children
,
872 for (i
= 0; i
< num_children
; ++i
)
874 XtVaSetValues(children
[i
],
875 XtNrightMargin
, puller_width
,
879 gui_athena_menu_colors(menu
->id
);
880 gui_athena_menu_font(menu
->id
);
882 pullright_name
= make_pull_name(menu
->dname
);
883 menu
->submenu_id
= XtVaCreatePopupShell((char *)pullright_name
,
884 simpleMenuWidgetClass
, parent
->submenu_id
,
885 XtNtranslations
, menuTrans
,
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
);
893 if (parent
->parent
!= NULL
)
894 XtOverrideTranslations(parent
->submenu_id
, parentTrans
);
899 /* Used to determine whether a SimpleMenu has pulldown entries.
901 * "id" is the parent of the menu items.
902 * Ignore widget "ignore" in the pane.
905 gui_athena_menu_has_submenus(id
, ignore
)
910 Cardinal num_children
;
913 XtVaGetValues(id
, XtNchildren
, &children
,
914 XtNnumChildren
, &num_children
,
916 for (i
= 0; i
< num_children
; ++i
)
918 if (children
[i
] == ignore
)
920 if (has_submenu(children
[i
]))
927 gui_athena_menu_font(id
)
930 #ifdef FONTSET_ALWAYS
931 if (gui
.menu_fontset
!= NOFONTSET
)
936 XtVaSetValues(id
, XtNfontSet
, gui
.menu_fontset
, NULL
);
937 /* We should force the widget to recalculate it's
942 XtVaSetValues(id
, XtNfontSet
, gui
.menu_fontset
, NULL
);
944 XtVaSetValues(id
, XtNrightBitmap
, pullerBitmap
, NULL
);
949 if (gui
.menu_font
!= NOFONT
)
957 # ifdef FEAT_XFONTSET
958 if (gui
.fontset
!= NOFONTSET
)
959 XtVaSetValues(id
, XtNfontSet
, gui
.menu_font
, NULL
);
962 XtVaSetValues(id
, XtNfont
, gui
.menu_font
, NULL
);
964 XtVaSetValues(id
, XtNrightBitmap
, pullerBitmap
, NULL
);
966 /* Force the widget to recalculate it's geometry now. */
975 gui_mch_new_menu_font()
977 Pixmap oldpuller
= None
;
979 if (menuBar
== (Widget
)0)
982 if (pullerBitmap
!= None
)
984 oldpuller
= pullerBitmap
;
985 pullerBitmap
= gui_athena_create_pullright_pixmap(NULL
);
987 gui_mch_submenu_change(root_menu
, FALSE
);
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
995 int max_height
= 9999;
997 for (mp
= root_menu
; mp
!= NULL
; mp
= mp
->next
)
999 if (menu_is_menubar(mp
->dname
))
1003 XtVaGetValues(mp
->id
,
1006 if (height
< max_height
)
1007 max_height
= height
;
1010 if (max_height
!= 9999)
1012 /* Don't update the menu height when it was set at a fixed value */
1013 if (!gui
.menu_height_fixed
)
1015 Dimension space
, border
;
1017 XtVaGetValues(menuBar
,
1019 XtNborderWidth
, &border
,
1021 gui
.menu_height
= max_height
+ 2 * (space
+ border
);
1025 /* Now, to simulate the window being resized. Only, this
1026 * will resize the window to it's current state.
1028 * There has to be a better way, but I do not see one at this time.
1034 XtVaGetValues(vimShell
,
1038 gui_resize_shell(w
, h
1040 - xim_get_status_area_height()
1044 gui_set_shellsize(FALSE
, TRUE
, RESIZE_VERT
);
1046 if (oldpuller
!= None
)
1047 XFreePixmap(gui
.dpy
, oldpuller
);
1050 #if defined(FEAT_BEVAL) || defined(PROTO)
1052 gui_mch_new_tooltip_font()
1054 # ifdef FEAT_TOOLBAR
1057 if (toolBar
== (Widget
)0)
1060 menu
= gui_find_menu((char_u
*)"ToolBar");
1062 gui_mch_submenu_change(menu
, FALSE
);
1067 gui_mch_new_tooltip_colors()
1069 # ifdef FEAT_TOOLBAR
1072 if (toolBar
== (Widget
)0)
1075 menu
= gui_find_menu((char_u
*)"ToolBar");
1077 gui_mch_submenu_change(menu
, TRUE
);
1083 gui_mch_submenu_change(menu
, colors
)
1085 int colors
; /* TRUE for colors, FALSE for font */
1089 for (mp
= menu
; mp
!= NULL
; mp
= mp
->next
)
1091 if (mp
->id
!= (Widget
)0)
1095 gui_athena_menu_colors(mp
->id
);
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)
1101 XFreePixmap(gui
.dpy
, mp
->image
);
1102 get_toolbar_pixmap(mp
, &mp
->image
);
1103 if (mp
->image
!= (Pixmap
)0)
1104 XtVaSetValues(mp
->id
, XtNbitmap
, mp
->image
, NULL
);
1108 /* If we have a tooltip, then we need to change it's colors */
1109 if (mp
->tip
!= NULL
)
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
));
1124 gui_athena_menu_font(mp
->id
);
1126 /* If we have a tooltip, then we need to change it's font */
1127 /* Assume XtNinternational == True (in createBalloonEvalWindow)
1129 if (mp
->tip
!= NULL
)
1133 args
[0].name
= XtNfontSet
;
1134 args
[0].value
= (XtArgVal
)gui
.tooltip_fontset
;
1135 XtSetValues(mp
->tip
->balloonLabel
, &args
[0], XtNumber(args
));
1141 if (mp
->children
!= NULL
)
1143 /* Set the colors/font for the tear off widget */
1144 if (mp
->submenu_id
!= (Widget
)0)
1147 gui_athena_menu_colors(mp
->submenu_id
);
1149 gui_athena_menu_font(mp
->submenu_id
);
1151 /* Set the colors for the children */
1152 gui_mch_submenu_change(mp
->children
, colors
);
1158 * Make a submenu name into a pullright name.
1159 * Replace '.' by '_', can't include '.' in the submenu name.
1162 make_pull_name(name
)
1168 pname
= vim_strnsave(name
, STRLEN(name
) + strlen("-pullright"));
1171 strcat((char *)pname
, "-pullright");
1172 while ((p
= vim_strchr(pname
, '.')) != NULL
)
1180 gui_mch_add_menu_item(menu
, idx
)
1184 vimmenu_T
*parent
= menu
->parent
;
1187 # ifdef FEAT_TOOLBAR
1188 if (menu_is_toolbar(parent
->name
))
1195 if (menu_is_separator(menu
->name
))
1197 XtSetArg(args
[n
], XtNlabel
, ""); n
++;
1198 XtSetArg(args
[n
], XtNborderWidth
, 0); n
++;
1202 get_toolbar_pixmap(menu
, &menu
->image
);
1203 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
++;
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?
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".
1221 /* TODO: Could we just store "idx" and use that as the child
1225 if (menu
->id
== NULL
)
1227 menu
->id
= XtCreateManagedWidget((char *)menu
->dname
,
1228 type
, toolBar
, args
, n
);
1229 XtAddCallback(menu
->id
,
1230 XtNcallback
, gui_x11_menu_cb
, menu
);
1233 XtSetValues(menu
->id
, args
, n
);
1234 gui_athena_menu_colors(menu
->id
);
1237 gui_mch_menu_set_tip(menu
);
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();
1247 } /* toolbar menu item */
1250 /* Add menu separator */
1251 if (menu_is_separator(menu
->name
))
1253 menu
->submenu_id
= (Widget
)0;
1254 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
1255 smeLineObjectClass
, parent
->submenu_id
,
1257 if (menu
->id
== (Widget
)0)
1259 gui_athena_menu_colors(menu
->id
);
1263 if (parent
!= NULL
&& parent
->submenu_id
!= (Widget
)0)
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
,
1273 if (menu
->id
== (Widget
)0)
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.
1281 Dimension left_margin
;
1283 XtVaGetValues(menu
->id
, XtNleftMargin
, &left_margin
, NULL
);
1284 XtVaSetValues(menu
->id
, XtNrightMargin
,
1285 gui_athena_menu_has_submenus(parent
->submenu_id
, NULL
) ?
1291 gui_athena_menu_colors(menu
->id
);
1292 gui_athena_menu_font(menu
->id
);
1293 XtAddCallback(menu
->id
, XtNcallback
, gui_x11_menu_cb
,
1300 #if defined(FEAT_TOOLBAR) || defined(PROTO)
1302 gui_mch_show_toolbar(int showit
)
1304 Cardinal numChildren
; /* how many children toolBar has */
1306 if (toolBar
== (Widget
)0)
1308 XtVaGetValues(toolBar
, XtNnumChildren
, &numChildren
, NULL
);
1309 if (showit
&& numChildren
> 0)
1311 /* Assume that we want to show the toolbar if p_toolbar contains valid
1312 * option settings, therefore p_toolbar must not be NULL.
1314 WidgetList children
;
1316 XtVaGetValues(toolBar
, XtNchildren
, &children
, NULL
);
1318 void (*action
)(BalloonEval
*);
1321 if (strstr((const char *)p_toolbar
, "tooltips"))
1322 action
= &gui_mch_enable_beval_area
;
1324 action
= &gui_mch_disable_beval_area
;
1325 if (strstr((const char *)p_toolbar
, "text"))
1327 else if (strstr((const char *)p_toolbar
, "icons"))
1334 for (toolbar
= root_menu
; toolbar
; toolbar
= toolbar
->next
)
1335 if (menu_is_toolbar(toolbar
->dname
))
1337 /* Assumption: toolbar is NULL if there is no toolbar,
1338 * otherwise it contains the toolbar menu structure.
1340 * Assumption: "numChildren" == the number of items in the list
1341 * of items beginning with toolbar->children.
1345 for (cur
= toolbar
->children
; cur
; cur
= cur
->next
)
1350 /* Enable/Disable tooltip (OK to enable while currently
1353 if (cur
->tip
!= NULL
)
1354 (*action
)(cur
->tip
);
1357 XtSetArg(args
[n
], XtNbitmap
, None
);
1359 XtSetArg(args
[n
], XtNlabel
,
1360 menu_is_separator(cur
->name
) ? "" :
1361 (char *)cur
->dname
);
1366 XtSetArg(args
[n
], XtNbitmap
, cur
->image
);
1368 XtSetArg(args
[n
], XtNlabel
, (cur
->image
== None
) ?
1369 menu_is_separator(cur
->name
) ?
1376 if (cur
->id
!= NULL
)
1378 XtUnmanageChild(cur
->id
);
1379 XtSetValues(cur
->id
, args
, n
);
1380 XtManageChild(cur
->id
);
1386 gui
.toolbar_height
= gui_mch_compute_toolbar_height();
1387 XtManageChild(toolBar
);
1388 if (XtIsManaged(menuBar
))
1390 XtVaSetValues(textArea
,
1391 XtNvertDistance
, gui
.toolbar_height
+ gui
.menu_height
,
1393 XtVaSetValues(toolBar
,
1394 XtNvertDistance
, gui
.menu_height
,
1399 XtVaSetValues(textArea
,
1400 XtNvertDistance
, gui
.toolbar_height
,
1402 XtVaSetValues(toolBar
,
1409 gui
.toolbar_height
= 0;
1410 if (XtIsManaged(menuBar
))
1411 XtVaSetValues(textArea
,
1412 XtNvertDistance
, gui
.menu_height
,
1415 XtVaSetValues(textArea
,
1419 XtUnmanageChild(toolBar
);
1421 gui_set_shellsize(FALSE
, FALSE
, RESIZE_VERT
);
1426 gui_mch_compute_toolbar_height()
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 */
1437 shadowThickness
= 0;
1439 if (toolBar
!= (Widget
)0)
1441 XtVaGetValues(toolBar
,
1442 XtNborderWidth
, &shadowThickness
,
1443 XtNvSpace
, &marginHeight
,
1444 XtNchildren
, &children
,
1445 XtNnumChildren
, &numChildren
,
1447 for (i
= 0; i
< numChildren
; i
++)
1451 XtVaGetValues(children
[i
], XtNheight
, &whgt
, NULL
);
1457 return (int)(height
+ (marginHeight
<< 1) + (shadowThickness
<< 1));
1461 gui_mch_get_toolbar_colors(bgp
, fgp
, bsp
, tsp
, hsp
)
1468 XtVaGetValues(toolBar
, XtNbackground
, bgp
, XtNborderColor
, fgp
, NULL
);
1478 gui_mch_toggle_tearoffs(enable
)
1481 /* no tearoff menus */
1485 gui_mch_new_menu_colors()
1487 if (menuBar
== (Widget
)0)
1489 if (gui
.menu_fg_pixel
!= INVALCOLOR
)
1490 XtVaSetValues(menuBar
, XtNborderColor
, gui
.menu_fg_pixel
, NULL
);
1491 gui_athena_menu_colors(menuBar
);
1493 gui_athena_menu_colors(toolBar
);
1496 gui_mch_submenu_change(root_menu
, TRUE
);
1500 * Destroy the machine specific menu widget.
1503 gui_mch_destroy_menu(menu
)
1508 /* There is no item for the toolbar. */
1509 if (menu
->id
== (Widget
)0)
1512 parent
= XtParent(menu
->id
);
1514 /* When removing the last "pulldown" menu item from a pane, adjust the
1515 * right margins of the remaining widgets.
1517 if (menu
->submenu_id
!= (Widget
)0)
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.
1526 WidgetList children
;
1527 Cardinal num_children
;
1529 Dimension right_margin
= 0;
1530 Boolean get_left_margin
= False
;
1532 XtVaGetValues(parent
, XtNchildren
, &children
,
1533 XtNnumChildren
, &num_children
,
1535 if (gui_athena_menu_has_submenus(parent
, menu
->id
))
1536 right_margin
= puller_width
;
1538 get_left_margin
= True
;
1540 for (i
= 0; i
< num_children
; ++i
)
1542 if (children
[i
] == menu
->id
)
1544 if (get_left_margin
== True
)
1546 Dimension left_margin
;
1548 XtVaGetValues(children
[i
], XtNleftMargin
, &left_margin
,
1550 XtVaSetValues(children
[i
], XtNrightMargin
, left_margin
,
1554 XtVaSetValues(children
[i
], XtNrightMargin
, right_margin
,
1559 /* Please be sure to destroy the parent widget first (i.e. menu->id).
1561 * This code should be basically identical to that in the file gui_motif.c
1562 * because they are both Xt based.
1564 if (menu
->id
!= (Widget
)0)
1566 Cardinal num_children
;
1567 Dimension height
, space
, border
;
1569 XtVaGetValues(menuBar
,
1571 XtNborderWidth
, &border
,
1573 XtVaGetValues(menu
->id
,
1576 #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
1577 if (parent
== toolBar
&& menu
->tip
!= NULL
)
1579 /* We try to destroy this before the actual menu, because there are
1580 * callbacks, etc. that will be unregistered during the tooltip
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
1588 gui_mch_destroy_beval_area(menu
->tip
);
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.
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.
1606 * This happens in phase two of the widget destruction process.
1609 if (parent
!= menuBar
1611 && parent
!= toolBar
1615 XtVaGetValues(parent
, XtNnumChildren
, &num_children
, NULL
);
1616 if (num_children
> 1)
1617 XtDestroyWidget(menu
->id
);
1620 XtDestroyWidget(menu
->id
);
1621 menu
->id
= (Widget
)0;
1624 if (parent
== menuBar
)
1626 if (!gui
.menu_height_fixed
)
1627 gui
.menu_height
= height
+ 2 * (space
+ border
);
1630 else if (parent
== toolBar
)
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
);
1637 gui
.toolbar_height
= gui_mch_compute_toolbar_height();
1641 if (menu
->submenu_id
!= (Widget
)0)
1643 XtDestroyWidget(menu
->submenu_id
);
1644 menu
->submenu_id
= (Widget
)0;
1650 gui_athena_menu_timeout(client_data
, id
)
1651 XtPointer client_data
;
1654 Widget w
= (Widget
)client_data
;
1658 if (XtIsSubclass(w
,smeBSBObjectClass
))
1662 XtVaGetValues(w
, XtNrightBitmap
, &p
, NULL
);
1663 if ((p
!= None
) && (p
!= XtUnspecifiedPixmap
))
1665 /* We are dealing with an item that has a submenu */
1666 popup
= get_popup_entry(XtParent(w
));
1667 if (popup
== (Widget
)0)
1669 XtPopup(popup
, XtGrabNonexclusive
);
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.
1679 * This is called when XtPopup() is called.
1683 gui_athena_popup_callback(w
, client_data
, call_data
)
1685 XtPointer client_data
;
1686 XtPointer call_data
;
1688 /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
1689 vimmenu_T
*menu
= (vimmenu_T
*)client_data
;
1691 Position root_x
, root_y
;
1693 /* First, popdown any siblings that may have menus popped up */
1697 for (i
= menu
->parent
->children
; i
!= NULL
; i
= i
->next
)
1699 if (i
->submenu_id
!= NULL
&& XtIsManaged(i
->submenu_id
))
1700 XtPopdown(i
->submenu_id
);
1703 XtVaGetValues(XtParent(w
),
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
,
1716 gui_athena_popdown_submenus_action(w
, event
, args
, nargs
)
1722 WidgetList children
;
1723 Cardinal num_children
;
1725 XtVaGetValues(w
, XtNchildren
, &children
,
1726 XtNnumChildren
, &num_children
,
1728 for (; num_children
> 0; --num_children
)
1730 Widget child
= children
[num_children
- 1];
1732 if (has_submenu(child
))
1736 temp_w
= submenu_widget(child
);
1737 gui_athena_popdown_submenus_action(temp_w
,event
,args
,nargs
);
1743 /* Used to determine if the given widget has a submenu that can be popped up. */
1748 if ((widget
!= NULL
) && XtIsSubclass(widget
,smeBSBObjectClass
))
1752 XtVaGetValues(widget
, XtNrightBitmap
, &p
, NULL
);
1753 if ((p
!= None
) && (p
!= XtUnspecifiedPixmap
))
1761 gui_athena_delayed_arm_action(w
, event
, args
, nargs
)
1767 Dimension width
, height
;
1769 if (event
->type
!= MotionNotify
)
1777 if (event
->xmotion
.x
>= (int)width
|| event
->xmotion
.y
>= (int)height
)
1781 static Widget previous_active_widget
= NULL
;
1784 current
= XawSimpleMenuGetActiveEntry(w
);
1785 if (current
!= previous_active_widget
)
1789 /* If the timeout hasn't been triggered, remove it */
1790 XtRemoveTimeOut(timer
);
1792 gui_athena_popdown_submenus_action(w
,event
,args
,nargs
);
1793 if (has_submenu(current
))
1795 XtAppAddTimeOut(XtWidgetToApplicationContext(w
), 600L,
1796 gui_athena_menu_timeout
,
1797 (XtPointer
)current
);
1799 previous_active_widget
= current
;
1810 /* Get the active entry for the current menu */
1811 if ((menuw
= XawSimpleMenuGetActiveEntry(w
)) == (Widget
)0)
1814 return submenu_widget(menuw
);
1817 /* Given the widget that has been determined to have a submenu, return the submenu widget
1818 * that is to be popped up.
1821 submenu_widget(widget
)
1824 /* Precondition: has_submenu(widget) == True
1825 * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
1828 char_u
*pullright_name
;
1831 pullright_name
= make_pull_name((char_u
*)XtName(widget
));
1832 popup
= XtNameToWidget(XtParent(widget
), (char *)pullright_name
);
1833 vim_free(pullright_name
);
1836 /* Postcondition: (popup != NULL) implies
1837 * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
1842 gui_mch_show_popupmenu(menu
)
1845 int rootx
, rooty
, winx
, winy
;
1849 if (menu
->submenu_id
== (Widget
)0)
1852 /* Position the popup menu at the pointer */
1853 if (XQueryPointer(gui
.dpy
, XtWindow(vimShell
), &root
, &child
,
1854 &rootx
, &rooty
, &winx
, &winy
, &mask
))
1862 XtVaSetValues(menu
->submenu_id
,
1868 XtOverrideTranslations(menu
->submenu_id
, popupTrans
);
1869 XtPopupSpringLoaded(menu
->submenu_id
);
1872 #endif /* FEAT_MENU */
1875 * Set the menu and scrollbar colors to their default values.
1878 gui_mch_def_colors()
1881 * Get the colors ourselves. Using the automatic conversion doesn't
1882 * handle looking for approximate colors.
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
);
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
);
1903 gui_mch_set_scrollbar_thumb(sb
, val
, size
, max
)
1911 if (sb
->id
== (Widget
)0)
1915 * Athena scrollbar must go from 0.0 to 1.0.
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);
1923 vim_XawScrollbarSetThumb(sb
->id
, 0.0, 1.0, 0.0);
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
);
1933 vim_XawScrollbarSetThumb(sb
->id
, v
, s
, 1.0);
1939 gui_mch_set_scrollbar_pos(sb
, x
, y
, w
, h
)
1946 if (sb
->id
== (Widget
)0)
1949 XtUnmanageChild(sb
->id
);
1950 XtVaSetValues(sb
->id
,
1951 XtNhorizDistance
, x
,
1956 XtManageChild(sb
->id
);
1960 gui_mch_enable_scrollbar(sb
, flag
)
1964 if (sb
->id
!= (Widget
)0)
1967 XtManageChild(sb
->id
);
1969 XtUnmanageChild(sb
->id
);
1974 gui_mch_create_scrollbar(sb
, orient
)
1976 int orient
; /* SBAR_VERT or SBAR_HORIZ */
1978 sb
->id
= XtVaCreateWidget("scrollBar",
1979 #ifdef FEAT_GUI_NEXTAW
1980 scrollbarWidgetClass
, vimForm
,
1982 vim_scrollbarWidgetClass
, vimForm
,
1986 XtNbottom
, XtChainTop
,
1987 XtNleft
, XtChainLeft
,
1988 XtNright
, XtChainLeft
,
1990 XtNorientation
, (orient
== SBAR_VERT
) ? XtorientVertical
1991 : XtorientHorizontal
,
1992 XtNforeground
, gui
.scroll_fg_pixel
,
1993 XtNbackground
, gui
.scroll_bg_pixel
,
1995 if (sb
->id
== (Widget
)0)
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
);
2003 #ifdef FEAT_GUI_NEXTAW
2004 XawScrollbarSetThumb(sb
->id
, 0.0, 1.0);
2006 vim_XawScrollbarSetThumb(sb
->id
, 0.0, 1.0, 0.0);
2010 #if defined(FEAT_WINDOWS) || defined(PROTO)
2012 gui_mch_destroy_scrollbar(sb
)
2015 if (sb
->id
!= (Widget
)0)
2016 XtDestroyWidget(sb
->id
);
2021 gui_mch_set_scrollbar_colors(sb
)
2024 if (sb
->id
!= (Widget
)0)
2025 XtVaSetValues(sb
->id
,
2026 XtNforeground
, gui
.scroll_fg_pixel
,
2027 XtNbackground
, gui
.scroll_bg_pixel
,
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
);
2036 * Miscellaneous stuff:
2041 return XtWindow(textArea
);
2044 #if defined(FEAT_BROWSE) || defined(PROTO)
2046 * Put up a file requester.
2047 * Returns the selected name in allocated memory, or NULL for Cancel.
2051 gui_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) */
2060 char_u dirbuf
[MAXPATHL
];
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
);
2069 if (dflt
!= NULL
&& *dflt
!= NUL
2070 && STRLEN(dirbuf
) + 2 + STRLEN(dflt
) < MAXPATHL
)
2072 add_pathsep(dirbuf
);
2073 STRCAT(dirbuf
, dflt
);
2076 /* Position the file selector just below the menubar */
2077 XtTranslateCoords(vimShell
, (Position
)0, (Position
)
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
);
2090 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2092 static int dialogStatus
;
2093 static Atom dialogatom
;
2095 static void keyhit_callback
__ARGS((Widget w
, XtPointer client_data
, XEvent
*event
, Boolean
*cont
));
2096 static void butproc
__ARGS((Widget w
, XtPointer client_data
, XtPointer call_data
));
2097 static void dialog_wm_handler
__ARGS((Widget w
, XtPointer client_data
, XEvent
*event
, Boolean
*dum
));
2100 * Callback function for the textfield. When CR is hit this works like
2101 * hitting the "OK" button, ESC like "Cancel".
2105 keyhit_callback(w
, client_data
, event
, cont
)
2107 XtPointer client_data
;
2113 if (XLookupString(&(event
->xkey
), buf
, 2, NULL
, NULL
) == 1)
2117 else if (*buf
== ESC
)
2124 butproc(w
, client_data
, call_data
)
2126 XtPointer client_data
;
2127 XtPointer call_data
;
2129 dialogStatus
= (int)(long)client_data
+ 1;
2133 * Function called when dialog window closed.
2137 dialog_wm_handler(w
, client_data
, event
, dum
)
2139 XtPointer client_data
;
2143 if (event
->type
== ClientMessage
2144 && ((XClientMessageEvent
*)event
)->data
.l
[0] == dialogatom
)
2150 gui_mch_dialog(type
, title
, message
, buttons
, dfltbutton
, textfield
)
2167 Widget dialogmessage
;
2168 Widget dialogtextfield
= 0;
2169 Widget dialogButton
;
2170 Widget prev_dialogButton
= NULL
;
2175 title
= (char_u
*)_("Vim dialog");
2178 /* if our pointer is currently hidden, then we should show it. */
2179 gui_mch_mousehide(FALSE
);
2181 /* Check 'v' flag in 'guioptions': vertical button placement. */
2182 vertical
= (vim_strchr(p_go
, GO_VERTICAL
) != NULL
);
2184 /* The shell is created each time, to make sure it is resized properly */
2185 dialogshell
= XtVaCreatePopupShell("dialogShell",
2186 transientShellWidgetClass
, vimShell
,
2189 if (dialogshell
== (Widget
)0)
2192 dialog
= XtVaCreateManagedWidget("dialog",
2193 formWidgetClass
, dialogshell
,
2194 XtNdefaultDistance
, 20,
2196 if (dialog
== (Widget
)0)
2198 gui_athena_menu_colors(dialog
);
2199 dialogmessage
= XtVaCreateManagedWidget("dialogMessage",
2200 labelWidgetClass
, dialog
,
2203 XtNbottom
, XtChainTop
,
2204 XtNleft
, XtChainLeft
,
2205 XtNright
, XtChainLeft
,
2209 gui_athena_menu_colors(dialogmessage
);
2211 if (textfield
!= NULL
)
2213 dialogtextfield
= XtVaCreateManagedWidget("textfield",
2214 asciiTextWidgetClass
, dialog
,
2217 XtNbottom
, XtChainTop
,
2218 XtNleft
, XtChainLeft
,
2219 XtNright
, XtChainRight
,
2220 XtNfromVert
, dialogmessage
,
2222 XtNstring
, textfield
,
2224 XtNuseStringInPlace
, True
,
2225 XtNeditType
, XawtextEdit
,
2226 XtNwrap
, XawtextWrapNever
,
2227 XtNresize
, XawtextResizeHeight
,
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
);
2237 /* make a copy, so that we can insert NULs */
2238 buts
= vim_strsave(buttons
);
2243 for (butcount
= 0; *p
; ++butcount
)
2245 for (next
= p
; *next
; ++next
)
2247 if (*next
== DLG_HOTKEY_CHAR
)
2248 mch_memmove(next
, next
+ 1, STRLEN(next
));
2249 if (*next
== DLG_BUTTON_SEP
)
2255 dialogButton
= XtVaCreateManagedWidget("button",
2256 commandWidgetClass
, dialog
,
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
,
2266 gui_athena_menu_colors(dialogButton
);
2268 XtVaSetValues(dialogButton
,
2269 vertical
? XtNfromVert
: XtNfromHoriz
, prev_dialogButton
,
2272 XtAddCallback(dialogButton
, XtNcallback
, butproc
, (XtPointer
)butcount
);
2274 prev_dialogButton
= dialogButton
;
2278 XtRealizeWidget(dialogshell
);
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
);
2285 XtVaGetValues(dialogshell
,
2289 XtVaGetValues(vimShell
,
2293 XtTranslateCoords(vimShell
,
2294 (Position
)((wv
- wd
) / 2),
2295 (Position
)((hv
- hd
) / 2),
2301 XtVaSetValues(dialogshell
, XtNx
, x
, XtNy
, y
, NULL
);
2303 /* Position the mouse pointer in the dialog, required for when focus
2305 XWarpPointer(gui
.dpy
, (Window
)0, XtWindow(dialogshell
), 0, 0, 0, 0, 20, 40);
2308 app
= XtWidgetToApplicationContext(dialogshell
);
2310 XtPopup(dialogshell
, XtGrabNonexclusive
);
2314 XtAppNextEvent(app
, &event
);
2315 XtDispatchEvent(&event
);
2316 if (dialogStatus
>= 0)
2320 XtPopdown(dialogshell
);
2322 if (textfield
!= NULL
&& dialogStatus
< 0)
2326 XtDestroyWidget(dialogshell
);
2328 return dialogStatus
;
2332 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
2334 * Set the colors of Widget "id" to the menu colors.
2337 gui_athena_menu_colors(id
)
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
);
2348 * Set the colors of Widget "id" to the scroll colors.
2351 gui_athena_scroll_colors(id
)
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
);