/* vi:set ts=8 sts=4 sw=4: * * VIM - Vi IMproved by Bram Moolenaar * GUI/Motif support by Robert Webb * * 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 #include #include #include #include #include #include #include #include #include #include #if (XmVersion >= 1002) # include #endif #include #include #include #include #include #include #include #include #include "vim.h" #ifdef HAVE_X11_XPM_H # include #else # ifdef HAVE_XM_XPMP_H # include # endif #endif #if defined(FEAT_GUI_DIALOG) && defined(HAVE_XPM) # include "../pixmaps/alert.xpm" # include "../pixmaps/error.xpm" # include "../pixmaps/generic.xpm" # include "../pixmaps/info.xpm" # include "../pixmaps/quest.xpm" #endif #define MOTIF_POPUP extern Widget vimShell; static Widget vimForm; static Widget textAreaForm; Widget textArea; #ifdef FEAT_TOOLBAR static Widget toolBarFrame; static Widget toolBar; #endif #ifdef FEAT_FOOTER static Widget footer; #endif #ifdef FEAT_MENU # if (XmVersion >= 1002) /* remember the last set value for the tearoff item */ static int tearoff_val = (int)XmTEAR_OFF_ENABLED; # endif static Widget menuBar; #endif static void scroll_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); #ifdef FEAT_TOOLBAR # if 0 static void toolbar_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); static void toolbar_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); # endif # ifdef FEAT_FOOTER static void toolbarbutton_enter_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); static void toolbarbutton_leave_cb __ARGS((Widget, XtPointer, XEvent *, Boolean *)); # endif static void gui_mch_reset_focus __ARGS((void)); #endif #ifdef FEAT_FOOTER static int gui_mch_compute_footer_height __ARGS((void)); #endif #ifdef WSDEBUG static void attachDump(Widget, char *); #endif static void gui_motif_menu_colors __ARGS((Widget id)); static void gui_motif_scroll_colors __ARGS((Widget id)); #ifdef FEAT_MENU static void gui_motif_menu_fontlist __ARGS((Widget id)); #endif #if (XmVersion >= 1002) # define STRING_TAG XmFONTLIST_DEFAULT_TAG #else # define STRING_TAG XmSTRING_DEFAULT_CHARSET #endif /* * Call-back routines. */ /* ARGSUSED */ static void scroll_cb(w, client_data, call_data) Widget w; XtPointer client_data, call_data; { scrollbar_T *sb; long value; int dragging; sb = gui_find_scrollbar((long)client_data); value = ((XmScrollBarCallbackStruct *)call_data)->value; dragging = (((XmScrollBarCallbackStruct *)call_data)->reason == (int)XmCR_DRAG); gui_drag_scrollbar(sb, value, dragging); } /* * End of call-back routines */ /* * Create all the motif widgets necessary. */ void gui_x11_create_widgets() { /* * Start out by adding the configured border width into the border offset */ gui.border_offset = gui.border_width; /* * Install the tearOffModel resource converter. */ #if (XmVersion >= 1002) XmRepTypeInstallTearOffModelConverter(); #endif /* Make sure the "Quit" menu entry of the window manager is ignored */ XtVaSetValues(vimShell, XmNdeleteResponse, XmDO_NOTHING, NULL); vimForm = XtVaCreateManagedWidget("vimForm", xmFormWidgetClass, vimShell, XmNborderWidth, 0, XmNhighlightThickness, 0, XmNshadowThickness, 0, XmNmarginWidth, 0, XmNmarginHeight, 0, XmNresizePolicy, XmRESIZE_ANY, NULL); gui_motif_menu_colors(vimForm); #ifdef FEAT_MENU { Arg al[7]; /* Make sure there is enough room for arguments! */ int ac = 0; # if (XmVersion >= 1002) XtSetArg(al[ac], XmNtearOffModel, tearoff_val); ac++; # endif XtSetArg(al[ac], XmNleftAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNtopAttachment, XmATTACH_FORM); ac++; XtSetArg(al[ac], XmNrightAttachment, XmATTACH_FORM); ac++; # ifndef FEAT_TOOLBAR /* Always stick to right hand side. */ XtSetArg(al[ac], XmNrightOffset, 0); ac++; # endif menuBar = XmCreateMenuBar(vimForm, "menuBar", al, ac); XtManageChild(menuBar); /* Remember the default colors, needed for ":hi clear". */ XtVaGetValues(menuBar, XmNbackground, &gui.menu_def_bg_pixel, XmNforeground, &gui.menu_def_fg_pixel, NULL); gui_motif_menu_colors(menuBar); } #endif #ifdef FEAT_TOOLBAR /* * Create an empty ToolBar. We should get buttons defined from menu.vim. */ toolBarFrame = XtVaCreateWidget("toolBarFrame", xmFrameWidgetClass, vimForm, XmNshadowThickness, 0, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); gui_motif_menu_colors(toolBarFrame); toolBar = XtVaCreateManagedWidget("toolBar", xmRowColumnWidgetClass, toolBarFrame, XmNchildType, XmFRAME_WORKAREA_CHILD, XmNrowColumnType, XmWORK_AREA, XmNorientation, XmHORIZONTAL, XmNtraversalOn, False, XmNisHomogeneous, False, XmNpacking, XmPACK_TIGHT, XmNspacing, 0, XmNshadowThickness, 0, XmNhighlightThickness, 0, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNadjustLast, True, NULL); gui_motif_menu_colors(toolBar); # if 0 /* these don't work, because of the XmNtraversalOn above. */ XtAddEventHandler(toolBar, EnterWindowMask, False, toolbar_enter_cb, NULL); XtAddEventHandler(toolBar, LeaveWindowMask, False, toolbar_leave_cb, NULL); # endif #endif textAreaForm = XtVaCreateManagedWidget("textAreaForm", xmFormWidgetClass, vimForm, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNmarginWidth, 0, XmNmarginHeight, 0, XmNresizePolicy, XmRESIZE_ANY, NULL); gui_motif_scroll_colors(textAreaForm); textArea = XtVaCreateManagedWidget("textArea", xmDrawingAreaWidgetClass, textAreaForm, XmNforeground, gui.norm_pixel, XmNbackground, gui.back_pixel, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, /* * These take some control away from the user, but avoids making them * add resources to get a decent looking setup. */ XmNborderWidth, 0, XmNhighlightThickness, 0, XmNshadowThickness, 0, NULL); #ifdef FEAT_FOOTER /* * Create the Footer. */ footer = XtVaCreateWidget("footer", xmLabelGadgetClass, vimForm, XmNalignment, XmALIGNMENT_BEGINNING, XmNmarginHeight, 0, XmNmarginWidth, 0, XmNtraversalOn, False, XmNrecomputeSize, False, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 5, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); gui_mch_set_footer((char_u *) ""); #endif /* * Install the callbacks. */ gui_x11_callbacks(textArea, vimForm); /* Pretend we don't have input focus, we will get an event if we do. */ gui.in_focus = FALSE; } /* * Called when the GUI is not going to start after all. */ void gui_x11_destroy_widgets() { textArea = NULL; #ifdef FEAT_MENU menuBar = NULL; #endif } /*ARGSUSED*/ void gui_mch_set_text_area_pos(x, y, w, h) int x; int y; int w; int h; { #ifdef FEAT_TOOLBAR /* Give keyboard focus to the textArea instead of the toolbar. */ gui_mch_reset_focus(); #endif } void gui_x11_set_back_color() { if (textArea != NULL) #if (XmVersion >= 1002) XmChangeColor(textArea, gui.back_pixel); #else XtVaSetValues(textArea, XmNbackground, gui.back_pixel, NULL); #endif } /* * Manage dialog centered on pointer. This could be used by the Athena code as * well. */ static void manage_centered __ARGS((Widget dialog_child)); static void manage_centered(dialog_child) Widget dialog_child; { Widget shell = XtParent(dialog_child); Window root, child; unsigned int mask; unsigned int width, height, border_width, depth; int x, y, win_x, win_y, maxX, maxY; Boolean mappedWhenManaged; /* Temporarily set value of XmNmappedWhenManaged to stop the dialog from popping up right away */ XtVaGetValues(shell, XmNmappedWhenManaged, &mappedWhenManaged, 0); XtVaSetValues(shell, XmNmappedWhenManaged, False, 0); XtManageChild(dialog_child); /* Get the pointer position (x, y) */ XQueryPointer(XtDisplay(shell), XtWindow(shell), &root, &child, &x, &y, &win_x, &win_y, &mask); /* Translate the pointer position (x, y) into a position for the new window that will place the pointer at its center */ XGetGeometry(XtDisplay(shell), XtWindow(shell), &root, &win_x, &win_y, &width, &height, &border_width, &depth); width += 2 * border_width; height += 2 * border_width; x -= width / 2; y -= height / 2; /* Ensure that the dialog remains on screen */ maxX = XtScreen(shell)->width - width; maxY = XtScreen(shell)->height - height; if (x < 0) x = 0; if (x > maxX) x = maxX; if (y < 0) y = 0; if (y > maxY) y = maxY; /* Set desired window position in the DialogShell */ XtVaSetValues(shell, XmNx, x, XmNy, y, NULL); /* Map the widget */ XtMapWidget(shell); /* Restore the value of XmNmappedWhenManaged */ XtVaSetValues(shell, XmNmappedWhenManaged, mappedWhenManaged, 0); } #if defined(FEAT_MENU) || defined(FEAT_SUN_WORKSHOP) \ || defined(FEAT_GUI_DIALOG) || defined(PROTO) /* * Encapsulate the way an XmFontList is created. */ XmFontList gui_motif_create_fontlist(font) XFontStruct *font; { XmFontList font_list; # if (XmVersion <= 1001) /* Motif 1.1 method */ font_list = XmFontListCreate(font, STRING_TAG); # else /* Motif 1.2 method */ XmFontListEntry font_list_entry; font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONT, (XtPointer)font); font_list = XmFontListAppendEntry(NULL, font_list_entry); XmFontListEntryFree(&font_list_entry); # endif return font_list; } # if ((XmVersion > 1001) && defined(FEAT_XFONTSET)) || defined(PROTO) XmFontList gui_motif_fontset2fontlist(fontset) XFontSet *fontset; { XmFontList font_list; /* Motif 1.2 method */ XmFontListEntry font_list_entry; font_list_entry = XmFontListEntryCreate(STRING_TAG, XmFONT_IS_FONTSET, (XtPointer)*fontset); font_list = XmFontListAppendEntry(NULL, font_list_entry); XmFontListEntryFree(&font_list_entry); return font_list; } # endif #endif #if defined(FEAT_MENU) || defined(PROTO) /* * Menu stuff. */ static void gui_motif_add_actext __ARGS((vimmenu_T *menu)); #if (XmVersion >= 1002) static void toggle_tearoff __ARGS((Widget wid)); static void gui_mch_recurse_tearoffs __ARGS((vimmenu_T *menu)); #endif static void gui_mch_submenu_change __ARGS((vimmenu_T *mp, int colors)); static void do_set_mnemonics __ARGS((int enable)); static int menu_enabled = TRUE; void gui_mch_enable_menu(flag) int flag; { if (flag) { XtManageChild(menuBar); #ifdef FEAT_TOOLBAR if (XtIsManaged(XtParent(toolBar))) { /* toolBar is attached to top form */ XtVaSetValues(XtParent(toolBar), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); } else #endif { XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); } } else { XtUnmanageChild(menuBar); #ifdef FEAT_TOOLBAR if (XtIsManaged(XtParent(toolBar))) { XtVaSetValues(XtParent(toolBar), XmNtopAttachment, XmATTACH_FORM, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); } else #endif { XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_FORM, NULL); } } } /* * Enable or disable mnemonics for the toplevel menus. */ void gui_motif_set_mnemonics(enable) int enable; { /* * Don't enable menu mnemonics when the menu bar is disabled, LessTif * crashes when using a mnemonic then. */ if (!menu_enabled) enable = FALSE; do_set_mnemonics(enable); } static void do_set_mnemonics(enable) int enable; { vimmenu_T *menu; for (menu = root_menu; menu != NULL; menu = menu->next) if (menu->id != (Widget)0) XtVaSetValues(menu->id, XmNmnemonic, enable ? menu->mnemonic : NUL, NULL); } void gui_mch_add_menu(menu, idx) vimmenu_T *menu; int idx; { XmString label; Widget shell; vimmenu_T *parent = menu->parent; #ifdef MOTIF_POPUP if (menu_is_popup(menu->name)) { Arg arg[2]; int n = 0; /* Only create the popup menu when it's actually used, otherwise there * is a delay when using the right mouse button. */ # if (XmVersion <= 1002) if (mouse_model_popup()) # endif { if (gui.menu_bg_pixel != INVALCOLOR) { XtSetArg(arg[0], XmNbackground, gui.menu_bg_pixel); n++; } if (gui.menu_fg_pixel != INVALCOLOR) { XtSetArg(arg[1], XmNforeground, gui.menu_fg_pixel); n++; } menu->submenu_id = XmCreatePopupMenu(textArea, "contextMenu", arg, n); menu->id = (Widget)0; } return; } #endif if (!menu_is_menubar(menu->name) || (parent != NULL && parent->submenu_id == (Widget)0)) return; label = XmStringCreate((char *)menu->dname, STRING_TAG); if (label == NULL) return; menu->id = XtVaCreateWidget("subMenu", xmCascadeButtonWidgetClass, (parent == NULL) ? menuBar : parent->submenu_id, XmNlabelString, label, XmNmnemonic, p_wak[0] == 'n' ? NUL : menu->mnemonic, #if (XmVersion >= 1002) /* submenu: count the tearoff item (needed for LessTif) */ XmNpositionIndex, idx + (parent != NULL && tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0), #endif NULL); gui_motif_menu_colors(menu->id); gui_motif_menu_fontlist(menu->id); XmStringFree(label); if (menu->id == (Widget)0) /* failed */ return; /* add accelerator text */ gui_motif_add_actext(menu); shell = XtVaCreateWidget("subMenuShell", xmMenuShellWidgetClass, menu->id, XmNwidth, 1, XmNheight, 1, NULL); gui_motif_menu_colors(shell); menu->submenu_id = XtVaCreateWidget("rowColumnMenu", xmRowColumnWidgetClass, shell, XmNrowColumnType, XmMENU_PULLDOWN, NULL); gui_motif_menu_colors(menu->submenu_id); if (menu->submenu_id == (Widget)0) /* failed */ return; #if (XmVersion >= 1002) /* Set the colors for the tear off widget */ toggle_tearoff(menu->submenu_id); #endif XtVaSetValues(menu->id, XmNsubMenuId, menu->submenu_id, NULL); /* * The "Help" menu is a special case, and should be placed at the far * right hand side of the menu-bar. It's recognized by its high priority. */ if (parent == NULL && menu->priority >= 9999) XtVaSetValues(menuBar, XmNmenuHelpWidget, menu->id, NULL); /* * When we add a top-level item to the menu bar, we can figure out how * high the menu bar should be. */ if (parent == NULL) gui_mch_compute_menu_height(menu->id); } /* * Add mnemonic and accelerator text to a menu button. */ static void gui_motif_add_actext(menu) vimmenu_T *menu; { XmString label; /* Add accelrator text, if there is one */ if (menu->actext != NULL && menu->id != (Widget)0) { label = XmStringCreate((char *)menu->actext, STRING_TAG); if (label == NULL) return; XtVaSetValues(menu->id, XmNacceleratorText, label, NULL); XmStringFree(label); } } void gui_mch_toggle_tearoffs(enable) int enable; { #if (XmVersion >= 1002) if (enable) tearoff_val = (int)XmTEAR_OFF_ENABLED; else tearoff_val = (int)XmTEAR_OFF_DISABLED; toggle_tearoff(menuBar); gui_mch_recurse_tearoffs(root_menu); #endif } #if (XmVersion >= 1002) /* * Set the tearoff for one menu widget on or off, and set the color of the * tearoff widget. */ static void toggle_tearoff(wid) Widget wid; { Widget w; XtVaSetValues(wid, XmNtearOffModel, tearoff_val, NULL); if (tearoff_val == (int)XmTEAR_OFF_ENABLED && (w = XmGetTearOffControl(wid)) != (Widget)0) gui_motif_menu_colors(w); } static void gui_mch_recurse_tearoffs(menu) vimmenu_T *menu; { while (menu != NULL) { if (!menu_is_popup(menu->name)) { if (menu->submenu_id != (Widget)0) toggle_tearoff(menu->submenu_id); gui_mch_recurse_tearoffs(menu->children); } menu = menu->next; } } #endif int gui_mch_text_area_extra_height() { Dimension shadowHeight; XtVaGetValues(textAreaForm, XmNshadowThickness, &shadowHeight, NULL); return shadowHeight; } /* * Compute the height of the menu bar. * We need to check all the items for their position and height, for the case * there are several rows, and/or some characters extend higher or lower. */ void gui_mch_compute_menu_height(id) Widget id; /* can be NULL when deleting menu */ { Dimension y, maxy; Dimension margin, shadow; vimmenu_T *mp; static Dimension height = 21; /* normal height of a menu item */ /* * Get the height of the new item, before managing it, because it will * still reflect the font size. After managing it depends on the menu * height, which is what we just wanted to get!. */ if (id != (Widget)0) XtVaGetValues(id, XmNheight, &height, NULL); /* Find any menu Widget, to be able to call XtManageChild() */ else for (mp = root_menu; mp != NULL; mp = mp->next) if (mp->id != (Widget)0 && menu_is_menubar(mp->name)) { id = mp->id; break; } /* * Now manage the menu item, to make them all be positioned (makes an * extra row when needed, removes it when not needed). */ if (id != (Widget)0) XtManageChild(id); /* * Now find the menu item that is the furthest down, and get it's position. */ maxy = 0; for (mp = root_menu; mp != NULL; mp = mp->next) { if (mp->id != (Widget)0 && menu_is_menubar(mp->name)) { XtVaGetValues(mp->id, XmNy, &y, NULL); if (y > maxy) maxy = y; } } XtVaGetValues(menuBar, XmNmarginHeight, &margin, XmNshadowThickness, &shadow, NULL); /* * This computation is the result of trial-and-error: * maxy = The maximum position of an item; required for when there are * two or more rows * height = height of an item, before managing it; Hopefully this will * change with the font height. Includes shadow-border. * shadow = shadow-border; must be subtracted from the height. * margin = margin around the menu buttons; Must be added. * Add 4 for the underlining of shortcut keys. */ gui.menu_height = maxy + height - 2 * shadow + 2 * margin + 4; #ifdef LESSTIF_VERSION /* Somehow the menu bar doesn't resize automatically. Set it here, * even though this is a catch 22. Don't do this when starting up, * somehow the menu gets very high then. */ if (gui.shell_created) XtVaSetValues(menuBar, XmNheight, gui.menu_height, NULL); #endif } void gui_mch_add_menu_item(menu, idx) vimmenu_T *menu; int idx; { XmString label; vimmenu_T *parent = menu->parent; # ifdef EBCDIC menu->mnemonic = 0; # endif # if (XmVersion <= 1002) /* Don't add Popup menu items when the popup menu isn't used. */ if (menu_is_child_of_popup(menu) && !mouse_model_popup()) return; # endif # ifdef FEAT_TOOLBAR if (menu_is_toolbar(parent->name)) { WidgetClass type; XmString xms = NULL; /* fallback label if pixmap not found */ int n; Arg args[18]; n = 0; if (menu_is_separator(menu->name)) { char *cp; Dimension wid; /* * A separator has the format "-sep%d[:%d]-". The optional :%d is * a width specifier. If no width is specified then we choose one. */ cp = (char *)vim_strchr(menu->name, ':'); if (cp != NULL) wid = (Dimension)atoi(++cp); else wid = 4; #if 0 /* We better use a FormWidget here, since it's far more * flexible in terms of size. */ type = xmFormWidgetClass; XtSetArg(args[n], XmNwidth, wid); n++; #else type = xmSeparatorWidgetClass; XtSetArg(args[n], XmNwidth, wid); n++; XtSetArg(args[n], XmNminWidth, wid); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNseparatorType, XmNO_LINE); n++; #endif } else { get_toolbar_pixmap(menu, &menu->image, &menu->image_ins); /* Set the label here, so that we can switch between icons/text * by changing the XmNlabelType resource. */ xms = XmStringCreate((char *)menu->dname, STRING_TAG); XtSetArg(args[n], XmNlabelString, xms); n++; #ifndef FEAT_SUN_WORKSHOP /* Without shadows one can't sense whatever the button has been * pressed or not! However we wan't to save a bit of space... */ XtSetArg(args[n], XmNhighlightThickness, 0); n++; XtSetArg(args[n], XmNhighlightOnEnter, True); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; #endif if (menu->image == 0) { XtSetArg(args[n], XmNlabelType, XmSTRING); n++; XtSetArg(args[n], XmNlabelPixmap, 0); n++; XtSetArg(args[n], XmNlabelInsensitivePixmap, 0); n++; } else { XtSetArg(args[n], XmNlabelPixmap, menu->image); n++; XtSetArg(args[n], XmNlabelInsensitivePixmap, menu->image_ins); n++; XtSetArg(args[n], XmNlabelType, XmPIXMAP); n++; } type = xmPushButtonWidgetClass; XtSetArg(args[n], XmNwidth, 80); n++; } XtSetArg(args[n], XmNpositionIndex, idx); n++; if (menu->id == NULL) { menu->id = XtCreateManagedWidget((char *)menu->dname, type, toolBar, args, n); if (menu->id != NULL && type == xmPushButtonWidgetClass) { XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb, menu); # ifdef FEAT_FOOTER XtAddEventHandler(menu->id, EnterWindowMask, False, toolbarbutton_enter_cb, menu); XtAddEventHandler(menu->id, LeaveWindowMask, False, toolbarbutton_leave_cb, menu); # endif } } else XtSetValues(menu->id, args, n); if (xms != NULL) XmStringFree(xms); #ifdef FEAT_BEVAL gui_mch_menu_set_tip(menu); #endif menu->parent = parent; menu->submenu_id = NULL; /* When adding first item to toolbar it might have to be enabled .*/ if (!XtIsManaged(XtParent(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 /* No parent, must be a non-menubar menu */ if (parent->submenu_id == (Widget)0) return; menu->submenu_id = (Widget)0; /* Add menu separator */ if (menu_is_separator(menu->name)) { menu->id = XtVaCreateWidget("subMenu", xmSeparatorGadgetClass, parent->submenu_id, #if (XmVersion >= 1002) /* count the tearoff item (needed for LessTif) */ XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0), #endif NULL); gui_motif_menu_colors(menu->id); return; } label = XmStringCreate((char *)menu->dname, STRING_TAG); if (label == NULL) return; menu->id = XtVaCreateWidget("subMenu", xmPushButtonWidgetClass, parent->submenu_id, XmNlabelString, label, XmNmnemonic, menu->mnemonic, #if (XmVersion >= 1002) /* count the tearoff item (needed for LessTif) */ XmNpositionIndex, idx + (tearoff_val == (int)XmTEAR_OFF_ENABLED ? 1 : 0), #endif NULL); gui_motif_menu_colors(menu->id); gui_motif_menu_fontlist(menu->id); XmStringFree(label); if (menu->id != (Widget)0) { XtAddCallback(menu->id, XmNactivateCallback, gui_x11_menu_cb, (XtPointer)menu); /* add accelerator text */ gui_motif_add_actext(menu); } } #if (XmVersion <= 1002) || defined(PROTO) /* * This function will destroy/create the popup menus dynamically, * according to the value of 'mousemodel'. * This will fix the "right mouse button freeze" that occurs when * there exists a popup menu but it isn't managed. */ void gui_motif_update_mousemodel(menu) vimmenu_T *menu; { int idx = 0; /* When GUI hasn't started the menus have not been created. */ if (!gui.in_use) return; while (menu) { if (menu->children != NULL) { if (menu_is_popup(menu->name)) { if (mouse_model_popup()) { /* Popup menu will be used. Create the popup menus. */ gui_mch_add_menu(menu, idx); gui_motif_update_mousemodel(menu->children); } else { /* Popup menu will not be used. Destroy the popup menus. */ gui_motif_update_mousemodel(menu->children); gui_mch_destroy_menu(menu); } } } else if (menu_is_child_of_popup(menu)) { if (mouse_model_popup()) gui_mch_add_menu_item(menu, idx); else gui_mch_destroy_menu(menu); } menu = menu->next; ++idx; } } #endif void gui_mch_new_menu_colors() { if (menuBar == (Widget)0) return; gui_motif_menu_colors(menuBar); #ifdef FEAT_TOOLBAR gui_motif_menu_colors(toolBarFrame); gui_motif_menu_colors(toolBar); #endif gui_mch_submenu_change(root_menu, TRUE); } void gui_mch_new_menu_font() { if (menuBar == (Widget)0) return; gui_mch_submenu_change(root_menu, FALSE); { Dimension height; Position w, h; XtVaGetValues(menuBar, XmNheight, &height, NULL); gui.menu_height = height; 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 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 *toolbar; if (toolBar == (Widget)0) return; toolbar = gui_find_menu((char_u *)"ToolBar"); if (toolbar != NULL) gui_mch_submenu_change(toolbar, 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_motif_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); XFreePixmap(gui.dpy, mp->image_ins); get_toolbar_pixmap(mp, &mp->image, &mp->image_ins); if (mp->image != (Pixmap)0) XtVaSetValues(mp->id, XmNlabelPixmap, mp->image, XmNlabelInsensitivePixmap, mp->image_ins, NULL); } # ifdef FEAT_BEVAL /* If we have a tooltip, then we need to change it's font */ if (mp->tip != NULL) { Arg args[2]; args[0].name = XmNbackground; args[0].value = gui.tooltip_bg_pixel; args[1].name = XmNforeground; args[1].value = gui.tooltip_fg_pixel; XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); } # endif #endif } else { gui_motif_menu_fontlist(mp->id); #ifdef FEAT_BEVAL /* If we have a tooltip, then we need to change it's font */ if (mp->tip != NULL) { Arg args[1]; args[0].name = XmNfontList; args[0].value = (XtArgVal)gui_motif_fontset2fontlist( &gui.tooltip_fontset); XtSetValues(mp->tip->balloonLabel, &args[0], XtNumber(args)); } #endif } } if (mp->children != NULL) { #if (XmVersion >= 1002) /* Set the colors/font for the tear off widget */ if (mp->submenu_id != (Widget)0) { if (colors) gui_motif_menu_colors(mp->submenu_id); else gui_motif_menu_fontlist(mp->submenu_id); toggle_tearoff(mp->submenu_id); } #endif /* Set the colors for the children */ gui_mch_submenu_change(mp->children, colors); } } } /* * Destroy the machine specific menu widget. */ void gui_mch_destroy_menu(menu) vimmenu_T *menu; { /* Please be sure to destroy the parent widget first (i.e. menu->id). * On the other hand, problems have been reported that the submenu must be * deleted first... * * This code should be basically identical to that in the file gui_athena.c * because they are both Xt based. */ if (menu->submenu_id != (Widget)0) { XtDestroyWidget(menu->submenu_id); menu->submenu_id = (Widget)0; } if (menu->id != (Widget)0) { Widget parent; parent = XtParent(menu->id); #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 XtDestroyWidget(menu->id); menu->id = (Widget)0; if (parent == menuBar) gui_mch_compute_menu_height((Widget)0); #ifdef FEAT_TOOLBAR else if (parent == toolBar) { Cardinal num_children; /* When removing last toolbar item, don't display the toolbar. */ XtVaGetValues(toolBar, XmNnumChildren, &num_children, NULL); if (num_children == 0) gui_mch_show_toolbar(FALSE); else gui.toolbar_height = gui_mch_compute_toolbar_height(); } #endif } } /* ARGSUSED */ void gui_mch_show_popupmenu(menu) vimmenu_T *menu; { #ifdef MOTIF_POPUP XmMenuPosition(menu->submenu_id, gui_x11_get_last_mouse_event()); XtManageChild(menu->submenu_id); #endif } #endif /* FEAT_MENU */ /* * Set the menu and scrollbar colors to their default values. */ void gui_mch_def_colors() { if (gui.in_use) { /* Use the values saved when starting up. These should come from the * window manager or a resources file. */ gui.menu_fg_pixel = gui.menu_def_fg_pixel; gui.menu_bg_pixel = gui.menu_def_bg_pixel; gui.scroll_fg_pixel = gui.scroll_def_fg_pixel; gui.scroll_bg_pixel = gui.scroll_def_bg_pixel; #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; { if (sb->id != (Widget)0) XtVaSetValues(sb->id, XmNvalue, val, XmNsliderSize, size, XmNpageIncrement, (size > 2 ? size - 2 : 1), XmNmaximum, max + 1, /* Motif has max one past the end */ NULL); } 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) { if (sb->type == SBAR_LEFT || sb->type == SBAR_RIGHT) { if (y == 0) h -= gui.border_offset; else y -= gui.border_offset; XtVaSetValues(sb->id, XmNtopOffset, y, XmNbottomOffset, -y - h, XmNwidth, w, NULL); } else XtVaSetValues(sb->id, XmNtopOffset, y, XmNleftOffset, x, XmNrightOffset, gui.which_scrollbars[SBAR_RIGHT] ? gui.scrollbar_width : 0, XmNheight, h, NULL); XtManageChild(sb->id); } } void gui_mch_enable_scrollbar(sb, flag) scrollbar_T *sb; int flag; { Arg args[16]; int n; if (sb->id != (Widget)0) { n = 0; if (flag) { switch (sb->type) { case SBAR_LEFT: XtSetArg(args[n], XmNleftOffset, gui.scrollbar_width); n++; break; case SBAR_RIGHT: XtSetArg(args[n], XmNrightOffset, gui.scrollbar_width); n++; break; case SBAR_BOTTOM: XtSetArg(args[n], XmNbottomOffset, gui.scrollbar_height);n++; break; } XtSetValues(textArea, args, n); XtManageChild(sb->id); } else { if (!gui.which_scrollbars[sb->type]) { /* The scrollbars of this type are all disabled, adjust the * textArea attachment offset. */ switch (sb->type) { case SBAR_LEFT: XtSetArg(args[n], XmNleftOffset, 0); n++; break; case SBAR_RIGHT: XtSetArg(args[n], XmNrightOffset, 0); n++; break; case SBAR_BOTTOM: XtSetArg(args[n], XmNbottomOffset, 0);n++; break; } XtSetValues(textArea, args, n); } XtUnmanageChild(sb->id); } } } void gui_mch_create_scrollbar(sb, orient) scrollbar_T *sb; int orient; /* SBAR_VERT or SBAR_HORIZ */ { Arg args[16]; int n; n = 0; XtSetArg(args[n], XmNshadowThickness, 1); n++; XtSetArg(args[n], XmNminimum, 0); n++; XtSetArg(args[n], XmNorientation, (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++; switch (sb->type) { case SBAR_LEFT: XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; break; case SBAR_RIGHT: XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_OPPOSITE_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; break; case SBAR_BOTTOM: XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; break; } sb->id = XtCreateWidget("scrollBar", xmScrollBarWidgetClass, textAreaForm, args, n); /* Remember the default colors, needed for ":hi clear". */ if (gui.scroll_def_bg_pixel == (guicolor_T)0 && gui.scroll_def_fg_pixel == (guicolor_T)0) XtVaGetValues(sb->id, XmNbackground, &gui.scroll_def_bg_pixel, XmNforeground, &gui.scroll_def_fg_pixel, NULL); if (sb->id != (Widget)0) { gui_mch_set_scrollbar_colors(sb); XtAddCallback(sb->id, XmNvalueChangedCallback, scroll_cb, (XtPointer)sb->ident); XtAddCallback(sb->id, XmNdragCallback, scroll_cb, (XtPointer)sb->ident); XtAddEventHandler(sb->id, KeyPressMask, FALSE, gui_x11_key_hit_cb, (XtPointer)0); } } #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) { if (gui.scroll_bg_pixel != INVALCOLOR) { #if (XmVersion>=1002) XmChangeColor(sb->id, gui.scroll_bg_pixel); #else XtVaSetValues(sb->id, XmNtroughColor, gui.scroll_bg_pixel, NULL); #endif } if (gui.scroll_fg_pixel != INVALCOLOR) XtVaSetValues(sb->id, XmNforeground, gui.scroll_fg_pixel, #if (XmVersion<1002) XmNbackground, gui.scroll_fg_pixel, #endif NULL); } /* This is needed for the rectangle below the vertical scrollbars. */ if (sb == &gui.bottom_sbar && textAreaForm != (Widget)0) gui_motif_scroll_colors(textAreaForm); } /* * Miscellaneous stuff: */ Window gui_x11_get_wid() { return(XtWindow(textArea)); } #if defined(FEAT_BROWSE) || defined(PROTO) /* * file selector related stuff */ #include #include typedef struct dialog_callback_arg { char * args; /* not used right now */ int id; } dcbarg_T; static Widget dialog_wgt; static char *browse_fname = NULL; static XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; /* used to set up XmStrings */ static void DialogCancelCB __ARGS((Widget, XtPointer, XtPointer)); static void DialogAcceptCB __ARGS((Widget, XtPointer, XtPointer)); /* * This function is used to translate the predefined label text of the * precomposed dialogs. We do this explicitly to allow: * * - usage of gettext for translation, as in all the other places. * * - equalize the messages between different GUI implementations as far as * possible. */ static void set_predefined_label __ARGS((Widget parent, String name, char * new_label)); static void set_predefined_label(parent, name, new_label) Widget parent; String name; char * new_label; { XmString str; Widget w; w = XtNameToWidget(parent, name); if (!w) return; str = XmStringCreate(new_label, STRING_TAG); if (str) { XtVaSetValues(w, XmNlabelString, str, NULL); XmStringFree(str); } } /* * 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; /* title for the window */ char_u *dflt; /* default name */ char_u *ext; /* not used (extension added) */ char_u *initdir; /* initial directory, NULL for current dir */ char_u *filter; /* file name filter */ { char_u dirbuf[MAXPATHL]; char_u dfltbuf[MAXPATHL]; char_u *pattern; char_u *tofree = NULL; dialog_wgt = XmCreateFileSelectionDialog(vimShell, (char *)title, NULL, 0); if (initdir == NULL || *initdir == NUL) { mch_dirname(dirbuf, MAXPATHL); initdir = dirbuf; } if (dflt == NULL) dflt = (char_u *)""; else if (STRLEN(initdir) + STRLEN(dflt) + 2 < MAXPATHL) { /* The default selection should be the full path, "dflt" is only the * file name. */ STRCPY(dfltbuf, initdir); add_pathsep(dfltbuf); STRCAT(dfltbuf, dflt); dflt = dfltbuf; } /* Can only use one pattern for a file name. Get the first pattern out of * the filter. An empty pattern means everything matches. */ if (filter == NULL) pattern = (char_u *)""; else { char_u *s, *p; s = filter; for (p = filter; *p != NUL; ++p) { if (*p == '\t') /* end of description, start of pattern */ s = p + 1; if (*p == ';' || *p == '\n') /* end of (first) pattern */ break; } pattern = vim_strnsave(s, p - s); tofree = pattern; if (pattern == NULL) pattern = (char_u *)""; } XtVaSetValues(dialog_wgt, XtVaTypedArg, XmNdirectory, XmRString, (char *)initdir, STRLEN(initdir) + 1, XtVaTypedArg, XmNdirSpec, XmRString, (char *)dflt, STRLEN(dflt) + 1, XtVaTypedArg, XmNpattern, XmRString, (char *)pattern, STRLEN(pattern) + 1, XtVaTypedArg, XmNdialogTitle, XmRString, (char *)title, STRLEN(title) + 1, NULL); set_predefined_label(dialog_wgt, "Apply", _("Filter")); set_predefined_label(dialog_wgt, "Cancel", _("Cancel")); set_predefined_label(dialog_wgt, "Dir", _("Directories")); set_predefined_label(dialog_wgt, "FilterLabel", _("Filter")); set_predefined_label(dialog_wgt, "Help", _("Help")); set_predefined_label(dialog_wgt, "Items", _("Files")); set_predefined_label(dialog_wgt, "OK", _("OK")); set_predefined_label(dialog_wgt, "Selection", _("Selection")); gui_motif_menu_colors(dialog_wgt); if (gui.scroll_bg_pixel != INVALCOLOR) XtVaSetValues(dialog_wgt, XmNtroughColor, gui.scroll_bg_pixel, NULL); XtAddCallback(dialog_wgt, XmNokCallback, DialogAcceptCB, (XtPointer)0); XtAddCallback(dialog_wgt, XmNcancelCallback, DialogCancelCB, (XtPointer)0); /* We have no help in this window, so hide help button */ XtUnmanageChild(XmFileSelectionBoxGetChild(dialog_wgt, (unsigned char)XmDIALOG_HELP_BUTTON)); manage_centered(dialog_wgt); /* sit in a loop until the dialog box has gone away */ do { XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt), (XtInputMask)XtIMAll); } while (XtIsManaged(dialog_wgt)); XtDestroyWidget(dialog_wgt); vim_free(tofree); if (browse_fname == NULL) return NULL; return vim_strsave((char_u *)browse_fname); } /* * The code below was originally taken from * /usr/examples/motif/xmsamplers/xmeditor.c * on Digital Unix 4.0d, but heavily modified. */ /* * Process callback from Dialog cancel actions. */ /* ARGSUSED */ static void DialogCancelCB(w, client_data, call_data) Widget w; /* widget id */ XtPointer client_data; /* data from application */ XtPointer call_data; /* data from widget class */ { if (browse_fname != NULL) { XtFree(browse_fname); browse_fname = NULL; } XtUnmanageChild(dialog_wgt); } /* * Process callback from Dialog actions. */ /* ARGSUSED */ static void DialogAcceptCB(w, client_data, call_data) Widget w; /* widget id */ XtPointer client_data; /* data from application */ XtPointer call_data; /* data from widget class */ { XmFileSelectionBoxCallbackStruct *fcb; if (browse_fname != NULL) { XtFree(browse_fname); browse_fname = NULL; } fcb = (XmFileSelectionBoxCallbackStruct *)call_data; /* get the filename from the file selection box */ XmStringGetLtoR(fcb->value, charset, &browse_fname); /* popdown the file selection box */ XtUnmanageChild(dialog_wgt); } #endif /* FEAT_BROWSE */ #if defined(FEAT_GUI_DIALOG) || defined(PROTO) static int dialogStatus; 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)); /* * 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]; KeySym key_sym; if (XLookupString(&(event->xkey), buf, 2, &key_sym, NULL) == 1) { if (*buf == CAR) dialogStatus = 1; else if (*buf == ESC) dialogStatus = 2; } if ((key_sym == XK_Left || key_sym == XK_Right) && !(event->xkey.state & ShiftMask)) XmTextFieldClearSelection(w, XtLastTimestampProcessed(gui.dpy)); } /* ARGSUSED */ static void butproc(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { dialogStatus = (int)(long)client_data + 1; } static void gui_motif_set_fontlist __ARGS((Widget wg)); /* * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget. */ static void gui_motif_set_fontlist(wg) Widget wg; { XmFontList fl; fl = #ifdef FEAT_XFONTSET gui.fontset != NOFONTSET ? gui_motif_fontset2fontlist((XFontSet *)&gui.fontset) : #endif gui_motif_create_fontlist((XFontStruct *)gui.norm_font); if (fl != NULL) { XtVaSetValues(wg, XmNfontList, fl, NULL); XmFontListFree(fl); } } #ifdef HAVE_XPM static Widget create_pixmap_label(Widget parent, String name, char **data, ArgList args, Cardinal arg); static Widget create_pixmap_label(parent, name, data, args, arg) Widget parent; String name; char **data; ArgList args; Cardinal arg; { Widget label; Display *dsp; Screen *scr; int depth; Pixmap pixmap = 0; XpmAttributes attr; Boolean rs; XpmColorSymbol color[5] = { {"none", NULL, 0}, {"iconColor1", NULL, 0}, {"bottomShadowColor", NULL, 0}, {"topShadowColor", NULL, 0}, {"selectColor", NULL, 0} }; label = XmCreateLabelGadget(parent, name, args, arg); /* * We need to be carefull here, since in case of gadgets, there is * no way to get the background color directly from the widget itself. * In such cases we get it from The Core part of his parent instead. */ dsp = XtDisplayOfObject(label); scr = XtScreenOfObject(label); XtVaGetValues(XtIsSubclass(label, coreWidgetClass) ? label : XtParent(label), XmNdepth, &depth, XmNbackground, &color[0].pixel, XmNforeground, &color[1].pixel, XmNbottomShadowColor, &color[2].pixel, XmNtopShadowColor, &color[3].pixel, XmNhighlight, &color[4].pixel, NULL); attr.valuemask = XpmColorSymbols | XpmCloseness | XpmDepth; attr.colorsymbols = color; attr.numsymbols = 5; attr.closeness = 65535; attr.depth = depth; XpmCreatePixmapFromData(dsp, RootWindowOfScreen(scr), data, &pixmap, NULL, &attr); XtVaGetValues(label, XmNrecomputeSize, &rs, NULL); XtVaSetValues(label, XmNrecomputeSize, True, NULL); XtVaSetValues(label, XmNlabelType, XmPIXMAP, XmNlabelPixmap, pixmap, NULL); XtVaSetValues(label, XmNrecomputeSize, rs, NULL); return label; } #endif /* ARGSUSED */ int gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) int type; char_u *title; char_u *message; char_u *button_names; int dfltbutton; char_u *textfield; /* buffer of size IOSIZE */ { char_u *buts; char_u *p, *next; XtAppContext app; XmString label; int butcount; Widget dialogform = NULL; Widget form = NULL; Widget dialogtextfield = NULL; Widget *buttons; Widget sep_form = NULL; Boolean vertical; Widget separator = NULL; int n; Arg args[6]; #ifdef HAVE_XPM char **icon_data = NULL; Widget dialogpixmap = NULL; #endif if (title == NULL) title = (char_u *)_("Vim dialog"); /* if our pointer is currently hidden, then we should show it. */ gui_mch_mousehide(FALSE); dialogform = XmCreateFormDialog(vimShell, (char *)"dialog", NULL, 0); /* Check 'v' flag in 'guioptions': vertical button placement. */ vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); /* Set the title of the Dialog window */ label = XmStringCreateSimple((char *)title); if (label == NULL) return -1; XtVaSetValues(dialogform, XmNdialogTitle, label, XmNhorizontalSpacing, 4, XmNverticalSpacing, vertical ? 0 : 4, NULL); XmStringFree(label); /* make a copy, so that we can insert NULs */ buts = vim_strsave(button_names); if (buts == NULL) return -1; /* Count the number of buttons and allocate buttons[]. */ butcount = 1; for (p = buts; *p; ++p) if (*p == DLG_BUTTON_SEP) ++butcount; buttons = (Widget *)alloc((unsigned)(butcount * sizeof(Widget))); if (buttons == NULL) { vim_free(buts); return -1; } /* * Create the buttons. */ sep_form = (Widget) 0; 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; } } label = XmStringCreate(_((char *)p), STRING_TAG); if (label == NULL) break; buttons[butcount] = XtVaCreateManagedWidget("button", xmPushButtonWidgetClass, dialogform, XmNlabelString, label, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, XmNshowAsDefault, butcount == dfltbutton - 1, XmNdefaultButtonShadowThickness, 1, NULL); XmStringFree(label); /* Layout properly. */ if (butcount > 0) { if (vertical) XtVaSetValues(buttons[butcount], XmNtopWidget, buttons[butcount - 1], NULL); else { if (*next == NUL) { XtVaSetValues(buttons[butcount], XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 4, NULL); /* fill in a form as invisible separator */ sep_form = XtVaCreateWidget("separatorForm", xmFormWidgetClass, dialogform, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, buttons[butcount - 1], XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, buttons[butcount], XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, NULL); XtManageChild(sep_form); } else { XtVaSetValues(buttons[butcount], XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, buttons[butcount - 1], NULL); } } } else if (!vertical) { if (*next == NUL) { XtVaSetValues(buttons[0], XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 4, NULL); /* fill in a form as invisible separator */ sep_form = XtVaCreateWidget("separatorForm", xmFormWidgetClass, dialogform, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, buttons[0], XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, NULL); XtManageChild(sep_form); } else XtVaSetValues(buttons[0], XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, NULL); } XtAddCallback(buttons[butcount], XmNactivateCallback, (XtCallbackProc)butproc, (XtPointer)(long)butcount); p = next; } vim_free(buts); separator = (Widget) 0; if (butcount > 0) { /* Create the separator for beauty. */ n = 0; XtSetArg(args[n], XmNorientation, XmHORIZONTAL); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNbottomWidget, buttons[0]); n++; XtSetArg(args[n], XmNbottomOffset, 4); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; separator = XmCreateSeparatorGadget(dialogform, "separator", args, n); XtManageChild(separator); } if (textfield != NULL) { dialogtextfield = XtVaCreateWidget("textField", xmTextFieldWidgetClass, dialogform, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); if (butcount > 0) XtVaSetValues(dialogtextfield, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, separator, NULL); else XtVaSetValues(dialogtextfield, XmNbottomAttachment, XmATTACH_FORM, NULL); gui_motif_set_fontlist(dialogtextfield); XmTextFieldSetString(dialogtextfield, (char *)textfield); XtManageChild(dialogtextfield); XtAddEventHandler(dialogtextfield, KeyPressMask, False, (XtEventHandler)keyhit_callback, (XtPointer)NULL); } /* Form holding both message and pixmap labels */ form = XtVaCreateWidget("separatorForm", xmFormWidgetClass, dialogform, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, NULL); XtManageChild(form); #ifdef HAVE_XPM /* Add a pixmap, left of the message. */ switch (type) { case VIM_GENERIC: icon_data = generic_xpm; break; case VIM_ERROR: icon_data = error_xpm; break; case VIM_WARNING: icon_data = alert_xpm; break; case VIM_INFO: icon_data = info_xpm; break; case VIM_QUESTION: icon_data = quest_xpm; break; default: icon_data = generic_xpm; } n = 0; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNtopOffset, 8); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomOffset, 8); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNleftOffset, 8); n++; dialogpixmap = create_pixmap_label(form, "dialogPixmap", icon_data, args, n); XtManageChild(dialogpixmap); #endif /* Create the dialog message. */ label = XmStringLtoRCreate((char *)message, STRING_TAG); if (label == NULL) return -1; (void)XtVaCreateManagedWidget("dialogMessage", xmLabelGadgetClass, form, XmNlabelString, label, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, #ifdef HAVE_XPM XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, dialogpixmap, #else XmNleftAttachment, XmATTACH_FORM, #endif XmNleftOffset, 8, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 8, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 8, NULL); XmStringFree(label); if (textfield != NULL) { XtVaSetValues(form, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, dialogtextfield, NULL); } else { if (butcount > 0) XtVaSetValues(form, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, separator, NULL); else XtVaSetValues(form, XmNbottomAttachment, XmATTACH_FORM, NULL); } if (dfltbutton < 1) dfltbutton = 1; if (dfltbutton > butcount) dfltbutton = butcount; XtVaSetValues(dialogform, XmNdefaultButton, buttons[dfltbutton - 1], NULL); if (textfield != NULL) XtVaSetValues(dialogform, XmNinitialFocus, dialogtextfield, NULL); else XtVaSetValues(dialogform, XmNinitialFocus, buttons[dfltbutton - 1], NULL); manage_centered(dialogform); if (textfield != NULL && *textfield != NUL) { /* This only works after the textfield has been realised. */ XmTextFieldSetSelection(dialogtextfield, (XmTextPosition)0, (XmTextPosition)STRLEN(textfield), XtLastTimestampProcessed(gui.dpy)); XmTextFieldSetCursorPosition(dialogtextfield, (XmTextPosition)STRLEN(textfield)); } app = XtWidgetToApplicationContext(dialogform); /* Loop until a button is pressed or the dialog is killed somehow. */ dialogStatus = -1; for (;;) { XtAppProcessEvent(app, (XtInputMask)XtIMAll); if (dialogStatus >= 0 || !XtIsManaged(dialogform)) break; } vim_free(buttons); if (textfield != NULL) { p = (char_u *)XmTextGetString(dialogtextfield); if (p == NULL || dialogStatus < 0) *textfield = NUL; else { STRNCPY(textfield, p, IOSIZE); textfield[IOSIZE - 1] = NUL; } } XtDestroyWidget(dialogform); return dialogStatus; } #endif /* FEAT_GUI_DIALOG */ #if defined(FEAT_FOOTER) || defined(PROTO) static int gui_mch_compute_footer_height() { Dimension height; /* total Toolbar height */ Dimension top; /* XmNmarginTop */ Dimension bottom; /* XmNmarginBottom */ Dimension shadow; /* XmNshadowThickness */ XtVaGetValues(footer, XmNheight, &height, XmNmarginTop, &top, XmNmarginBottom, &bottom, XmNshadowThickness, &shadow, NULL); return (int) height + top + bottom + (shadow << 1); } #if 0 /* not used */ void gui_mch_set_footer_pos(h) int h; /* textArea height */ { XtVaSetValues(footer, XmNtopOffset, h + 7, NULL); } #endif void gui_mch_enable_footer(showit) int showit; { if (showit) { gui.footer_height = gui_mch_compute_footer_height(); XtManageChild(footer); } else { gui.footer_height = 0; XtUnmanageChild(footer); } XtVaSetValues(textAreaForm, XmNbottomOffset, gui.footer_height, NULL); } void gui_mch_set_footer(s) char_u *s; { XmString xms; xms = XmStringCreate((char *)s, STRING_TAG); XtVaSetValues(footer, XmNlabelString, xms, NULL); XmStringFree(xms); } #endif #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, XmNnumChildren, &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, XmNchildren, &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[1]; int n = 0; /* Enable/Disable tooltip (OK to enable while * currently enabled) */ if (cur->tip != NULL) (*action)(cur->tip); if (!menu_is_separator(cur->name)) { if (text == 1 || cur->image == 0) XtSetArg(args[n], XmNlabelType, XmSTRING); else XtSetArg(args[n], XmNlabelType, XmPIXMAP); 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(XtParent(toolBar)); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); if (XtIsManaged(menuBar)) XtVaSetValues(XtParent(toolBar), XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); else XtVaSetValues(XtParent(toolBar), XmNtopAttachment, XmATTACH_FORM, NULL); } else { gui.toolbar_height = 0; if (XtIsManaged(menuBar)) XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); else XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_FORM, NULL); XtUnmanageChild(XtParent(toolBar)); } gui_set_shellsize(FALSE, FALSE); } /* * 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() { if (textArea != NULL) XmProcessTraversal(textArea, XmTRAVERSE_CURRENT); } 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 && toolBarFrame != (Widget)0) { /* get height of XmFrame parent */ XtVaGetValues(toolBarFrame, XmNshadowThickness, &shadowThickness, NULL); XtVaGetValues(toolBar, XmNmarginHeight, &marginHeight, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i = 0; i < numChildren; i++) { whgt = 0; XtVaGetValues(children[i], XmNheight, &whgt, NULL); if (height < whgt) height = whgt; } } return (int)(height + (marginHeight << 1) + (shadowThickness << 1)); } #if 0 /* these are never called. */ /* * The next toolbar enter/leave callbacks make sure the text area gets the * keyboard focus when the pointer is not in the toolbar. */ /*ARGSUSED*/ static void toolbar_enter_cb(w, client_data, event, cont) Widget w; XtPointer client_data; XEvent *event; Boolean *cont; { XmProcessTraversal(toolBar, XmTRAVERSE_CURRENT); } /*ARGSUSED*/ static void toolbar_leave_cb(w, client_data, event, cont) Widget w; XtPointer client_data; XEvent *event; Boolean *cont; { XmProcessTraversal(textArea, XmTRAVERSE_CURRENT); } #endif # ifdef FEAT_FOOTER /* * The next toolbar enter/leave callbacks should really do balloon help. But * I have to use footer help for backwards compatability. Hopefully both will * get implemented and the user will have a choice. */ /*ARGSUSED*/ static void toolbarbutton_enter_cb(w, client_data, event, cont) Widget w; XtPointer client_data; XEvent *event; Boolean *cont; { vimmenu_T *menu = (vimmenu_T *) client_data; if (menu->strings[MENU_INDEX_TIP] != NULL) { if (vim_strchr(p_go, GO_FOOTER) != NULL) gui_mch_set_footer(menu->strings[MENU_INDEX_TIP]); } } /*ARGSUSED*/ static void toolbarbutton_leave_cb(w, client_data, event, cont) Widget w; XtPointer client_data; XEvent *event; Boolean *cont; { gui_mch_set_footer((char_u *) ""); } # endif void gui_mch_get_toolbar_colors(bgp, fgp, bsp, tsp, hsp) Pixel *bgp; Pixel *fgp; Pixel *bsp; Pixel *tsp; Pixel *hsp; { XtVaGetValues(toolBar, XmNbackground, bgp, XmNforeground, fgp, XmNbottomShadowColor, bsp, XmNtopShadowColor, tsp, XmNhighlightColor, hsp, NULL); } #endif /* * Set the colors of Widget "id" to the menu colors. */ static void gui_motif_menu_colors(id) Widget id; { if (gui.menu_bg_pixel != INVALCOLOR) #if (XmVersion >= 1002) XmChangeColor(id, gui.menu_bg_pixel); #else XtVaSetValues(id, XmNbackground, gui.menu_bg_pixel, NULL); #endif if (gui.menu_fg_pixel != INVALCOLOR) XtVaSetValues(id, XmNforeground, gui.menu_fg_pixel, NULL); } /* * Set the colors of Widget "id" to the scrollbar colors. */ static void gui_motif_scroll_colors(id) Widget id; { if (gui.scroll_bg_pixel != INVALCOLOR) #if (XmVersion >= 1002) XmChangeColor(id, gui.scroll_bg_pixel); #else XtVaSetValues(id, XmNbackground, gui.scroll_bg_pixel, NULL); #endif if (gui.scroll_fg_pixel != INVALCOLOR) XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL); } #ifdef FEAT_MENU /* * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font. */ static void gui_motif_menu_fontlist(id) Widget id; { #ifdef FONTSET_ALWAYS if (gui.menu_fontset != NOFONTSET) { XmFontList fl; fl = gui_motif_fontset2fontlist((XFontSet *)&gui.menu_fontset); if (fl != NULL) { if (XtIsManaged(id)) { XtUnmanageChild(id); XtVaSetValues(id, XmNfontList, fl, NULL); /* We should force the widget to recalculate it's * geometry now. */ XtManageChild(id); } else XtVaSetValues(id, XmNfontList, fl, NULL); XmFontListFree(fl); } } #else if (gui.menu_font != NOFONT) { XmFontList fl; fl = gui_motif_create_fontlist((XFontStruct *)gui.menu_font); if (fl != NULL) { if (XtIsManaged(id)) { XtUnmanageChild(id); XtVaSetValues(id, XmNfontList, fl, NULL); /* We should force the widget to recalculate it's * geometry now. */ XtManageChild(id); } else XtVaSetValues(id, XmNfontList, fl, NULL); XmFontListFree(fl); } } #endif } #endif /* * We don't create it twice for the sake of speed. */ typedef struct _SharedFindReplace { Widget dialog; /* the main dialog widget */ Widget wword; /* 'Exact match' check button */ Widget mcase; /* 'match case' check button */ Widget up; /* search direction 'Up' radio button */ Widget down; /* search direction 'Down' radio button */ Widget what; /* 'Find what' entry text widget */ Widget with; /* 'Replace with' entry text widget */ Widget find; /* 'Find Next' action button */ Widget replace; /* 'Replace With' action button */ Widget all; /* 'Replace All' action button */ Widget undo; /* 'Undo' action button */ Widget cancel; } SharedFindReplace; static SharedFindReplace find_widgets = { NULL }; static SharedFindReplace repl_widgets = { NULL }; static void find_replace_destroy_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void find_replace_dismiss_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void entry_activate_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void find_replace_callback __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void find_replace_keypress __ARGS((Widget w, SharedFindReplace * frdp, XKeyEvent * event)); static void find_replace_dialog_create __ARGS((char_u *entry_text, int do_replace)); /*ARGSUSED*/ static void find_replace_destroy_callback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { SharedFindReplace *cd = (SharedFindReplace *)client_data; if (cd != NULL) cd->dialog = (Widget)0; } /*ARGSUSED*/ static void find_replace_dismiss_callback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { SharedFindReplace *cd = (SharedFindReplace *)client_data; if (cd != NULL) XtUnmanageChild(cd->dialog); } /*ARGSUSED*/ static void entry_activate_callback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT); } /*ARGSUSED*/ static void find_replace_callback(w, client_data, call_data) Widget w; XtPointer client_data; XtPointer call_data; { long_u flags = (long_u)client_data; char *find_text, *repl_text; Boolean direction_down = TRUE; Boolean wword; Boolean mcase; SharedFindReplace *sfr; if (flags == FRD_UNDO) { char_u *save_cpo = p_cpo; /* No need to be Vi compatible here. */ p_cpo = (char_u *)""; u_undo(1); p_cpo = save_cpo; gui_update_screen(); return; } /* Get the search/replace strings from the dialog */ if (flags == FRD_FINDNEXT) { repl_text = NULL; sfr = &find_widgets; } else { repl_text = XmTextFieldGetString(repl_widgets.with); sfr = &repl_widgets; } find_text = XmTextFieldGetString(sfr->what); XtVaGetValues(sfr->down, XmNset, &direction_down, NULL); XtVaGetValues(sfr->wword, XmNset, &wword, NULL); XtVaGetValues(sfr->mcase, XmNset, &mcase, NULL); if (wword) flags |= FRD_WHOLE_WORD; if (mcase) flags |= FRD_MATCH_CASE; (void)gui_do_findrepl((int)flags, (char_u *)find_text, (char_u *)repl_text, direction_down); if (find_text != NULL) XtFree(find_text); if (repl_text != NULL) XtFree(repl_text); } /*ARGSUSED*/ static void find_replace_keypress(w, frdp, event) Widget w; SharedFindReplace *frdp; XKeyEvent *event; { KeySym keysym; if (frdp == NULL) return; keysym = XLookupKeysym(event, 0); /* the scape key pops the whole dialog down */ if (keysym == XK_Escape) XtUnmanageChild(frdp->dialog); } static void find_replace_dialog_create(arg, do_replace) char_u *arg; int do_replace; { SharedFindReplace *frdp; Widget separator; Widget input_form; Widget button_form; Widget toggle_form; Widget frame; XmString str; int n; Arg args[6]; int wword = FALSE; int mcase = !p_ic; Dimension width; Dimension widest; char_u *entry_text; frdp = do_replace ? &repl_widgets : &find_widgets; /* Get the search string to use. */ entry_text = get_find_dialog_text(arg, &wword, &mcase); /* If the dialog already exists, just raise it. */ if (frdp->dialog) { /* If the window is already up, just pop it to the top */ if (XtIsManaged(frdp->dialog)) XMapRaised(XtDisplay(frdp->dialog), XtWindow(XtParent(frdp->dialog))); else XtManageChild(frdp->dialog); XtPopup(XtParent(frdp->dialog), XtGrabNone); XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT); if (entry_text != NULL) XmTextFieldSetString(frdp->what, (char *)entry_text); vim_free(entry_text); XtVaSetValues(frdp->wword, XmNset, wword, NULL); return; } /* Create a fresh new dialog window */ if (do_replace) str = XmStringCreateSimple(_("VIM - Search and Replace...")); else str = XmStringCreateSimple(_("VIM - Search...")); n = 0; XtSetArg(args[n], XmNautoUnmanage, False); n++; XtSetArg(args[n], XmNnoResize, True); n++; XtSetArg(args[n], XmNdialogTitle, str); n++; frdp->dialog = XmCreateFormDialog(vimShell, "findReplaceDialog", args, n); XmStringFree(str); XtAddCallback(frdp->dialog, XmNdestroyCallback, find_replace_destroy_callback, frdp); button_form = XtVaCreateWidget("buttonForm", xmFormWidgetClass, frdp->dialog, XmNrightAttachment, XmATTACH_FORM, XmNrightOffset, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, NULL); str = XmStringCreateSimple(_("Find Next")); frdp->find = XtVaCreateManagedWidget("findButton", xmPushButtonWidgetClass, button_form, XmNlabelString, str, XmNsensitive, True, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(frdp->find, XmNactivateCallback, find_replace_callback, (XtPointer) (do_replace ? FRD_R_FINDNEXT : FRD_FINDNEXT)); if (do_replace) { str = XmStringCreateSimple(_("Replace")); frdp->replace = XtVaCreateManagedWidget("replaceButton", xmPushButtonWidgetClass, button_form, XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->find, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(frdp->replace, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACE); str = XmStringCreateSimple(_("Replace All")); frdp->all = XtVaCreateManagedWidget("replaceAllButton", xmPushButtonWidgetClass, button_form, XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->replace, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(frdp->all, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACEALL); str = XmStringCreateSimple(_("Undo")); frdp->undo = XtVaCreateManagedWidget("undoButton", xmPushButtonWidgetClass, button_form, XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->all, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(frdp->undo, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_UNDO); } str = XmStringCreateSimple(_("Cancel")); frdp->cancel = XtVaCreateManagedWidget("closeButton", xmPushButtonWidgetClass, button_form, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(str); XtAddCallback(frdp->cancel, XmNactivateCallback, find_replace_dismiss_callback, frdp); XtManageChild(button_form); n = 0; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; XtSetArg(args[n], XmNrightWidget, button_form); n++; XtSetArg(args[n], XmNrightOffset, 4); n++; XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; separator = XmCreateSeparatorGadget(frdp->dialog, "separator", args, n); XtManageChild(separator); input_form = XtVaCreateWidget("inputForm", xmFormWidgetClass, frdp->dialog, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, separator, XmNrightOffset, 4, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, NULL); { Widget label_what; Widget label_with = (Widget)0; str = XmStringCreateSimple(_("Find what:")); label_what = XtVaCreateManagedWidget("whatLabel", xmLabelGadgetClass, input_form, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, NULL); XmStringFree(str); frdp->what = XtVaCreateManagedWidget("whatText", xmTextFieldWidgetClass, input_form, XmNtopAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, NULL); if (do_replace) { frdp->with = XtVaCreateManagedWidget("withText", xmTextFieldWidgetClass, input_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->what, XmNtopOffset, 4, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); XtAddCallback(frdp->with, XmNactivateCallback, find_replace_callback, (XtPointer) FRD_R_FINDNEXT); str = XmStringCreateSimple(_("Replace with:")); label_with = XtVaCreateManagedWidget("withLabel", xmLabelGadgetClass, input_form, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->what, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(str); /* * Make the entry activation only change the input focus onto the * with item. */ XtAddCallback(frdp->what, XmNactivateCallback, entry_activate_callback, frdp->with); XtAddEventHandler(frdp->with, KeyPressMask, False, (XtEventHandler)find_replace_keypress, (XtPointer) frdp); } else { /* * Make the entry activation do the search. */ XtAddCallback(frdp->what, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_FINDNEXT); } XtAddEventHandler(frdp->what, KeyPressMask, False, (XtEventHandler)find_replace_keypress, (XtPointer)frdp); /* Get the maximum width between the label widgets and line them up. */ n = 0; XtSetArg(args[n], XmNwidth, &width); n++; XtGetValues(label_what, args, n); widest = width; if (do_replace) { XtGetValues(label_with, args, n); if (width > widest) widest = width; } XtVaSetValues(frdp->what, XmNleftOffset, widest, NULL); if (do_replace) XtVaSetValues(frdp->with, XmNleftOffset, widest, NULL); } XtManageChild(input_form); { Widget radio_box; frame = XtVaCreateWidget("directionFrame", xmFrameWidgetClass, frdp->dialog, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, input_form, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, XmNrightAttachment, XmATTACH_OPPOSITE_WIDGET, XmNrightWidget, input_form, NULL); str = XmStringCreateSimple(_("Direction")); (void)XtVaCreateManagedWidget("directionFrameLabel", xmLabelGadgetClass, frame, XmNlabelString, str, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, XmNchildType, XmFRAME_TITLE_CHILD, NULL); XmStringFree(str); radio_box = XmCreateRadioBox(frame, "radioBox", (ArgList)NULL, 0); str = XmStringCreateSimple( _("Up")); frdp->up = XtVaCreateManagedWidget("upRadioButton", xmToggleButtonGadgetClass, radio_box, XmNlabelString, str, XmNset, False, NULL); XmStringFree(str); str = XmStringCreateSimple(_("Down")); frdp->down = XtVaCreateManagedWidget("downRadioButton", xmToggleButtonGadgetClass, radio_box, XmNlabelString, str, XmNset, True, NULL); XmStringFree(str); XtManageChild(radio_box); XtManageChild(frame); } toggle_form = XtVaCreateWidget("toggleForm", xmFormWidgetClass, frdp->dialog, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, frame, XmNrightOffset, 4, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, input_form, XmNtopOffset, 4, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, NULL); str = XmStringCreateSimple(_("Match whole word only")); frdp->wword = XtVaCreateManagedWidget("wordToggle", xmToggleButtonGadgetClass, toggle_form, XmNlabelString, str, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 4, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNset, wword, NULL); XmStringFree(str); str = XmStringCreateSimple(_("Match case")); frdp->mcase = XtVaCreateManagedWidget("caseToggle", xmToggleButtonGadgetClass, toggle_form, XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNleftOffset, 4, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->wword, XmNtopOffset, 4, XmNset, mcase, NULL); XmStringFree(str); XtManageChild(toggle_form); if (entry_text != NULL) XmTextFieldSetString(frdp->what, (char *)entry_text); vim_free(entry_text); XtManageChild(frdp->dialog); XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT); } void gui_mch_find_dialog(eap) exarg_T *eap; { if (!gui.in_use) return; find_replace_dialog_create(eap->arg, FALSE); } void gui_mch_replace_dialog(eap) exarg_T *eap; { if (!gui.in_use) return; find_replace_dialog_create(eap->arg, TRUE); }