From dfccaf0f00e8308eae09cb8f012fce3e56097f0f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Fri, 31 Dec 2004 20:56:11 +0000 Subject: updated for version 7.0027 --- src/Makefile | 13 +- src/gui_amiga.c | 2 + src/gui_beos.cc | 2 + src/gui_kde_x11.cc | 2 + src/gui_mac.c | 2 + src/gui_motif.c | 606 +++++++++++++++++++--- src/gui_photon.c | 2 + src/gui_riscos.c | 2 + src/gui_w48.c | 2 + src/gui_xmdlg.c | 1287 +++++++++++++++++++++++++++++++++++++++++++++++ src/misc2.c | 4 +- src/proto.h | 1 + src/proto/gui_xmdlg.pro | 3 + src/workshop.c | 2 +- 14 files changed, 1844 insertions(+), 86 deletions(-) create mode 100644 src/gui_xmdlg.c create mode 100644 src/proto/gui_xmdlg.pro (limited to 'src') diff --git a/src/Makefile b/src/Makefile index 9b21a2e76a..5e43ee9df7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1089,9 +1089,11 @@ GTK_MAN_TARGETS = yes GTK_TESTTARGET = gui ### Motif GUI -MOTIF_SRC = gui.c gui_motif.c gui_x11.c pty.c gui_beval.c +MOTIF_SRC = gui.c gui_motif.c gui_x11.c pty.c gui_beval.c \ + gui_xmdlg.c MOTIF_OBJ = objects/gui.o objects/gui_motif.o objects/gui_x11.o \ - objects/pty.o objects/gui_beval.o + objects/pty.o objects/gui_beval.o \ + objects/gui_xmdlg.o MOTIF_DEFS = -DFEAT_GUI_MOTIF $(NARROW_PROTO) MOTIF_IPATH = $(GUI_INC_LOC) MOTIF_LIBS_DIR = $(GUI_LIB_LOC) @@ -1203,8 +1205,8 @@ CARBONGUI_BUNDLE = $(VIMNAME).app CARBONGUI_TESTARG = VIMPROG=../$(CARBONGUI_BUNDLE)/Contents/MacOS/$(VIMTARGET) # All GUI files -ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c gui_kde.cc gui_kde_wid.cc gui_kde_x11.cc gui_kde_wid_moc.cc -ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w16.pro gui_w32.pro gui_amiga.pro gui_photon.pro +ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c gui_kde.cc gui_kde_wid.cc gui_kde_x11.cc gui_kde_wid_moc.cc +ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w16.pro gui_w32.pro gui_amiga.pro gui_photon.pro # }}} @@ -2194,6 +2196,9 @@ objects/gui_gtk_x11.o: gui_gtk_x11.c objects/gui_motif.o: gui_motif.c $(CCC) -o $@ gui_motif.c +objects/gui_xmdlg.o: gui_xmdlg.c + $(CCC) -o $@ gui_xmdlg.c + objects/gui_x11.o: gui_x11.c $(CCC) -o $@ gui_x11.c diff --git a/src/gui_amiga.c b/src/gui_amiga.c index 9ce44ed367..0b76245fd4 100644 --- a/src/gui_amiga.c +++ b/src/gui_amiga.c @@ -1238,6 +1238,7 @@ gui_mch_get_font(char_u *name, int giveErrorIfMissing) return NULL; } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * We always use the default font. @@ -1247,6 +1248,7 @@ gui_mch_get_fontname(GuiFont font, char_u *name) { return vim_strsave((char_u *)"default"); } +#endif void gui_mch_set_font(GuiFont font) diff --git a/src/gui_beos.cc b/src/gui_beos.cc index 32e4db0cb4..315136559e 100644 --- a/src/gui_beos.cc +++ b/src/gui_beos.cc @@ -2396,6 +2396,7 @@ error: return (GuiFont)font; } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. */ @@ -2404,6 +2405,7 @@ gui_mch_get_fontname(GuiFont font, char_u *name) { return vim_strsave(((VimFont *)font)->name); } +#endif /* * Set the current text font. diff --git a/src/gui_kde_x11.cc b/src/gui_kde_x11.cc index 8956264d4a..c8873ecb78 100644 --- a/src/gui_kde_x11.cc +++ b/src/gui_kde_x11.cc @@ -700,6 +700,7 @@ gui_mch_get_font(char_u * name, int report_error)//{{{ return (GuiFont) myFont; }//}}} +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. @@ -711,6 +712,7 @@ gui_mch_get_fontname(GuiFont font, char_u *name)//{{{ return NULL; return vim_strsave(name); }//}}} +#endif /* * Set the current text font. diff --git a/src/gui_mac.c b/src/gui_mac.c index f5e29abf28..3b73339df4 100644 --- a/src/gui_mac.c +++ b/src/gui_mac.c @@ -3569,6 +3569,7 @@ gui_mch_get_font(name, giveErrorIfMissing) return font; } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. @@ -3582,6 +3583,7 @@ gui_mch_get_fontname(font, name) return NULL; return vim_strsave(name); } +#endif /* * Set the current text font. diff --git a/src/gui_motif.c b/src/gui_motif.c index 4fe26ec57b..d345af5cb6 100644 --- a/src/gui_motif.c +++ b/src/gui_motif.c @@ -93,9 +93,6 @@ static void attachDump(Widget, char *); static void gui_motif_menu_colors __ARGS((Widget id)); static void gui_motif_scroll_colors __ARGS((Widget id)); -#ifdef FEAT_MENU -static void gui_motif_menu_fontlist __ARGS((Widget id)); -#endif #if (XmVersion >= 1002) # define STRING_TAG XmFONTLIST_DEFAULT_TAG @@ -125,17 +122,122 @@ scroll_cb(w, client_data, call_data) gui_drag_scrollbar(sb, value, dragging); } - /* * End of call-back routines */ +#ifndef LESSTIF_VERSION +/* + * Implement three dimensional shading of insensitive labels. + * By Martin Dalecki. + */ + +#include +#include + +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 = XmSTRING; + + XtVaGetValues(_w, XmNlabelType, &label_type, (XtPointer)0); + + if (XtIsSensitive(_w) || label_type != 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, 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, 0); + (*old_label_expose)(_w, _event, _region); + XtReleaseGC(_w, lw->label.insensitive_GC); + + lw->label.insensitive_GC = insensitiveGC; + } +} +#endif + + /* * Create all the motif widgets necessary. */ void gui_x11_create_widgets() { +#ifndef LESSTIF_VERSION + /* + * 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; + } +#endif + /* * Start out by adding the configured border width into the border offset */ @@ -329,9 +431,7 @@ gui_x11_set_back_color() * Manage dialog centered on pointer. This could be used by the Athena code as * well. */ -static void manage_centered __ARGS((Widget dialog_child)); - -static void + void manage_centered(dialog_child) Widget dialog_child; { @@ -855,16 +955,15 @@ gui_mch_add_menu_item(menu, idx) xms = XmStringCreate((char *)menu->dname, STRING_TAG); XtSetArg(args[n], XmNlabelString, xms); n++; -#ifndef FEAT_SUN_WORKSHOP - /* Without shadows one can't sense whatever the button has been * pressed or not! However we wan't to save a bit of space... + * Need the highlightThickness to see the focus. */ - XtSetArg(args[n], XmNhighlightThickness, 0); n++; + XtSetArg(args[n], XmNhighlightThickness, 1); n++; XtSetArg(args[n], XmNhighlightOnEnter, True); n++; XtSetArg(args[n], XmNmarginWidth, 0); n++; XtSetArg(args[n], XmNmarginHeight, 0); n++; -#endif + if (menu->image == 0) { XtSetArg(args[n], XmNlabelType, XmSTRING); n++; @@ -1384,7 +1483,6 @@ gui_mch_create_scrollbar(sb, orient) int n; n = 0; - XtSetArg(args[n], XmNshadowThickness, 1); n++; XtSetArg(args[n], XmNminimum, 0); n++; XtSetArg(args[n], XmNorientation, (orient == SBAR_VERT) ? XmVERTICAL : XmHORIZONTAL); n++; @@ -1484,6 +1582,219 @@ 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, 0); + isMenu = (rowColType != (unsigned char)XmWORK_AREA); + } + else + isMenu = False; + if (!isMenu) + { + XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, + &numChildren, 0); + for (i = 0; i < numChildren; i++) + do_mnemonic(children[i], keycode); + } + } + else + { + XtVaGetValues(w, XmNmnemonic, &mnemonic, 0); + 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, 0); + if (userData != NULL && XtIsWidget(userData)) + XmProcessTraversal(userData, XmTRAVERSE_CURRENT); + } + else + { + XKeyPressedEvent keyEvent; + + XmProcessTraversal(w, XmTRAVERSE_CURRENT); + + 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. + */ +/*ARGSUSED*/ + static void +mnemonic_event(Widget w, XtPointer call_data, 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, 0); + isMenu = (rowColType != (unsigned char)XmWORK_AREA); + } + else + isMenu = False; + if (!isMenu) + { + XtVaGetValues(w, XmNchildren, &children, XmNnumChildren, + &numChildren, 0); + for (i = 0; i < numChildren; i++) + add_mnemonic_grabs(dialog, children[i]); + } + } + else + { + XtVaGetValues(w, XmNmnemonic, &mnemonic, 0); + 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) @@ -1517,29 +1828,67 @@ static void DialogAcceptCB __ARGS((Widget, XtPointer, XtPointer)); * - 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 __ARGS((Widget parent, String name, char *new_label)); static void set_predefined_label(parent, name, new_label) - Widget parent; - String name; - char * new_label; + Widget parent; + String name; + char *new_label; { - XmString str; - Widget w; + XmString str; + Widget w; + char_u *p, *next; + KeySym mnemonic = NUL; w = XtNameToWidget(parent, name); if (!w) return; - str = XmStringCreate(new_label, STRING_TAG); + 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 (str) + 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, 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); } /* @@ -1561,7 +1910,12 @@ gui_mch_browse(saving, title, dflt, ext, initdir, filter) char_u *pattern; char_u *tofree = NULL; - dialog_wgt = XmCreateFileSelectionDialog(vimShell, (char *)title, NULL, 0); + /* 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) { @@ -1614,15 +1968,21 @@ gui_mch_browse(saving, title, dflt, ext, initdir, filter) 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, "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, "Help", _("&Help")); set_predefined_label(dialog_wgt, "Items", _("Files")); - set_predefined_label(dialog_wgt, "OK", _("OK")); + 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); @@ -1634,6 +1994,7 @@ gui_mch_browse(saving, title, dflt, ext, initdir, filter) (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 @@ -1642,6 +2003,7 @@ gui_mch_browse(saving, title, dflt, ext, initdir, filter) (XtInputMask)XtIMAll); } while (XtIsManaged(dialog_wgt)); + suppress_dialog_mnemonics(dialog_wgt); XtDestroyWidget(dialog_wgt); vim_free(tofree); @@ -1746,31 +2108,6 @@ butproc(w, client_data, call_data) dialogStatus = (int)(long)client_data + 1; } -static void gui_motif_set_fontlist __ARGS((Widget wg)); - -/* - * Use the 'guifont' or 'guifontset' as a fontlist for a dialog widget. - */ - static void -gui_motif_set_fontlist(wg) - Widget wg; -{ - XmFontList fl; - - fl = -#ifdef FEAT_XFONTSET - gui.fontset != NOFONTSET ? - gui_motif_fontset2fontlist((XFontSet *)&gui.fontset) - : -#endif - gui_motif_create_fontlist((XFontStruct *)gui.norm_font); - if (fl != NULL) - { - XtVaSetValues(wg, XmNfontList, fl, NULL); - XmFontListFree(fl); - } -} - #ifdef HAVE_XPM static Widget create_pixmap_label(Widget parent, String name, char **data, ArgList args, Cardinal arg); @@ -1853,6 +2190,7 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) XtAppContext app; XmString label; int butcount; + Widget w; Widget dialogform = NULL; Widget form = NULL; Widget dialogtextfield = NULL; @@ -1913,10 +2251,20 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) p = buts; for (butcount = 0; *p; ++butcount) { + KeySym mnemonic = NUL; + for (next = p; *next; ++next) { if (*next == DLG_HOTKEY_CHAR) - mch_memmove(next, next + 1, STRLEN(next)); + { + int len = STRLEN(next); + + if (len > 0) + { + mch_memmove(next, next + 1, len); + mnemonic = next[0]; + } + } if (*next == DLG_BUTTON_SEP) { *next++ = NUL; @@ -1930,12 +2278,14 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) 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. */ @@ -2041,7 +2391,7 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) XmNbottomAttachment, XmATTACH_FORM, NULL); - gui_motif_set_fontlist(dialogtextfield); + set_fontlist(dialogtextfield); XmTextFieldSetString(dialogtextfield, (char *)textfield); XtManageChild(dialogtextfield); XtAddEventHandler(dialogtextfield, KeyPressMask, False, @@ -2093,13 +2443,19 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) XtManageChild(dialogpixmap); #endif - /* Create the dialog message. */ - label = XmStringLtoRCreate((char *)message, STRING_TAG); + /* 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; - (void)XtVaCreateManagedWidget("dialogMessage", + w = XtVaCreateManagedWidget("dialogMessage", xmLabelGadgetClass, form, XmNlabelString, label, + XmNalignment, XmALIGNMENT_BEGINNING, XmNtopAttachment, XmATTACH_FORM, XmNtopOffset, 8, #ifdef HAVE_XPM @@ -2115,6 +2471,7 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) XmNbottomOffset, 8, NULL); XmStringFree(label); + set_fontlist(w); if (textfield != NULL) { @@ -2149,6 +2506,7 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) NULL); manage_centered(dialogform); + activate_dialog_mnemonics(dialogform); if (textfield != NULL && *textfield != NUL) { @@ -2185,6 +2543,7 @@ gui_mch_dialog(type, title, message, button_names, dfltbutton, textfield) } } + suppress_dialog_mnemonics(dialogform); XtDestroyWidget(dialogform); return dialogStatus; @@ -2246,8 +2605,11 @@ gui_mch_set_footer(s) XmString xms; xms = XmStringCreate((char *)s, STRING_TAG); - XtVaSetValues(footer, XmNlabelString, xms, NULL); - XmStringFree(xms); + if (xms != NULL) + { + XtVaSetValues(footer, XmNlabelString, xms, NULL); + XmStringFree(xms); + } } #endif @@ -2522,14 +2884,15 @@ gui_motif_scroll_colors(id) XtVaSetValues(id, XmNforeground, gui.scroll_fg_pixel, NULL); } -#ifdef FEAT_MENU /* * Set the fontlist for Widget "id" to use gui.menu_fontset or gui.menu_font. */ - static void +/*ARGSUSED*/ + void gui_motif_menu_fontlist(id) Widget id; { +#ifdef FEAT_MENU #ifdef FONTSET_ALWAYS if (gui.menu_fontset != NOFONTSET) { @@ -2573,9 +2936,9 @@ gui_motif_menu_fontlist(id) } } #endif +#endif } -#endif /* * We don't create it twice for the sake of speed. @@ -2617,8 +2980,10 @@ find_replace_destroy_callback(w, client_data, call_data) { SharedFindReplace *cd = (SharedFindReplace *)client_data; - if (cd != NULL) + if (cd != NULL) { + /* suppress_dialog_mnemonics(cd->dialog); */ cd->dialog = (Widget)0; + } } /*ARGSUSED*/ @@ -2718,6 +3083,48 @@ find_replace_keypress(w, frdp, event) XtUnmanageChild(frdp->dialog); } + static void +set_label(w, label) + Widget w; + char_u *label; +{ + XmString str; + char_u *p, *next; + KeySym mnemonic = NUL; + + if (!w) + return; + + p = vim_strsave(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; @@ -2746,6 +3153,8 @@ find_replace_dialog_create(arg, do_replace) /* 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), @@ -2789,16 +3198,14 @@ find_replace_dialog_create(arg, do_replace) XmNbottomOffset, 4, NULL); - str = XmStringCreateSimple(_("Find Next")); frdp->find = XtVaCreateManagedWidget("findButton", xmPushButtonWidgetClass, button_form, - XmNlabelString, str, XmNsensitive, True, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); - XmStringFree(str); + set_label(frdp->find, _("Find &Next")); XtAddCallback(frdp->find, XmNactivateCallback, find_replace_callback, @@ -2806,57 +3213,50 @@ find_replace_dialog_create(arg, do_replace) if (do_replace) { - str = XmStringCreateSimple(_("Replace")); frdp->replace = XtVaCreateManagedWidget("replaceButton", xmPushButtonWidgetClass, button_form, - XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->find, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); - XmStringFree(str); + set_label(frdp->replace, _("&Replace")); XtAddCallback(frdp->replace, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACE); - str = XmStringCreateSimple(_("Replace All")); frdp->all = XtVaCreateManagedWidget("replaceAllButton", xmPushButtonWidgetClass, button_form, - XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->replace, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); - XmStringFree(str); + set_label(frdp->all, _("Replace &All")); XtAddCallback(frdp->all, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_REPLACEALL); - str = XmStringCreateSimple(_("Undo")); frdp->undo = XtVaCreateManagedWidget("undoButton", xmPushButtonWidgetClass, button_form, - XmNlabelString, str, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, frdp->all, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, NULL); - XmStringFree(str); + set_label(frdp->undo, _("&Undo")); XtAddCallback(frdp->undo, XmNactivateCallback, find_replace_callback, (XtPointer)FRD_UNDO); } - str = XmStringCreateSimple(_("Cancel")); frdp->cancel = XtVaCreateManagedWidget("closeButton", xmPushButtonWidgetClass, button_form, - XmNlabelString, str, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, NULL); - XmStringFree(str); + set_label(frdp->cancel, _("&Cancel")); XtAddCallback(frdp->cancel, XmNactivateCallback, find_replace_dismiss_callback, frdp); + gui_motif_menu_fontlist(frdp->cancel); XtManageChild(button_form); @@ -2894,6 +3294,7 @@ find_replace_dialog_create(arg, do_replace) XmNtopOffset, 4, NULL); XmStringFree(str); + gui_motif_menu_fontlist(label_what); frdp->what = XtVaCreateManagedWidget("whatText", xmTextFieldWidgetClass, input_form, @@ -2928,6 +3329,7 @@ find_replace_dialog_create(arg, do_replace) XmNbottomAttachment, XmATTACH_FORM, NULL); XmStringFree(str); + gui_motif_menu_fontlist(label_with); /* * Make the entry activation only change the input focus onto the @@ -2975,6 +3377,7 @@ find_replace_dialog_create(arg, do_replace) { Widget radio_box; + Widget w; frame = XtVaCreateWidget("directionFrame", xmFrameWidgetClass, frdp->dialog, @@ -2988,13 +3391,14 @@ find_replace_dialog_create(arg, do_replace) NULL); str = XmStringCreateSimple(_("Direction")); - (void)XtVaCreateManagedWidget("directionFrameLabel", + 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); @@ -3006,6 +3410,7 @@ find_replace_dialog_create(arg, do_replace) XmNset, False, NULL); XmStringFree(str); + gui_motif_menu_fontlist(frdp->up); str = XmStringCreateSimple(_("Down")); frdp->down = XtVaCreateManagedWidget("downRadioButton", @@ -3014,6 +3419,7 @@ find_replace_dialog_create(arg, do_replace) XmNset, True, NULL); XmStringFree(str); + gui_motif_menu_fontlist(frdp->down); XtManageChild(radio_box); XtManageChild(frame); @@ -3057,6 +3463,8 @@ find_replace_dialog_create(arg, do_replace) XmNset, mcase, NULL); XmStringFree(str); + gui_motif_menu_fontlist(frdp->wword); + gui_motif_menu_fontlist(frdp->mcase); XtManageChild(toggle_form); @@ -3064,7 +3472,10 @@ find_replace_dialog_create(arg, do_replace) XmTextFieldSetString(frdp->what, (char *)entry_text); vim_free(entry_text); - XtManageChild(frdp->dialog); + gui_motif_synch_fonts(); + + manage_centered(frdp->dialog); + activate_dialog_mnemonics(frdp->dialog); XmProcessTraversal(frdp->what, XmTRAVERSE_CURRENT); } @@ -3088,3 +3499,40 @@ gui_mch_replace_dialog(eap) 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); +} diff --git a/src/gui_photon.c b/src/gui_photon.c index b7c92df3dd..9223a40ec8 100644 --- a/src/gui_photon.c +++ b/src/gui_photon.c @@ -3047,6 +3047,7 @@ gui_mch_get_font(char_u *vim_font_name, int report_error) return( FAIL ); } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. @@ -3060,6 +3061,7 @@ gui_mch_get_fontname(font, name) return NULL; return vim_strsave(name); } +#endif void gui_mch_set_font(GuiFont font) diff --git a/src/gui_riscos.c b/src/gui_riscos.c index 7c9555e60e..f9784a2416 100644 --- a/src/gui_riscos.c +++ b/src/gui_riscos.c @@ -1052,6 +1052,7 @@ gui_mch_get_font(name, giveErrorIfMissing) return handle; } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. @@ -1065,6 +1066,7 @@ gui_mch_get_fontname(font, name) return NULL; return vim_strsave(name); } +#endif /* * Set the current text font. diff --git a/src/gui_w48.c b/src/gui_w48.c index b3948ce317..77cc24dbe3 100644 --- a/src/gui_w48.c +++ b/src/gui_w48.c @@ -1249,6 +1249,7 @@ gui_mch_get_font( return font; } +#if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. @@ -1262,6 +1263,7 @@ gui_mch_get_fontname(font, name) return NULL; return vim_strsave(name); } +#endif void gui_mch_free_font(GuiFont font) diff --git a/src/gui_xmdlg.c b/src/gui_xmdlg.c new file mode 100644 index 0000000000..3f1bd554fd --- /dev/null +++ b/src/gui_xmdlg.c @@ -0,0 +1,1287 @@ +/* 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. + */ + +/* + * (C) 2001 by Marcin Dalecki + * + * Implementation of dialogue functions for the Motif GUI variant. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "vim.h" + +extern Widget vimShell; + +#ifdef FEAT_MENU +# define apply_fontlist(w) gui_motif_menu_fontlist(w) +#else +# define apply_fontlist(w) +#endif + +/**************************************************************************** + * Font selection dialogue implementation. + */ + +static char wild[3] = "*"; + +/* + * FIXME: This is a generic function, which should be used throughout the whole + * application. + * + * Add close_callback, which will be called when the user selects close from + * the window menu. The close menu item usually activates f.kill which sends a + * WM_DELETE_WINDOW protocol request for the window. + */ + + static void +add_cancel_action(Widget shell, XtCallbackProc close_callback, void *arg) +{ + static Atom wmp_atom = 0; + static Atom dw_atom = 0; + Display *display = XtDisplay(shell); + + /* deactivate the built-in delete response of killing the application */ + XtVaSetValues(shell, XmNdeleteResponse, XmDO_NOTHING, 0); + + /* add a delete window protocol callback instead */ + if (!dw_atom) + { + wmp_atom = XmInternAtom(display, "WM_PROTOCOLS", True); + dw_atom = XmInternAtom(display, "WM_DELETE_WINDOW", True); + } + XmAddProtocolCallback(shell, wmp_atom, dw_atom, close_callback, arg); +} + +#define MAX_FONTS 65535 +#define MAX_FONT_NAME_LEN 256 +#define MAX_ENTRIES_IN_LIST 5000 +#define MAX_DISPLAY_SIZE 150 +#define TEMP_BUF_SIZE 256 + +enum ListSpecifier +{ + ENCODING, + NAME, + STYLE, + SIZE, + NONE +}; + +typedef struct _SharedFontSelData +{ + Widget dialog; + Widget ok; + Widget cancel; + Widget encoding_pulldown; + Widget encoding_menu; + Widget list[NONE]; + Widget name; + Widget sample; + char **names; /* font name array of arrays */ + int num; /* number of font names */ + String sel[NONE]; /* selection category */ + Boolean in_pixels; /* toggle state - size in pixels */ + char *font_name; /* current font name */ + XFontStruct *old; /* font data structure for sample display */ + XmFontList old_list; /* font data structure for sample display */ + Boolean exit; /* used for program exit control */ +} SharedFontSelData; + +/* + * Checking access to the font name array for validity. + */ + static char * +fn(SharedFontSelData *data, int i) +{ + /* Assertion checks: */ + if (data->num < 0) + abort(); + if (i >= data->num) + i = data->num - 1; + if (i < 0) + i = 0; + + return data->names[i]; +} + +/* + * Get a specific substring from a font name. + */ + static void +get_part(char *in, int pos, char *out) +{ + int i; + int j; + + *out = '\0'; + + for (i = 0; (pos > 0) && (in[i] != '\0'); ++i) + if (in[i] == '-') + pos--; + + if (in[i] == '\0') + return; + + for (j = 0; (in[i] != '-') && (in[i] != '\0'); ++i, ++j) + out[j] = in[i]; + out[j] = '\0'; +} + +/* + * Given a font name this function returns the part used in the first + * scroll list. + */ + static void +name_part(char *font, char *buf) +{ + char buf2[TEMP_BUF_SIZE]; + char buf3[TEMP_BUF_SIZE]; + + get_part(font, 2, buf2); + get_part(font, 1, buf3); + + if (strlen(buf3)) + sprintf(buf, "%s (%s)", buf2, buf3); + else + sprintf(buf, "%s", buf2); +} + +/* + * Given a font name this function returns the part used in the second scroll list. + */ + static void +style_part(char *font, char *buf) +{ + char buf2[TEMP_BUF_SIZE]; + char buf3[TEMP_BUF_SIZE]; + + get_part(font, 3, buf3); + get_part(font, 5, buf2); + + if (!strcmp(buf2, "normal") && !strcmp(buf2, "Normal") + && !strcmp(buf2, "NORMAL")) + sprintf(buf, "%s %s", buf3, buf2); + else + strcpy(buf, buf3); + + get_part(font, 6, buf2); + + if (buf2[0] != '\0') + sprintf(buf3, "%s %s", buf, buf2); + else + strcpy(buf3, buf); + + get_part(font, 4, buf2); + + if (!strcmp(buf2, "o") || !strcmp(buf2, "O")) + sprintf(buf, "%s oblique", buf3); + else if (!strcmp(buf2, "i") || !strcmp(buf2, "I")) + sprintf(buf, "%s italic", buf3); + + if (!strcmp(buf, " ")) + strcpy(buf, "-"); +} + +/* + * Given a font name this function returns the part used in the third + * scroll list. + */ + static void +size_part(char *font, char *buf, int inPixels) +{ + int size; + float temp; + + *buf = '\0'; + + if (inPixels) + { + get_part(font, 7, buf); + if (strlen(buf) > 0) + { + size = atoi(buf); + sprintf(buf, "%3d", size); + } + } + else + { + get_part(font, 8, buf); + if (strlen(buf) > 0) + { + size = atoi(buf); + temp = (float)size / 10.0; + size = temp; + if (buf[strlen(buf) - 1] == '0') + sprintf(buf, "%3d", size); + else + sprintf(buf, "%4.1f", temp); + } + } +} + +/* + * Given a font name this function returns the part used in the choice menu. + */ + static void +encoding_part(char *font, char *buf) +{ + char buf1[TEMP_BUF_SIZE]; + char buf2[TEMP_BUF_SIZE]; + + *buf = '\0'; + + get_part(font, 13, buf1); + get_part(font, 14, buf2); + + if (strlen(buf1) > 0 && strlen(buf2)) + sprintf(buf, "%s-%s", buf1, buf2); + if (!strcmp(buf, " ")) + strcpy(buf, "-"); +} + +/* + * Inserts a string into correct sorted position in a list. + */ + static void +add_to_list(char **buf, char *item, int *count) +{ + int i; + int j; + + if (*count == MAX_ENTRIES_IN_LIST) + return; + + /* avoid duplication */ + for (i = 0; i < *count; ++i) + { + if (!strcmp(buf[i], item)) + return; + } + + /* find order place, but make sure that wild card comes first */ + if (!strcmp(item, wild)) + i = 0; + else + for (i = 0; i < *count; ++i) + if (strcmp(buf[i], item) > 0 && strcmp(buf[i], wild)) + break; + + /* now insert the item */ + for (j = *count; j > i; --j) + buf[j] = buf[j-1]; + buf[i] = XtNewString(item); + + ++(*count); +} + +/* + * True if the font matches some field. + */ + static Boolean +match(SharedFontSelData *data, enum ListSpecifier l, int i) +{ + char buf[TEMP_BUF_SIZE]; + + /* An empty selection or a wild card matches anything. + */ + if (!data->sel[l] || !strcmp(data->sel[l], wild)) + return True; + + /* chunk out the desired part... */ + switch (l) + { + case ENCODING: + encoding_part(fn(data, i), buf); + break; + + case NAME: + name_part(fn(data, i), buf); + break; + + case STYLE: + style_part(fn(data, i), buf); + break; + + case SIZE: + size_part(fn(data, i), buf, data->in_pixels); + break; + default: + ; + } + + /* ...and chew it now */ + + return !strcmp(buf, data->sel[l]); +} + + static Boolean +proportional(char *font) +{ + char buf[TEMP_BUF_SIZE]; + + get_part(font, 11, buf); + + return !strcmp(buf, "p") || !strcmp(buf, "P"); +} + + +static void encoding_callback(Widget w, SharedFontSelData *data, + XtPointer dummy); + +/* + * Parse through the fontlist data and set up the three scroll lists. The fix + * parameter can be used to exclude a list from any changes. This is used for + * updates after selections caused by the users actions. + */ + static void +fill_lists(enum ListSpecifier fix, SharedFontSelData *data) +{ + char *list[NONE][MAX_ENTRIES_IN_LIST]; + int count[NONE]; + char buf[TEMP_BUF_SIZE]; + XmString items[MAX_ENTRIES_IN_LIST]; + int i; + int index; + + for (index = (int)ENCODING; index < (int)NONE; ++index) + count[index] = 0; + + /* First we insert the wild char into every single list. */ + if (fix != ENCODING) + add_to_list(list[ENCODING], wild, &count[ENCODING]); + if (fix != NAME) + add_to_list(list[NAME], wild, &count[NAME]); + if (fix != STYLE) + add_to_list(list[STYLE], wild, &count[STYLE]); + if (fix != SIZE) + add_to_list(list[SIZE], wild, &count[SIZE]); + + for (i = 0; i < data->num && i < MAX_ENTRIES_IN_LIST; i++) + { + if (proportional(fn(data, i))) + continue; + + if (fix != ENCODING + && match(data, NAME, i) + && match(data, STYLE, i) + && match(data, SIZE, i)) + { + encoding_part(fn(data, i), buf); + add_to_list(list[ENCODING], buf, &count[ENCODING]); + } + + if (fix != NAME + && match(data, ENCODING, i) + && match(data, STYLE, i) + && match(data, SIZE, i)) + { + name_part(fn(data, i), buf); + add_to_list(list[NAME], buf, &count[NAME]); + } + + if (fix != STYLE + && match(data, ENCODING, i) + && match(data, NAME, i) + && match(data, SIZE, i)) + { + style_part(fn(data, i), buf); + add_to_list(list[STYLE], buf, &count[STYLE]); + } + + if (fix != SIZE + && match(data, ENCODING, i) + && match(data, NAME, i) + && match(data, STYLE, i)) + { + size_part(fn(data, i), buf, data->in_pixels); + add_to_list(list[SIZE], buf, &count[SIZE]); + } + } + + /* + * And now do the preselection in all lists where there was one: + */ + + if (fix != ENCODING) + { + Cardinal n_items; + WidgetList children; + Widget selected_button = 0; + + /* Get and update the current button list. */ + XtVaGetValues(data->encoding_pulldown, + XmNchildren, &children, + XmNnumChildren, &n_items, + NULL); + + for (i = 0; i < count[ENCODING]; ++i) + { + Widget button; + + items[i] = XmStringCreateLocalized(list[ENCODING][i]); + + if (i < n_items) + { + /* recycle old button */ + XtVaSetValues(children[i], + XmNlabelString, items[i], + XmNuserData, i, + NULL); + button = children[i]; + } + else + { + /* create a new button */ + button = XtVaCreateManagedWidget("button", + xmPushButtonGadgetClass, + data->encoding_pulldown, + XmNlabelString, items[i], + XmNuserData, i, + NULL); + XtAddCallback(button, XmNactivateCallback, + (XtCallbackProc) encoding_callback, (XtPointer) data); + XtManageChild(button); + } + + if (data->sel[ENCODING]) + { + if (!strcmp(data->sel[ENCODING], list[ENCODING][i])) + selected_button = button; + } + XtFree(list[ENCODING][i]); + } + + /* Destroy all the outstandig menu items. + */ + for (i = count[ENCODING]; i < n_items; ++i) + { + XtUnmanageChild(children[i]); + XtDestroyWidget(children[i]); + } + + /* Preserve the current selection visually. + */ + if (selected_button) + { + XtVaSetValues(data->encoding_menu, + XmNmenuHistory, selected_button, + NULL); + } + + for (i = 0; i < count[ENCODING]; ++i) + XmStringFree(items[i]); + } + + /* + * Now loop trough the remaining lists and set them up. + */ + for (index = (int)NAME; index < (int)NONE; ++index) + { + Widget w; + + if (fix == (enum ListSpecifier)index) + continue; + + switch ((enum ListSpecifier)index) + { + case NAME: + w = data->list[NAME]; + break; + case STYLE: + w = data->list[STYLE]; + break; + case SIZE: + w = data->list[SIZE]; + break; + default: + w = (Widget)0; /* for lint */ + } + + for (i = 0; i < count[index]; ++i) + { + items[i] = XmStringCreateLocalized(list[index][i]); + XtFree(list[index][i]); + } + XmListDeleteAllItems(w); + XmListAddItems(w, items, count[index], 1); + if (data->sel[index]) + { + XmStringFree(items[0]); + items[0] = XmStringCreateLocalized(data->sel[index]); + XmListSelectItem(w, items[0], False); + XmListSetBottomItem(w, items[0]); + } + for (i = 0; i < count[index]; ++i) + XmStringFree(items[i]); + } +} + +/*ARGSUSED*/ + static void +stoggle_callback(Widget w, + SharedFontSelData *data, + XmToggleButtonCallbackStruct *call_data) +{ + int i, do_sel; + char newSize[10]; + XmString str; + + if (call_data->reason != (int)XmCR_VALUE_CHANGED) + return; + + do_sel = (data->sel[SIZE] != NULL) && strcmp(data->sel[SIZE], wild); + + for (i = 0; do_sel && (i < data->num); i++) + if (match(data, ENCODING, i) + && match(data, NAME, i) + && match(data, STYLE, i) + && match(data, SIZE, i)) + { + size_part(fn(data, i), newSize, !data->in_pixels); + break; + } + + data->in_pixels = !data->in_pixels; + + if (data->sel[SIZE]) + XtFree(data->sel[SIZE]); + data->sel[SIZE] = NULL; + fill_lists(NONE, data); + + if (do_sel) + { + str = XmStringCreateLocalized(newSize); + XmListSelectItem(data->list[SIZE], str, True); + XmListSetBottomItem(data->list[SIZE], str); + XmStringFree(str); + } +} + +/* + * Show the currently selected font in the sample text label. + */ + static void +display_sample(SharedFontSelData *data) +{ + Arg args[2]; + int n; + XFontStruct * font; + XmFontList font_list; + Display * display; + XmString str; + + display = XtDisplay(data->dialog); + font = XLoadQueryFont(display, data->font_name); + font_list = gui_motif_create_fontlist(font); + + n = 0; + str = XmStringCreateLocalized("AaBbZzYy 0123456789"); + XtSetArg(args[n], XmNlabelString, str); n++; + XtSetArg(args[n], XmNfontList, font_list); n++; + + XtSetValues(data->sample, args, n); + XmStringFree(str); + + if (data->old) + { + XFreeFont(display, data->old); + XmFontListFree(data->old_list); + } + data->old = font; + data->old_list = font_list; +} + + + static Boolean +do_choice(Widget w, + SharedFontSelData *data, + XmListCallbackStruct *call_data, + enum ListSpecifier which) +{ + char *sel; + + XmStringGetLtoR(call_data->item, XmSTRING_DEFAULT_CHARSET, &sel); + + if (!data->sel[which]) + data->sel[which] = XtNewString(sel); + else + { + XtFree(data->sel[which]); + if (!strcmp(data->sel[which], sel)) + { + /* unselecting current selection */ + data->sel[which] = NULL; + if (w) + XmListDeselectItem(w, call_data->item); + } + else + data->sel[which] = XtNewString(sel); + } + XtFree(sel); + + fill_lists(which, data); + + /* If there is a font selection, we display it. */ + if (data->sel[ENCODING] + && data->sel[NAME] + && data->sel[STYLE] + && data->sel[SIZE] + && strcmp(data->sel[ENCODING], wild) + && strcmp(data->sel[NAME], wild) + && strcmp(data->sel[STYLE], wild) + && strcmp(data->sel[SIZE], wild)) + { + int i; + + if (data->font_name) + XtFree(data->font_name); + data->font_name = NULL; + + for (i = 0; i < data->num; i++) + { + if (match(data, ENCODING, i) + && match(data, NAME, i) + && match(data, STYLE, i) + && match(data, SIZE, i)) + { + data->font_name = XtNewString(fn(data, i)); + break; + } + } + + if (data->font_name) + { + XmTextSetString(data->name, data->font_name); + display_sample(data); + } + else + do_dialog(VIM_ERROR, + (char_u *)_("Error"), + (char_u *)_("Invalid font specification"), + (char_u *)_("&Dismiss"), 1, NULL); + + return True; + } + else + { + int n; + XmString str; + Arg args[4]; + char *msg = _("no specific match"); + + n = 0; + str = XmStringCreateLocalized(msg); + XtSetArg(args[n], XmNlabelString, str); ++n; + XtSetValues(data->sample, args, n); + apply_fontlist(data->sample); + XmTextSetString(data->name, msg); + XmStringFree(str); + + return False; + } +} + +/*ARGSUSED*/ + static void +encoding_callback(Widget w, + SharedFontSelData *data, + XtPointer dummy) +{ + XmString str; + XmListCallbackStruct fake_data; + + XtVaGetValues(w, XmNlabelString, &str, NULL); + + if (!str) + return; + + fake_data.item = str; + + do_choice(0, data, &fake_data, ENCODING); +} + + static void +name_callback(Widget w, + SharedFontSelData *data, + XmListCallbackStruct *call_data) +{ + do_choice(w, data, call_data, NAME); +} + + static void +style_callback(Widget w, + SharedFontSelData *data, + XmListCallbackStruct *call_data) +{ + do_choice(w, data, call_data, STYLE); +} + + static void +size_callback(Widget w, + SharedFontSelData *data, + XmListCallbackStruct *call_data) +{ + do_choice(w, data, call_data, SIZE); +} + +/*ARGSUSED*/ + static void +cancel_callback(Widget w, + SharedFontSelData *data, + XmListCallbackStruct *call_data) +{ + if (data->sel[ENCODING]) + { + XtFree(data->sel[ENCODING]); + data->sel[ENCODING] = NULL; + } + if (data->sel[NAME]) + { + XtFree(data->sel[NAME]); + data->sel[NAME] = NULL; + } + if (data->sel[STYLE]) + { + XtFree(data->sel[STYLE]); + data->sel[STYLE] = NULL; + } + if (data->sel[SIZE]) + { + XtFree(data->sel[SIZE]); + data->sel[SIZE] = NULL; + } + + if (data->font_name) + XtFree(data->font_name); + data->font_name = NULL; + + data->num = 0; + XFreeFontNames(data->names); + data->names = NULL; + data->exit = True; +} + +/*ARGSUSED*/ + static void +ok_callback(Widget w, + SharedFontSelData *data, + XmPushButtonCallbackStruct *call_data) +{ + char *pattern; + char **name; + int i; + + pattern = XmTextGetString(data->name); + name = XListFonts(XtDisplay(data->dialog), pattern, 1, &i); + XtFree(pattern); + + if (i != 1) + { + do_dialog(VIM_ERROR, + (char_u *)_("Error"), + (char_u *)_("Invalid font specification"), + (char_u *)_("&Dismiss"), 1, NULL); + XFreeFontNames(name); + } + else + { + if (data->font_name) + XtFree(data->font_name); + data->font_name = XtNewString(name[0]); + + if (data->sel[ENCODING]) + { + XtFree(data->sel[ENCODING]); + data->sel[ENCODING] = NULL; + } + if (data->sel[NAME]) + { + XtFree(data->sel[NAME]); + data->sel[NAME] = NULL; + } + if (data->sel[STYLE]) + { + XtFree(data->sel[STYLE]); + data->sel[STYLE] = NULL; + } + if (data->sel[SIZE]) + { + XtFree(data->sel[SIZE]); + data->sel[SIZE] = NULL; + } + + XFreeFontNames(name); + + data->num = 0; + XFreeFontNames(data->names); + data->names = NULL; + data->exit = True; + } +} + +/* + * Returns pointer to an ASCII character string that contains the name of the + * selected font (in X format for naming fonts); it is the users responsibility + * to free the space allocated to this string. + */ + char_u * +gui_xm_select_font(char_u *current) +{ + static SharedFontSelData _data; + + Widget parent; + Widget form; + Widget separator; + Widget sub_form; + Widget size_toggle; + Widget name; + Widget disp_frame; + Widget frame; + Arg args[64]; + int n; + XmString str; + char big_font[MAX_FONT_NAME_LEN]; + SharedFontSelData *data; + + data = &_data; + + parent = vimShell; + data->names = XListFonts(XtDisplay(parent), "-*-*-*-*-*-*-*-*-*-*-*-*-*-*", + MAX_FONTS, &data->num); + + /* + * Find the name of the biggest font less than the given limit + * MAX_DISPLAY_SIZE used to set up the initial height of the display + * widget. + */ + + { + int i; + int max; + int index = 0; + int size; + char str[128]; + + for (i = 0, max = 0; i < data->num; i++) + { + get_part(fn(data, i), 7, str); + size = atoi(str); + if ((size > max) && (size < MAX_DISPLAY_SIZE)) + { + index = i; + max = size; + } + } + strcpy(big_font, fn(data, index)); + } + data->old = XLoadQueryFont(XtDisplay(parent), big_font); + data->old_list = gui_motif_create_fontlist(data->old); + + /* Set the title of the Dialog window. */ + data->dialog = XmCreateDialogShell(parent, "fontSelector", NULL, 0); + str = XmStringCreateLocalized(_("Vim - Font Selector")); + + /* Create form popup dialog widget. */ + form = XtVaCreateWidget("form", + xmFormWidgetClass, data->dialog, + XmNdialogTitle, str, + XmNautoUnmanage, False, + XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL, + NULL); + XmStringFree(str); + + sub_form = XtVaCreateManagedWidget("subForm", + xmFormWidgetClass, form, + XmNbottomAttachment, XmATTACH_FORM, + XmNbottomOffset, 4, + XmNrightAttachment, XmATTACH_FORM, + XmNrightOffset, 4, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 4, + XmNorientation, XmVERTICAL, + NULL); + + data->ok = XtVaCreateManagedWidget(_("OK"), + xmPushButtonGadgetClass, sub_form, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 4, + NULL); + apply_fontlist(data->ok); + + data->cancel = XtVaCreateManagedWidget(_("Cancel"), + xmPushButtonGadgetClass, sub_form, + XmNrightAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_WIDGET, + XmNtopWidget, data->ok, + XmNtopOffset, 4, + XmNshowAsDefault, True, + NULL); + apply_fontlist(data->cancel); + + /* Create the separator for beauty. */ + n = 0; + XtSetArg(args[n], XmNorientation, XmVERTICAL); n++; + XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++; + XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++; + XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); n++; + XtSetArg(args[n], XmNrightWidget, sub_form); n++; + XtSetArg(args[n], XmNrightOffset, 4); n++; + separator = XmCreateSeparatorGadget(form, "separator", args, n); + XtManageChild(separator); + + /* Create font name text widget and the corresponding label. */ + data->name = XtVaCreateManagedWidget("fontName", + xmTextWidgetClass, form, + XmNbottomAttachment, XmATTACH_FORM, + XmNbottomOffset, 4, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 4, + XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, separator, + XmNrightOffset, 4, + XmNeditable, False, + XmNeditMode, XmSINGLE_LINE_EDIT, + XmNmaxLength, MAX_FONT_NAME_LEN, + XmNcolumns, 60, + NULL); + + str = XmStringCreateLocalized(_("Name:")); + name = XtVaCreateManagedWidget("fontNameLabel", + xmLabelGadgetClass, form, + XmNlabelString, str, + XmNuserData, data->name, + XmNleftAttachment, XmATTACH_OPPOSITE_WIDGET, + XmNleftWidget, data->name, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, data->name, + XmNtopOffset, 1, + NULL); + XmStringFree(str); + apply_fontlist(name); + + /* create sample display label widget */ + disp_frame = XtVaCreateManagedWidget("sampleFrame", + xmFrameWidgetClass, form, + XmNshadowType, XmSHADOW_ETCHED_IN, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 4, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, name, + XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, separator, + XmNrightOffset, 4, + XmNalignment, XmALIGNMENT_BEGINNING, + NULL); + + data->sample = XtVaCreateManagedWidget("sampleLabel", + xmLabelWidgetClass, disp_frame, + XmNleftAttachment, XmATTACH_FORM, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_FORM, + XmNalignment, XmALIGNMENT_BEGINNING, + XmNrecomputeSize, False, + XmNfontList, data->old_list, + NULL); + + /* create toggle button */ + str = XmStringCreateLocalized(_("Show size in Points")); + size_toggle = XtVaCreateManagedWidget("sizeToggle", + xmToggleButtonGadgetClass, form, + XmNlabelString, str, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 4, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, disp_frame, + XmNbottomOffset, 4, + NULL); + XmStringFree(str); + apply_fontlist(size_toggle); + XtManageChild(size_toggle); + + /* Encoding pulldown menu. + */ + + data->encoding_pulldown = XmCreatePulldownMenu(form, + "encodingPulldown", NULL, 0); + str = XmStringCreateLocalized(_("Encoding:")); + n = 0; + XtSetArg(args[n], XmNsubMenuId, data->encoding_pulldown); ++n; + XtSetArg(args[n], XmNlabelString, str); ++n; + XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); ++n; + XtSetArg(args[n], XmNleftOffset, 4); ++n; + XtSetArg(args[n], XmNbottomAttachment, XmATTACH_WIDGET); ++n; + XtSetArg(args[n], XmNbottomWidget, size_toggle); ++n; + XtSetArg(args[n], XmNbottomOffset, 4); ++n; + XtSetArg(args[n], XmNrightAttachment, XmATTACH_WIDGET); ++n; + XtSetArg(args[n], XmNrightWidget, separator); ++n; + XtSetArg(args[n], XmNrightOffset, 4); ++n; + data->encoding_menu = XmCreateOptionMenu(form, "encodingMenu", args, n); + XmStringFree(str); + XmAddTabGroup(data->encoding_menu); + + /* + * Create scroll list widgets in a separate subform used to manage the + * different sizes of the lists. + */ + + sub_form = XtVaCreateManagedWidget("subForm", + xmFormWidgetClass, form, + XmNbottomAttachment, XmATTACH_WIDGET, + XmNbottomWidget, data->encoding_menu, + XmNbottomOffset, 4, + XmNleftAttachment, XmATTACH_FORM, + XmNleftOffset, 4, + XmNrightAttachment, XmATTACH_WIDGET, + XmNrightWidget, separator, + XmNrightOffset, 4, + XmNtopAttachment, XmATTACH_FORM, + XmNtopOffset, 2, + XmNorientation, XmVERTICAL, + NULL); + + /* font list */ + frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, + XmNshadowThickness, 0, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_FORM, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 50, + NULL); + + str = XmStringCreateLocalized(_("Font:")); + name = XtVaCreateManagedWidget("nameListLabel", xmLabelGadgetClass, frame, + XmNchildType, XmFRAME_TITLE_CHILD, + XmNchildVerticalAlignment, XmALIGNMENT_CENTER, + XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, + XmNlabelString, str, + NULL); + XmStringFree(str); + apply_fontlist(name); + + n = 0; + XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; + XtSetArg(args[n], XmNresizable, True); ++n; + XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; + XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; +#ifdef LESSTIF_VERSION + XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; +#endif + data->list[NAME] = XmCreateScrolledList(frame, "fontList", args, n); + XtVaSetValues(name, XmNuserData, data->list[NAME], NULL); + + /* style list */ + frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, + XmNshadowThickness, 0, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 50, + XmNleftOffset, 4, + XmNrightAttachment, XmATTACH_POSITION, + XmNrightPosition, 80, + NULL); + + str = XmStringCreateLocalized(_("Style:")); + name = XtVaCreateManagedWidget("styleListLabel", xmLabelWidgetClass, frame, + XmNchildType, XmFRAME_TITLE_CHILD, + XmNchildVerticalAlignment, XmALIGNMENT_CENTER, + XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, + XmNlabelString, str, + NULL); + XmStringFree(str); + apply_fontlist(name); + + n = 0; + XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; + XtSetArg(args[n], XmNresizable, True); ++n; + XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; + XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; +#ifdef LESSTIF_VERSION + XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; +#endif + data->list[STYLE] = XmCreateScrolledList(frame, "styleList", args, n); + XtVaSetValues(name, XmNuserData, data->list[STYLE], NULL); + + /* size list */ + frame = XtVaCreateManagedWidget("frame", xmFrameWidgetClass, sub_form, + XmNshadowThickness, 0, + XmNtopAttachment, XmATTACH_FORM, + XmNbottomAttachment, XmATTACH_FORM, + XmNleftAttachment, XmATTACH_POSITION, + XmNleftPosition, 80, + XmNleftOffset, 4, + XmNrightAttachment, XmATTACH_FORM, + NULL); + + str = XmStringCreateLocalized(_("Size:")); + name = XtVaCreateManagedWidget("sizeListLabel", xmLabelGadgetClass, frame, + XmNchildType, XmFRAME_TITLE_CHILD, + XmNchildVerticalAlignment, XmALIGNMENT_CENTER, + XmNchildHorizontalAlignment, XmALIGNMENT_BEGINNING, + XmNlabelString, str, + NULL); + XmStringFree(str); + apply_fontlist(name); + + n = 0; + XtSetArg(args[n], XmNvisibleItemCount, 8); ++n; + XtSetArg(args[n], XmNresizable, True); ++n; + XtSetArg(args[n], XmNlistSizePolicy, XmCONSTANT); ++n; + XtSetArg(args[n], XmNvisualPolicy, XmVARIABLE); ++n; +#ifdef LESSTIF_VERSION + XtSetArg(args[n], XmNscrollBarDisplayPolicy, XmSTATIC); ++n; +#endif + data->list[SIZE] = XmCreateScrolledList(frame, "sizeList", args, n); + XtVaSetValues(name, XmNuserData, data->list[SIZE], NULL); + + /* update form widgets cancel button */ + XtVaSetValues(form, XmNcancelButton, data->cancel, NULL); + + XtAddCallback(size_toggle, XmNvalueChangedCallback, + (XtCallbackProc)stoggle_callback, (XtPointer)data); + XtAddCallback(data->list[NAME], XmNbrowseSelectionCallback, + (XtCallbackProc)name_callback, (XtPointer)data); + XtAddCallback(data->list[STYLE], XmNbrowseSelectionCallback, + (XtCallbackProc)style_callback, (XtPointer)data); + XtAddCallback(data->list[SIZE], XmNbrowseSelectionCallback, + (XtCallbackProc)size_callback, (XtPointer)data); + XtAddCallback(data->ok, XmNactivateCallback, + (XtCallbackProc)ok_callback, (XtPointer)data); + XtAddCallback(data->cancel, XmNactivateCallback, + (XtCallbackProc)cancel_callback, (XtPointer)data); + + XmProcessTraversal(data->list[NAME], XmTRAVERSE_CURRENT); + + /* setup tabgroups */ + + XmAddTabGroup(data->list[NAME]); + XmAddTabGroup(data->list[STYLE]); + XmAddTabGroup(data->list[SIZE]); + XmAddTabGroup(size_toggle); + XmAddTabGroup(data->name); + XmAddTabGroup(data->ok); + XmAddTabGroup(data->cancel); + + add_cancel_action(data->dialog, (XtCallbackProc)cancel_callback, data); + + /* Preset selection data. */ + + data->exit = False; + data->in_pixels= True; + data->sel[ENCODING] = NULL; + data->sel[NAME] = NULL; + data->sel[STYLE] = NULL; + data->sel[SIZE] = NULL; + data->font_name = NULL; + + /* set up current font parameters */ + if (current && current[0] != '\0') + { + int i; + char **names; + + names = XListFonts(XtDisplay(form), (char *) current, 1, &i); + + if (i != 0) + { + char name[TEMP_BUF_SIZE]; + char style[TEMP_BUF_SIZE]; + char size[TEMP_BUF_SIZE]; + char encoding[TEMP_BUF_SIZE]; + char *found; + + found = names[0]; + + name_part(found, name); + style_part(found, style); + size_part(found, size, data->in_pixels); + encoding_part(found, encoding); + + if (strlen(name) > 0 + && strlen(style) > 0 + && strlen(size) > 0 + && strlen(encoding) > 0) + { + data->sel[NAME] = XtNewString(name); + data->sel[STYLE] = XtNewString(style); + data->sel[SIZE] = XtNewString(size); + d