home *** CD-ROM | disk | FTP | other *** search
- /* vi:set ts=8 sts=4 sw=4:
- *
- * VIM - Vi IMproved by Bram Moolenaar
- * GUI/Motif support by Robert Webb
- * Athena port by Bill Foster
- *
- * Do ":help uganda" in Vim to read copying and usage conditions.
- * Do ":help credits" in Vim to see a list of people who contributed.
- * See README.txt for an overview of the Vim source code.
- */
-
- #include <X11/StringDefs.h>
- #include <X11/Intrinsic.h>
- #ifdef FEAT_GUI_NEXTAW
- # include <X11/neXtaw/Form.h>
- # include <X11/neXtaw/SimpleMenu.h>
- # include <X11/neXtaw/MenuButton.h>
- # include <X11/neXtaw/SmeBSB.h>
- # include <X11/neXtaw/SmeLine.h>
- # include <X11/neXtaw/Box.h>
- # include <X11/neXtaw/Dialog.h>
- # include <X11/neXtaw/Text.h>
- # include <X11/neXtaw/AsciiText.h>
- # include <X11/neXtaw/Scrollbar.h>
- #else
- # include <X11/Xaw/Form.h>
- # include <X11/Xaw/SimpleMenu.h>
- # include <X11/Xaw/MenuButton.h>
- # include <X11/Xaw/SmeBSB.h>
- # include <X11/Xaw/SmeLine.h>
- # include <X11/Xaw/Box.h>
- # include <X11/Xaw/Dialog.h>
- # include <X11/Xaw/Text.h>
- # include <X11/Xaw/AsciiText.h>
- #endif /* FEAT_GUI_NEXTAW */
-
- #include "vim.h"
- #ifndef FEAT_GUI_NEXTAW
- # include "gui_at_sb.h"
- #endif
-
- extern Widget vimShell;
-
- static Widget vimForm = (Widget)0;
- static Widget textArea = (Widget)0;
- #ifdef FEAT_MENU
- static Widget menuBar = (Widget)0;
- static XtIntervalId timer = 0; /* 0 = expired, otherwise active */
-
- /* Used to figure out menu ordering */
- static vimmenu_T *a_cur_menu = NULL;
- static Cardinal athena_calculate_ins_pos __ARGS((Widget));
-
- static Pixmap gui_athena_create_pullright_pixmap __ARGS((Widget));
- static void gui_athena_menu_timeout __ARGS((XtPointer, XtIntervalId *));
- static void gui_athena_popup_callback __ARGS((Widget, XtPointer, XtPointer));
- static void gui_athena_delayed_arm_action __ARGS((Widget, XEvent *, String *,
- Cardinal *));
- static void gui_athena_popdown_submenus_action __ARGS((Widget, XEvent *,
- String *, Cardinal *));
- static XtActionsRec pullAction[2] = {
- { "menu-delayedpopup", (XtActionProc)gui_athena_delayed_arm_action},
- { "menu-popdownsubmenus", (XtActionProc)gui_athena_popdown_submenus_action}
- };
- #endif
-
- #ifdef FEAT_TOOLBAR
- static void gui_mch_reset_focus __ARGS((void));
- static Widget toolBar = (Widget)0;
- #endif
-
- static void gui_athena_scroll_cb_jump __ARGS((Widget, XtPointer, XtPointer));
- static void gui_athena_scroll_cb_scroll __ARGS((Widget, XtPointer, XtPointer));
- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
- static void gui_athena_menu_colors __ARGS((Widget id));
- #endif
- static void gui_athena_scroll_colors __ARGS((Widget id));
-
- #ifdef FEAT_MENU
- static XtTranslations popupTrans, parentTrans, menuTrans, supermenuTrans;
- static Pixmap pullerBitmap = None;
- static int puller_width = 0;
- #endif
-
- /*
- * Scrollbar callback (XtNjumpProc) for when the scrollbar is dragged with the
- * left or middle mouse button.
- */
- /* ARGSUSED */
- static void
- gui_athena_scroll_cb_jump(w, client_data, call_data)
- Widget w;
- XtPointer client_data, call_data;
- {
- scrollbar_T *sb, *sb_info;
- long value;
-
- sb = gui_find_scrollbar((long)client_data);
-
- if (sb == NULL)
- return;
- else if (sb->wp != NULL) /* Left or right scrollbar */
- {
- /*
- * Careful: need to get scrollbar info out of first (left) scrollbar
- * for window, but keep real scrollbar too because we must pass it to
- * gui_drag_scrollbar().
- */
- sb_info = &sb->wp->w_scrollbars[0];
- }
- else /* Bottom scrollbar */
- sb_info = sb;
-
- value = (long)(*((float *)call_data) * (float)(sb_info->max + 1) + 0.001);
- if (value > sb_info->max)
- value = sb_info->max;
-
- gui_drag_scrollbar(sb, value, TRUE);
- }
-
- /*
- * Scrollbar callback (XtNscrollProc) for paging up or down with the left or
- * right mouse buttons.
- */
- /* ARGSUSED */
- static void
- gui_athena_scroll_cb_scroll(w, client_data, call_data)
- Widget w;
- XtPointer client_data, call_data;
- {
- scrollbar_T *sb, *sb_info;
- long value;
- int data = (int)(long)call_data;
- int page;
-
- sb = gui_find_scrollbar((long)client_data);
-
- if (sb == NULL)
- return;
- if (sb->wp != NULL) /* Left or right scrollbar */
- {
- /*
- * Careful: need to get scrollbar info out of first (left) scrollbar
- * for window, but keep real scrollbar too because we must pass it to
- * gui_drag_scrollbar().
- */
- sb_info = &sb->wp->w_scrollbars[0];
-
- if (sb_info->size > 5)
- page = sb_info->size - 2; /* use two lines of context */
- else
- page = sb_info->size;
- #ifdef FEAT_GUI_NEXTAW
- if (data < 0)
- {
- data = (data - gui.char_height + 1) / gui.char_height;
- if (data > -sb_info->size)
- data = -1;
- else
- data = -page;
- }
- else if (data > 0)
- {
- data = (data + gui.char_height - 1) / gui.char_height;
- if (data < sb_info->size)
- data = 1;
- else
- data = page;
- }
- #else
- switch (data)
- {
- case ONE_LINE_DATA: data = 1; break;
- case -ONE_LINE_DATA: data = -1; break;
- case ONE_PAGE_DATA: data = page; break;
- case -ONE_PAGE_DATA: data = -page; break;
- case END_PAGE_DATA: data = sb_info->max; break;
- case -END_PAGE_DATA: data = -sb_info->max; break;
- default: data = 0; break;
- }
- #endif
- }
- else /* Bottom scrollbar */
- {
- sb_info = sb;
- #ifdef FEAT_GUI_NEXTAW
- if (data < 0)
- {
- data = (data - gui.char_width + 1) / gui.char_width;
- if (data > -sb->size)
- data = -1;
- }
- else if (data > 0)
- {
- data = (data + gui.char_width - 1) / gui.char_width;
- if (data < sb->size)
- data = 1;
- }
- #endif
- if (data < -1) /* page-width left */
- {
- if (sb->size > 8)
- data = -(sb->size - 5);
- else
- data = -sb->size;
- }
- else if (data > 1) /* page-width right */
- {
- if (sb->size > 8)
- data = (sb->size - 5);
- else
- data = sb->size;
- }
- }
-
- value = sb_info->value + data;
- if (value > sb_info->max)
- value = sb_info->max;
- else if (value < 0)
- value = 0;
-
- /* Update the bottom scrollbar an extra time (why is this needed?? */
- if (sb->wp == NULL) /* Bottom scrollbar */
- gui_mch_set_scrollbar_thumb(sb, value, sb->size, sb->max);
-
- gui_drag_scrollbar(sb, value, FALSE);
- }
-
- /*
- * Create all the Athena widgets necessary.
- */
- void
- gui_x11_create_widgets()
- {
- /*
- * We don't have any borders handled internally by the textArea to worry
- * about so only skip over the configured border width.
- */
- gui.border_offset = gui.border_width;
-
- #if 0 /* not needed? */
- XtInitializeWidgetClass(formWidgetClass);
- XtInitializeWidgetClass(boxWidgetClass);
- XtInitializeWidgetClass(coreWidgetClass);
- #ifdef FEAT_MENU
- XtInitializeWidgetClass(menuButtonWidgetClass);
- #endif
- XtInitializeWidgetClass(simpleMenuWidgetClass);
- #ifdef FEAT_GUI_NEXTAW
- XtInitializeWidgetClass(scrollbarWidgetClass);
- #else
- XtInitializeWidgetClass(vim_scrollbarWidgetClass);
- #endif
- #endif
-
- /* The form containing all the other widgets */
- vimForm = XtVaCreateManagedWidget("vimForm",
- formWidgetClass, vimShell,
- XtNborderWidth, 0,
- NULL);
- gui_athena_scroll_colors(vimForm);
-
- #ifdef FEAT_MENU
- /* The top menu bar */
- menuBar = XtVaCreateManagedWidget("menuBar",
- boxWidgetClass, vimForm,
- XtNresizable, True,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainRight,
- XtNinsertPosition, athena_calculate_ins_pos,
- NULL);
- gui_athena_menu_colors(menuBar);
- if (gui.menu_fg_pixel != INVALCOLOR)
- XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
- #endif
-
- #ifdef FEAT_TOOLBAR
- /* Don't create it Managed, it will be managed when creating the first
- * item. Otherwise an empty toolbar shows up. */
- toolBar = XtVaCreateWidget("toolBar",
- boxWidgetClass, vimForm,
- XtNresizable, True,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainRight,
- XtNorientation, XtorientHorizontal,
- XtNhSpace, 1,
- XtNvSpace, 3,
- XtNinsertPosition, athena_calculate_ins_pos,
- NULL);
- gui_athena_menu_colors(toolBar);
- #endif
-
- /* The text area. */
- textArea = XtVaCreateManagedWidget("textArea",
- coreWidgetClass, vimForm,
- XtNresizable, True,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainLeft,
- XtNbackground, gui.back_pixel,
- XtNborderWidth, 0,
- NULL);
-
- /*
- * Install the callbacks.
- */
- gui_x11_callbacks(textArea, vimForm);
-
- #ifdef FEAT_MENU
- popupTrans = XtParseTranslationTable(
- "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
- "<LeaveWindow>: unhighlight()\n"
- "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
- "<Motion>: highlight() menu-delayedpopup()");
- parentTrans = XtParseTranslationTable("<LeaveWindow>: unhighlight()");
- menuTrans = XtParseTranslationTable(
- "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
- "<LeaveWindow>: menu-popdownsubmenus() XtMenuPopdown() unhighlight()\n"
- "<BtnUp>: notify() unhighlight()\n"
- "<BtnMotion>: highlight() menu-delayedpopup()");
- supermenuTrans = XtParseTranslationTable(
- "<EnterWindow>: menu-popdownsubmenus() highlight() menu-delayedpopup()\n"
- "<LeaveWindow>: unhighlight()\n"
- "<BtnUp>: menu-popdownsubmenus() XtMenuPopdown() notify() unhighlight()\n"
- "<BtnMotion>: highlight() menu-delayedpopup()");
-
- XtAppAddActions(XtWidgetToApplicationContext(vimForm), pullAction,
- XtNumber(pullAction));
- #endif
-
- /* Pretend we don't have input focus, we will get an event if we do. */
- gui.in_focus = FALSE;
- }
-
- #ifdef FEAT_MENU
- /*
- * Calculates the Pixmap based on the size of the current menu font.
- */
- static Pixmap
- gui_athena_create_pullright_pixmap(w)
- Widget w;
- {
- Pixmap retval;
- #ifdef FONTSET_ALWAYS
- XFontSet font = None;
- #else
- XFontStruct *font = NULL;
- #endif
-
- #ifdef FONTSET_ALWAYS
- if (gui.menu_fontset == NOFONTSET)
- #else
- if (gui.menu_font == NOFONT)
- #endif
- {
- XrmValue from, to;
- WidgetList children;
- Cardinal num_children;
-
- #ifdef FONTSET_ALWAYS
- from.size = strlen(from.addr = XtDefaultFontSet);
- to.addr = (XtPointer)&font;
- to.size = sizeof(XFontSet);
- #else
- from.size = strlen(from.addr = XtDefaultFont);
- to.addr = (XtPointer)&font;
- to.size = sizeof(XFontStruct *);
- #endif
- /* Assumption: The menuBar children will use the same font as the
- * pulldown menu items AND they will all be of type
- * XtNfont.
- */
- XtVaGetValues(menuBar, XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
- if (XtConvertAndStore(w ? w :
- (num_children > 0) ? children[0] : menuBar,
- XtRString, &from,
- #ifdef FONTSET_ALWAYS
- XtRFontSet, &to
- #else
- XtRFontStruct, &to
- #endif
- ) == False)
- return None;
- /* "font" should now contain data */
- }
- else
- #ifdef FONTSET_ALWAYS
- font = (XFontSet)gui.menu_fontset;
- #else
- font = (XFontStruct *)gui.menu_font;
- #endif
-
- {
- int width, height;
- GC draw_gc, undraw_gc;
- XGCValues gc_values;
- XPoint points[3];
-
- #ifdef FONTSET_ALWAYS
- height = fontset_height2(font);
- #else
- height = font->max_bounds.ascent + font->max_bounds.descent;
- #endif
- width = height - 2;
- puller_width = width + 4;
- retval = XCreatePixmap(gui.dpy,DefaultRootWindow(gui.dpy),width,
- height, 1);
- gc_values.foreground = 1;
- gc_values.background = 0;
- draw_gc = XCreateGC(gui.dpy, retval,
- GCForeground | GCBackground,
- &gc_values);
- gc_values.foreground = 0;
- gc_values.background = 1;
- undraw_gc = XCreateGC(gui.dpy, retval,
- GCForeground | GCBackground,
- &gc_values);
- points[0].x = 0;
- points[0].y = 0;
- points[1].x = width - 1;
- points[1].y = (height - 1) / 2;
- points[2].x = 0;
- points[2].y = height - 1;
- XFillRectangle(gui.dpy, retval, undraw_gc, 0, 0, height, height);
- XFillPolygon(gui.dpy, retval, draw_gc, points, XtNumber(points),
- Convex, CoordModeOrigin);
- XFreeGC(gui.dpy, draw_gc);
- XFreeGC(gui.dpy, undraw_gc);
- }
- return retval;
- }
- #endif
-
- /*
- * Called when the GUI is not going to start after all.
- */
- void
- gui_x11_destroy_widgets()
- {
- textArea = NULL;
- #ifdef FEAT_MENU
- menuBar = NULL;
- #endif
- #ifdef FEAT_TOOLBAR
- toolBar = NULL;
- #endif
- }
-
- #if defined(FEAT_TOOLBAR) || defined(PROTO)
- void
- gui_mch_set_toolbar_pos(x, y, w, h)
- int x;
- int y;
- int w;
- int h;
- {
- Dimension border;
- int height;
-
- if (!XtIsManaged(toolBar)) /* nothing to do */
- return;
- XtUnmanageChild(toolBar);
- XtVaGetValues(toolBar,
- XtNborderWidth, &border,
- NULL);
- height = h - 2 * border;
- if (height < 0)
- height = 1;
- XtVaSetValues(toolBar,
- XtNhorizDistance, x,
- XtNvertDistance, y,
- XtNwidth, w - 2 * border,
- XtNheight, height,
- NULL);
- XtManageChild(toolBar);
- }
- #endif
-
- void
- gui_mch_set_text_area_pos(x, y, w, h)
- int x;
- int y;
- int w;
- int h;
- {
- XtUnmanageChild(textArea);
- XtVaSetValues(textArea,
- XtNhorizDistance, x,
- XtNvertDistance, y,
- XtNwidth, w,
- XtNheight, h,
- NULL);
- XtManageChild(textArea);
- #ifdef FEAT_TOOLBAR
- /* Give keyboard focus to the textArea instead of the toolbar. */
- gui_mch_reset_focus();
- #endif
- }
-
- #ifdef FEAT_TOOLBAR
- /*
- * A toolbar button has been pushed; now reset the input focus
- * such that the user can type page up/down etc. and have the
- * input go to the editor window, not the button
- */
- static void
- gui_mch_reset_focus()
- {
- XtSetKeyboardFocus(vimForm, textArea);
- }
- #endif
-
-
- void
- gui_x11_set_back_color()
- {
- if (textArea != NULL)
- XtVaSetValues(textArea,
- XtNbackground, gui.back_pixel,
- NULL);
- }
-
- #if defined(FEAT_MENU) || defined(PROTO)
- /*
- * Menu stuff.
- */
-
- static char_u *make_pull_name __ARGS((char_u * name));
- static Widget get_popup_entry __ARGS((Widget w));
- static Widget submenu_widget __ARGS((Widget));
- static Boolean has_submenu __ARGS((Widget));
- static void gui_mch_submenu_change __ARGS((vimmenu_T *mp, int colors));
- static void gui_athena_menu_font __ARGS((Widget id));
- static Boolean gui_athena_menu_has_submenus __ARGS((Widget, Widget));
-
- void
- gui_mch_enable_menu(flag)
- int flag;
- {
- if (flag)
- {
- XtManageChild(menuBar);
- # ifdef FEAT_TOOLBAR
- if (XtIsManaged(toolBar))
- {
- XtVaSetValues(toolBar,
- XtNvertDistance, gui.menu_height,
- NULL);
- XtVaSetValues(textArea,
- XtNvertDistance, gui.menu_height + gui.toolbar_height,
- NULL);
- }
- # endif
- }
- else
- {
- XtUnmanageChild(menuBar);
- # ifdef FEAT_TOOLBAR
- if (XtIsManaged(toolBar))
- {
- XtVaSetValues(toolBar,
- XtNvertDistance, 0,
- NULL);
- }
- # endif
- }
- }
-
- void
- gui_mch_set_menu_pos(x, y, w, h)
- int x;
- int y;
- int w;
- int h;
- {
- Dimension border;
- int height;
-
- XtUnmanageChild(menuBar);
- XtVaGetValues(menuBar, XtNborderWidth, &border, NULL);
- /* avoid trouble when there are no menu items, and h is 1 */
- height = h - 2 * border;
- if (height < 0)
- height = 1;
- XtVaSetValues(menuBar,
- XtNhorizDistance, x,
- XtNvertDistance, y,
- XtNwidth, w - 2 * border,
- XtNheight, height,
- NULL);
- XtManageChild(menuBar);
- }
-
- /*
- * Used to calculate the insertion position of a widget with respect to its
- * neighbors.
- *
- * Valid range of return values is: 0 (beginning of children) to
- * numChildren (end of children).
- */
- static Cardinal
- athena_calculate_ins_pos(widget)
- Widget widget;
- {
- /* Assume that if the parent of the vimmenu_T is NULL, then we can get
- * to this menu by traversing "next", starting at "root_menu".
- *
- * This holds true for popup menus, toolbar, and toplevel menu items.
- */
-
- /* Popup menus: "id" is NULL. Only submenu_id is valid */
-
- /* Menus that are not toplevel: "parent" will be non-NULL, "id" &
- * "submenu_id" will be non-NULL.
- */
-
- /* Toplevel menus: "parent" is NULL, id is the widget of the menu item */
-
- WidgetList children;
- Cardinal num_children = 0;
- int retval;
- Arg args[2];
- int n = 0;
- int i;
-
- XtSetArg(args[n], XtNchildren, &children); n++;
- XtSetArg(args[n], XtNnumChildren, &num_children); n++;
- XtGetValues(XtParent(widget), args, n);
-
- retval = num_children;
- for (i = 0; i < num_children; ++i)
- {
- Widget current = children[i];
- vimmenu_T *menu = NULL;
-
- for (menu = (a_cur_menu->parent == NULL)
- ? root_menu : a_cur_menu->parent->children;
- menu != NULL;
- menu = menu->next)
- if (current == menu->id
- && a_cur_menu->priority < menu->priority
- && i < retval)
- retval = i;
- }
- return retval;
- }
-
- /* ARGSUSED */
- void
- gui_mch_add_menu(menu, idx)
- vimmenu_T *menu;
- int idx;
- {
- char_u *pullright_name;
- Dimension height, space, border;
- vimmenu_T *parent = menu->parent;
-
- a_cur_menu = menu;
- if (parent == NULL)
- {
- if (menu_is_popup(menu->dname))
- {
- menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
- simpleMenuWidgetClass, vimShell,
- XtNinsertPosition, athena_calculate_ins_pos,
- XtNtranslations, popupTrans,
- NULL);
- gui_athena_menu_colors(menu->submenu_id);
- }
- else if (menu_is_menubar(menu->dname))
- {
- menu->id = XtVaCreateManagedWidget((char *)menu->dname,
- menuButtonWidgetClass, menuBar,
- XtNmenuName, menu->dname,
- #ifdef FONTSET_ALWAYS
- XtNinternational, True,
- #endif
- NULL);
- if (menu->id == (Widget)0)
- return;
- gui_athena_menu_colors(menu->id);
- gui_athena_menu_font(menu->id);
-
- menu->submenu_id = XtVaCreatePopupShell((char *)menu->dname,
- simpleMenuWidgetClass, menu->id,
- XtNinsertPosition, athena_calculate_ins_pos,
- XtNtranslations, supermenuTrans,
- NULL);
- gui_athena_menu_colors(menu->submenu_id);
- gui_athena_menu_font(menu->submenu_id);
-
- /* Don't update the menu height when it was set at a fixed value */
- if (!gui.menu_height_fixed)
- {
- /*
- * When we add a top-level item to the menu bar, we can figure
- * out how high the menu bar should be.
- */
- XtVaGetValues(menuBar,
- XtNvSpace, &space,
- XtNborderWidth, &border,
- NULL);
- XtVaGetValues(menu->id,
- XtNheight, &height,
- NULL);
- gui.menu_height = height + 2 * (space + border);
- }
- }
- }
- else if (parent->submenu_id != (Widget)0)
- {
- menu->id = XtVaCreateManagedWidget((char *)menu->dname,
- smeBSBObjectClass, parent->submenu_id,
- XtNlabel, menu->dname,
- #ifdef FONTSET_ALWAYS
- XtNinternational, True,
- #endif
- NULL);
- if (menu->id == (Widget)0)
- return;
- if (pullerBitmap == None)
- pullerBitmap = gui_athena_create_pullright_pixmap(menu->id);
-
- XtVaSetValues(menu->id, XtNrightBitmap, pullerBitmap,
- NULL);
- /* If there are other menu items that are not pulldown menus,
- * we need to adjust the right margins of those, too.
- */
- {
- WidgetList children;
- Cardinal num_children;
- int i;
-
- XtVaGetValues(parent->submenu_id, XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
- for (i = 0; i < num_children; ++i)
- {
- XtVaSetValues(children[i],
- XtNrightMargin, puller_width,
- NULL);
- }
- }
- gui_athena_menu_colors(menu->id);
- gui_athena_menu_font(menu->id);
-
- pullright_name = make_pull_name(menu->dname);
- menu->submenu_id = XtVaCreatePopupShell((char *)pullright_name,
- simpleMenuWidgetClass, parent->submenu_id,
- XtNtranslations, menuTrans,
- NULL);
- gui_athena_menu_colors(menu->submenu_id);
- gui_athena_menu_font(menu->submenu_id);
- vim_free(pullright_name);
- XtAddCallback(menu->submenu_id, XtNpopupCallback,
- gui_athena_popup_callback, (XtPointer)menu);
-
- if (parent->parent != NULL)
- XtOverrideTranslations(parent->submenu_id, parentTrans);
- }
- a_cur_menu = NULL;
- }
-
- /* Used to determine whether a SimpleMenu has pulldown entries.
- *
- * "id" is the parent of the menu items.
- * Ignore widget "ignore" in the pane.
- */
- static Boolean
- gui_athena_menu_has_submenus(id, ignore)
- Widget id;
- Widget ignore;
- {
- WidgetList children;
- Cardinal num_children;
- int i;
-
- XtVaGetValues(id, XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
- for (i = 0; i < num_children; ++i)
- {
- if (children[i] == ignore)
- continue;
- if (has_submenu(children[i]))
- return True;
- }
- return False;
- }
-
- static void
- gui_athena_menu_font(id)
- Widget id;
- {
- #ifdef FONTSET_ALWAYS
- if (gui.menu_fontset != NOFONTSET)
- {
- if (XtIsManaged(id))
- {
- XtUnmanageChild(id);
- XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
- /* We should force the widget to recalculate it's
- * geometry now. */
- XtManageChild(id);
- }
- else
- XtVaSetValues(id, XtNfontSet, gui.menu_fontset, NULL);
- if (has_submenu(id))
- XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
- }
- #else
- int managed = FALSE;
-
- if (gui.menu_font != NOFONT)
- {
- if (XtIsManaged(id))
- {
- XtUnmanageChild(id);
- managed = TRUE;
- }
-
- # ifdef FEAT_XFONTSET
- if (gui.fontset != NOFONTSET)
- XtVaSetValues(id, XtNfontSet, gui.menu_font, NULL);
- else
- # endif
- XtVaSetValues(id, XtNfont, gui.menu_font, NULL);
- if (has_submenu(id))
- XtVaSetValues(id, XtNrightBitmap, pullerBitmap, NULL);
-
- /* Force the widget to recalculate it's geometry now. */
- if (managed)
- XtManageChild(id);
- }
- #endif
- }
-
-
- void
- gui_mch_new_menu_font()
- {
- Pixmap oldpuller = None;
-
- if (menuBar == (Widget)0)
- return;
-
- if (pullerBitmap != None)
- {
- oldpuller = pullerBitmap;
- pullerBitmap = gui_athena_create_pullright_pixmap(NULL);
- }
- gui_mch_submenu_change(root_menu, FALSE);
-
- {
- /* Iterate through the menubar menu items and get the height of
- * each one. The menu bar height is set to the maximum of all
- * the heights.
- */
- vimmenu_T *mp;
- int max_height = 9999;
-
- for (mp = root_menu; mp != NULL; mp = mp->next)
- {
- if (menu_is_menubar(mp->dname))
- {
- Dimension height;
-
- XtVaGetValues(mp->id,
- XtNheight,(XtArgVal *)&height,
- NULL);
- if (height < max_height)
- max_height = height;
- }
- }
- if (max_height != 9999)
- {
- /* Don't update the menu height when it was set at a fixed value */
- if (!gui.menu_height_fixed)
- {
- Dimension space, border;
-
- XtVaGetValues(menuBar,
- XtNvSpace, &space,
- XtNborderWidth, &border,
- NULL);
- gui.menu_height = max_height + 2 * (space + border);
- }
- }
- }
- /* Now, to simulate the window being resized. Only, this
- * will resize the window to it's current state.
- *
- * There has to be a better way, but I do not see one at this time.
- * (David Harrison)
- */
- {
- Position w, h;
-
- XtVaGetValues(vimShell,
- XtNwidth, &w,
- XtNheight, &h,
- NULL);
- gui_resize_shell(w, h
- #ifdef FEAT_XIM
- - xim_get_status_area_height()
- #endif
- );
- }
- gui_set_shellsize(FALSE, TRUE);
- ui_new_shellsize();
- if (oldpuller != None)
- XFreePixmap(gui.dpy, oldpuller);
- }
-
- #if defined(FEAT_BEVAL) || defined(PROTO)
- void
- gui_mch_new_tooltip_font()
- {
- # ifdef FEAT_TOOLBAR
- vimmenu_T *menu;
-
- if (toolBar == (Widget)0)
- return;
-
- menu = gui_find_menu((char_u *)"ToolBar");
- if (menu != NULL)
- gui_mch_submenu_change(menu, FALSE);
- # endif
- }
-
- void
- gui_mch_new_tooltip_colors()
- {
- # ifdef FEAT_TOOLBAR
- vimmenu_T *menu;
-
- if (toolBar == (Widget)0)
- return;
-
- menu = gui_find_menu((char_u *)"ToolBar");
- if (menu != NULL)
- gui_mch_submenu_change(menu, TRUE);
- # endif
- }
- #endif
-
- static void
- gui_mch_submenu_change(menu, colors)
- vimmenu_T *menu;
- int colors; /* TRUE for colors, FALSE for font */
- {
- vimmenu_T *mp;
-
- for (mp = menu; mp != NULL; mp = mp->next)
- {
- if (mp->id != (Widget)0)
- {
- if (colors)
- {
- gui_athena_menu_colors(mp->id);
- #ifdef FEAT_TOOLBAR
- /* For a toolbar item: Free the pixmap and allocate a new one,
- * so that the background color is right. */
- if (mp->image != (Pixmap)0)
- {
- XFreePixmap(gui.dpy, mp->image);
- get_toolbar_pixmap(mp, &mp->image, NULL);
- if (mp->image != (Pixmap)0)
- XtVaSetValues(mp->id, XtNbitmap, mp->image, NULL);
- }
-
- # ifdef FEAT_BEVAL
- /* If we have a tooltip, then we need to change it's colors */
- if (mp->tip != NULL)
- {
- Arg args[2];
-
- args[0].name = XtNbackground;
- args[0].value = gui.tooltip_bg_pixel;
- args[1].name = XtNforeground;
- args[1].value = gui.tooltip_fg_pixel;
- XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
- }
- # endif
- #endif
- }
- else
- {
- gui_athena_menu_font(mp->id);
- #ifdef FEAT_BEVAL
- /* If we have a tooltip, then we need to change it's font */
- /* Assume XtNinternational == True (in createBalloonEvalWindow)
- */
- if (mp->tip != NULL)
- {
- Arg args[1];
-
- args[0].name = XtNfontSet;
- args[0].value = (XtArgVal)gui.tooltip_fontset;
- XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args));
- }
- #endif
- }
- }
-
- if (mp->children != NULL)
- {
- /* Set the colors/font for the tear off widget */
- if (mp->submenu_id != (Widget)0)
- {
- if (colors)
- gui_athena_menu_colors(mp->submenu_id);
- else
- gui_athena_menu_font(mp->submenu_id);
- }
- /* Set the colors for the children */
- gui_mch_submenu_change(mp->children, colors);
- }
- }
- }
-
- /*
- * Make a submenu name into a pullright name.
- * Replace '.' by '_', can't include '.' in the submenu name.
- */
- static char_u *
- make_pull_name(name)
- char_u * name;
- {
- char_u *pname;
- char_u *p;
-
- pname = vim_strnsave(name, STRLEN(name) + strlen("-pullright"));
- if (pname != NULL)
- {
- strcat((char *)pname, "-pullright");
- while ((p = vim_strchr(pname, '.')) != NULL)
- *p = '_';
- }
- return pname;
- }
-
- /* ARGSUSED */
- void
- gui_mch_add_menu_item(menu, idx)
- vimmenu_T *menu;
- int idx;
- {
- vimmenu_T *parent = menu->parent;
-
- a_cur_menu = menu;
- # ifdef FEAT_TOOLBAR
- if (menu_is_toolbar(parent->name))
- {
- WidgetClass type;
- int n;
- Arg args[21];
-
- n = 0;
- if (menu_is_separator(menu->name))
- {
- XtSetArg(args[n], XtNlabel, ""); n++;
- XtSetArg(args[n], XtNborderWidth, 0); n++;
- }
- else
- {
- get_toolbar_pixmap(menu, &menu->image, NULL);
- XtSetArg(args[n], XtNlabel, menu->dname); n++;
- XtSetArg(args[n], XtNinternalHeight, 1); n++;
- XtSetArg(args[n], XtNinternalWidth, 1); n++;
- XtSetArg(args[n], XtNborderWidth, 1); n++;
- if (menu->image != 0)
- XtSetArg(args[n], XtNbitmap, menu->image); n++;
- }
- XtSetArg(args[n], XtNhighlightThickness, 0); n++;
- type = commandWidgetClass;
- /* TODO: figure out the position in the toolbar?
- * This currently works fine for the default toolbar, but
- * what if we add/remove items during later runtime?
- */
-
- /* NOTE: "idx" isn't used here. The position is calculated by
- * athena_calculate_ins_pos(). The position it calculates
- * should be equal to "idx".
- */
- /* TODO: Could we just store "idx" and use that as the child
- * placement?
- */
-
- if (menu->id == NULL)
- {
- menu->id = XtCreateManagedWidget((char *)menu->dname,
- type, toolBar, args, n);
- XtAddCallback(menu->id,
- XtNcallback, gui_x11_menu_cb, menu);
- }
- else
- XtSetValues(menu->id, args, n);
- gui_athena_menu_colors(menu->id);
-
- #ifdef FEAT_BEVAL
- gui_mch_menu_set_tip(menu);
- #endif
-
- menu->parent = parent;
- menu->submenu_id = NULL;
- if (!XtIsManaged(toolBar)
- && vim_strchr(p_go, GO_TOOLBAR) != NULL)
- gui_mch_show_toolbar(TRUE);
- gui.toolbar_height = gui_mch_compute_toolbar_height();
- return;
- } /* toolbar menu item */
- # endif
-
- /* Add menu separator */
- if (menu_is_separator(menu->name))
- {
- menu->submenu_id = (Widget)0;
- menu->id = XtVaCreateManagedWidget((char *)menu->dname,
- smeLineObjectClass, parent->submenu_id,
- NULL);
- if (menu->id == (Widget)0)
- return;
- gui_athena_menu_colors(menu->id);
- }
- else
- {
- if (parent != NULL && parent->submenu_id != (Widget)0)
- {
- menu->submenu_id = (Widget)0;
- menu->id = XtVaCreateManagedWidget((char *)menu->dname,
- smeBSBObjectClass, parent->submenu_id,
- XtNlabel, menu->dname,
- #ifdef FONTSET_ALWAYS
- XtNinternational, True,
- #endif
- NULL);
- if (menu->id == (Widget)0)
- return;
-
- /* If there are other "pulldown" items in this pane, then adjust
- * the right margin to accomodate the arrow pixmap, otherwise
- * the right margin will be the same as the left margin.
- */
- {
- Dimension left_margin;
-
- XtVaGetValues(menu->id, XtNleftMargin, &left_margin, NULL);
- XtVaSetValues(menu->id, XtNrightMargin,
- gui_athena_menu_has_submenus(parent->submenu_id, NULL) ?
- puller_width :
- left_margin,
- NULL);
- }
-
- gui_athena_menu_colors(menu->id);
- gui_athena_menu_font(menu->id);
- XtAddCallback(menu->id, XtNcallback, gui_x11_menu_cb,
- (XtPointer)menu);
- }
- }
- a_cur_menu = NULL;
- }
-
- #if defined(FEAT_TOOLBAR) || defined(PROTO)
- void
- gui_mch_show_toolbar(int showit)
- {
- Cardinal numChildren; /* how many children toolBar has */
-
- if (toolBar == (Widget)0)
- return;
- XtVaGetValues(toolBar, XtNnumChildren, &numChildren, NULL);
- if (showit && numChildren > 0)
- {
- /* Assume that we want to show the toolbar if p_toolbar contains valid
- * option settings, therefore p_toolbar must not be NULL.
- */
- WidgetList children;
-
- XtVaGetValues(toolBar, XtNchildren, &children, NULL);
- {
- void (*action)(BalloonEval *);
- int text = 0;
-
- if (strstr((const char *)p_toolbar, "tooltips"))
- action = &gui_mch_enable_beval_area;
- else
- action = &gui_mch_disable_beval_area;
- if (strstr((const char *)p_toolbar, "text"))
- text = 1;
- else if (strstr((const char *)p_toolbar, "icons"))
- text = -1;
- if (text != 0)
- {
- vimmenu_T *toolbar;
- vimmenu_T *cur;
-
- for (toolbar = root_menu; toolbar; toolbar = toolbar->next)
- if (menu_is_toolbar(toolbar->dname))
- break;
- /* Assumption: toolbar is NULL if there is no toolbar,
- * otherwise it contains the toolbar menu structure.
- *
- * Assumption: "numChildren" == the number of items in the list
- * of items beginning with toolbar->children.
- */
- if (toolbar)
- {
- for (cur = toolbar->children; cur; cur = cur->next)
- {
- Arg args[2];
- int n = 0;
-
- /* Enable/Disable tooltip (OK to enable while currently
- * enabled)
- */
- if (cur->tip != NULL)
- (*action)(cur->tip);
- if (text == 1)
- {
- XtSetArg(args[n], XtNbitmap, None);
- n++;
- XtSetArg(args[n], XtNlabel,
- menu_is_separator(cur->name) ? "" :
- (char *)cur->dname);
- n++;
- }
- else
- {
- XtSetArg(args[n], XtNbitmap, cur->image);
- n++;
- XtSetArg(args[n], XtNlabel, (cur->image == None) ?
- menu_is_separator(cur->name) ?
- "" :
- (char *)cur->dname
- :
- (char *)None);
- n++;
- }
- if (cur->id != NULL)
- {
- XtUnmanageChild(cur->id);
- XtSetValues(cur->id, args, n);
- XtManageChild(cur->id);
- }
- }
- }
- }
- }
- gui.toolbar_height = gui_mch_compute_toolbar_height();
- XtManageChild(toolBar);
- if (XtIsManaged(menuBar))
- {
- XtVaSetValues(textArea,
- XtNvertDistance, gui.toolbar_height + gui.menu_height,
- NULL);
- XtVaSetValues(toolBar,
- XtNvertDistance, gui.menu_height,
- NULL);
- }
- else
- {
- XtVaSetValues(textArea,
- XtNvertDistance, gui.toolbar_height,
- NULL);
- XtVaSetValues(toolBar,
- XtNvertDistance, 0,
- NULL);
- }
- }
- else
- {
- gui.toolbar_height = 0;
- if (XtIsManaged(menuBar))
- XtVaSetValues(textArea,
- XtNvertDistance, gui.menu_height,
- NULL);
- else
- XtVaSetValues(textArea,
- XtNvertDistance, 0,
- NULL);
-
- XtUnmanageChild(toolBar);
- }
- gui_set_shellsize(FALSE, FALSE);
- }
-
-
- int
- gui_mch_compute_toolbar_height()
- {
- Dimension height; /* total Toolbar height */
- Dimension whgt; /* height of each widget */
- Dimension marginHeight; /* XmNmarginHeight of toolBar */
- Dimension shadowThickness; /* thickness of Xtparent(toolBar) */
- WidgetList children; /* list of toolBar's children */
- Cardinal numChildren; /* how many children toolBar has */
- int i;
-
- height = 0;
- shadowThickness = 0;
- marginHeight = 0;
- if (toolBar != (Widget)0)
- {
- XtVaGetValues(toolBar,
- XtNborderWidth, &shadowThickness,
- XtNvSpace, &marginHeight,
- XtNchildren, &children,
- XtNnumChildren, &numChildren,
- NULL);
- for (i = 0; i < numChildren; i++)
- {
- whgt = 0;
-
- XtVaGetValues(children[i], XtNheight, &whgt, NULL);
- if (height < whgt)
- height = whgt;
- }
- }
-
- return (int)(height + (marginHeight << 1) + (shadowThickness << 1));
- }
-
- void
- gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp)
- Pixel *bgp;
- Pixel *fgp;
- Pixel *bsp;
- Pixel *tsp;
- Pixel *hsp;
- {
- XtVaGetValues(toolBar, XtNbackground, bgp, XtNborderColor, fgp, NULL);
- *bsp = *bgp;
- *tsp = *fgp;
- *hsp = *tsp;
- }
- #endif
-
-
- /* ARGSUSED */
- void
- gui_mch_toggle_tearoffs(enable)
- int enable;
- {
- /* no tearoff menus */
- }
-
- void
- gui_mch_new_menu_colors()
- {
- if (menuBar == (Widget)0)
- return;
- if (gui.menu_fg_pixel != INVALCOLOR)
- XtVaSetValues(menuBar, XtNborderColor, gui.menu_fg_pixel, NULL);
- gui_athena_menu_colors(menuBar);
- #ifdef FEAT_TOOLBAR
- gui_athena_menu_colors(toolBar);
- #endif
-
- gui_mch_submenu_change(root_menu, TRUE);
- }
-
- /*
- * Destroy the machine specific menu widget.
- */
- void
- gui_mch_destroy_menu(menu)
- vimmenu_T *menu;
- {
- Widget parent;
-
- /* There is no item for the toolbar. */
- if (menu->id == (Widget)0)
- return;
-
- parent = XtParent(menu->id);
-
- /* When removing the last "pulldown" menu item from a pane, adjust the
- * right margins of the remaining widgets.
- */
- if (menu->submenu_id != (Widget)0)
- {
- /* Go through the menu items in the parent of this item and
- * adjust their margins, if necessary.
- * This takes care of the case when we delete the last menu item in a
- * pane that has a submenu. In this case, there will be no arrow
- * pixmaps shown anymore.
- */
- {
- WidgetList children;
- Cardinal num_children;
- int i;
- Dimension right_margin = 0;
- Boolean get_left_margin = False;
-
- XtVaGetValues(parent, XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
- if (gui_athena_menu_has_submenus(parent, menu->id))
- right_margin = puller_width;
- else
- get_left_margin = True;
-
- for (i = 0; i < num_children; ++i)
- {
- if (children[i] == menu->id)
- continue;
- if (get_left_margin == True)
- {
- Dimension left_margin;
-
- XtVaGetValues(children[i], XtNleftMargin, &left_margin,
- NULL);
- XtVaSetValues(children[i], XtNrightMargin, left_margin,
- NULL);
- }
- else
- XtVaSetValues(children[i], XtNrightMargin, right_margin,
- NULL);
- }
- }
- }
- /* Please be sure to destroy the parent widget first (i.e. menu->id).
- *
- * This code should be basically identical to that in the file gui_motif.c
- * because they are both Xt based.
- */
- if (menu->id != (Widget)0)
- {
- Cardinal num_children;
- Dimension height, space, border;
-
- XtVaGetValues(menuBar,
- XtNvSpace, &space,
- XtNborderWidth, &border,
- NULL);
- XtVaGetValues(menu->id,
- XtNheight, &height,
- NULL);
- #if defined(FEAT_TOOLBAR) && defined(FEAT_BEVAL)
- if (parent == toolBar && menu->tip != NULL)
- {
- /* We try to destroy this before the actual menu, because there are
- * callbacks, etc. that will be unregistered during the tooltip
- * destruction.
- *
- * If you call "gui_mch_destroy_beval_area()" after destroying
- * menu->id, then the tooltip's window will have already been
- * deallocated by Xt, and unknown behaviour will ensue (probably
- * a core dump).
- */
- gui_mch_destroy_beval_area(menu->tip);
- menu->tip = NULL;
- }
- #endif
- /*
- * This is a hack to stop the Athena simpleMenuWidget from getting a
- * BadValue error when a menu's last child is destroyed. We check to
- * see if this is the last child and if so, don't delete it. The parent
- * will be deleted soon anyway, and it will delete it's children like
- * all good widgets do.
- */
- /* NOTE: The cause of the BadValue X Protocol Error is because when the
- * last child is destroyed, it is first unmanaged, thus causing a
- * geometry resize request from the parent Shell widget.
- * Since the Shell widget has no more children, it is resized to have
- * width/height of 0. XConfigureWindow() is then called with the
- * width/height of 0, which generates the BadValue.
- *
- * This happens in phase two of the widget destruction process.
- */
- {
- if (parent != menuBar
- #ifdef FEAT_TOOLBAR
- && parent != toolBar
- #endif
- )
- {
- XtVaGetValues(parent, XtNnumChildren, &num_children, NULL);
- if (num_children > 1)
- XtDestroyWidget(menu->id);
- }
- else
- XtDestroyWidget(menu->id);
- menu->id = (Widget)0;
- }
-
- if (parent == menuBar)
- {
- if (!gui.menu_height_fixed)
- gui.menu_height = height + 2 * (space + border);
- }
- #ifdef FEAT_TOOLBAR
- else if (parent == toolBar)
- {
- /* When removing last toolbar item, don't display the toolbar. */
- XtVaGetValues(toolBar, XtNnumChildren, &num_children, NULL);
- if (num_children == 0)
- gui_mch_show_toolbar(FALSE);
- else
- gui.toolbar_height = gui_mch_compute_toolbar_height();
- }
- #endif
- }
- if (menu->submenu_id != (Widget)0)
- {
- XtDestroyWidget(menu->submenu_id);
- menu->submenu_id = (Widget)0;
- }
- }
-
- /*ARGSUSED*/
- static void
- gui_athena_menu_timeout(client_data, id)
- XtPointer client_data;
- XtIntervalId *id;
- {
- Widget w = (Widget)client_data;
- Widget popup;
-
- timer = 0;
- if (XtIsSubclass(w,smeBSBObjectClass))
- {
- Pixmap p;
-
- XtVaGetValues(w, XtNrightBitmap, &p, NULL);
- if ((p != None) && (p != XtUnspecifiedPixmap))
- {
- /* We are dealing with an item that has a submenu */
- popup = get_popup_entry(XtParent(w));
- if (popup == (Widget)0)
- return;
- XtPopup(popup, XtGrabNonexclusive);
- }
- }
- }
-
- /* This routine is used to calculate the position (in screen coordinates)
- * where a submenu should appear relative to the menu entry that popped it
- * up. It should appear even with and just slightly to the left of the
- * rightmost end of the menu entry that caused the popup.
- *
- * This is called when XtPopup() is called.
- */
- /*ARGSUSED*/
- static void
- gui_athena_popup_callback(w, client_data, call_data)
- Widget w;
- XtPointer client_data;
- XtPointer call_data;
- {
- /* Assumption: XtIsSubclass(XtParent(w),simpleMenuWidgetClass) */
- vimmenu_T *menu = (vimmenu_T *)client_data;
- Dimension width;
- Position root_x, root_y;
-
- /* First, popdown any siblings that may have menus popped up */
- {
- vimmenu_T *i;
-
- for (i = menu->parent->children; i != NULL; i = i->next)
- {
- if (i->submenu_id != NULL && XtIsManaged(i->submenu_id))
- XtPopdown(i->submenu_id);
- }
- }
- XtVaGetValues(XtParent(w),
- XtNwidth, &width,
- NULL);
- /* Assumption: XawSimpleMenuGetActiveEntry(XtParent(w)) == menu->id */
- /* i.e. This IS the active entry */
- XtTranslateCoords(menu->id,width - 5, 0, &root_x, &root_y);
- XtVaSetValues(w, XtNx, root_x,
- XtNy, root_y,
- NULL);
- }
-
- /* ARGSUSED */
- static void
- gui_athena_popdown_submenus_action(w, event, args, nargs)
- Widget w;
- XEvent *event;
- String *args;
- Cardinal *nargs;
- {
- WidgetList children;
- Cardinal num_children;
-
- XtVaGetValues(w, XtNchildren, &children,
- XtNnumChildren, &num_children,
- NULL);
- for (; num_children > 0; --num_children)
- {
- Widget child = children[num_children - 1];
-
- if (has_submenu(child))
- {
- Widget temp_w;
-
- temp_w = submenu_widget(child);
- gui_athena_popdown_submenus_action(temp_w,event,args,nargs);
- XtPopdown(temp_w);
- }
- }
- }
-
- /* Used to determine if the given widget has a submenu that can be popped up. */
- static Boolean
- has_submenu(widget)
- Widget widget;
- {
- if ((widget != NULL) && XtIsSubclass(widget,smeBSBObjectClass))
- {
- Pixmap p;
-
- XtVaGetValues(widget, XtNrightBitmap, &p, NULL);
- if ((p != None) && (p != XtUnspecifiedPixmap))
- return True;
- }
- return False;
- }
-
- /* ARGSUSED */
- static void
- gui_athena_delayed_arm_action(w, event, args, nargs)
- Widget w;
- XEvent *event;
- String *args;
- Cardinal *nargs;
- {
- Dimension width, height;
-
- if (event->type != MotionNotify)
- return;
-
- XtVaGetValues(w,
- XtNwidth, &width,
- XtNheight, &height,
- NULL);
-
- if (event->xmotion.x >= (int)width || event->xmotion.y >= (int)height)
- return;
-
- {
- static Widget previous_active_widget = NULL;
- Widget current;
-
- current = XawSimpleMenuGetActiveEntry(w);
- if (current != previous_active_widget)
- {
- if (timer)
- {
- /* If the timeout hasn't been triggered, remove it */
- XtRemoveTimeOut(timer);
- }
- gui_athena_popdown_submenus_action(w,event,args,nargs);
- if (has_submenu(current))
- {
- XtAppAddTimeOut(XtWidgetToApplicationContext(w), 600L,
- gui_athena_menu_timeout,
- (XtPointer)current);
- }
- previous_active_widget = current;
- }
- }
- }
-
- static Widget
- get_popup_entry(w)
- Widget w;
- {
- Widget menuw;
-
- /* Get the active entry for the current menu */
- if ((menuw = XawSimpleMenuGetActiveEntry(w)) == (Widget)0)
- return NULL;
-
- return submenu_widget(menuw);
- }
-
- /* Given the widget that has been determined to have a submenu, return the submenu widget
- * that is to be popped up.
- */
- static Widget
- submenu_widget(widget)
- Widget widget;
- {
- /* Precondition: has_submenu(widget) == True
- * XtIsSubclass(XtParent(widget),simpleMenuWidgetClass) == True
- */
-
- char_u *pullright_name;
- Widget popup;
-
- pullright_name = make_pull_name((char_u *)XtName(widget));
- popup = XtNameToWidget(XtParent(widget), (char *)pullright_name);
- vim_free(pullright_name);
-
- return popup;
- /* Postcondition: (popup != NULL) implies
- * (XtIsSubclass(popup,simpleMenuWidgetClass) == True) */
- }
-
- /* ARGSUSED */
- void
- gui_mch_show_popupmenu(menu)
- vimmenu_T *menu;
- {
- int rootx, rooty, winx, winy;
- Window root, child;
- unsigned int mask;
-
- if (menu->submenu_id == (Widget)0)
- return;
-
- /* Position the popup menu at the pointer */
- if (XQueryPointer(gui.dpy, XtWindow(vimShell), &root, &child,
- &rootx, &rooty, &winx, &winy, &mask))
- {
- rootx -= 30;
- if (rootx < 0)
- rootx = 0;
- rooty -= 5;
- if (rooty < 0)
- rooty = 0;
- XtVaSetValues(menu->submenu_id,
- XtNx, rootx,
- XtNy, rooty,
- NULL);
- }
-
- XtOverrideTranslations(menu->submenu_id, popupTrans);
- XtPopupSpringLoaded(menu->submenu_id);
- }
-
- #endif /* FEAT_MENU */
-
- /*
- * Set the menu and scrollbar colors to their default values.
- */
- void
- gui_mch_def_colors()
- {
- /*
- * Get the colors ourselves. Using the automatic conversion doesn't
- * handle looking for approximate colors.
- */
- if (gui.in_use)
- {
- gui.menu_fg_pixel = gui_get_color((char_u *)gui.rsrc_menu_fg_name);
- gui.menu_bg_pixel = gui_get_color((char_u *)gui.rsrc_menu_bg_name);
- gui.scroll_fg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_fg_name);
- gui.scroll_bg_pixel = gui_get_color((char_u *)gui.rsrc_scroll_bg_name);
- #ifdef FEAT_BEVAL
- gui.tooltip_fg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_fg_name);
- gui.tooltip_bg_pixel = gui_get_color((char_u *)gui.rsrc_tooltip_bg_name);
- #endif
- }
- }
-
-
- /*
- * Scrollbar stuff.
- */
-
- void
- gui_mch_set_scrollbar_thumb(sb, val, size, max)
- scrollbar_T *sb;
- long val;
- long size;
- long max;
- {
- double v, s;
-
- if (sb->id == (Widget)0)
- return;
-
- /*
- * Athena scrollbar must go from 0.0 to 1.0.
- */
- if (max == 0)
- {
- /* So you can't scroll it at all (normally it scrolls past end) */
- #ifdef FEAT_GUI_NEXTAW
- XawScrollbarSetThumb(sb->id, 0.0, 1.0);
- #else
- vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
- #endif
- }
- else
- {
- v = (double)val / (double)(max + 1);
- s = (double)size / (double)(max + 1);
- #ifdef FEAT_GUI_NEXTAW
- XawScrollbarSetThumb(sb->id, v, s);
- #else
- vim_XawScrollbarSetThumb(sb->id, v, s, 1.0);
- #endif
- }
- }
-
- void
- gui_mch_set_scrollbar_pos(sb, x, y, w, h)
- scrollbar_T *sb;
- int x;
- int y;
- int w;
- int h;
- {
- if (sb->id == (Widget)0)
- return;
-
- XtUnmanageChild(sb->id);
- XtVaSetValues(sb->id,
- XtNhorizDistance, x,
- XtNvertDistance, y,
- XtNwidth, w,
- XtNheight, h,
- NULL);
- XtManageChild(sb->id);
- }
-
- void
- gui_mch_enable_scrollbar(sb, flag)
- scrollbar_T *sb;
- int flag;
- {
- if (sb->id != (Widget)0)
- {
- if (flag)
- XtManageChild(sb->id);
- else
- XtUnmanageChild(sb->id);
- }
- }
-
- void
- gui_mch_create_scrollbar(sb, orient)
- scrollbar_T *sb;
- int orient; /* SBAR_VERT or SBAR_HORIZ */
- {
- sb->id = XtVaCreateWidget("scrollBar",
- #ifdef FEAT_GUI_NEXTAW
- scrollbarWidgetClass, vimForm,
- #else
- vim_scrollbarWidgetClass, vimForm,
- #endif
- XtNresizable, True,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainLeft,
- XtNborderWidth, 0,
- XtNorientation, (orient == SBAR_VERT) ? XtorientVertical
- : XtorientHorizontal,
- XtNforeground, gui.scroll_fg_pixel,
- XtNbackground, gui.scroll_bg_pixel,
- NULL);
- if (sb->id == (Widget)0)
- return;
-
- XtAddCallback(sb->id, XtNjumpProc,
- gui_athena_scroll_cb_jump, (XtPointer)sb->ident);
- XtAddCallback(sb->id, XtNscrollProc,
- gui_athena_scroll_cb_scroll, (XtPointer)sb->ident);
-
- #ifdef FEAT_GUI_NEXTAW
- XawScrollbarSetThumb(sb->id, 0.0, 1.0);
- #else
- vim_XawScrollbarSetThumb(sb->id, 0.0, 1.0, 0.0);
- #endif
- }
-
- #if defined(FEAT_WINDOWS) || defined(PROTO)
- void
- gui_mch_destroy_scrollbar(sb)
- scrollbar_T *sb;
- {
- if (sb->id != (Widget)0)
- XtDestroyWidget(sb->id);
- }
- #endif
-
- void
- gui_mch_set_scrollbar_colors(sb)
- scrollbar_T *sb;
- {
- if (sb->id != (Widget)0)
- XtVaSetValues(sb->id,
- XtNforeground, gui.scroll_fg_pixel,
- XtNbackground, gui.scroll_bg_pixel,
- NULL);
-
- /* This is needed for the rectangle below the vertical scrollbars. */
- if (sb == &gui.bottom_sbar && vimForm != (Widget)0)
- gui_athena_scroll_colors(vimForm);
- }
-
- /*
- * Miscellaneous stuff:
- */
- Window
- gui_x11_get_wid()
- {
- return XtWindow(textArea);
- }
-
- #if defined(FEAT_BROWSE) || defined(PROTO)
- /*
- * Put up a file requester.
- * Returns the selected name in allocated memory, or NULL for Cancel.
- */
- /* ARGSUSED */
- char_u *
- gui_mch_browse(saving, title, dflt, ext, initdir, filter)
- int saving; /* select file to write */
- char_u *title; /* not used (title for the window) */
- char_u *dflt; /* not used (default name) */
- char_u *ext; /* not used (extension added) */
- char_u *initdir; /* initial directory, NULL for current dir */
- char_u *filter; /* not used (file name filter) */
- {
- Position x, y;
- char_u dirbuf[MAXPATHL];
-
- /* Concatenate "initdir" and "dflt". */
- if (initdir == NULL || *initdir == NUL)
- mch_dirname(dirbuf, MAXPATHL);
- else if (STRLEN(initdir) + 2 < MAXPATHL)
- STRCPY(dirbuf, initdir);
- else
- dirbuf[0] = NUL;
- if (dflt != NULL && *dflt != NUL
- && STRLEN(dirbuf) + 2 + STRLEN(dflt) < MAXPATHL)
- {
- add_pathsep(dirbuf);
- STRCAT(dirbuf, dflt);
- }
-
- /* Position the file selector just below the menubar */
- XtTranslateCoords(vimShell, (Position)0, (Position)
- #ifdef FEAT_MENU
- gui.menu_height
- #else
- 0
- #endif
- , &x, &y);
- return (char_u *)vim_SelFile(vimShell, (char *)title, (char *)dirbuf,
- NULL, (int)x, (int)y, gui.menu_fg_pixel, gui.menu_bg_pixel,
- gui.scroll_fg_pixel, gui.scroll_bg_pixel);
- }
- #endif
-
- #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
-
- static int dialogStatus;
- static Atom dialogatom;
-
- static void keyhit_callback __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *cont));
- static void butproc __ARGS((Widget w, XtPointer client_data, XtPointer call_data));
- static void dialog_wm_handler __ARGS((Widget w, XtPointer client_data, XEvent *event, Boolean *dum));
-
- /*
- * Callback function for the textfield. When CR is hit this works like
- * hitting the "OK" button, ESC like "Cancel".
- */
- /* ARGSUSED */
- static void
- keyhit_callback(w, client_data, event, cont)
- Widget w;
- XtPointer client_data;
- XEvent *event;
- Boolean *cont;
- {
- char buf[2];
-
- if (XLookupString(&(event->xkey), buf, 2, NULL, NULL) == 1)
- {
- if (*buf == CR)
- dialogStatus = 1;
- else if (*buf == ESC)
- dialogStatus = 0;
- }
- }
-
- /* ARGSUSED */
- static void
- butproc(w, client_data, call_data)
- Widget w;
- XtPointer client_data;
- XtPointer call_data;
- {
- dialogStatus = (int)(long)client_data + 1;
- }
-
- /*
- * Function called when dialog window closed.
- */
- /*ARGSUSED*/
- static void
- dialog_wm_handler(w, client_data, event, dum)
- Widget w;
- XtPointer client_data;
- XEvent *event;
- Boolean *dum;
- {
- if (event->type == ClientMessage
- && ((XClientMessageEvent *)event)->data.l[0] == dialogatom)
- dialogStatus = 0;
- }
-
- /* ARGSUSED */
- int
- gui_mch_dialog(type, title, message, buttons, dfltbutton, textfield)
- int type;
- char_u *title;
- char_u *message;
- char_u *buttons;
- int dfltbutton;
- char_u *textfield;
- {
- char_u *buts;
- char_u *p, *next;
- XtAppContext app;
- XEvent event;
- Position wd, hd;
- Position wv, hv;
- Position x, y;
- Widget dialog;
- Widget dialogshell;
- Widget dialogmessage;
- Widget dialogtextfield = 0;
- Widget dialogButton;
- Widget prev_dialogButton = NULL;
- int butcount;
- int vertical;
-
- if (title == NULL)
- title = (char_u *)_("Vim dialog");
- dialogStatus = -1;
-
- /* if our pointer is currently hidden, then we should show it. */
- gui_mch_mousehide(FALSE);
-
- /* Check 'v' flag in 'guioptions': vertical button placement. */
- vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL);
-
- /* The shell is created each time, to make sure it is resized properly */
- dialogshell = XtVaCreatePopupShell("dialogShell",
- transientShellWidgetClass, vimShell,
- XtNtitle, title,
- NULL);
- if (dialogshell == (Widget)0)
- goto error;
-
- dialog = XtVaCreateManagedWidget("dialog",
- formWidgetClass, dialogshell,
- XtNdefaultDistance, 20,
- NULL);
- if (dialog == (Widget)0)
- goto error;
- gui_athena_menu_colors(dialog);
- dialogmessage = XtVaCreateManagedWidget("dialogMessage",
- labelWidgetClass, dialog,
- XtNlabel, message,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainLeft,
- XtNresizable, True,
- XtNborderWidth, 0,
- NULL);
- gui_athena_menu_colors(dialogmessage);
-
- if (textfield != NULL)
- {
- dialogtextfield = XtVaCreateManagedWidget("textfield",
- asciiTextWidgetClass, dialog,
- XtNwidth, 400,
- XtNtop, XtChainTop,
- XtNbottom, XtChainTop,
- XtNleft, XtChainLeft,
- XtNright, XtChainRight,
- XtNfromVert, dialogmessage,
- XtNresizable, True,
- XtNstring, textfield,
- XtNlength, IOSIZE,
- XtNuseStringInPlace, True,
- XtNeditType, XawtextEdit,
- XtNwrap, XawtextWrapNever,
- XtNresize, XawtextResizeHeight,
- NULL);
- XtManageChild(dialogtextfield);
- XtAddEventHandler(dialogtextfield, KeyPressMask, False,
- (XtEventHandler)keyhit_callback, (XtPointer)NULL);
- XawTextSetInsertionPoint(dialogtextfield,
- (XawTextPosition)STRLEN(textfield));
- XtSetKeyboardFocus(dialog, dialogtextfield);
- }
-
- /* make a copy, so that we can insert NULs */
- buts = vim_strsave(buttons);
- if (buts == NULL)
- return -1;
-
- p = buts;
- for (butcount = 0; *p; ++butcount)
- {
- for (next = p; *next; ++next)
- {
- if (*next == DLG_HOTKEY_CHAR)
- mch_memmove(next, next + 1, STRLEN(next));
- if (*next == DLG_BUTTON_SEP)
- {
- *next++ = NUL;
- break;
- }
- }
- dialogButton = XtVaCreateManagedWidget("button",
- commandWidgetClass, dialog,
- XtNlabel, p,
- XtNtop, XtChainBottom,
- XtNbottom, XtChainBottom,
- XtNleft, XtChainLeft,
- XtNright, XtChainLeft,
- XtNfromVert, textfield == NULL ? dialogmessage : dialogtextfield,
- XtNvertDistance, vertical ? 4 : 20,
- XtNresizable, False,
- NULL);
- gui_athena_menu_colors(dialogButton);
- if (butcount > 0)
- XtVaSetValues(dialogButton,
- vertical ? XtNfromVert : XtNfromHoriz, prev_dialogButton,
- NULL);
-
- XtAddCallback(dialogButton, XtNcallback, butproc, (XtPointer)butcount);
- p = next;
- prev_dialogButton = dialogButton;
- }
- vim_free(buts);
-
- XtRealizeWidget(dialogshell);
-
- /* Setup for catching the close-window event, don't let it close Vim! */
- dialogatom = XInternAtom(gui.dpy, "WM_DELETE_WINDOW", False);
- XSetWMProtocols(gui.dpy, XtWindow(dialogshell), &dialogatom, 1);
- XtAddEventHandler(dialogshell, NoEventMask, True, dialog_wm_handler, NULL);
-
- XtVaGetValues(dialogshell,
- XtNwidth, &wd,
- XtNheight, &hd,
- NULL);
- XtVaGetValues(vimShell,
- XtNwidth, &wv,
- XtNheight, &hv,
- NULL);
- XtTranslateCoords(vimShell,
- (Position)((wv - wd) / 2),
- (Position)((hv - hd) / 2),
- &x, &y);
- if (x < 0)
- x = 0;
- if (y < 0)
- y = 0;
- XtVaSetValues(dialogshell, XtNx, x, XtNy, y, NULL);
-
- /* Position the mouse pointer in the dialog, required for when focus
- * follows mouse. */
- XWarpPointer(gui.dpy, (Window)0, XtWindow(dialogshell), 0, 0, 0, 0, 20, 40);
-
-
- app = XtWidgetToApplicationContext(dialogshell);
-
- XtPopup(dialogshell, XtGrabNonexclusive);
-
- while (1)
- {
- XtAppNextEvent(app, &event);
- XtDispatchEvent(&event);
- if (dialogStatus >= 0)
- break;
- }
-
- XtPopdown(dialogshell);
-
- if (textfield != NULL && dialogStatus < 0)
- *textfield = NUL;
-
- error:
- XtDestroyWidget(dialogshell);
-
- return dialogStatus;
- }
- #endif
-
- #if defined(FEAT_GUI_DIALOG) || defined(FEAT_MENU)
- /*
- * Set the colors of Widget "id" to the menu colors.
- */
- static void
- gui_athena_menu_colors(id)
- Widget id;
- {
- if (gui.menu_bg_pixel != INVALCOLOR)
- XtVaSetValues(id, XtNbackground, gui.menu_bg_pixel, NULL);
- if (gui.menu_fg_pixel != INVALCOLOR)
- XtVaSetValues(id, XtNforeground, gui.menu_fg_pixel, NULL);
- }
- #endif
-
- /*
- * Set the colors of Widget "id" to the scroll colors.
- */
- static void
- gui_athena_scroll_colors(id)
- Widget id;
- {
- if (gui.scroll_bg_pixel != INVALCOLOR)
- XtVaSetValues(id, XtNbackground, gui.scroll_bg_pixel, NULL);
- if (gui.scroll_fg_pixel != INVALCOLOR)
- XtVaSetValues(id, XtNforeground, gui.scroll_fg_pixel, NULL);
- }
-