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.
90 gui_athena_scroll_cb_jump(w
, client_data
, call_data
)
92 XtPointer client_data
, call_data
;
94 scrollbar_T
*sb
, *sb_info
;
97 sb
= gui_find_scrollbar((long)client_data
);
101 else if (sb
->wp
!= NULL
) /* Left or right scrollbar */
104 * Careful: need to get scrollbar info out of first (left) scrollbar
105 * for window, but keep real scrollbar too because we must pass it to
106 * gui_drag_scrollbar().
108 sb_info
= &sb
->wp
->w_scrollbars
[0];
110 else /* Bottom scrollbar */
113 value
= (long)(*((float *)call_data
) * (float)(sb_info
->max
+ 1) + 0.001);
114 if (value
> sb_info
->max
)
115 value
= sb_info
->max
;
117 gui_drag_scrollbar(sb
, value
, TRUE
);
121 * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
122 * right mouse buttons.
125 gui_athena_scroll_cb_scroll(w
, client_data
, call_data
)
127 XtPointer client_data
, call_data
;
129 scrollbar_T
*sb
, *sb_info
;
131 int data
= (int)(long)call_data
;
134 sb
= gui_find_scrollbar((long)client_data
);
138 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
141 * Careful: need to get scrollbar info out of first (left) scrollbar
142 * for window, but keep real scrollbar too because we must pass it to
143 * gui_drag_scrollbar().
145 sb_info
= &sb
->wp
->w_scrollbars
[0];
147 if (sb_info
->size
> 5)
148 page
= sb_info
->size
- 2; /* use two lines of context */
150 page
= sb_info
->size
;
151 #ifdef FEAT_GUI_NEXTAW
154 data
= (data
- gui
.char_height
+ 1) / gui
.char_height
;
155 if (data
> -sb_info
->size
)
162 data
= (data
+ gui
.char_height
- 1) / gui
.char_height
;
163 if (data
< sb_info
->size
)
171 case ONE_LINE_DATA
: data
= 1; break;
172 case -ONE_LINE_DATA
: data
= -1; break;
173 case ONE_PAGE_DATA
: data
= page
; break;
174 case -ONE_PAGE_DATA
: data
= -page
; break;
175 case END_PAGE_DATA
: data
= sb_info
->max
; break;
176 case -END_PAGE_DATA
: data
= -sb_info
->max
; break;
177 default: data
= 0; break;
181 else /* Bottom scrollbar */
184 #ifdef FEAT_GUI_NEXTAW
187 data
= (data
- gui
.char_width
+ 1) / gui
.char_width
;
188 if (data
> -sb
->size
)
193 data
= (data
+ gui
.char_width
- 1) / gui
.char_width
;
198 if (data
< -1) /* page-width left */
201 data
= -(sb
->size
- 5);
205 else if (data
> 1) /* page-width right */
208 data
= (sb
->size
- 5);
214 value
= sb_info
->value
+ data
;
215 if (value
> sb_info
->max
)
216 value
= sb_info
->max
;
220 /* Update the bottom scrollbar an extra time (why is this needed?? */
221 if (sb
->wp
== NULL
) /* Bottom scrollbar */
222 gui_mch_set_scrollbar_thumb(sb
, value
, sb
->size
, sb
->max
);
224 gui_drag_scrollbar(sb
, value
, FALSE
);
228 * Create all the Athena widgets necessary.
231 gui_x11_create_widgets()
234 * We don't have any borders handled internally by the textArea to worry
235 * about so only skip over the configured border width.
237 gui
.border_offset
= gui
.border_width
;
239 #if 0 /* not needed? */
240 XtInitializeWidgetClass(formWidgetClass
);
241 XtInitializeWidgetClass(boxWidgetClass
);
242 XtInitializeWidgetClass(coreWidgetClass
);
244 XtInitializeWidgetClass(menuButtonWidgetClass
);
246 XtInitializeWidgetClass(simpleMenuWidgetClass
);
247 #ifdef FEAT_GUI_NEXTAW
248 XtInitializeWidgetClass(scrollbarWidgetClass
);
250 XtInitializeWidgetClass(vim_scrollbarWidgetClass
);
254 /* The form containing all the other widgets */
255 vimForm
= XtVaCreateManagedWidget("vimForm",
256 formWidgetClass
, vimShell
,
259 gui_athena_scroll_colors(vimForm
);
262 /* The top menu bar */
263 menuBar
= XtVaCreateManagedWidget("menuBar",
264 boxWidgetClass
, vimForm
,
267 XtNbottom
, XtChainTop
,
268 XtNleft
, XtChainLeft
,
269 XtNright
, XtChainRight
,
270 XtNinsertPosition
, athena_calculate_ins_pos
,
272 gui_athena_menu_colors(menuBar
);
273 if (gui
.menu_fg_pixel
!= INVALCOLOR
)
274 XtVaSetValues(menuBar
, XtNborderColor
, gui
.menu_fg_pixel
, NULL
);
278 /* Don't create it Managed, it will be managed when creating the first
279 * item. Otherwise an empty toolbar shows up. */
280 toolBar
= XtVaCreateWidget("toolBar",
281 boxWidgetClass
, vimForm
,
284 XtNbottom
, XtChainTop
,
285 XtNleft
, XtChainLeft
,
286 XtNright
, XtChainRight
,
287 XtNorientation
, XtorientHorizontal
,
290 XtNinsertPosition
, athena_calculate_ins_pos
,
292 gui_athena_menu_colors(toolBar
);
296 textArea
= XtVaCreateManagedWidget("textArea",
297 coreWidgetClass
, vimForm
,
300 XtNbottom
, XtChainTop
,
301 XtNleft
, XtChainLeft
,
302 XtNright
, XtChainLeft
,
303 XtNbackground
, gui
.back_pixel
,
308 * Install the callbacks.
310 gui_x11_callbacks(textArea
, vimForm
);
313 popupTrans
= XtParseTranslationTable(
314 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
315 "<LeaveWindow>: unhighlight()\n"
316 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
317 "<Motion>: highlight() menu-delayedpopup()");
318 parentTrans
= XtParseTranslationTable("<LeaveWindow>: unhighlight()");
319 menuTrans
= XtParseTranslationTable(
320 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
321 "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n"
322 "<BtnUp>: notify() unhighlight()\n"
323 "<BtnMotion>: highlight() menu-delayedpopup()");
324 supermenuTrans
= XtParseTranslationTable(
325 "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
326 "<LeaveWindow>: unhighlight()\n"
327 "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
328 "<BtnMotion>: highlight() menu-delayedpopup()");
330 XtAppAddActions(XtWidgetToApplicationContext(vimForm
), pullAction
,
331 XtNumber(pullAction
));
334 /* Pretend we don't have input focus, we will get an event if we do. */
335 gui
.in_focus
= FALSE
;
340 * Calculates the Pixmap based on the size of the current menu font.
343 gui_athena_create_pullright_pixmap(w
)
347 #ifdef FONTSET_ALWAYS
348 XFontSet font
= None
;
350 XFontStruct
*font
= NULL
;
353 #ifdef FONTSET_ALWAYS
354 if (gui
.menu_fontset
== NOFONTSET
)
356 if (gui
.menu_font
== NOFONT
)
361 Cardinal num_children
;
363 #ifdef FONTSET_ALWAYS
364 from
.size
= strlen(from
.addr
= XtDefaultFontSet
);
365 to
.addr
= (XtPointer
)&font
;
366 to
.size
= sizeof(XFontSet
);
368 from
.size
= strlen(from
.addr
= XtDefaultFont
);
369 to
.addr
= (XtPointer
)&font
;
370 to
.size
= sizeof(XFontStruct
*);
372 /* Assumption: The menuBar children will use the same font as the
373 * pulldown menu items AND they will all be of type
376 XtVaGetValues(menuBar
, XtNchildren
, &children
,
377 XtNnumChildren
, &num_children
,
379 if (XtConvertAndStore(w
? w
:
380 (num_children
> 0) ? children
[0] : menuBar
,
382 #ifdef FONTSET_ALWAYS
389 /* "font" should now contain data */
392 #ifdef FONTSET_ALWAYS
393 font
= (XFontSet
)gui
.menu_fontset
;
395 font
= (XFontStruct
*)gui
.menu_font
;
400 GC draw_gc
, undraw_gc
;
404 #ifdef FONTSET_ALWAYS
405 height
= fontset_height2(font
);
407 height
= font
->max_bounds
.ascent
+ font
->max_bounds
.descent
;
410 puller_width
= width
+ 4;
411 retval
= XCreatePixmap(gui
.dpy
,DefaultRootWindow(gui
.dpy
),width
,
413 gc_values
.foreground
= 1;
414 gc_values
.background
= 0;
415 draw_gc
= XCreateGC(gui
.dpy
, retval
,
416 GCForeground
| GCBackground
,
418 gc_values
.foreground
= 0;
419 gc_values
.background
= 1;
420 undraw_gc
= XCreateGC(gui
.dpy
, retval
,
421 GCForeground
| GCBackground
,
425 points
[1].x
= width
- 1;
426 points
[1].y
= (height
- 1) / 2;
428 points
[2].y
= height
- 1;
429 XFillRectangle(gui
.dpy
, retval
, undraw_gc
, 0, 0, height
, height
);
430 XFillPolygon(gui
.dpy
, retval
, draw_gc
, points
, XtNumber(points
),
431 Convex
, CoordModeOrigin
);
432 XFreeGC(gui
.dpy
, draw_gc
);
433 XFreeGC(gui
.dpy
, undraw_gc
);
440 * Called when the GUI is not going to start after all.
443 gui_x11_destroy_widgets()
454 #if defined(FEAT_TOOLBAR) || defined(PROTO)
455 # include "gui_x11_pm.h"
456 # ifdef HAVE_X11_XPM_H
457 # include <X11/xpm.h>
460 static void createXpmImages
__ARGS((char_u
*path
, char **xpm
, Pixmap
*sen
));
461 static void get_toolbar_pixmap
__ARGS((vimmenu_T
*menu
, Pixmap
*sen
));
464 * Allocated a pixmap for toolbar menu "menu".
468 get_toolbar_pixmap(menu
, sen
)
472 char_u buf
[MAXPATHL
]; /* buffer storing expanded pathname */
473 char **xpm
= NULL
; /* xpm array */
475 buf
[0] = NUL
; /* start with NULL path */
477 if (menu
->iconfile
!= NULL
)
479 /* Use the "icon=" argument. */
480 gui_find_iconfile(menu
->iconfile
, buf
, "xpm");
481 createXpmImages(buf
, NULL
, sen
);
483 /* If it failed, try using the menu name. */
484 if (*sen
== (Pixmap
)0 && gui_find_bitmap(menu
->name
, buf
, "xpm") == OK
)
485 createXpmImages(buf
, NULL
, sen
);
486 if (*sen
!= (Pixmap
)0)
490 if (menu
->icon_builtin
|| gui_find_bitmap(menu
->name
, buf
, "xpm") == FAIL
)
492 if (menu
->iconidx
>= 0 && menu
->iconidx
493 < (int)(sizeof(built_in_pixmaps
) / sizeof(built_in_pixmaps
[0])))
494 xpm
= built_in_pixmaps
[menu
->iconidx
];
499 if (xpm
!= NULL
|| buf
[0] != NUL
)
500 createXpmImages(buf
, xpm
, sen
);
504 * Read an Xpm file, doing color substitutions for the foreground and
505 * background colors. If there is an error reading a color xpm file,
506 * drop back and read the monochrome file. If successful, create the
507 * insensitive Pixmap too.
510 createXpmImages(path
, xpm
, sen
)
517 XpmColorSymbol color
[5] =
520 {"iconColor1", NULL
, 0},
521 {"bottomShadowColor", NULL
, 0},
522 {"topShadowColor", NULL
, 0},
523 {"selectColor", NULL
, 0}
530 gui_mch_get_toolbar_colors(
531 &color
[BACKGROUND
].pixel
,
532 &color
[FOREGROUND
].pixel
,
533 &color
[BOTTOM_SHADOW
].pixel
,
534 &color
[TOP_SHADOW
].pixel
,
535 &color
[HIGHLIGHT
].pixel
);
537 /* Setup the color subsititution table */
538 attrs
.valuemask
= XpmColorSymbols
;
539 attrs
.colorsymbols
= color
;
540 attrs
.numsymbols
= 5;
542 screenNum
= DefaultScreen(gui
.dpy
);
543 rootWindow
= RootWindow(gui
.dpy
, screenNum
);
545 /* Create the "sensitive" pixmap */
547 status
= XpmCreatePixmapFromData(gui
.dpy
, rootWindow
, xpm
,
548 &map
, &mask
, &attrs
);
550 status
= XpmReadFileToPixmap(gui
.dpy
, rootWindow
, (char *)path
,
551 &map
, &mask
, &attrs
);
552 if (status
== XpmSuccess
&& map
!= 0)
558 /* Need to create new Pixmaps with the mask applied. */
559 gcvalues
.foreground
= color
[BACKGROUND
].pixel
;
560 back_gc
= XCreateGC(gui
.dpy
, map
, GCForeground
, &gcvalues
);
561 mask_gc
= XCreateGC(gui
.dpy
, map
, GCForeground
, &gcvalues
);
562 XSetClipMask(gui
.dpy
, mask_gc
, mask
);
564 /* Create the "sensitive" pixmap. */
565 *sen
= XCreatePixmap(gui
.dpy
, rootWindow
,
566 attrs
.width
, attrs
.height
,
567 DefaultDepth(gui
.dpy
, screenNum
));
568 XFillRectangle(gui
.dpy
, *sen
, back_gc
, 0, 0,
569 attrs
.width
, attrs
.height
);
570 XCopyArea(gui
.dpy
, map
, *sen
, mask_gc
, 0, 0,
571 attrs
.width
, attrs
.height
, 0, 0);
573 XFreeGC(gui
.dpy
, back_gc
);
574 XFreeGC(gui
.dpy
, mask_gc
);
575 XFreePixmap(gui
.dpy
, map
);
580 XpmFreeAttributes(&attrs
);
584 gui_mch_set_toolbar_pos(x
, y
, w
, h
)
593 if (!XtIsManaged(toolBar
)) /* nothing to do */
595 XtUnmanageChild(toolBar
);
596 XtVaGetValues(toolBar
,
597 XtNborderWidth
, &border
,
599 height
= h
- 2 * border
;
602 XtVaSetValues(toolBar
,
605 XtNwidth
, w
- 2 * border
,
608 XtManageChild(toolBar
);
613 gui_mch_set_text_area_pos(x
, y
, w
, h
)
619 XtUnmanageChild(textArea
);
620 XtVaSetValues(textArea
,
626 XtManageChild(textArea
);
628 /* Give keyboard focus to the textArea instead of the toolbar. */
629 gui_mch_reset_focus();
635 * A toolbar button has been pushed; now reset the input focus
636 * such that the user can type page up/down etc. and have the
637 * input go to the editor window, not the button
640 gui_mch_reset_focus()
642 XtSetKeyboardFocus(vimForm
, textArea
);
648 gui_x11_set_back_color()
650 if (textArea
!= NULL
)
651 XtVaSetValues(textArea
,
652 XtNbackground
, gui
.back_pixel
,
656 #if defined(FEAT_MENU) || defined(PROTO)
661 static char_u
*make_pull_name
__ARGS((char_u
* name
));
662 static Widget get_popup_entry
__ARGS((Widget w
));
663 static Widget submenu_widget
__ARGS((Widget
));
664 static Boolean has_submenu
__ARGS((Widget
));
665 static void gui_mch_submenu_change
__ARGS((vimmenu_T
*mp
, int colors
));
666 static void gui_athena_menu_font
__ARGS((Widget id
));
667 static Boolean gui_athena_menu_has_submenus
__ARGS((Widget
, Widget
));
670 gui_mch_enable_menu(flag
)
675 XtManageChild(menuBar
);
677 if (XtIsManaged(toolBar
))
679 XtVaSetValues(toolBar
,
680 XtNvertDistance
, gui
.menu_height
,
682 XtVaSetValues(textArea
,
683 XtNvertDistance
, gui
.menu_height
+ gui
.toolbar_height
,
690 XtUnmanageChild(menuBar
);
692 if (XtIsManaged(toolBar
))
694 XtVaSetValues(toolBar
,
703 gui_mch_set_menu_pos(x
, y
, w
, h
)
712 XtUnmanageChild(menuBar
);
713 XtVaGetValues(menuBar
, XtNborderWidth
, &border
, NULL
);
714 /* avoid trouble when there are no menu items, and h is 1 */
715 height
= h
- 2 * border
;
718 XtVaSetValues(menuBar
,
721 XtNwidth
, w
- 2 * border
,
724 XtManageChild(menuBar
);
728 * Used to calculate the insertion position of a widget with respect to its
731 * Valid range of return values is: 0 (beginning of children) to
732 * numChildren (end of children).
735 athena_calculate_ins_pos(widget
)
738 /* Assume that if the parent of the vimmenu_T is NULL, then we can get
739 * to this menu by traversing "next", starting at "root_menu".
741 * This holds true for popup menus, toolbar, and toplevel menu items.
744 /* Popup menus: "id" is NULL. Only submenu_id is valid */
746 /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
747 * "submenu_id" will be non-NULL.
750 /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
753 Cardinal num_children
= 0;
759 XtSetArg(args
[n
], XtNchildren
, &children
); n
++;
760 XtSetArg(args
[n
], XtNnumChildren
, &num_children
); n
++;
761 XtGetValues(XtParent(widget
), args
, n
);
763 retval
= num_children
;
764 for (i
= 0; i
< (int)num_children
; ++i
)
766 Widget current
= children
[i
];
767 vimmenu_T
*menu
= NULL
;
769 for (menu
= (a_cur_menu
->parent
== NULL
)
770 ? root_menu
: a_cur_menu
->parent
->children
;
773 if (current
== menu
->id
774 && a_cur_menu
->priority
< menu
->priority
782 gui_mch_add_menu(menu
, idx
)
786 char_u
*pullright_name
;
787 Dimension height
, space
, border
;
788 vimmenu_T
*parent
= menu
->parent
;
793 if (menu_is_popup(menu
->dname
))
795 menu
->submenu_id
= XtVaCreatePopupShell((char *)menu
->dname
,
796 simpleMenuWidgetClass
, vimShell
,
797 XtNinsertPosition
, athena_calculate_ins_pos
,
798 XtNtranslations
, popupTrans
,
800 gui_athena_menu_colors(menu
->submenu_id
);
802 else if (menu_is_menubar(menu
->dname
))
804 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
805 menuButtonWidgetClass
, menuBar
,
806 XtNmenuName
, menu
->dname
,
807 #ifdef FONTSET_ALWAYS
808 XtNinternational
, True
,
811 if (menu
->id
== (Widget
)0)
813 gui_athena_menu_colors(menu
->id
);
814 gui_athena_menu_font(menu
->id
);
816 menu
->submenu_id
= XtVaCreatePopupShell((char *)menu
->dname
,
817 simpleMenuWidgetClass
, menu
->id
,
818 XtNinsertPosition
, athena_calculate_ins_pos
,
819 XtNtranslations
, supermenuTrans
,
821 gui_athena_menu_colors(menu
->submenu_id
);
822 gui_athena_menu_font(menu
->submenu_id
);
824 /* Don't update the menu height when it was set at a fixed value */
825 if (!gui
.menu_height_fixed
)
828 * When we add a top-level item to the menu bar, we can figure
829 * out how high the menu bar should be.
831 XtVaGetValues(menuBar
,
833 XtNborderWidth
, &border
,
835 XtVaGetValues(menu
->id
,
838 gui
.menu_height
= height
+ 2 * (space
+ border
);
842 else if (parent
->submenu_id
!= (Widget
)0)
844 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
845 smeBSBObjectClass
, parent
->submenu_id
,
846 XtNlabel
, menu
->dname
,
847 #ifdef FONTSET_ALWAYS
848 XtNinternational
, True
,
851 if (menu
->id
== (Widget
)0)
853 if (pullerBitmap
== None
)
854 pullerBitmap
= gui_athena_create_pullright_pixmap(menu
->id
);
856 XtVaSetValues(menu
->id
, XtNrightBitmap
, pullerBitmap
,
858 /* If there are other menu items that are not pulldown menus,
859 * we need to adjust the right margins of those, too.
863 Cardinal num_children
;
866 XtVaGetValues(parent
->submenu_id
, XtNchildren
, &children
,
867 XtNnumChildren
, &num_children
,
869 for (i
= 0; i
< (int)num_children
; ++i
)
871 XtVaSetValues(children
[i
],
872 XtNrightMargin
, puller_width
,
876 gui_athena_menu_colors(menu
->id
);
877 gui_athena_menu_font(menu
->id
);
879 pullright_name
= make_pull_name(menu
->dname
);
880 menu
->submenu_id
= XtVaCreatePopupShell((char *)pullright_name
,
881 simpleMenuWidgetClass
, parent
->submenu_id
,
882 XtNtranslations
, menuTrans
,
884 gui_athena_menu_colors(menu
->submenu_id
);
885 gui_athena_menu_font(menu
->submenu_id
);
886 vim_free(pullright_name
);
887 XtAddCallback(menu
->submenu_id
, XtNpopupCallback
,
888 gui_athena_popup_callback
, (XtPointer
)menu
);
890 if (parent
->parent
!= NULL
)
891 XtOverrideTranslations(parent
->submenu_id
, parentTrans
);
896 /* Used to determine whether a SimpleMenu has pulldown entries.
898 * "id" is the parent of the menu items.
899 * Ignore widget "ignore" in the pane.
902 gui_athena_menu_has_submenus(id
, ignore
)
907 Cardinal num_children
;
910 XtVaGetValues(id
, XtNchildren
, &children
,
911 XtNnumChildren
, &num_children
,
913 for (i
= 0; i
< (int)num_children
; ++i
)
915 if (children
[i
] == ignore
)
917 if (has_submenu(children
[i
]))
924 gui_athena_menu_font(id
)
927 #ifdef FONTSET_ALWAYS
928 if (gui
.menu_fontset
!= NOFONTSET
)
933 XtVaSetValues(id
, XtNfontSet
, gui
.menu_fontset
, NULL
);
934 /* We should force the widget to recalculate it's
939 XtVaSetValues(id
, XtNfontSet
, gui
.menu_fontset
, NULL
);
941 XtVaSetValues(id
, XtNrightBitmap
, pullerBitmap
, NULL
);
946 if (gui
.menu_font
!= NOFONT
)
954 # ifdef FEAT_XFONTSET
955 if (gui
.fontset
!= NOFONTSET
)
956 XtVaSetValues(id
, XtNfontSet
, gui
.menu_font
, NULL
);
959 XtVaSetValues(id
, XtNfont
, gui
.menu_font
, NULL
);
961 XtVaSetValues(id
, XtNrightBitmap
, pullerBitmap
, NULL
);
963 /* Force the widget to recalculate it's geometry now. */
972 gui_mch_new_menu_font()
974 Pixmap oldpuller
= None
;
976 if (menuBar
== (Widget
)0)
979 if (pullerBitmap
!= None
)
981 oldpuller
= pullerBitmap
;
982 pullerBitmap
= gui_athena_create_pullright_pixmap(NULL
);
984 gui_mch_submenu_change(root_menu
, FALSE
);
987 /* Iterate through the menubar menu items and get the height of
988 * each one. The menu bar height is set to the maximum of all
992 int max_height
= 9999;
994 for (mp
= root_menu
; mp
!= NULL
; mp
= mp
->next
)
996 if (menu_is_menubar(mp
->dname
))
1000 XtVaGetValues(mp
->id
,
1003 if (height
< max_height
)
1004 max_height
= height
;
1007 if (max_height
!= 9999)
1009 /* Don't update the menu height when it was set at a fixed value */
1010 if (!gui
.menu_height_fixed
)
1012 Dimension space
, border
;
1014 XtVaGetValues(menuBar
,
1016 XtNborderWidth
, &border
,
1018 gui
.menu_height
= max_height
+ 2 * (space
+ border
);
1022 /* Now, to simulate the window being resized. Only, this
1023 * will resize the window to it's current state.
1025 * There has to be a better way, but I do not see one at this time.
1031 XtVaGetValues(vimShell
,
1035 gui_resize_shell(w
, h
1037 - xim_get_status_area_height()
1041 gui_set_shellsize(FALSE
, TRUE
, RESIZE_VERT
);
1043 if (oldpuller
!= None
)
1044 XFreePixmap(gui
.dpy
, oldpuller
);
1047 #if defined(FEAT_BEVAL) || defined(PROTO)
1049 gui_mch_new_tooltip_font()
1051 # ifdef FEAT_TOOLBAR
1054 if (toolBar
== (Widget
)0)
1057 menu
= gui_find_menu((char_u
*)"ToolBar");
1059 gui_mch_submenu_change(menu
, FALSE
);
1064 gui_mch_new_tooltip_colors()
1066 # ifdef FEAT_TOOLBAR
1069 if (toolBar
== (Widget
)0)
1072 menu
= gui_find_menu((char_u
*)"ToolBar");
1074 gui_mch_submenu_change(menu
, TRUE
);
1080 gui_mch_submenu_change(menu
, colors
)
1082 int colors
; /* TRUE for colors, FALSE for font */
1086 for (mp
= menu
; mp
!= NULL
; mp
= mp
->next
)
1088 if (mp
->id
!= (Widget
)0)
1092 gui_athena_menu_colors(mp
->id
);
1094 /* For a toolbar item: Free the pixmap and allocate a new one,
1095 * so that the background color is right. */
1096 if (mp
->image
!= (Pixmap
)0)
1098 XFreePixmap(gui
.dpy
, mp
->image
);
1099 get_toolbar_pixmap(mp
, &mp
->image
);
1100 if (mp
->image
!= (Pixmap
)0)
1101 XtVaSetValues(mp
->id
, XtNbitmap
, mp
->image
, NULL
);
1105 /* If we have a tooltip, then we need to change it's colors */
1106 if (mp
->tip
!= NULL
)
1110 args
[0].name
= XtNbackground
;
1111 args
[0].value
= gui
.tooltip_bg_pixel
;
1112 args
[1].name
= XtNforeground
;
1113 args
[1].value
= gui
.tooltip_fg_pixel
;
1114 XtSetValues(mp
->tip
->balloonLabel
, &args
[0], XtNumber(args
));
1121 gui_athena_menu_font(mp
->id
);
1123 /* If we have a tooltip, then we need to change it's font */
1124 /* Assume XtNinternational == True (in createBalloonEvalWindow)
1126 if (mp
->tip
!= NULL
)
1130 args
[0].name
= XtNfontSet
;
1131 args
[0].value
= (XtArgVal
)gui
.tooltip_fontset
;
1132 XtSetValues(mp
->tip
->balloonLabel
, &args
[0], XtNumber(args
));
1138 if (mp
->children
!= NULL
)
1140 /* Set the colors/font for the tear off widget */
1141 if (mp
->submenu_id
!= (Widget
)0)
1144 gui_athena_menu_colors(mp
->submenu_id
);
1146 gui_athena_menu_font(mp
->submenu_id
);
1148 /* Set the colors for the children */
1149 gui_mch_submenu_change(mp
->children
, colors
);
1155 * Make a submenu name into a pullright name.
1156 * Replace '.' by '_', can't include '.' in the submenu name.
1159 make_pull_name(name
)
1165 pname
= vim_strnsave(name
, STRLEN(name
) + strlen("-pullright"));
1168 strcat((char *)pname
, "-pullright");
1169 while ((p
= vim_strchr(pname
, '.')) != NULL
)
1176 gui_mch_add_menu_item(menu
, idx
)
1180 vimmenu_T
*parent
= menu
->parent
;
1183 # ifdef FEAT_TOOLBAR
1184 if (menu_is_toolbar(parent
->name
))
1191 if (menu_is_separator(menu
->name
))
1193 XtSetArg(args
[n
], XtNlabel
, ""); n
++;
1194 XtSetArg(args
[n
], XtNborderWidth
, 0); n
++;
1198 get_toolbar_pixmap(menu
, &menu
->image
);
1199 XtSetArg(args
[n
], XtNlabel
, menu
->dname
); n
++;
1200 XtSetArg(args
[n
], XtNinternalHeight
, 1); n
++;
1201 XtSetArg(args
[n
], XtNinternalWidth
, 1); n
++;
1202 XtSetArg(args
[n
], XtNborderWidth
, 1); n
++;
1203 if (menu
->image
!= 0)
1204 XtSetArg(args
[n
], XtNbitmap
, menu
->image
); n
++;
1206 XtSetArg(args
[n
], XtNhighlightThickness
, 0); n
++;
1207 type
= commandWidgetClass
;
1208 /* TODO: figure out the position in the toolbar?
1209 * This currently works fine for the default toolbar, but
1210 * what if we add/remove items during later runtime?
1213 /* NOTE: "idx" isn't used here. The position is calculated by
1214 * athena_calculate_ins_pos(). The position it calculates
1215 * should be equal to "idx".
1217 /* TODO: Could we just store "idx" and use that as the child
1221 if (menu
->id
== NULL
)
1223 menu
->id
= XtCreateManagedWidget((char *)menu
->dname
,
1224 type
, toolBar
, args
, n
);
1225 XtAddCallback(menu
->id
,
1226 XtNcallback
, gui_x11_menu_cb
, menu
);
1229 XtSetValues(menu
->id
, args
, n
);
1230 gui_athena_menu_colors(menu
->id
);
1233 gui_mch_menu_set_tip(menu
);
1236 menu
->parent
= parent
;
1237 menu
->submenu_id
= NULL
;
1238 if (!XtIsManaged(toolBar
)
1239 && vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1240 gui_mch_show_toolbar(TRUE
);
1241 gui
.toolbar_height
= gui_mch_compute_toolbar_height();
1243 } /* toolbar menu item */
1246 /* Add menu separator */
1247 if (menu_is_separator(menu
->name
))
1249 menu
->submenu_id
= (Widget
)0;
1250 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
1251 smeLineObjectClass
, parent
->submenu_id
,
1253 if (menu
->id
== (Widget
)0)
1255 gui_athena_menu_colors(menu
->id
);
1259 if (parent
!= NULL
&& parent
->submenu_id
!= (Widget
)0)
1261 menu
->submenu_id
= (Widget
)0;
1262 menu
->id
= XtVaCreateManagedWidget((char *)menu
->dname
,
1263 smeBSBObjectClass
, parent
->submenu_id
,
1264 XtNlabel
, menu
->dname
,
1265 #ifdef FONTSET_ALWAYS
1266 XtNinternational
, True
,
1269 if (menu
->id
== (Widget
)0)
1272 /* If there are other "pulldown" items in this pane, then adjust
1273 * the right margin to accomodate the arrow pixmap, otherwise
1274 * the right margin will be the same as the left margin.
1277 Dimension left_margin
;
1279 XtVaGetValues(menu
->id
, XtNleftMargin
, &left_margin
, NULL
);
1280 XtVaSetValues(menu
->id
, XtNrightMargin
,
1281 gui_athena_menu_has_submenus(parent
->submenu_id
, NULL
) ?
1287 gui_athena_menu_colors(menu
->id
);
1288 gui_athena_menu_font(menu
->id
);
1289 XtAddCallback(menu
->id
, XtNcallback
, gui_x11_menu_cb
,
1296 #if defined(FEAT_TOOLBAR) || defined(PROTO)
1298 gui_mch_show_toolbar(int showit
)
1300 Cardinal numChildren
; /* how many children toolBar has */
1302 if (toolBar
== (Widget
)0)
1304 XtVaGetValues(toolBar
, XtNnumChildren
, &numChildren
, NULL
);
1305 if (showit
&& numChildren
> 0)
1307 /* Assume that we want to show the toolbar if p_toolbar contains valid
1308 * option settings, therefore p_toolbar must not be NULL.
1310 WidgetList children
;
1312 XtVaGetValues(toolBar
, XtNchildren
, &children
, NULL
);
1314 void (*action
)(BalloonEval
*);
1317 if (strstr((const char *)p_toolbar
, "tooltips"))
1318 action
= &gui_mch_enable_beval_area
;
1320 action
= &gui_mch_disable_beval_area
;
1321 if (strstr((const char *)p_toolbar
, "text"))
1323 else if (strstr((const char *)p_toolbar
, "icons"))
1330 for (toolbar
= root_menu
; toolbar
; toolbar
= toolbar
->next
)
1331 if (menu_is_toolbar(toolbar
->dname
))
1333 /* Assumption: toolbar is NULL if there is no toolbar,
1334 * otherwise it contains the toolbar menu structure.
1336 * Assumption: "numChildren" == the number of items in the list
1337 * of items beginning with toolbar->children.
1341 for (cur
= toolbar
->children
; cur
; cur
= cur
->next
)
1346 /* Enable/Disable tooltip (OK to enable while currently
1349 if (cur
->tip
!= NULL
)
1350 (*action
)(cur
->tip
);
1353 XtSetArg(args
[n
], XtNbitmap
, None
);
1355 XtSetArg(args
[n
], XtNlabel
,
1356 menu_is_separator(cur
->name
) ? "" :
1357 (char *)cur
->dname
);
1362 XtSetArg(args
[n
], XtNbitmap
, cur
->image
);
1364 XtSetArg(args
[n
], XtNlabel
, (cur
->image
== None
) ?
1365 menu_is_separator(cur
->name
) ?
1372 if (cur
->id
!= NULL
)
1374 XtUnmanageChild(cur
->id
);
1375 XtSetValues(cur
->id
, args
, n
);
1376 XtManageChild(cur
->id
);
1382 gui
.toolbar_height
= gui_mch_compute_toolbar_height();
1383 XtManageChild(toolBar
);
1384 if (XtIsManaged(menuBar
))
1386 XtVaSetValues(textArea
,
1387 XtNvertDistance
, gui
.toolbar_height
+ gui
.menu_height
,
1389 XtVaSetValues(toolBar
,
1390 XtNvertDistance
, gui
.menu_height
,
1395 XtVaSetValues(textArea
,
1396 XtNvertDistance
, gui
.toolbar_height
,
1398 XtVaSetValues(toolBar
,
1405 gui
.toolbar_height
= 0;
1406 if (XtIsManaged(menuBar
))
1407 XtVaSetValues(textArea
,
1408 XtNvertDistance
, gui
.menu_height
,
1411 XtVaSetValues(textArea
,
1415 XtUnmanageChild(toolBar
);
1417 gui_set_shellsize(FALSE
, FALSE
, RESIZE_VERT
);
1422 gui_mch_compute_toolbar_height()
1424 Dimension height
; /* total Toolbar height */
1425 Dimension whgt
; /* height of each widget */
1426 Dimension marginHeight
; /* XmNmarginHeight of toolBar */
1427 Dimension shadowThickness
; /* thickness of Xtparent(toolBar) */
1428 WidgetList children
; /* list of toolBar's children */
1429 Cardinal numChildren
; /* how many children toolBar has */
1433 shadowThickness
= 0;
1435 if (toolBar
!= (Widget
)0)
1437 XtVaGetValues(toolBar
,
1438 XtNborderWidth
, &shadowThickness
,
1439 XtNvSpace
, &marginHeight
,
1440 XtNchildren
, &children
,
1441 XtNnumChildren
, &numChildren
,
1443 for (i
= 0; i
< (int)numChildren
; i
++)
1447 XtVaGetValues(children
[i
], XtNheight
, &whgt
, NULL
);
1453 return (int)(height
+ (marginHeight
<< 1) + (shadowThickness
<< 1));
1457 gui_mch_get_toolbar_colors(bgp
, fgp
, bsp
, tsp
, hsp
)
1464 XtVaGetValues(toolBar
, XtNbackground
, bgp
, XtNborderColor
, fgp
, NULL
);
1473 gui_mch_toggle_tearoffs(enable
)
1476 /* no tearoff menus */
1480 gui_mch_new_menu_colors()
1482 if (menuBar
== (Widget
)0)
1484 if (gui
.menu_fg_pixel
!= INVALCOLOR
)
1485 XtVaSetValues(menuBar
, XtNborderColor
, gui
.menu_fg_pixel
, NULL
);
1486 gui_athena_menu_colors(menuBar
);
1488 gui_athena_menu_colors(toolBar
);
1491 gui_mch_submenu_change(root_menu
, TRUE
);
1495 * Destroy the machine specific menu widget.
1498 gui_mch_destroy_menu(menu
)
1503 /* There is no item for the toolbar. */
1504 if (menu
->id
== (Widget
)0)
1507 parent
= XtParent(menu
->id
);
1509 /* When removing the last "pulldown" menu item from a pane, adjust the
1510 * right margins of the remaining widgets.
1512 if (menu
->submenu_id
!= (Widget
)0)
1514 /* Go through the menu items in the parent of this item and
1515 * adjust their margins, if necessary.
1516 * This takes care of the case when we delete the last menu item in a
1517 * pane that has a submenu. In this case, there will be no arrow
1518 * pixmaps shown anymore.
1521 WidgetList children
;
1522 Cardinal num_children
;
1524 Dimension right_margin
= 0;
1525 Boolean get_left_margin
= False
;
1527 XtVaGetValues(parent
, XtNchildren
, &children
,
1528 XtNnumChildren
, &num_children
,
1530 if (gui_athena_menu_has_submenus(parent
, menu
->id
))
1531 right_margin
= puller_width
;
1533 get_left_margin
= True
;
1535 for (i
= 0; i
< (int)num_children
; ++i
)
1537 if (children
[i
] == menu
->id
)
1539 if (get_left_margin
== True
)
1541 Dimension left_margin
;
1543 XtVaGetValues(children
[i
], XtNleftMargin
, &left_margin
,
1545 XtVaSetValues(children
[i
], XtNrightMargin
, left_margin
,
1549 XtVaSetValues(children
[i
], XtNrightMargin
, right_margin
,
1554 /* Please be sure to destroy the parent widget first (i.e. menu->id).
1556 * This code should be basically identical to that in the file gui_motif.c
1557 * because they are both Xt based.
1559 if (menu
->id
!= (Widget
)0)
1561 Cardinal num_children
;
1562 Dimension height
, space
, border
;
1564 XtVaGetValues(menuBar
,
1566 XtNborderWidth
, &border
,
1568 XtVaGetValues(menu
->id
,
1571 #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
1572 if (parent
== toolBar
&& menu
->tip
!= NULL
)
1574 /* We try to destroy this before the actual menu, because there are
1575 * callbacks, etc. that will be unregistered during the tooltip
1578 * If you call "gui_mch_destroy_beval_area()" after destroying
1579 * menu->id, then the tooltip's window will have already been
1580 * deallocated by Xt, and unknown behaviour will ensue (probably
1583 gui_mch_destroy_beval_area(menu
->tip
);
1588 * This is a hack to stop the Athena simpleMenuWidget from getting a
1589 * BadValue error when a menu's last child is destroyed. We check to
1590 * see if this is the last child and if so, don't delete it. The parent
1591 * will be deleted soon anyway, and it will delete it's children like
1592 * all good widgets do.
1594 /* NOTE: The cause of the BadValue X Protocol Error is because when the
1595 * last child is destroyed, it is first unmanaged, thus causing a
1596 * geometry resize request from the parent Shell widget.
1597 * Since the Shell widget has no more children, it is resized to have
1598 * width/height of 0. XConfigureWindow() is then called with the
1599 * width/height of 0, which generates the BadValue.
1601 * This happens in phase two of the widget destruction process.
1604 if (parent
!= menuBar
1606 && parent
!= toolBar
1610 XtVaGetValues(parent
, XtNnumChildren
, &num_children
, NULL
);
1611 if (num_children
> 1)
1612 XtDestroyWidget(menu
->id
);
1615 XtDestroyWidget(menu
->id
);
1616 menu
->id
= (Widget
)0;
1619 if (parent
== menuBar
)
1621 if (!gui
.menu_height_fixed
)
1622 gui
.menu_height
= height
+ 2 * (space
+ border
);
1625 else if (parent
== toolBar
)
1627 /* When removing last toolbar item, don't display the toolbar. */
1628 XtVaGetValues(toolBar
, XtNnumChildren
, &num_children
, NULL
);
1629 if (num_children
== 0)
1630 gui_mch_show_toolbar(FALSE
);
1632 gui
.toolbar_height
= gui_mch_compute_toolbar_height();
1636 if (menu
->submenu_id
!= (Widget
)0)
1638 XtDestroyWidget(menu
->submenu_id
);
1639 menu
->submenu_id
= (Widget
)0;
1644 gui_athena_menu_timeout(client_data
, id
)
1645 XtPointer client_data
;
1646 XtIntervalId
*id UNUSED
;
1648 Widget w
= (Widget
)client_data
;
1652 if (XtIsSubclass(w
,smeBSBObjectClass
))
1656 XtVaGetValues(w
, XtNrightBitmap
, &p
, NULL
);
1657 if ((p
!= None
) && (p
!= XtUnspecifiedPixmap
))
1659 /* We are dealing with an item that has a submenu */
1660 popup
= get_popup_entry(XtParent(w
));
1661 if (popup
== (Widget
)0)
1663 XtPopup(popup
, XtGrabNonexclusive
);
1668 /* This routine is used to calculate the position (in screen coordinates)
1669 * where a submenu should appear relative to the menu entry that popped it
1670 * up. It should appear even with and just slightly to the left of the
1671 * rightmost end of the menu entry that caused the popup.
1673 * This is called when XtPopup() is called.
1676 gui_athena_popup_callback(w
, client_data
, call_data
)
1678 XtPointer client_data
;
1679 XtPointer call_data UNUSED
;
1681 /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
1682 vimmenu_T
*menu
= (vimmenu_T
*)client_data
;
1684 Position root_x
, root_y
;
1686 /* First, popdown any siblings that may have menus popped up */
1690 for (i
= menu
->parent
->children
; i
!= NULL
; i
= i
->next
)
1692 if (i
->submenu_id
!= NULL
&& XtIsManaged(i
->submenu_id
))
1693 XtPopdown(i
->submenu_id
);
1696 XtVaGetValues(XtParent(w
),
1699 /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */
1700 /* i.e. This IS the active entry */
1701 XtTranslateCoords(menu
->id
,width
- 5, 0, &root_x
, &root_y
);
1702 XtVaSetValues(w
, XtNx
, root_x
,
1708 gui_athena_popdown_submenus_action(w
, event
, args
, nargs
)
1714 WidgetList children
;
1715 Cardinal num_children
;
1717 XtVaGetValues(w
, XtNchildren
, &children
,
1718 XtNnumChildren
, &num_children
,
1720 for (; num_children
> 0; --num_children
)
1722 Widget child
= children
[num_children
- 1];
1724 if (has_submenu(child
))
1728 temp_w
= submenu_widget(child
);
1729 gui_athena_popdown_submenus_action(temp_w
,event
,args
,nargs
);
1735 /* Used to determine if the given widget has a submenu that can be popped up. */
1740 if ((widget
!= NULL
) && XtIsSubclass(widget
,smeBSBObjectClass
))
1744 XtVaGetValues(widget
, XtNrightBitmap
, &p
, NULL
);
1745 if ((p
!= None
) && (p
!= XtUnspecifiedPixmap
))
1752 gui_athena_delayed_arm_action(w
, event
, args
, nargs
)
1758 Dimension width
, height
;
1760 if (event
->type
!= MotionNotify
)
1768 if (event
->xmotion
.x
>= (int)width
|| event
->xmotion
.y
>= (int)height
)
1772 static Widget previous_active_widget
= NULL
;
1775 current
= XawSimpleMenuGetActiveEntry(w
);
1776 if (current
!= previous_active_widget
)
1780 /* If the timeout hasn't been triggered, remove it */
1781 XtRemoveTimeOut(timer
);
1783 gui_athena_popdown_submenus_action(w
,event
,args
,nargs
);
1784 if (has_submenu(current
))
1786 XtAppAddTimeOut(XtWidgetToApplicationContext(w
), 600L,
1787 gui_athena_menu_timeout
,
1788 (XtPointer
)current
);
1790 previous_active_widget
= current
;
1801 /* Get the active entry for the current menu */
1802 if ((menuw
= XawSimpleMenuGetActiveEntry(w
)) == (Widget
)0)
1805 return submenu_widget(menuw
);
1808 /* Given the widget that has been determined to have a submenu, return the submenu widget
1809 * that is to be popped up.
1812 submenu_widget(widget
)
1815 /* Precondition: has_submenu(widget) == True
1816 * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
1819 char_u
*pullright_name
;
1822 pullright_name
= make_pull_name((char_u
*)XtName(widget
));
1823 popup
= XtNameToWidget(XtParent(widget
), (char *)pullright_name
);
1824 vim_free(pullright_name
);
1827 /* Postcondition: (popup != NULL) implies
1828 * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
1832 gui_mch_show_popupmenu(menu
)
1835 int rootx
, rooty
, winx
, winy
;
1839 if (menu
->submenu_id
== (Widget
)0)
1842 /* Position the popup menu at the pointer */
1843 if (XQueryPointer(gui
.dpy
, XtWindow(vimShell
), &root
, &child
,
1844 &rootx
, &rooty
, &winx
, &winy
, &mask
))
1852 XtVaSetValues(menu
->submenu_id
,
1858 XtOverrideTranslations(menu
->submenu_id
, popupTrans
);
1859 XtPopupSpringLoaded(menu
->submenu_id
);
1862 #endif /* FEAT_MENU */
1865 * Set the menu and scrollbar colors to their default values.
1868 gui_mch_def_colors()
1871 * Get the colors ourselves. Using the automatic conversion doesn't
1872 * handle looking for approximate colors.
1876 gui
.menu_fg_pixel
= gui_get_color((char_u
*)gui
.rsrc_menu_fg_name
);
1877 gui
.menu_bg_pixel
= gui_get_color((char_u
*)gui
.rsrc_menu_bg_name
);
1878 gui
.scroll_fg_pixel
= gui_get_color((char_u
*)gui
.rsrc_scroll_fg_name
);
1879 gui
.scroll_bg_pixel
= gui_get_color((char_u
*)gui
.rsrc_scroll_bg_name
);
1881 gui
.tooltip_fg_pixel
= gui_get_color((char_u
*)gui
.rsrc_tooltip_fg_name
);
1882 gui
.tooltip_bg_pixel
= gui_get_color((char_u
*)gui
.rsrc_tooltip_bg_name
);
1893 gui_mch_set_scrollbar_thumb(sb
, val
, size
, max
)
1901 if (sb
->id
== (Widget
)0)
1905 * Athena scrollbar must go from 0.0 to 1.0.
1909 /* So you can't scroll it at all (normally it scrolls past end) */
1910 #ifdef FEAT_GUI_NEXTAW
1911 XawScrollbarSetThumb(sb
->id
, 0.0, 1.0);
1913 vim_XawScrollbarSetThumb(sb
->id
, 0.0, 1.0, 0.0);
1918 v
= (double)val
/ (double)(max
+ 1);
1919 s
= (double)size
/ (double)(max
+ 1);
1920 #ifdef FEAT_GUI_NEXTAW
1921 XawScrollbarSetThumb(sb
->id
, v
, s
);
1923 vim_XawScrollbarSetThumb(sb
->id
, v
, s
, 1.0);
1929 gui_mch_set_scrollbar_pos(sb
, x
, y
, w
, h
)
1936 if (sb
->id
== (Widget
)0)
1939 XtUnmanageChild(sb
->id
);
1940 XtVaSetValues(sb
->id
,
1941 XtNhorizDistance
, x
,
1946 XtManageChild(sb
->id
);
1950 gui_mch_enable_scrollbar(sb
, flag
)
1954 if (sb
->id
!= (Widget
)0)
1957 XtManageChild(sb
->id
);
1959 XtUnmanageChild(sb
->id
);
1964 gui_mch_create_scrollbar(sb
, orient
)
1966 int orient
; /* SBAR_VERT or SBAR_HORIZ */
1968 sb
->id
= XtVaCreateWidget("scrollBar",
1969 #ifdef FEAT_GUI_NEXTAW
1970 scrollbarWidgetClass
, vimForm
,
1972 vim_scrollbarWidgetClass
, vimForm
,
1976 XtNbottom
, XtChainTop
,
1977 XtNleft
, XtChainLeft
,
1978 XtNright
, XtChainLeft
,
1980 XtNorientation
, (orient
== SBAR_VERT
) ? XtorientVertical
1981 : XtorientHorizontal
,
1982 XtNforeground
, gui
.scroll_fg_pixel
,
1983 XtNbackground
, gui
.scroll_bg_pixel
,
1985 if (sb
->id
== (Widget
)0)
1988 XtAddCallback(sb
->id
, XtNjumpProc
,
1989 gui_athena_scroll_cb_jump
, (XtPointer
)sb
->ident
);
1990 XtAddCallback(sb
->id
, XtNscrollProc
,
1991 gui_athena_scroll_cb_scroll
, (XtPointer
)sb
->ident
);
1993 #ifdef FEAT_GUI_NEXTAW
1994 XawScrollbarSetThumb(sb
->id
, 0.0, 1.0);
1996 vim_XawScrollbarSetThumb(sb
->id
, 0.0, 1.0, 0.0);
2000 #if defined(FEAT_WINDOWS) || defined(PROTO)
2002 gui_mch_destroy_scrollbar(sb
)
2005 if (sb
->id
!= (Widget
)0)
2006 XtDestroyWidget(sb
->id
);
2011 gui_mch_set_scrollbar_colors(sb
)
2014 if (sb
->id
!= (Widget
)0)
2015 XtVaSetValues(sb
->id
,
2016 XtNforeground
, gui
.scroll_fg_pixel
,
2017 XtNbackground
, gui
.scroll_bg_pixel
,
2020 /* This is needed for the rectangle below the vertical scrollbars. */
2021 if (sb
== &gui
.bottom_sbar
&& vimForm
!= (Widget
)0)
2022 gui_athena_scroll_colors(vimForm
);
2026 * Miscellaneous stuff:
2031 return XtWindow(textArea
);
2034 #if defined(FEAT_BROWSE) || defined(PROTO)
2036 * Put up a file requester.
2037 * Returns the selected name in allocated memory, or NULL for Cancel.
2040 gui_mch_browse(saving
, title
, dflt
, ext
, initdir
, filter
)
2041 int saving UNUSED
; /* select file to write */
2042 char_u
*title
; /* title for the window */
2043 char_u
*dflt
; /* default name */
2044 char_u
*ext UNUSED
; /* extension added */
2045 char_u
*initdir
; /* initial directory, NULL for current dir */
2046 char_u
*filter UNUSED
; /* file name filter */
2049 char_u dirbuf
[MAXPATHL
];
2051 /* Concatenate "initdir" and "dflt". */
2052 if (initdir
== NULL
|| *initdir
== NUL
)
2053 mch_dirname(dirbuf
, MAXPATHL
);
2054 else if (STRLEN(initdir
) + 2 < MAXPATHL
)
2055 STRCPY(dirbuf
, initdir
);
2058 if (dflt
!= NULL
&& *dflt
!= NUL
2059 && STRLEN(dirbuf
) + 2 + STRLEN(dflt
) < MAXPATHL
)
2061 add_pathsep(dirbuf
);
2062 STRCAT(dirbuf
, dflt
);
2065 /* Position the file selector just below the menubar */
2066 XtTranslateCoords(vimShell
, (Position
)0, (Position
)
2073 return (char_u
*)vim_SelFile(vimShell
, (char *)title
, (char *)dirbuf
,
2074 NULL
, (int)x
, (int)y
, gui
.menu_fg_pixel
, gui
.menu_bg_pixel
,
2075 gui
.scroll_fg_pixel
, gui
.scroll_bg_pixel
);
2079 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2081 static int dialogStatus
;
2082 static Atom dialogatom
;
2084 static void keyhit_callback
__ARGS((Widget w
, XtPointer client_data
, XEvent
*event
, Boolean
*cont
));
2085 static void butproc
__ARGS((Widget w
, XtPointer client_data
, XtPointer call_data
));
2086 static void dialog_wm_handler
__ARGS((Widget w
, XtPointer client_data
, XEvent
*event
, Boolean
*dum
));
2089 * Callback function for the textfield. When CR is hit this works like
2090 * hitting the "OK" button, ESC like "Cancel".
2093 keyhit_callback(w
, client_data
, event
, cont
)
2095 XtPointer client_data UNUSED
;
2097 Boolean
*cont UNUSED
;
2101 if (XLookupString(&(event
->xkey
), buf
, 2, NULL
, NULL
) == 1)
2105 else if (*buf
== ESC
)
2111 butproc(w
, client_data
, call_data
)
2113 XtPointer client_data
;
2114 XtPointer call_data UNUSED
;
2116 dialogStatus
= (int)(long)client_data
+ 1;
2120 * Function called when dialog window closed.
2123 dialog_wm_handler(w
, client_data
, event
, dum
)
2125 XtPointer client_data UNUSED
;
2127 Boolean
*dum UNUSED
;
2129 if (event
->type
== ClientMessage
2130 && (Atom
)((XClientMessageEvent
*)event
)->data
.l
[0] == dialogatom
)
2135 gui_mch_dialog(type
, title
, message
, buttons
, dfltbutton
, textfield
)
2140 int dfltbutton UNUSED
;
2152 Widget dialogmessage
;
2153 Widget dialogtextfield
= 0;
2154 Widget dialogButton
;
2155 Widget prev_dialogButton
= NULL
;
2160 title
= (char_u
*)_("Vim dialog");
2163 /* if our pointer is currently hidden, then we should show it. */
2164 gui_mch_mousehide(FALSE
);
2166 /* Check 'v' flag in 'guioptions': vertical button placement. */
2167 vertical
= (vim_strchr(p_go
, GO_VERTICAL
) != NULL
);
2169 /* The shell is created each time, to make sure it is resized properly */
2170 dialogshell
= XtVaCreatePopupShell("dialogShell",
2171 transientShellWidgetClass
, vimShell
,
2174 if (dialogshell
== (Widget
)0)
2177 dialog
= XtVaCreateManagedWidget("dialog",
2178 formWidgetClass
, dialogshell
,
2179 XtNdefaultDistance
, 20,
2181 if (dialog
== (Widget
)0)
2183 gui_athena_menu_colors(dialog
);
2184 dialogmessage
= XtVaCreateManagedWidget("dialogMessage",
2185 labelWidgetClass
, dialog
,
2188 XtNbottom
, XtChainTop
,
2189 XtNleft
, XtChainLeft
,
2190 XtNright
, XtChainLeft
,
2194 gui_athena_menu_colors(dialogmessage
);
2196 if (textfield
!= NULL
)
2198 dialogtextfield
= XtVaCreateManagedWidget("textfield",
2199 asciiTextWidgetClass
, dialog
,
2202 XtNbottom
, XtChainTop
,
2203 XtNleft
, XtChainLeft
,
2204 XtNright
, XtChainRight
,
2205 XtNfromVert
, dialogmessage
,
2207 XtNstring
, textfield
,
2209 XtNuseStringInPlace
, True
,
2210 XtNeditType
, XawtextEdit
,
2211 XtNwrap
, XawtextWrapNever
,
2212 XtNresize
, XawtextResizeHeight
,
2214 XtManageChild(dialogtextfield
);
2215 XtAddEventHandler(dialogtextfield
, KeyPressMask
, False
,
2216 (XtEventHandler
)keyhit_callback
, (XtPointer
)NULL
);
2217 XawTextSetInsertionPoint(dialogtextfield
,
2218 (XawTextPosition
)STRLEN(textfield
));
2219 XtSetKeyboardFocus(dialog
, dialogtextfield
);
2222 /* make a copy, so that we can insert NULs */
2223 buts
= vim_strsave(buttons
);
2228 for (butcount
= 0; *p
; ++butcount
)
2230 for (next
= p
; *next
; ++next
)
2232 if (*next
== DLG_HOTKEY_CHAR
)
2233 STRMOVE(next
, next
+ 1);
2234 if (*next
== DLG_BUTTON_SEP
)
2240 dialogButton
= XtVaCreateManagedWidget("button",
2241 commandWidgetClass
, dialog
,
2243 XtNtop
, XtChainBottom
,
2244 XtNbottom
, XtChainBottom
,
2245 XtNleft
, XtChainLeft
,
2246 XtNright
, XtChainLeft
,
2247 XtNfromVert
, textfield
== NULL
? dialogmessage
: dialogtextfield
,
2248 XtNvertDistance
, vertical
? 4 : 20,
2249 XtNresizable
, False
,
2251 gui_athena_menu_colors(dialogButton
);
2253 XtVaSetValues(dialogButton
,
2254 vertical
? XtNfromVert
: XtNfromHoriz
, prev_dialogButton
,
2257 XtAddCallback(dialogButton
, XtNcallback
, butproc
, (XtPointer
)butcount
);
2259 prev_dialogButton
= dialogButton
;
2263 XtRealizeWidget(dialogshell
);
2265 /* Setup for catching the close-window event, don't let it close Vim! */
2266 dialogatom
= XInternAtom(gui
.dpy
, "WM_DELETE_WINDOW", False
);
2267 XSetWMProtocols(gui
.dpy
, XtWindow(dialogshell
), &dialogatom
, 1);
2268 XtAddEventHandler(dialogshell
, NoEventMask
, True
, dialog_wm_handler
, NULL
);
2270 XtVaGetValues(dialogshell
,
2274 XtVaGetValues(vimShell
,
2278 XtTranslateCoords(vimShell
,
2279 (Position
)((wv
- wd
) / 2),
2280 (Position
)((hv
- hd
) / 2),
2286 XtVaSetValues(dialogshell
, XtNx
, x
, XtNy
, y
, NULL
);
2288 /* Position the mouse pointer in the dialog, required for when focus
2290 XWarpPointer(gui
.dpy
, (Window
)0, XtWindow(dialogshell
), 0, 0, 0, 0, 20, 40);
2293 app
= XtWidgetToApplicationContext(dialogshell
);
2295 XtPopup(dialogshell
, XtGrabNonexclusive
);
2299 XtAppNextEvent(app
, &event
);
2300 XtDispatchEvent(&event
);
2301 if (dialogStatus
>= 0)
2305 XtPopdown(dialogshell
);
2307 if (textfield
!= NULL
&& dialogStatus
< 0)
2311 XtDestroyWidget(dialogshell
);
2313 return dialogStatus
;
2317 #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
2319 * Set the colors of Widget "id" to the menu colors.
2322 gui_athena_menu_colors(id
)
2325 if (gui
.menu_bg_pixel
!= INVALCOLOR
)
2326 XtVaSetValues(id
, XtNbackground
, gui
.menu_bg_pixel
, NULL
);
2327 if (gui
.menu_fg_pixel
!= INVALCOLOR
)
2328 XtVaSetValues(id
, XtNforeground
, gui
.menu_fg_pixel
, NULL
);
2333 * Set the colors of Widget "id" to the scroll colors.
2336 gui_athena_scroll_colors(id
)
2339 if (gui
.scroll_bg_pixel
!= INVALCOLOR
)
2340 XtVaSetValues(id
, XtNbackground
, gui
.scroll_bg_pixel
, NULL
);
2341 if (gui
.scroll_fg_pixel
!= INVALCOLOR
)
2342 XtVaSetValues(id
, XtNforeground
, gui
.scroll_fg_pixel
, NULL
);