Mercurial > hg > xemacs-beta
diff src/fontcolor-x.c @ 5176:8b2f75cecb89
rename objects* (.c, .h and .el files) to fontcolor*
-------------------- ChangeLog entries follow: --------------------
etc/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* dbxrc.in:
Rename objects.c -> fontcolor.c.
lisp/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* dumped-lisp.el (preloaded-file-list):
* font.el (font-tty-find-closest-color):
* fontcolor.el:
* fontcolor.el (ws-object-property-1): Removed.
* fontcolor.el (fontcolor-property-1): New.
* fontcolor.el (font-name):
* fontcolor.el (font-ascent):
* fontcolor.el (font-descent):
* fontcolor.el (font-width):
* fontcolor.el (font-height):
* fontcolor.el (font-proportional-p):
* fontcolor.el (font-properties):
* fontcolor.el (font-truename):
* fontcolor.el (color-name):
* fontcolor.el (color-rgb-components):
* x-faces.el:
Rename objects.el -> fontcolor.el.
lwlib/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* lwlib-colors.h:
objects*.h -> fontcolor*.h.
man/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* internals/internals.texi (A Summary of the Various XEmacs Modules):
* internals/internals.texi (Modules for other Display-Related Lisp Objects):
objects*.[ch] -> fontcolor*.[ch].
nt/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* xemacs.dsp:
* xemacs.mak:
* xemacs.mak (OPT_OBJS):
objects*.[ch] -> fontcolor*.[ch].
src/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* EmacsFrame.c:
* Makefile.in.in (x_objs):
* Makefile.in.in (mswindows_objs):
* Makefile.in.in (tty_objs):
* Makefile.in.in (gtk_objs):
* Makefile.in.in (objs):
* console-tty.h:
* console-x-impl.h:
* console-x-impl.h (struct x_device):
* console-x.h:
* console-xlike-inc.h:
* depend:
* device-gtk.c:
* device-msw.c:
* device-x.c:
* device-x.c (x_init_device):
* device-x.c (x_finish_init_device):
* device.c:
* devslots.h (MARKED_SLOT):
* emacs.c (main_1):
* event-Xt.c:
* event-gtk.c:
* event-msw.c:
* faces.c:
* font-mgr.c:
* fontcolor-gtk-impl.h:
* fontcolor-gtk.c:
* fontcolor-gtk.c (syms_of_fontcolor_gtk):
* fontcolor-gtk.c (console_type_create_fontcolor_gtk):
* fontcolor-gtk.c (vars_of_fontcolor_gtk):
* fontcolor-gtk.h:
* fontcolor-impl.h:
* fontcolor-msw-impl.h:
* fontcolor-msw.c:
* fontcolor-msw.c (syms_of_fontcolor_mswindows):
* fontcolor-msw.c (console_type_create_fontcolor_mswindows):
* fontcolor-msw.c (reinit_vars_of_fontcolor_mswindows):
* fontcolor-msw.c (vars_of_fontcolor_mswindows):
* fontcolor-msw.h:
* fontcolor-msw.h (mswindows_color_to_string):
* fontcolor-tty-impl.h:
* fontcolor-tty.c:
* fontcolor-tty.c (syms_of_fontcolor_tty):
* fontcolor-tty.c (console_type_create_fontcolor_tty):
* fontcolor-tty.c (vars_of_fontcolor_tty):
* fontcolor-tty.h:
* fontcolor-x-impl.h:
* fontcolor-x.c:
* fontcolor-x.c (syms_of_fontcolor_x):
* fontcolor-x.c (console_type_create_fontcolor_x):
* fontcolor-x.c (vars_of_fontcolor_x):
* fontcolor-x.c (Xatoms_of_fontcolor_x):
* fontcolor-x.h:
* fontcolor.c:
* fontcolor.c (syms_of_fontcolor):
* fontcolor.c (specifier_type_create_fontcolor):
* fontcolor.c (reinit_specifier_type_create_fontcolor):
* fontcolor.c (reinit_vars_of_fontcolor):
* fontcolor.c (vars_of_fontcolor):
* fontcolor.h:
* fontcolor.h (set_face_boolean_attached_to):
* frame-gtk.c:
* frame-x.c:
* glyphs-eimage.c:
* glyphs-gtk.c:
* glyphs-msw.c:
* glyphs-widget.c:
* glyphs-x.c:
* glyphs.c:
* gtk-glue.c:
* gtk-glue.c (xemacs_type_register):
* gtk-xemacs.c:
* inline.c:
* intl-win32.c:
* lisp.h:
* lrecord.h:
* mule-charset.c:
* native-gtk-toolbar.c:
* redisplay-msw.c:
* redisplay-tty.c:
* redisplay.c:
* select-x.c:
* select.c:
* symsinit.h:
* toolbar-msw.c:
* toolbar-msw.c (TOOLBAR_ITEM_ID_BITS):
* toolbar-x.c:
* ui-gtk.c:
* window.c:
Rename objects*.[ch] -> fontcolor*.[ch]. Fix up all references to
the old files (e.g. in #include statements, Makefiles,
functions like syms_of_objects_x(), etc.).
tests/ChangeLog addition:
2010-02-22 Ben Wing <ben@xemacs.org>
* reproduce-crashes.el (8):
objects*.[ch] -> fontcolor*.[ch].
author | Ben Wing <ben@xemacs.org> |
---|---|
date | Mon, 22 Feb 2010 06:49:30 -0600 |
parents | src/objects-x.c@3c3c1d139863 |
children | b65692aa90d8 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/fontcolor-x.c Mon Feb 22 06:49:30 2010 -0600 @@ -0,0 +1,988 @@ +/* X-specific Lisp objects. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + Copyright (C) 1995 Board of Trustees, University of Illinois. + Copyright (C) 1995 Tinker Systems. + Copyright (C) 1995, 1996, 2000, 2001, 2002, 2004 Ben Wing. + Copyright (C) 1995 Sun Microsystems, Inc. + +This file is part of XEmacs. + +XEmacs is free software; you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the +Free Software Foundation; either version 2, or (at your option) any +later version. + +XEmacs is distributed in the hope that it will be useful, but WITHOUT +ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with XEmacs; see the file COPYING. If not, write to +the Free Software Foundation, Inc., 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ + +/* Synched up with: Not in FSF. */ + +/* Authors: Jamie Zawinski, Chuck Thompson, Ben Wing */ + +/* This file Mule-ized by Ben Wing, 7-10-00. */ + +#include <config.h> +#include "lisp.h" + +#include "charset.h" +#include "device-impl.h" +#include "insdel.h" + +#include "console-x-impl.h" +#include "fontcolor-x-impl.h" +#include "elhash.h" + +#ifdef HAVE_XFT +#include "font-mgr.h" +#endif + +int x_handle_non_fully_specified_fonts; + +#ifdef DEBUG_XEMACS +Fixnum debug_x_objects; +#endif /* DEBUG_XEMACS */ + + +/************************************************************************/ +/* color instances */ +/************************************************************************/ + +static int +x_parse_nearest_color (struct device *d, XColor *color, Lisp_Object name, + Error_Behavior errb) +{ + Display *dpy = DEVICE_X_DISPLAY (d); + Colormap cmap = DEVICE_X_COLORMAP (d); + Visual *visual = DEVICE_X_VISUAL (d); + int result; + + xzero (*color); + { + const Extbyte *extname; + + extname = LISP_STRING_TO_EXTERNAL (name, Qx_color_name_encoding); + result = XParseColor (dpy, cmap, extname, color); + } + if (!result) + { + maybe_signal_error (Qgui_error, "Unrecognized color", + name, Qcolor, errb); + return 0; + } + result = x_allocate_nearest_color (dpy, cmap, visual, color); + if (!result) + { + maybe_signal_error (Qgui_error, "Couldn't allocate color", + name, Qcolor, errb); + return 0; + } + + return result; +} + +static int +x_initialize_color_instance (Lisp_Color_Instance *c, Lisp_Object name, + Lisp_Object device, Error_Behavior errb) +{ + XColor color; +#ifdef HAVE_XFT + XftColor xftColor; +#endif + int result; + + result = x_parse_nearest_color (XDEVICE (device), &color, name, errb); + + if (!result) + return 0; + + /* Don't allocate the data until we're sure that we will succeed, + or the finalize method may get fucked. */ + c->data = xnew (struct x_color_instance_data); + if (result == 3) + COLOR_INSTANCE_X_DEALLOC (c) = 0; + else + COLOR_INSTANCE_X_DEALLOC (c) = 1; + COLOR_INSTANCE_X_COLOR (c) = color; + +#ifdef HAVE_XFT + xftColor.pixel = color.pixel; + xftColor.color.red = color.red; + xftColor.color.green = color.green; + xftColor.color.blue = color.blue; + xftColor.color.alpha = 0xffff; + + COLOR_INSTANCE_X_XFTCOLOR (c) = xftColor; +#endif + + return 1; +} + +static void +x_print_color_instance (Lisp_Color_Instance *c, + Lisp_Object printcharfun, + int UNUSED (escapeflag)) +{ + XColor color = COLOR_INSTANCE_X_COLOR (c); + write_fmt_string (printcharfun, " %ld=(%X,%X,%X)", + color.pixel, color.red, color.green, color.blue); +} + +static void +x_finalize_color_instance (Lisp_Color_Instance *c) +{ + if (c->data) + { + if (DEVICE_LIVE_P (XDEVICE (c->device))) + { + if (COLOR_INSTANCE_X_DEALLOC (c)) + { + XFreeColors (DEVICE_X_DISPLAY (XDEVICE (c->device)), + DEVICE_X_COLORMAP (XDEVICE (c->device)), + &COLOR_INSTANCE_X_COLOR (c).pixel, 1, 0); + } + } + xfree (c->data); + c->data = 0; + } +} + +/* Color instances are equal if they resolve to the same color on the + screen (have the same RGB values). I imagine that + "same RGB values" == "same cell in the colormap." Arguably we should + be comparing their names or pixel values instead. */ + +static int +x_color_instance_equal (Lisp_Color_Instance *c1, + Lisp_Color_Instance *c2, + int UNUSED (depth)) +{ + XColor color1 = COLOR_INSTANCE_X_COLOR (c1); + XColor color2 = COLOR_INSTANCE_X_COLOR (c2); + return ((color1.red == color2.red) && + (color1.green == color2.green) && + (color1.blue == color2.blue)); +} + +static Hashcode +x_color_instance_hash (Lisp_Color_Instance *c, int UNUSED (depth)) +{ + XColor color = COLOR_INSTANCE_X_COLOR (c); + return HASH3 (color.red, color.green, color.blue); +} + +static Lisp_Object +x_color_instance_rgb_components (Lisp_Color_Instance *c) +{ + XColor color = COLOR_INSTANCE_X_COLOR (c); + return (list3 (make_int (color.red), + make_int (color.green), + make_int (color.blue))); +} + +static int +x_valid_color_name_p (struct device *d, Lisp_Object color) +{ + XColor c; + Display *dpy = DEVICE_X_DISPLAY (d); + Colormap cmap = DEVICE_X_COLORMAP (d); + const Extbyte *extname; + + extname = LISP_STRING_TO_EXTERNAL (color, Qx_color_name_encoding); + + return XParseColor (dpy, cmap, extname, &c); +} + +static Lisp_Object +x_color_list (void) +{ + return call0 (intern ("x-color-list-internal")); +} + + +/************************************************************************/ +/* font instances */ +/************************************************************************/ + + +static int +x_initialize_font_instance (Lisp_Font_Instance *f, Lisp_Object UNUSED (name), + Lisp_Object device, Error_Behavior errb) +{ + Display *dpy = DEVICE_X_DISPLAY (XDEVICE (device)); + Extbyte *extname; + XFontStruct *fs = NULL; /* _F_ont _S_truct */ +#ifdef HAVE_XFT + XftFont *rf = NULL; /* _R_ender _F_ont (X Render extension) */ +#else +#define rf (0) +#endif + +#ifdef HAVE_XFT + DEBUG_XFT1 (2, "attempting to initialize font spec %s\n", + XSTRING_DATA(f->name)); + /* #### serialize (optimize) these later... */ + /* #### This function really needs to go away. + The problem is that the fontconfig/Xft functions work much too hard + to ensure that something is returned; but that something need not be + at all close to what we asked for. */ + extname = LISP_STRING_TO_EXTERNAL (f->name, Qfc_font_name_encoding); + rf = xft_open_font_by_name (dpy, extname); +#endif + extname = LISP_STRING_TO_EXTERNAL (f->name, Qx_font_name_encoding); + /* With XFree86 4.0's fonts, XListFonts returns an entry for + -isas-fangsong ti-medium-r-normal--16-160-72-72-c-160-gb2312.1980-0 but + an XLoadQueryFont on the corresponding XLFD returns NULL. + + XListFonts is not trustworthy (of course, this is news to exactly + no-one used to reading XEmacs source.) */ + fs = XLoadQueryFont (dpy, extname); + + if (!fs && !rf) + { + /* #### should this refer to X and/or Xft? */ + maybe_signal_error (Qgui_error, "Couldn't load font", f->name, + Qfont, errb); + return 0; + } + + if (rf && fs) + { + XFreeFont (dpy, fs); + fs = NULL; /* we don' need no steenkin' X font */ + } + + if (fs && !fs->max_bounds.width) + { + /* yes, this has been known to happen. */ + XFreeFont (dpy, fs); + fs = NULL; + maybe_signal_error (Qgui_error, "X font is too small", f->name, Qfont, + errb); + return 0; + } + + /* Now that we're sure that we will succeed, we can allocate data without + fear that the finalize method may get fucked. */ + f->data = xnew (struct x_font_instance_data); + +#ifdef HAVE_XFT + FONT_INSTANCE_X_XFTFONT (f) = rf; + if (rf) + /* Have an Xft font, initialize font info from it. */ + { + DEBUG_XFT4 (2, "pre-initial ascent %d descent %d width %d height %d\n", + f->ascent, f->descent, f->width, f->height); + + /* #### This shit is just plain wrong unless we have a character cell + font. It really hoses us on large repertoire Unicode fonts with + "double-width" characters. */ + f->ascent = rf->ascent; + f->descent = rf->descent; + { + /* This is an approximation that AFAIK only gets used to compute + cell size for estimating window dimensions. The test_string8 + is an ASCII string whose characters should approximate the + distribution of widths expected in real text. */ + static const FcChar8 test_string8[] = "Mmneei"; + static const int len = sizeof (test_string8) - 1; + XGlyphInfo glyphinfo; + + XftTextExtents8 (dpy, rf, test_string8, len, &glyphinfo); + /* #### maybe should be glyphinfo.xOff - glyphinfo.x? */ + f->width = (2*glyphinfo.width + len)/(2*len); + } + f->height = rf->height; + f->proportional_p = 1; /* we can't recognize monospaced fonts! */ + + /* #### This message appears wa-a-ay too often! + We probably need to cache truenames or something? + Even if Xft does it for us, we cons too many font instances. */ + DEBUG_XFT4 (0, + "initialized metrics ascent %d descent %d width %d height %d\n", + f->ascent, f->descent, f->width, f->height); + } + else + { + DEBUG_XFT1 (0, "couldn't initialize Xft font %s\n", + XSTRING_DATA(f->name)); + } +#endif + + FONT_INSTANCE_X_FONT (f) = fs; + if (fs) + /* Have to use a core font, initialize font info from it. */ + { + f->ascent = fs->ascent; + f->descent = fs->descent; + f->height = fs->ascent + fs->descent; + { + /* following change suggested by Ted Phelps <phelps@dstc.edu.au> */ + int def_char = 'n'; /*fs->default_char;*/ + int byte1, byte2; + + once_more: + byte1 = def_char >> 8; + byte2 = def_char & 0xFF; + + if (fs->per_char) + { + /* Old versions of the R5 font server have garbage (>63k) as + def_char. 'n' might not be a valid character. */ + if (byte1 < (int) fs->min_byte1 || + byte1 > (int) fs->max_byte1 || + byte2 < (int) fs->min_char_or_byte2 || + byte2 > (int) fs->max_char_or_byte2) + f->width = 0; + else + f->width = fs->per_char[(byte1 - fs->min_byte1) * + (fs->max_char_or_byte2 - + fs->min_char_or_byte2 + 1) + + (byte2 - fs->min_char_or_byte2)].width; + } + else + f->width = fs->max_bounds.width; + + /* Some fonts have a default char whose width is 0. This is no good. + If that's the case, first try 'n' as the default char, and if n has + 0 width too (unlikely) then just use the max width. */ + if (f->width == 0) + { + if (def_char == (int) fs->default_char) + f->width = fs->max_bounds.width; + else + { + def_char = fs->default_char; + goto once_more; + } + } + } + + /* If all characters don't exist then there could potentially be + 0-width characters lurking out there. Not setting this flag + trips an optimization that would make them appear to have width + to redisplay. This is bad. So we set it if not all characters + have the same width or if not all characters are defined. */ + /* #### This sucks. There is a measurable performance increase + when using proportional width fonts if this flag is not set. + Unfortunately so many of the fucking X fonts are not fully + defined that we could almost just get rid of this damn flag and + make it an assertion. */ + f->proportional_p = (fs->min_bounds.width != fs->max_bounds.width || + (x_handle_non_fully_specified_fonts && + !fs->all_chars_exist)); + } + +#ifdef HAVE_XFT + if (debug_xft > 0) + { + int n = 3, d = 5; + /* check for weirdness */ + if (n * f->height < d * f->width) + stderr_out ("font %s: width:height is %d:%d, larger than %d:%d\n", + XSTRING_DATA(f->name), f->width, f->height, n, d); + if (f->height <= 0 || f->width <= 0) + stderr_out ("bogus dimensions of font %s: width = %d, height = %d\n", + XSTRING_DATA(f->name), f->width, f->height); + stderr_out ("initialized font %s\n", XSTRING_DATA(f->name)); + } +#else +#undef rf +#endif + + return 1; +} + +static void +x_print_font_instance (Lisp_Font_Instance *f, + Lisp_Object printcharfun, + int UNUSED (escapeflag)) +{ + /* We should print information here about initial vs. final stages; we + can't rely on the device charset stage cache for that, + unfortunately. */ + if (FONT_INSTANCE_X_FONT (f)) + write_fmt_string (printcharfun, " font id: 0x%lx,", + (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); + +#ifdef HAVE_XFT + /* #### What should we do here? For now, print the address. */ + if (FONT_INSTANCE_X_XFTFONT (f)) + write_fmt_string (printcharfun, " xft font: 0x%lx", + (unsigned long) FONT_INSTANCE_X_XFTFONT (f)); +#endif +} + +static void +x_finalize_font_instance (Lisp_Font_Instance *f) +{ + +#ifdef HAVE_XFT + DEBUG_XFT1 (0, "finalizing %s\n", (STRINGP (f->name) + ? (char *) XSTRING_DATA (f->name) + : "(unnamed font)")); +#endif + + if (f->data) + { + if (DEVICE_LIVE_P (XDEVICE (f->device))) + { + Display *dpy = DEVICE_X_DISPLAY (XDEVICE (f->device)); + + if (FONT_INSTANCE_X_FONT (f)) + XFreeFont (dpy, FONT_INSTANCE_X_FONT (f)); +#ifdef HAVE_XFT + if (FONT_INSTANCE_X_XFTFONT (f)) + XftFontClose (dpy, FONT_INSTANCE_X_XFTFONT (f)); +#endif + } + xfree (f->data); + f->data = 0; + } +} + +/* Determining the truename of a font is hard. (Big surprise.) + + This is not true for fontconfig. Each font has a (nearly) canonical + representation up to permutation of the order of properties. It is + possible to construct a name which exactly identifies the properties of + the current font. However, it is theoretically possible that there exists + another font with a super set of those properties that would happen to get + selected. -- sjt + + By "truename" we mean an XLFD-form name which contains no wildcards, yet + which resolves to *exactly* the same font as the one which we already have + the (probably wildcarded) name and `XFontStruct' of. + + One might think that the first font returned by XListFonts would be the one + that XOpenFont would pick. Apparently this is the case on some servers, + but not on others. It would seem not to be specified. + + The MIT R5 server sometimes appears to be picking the lexicographically + smallest font which matches the name (thus picking "adobe" fonts before + "bitstream" fonts even if the bitstream fonts are earlier in the path, and + also picking 100dpi adobe fonts over 75dpi adobe fonts even though the + 75dpi are in the path earlier) but sometimes appears to be doing something + else entirely (for example, removing the bitstream fonts from the path will + cause the 75dpi adobe fonts to be used instead of the 100dpi, even though + their relative positions in the path (and their names!) have not changed). + + The documentation for XSetFontPath() seems to indicate that the order of + entries in the font path means something, but it's pretty noncommittal about + it, and the spirit of the law is apparently not being obeyed... + + All the fonts I've seen have a property named `FONT' which contains the + truename of the font. However, there are two problems with using this: the + first is that the X Protocol Document is quite explicit that all properties + are optional, so we can't depend on it being there. The second is that + it's conceivable that this alleged truename isn't actually accessible as a + font, due to some difference of opinion between the font designers and + whoever installed the font on the system. + + So, our first attempt is to look for a FONT property, and then verify that + the name there is a valid name by running XListFonts on it. There's still + the potential that this could be true but we could still be being lied to, + but that seems pretty remote. + + Late breaking news: I've gotten reports that SunOS 4.1.3U1 + with OpenWound 3.0 has a font whose truename is really + "-Adobe-Courier-Medium-R-Normal--12-120-75-75-M-70-ISO8859-1" + but whose FONT property contains "Courier". + + So we disbelieve the FONT property unless it begins with a dash and + is more than 30 characters long. X Windows: The defacto substandard. + X Windows: Complex nonsolutions to simple nonproblems. X Windows: + Live the nightmare. + + If the FONT property doesn't exist, then we try and construct an XLFD name + out of the other font properties (FOUNDRY, FAMILY_NAME, WEIGHT_NAME, etc). + This is necessary at least for some versions of OpenWound. But who knows + what the future will bring. + + If that doesn't work, then we use XListFonts and either take the first font + (which I think is the most sensible thing) or we find the lexicographically + least, depending on whether the preprocessor constant `XOPENFONT_SORTS' is + defined. This sucks because the two behaviors are a property of the server + being used, not the architecture on which emacs has been compiled. Also, + as I described above, sorting isn't ALWAYS what the server does. Really it + does something seemingly random. There is no reliable way to win if the + FONT property isn't present. + + Another possibility which I haven't bothered to implement would be to map + over all of the matching fonts and find the first one that has the same + character metrics as the font we already have loaded. Even if this didn't + return exactly the same font, it would at least return one whose characters + were the same sizes, which would probably be good enough. + + More late-breaking news: on RS/6000 AIX 3.2.4, the expression + XLoadQueryFont (dpy, "-*-Fixed-Medium-R-*-*-*-130-75-75-*-*-ISO8859-1") + actually returns the font + -Misc-Fixed-Medium-R-Normal--13-120-75-75-C-80-ISO8859-1 + which is crazy, because that font doesn't even match that pattern! It is + also not included in the output produced by `xlsfonts' with that pattern. + + So this is yet another example of XListFonts() and XOpenFont() using + completely different algorithms. This, however, is a goofier example of + this bug, because in this case, it's not just the search order that is + different -- the sets don't even intersect. + + If anyone has any better ideas how to do this, or any insights on what it is + that the various servers are actually doing, please let me know! -- jwz. */ + +static int +valid_x_font_name_p (Display *dpy, Extbyte *name) +{ + /* Maybe this should be implemented by calling XLoadFont and trapping + the error. That would be a lot of work, and wasteful as hell, but + might be more correct. + */ + int nnames = 0; + Extbyte **names = 0; + if (! name) + return 0; + names = XListFonts (dpy, name, 1, &nnames); + if (names) + XFreeFontNames (names); + return (nnames != 0); +} + +static Extbyte * +truename_via_FONT_prop (Display *dpy, XFontStruct *font) +{ + unsigned long value = 0; + Extbyte *result = 0; + if (XGetFontProperty (font, XA_FONT, &value)) + result = XGetAtomName (dpy, value); + /* result is now 0, or the string value of the FONT property. */ + if (result) + { + /* Verify that result is an XLFD name (roughly...) */ + if (result [0] != '-' || strlen (result) < 30) + { + XFree (result); + result = 0; + } + } + return result; /* this must be freed by caller if non-0 */ +} + +static Extbyte * +truename_via_random_props (Display *dpy, XFontStruct *font) +{ + struct device *d = get_device_from_display (dpy); + unsigned long value = 0; + Extbyte *foundry, *family, *weight, *slant, *setwidth, *add_style; + unsigned long pixel, point, res_x, res_y; + Extbyte *spacing; + unsigned long avg_width; + Extbyte *registry, *encoding; + Extbyte composed_name [2048]; + int ok = 0; + Extbyte *result; + +#define get_string(atom,var) \ + if (XGetFontProperty (font, (atom), &value)) \ + var = XGetAtomName (dpy, value); \ + else { \ + var = 0; \ + goto FAIL; } +#define get_number(atom,var) \ + if (!XGetFontProperty (font, (atom), &var) || \ + var > 999) \ + goto FAIL; + + foundry = family = weight = slant = setwidth = 0; + add_style = spacing = registry = encoding = 0; + + get_string (DEVICE_XATOM_FOUNDRY (d), foundry); + get_string (DEVICE_XATOM_FAMILY_NAME (d), family); + get_string (DEVICE_XATOM_WEIGHT_NAME (d), weight); + get_string (DEVICE_XATOM_SLANT (d), slant); + get_string (DEVICE_XATOM_SETWIDTH_NAME (d), setwidth); + get_string (DEVICE_XATOM_ADD_STYLE_NAME (d), add_style); + get_number (DEVICE_XATOM_PIXEL_SIZE (d), pixel); + get_number (DEVICE_XATOM_POINT_SIZE (d), point); + get_number (DEVICE_XATOM_RESOLUTION_X (d), res_x); + get_number (DEVICE_XATOM_RESOLUTION_Y (d), res_y); + get_string (DEVICE_XATOM_SPACING (d), spacing); + get_number (DEVICE_XATOM_AVERAGE_WIDTH (d), avg_width); + get_string (DEVICE_XATOM_CHARSET_REGISTRY (d), registry); + get_string (DEVICE_XATOM_CHARSET_ENCODING (d), encoding); +#undef get_number +#undef get_string + + sprintf (composed_name, + "-%s-%s-%s-%s-%s-%s-%ld-%ld-%ld-%ld-%s-%ld-%s-%s", + foundry, family, weight, slant, setwidth, add_style, pixel, + point, res_x, res_y, spacing, avg_width, registry, encoding); + ok = 1; + + FAIL: + if (ok) + { + int L = strlen (composed_name) + 1; + result = xnew_extbytes (L); + strncpy (result, composed_name, L); + } + else + result = 0; + + if (foundry) XFree (foundry); + if (family) XFree (family); + if (weight) XFree (weight); + if (slant) XFree (slant); + if (setwidth) XFree (setwidth); + if (add_style) XFree (add_style); + if (spacing) XFree (spacing); + if (registry) XFree (registry); + if (encoding) XFree (encoding); + + return result; +} + +/* XListFonts doesn't allocate memory unconditionally based on this. (For + XFree86 in 2005, at least. */ +#define MAX_FONT_COUNT INT_MAX + +static Extbyte * +truename_via_XListFonts (Display *dpy, Extbyte *font_name) +{ + Extbyte *result = 0; + Extbyte **names; + int count = 0; + +#ifndef XOPENFONT_SORTS + /* In a sensible world, the first font returned by XListFonts() + would be the font that XOpenFont() would use. */ + names = XListFonts (dpy, font_name, 1, &count); + if (count) result = names [0]; +#else + /* But the world I live in is much more perverse. */ + names = XListFonts (dpy, font_name, MAX_FONT_COUNT, &count); + /* Find the lexicographic minimum of names[]. + (#### Should we be comparing case-insensitively?) */ + while (count--) + /* [[ !!#### Not Mule-friendly ]] + Doesn't matter, XLFDs are HPC (old) or Latin1 (modern). If they + aren't, who knows what they are? -- sjt */ + if (result == 0 || (strcmp (result, names [count]) < 0)) + result = names [count]; +#endif + + if (result) + result = xstrdup (result); + if (names) + XFreeFontNames (names); + + return result; /* this must be freed by caller if non-0 */ +} + +static Lisp_Object +x_font_truename (Display *dpy, Extbyte *name, XFontStruct *font) +{ + Extbyte *truename_FONT = 0; + Extbyte *truename_random = 0; + Extbyte *truename = 0; + + /* The search order is: + - if FONT property exists, and is a valid name, return it. + - if the other props exist, and add up to a valid name, return it. + - if we find a matching name with XListFonts, return it. + - if FONT property exists, return it regardless. + - if other props exist, return the resultant name regardless. + - else return 0. + */ + + truename = truename_FONT = truename_via_FONT_prop (dpy, font); + if (truename && !valid_x_font_name_p (dpy, truename)) + truename = 0; + if (!truename) + truename = truename_random = truename_via_random_props (dpy, font); + if (truename && !valid_x_font_name_p (dpy, truename)) + truename = 0; + if (!truename && name) + truename = truename_via_XListFonts (dpy, name); + + if (!truename) + { + /* Gag - we weren't able to find a seemingly-valid truename. + Well, maybe we're on one of those braindead systems where + XListFonts() and XLoadFont() are in violent disagreement. + If we were able to compute a truename, try using that even + if evidence suggests that it's not a valid name - because + maybe it is, really, and that's better than nothing. + X Windows: You'll envy the dead. + */ + if (truename_FONT) + truename = truename_FONT; + else if (truename_random) + truename = truename_random; + } + + /* One or both of these are not being used - free them. */ + if (truename_FONT && truename_FONT != truename) + XFree (truename_FONT); + if (truename_random && truename_random != truename) + XFree (truename_random); + + if (truename) + { + Lisp_Object result = build_extstring (truename, Qx_font_name_encoding); + XFree (truename); + return result; + } + else + return Qnil; +} + +static Lisp_Object +x_font_instance_truename (Lisp_Font_Instance *f, Error_Behavior errb) +{ + struct device *d = XDEVICE (f->device); + Display *dpy = DEVICE_X_DISPLAY (d); + Extbyte *nameext; + + /* #### restructure this so that we return a valid truename at the end, + and otherwise only return when we return something desperate that + doesn't get stored for future use. */ + +#ifdef HAVE_XFT + /* First, try an Xft font. */ + if (NILP (FONT_INSTANCE_TRUENAME (f)) && FONT_INSTANCE_X_XFTFONT (f)) + { + /* The font is already open, we just unparse. */ + FcChar8 *res = FcNameUnparse (FONT_INSTANCE_X_XFTFONT (f)->pattern); + if (! FONT_INSTANCE_X_XFTFONT (f)->pattern) + { + maybe_signal_error (Qgui_error, + "Xft font present but lacks pattern", + wrap_font_instance(f), Qfont, errb); + } + if (res) + { + FONT_INSTANCE_TRUENAME (f) = + build_extstring ((Extbyte *) res, Qfc_font_name_encoding); + free (res); + return FONT_INSTANCE_TRUENAME (f); + } + else + { + maybe_signal_error (Qgui_error, + "Couldn't unparse Xft font to truename", + wrap_font_instance(f), Qfont, errb); + /* used to return Qnil here */ + } + } +#endif /* HAVE_XFT */ + + /* OK, fall back to core font. */ + if (NILP (FONT_INSTANCE_TRUENAME (f)) + && FONT_INSTANCE_X_FONT (f)) + { + nameext = LISP_STRING_TO_EXTERNAL (f->name, Qx_font_name_encoding); + FONT_INSTANCE_TRUENAME (f) = + x_font_truename (dpy, nameext, FONT_INSTANCE_X_FONT (f)); + } + + if (NILP (FONT_INSTANCE_TRUENAME (f))) + { + /* Urk, no luck. Whine about our bad luck and exit. */ + Lisp_Object font_instance = wrap_font_instance (f); + + + maybe_signal_error (Qgui_error, "Couldn't determine font truename", + font_instance, Qfont, errb); + /* Ok, just this once, return the font name as the truename. + (This is only used by Fequal() right now.) */ + return f->name; + } + + /* Return what we found. */ + return FONT_INSTANCE_TRUENAME (f); +} + +static Lisp_Object +x_font_instance_properties (Lisp_Font_Instance *f) +{ + struct device *d = XDEVICE (f->device); + int i; + Lisp_Object result = Qnil; + Display *dpy = DEVICE_X_DISPLAY (d); + XFontProp *props = NULL; + + /* #### really should hack Xft fonts, too + Strategy: fontconfig must have an iterator for this purpose. */ + if (! FONT_INSTANCE_X_FONT (f)) return result; + + props = FONT_INSTANCE_X_FONT (f)->properties; + for (i = FONT_INSTANCE_X_FONT (f)->n_properties - 1; i >= 0; i--) + { + Lisp_Object name, value; + Atom atom = props [i].name; + Ibyte *name_str = 0; + Bytecount name_len; + Extbyte *namestrext = XGetAtomName (dpy, atom); + + if (namestrext) + TO_INTERNAL_FORMAT (C_STRING, namestrext, + ALLOCA, (name_str, name_len), + Qx_atom_name_encoding); + + name = (name_str ? intern_istring (name_str) : Qnil); + if (name_str && + (atom == XA_FONT || + atom == DEVICE_XATOM_FOUNDRY (d) || + atom == DEVICE_XATOM_FAMILY_NAME (d) || + atom == DEVICE_XATOM_WEIGHT_NAME (d) || + atom == DEVICE_XATOM_SLANT (d) || + atom == DEVICE_XATOM_SETWIDTH_NAME (d) || + atom == DEVICE_XATOM_ADD_STYLE_NAME (d) || + atom == DEVICE_XATOM_SPACING (d) || + atom == DEVICE_XATOM_CHARSET_REGISTRY (d) || + atom == DEVICE_XATOM_CHARSET_ENCODING (d) || + !qxestrcmp_ascii (name_str, "CHARSET_COLLECTIONS") || + !qxestrcmp_ascii (name_str, "FONTNAME_REGISTRY") || + !qxestrcmp_ascii (name_str, "CLASSIFICATION") || + !qxestrcmp_ascii (name_str, "COPYRIGHT") || + !qxestrcmp_ascii (name_str, "DEVICE_FONT_NAME") || + !qxestrcmp_ascii (name_str, "FULL_NAME") || + !qxestrcmp_ascii (name_str, "MONOSPACED") || + !qxestrcmp_ascii (name_str, "QUALITY") || + !qxestrcmp_ascii (name_str, "RELATIVE_SET") || + !qxestrcmp_ascii (name_str, "RELATIVE_WEIGHT") || + !qxestrcmp_ascii (name_str, "STYLE"))) + { + Extbyte *val_str = XGetAtomName (dpy, props [i].card32); + + value = (val_str ? build_extstring (val_str, Qx_atom_name_encoding) + : Qnil); + } + else + value = make_int (props [i].card32); + if (namestrext) XFree (namestrext); + result = Fcons (Fcons (name, value), result); + } + return result; +} + +static Lisp_Object +x_font_list (Lisp_Object pattern, Lisp_Object device, Lisp_Object maxnumber) +{ + Extbyte **names; + int count = 0; + int max_number = MAX_FONT_COUNT; + Lisp_Object result = Qnil; + const Extbyte *patternext; + + patternext = LISP_STRING_TO_EXTERNAL (pattern, Qx_font_name_encoding); + + if (!NILP(maxnumber) && INTP(maxnumber)) + { + max_number = XINT(maxnumber); + } + + names = XListFonts (DEVICE_X_DISPLAY (XDEVICE (device)), + patternext, max_number, &count); + while (count--) + result = Fcons (build_extstring (names[count], Qx_font_name_encoding), + result); + if (names) + XFreeFontNames (names); + return result; +} + +/* Include the charset support, shared, for the moment, with GTK. */ +#define THIS_IS_X +#include "fontcolor-xlike-inc.c" + + +/************************************************************************/ +/* initialization */ +/************************************************************************/ + +void +syms_of_fontcolor_x (void) +{ +} + +void +console_type_create_fontcolor_x (void) +{ + /* object methods */ + + CONSOLE_HAS_METHOD (x, initialize_color_instance); + CONSOLE_HAS_METHOD (x, print_color_instance); + CONSOLE_HAS_METHOD (x, finalize_color_instance); + CONSOLE_HAS_METHOD (x, color_instance_equal); + CONSOLE_HAS_METHOD (x, color_instance_hash); + CONSOLE_HAS_METHOD (x, color_instance_rgb_components); + CONSOLE_HAS_METHOD (x, valid_color_name_p); + CONSOLE_HAS_METHOD (x, color_list); + + CONSOLE_HAS_METHOD (x, initialize_font_instance); + CONSOLE_HAS_METHOD (x, print_font_instance); + CONSOLE_HAS_METHOD (x, finalize_font_instance); + CONSOLE_HAS_METHOD (x, font_instance_truename); + CONSOLE_HAS_METHOD (x, font_instance_properties); + CONSOLE_HAS_METHOD (x, font_list); +#ifdef MULE + CONSOLE_HAS_METHOD (x, find_charset_font); + CONSOLE_HAS_METHOD (x, font_spec_matches_charset); +#endif +} + +void +vars_of_fontcolor_x (void) +{ +#ifdef DEBUG_XEMACS + DEFVAR_INT ("debug-x-objects", &debug_x_objects /* +If non-zero, display debug information about X objects +*/ ); + debug_x_objects = 0; +#endif + + DEFVAR_BOOL ("x-handle-non-fully-specified-fonts", + &x_handle_non_fully_specified_fonts /* +If this is true then fonts which do not have all characters specified +will be considered to be proportional width even if they are actually +fixed-width. If this is not done then characters which are supposed to +have 0 width may appear to actually have some width. + +Note: While setting this to t guarantees correct output in all +circumstances, it also causes a noticeable performance hit when using +fixed-width fonts. Since most people don't use characters which could +cause problems this is set to nil by default. +*/ ); + x_handle_non_fully_specified_fonts = 0; + +#ifdef HAVE_XFT + Fprovide (intern ("xft-fonts")); +#endif +} + +void +Xatoms_of_fontcolor_x (struct device *d) +{ + Display *D = DEVICE_X_DISPLAY (d); + + DEVICE_XATOM_FOUNDRY (d) = XInternAtom (D, "FOUNDRY", False); + DEVICE_XATOM_FAMILY_NAME (d) = XInternAtom (D, "FAMILY_NAME", False); + DEVICE_XATOM_WEIGHT_NAME (d) = XInternAtom (D, "WEIGHT_NAME", False); + DEVICE_XATOM_SLANT (d) = XInternAtom (D, "SLANT", False); + DEVICE_XATOM_SETWIDTH_NAME (d) = XInternAtom (D, "SETWIDTH_NAME", False); + DEVICE_XATOM_ADD_STYLE_NAME (d) = XInternAtom (D, "ADD_STYLE_NAME", False); + DEVICE_XATOM_PIXEL_SIZE (d) = XInternAtom (D, "PIXEL_SIZE", False); + DEVICE_XATOM_POINT_SIZE (d) = XInternAtom (D, "POINT_SIZE", False); + DEVICE_XATOM_RESOLUTION_X (d) = XInternAtom (D, "RESOLUTION_X", False); + DEVICE_XATOM_RESOLUTION_Y (d) = XInternAtom (D, "RESOLUTION_Y", False); + DEVICE_XATOM_SPACING (d) = XInternAtom (D, "SPACING", False); + DEVICE_XATOM_AVERAGE_WIDTH (d) = XInternAtom (D, "AVERAGE_WIDTH", False); + DEVICE_XATOM_CHARSET_REGISTRY(d) = XInternAtom (D, "CHARSET_REGISTRY",False); + DEVICE_XATOM_CHARSET_ENCODING(d) = XInternAtom (D, "CHARSET_ENCODING",False); +}