Mercurial > vim
view src/gui_motif.c @ 5899:60cdaa05a6ad v7.4.292
updated for version 7.4.292
Problem: Searching for "a" does not match accented "a" with new regexp
engine, does match with old engine. (David B?rgin)
"ca" does not match "ca" with accented "a" with either engine.
Solution: Change the old engine, check for following composing character
also for single-byte patterns.
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Tue, 13 May 2014 18:04:00 +0200 |
parents | 27b008d5b7ac |
children | 5f24d6d51333 |
line wrap: on
line source
/* 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 <Xm/Form.h> #include <Xm/RowColumn.h> #include <Xm/PushB.h> #include <Xm/Text.h> #include <Xm/TextF.h> #include <Xm/Separator.h> #include <Xm/Label.h> #include <Xm/CascadeB.h> #include <Xm/ScrollBar.h> #include <Xm/MenuShell.h> #include <Xm/DrawingA.h> #if (XmVersion >= 1002) # include <Xm/RepType.h> #endif #include <Xm/Frame.h> #include <Xm/LabelG.h> #include <Xm/ToggleBG.h> #include <Xm/SeparatoG.h> #include <Xm/XmP.h> #include <X11/keysym.h> #include <X11/Xatom.h> #include <X11/StringDefs.h> #include <X11/Intrinsic.h> #include "vim.h" #ifdef HAVE_X11_XPM_H # include <X11/xpm.h> #else # ifdef HAVE_XM_XPMP_H # include <Xm/XpmP.h> # endif #endif #ifdef HAVE_XM_NOTEBOOK_H # include <Xm/Notebook.h> #endif #include "gui_xmebw.h" /* for our Enhanced Button Widget */ #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_GUI_TABLINE static Widget tabLine; static Widget tabLine_menu = 0; static int showing_tabline = 0; #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_GUI_TABLINE static void tabline_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void tabline_button_cb __ARGS((Widget w, XtPointer client_data, XtPointer call_data)); static void tabline_menu_cb __ARGS((Widget w, XtPointer closure, XEvent *e, Boolean *continue_dispatch)); static void tabline_balloon_cb __ARGS((BalloonEval *beval, int state)); #endif #ifdef FEAT_TOOLBAR # 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 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)); #if (XmVersion >= 1002) # define STRING_TAG XmFONTLIST_DEFAULT_TAG #else # define STRING_TAG XmSTRING_DEFAULT_CHARSET #endif /* * Call-back routines. */ static void scroll_cb(w, client_data, call_data) Widget w UNUSED; 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); } #ifdef FEAT_GUI_TABLINE static void tabline_cb(w, client_data, call_data) Widget w UNUSED; XtPointer client_data UNUSED; XtPointer call_data; { XmNotebookCallbackStruct *nptr; nptr = (XmNotebookCallbackStruct *)call_data; if (nptr->reason != (int)XmCR_NONE) send_tabline_event(nptr->page_number); } static void tabline_button_cb(w, client_data, call_data) Widget w; XtPointer client_data UNUSED; XtPointer call_data UNUSED; { int cmd, tab_idx; XtVaGetValues(w, XmNuserData, &cmd, NULL); XtVaGetValues(tabLine_menu, XmNuserData, &tab_idx, NULL); send_tabline_menu_event(tab_idx, cmd); } /* * Tabline single mouse click timeout handler */ static void motif_tabline_timer_cb (timed_out, interval_id) XtPointer timed_out; XtIntervalId *interval_id UNUSED; { *((int *)timed_out) = TRUE; } /* * check if the tabline tab scroller is clicked */ static int tabline_scroller_clicked(scroller_name, event) char *scroller_name; XButtonPressedEvent *event; { Widget tab_scroll_w; Position pos_x, pos_y; Dimension width, height; tab_scroll_w = XtNameToWidget(tabLine, scroller_name); if (tab_scroll_w != (Widget)0) { XtVaGetValues(tab_scroll_w, XmNx, &pos_x, XmNy, &pos_y, XmNwidth, &width, XmNheight, &height, NULL); if (pos_x >= 0) { /* Tab scroller (next) is visible */ if ((event->x >= pos_x) && (event->x <= pos_x + width) && (event->y >= pos_y) && (event->y <= pos_y + height)) { /* Clicked on the scroller */ return TRUE; } } } return FALSE; } static void tabline_menu_cb(w, closure, e, continue_dispatch) Widget w; XtPointer closure UNUSED; XEvent *e; Boolean *continue_dispatch UNUSED; { Widget tab_w; XButtonPressedEvent *event; int tab_idx = 0; WidgetList children; Cardinal numChildren; static XtIntervalId timer = (XtIntervalId)0; static int timed_out = TRUE; event = (XButtonPressedEvent *)e; if (event->button == Button1) { if (tabline_scroller_clicked("MajorTabScrollerNext", event) || tabline_scroller_clicked("MajorTabScrollerPrevious", event)) return; if (!timed_out) { XtRemoveTimeOut(timer); timed_out = TRUE; /* * Double click on the tabline gutter, add a new tab */ send_tabline_menu_event(0, TABLINE_MENU_NEW); } else { /* * Single click on the tabline gutter, start a timer to check * for double clicks */ timer = XtAppAddTimeOut(app_context, (long_u)p_mouset, motif_tabline_timer_cb, &timed_out); timed_out = FALSE; } return; } if (event->button != Button3) return; /* When ignoring events don't show the menu. */ if (hold_gui_events # ifdef FEAT_CMDWIN || cmdwin_type != 0 # endif ) return; if (event->subwindow != None) { tab_w = XtWindowToWidget(XtDisplay(w), event->subwindow); /* LINTED: avoid warning: dubious operation on enum */ if (tab_w != (Widget)0 && XmIsPushButton(tab_w)) XtVaGetValues(tab_w, XmNpageNumber, &tab_idx, NULL); } XtVaSetValues(tabLine_menu, XmNuserData, tab_idx, NULL); XtVaGetValues(tabLine_menu, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); XtManageChildren(children, numChildren); XmMenuPosition(tabLine_menu, (XButtonPressedEvent *)e) ; XtManageChild(tabLine_menu); } static void tabline_balloon_cb(beval, state) BalloonEval *beval; int state UNUSED; { int nr; tabpage_T *tp; if (beval->target == (Widget)0) return; XtVaGetValues(beval->target, XmNpageNumber, &nr, NULL); tp = find_tabpage(nr); if (tp == NULL) return; get_tabline_label(tp, TRUE); gui_mch_post_balloon(beval, NameBuff); } #endif /* * End of call-back routines */ /* * Implement three dimensional shading of insensitive labels. * By Marcin Dalecki. */ #include <Xm/XmP.h> #include <Xm/LabelP.h> static XtExposeProc old_label_expose = NULL; static void label_expose __ARGS((Widget _w, XEvent *_event, Region _region)); static void label_expose(_w, _event, _region) Widget _w; XEvent *_event; Region _region; { GC insensitiveGC; XmLabelWidget lw = (XmLabelWidget)_w; unsigned char label_type = (int)XmSTRING; XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0); if (XtIsSensitive(_w) || label_type != (int)XmSTRING) (*old_label_expose)(_w, _event, _region); else { XGCValues values; XtGCMask mask; XtGCMask dynamic; XFontStruct *fs; _XmFontListGetDefaultFont(lw->label.font, &fs); /* FIXME: we should be doing the whole drawing ourself here. */ insensitiveGC = lw->label.insensitive_GC; mask = GCForeground | GCBackground | GCGraphicsExposures; dynamic = GCClipMask | GCClipXOrigin | GCClipYOrigin; values.graphics_exposures = False; if (fs != 0) { mask |= GCFont; values.font = fs->fid; } if (lw->primitive.top_shadow_pixmap != None && lw->primitive.top_shadow_pixmap != XmUNSPECIFIED_PIXMAP) { mask |= GCFillStyle | GCTile; values.fill_style = FillTiled; values.tile = lw->primitive.top_shadow_pixmap; } lw->label.TextRect.x += 1; lw->label.TextRect.y += 1; if (lw->label._acc_text != 0) { lw->label.acc_TextRect.x += 1; lw->label.acc_TextRect.y += 1; } values.foreground = lw->primitive.top_shadow_color; values.background = lw->core.background_pixel; lw->label.insensitive_GC = XtAllocateGC((Widget)lw, 0, mask, &values, dynamic, (XtGCMask)0); (*old_label_expose)(_w, _event, _region); XtReleaseGC(_w, lw->label.insensitive_GC); lw->label.TextRect.x -= 1; lw->label.TextRect.y -= 1; if (lw->label._acc_text != 0) { lw->label.acc_TextRect.x -= 1; lw->label.acc_TextRect.y -= 1; } values.foreground = lw->primitive.bottom_shadow_color; values.background = lw->core.background_pixel; lw->label.insensitive_GC = XtAllocateGC((Widget) lw, 0, mask, &values, dynamic, (XtGCMask)0); (*old_label_expose)(_w, _event, _region); XtReleaseGC(_w, lw->label.insensitive_GC); lw->label.insensitive_GC = insensitiveGC; } } /* * Create all the motif widgets necessary. */ void gui_x11_create_widgets() { #ifdef FEAT_GUI_TABLINE Widget button, scroller; Arg args[10]; int n; XmString xms; #endif /* * Install the 3D shade effect drawing routines. */ if (old_label_expose == NULL) { old_label_expose = xmLabelWidgetClass->core_class.expose; xmLabelWidgetClass->core_class.expose = label_expose; } /* * 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 XtSetArg(al[ac], XmNmarginHeight, 0); ac++; 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); #endif #ifdef FEAT_GUI_TABLINE /* Create the Vim GUI tabline */ n = 0; XtSetArg(args[n], XmNbindingType, XmNONE); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNbackPageSize, XmNONE); n++; XtSetArg(args[n], XmNbackPageNumber, 0); n++; XtSetArg(args[n], XmNbackPagePlacement, XmTOP_RIGHT); n++; XtSetArg(args[n], XmNmajorTabSpacing, 0); n++; XtSetArg(args[n], XmNshadowThickness, 0); n++; XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++; XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++; tabLine = XmCreateNotebook(vimForm, "Vim tabline", args, n); XtAddCallback(tabLine, XmNpageChangedCallback, (XtCallbackProc)tabline_cb, NULL); XtAddEventHandler(tabLine, ButtonPressMask, False, (XtEventHandler)tabline_menu_cb, NULL); gui.tabline_height = TABLINE_HEIGHT; /* * Set the size of the minor next/prev scrollers to zero, so * that they are not displayed. Due to a bug in OpenMotif 2.3, * even if these children widget are unmanaged, they are again * managed by the Notebook widget and the notebook widget geometry * is adjusted to account for the minor scroller widgets. */ scroller = XtNameToWidget(tabLine, "MinorTabScrollerNext"); XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False, XmNtraversalOn, False, NULL); scroller = XtNameToWidget(tabLine, "MinorTabScrollerPrevious"); XtVaSetValues(scroller, XmNwidth, 0, XmNresizable, False, XmNtraversalOn, False, NULL); /* Create the tabline popup menu */ tabLine_menu = XmCreatePopupMenu(tabLine, "tabline popup", NULL, 0); /* Add the buttons to the menu */ n = 0; XtSetArg(args[n], XmNuserData, TABLINE_MENU_CLOSE); n++; xms = XmStringCreate((char *)"Close tab", STRING_TAG); XtSetArg(args[n], XmNlabelString, xms); n++; button = XmCreatePushButton(tabLine_menu, "Close", args, n); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)tabline_button_cb, NULL); XmStringFree(xms); n = 0; XtSetArg(args[n], XmNuserData, TABLINE_MENU_NEW); n++; xms = XmStringCreate((char *)"New Tab", STRING_TAG); XtSetArg(args[n], XmNlabelString, xms); n++; button = XmCreatePushButton(tabLine_menu, "New Tab", args, n); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)tabline_button_cb, NULL); XmStringFree(xms); n = 0; XtSetArg(args[n], XmNuserData, TABLINE_MENU_OPEN); n++; xms = XmStringCreate((char *)"Open tab...", STRING_TAG); XtSetArg(args[n], XmNlabelString, xms); n++; button = XmCreatePushButton(tabLine_menu, "Open tab...", args, n); XtAddCallback(button, XmNactivateCallback, (XtCallbackProc)tabline_button_cb, NULL); XmStringFree(xms); #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 } void gui_mch_set_text_area_pos(x, y, w, h) int x UNUSED; int y UNUSED; int w UNUSED; int h UNUSED; { #ifdef FEAT_TOOLBAR /* Give keyboard focus to the textArea instead of the toolbar. */ 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. */ 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, NULL); XtVaSetValues(shell, XmNmappedWhenManaged, False, NULL); 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, NULL); } #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 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); #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else #endif XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); } else #endif { #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, 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); #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else #endif XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); } else #endif { #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_FORM, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, 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 accelerator 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; /* 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); } #ifdef FEAT_TOOLBAR /* * Icons used by the toolbar code. */ #include "gui_x11_pm.h" static int check_xpm __ARGS((char_u *path)); static char **get_toolbar_pixmap __ARGS((vimmenu_T *menu, char **fname)); static int add_pixmap_args __ARGS((vimmenu_T *menu, Arg *args, int n)); /* * Read an Xpm file. Return OK or FAIL. */ static int check_xpm(path) char_u *path; { XpmAttributes attrs; int status; Pixmap mask; Pixmap map; attrs.valuemask = 0; /* Create the "sensitive" pixmap */ status = XpmReadFileToPixmap(gui.dpy, RootWindow(gui.dpy, DefaultScreen(gui.dpy)), (char *)path, &map, &mask, &attrs); XpmFreeAttributes(&attrs); if (status == XpmSuccess) return OK; return FAIL; } /* * Allocated a pixmap for toolbar menu "menu". * When it's to be read from a file, "fname" is set to the file name * (in allocated memory). * Return a blank pixmap if it fails. */ static char ** get_toolbar_pixmap(menu, fname) vimmenu_T *menu; char **fname; { char_u buf[MAXPATHL]; /* buffer storing expanded pathname */ char **xpm = NULL; /* xpm array */ int res; *fname = NULL; buf[0] = NUL; /* start with NULL path */ if (menu->iconfile != NULL) { /* Use the "icon=" argument. */ gui_find_iconfile(menu->iconfile, buf, "xpm"); res = check_xpm(buf); /* If it failed, try using the menu name. */ if (res == FAIL && gui_find_bitmap(menu->name, buf, "xpm") == OK) res = check_xpm(buf); if (res == OK) { *fname = (char *)vim_strsave(buf); return tb_blank_xpm; } } if (menu->icon_builtin || gui_find_bitmap(menu->name, buf, "xpm") == FAIL) { if (menu->iconidx >= 0 && menu->iconidx < (int)(sizeof(built_in_pixmaps) / sizeof(built_in_pixmaps[0]))) xpm = built_in_pixmaps[menu->iconidx]; else xpm = tb_blank_xpm; } return xpm; } /* * Add arguments for the toolbar pixmap to a menu item. */ static int add_pixmap_args(menu, args, n) vimmenu_T *menu; Arg *args; int n; { vim_free(menu->xpm_fname); menu->xpm = get_toolbar_pixmap(menu, &menu->xpm_fname); if (menu->xpm == NULL) { XtSetArg(args[n], XmNlabelType, XmSTRING); n++; } else { if (menu->xpm_fname != NULL) { XtSetArg(args[n], XmNpixmapFile, menu->xpm_fname); n++; } XtSetArg(args[n], XmNpixmapData, menu->xpm); n++; XtSetArg(args[n], XmNlabelLocation, XmBOTTOM); n++; } return n; } #endif /* FEAT_TOOLBAR */ 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; type = xmSeparatorWidgetClass; XtSetArg(args[n], XmNwidth, wid); n++; XtSetArg(args[n], XmNminWidth, wid); n++; XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; XtSetArg(args[n], XmNseparatorType, XmSHADOW_ETCHED_IN); n++; } else { /* Without shadows one can't sense whatever the button has been * pressed or not! However we want to save a bit of space... * Need the highlightThickness to see the focus. */ XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNhighlightOnEnter, True); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; XtSetArg(args[n], XmNtraversalOn, False); n++; /* 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++; n = add_pixmap_args(menu, args, n); type = xmEnhancedButtonWidgetClass; } 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 == xmEnhancedButtonWidgetClass) { 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 submenu_change(root_menu, TRUE); } void gui_mch_new_menu_font() { if (menuBar == (Widget)0) return; 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, RESIZE_VERT); 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) 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) submenu_change(toolbar, TRUE); # endif } #endif static void 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->xpm != NULL) { int n = 0; Arg args[18]; n = add_pixmap_args(mp, args, n); XtSetValues(mp->id, args, n); } # 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 */ 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 } } void gui_mch_show_popupmenu(menu) vimmenu_T *menu UNUSED; { #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], 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)); } /* * Look for a widget in the widget tree w, with a mnemonic matching keycode. * When one is found, simulate a button press on that widget and give it the * keyboard focus. If the mnemonic is on a label, look in the userData field * of the label to see if it points to another widget, and give that the focus. */ static void do_mnemonic(Widget w, unsigned int keycode) { WidgetList children; int numChildren, i; Boolean isMenu; KeySym mnemonic = '\0'; char mneString[2]; Widget userData; unsigned char rowColType; if (XtIsComposite(w)) { if (XtClass(w) == xmRowColumnWidgetClass) { XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); isMenu = (rowColType != (unsigned char)XmWORK_AREA); } else isMenu = False; if (!isMenu) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i = 0; i < numChildren; i++) do_mnemonic(children[i], keycode); } } else { XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); if (mnemonic != '\0') { mneString[0] = mnemonic; mneString[1] = '\0'; if (XKeysymToKeycode(XtDisplay(XtParent(w)), XStringToKeysym(mneString)) == keycode) { if (XtClass(w) == xmLabelWidgetClass || XtClass(w) == xmLabelGadgetClass) { XtVaGetValues(w, XmNuserData, &userData, NULL); if (userData != NULL && XtIsWidget(userData)) XmProcessTraversal(userData, XmTRAVERSE_CURRENT); } else { XKeyPressedEvent keyEvent; XmProcessTraversal(w, XmTRAVERSE_CURRENT); vim_memset((char *) &keyEvent, 0, sizeof(XKeyPressedEvent)); keyEvent.type = KeyPress; keyEvent.serial = 1; keyEvent.send_event = True; keyEvent.display = XtDisplay(w); keyEvent.window = XtWindow(w); XtCallActionProc(w, "Activate", (XEvent *) & keyEvent, NULL, 0); } } } } } /* * Callback routine for dialog mnemonic processing. */ static void mnemonic_event(Widget w, XtPointer call_data UNUSED, XKeyEvent *event) { do_mnemonic(w, event->keycode); } /* * Search the widget tree under w for widgets with mnemonics. When found, add * a passive grab to the dialog widget for the mnemonic character, thus * directing mnemonic events to the dialog widget. */ static void add_mnemonic_grabs(Widget dialog, Widget w) { char mneString[2]; WidgetList children; int numChildren, i; Boolean isMenu; KeySym mnemonic = '\0'; unsigned char rowColType; if (XtIsComposite(w)) { if (XtClass(w) == xmRowColumnWidgetClass) { XtVaGetValues(w, XmNrowColumnType, &rowColType, NULL); isMenu = (rowColType != (unsigned char)XmWORK_AREA); } else isMenu = False; if (!isMenu) { XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); for (i = 0; i < numChildren; i++) add_mnemonic_grabs(dialog, children[i]); } } else { XtVaGetValues(w, XmNmnemonic, &mnemonic, NULL); if (mnemonic != '\0') { mneString[0] = mnemonic; mneString[1] = '\0'; XtGrabKey(dialog, XKeysymToKeycode(XtDisplay(dialog), XStringToKeysym(mneString)), Mod1Mask, True, GrabModeAsync, GrabModeAsync); } } } /* * Add a handler for mnemonics in a dialog. Motif itself only handles * mnemonics in menus. Mnemonics added or changed after this call will be * ignored. * * To add a mnemonic to a text field or list, set the XmNmnemonic resource on * the appropriate label and set the XmNuserData resource of the label to the * widget to get the focus when the mnemonic is typed. */ static void activate_dialog_mnemonics(Widget dialog) { if (!dialog) return; XtAddEventHandler(dialog, KeyPressMask, False, (XtEventHandler) mnemonic_event, (XtPointer) NULL); add_mnemonic_grabs(dialog, dialog); } /* * Removes the event handler and key-grabs for dialog mnemonic handling. */ static void suppress_dialog_mnemonics(Widget dialog) { if (!dialog) return; XtUngrabKey(dialog, AnyKey, Mod1Mask); XtRemoveEventHandler(dialog, KeyPressMask, False, (XtEventHandler) mnemonic_event, (XtPointer) NULL); } #if defined(FEAT_BROWSE) || defined(FEAT_GUI_DIALOG) static void set_fontlist __ARGS((Widget wg)); /* * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget. */ static void set_fontlist(id) Widget id; { XmFontList fl; #ifdef FONTSET_ALWAYS if (gui.fontset != NOFONTSET) { fl = gui_motif_fontset2fontlist((XFontSet *)&gui.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.norm_font != NOFONT) { fl = gui_motif_create_fontlist((XFontStruct *)gui.norm_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 #if defined(FEAT_BROWSE) || defined(PROTO) /* * file selector related stuff */ #include <Xm/FileSB.h> #include <Xm/XmStrDefs.h> 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; char_u *p, *next; KeySym mnemonic = NUL; w = XtNameToWidget(parent, name); if (!w) return; p = vim_strsave((char_u *)new_label); if (p == NULL) return; for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) { int len = STRLEN(next); if (len > 0) { mch_memmove(next, next + 1, len); mnemonic = next[0]; } } } str = XmStringCreate((char *)p, STRING_TAG); vim_free(p); if (str != NULL) { XtVaSetValues(w, XmNlabelString, str, XmNmnemonic, mnemonic, NULL); XmStringFree(str); } gui_motif_menu_fontlist(w); } static void set_predefined_fontlist(parent, name) Widget parent; String name; { Widget w; w = XtNameToWidget(parent, name); if (!w) return; set_fontlist(w); } /* * Put up a file requester. * Returns the selected name in allocated memory, or NULL for Cancel. */ char_u * gui_mch_browse(saving, title, dflt, ext, initdir, filter) int saving UNUSED; /* select file to write */ char_u *title; /* title for the window */ char_u *dflt; /* default name */ char_u *ext UNUSED; /* 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; /* There a difference between the resource name and value, Therefore, we * avoid to (ab-)use the (maybe internationalized!) dialog title as a * dialog name. */ dialog_wgt = XmCreateFileSelectionDialog(vimShell, "browseDialog", 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")); /* This is to save us from silly external settings using not fixed with * fonts for file selection. */ set_predefined_fontlist(dialog_wgt, "DirListSW.DirList"); set_predefined_fontlist(dialog_wgt, "ItemsListSW.ItemsList"); 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); activate_dialog_mnemonics(dialog_wgt); /* sit in a loop until the dialog box has gone away */ do { XtAppProcessEvent(XtWidgetToApplicationContext(dialog_wgt), (XtInputMask)XtIMAll); } while (XtIsManaged(dialog_wgt)); suppress_dialog_mnemonics(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. */ static void DialogCancelCB(w, client_data, call_data) Widget w UNUSED; /* widget id */ XtPointer client_data UNUSED; /* data from application */ XtPointer call_data UNUSED; /* data from widget class */ { if (browse_fname != NULL) { XtFree(browse_fname); browse_fname = NULL; } XtUnmanageChild(dialog_wgt); } /* * Process callback from Dialog actions. */ static void DialogAcceptCB(w, client_data, call_data) Widget w UNUSED; /* widget id */ XtPointer client_data UNUSED; /* 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". */ static void keyhit_callback(w, client_data, event, cont) Widget w; XtPointer client_data UNUSED; XEvent *event; Boolean *cont UNUSED; { 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)); } static void butproc(w, client_data, call_data) Widget w UNUSED; XtPointer client_data; XtPointer call_data UNUSED; { dialogStatus = (int)(long)client_data + 1; } #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 careful 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 int gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield, ex_cmd) int type UNUSED; char_u *title; char_u *message; char_u *button_names; int dfltbutton; char_u *textfield; /* buffer of size IOSIZE */ int ex_cmd UNUSED; { char_u *buts; char_u *p, *next; XtAppContext app; XmString label; int butcount; Widget w; 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) { KeySym mnemonic = NUL; for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) { int len = STRLEN(next); if (len > 0) { mch_memmove(next, next + 1, len); mnemonic = next[0]; } } 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, XmNmnemonic, mnemonic, XmNbottomAttachment, XmATTACH_FORM, XmNbottomOffset, 4, XmNshowAsDefault, butcount == dfltbutton - 1, XmNdefaultButtonShadowThickness, 1, NULL); XmStringFree(label); gui_motif_menu_fontlist(buttons[butcount]); /* 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); 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. * Since LessTif is apparently having problems with the creation of * properly localized string, we use LtoR here. The symptom is that the * string sill not show properly in multiple lines as it does in native * Motif. */ label = XmStringCreateLtoR((char *)message, STRING_TAG); if (label == NULL) return -1; w = XtVaCreateManagedWidget("dialogMessage", xmLabelGadgetClass, form, XmNlabelString, label, XmNalignment, XmALIGNMENT_BEGINNING, 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); set_fontlist(w); 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); activate_dialog_mnemonics(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 vim_strncpy(textfield, p, IOSIZE - 1); XtFree((char *)p); } suppress_dialog_mnemonics(dialogform); 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); } 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); if (xms != NULL) { 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->xpm == NULL) { XtSetArg(args[n], XmNlabelType, XmSTRING); ++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)); #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else #endif 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)) { #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else #endif XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); } else { #ifdef FEAT_GUI_TABLINE if (showing_tabline) { XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_FORM, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else #endif XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_FORM, NULL); } XtUnmanageChild(XtParent(toolBar)); } gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); } /* * 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 reset_focus() { if (textArea != NULL) XmProcessTraversal(textArea, XmTRAVERSE_CURRENT); } int gui_mch_compute_toolbar_height() { Dimension borders; Dimension height; /* total Toolbar height */ Dimension whgt; /* height of each widget */ WidgetList children; /* list of toolBar's children */ Cardinal numChildren; /* how many children toolBar has */ int i; borders = 0; height = 0; if (toolBar != (Widget)0 && toolBarFrame != (Widget)0) { /* get height of XmFrame parent */ Dimension fst; Dimension fmh; Dimension tst; Dimension tmh; XtVaGetValues(toolBarFrame, XmNshadowThickness, &fst, XmNmarginHeight, &fmh, NULL); borders += fst + fmh; XtVaGetValues(toolBar, XmNshadowThickness, &tst, XmNmarginHeight, &tmh, XmNchildren, &children, XmNnumChildren, &numChildren, NULL); borders += tst + tmh; for (i = 0; i < (int)numChildren; i++) { whgt = 0; XtVaGetValues(children[i], XmNheight, &whgt, NULL); if (height < whgt) height = whgt; } } #ifdef LESSTIF_VERSION /* Hack: When starting up we get wrong dimensions. */ if (height < 10) height = 24; #endif return (int)(height + (borders << 1)); } void motif_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); } # ifdef FEAT_FOOTER /* * The next toolbar enter/leave callbacks should really do balloon help. But * I have to use footer help for backwards compatibility. Hopefully both will * get implemented and the user will have a choice. */ static void toolbarbutton_enter_cb(w, client_data, event, cont) Widget w UNUSED; XtPointer client_data; XEvent *event UNUSED; Boolean *cont UNUSED; { 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]); } } static void toolbarbutton_leave_cb(w, client_data, event, cont) Widget w UNUSED; XtPointer client_data UNUSED; XEvent *event UNUSED; Boolean *cont UNUSED; { gui_mch_set_footer((char_u *) ""); } # endif #endif #if defined(FEAT_GUI_TABLINE) || defined(PROTO) /* * Show or hide the tabline. */ void gui_mch_show_tabline(int showit) { if (tabLine == (Widget)0) return; if (!showit != !showing_tabline) { if (showit) { XtManageChild(tabLine); XtUnmanageChild(XtNameToWidget(tabLine, "PageScroller")); XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerNext")); XtUnmanageChild(XtNameToWidget(tabLine, "MinorTabScrollerPrevious")); #ifdef FEAT_MENU # ifdef FEAT_TOOLBAR if (XtIsManaged(XtParent(toolBar))) XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); else # endif if (XtIsManaged(menuBar)) XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); else #endif XtVaSetValues(tabLine, XmNtopAttachment, XmATTACH_FORM, NULL); XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, tabLine, NULL); } else { XtUnmanageChild(tabLine); #ifdef FEAT_MENU # ifdef FEAT_TOOLBAR if (XtIsManaged(XtParent(toolBar))) XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, XtParent(toolBar), NULL); else # endif if (XtIsManaged(menuBar)) XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, menuBar, NULL); else #endif XtVaSetValues(textAreaForm, XmNtopAttachment, XmATTACH_FORM, NULL); } showing_tabline = showit; } } /* * Return TRUE when tabline is displayed. */ int gui_mch_showing_tabline(void) { return tabLine != (Widget)0 && showing_tabline; } /* * Update the labels of the tabline. */ void gui_mch_update_tabline(void) { tabpage_T *tp; int nr = 1, n; Arg args[10]; int curtabidx = 0, currentpage; Widget tab; XmNotebookPageInfo page_info; XmNotebookPageStatus page_status; int last_page, tab_count; XmString label_str; char *label_cstr; BalloonEval *beval; if (tabLine == (Widget)0) return; /* Add a label for each tab page. They all contain the same text area. */ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) { if (tp == curtab) curtabidx = nr; page_status = XmNotebookGetPageInfo(tabLine, nr, &page_info); if (page_status == XmPAGE_INVALID || page_info.major_tab_widget == (Widget)0) { /* Add the tab */ n = 0; XtSetArg(args[n], XmNnotebookChildType, XmMAJOR_TAB); n++; XtSetArg(args[n], XmNtraversalOn, False); n++; XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++; XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNshadowThickness , 1); n++; tab = XmCreatePushButton(tabLine, "-Empty-", args, n); XtManageChild(tab); beval = gui_mch_create_beval_area(tab, NULL, tabline_balloon_cb, NULL); XtVaSetValues(tab, XmNuserData, beval, NULL); } else tab = page_info.major_tab_widget; XtVaSetValues(tab, XmNpageNumber, nr, NULL); /* * Change the label text only if it is different */ XtVaGetValues(tab, XmNlabelString, &label_str, NULL); if (XmStringGetLtoR(label_str, XmSTRING_DEFAULT_CHARSET, &label_cstr)) { get_tabline_label(tp, FALSE); if (STRCMP(label_cstr, NameBuff) != 0) { XtVaSetValues(tab, XtVaTypedArg, XmNlabelString, XmRString, NameBuff, STRLEN(NameBuff) + 1, NULL); /* * Force a resize of the tab label button */ XtUnmanageChild(tab); XtManageChild(tab); } XtFree(label_cstr); } } tab_count = nr - 1; XtVaGetValues(tabLine, XmNlastPageNumber, &last_page, NULL); /* Remove any old labels. */ while (nr <= last_page) { if (XmNotebookGetPageInfo(tabLine, nr, &page_info) != XmPAGE_INVALID && page_info.page_number == nr && page_info.major_tab_widget != (Widget)0) { XtVaGetValues(page_info.major_tab_widget, XmNuserData, &beval, NULL); if (beval != NULL) gui_mch_destroy_beval_area(beval); XtUnmanageChild(page_info.major_tab_widget); XtDestroyWidget(page_info.major_tab_widget); } nr++; } XtVaSetValues(tabLine, XmNlastPageNumber, tab_count, NULL); XtVaGetValues(tabLine, XmNcurrentPageNumber, ¤tpage, NULL); if (currentpage != curtabidx) XtVaSetValues(tabLine, XmNcurrentPageNumber, curtabidx, NULL); } /* * Set the current tab to "nr". First tab is 1. */ void gui_mch_set_curtab(nr) int nr; { int currentpage; if (tabLine == (Widget)0) return; XtVaGetValues(tabLine, XmNcurrentPageNumber, ¤tpage, NULL); if (currentpage != nr) XtVaSetValues(tabLine, XmNcurrentPageNumber, nr, 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); } /* * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font. */ void gui_motif_menu_fontlist(id) Widget id UNUSED; { #ifdef FEAT_MENU #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, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; static SharedFindReplace repl_widgets = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 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)); static void find_replace_destroy_callback(w, client_data, call_data) Widget w UNUSED; XtPointer client_data; XtPointer call_data UNUSED; { SharedFindReplace *cd = (SharedFindReplace *)client_data; if (cd != NULL) /* suppress_dialog_mnemonics(cd->dialog); */ cd->dialog = (Widget)0; } static void find_replace_dismiss_callback(w, client_data, call_data) Widget w UNUSED; XtPointer client_data; XtPointer call_data UNUSED; { SharedFindReplace *cd = (SharedFindReplace *)client_data; if (cd != NULL) XtUnmanageChild(cd->dialog); } static void entry_activate_callback(w, client_data, call_data) Widget w UNUSED; XtPointer client_data; XtPointer call_data UNUSED; { XmProcessTraversal((Widget)client_data, XmTRAVERSE_CURRENT); } static void find_replace_callback(w, client_data, call_data) Widget w UNUSED; XtPointer client_data; XtPointer call_data UNUSED; { 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); } static void find_replace_keypress(w, frdp, event) Widget w UNUSED; 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 set_label(w, label) Widget w; char *label; { XmString str; char_u *p, *next; KeySym mnemonic = NUL; if (!w) return; p = vim_strsave((char_u *)label); if (p == NULL) return; for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) { int len = STRLEN(next); if (len > 0) { mch_memmove(next, next + 1, len); mnemonic = next[0]; } } } str = XmStringCreateSimple((char *)p); vim_free(p); if (str) { XtVaSetValues(w, XmNlabelString, str, XmNmnemonic, mnemonic, NULL); XmStringFree(str); } gui_motif_menu_fontlist(w); } 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) { gui_motif_synch_fonts(); /* 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); frdp->find = XtVaCreateManagedWidget("findButton", xmPushButtonWidgetClass, button_form, XmNsensitive, True, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); set_label(frdp->find, _("Find &Next")); XtAddCallback(frdp->find, XmNactivateCallback, find_replace_callback, (do_replace ? (XtPointer)FRD_R_FINDNEXT : (XtPointer)FRD_FINDNEXT)); if (do_replace) { frdp->replace = XtVaCreateManagedWidget("replaceButton", xmPushButtonWidgetClass, button_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->find, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); set_label(frdp->replace, _("&Replace")); XtAddCallback(frdp->replace, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACE); frdp->all = XtVaCreateManagedWidget("replaceAllButton", xmPushButtonWidgetClass, button_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->replace, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); set_label(frdp->all, _("Replace &All")); XtAddCallback(frdp->all, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACEALL); frdp->undo = XtVaCreateManagedWidget("undoButton", xmPushButtonWidgetClass, button_form, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->all, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); set_label(frdp->undo, _("&Undo")); XtAddCallback(frdp->undo, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_UNDO); } frdp->cancel = XtVaCreateManagedWidget("closeButton", xmPushButtonWidgetClass, button_form, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); set_label(frdp->cancel, _("&Cancel")); XtAddCallback(frdp->cancel, XmNactivateCallback, find_replace_dismiss_callback, frdp); gui_motif_menu_fontlist(frdp->cancel); 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); gui_motif_menu_fontlist(label_what); 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); gui_motif_menu_fontlist(label_with); /* * 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; Widget w; 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")); w = XtVaCreateManagedWidget("directionFrameLabel", xmLabelGadgetClass, frame, XmNlabelString, str, XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, XmNchildType, XmFRAME_TITLE_CHILD, NULL); XmStringFree(str); gui_motif_menu_fontlist(w); 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); gui_motif_menu_fontlist(frdp->up); str = XmStringCreateSimple(_("Down")); frdp->down = XtVaCreateManagedWidget("downRadioButton", xmToggleButtonGadgetClass, radio_box, XmNlabelString, str, XmNset, True, NULL); XmStringFree(str); gui_motif_menu_fontlist(frdp->down); 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); gui_motif_menu_fontlist(frdp->wword); gui_motif_menu_fontlist(frdp->mcase); XtManageChild(toggle_form); if (entry_text != NULL) XmTextFieldSetString(frdp->what, (char *)entry_text); vim_free(entry_text); gui_motif_synch_fonts(); manage_centered(frdp->dialog); activate_dialog_mnemonics(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); } /* * Synchronize all gui elements, which are dependant upon the * main text font used. Those are in esp. the find/replace dialogs. * If you don't understand why this should be needed, please try to * search for "pięść" in iso8859-2. */ void gui_motif_synch_fonts(void) { SharedFindReplace *frdp; int do_replace; XFontStruct *font; XmFontList font_list; /* FIXME: Unless we find out how to create a XmFontList from a XFontSet, * we just give up here on font synchronization. */ font = (XFontStruct *)gui.norm_font; if (font == NULL) return; font_list = gui_motif_create_fontlist(font); /* OK this loop is a bit tricky... */ for (do_replace = 0; do_replace <= 1; ++do_replace) { frdp = (do_replace) ? (&repl_widgets) : (&find_widgets); if (frdp->dialog) { XtVaSetValues(frdp->what, XmNfontList, font_list, NULL); if (do_replace) XtVaSetValues(frdp->with, XmNfontList, font_list, NULL); } } XmFontListFree(font_list); }