# HG changeset patch # User Jan D. # Date 1271010309 -7200 # Node ID aa85632b7860a62765c22874a8736f12b72c26be # Parent 6438b98db9ddac3103fb71194cb30314ab42666d Use XFT in Lucid dialogs if available. * xmenu.c (apply_systemfont_to_dialog): New. (create_and_show_dialog): Call apply_systemfont_to_dialog if HAVE_XFT. * lwlib-Xaw.c (widget_xft_data): New for Xft data. (fill_xft_data, openFont, get_text_width_and_height) (draw_text, set_text, find_xft_data, command_press) (command_reset): New functions. (xaw_update_one_widget): Call set_text for dialog and buttons if HAVE_XFT. Also set internalHeight for buttons. (xaw_destroy_instance): Free all Xft related data. (button_actions, buttonTrans): New structures. (make_dialog): Call XtAppAddActions for button_actions. Find xft font to use and call fill_xft_data for widgets. (xaw_create_dialog): Pass instance parameter to make_dialog. * lwlib-int.h (_widget_instance): Add Xft data if HAVE_XFT. Override translations for buttons. If depth is 16 or more, tell Xaw3d to not be nice to colormap. Remove separator widget, use XtNhorizDistance on first right button instead. * xresources.texi (Lucid Resources): Mention faceName for dialogs. diff -r 6438b98db9dd -r aa85632b7860 doc/emacs/ChangeLog --- a/doc/emacs/ChangeLog Sun Apr 11 12:15:09 2010 -0400 +++ b/doc/emacs/ChangeLog Sun Apr 11 20:25:09 2010 +0200 @@ -1,3 +1,7 @@ +2010-04-11 Jan Djärv + + * xresources.texi (Lucid Resources): Mention faceName for dialogs. + 2010-04-08 Jan Djärv * xresources.texi (Lucid Resources): Mention faceName to set Xft fonts. diff -r 6438b98db9dd -r aa85632b7860 doc/emacs/xresources.texi --- a/doc/emacs/xresources.texi Sun Apr 11 12:15:09 2010 -0400 +++ b/doc/emacs/xresources.texi Sun Apr 11 20:25:09 2010 +0200 @@ -399,8 +399,9 @@ @end table @node Lucid Resources -@appendixsec Lucid Menu X Resources +@appendixsec Lucid Menu And Dialog X Resources @cindex Menu X Resources (Lucid widgets) +@cindex Dialog X Resources (Lucid widgets) @cindex Lucid Widget X Resources @ifnottex @@ -434,12 +435,13 @@ To specify a font, use fontconfig font names as values to the @code{faceName} resource. -If Emacs is not built with the Xft library, Lucid menus can only display -old style fonts. If Emacs is built with Xft and you prefer the old fonts, -you have to specify @samp{none} to @code{faceName}: +If Emacs is not built with the Xft library, Lucid menus and dialogs can only +display old style fonts. If Emacs is built with Xft and you prefer the old +fonts, you have to specify @samp{none} to @code{faceName}: @example Emacs.pane.menubar.faceName: none +Emacs.pane.dialog.faceName: none @end example @noindent @@ -477,7 +479,7 @@ For dialog boxes, use @samp{dialog*}: @example -Emacs.dialog*.font: 8x16 +Emacs.dialog*.faceName: Sans-12 @end example @noindent diff -r 6438b98db9dd -r aa85632b7860 etc/NEWS --- a/etc/NEWS Sun Apr 11 12:15:09 2010 -0400 +++ b/etc/NEWS Sun Apr 11 20:25:09 2010 +0200 @@ -65,7 +65,8 @@ ** GTK scroll-bars are now placed on the right by default. Use `set-scroll-bar-mode' to change this. -** Lucid menus can display antialiased fonts if Emacs is build with Xft. +** Lucid menus and dialogs can display antialiased fonts if Emacs is built +with Xft. ** New scrolling commands `scroll-up-command' and `scroll-down-command' (bound to [next] and [prior]) does not signal errors at top/bottom diff -r 6438b98db9dd -r aa85632b7860 lwlib/ChangeLog --- a/lwlib/ChangeLog Sun Apr 11 12:15:09 2010 -0400 +++ b/lwlib/ChangeLog Sun Apr 11 20:25:09 2010 +0200 @@ -1,3 +1,23 @@ +2010-04-11 Jan Djärv + + * lwlib-Xaw.c (widget_xft_data): New for Xft data. + (fill_xft_data, openFont, get_text_width_and_height) + (draw_text, set_text, find_xft_data, command_press) + (command_reset): New functions. + (xaw_update_one_widget): Call set_text for dialog and buttons + if HAVE_XFT. Also set internalHeight for buttons. + (xaw_destroy_instance): Free all Xft related data. + (button_actions, buttonTrans): New structures. + (make_dialog): Call XtAppAddActions for button_actions. + Find xft font to use and call fill_xft_data for widgets. + (xaw_create_dialog): Pass instance parameter to make_dialog. + + * lwlib-int.h (_widget_instance): Add Xft data if HAVE_XFT. + Override translations for buttons. If depth is 16 or more, tell + Xaw3d to not be nice to colormap. + Remove separator widget, use XtNhorizDistance on first right button + instead. + 2010-04-08 Jan Djärv * xlwmenu.c (xlwmenu_default_font): Make static. diff -r 6438b98db9dd -r aa85632b7860 lwlib/lwlib-Xaw.c --- a/lwlib/lwlib-Xaw.c Sun Apr 11 12:15:09 2010 -0400 +++ b/lwlib/lwlib-Xaw.c Sun Apr 11 20:25:09 2010 +0200 @@ -54,6 +54,22 @@ #include +#ifdef HAVE_XFT +#include + +struct widget_xft_data +{ + Widget widget; + XftFont *xft_font; + XftDraw *xft_draw; + XftColor xft_fg, xft_bg; + int p_width, p_height; + Pixmap p; +}; + + +#endif + static void xaw_generic_callback (/*Widget, XtPointer, XtPointer*/); @@ -130,6 +146,207 @@ } #endif +#ifdef HAVE_XFT +static void +fill_xft_data (struct widget_xft_data *data, Widget widget, XftFont *font) +{ + data->widget = widget; + data->xft_font = font; + Pixel bg, fg; + XColor colors[2]; + int screen = XScreenNumberOfScreen (XtScreen (widget)); + + XtVaGetValues (widget, + XtNbackground, &bg, + XtNforeground, &fg, + NULL); + + colors[0].pixel = data->xft_fg.pixel = fg; + colors[1].pixel = data->xft_bg.pixel = bg; + XQueryColors (XtDisplay (widget), + DefaultColormapOfScreen (XtScreen (widget)), + colors, 2); + + data->xft_fg.color.alpha = 0xFFFF; + data->xft_fg.color.red = colors[0].red; + data->xft_fg.color.green = colors[0].green; + data->xft_fg.color.blue = colors[0].blue; + data->xft_bg.color.alpha = 0xFFFF; + data->xft_bg.color.red = colors[1].red; + data->xft_bg.color.green = colors[1].green; + data->xft_bg.color.blue = colors[1].blue; + + data->p = None; + data->xft_draw = 0; + data->p_width = data->p_height = 0; +} + +static XftFont* +openFont (Widget widget, char *name) +{ + char *fname = name; + int screen = XScreenNumberOfScreen (XtScreen (widget)); + int len = strlen (fname), i = len-1; + XftFont *fn; + + /* Try to convert Gtk-syntax (Sans 9) to Xft syntax Sans-9. */ + while (i > 0 && isdigit (fname[i])) + --i; + if (fname[i] == ' ') + { + fname = xstrdup (name); + fname[i] = '-'; + } + + fn = XftFontOpenName (XtDisplay (widget), screen, fname); + if (fname != name) free (fname); + + return fn; +} + +static int +get_text_width_and_height (Widget widget, char *text, + XftFont *xft_font, + int *height) +{ + int w = 0, h = 0; + char *bp = text; + + while (bp && *bp != '\0') + { + XGlyphInfo gi; + char *cp = strchr (bp, '\n'); + XftTextExtentsUtf8 (XtDisplay (widget), xft_font, + (FcChar8 *) bp, + cp ? cp - bp : strlen (bp), + &gi); + bp = cp ? cp + 1 : NULL; + h += xft_font->height; + if (w < gi.width) w = gi.width; + } + + *height = h; + return w; +} + +static void +draw_text (struct widget_xft_data *data, char *lbl, int inverse) +{ + Screen *sc = XtScreen (data->widget); + int screen = XScreenNumberOfScreen (sc); + int y = data->xft_font->ascent; + int x = inverse ? 0 : 2; + char *bp = lbl; + + data->xft_draw = XftDrawCreate (XtDisplay (data->widget), + data->p, + DefaultVisual (XtDisplay (data->widget), + screen), + DefaultColormapOfScreen (sc)); + XftDrawRect (data->xft_draw, + inverse ? &data->xft_fg : &data->xft_bg, + 0, 0, data->p_width, data->p_height); + + if (!inverse) y += 2; + while (bp && *bp != '\0') + { + char *cp = strchr (bp, '\n'); + XftDrawStringUtf8 (data->xft_draw, + inverse ? &data->xft_bg : &data->xft_fg, + data->xft_font, x, y, bp, cp ? cp - bp : strlen (bp)); + bp = cp ? cp + 1 : NULL; + /* 1.2 gives reasonable line spacing. */ + y += data->xft_font->height * 1.2; + } + +} + + +static void +set_text (struct widget_xft_data *data, Widget toplevel, char *lbl, int margin) +{ + int screen = XScreenNumberOfScreen (XtScreen (data->widget)); + int width, height; + + width = get_text_width_and_height (data->widget, lbl, data->xft_font, + &height); + data->p_width = width + margin; + data->p_height = height + margin; + + data->p = XCreatePixmap (XtDisplay (data->widget), + XtWindow (toplevel), + data->p_width, + data->p_height, + DefaultDepthOfScreen (XtScreen (data->widget))); + draw_text (data, lbl, 0); + XtVaSetValues (data->widget, XtNbitmap, data->p, NULL); +} + +static struct widget_xft_data * +find_xft_data (Widget widget) +{ + widget_instance *inst = NULL; + Widget parent = XtParent (widget); + struct widget_xft_data *data = NULL; + int nr; + while (parent && !inst) + { + inst = lw_get_widget_instance (parent); + parent = XtParent (parent); + } + if (!inst || !inst->xft_data || !inst->xft_data[0].xft_font) return; + + for (nr = 0; data == NULL && nr < inst->nr_xft_data; ++nr) + { + if (inst->xft_data[nr].widget == widget) + data = &inst->xft_data[nr]; + } + + return data; +} + +static void +command_press (Widget widget, + XEvent* event, + String *params, + Cardinal *num_params) +{ + struct widget_xft_data *data = find_xft_data (widget); + if (data) + { + char *lbl; + /* Since this isn't used for rectangle buttons, use it to for armed. */ + XtVaSetValues (widget, XtNcornerRoundPercent, 1, NULL); + + XtVaGetValues (widget, XtNlabel, &lbl, NULL); + draw_text (data, lbl, 1); + } +} + +static void +command_reset (Widget widget, + XEvent* event, + String *params, + Cardinal *num_params) +{ + struct widget_xft_data *data = find_xft_data (widget); + if (data) + { + Dimension cr; + XtVaGetValues (widget, XtNcornerRoundPercent, &cr, NULL); + if (cr == 1) + { + char *lbl; + XtVaSetValues (widget, XtNcornerRoundPercent, 0, NULL); + XtVaGetValues (widget, XtNlabel, &lbl, NULL); + draw_text (data, lbl, 0); + } + } +} + + +#endif + void #ifdef PROTOTYPES xaw_update_one_widget (widget_instance *instance, Widget widget, @@ -150,15 +367,21 @@ #endif if (XtIsSubclass (widget, dialogWidgetClass)) { - Arg al[1]; - int ac = 0; - XtSetArg (al[ac], XtNlabel, val->contents->value); ac++; - XtSetValues (widget, al, ac); + +#ifdef HAVE_XFT + if (instance->xft_data && instance->xft_data[0].xft_font) + { + set_text (&instance->xft_data[0], instance->parent, + val->contents->value, 10); + } +#endif + XtVaSetValues (widget, XtNlabel, val->contents->value, NULL); } else if (XtIsSubclass (widget, commandWidgetClass)) { Dimension bw = 0; - Arg al[3]; + Arg al[10]; + int ac = 0; XtVaGetValues (widget, XtNborderWidth, &bw, NULL); if (bw == 0) @@ -174,10 +397,30 @@ } XtSetSensitive (widget, val->enabled); - XtSetArg (al[0], XtNlabel, val->value); + XtSetArg (al[ac], XtNlabel, val->value);ac++; /* Force centered button text. Se above. */ - XtSetArg (al[1], XtNjustify, XtJustifyCenter); - XtSetValues (widget, al, 2); + XtSetArg (al[ac], XtNjustify, XtJustifyCenter);ac++; +#ifdef HAVE_XFT + if (instance->xft_data && instance->xft_data[0].xft_font) + { + int th; + int nr; + for (nr = 0; nr < instance->nr_xft_data; ++nr) + if (instance->xft_data[nr].widget == widget) + break; + if (nr < instance->nr_xft_data) + { + set_text (&instance->xft_data[nr], instance->parent, + val->value, 6); + + /* Must set internalHeight to twice the highlight thickness, + or else it gets overwritten by our pixmap. Probably a bug. */ + XtVaGetValues (widget, XtNhighlightThickness, &th, NULL); + XtSetArg (al[ac], XtNinternalHeight, 2*th);ac++; + } + } +#endif + XtSetValues (widget, al, ac); XtRemoveAllCallbacks (widget, XtNcallback); XtAddCallback (widget, XtNcallback, xaw_generic_callback, instance); } @@ -198,6 +441,28 @@ xaw_destroy_instance (instance) widget_instance *instance; { +#ifdef HAVE_XFT + if (instance->xft_data) + { + int i; + for (i = 0; i < instance->nr_xft_data; ++i) + { + if (instance->xft_data[i].xft_draw) + XftDrawDestroy (instance->xft_data[i].xft_draw); + if (instance->xft_data[i].p != None) + { + XtVaSetValues (instance->xft_data[i].widget, XtNbitmap, None, + NULL); + XFreePixmap (XtDisplay (instance->widget), + instance->xft_data[i].p); + } + } + if (instance->xft_data[0].xft_font) + XftFontClose (XtDisplay (instance->widget), + instance->xft_data[0].xft_font); + free (instance->xft_data); + } +#endif if (XtIsSubclass (instance->widget, dialogWidgetClass)) /* Need to destroy the Shell too. */ XtDestroyWidget (XtParent (instance->widget)); @@ -298,8 +563,21 @@ }; static Boolean actions_initted = False; +#ifdef HAVE_XFT +static XtActionsRec button_actions[] = + { + { "my_reset", command_reset }, + { "my_press", command_press }, + }; +char buttonTrans[] = + ": reset() my_reset()\n" + ": set() my_press()\n" + ": my_reset() notify() unset()\n"; +#endif + static Widget -make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, radio_box, list, left_buttons, right_buttons) +make_dialog (name, parent, pop_up_p, shell_title, icon_name, text_input_slot, + radio_box, list, left_buttons, right_buttons, instance) char* name; Widget parent; Boolean pop_up_p; @@ -310,6 +588,7 @@ Boolean list; int left_buttons; int right_buttons; + widget_instance *instance; { Arg av [20]; int ac = 0; @@ -319,6 +598,10 @@ Widget dialog; Widget button; XtTranslations override; +#ifdef HAVE_XFT + XftFont *xft_font = 0; + XtTranslations button_override; +#endif if (! pop_up_p) abort (); /* not implemented */ if (text_input_slot) abort (); /* not implemented */ @@ -330,6 +613,10 @@ XtAppContext app = XtWidgetToApplicationContext (parent); XtAppAddActions (app, xaw_actions, sizeof (xaw_actions) / sizeof (xaw_actions[0])); +#ifdef HAVE_XFT + XtAppAddActions (app, button_actions, + sizeof (button_actions) / sizeof (button_actions[0])); +#endif actions_initted = True; } @@ -351,6 +638,49 @@ override = XtParseTranslationTable (dialogOverride); XtOverrideTranslations (dialog, override); +#ifdef HAVE_XFT + { + int num; + Widget *ch = NULL; + Widget w = 0; + XtVaGetValues (dialog, + XtNnumChildren, &num, + XtNchildren, &ch, NULL); + for (i = 0; i < num; ++i) + { + if (!XtIsSubclass (ch[i], commandWidgetClass) + && XtIsSubclass (ch[i], labelWidgetClass)) + { + w = ch[i]; + break; + } + } + instance->xft_data = 0; + instance->nr_xft_data = 0; + if (w) + { + XtResource rec[] = + { { "faceName", "FaceName", XtRString, sizeof(String), 0, XtRString, + (XtPointer)"Sans-14" }}; + char *faceName; + XtVaGetSubresources (dialog, &faceName, "Dialog", "dialog", + rec, 1, 0, NULL); + if (strcmp ("none", faceName) != 0) + xft_font = openFont (dialog, faceName); + if (xft_font) + { + instance->nr_xft_data = left_buttons + right_buttons + 1; + instance->xft_data = calloc (instance->nr_xft_data, + sizeof(*instance->xft_data)); + + fill_xft_data (&instance->xft_data[0], w, xft_font); + } + } + + button_override = XtParseTranslationTable (buttonTrans); + } +#endif + bc = 0; button = 0; for (i = 0; i < left_buttons; i++) @@ -362,51 +692,56 @@ XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; XtSetArg (av [ac], XtNresizable, True); ac++; +#ifdef HAVE_XAW3D + if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16) + { + /* Turn of dithered shadow if we can. Looks bad */ + XtSetArg (av [ac], "beNiceToColormap", False); ac++; + } +#endif sprintf (button_name, "button%d", ++bc); button = XtCreateManagedWidget (button_name, commandWidgetClass, dialog, av, ac); +#ifdef HAVE_XFT + if (xft_font) + { + fill_xft_data (&instance->xft_data[bc], button, xft_font); + XtOverrideTranslations (button, button_override); + } +#endif } - if (right_buttons) - { - /* Create a separator - I want the separator to take up the slack between the buttons on - the right and the buttons on the left (that is I want the buttons - after the separator to be packed against the right edge of the - window) but I can't seem to make it do it. - */ - ac = 0; - XtSetArg (av [ac], XtNfromHoriz, button); ac++; -/* XtSetArg (av [ac], XtNfromVert, XtNameToWidget (dialog, "label")); ac++; */ - XtSetArg (av [ac], XtNleft, XtChainLeft); ac++; - XtSetArg (av [ac], XtNright, XtChainRight); ac++; - XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; - XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; - XtSetArg (av [ac], XtNlabel, ""); ac++; - XtSetArg (av [ac], XtNwidth, 30); ac++; /* #### aaack!! */ - XtSetArg (av [ac], XtNborderWidth, 0); ac++; - XtSetArg (av [ac], XtNshapeStyle, XmuShapeRectangle); ac++; - XtSetArg (av [ac], XtNresizable, False); ac++; - XtSetArg (av [ac], XtNsensitive, False); ac++; - button = XtCreateManagedWidget ("separator", - /* labelWidgetClass, */ - /* This has to be Command to fake out - the Dialog widget... */ - commandWidgetClass, - dialog, av, ac); - } for (i = 0; i < right_buttons; i++) { ac = 0; XtSetArg (av [ac], XtNfromHoriz, button); ac++; + if (i == 0) + { + /* Separator to the other buttons. */ + XtSetArg (av [ac], XtNhorizDistance, 30); ac++; + } XtSetArg (av [ac], XtNleft, XtChainRight); ac++; XtSetArg (av [ac], XtNright, XtChainRight); ac++; XtSetArg (av [ac], XtNtop, XtChainBottom); ac++; XtSetArg (av [ac], XtNbottom, XtChainBottom); ac++; XtSetArg (av [ac], XtNresizable, True); ac++; +#ifdef HAVE_XAW3D + if (DefaultDepthOfScreen (XtScreen (dialog)) >= 16) + { + /* Turn of dithered shadow if we can. Looks bad */ + XtSetArg (av [ac], "beNiceToColormap", False); ac++; + } +#endif sprintf (button_name, "button%d", ++bc); button = XtCreateManagedWidget (button_name, commandWidgetClass, dialog, av, ac); +#ifdef HAVE_XFT + if (xft_font) + { + fill_xft_data (&instance->xft_data[bc], button, xft_font); + XtOverrideTranslations (button, button_override); + } +#endif } return dialog; @@ -472,8 +807,7 @@ widget = make_dialog (name, parent, pop_up_p, shell_name, icon_name, text_input_slot, radio_box, - list, left_buttons, right_buttons); - + list, left_buttons, right_buttons, instance); return widget; } diff -r 6438b98db9dd -r aa85632b7860 lwlib/lwlib-int.h --- a/lwlib/lwlib-int.h Sun Apr 11 12:15:09 2010 -0400 +++ b/lwlib/lwlib-int.h Sun Apr 11 20:25:09 2010 +0200 @@ -28,11 +28,17 @@ extern char *safe_strdup __P ((const char *)); +struct widget_xft_data; + typedef struct _widget_instance { Widget widget; Widget parent; Boolean pop_up_p; +#ifdef HAVE_XFT + struct widget_xft_data *xft_data; + int nr_xft_data; +#endif struct _widget_info* info; struct _widget_instance* next; } widget_instance; diff -r 6438b98db9dd -r aa85632b7860 src/ChangeLog --- a/src/ChangeLog Sun Apr 11 12:15:09 2010 -0400 +++ b/src/ChangeLog Sun Apr 11 20:25:09 2010 +0200 @@ -1,3 +1,8 @@ +2010-04-11 Jan Djärv + + * xmenu.c (apply_systemfont_to_dialog): New. + (create_and_show_dialog): Call apply_systemfont_to_dialog if HAVE_XFT. + 2010-04-11 Stefan Monnier * process.c (exec_sentinel): Preserve current-buffer. diff -r 6438b98db9dd -r aa85632b7860 src/xmenu.c --- a/src/xmenu.c Sun Apr 11 12:15:09 2010 -0400 +++ b/src/xmenu.c Sun Apr 11 20:25:09 2010 +0200 @@ -954,6 +954,19 @@ #ifdef USE_LUCID static void +apply_systemfont_to_dialog (w) + Widget w; +{ + const char *fn = xsettings_get_system_normal_font (); + if (fn) + { + XrmDatabase db = XtDatabase (XtDisplay (w)); + if (db) + XrmPutStringResource (&db, "*dialog.faceName", fn); + } +} + +static void apply_systemfont_to_menu (w) Widget w; { @@ -964,15 +977,15 @@ if (XtIsShell (w)) /* popup menu */ { - Widget *childs[1]; + Widget *childs = NULL; int num = 0; XtVaGetValues (w, XtNnumChildren, &num, NULL); if (num != 1) return; /* Should only be one. */ childs[0] = 0; - XtVaGetValues (w, XtNchildren, childs, NULL); - if (childs[0] && *childs[0]) w = *childs[0]; + XtVaGetValues (w, XtNchildren, &childs, NULL); + if (childs && *childs) w = *childs; } /* Only use system font if the default is used for the menu. */ @@ -2047,11 +2060,13 @@ abort(); dialog_id = widget_id_tick++; +#ifdef HAVE_XFT + apply_systemfont_to_dialog (f->output_data.x->widget); +#endif lw_create_widget (first_wv->name, "dialog", dialog_id, first_wv, f->output_data.x->widget, 1, 0, dialog_selection_callback, 0, 0); lw_modify_all_widgets (dialog_id, first_wv->contents, True); - /* Display the dialog box. */ lw_pop_up_all_widgets (dialog_id); popup_activated_flag = 1;