Mercurial > hg > xemacs-beta
view src/objects-xlike-inc.c @ 2586:196ee3cd1ac5
[xemacs-hg @ 2005-02-15 01:19:48 by ben]
first check-in of ben-fixup branch
author | ben |
---|---|
date | Tue, 15 Feb 2005 01:21:24 +0000 |
parents | |
children |
line wrap: on
line source
/* Include file for common code, X and GTK colors and fonts. 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, 2003, 2004, 2005 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 */ /* Extracted from objects-x.c, objects-gtk.c 2-13-05. NOTE: There is an advantage to having the code coalesced this way even when there is a fair amount of difference between the two versions, provided that they are still parallel -- having them side by side ensures that logic changes in one are propagated to the other, preventing bit-rot --ben */ #ifndef THIS_IS_GTK #define ZZCOLOR_TYPE XColor #define ZZCOLOR_INSTANCE(name) COLOR_INSTANCE_X_##name #define ZZ(z) x_##z #define ZZEND(z) z##_x #define ZZCONSOLE_HAS_METHOD(name) CONSOLE_HAS_METHOD (x, name) #define UNUSED_IF_GTK(arg) arg #else #define ZZCOLOR_TYPE GdkColor #define ZZCOLOR_INSTANCE(name) COLOR_INSTANCE_GTK_##name #define ZZ(z) gtk_##z #define ZZEND(z) z##_gtk #define ZZCONSOLE_HAS_METHOD(name) CONSOLE_HAS_METHOD (gtk, name) #define UNUSED_IF_GTK(arg) UNUSED (arg) #endif /************************************************************************/ /* color instances */ /************************************************************************/ static int ZZ (parse_nearest_color) (struct device *d, ZZCOLOR_TYPE *color, Lisp_Object name, Error_Behavior errb) { #ifndef THIS_IS_GTK Display *dpy = DEVICE_X_DISPLAY (d); Colormap cmap = DEVICE_X_COLORMAP (d); Visual *visual = DEVICE_X_VISUAL (d); #else /* THIS_IS_GTK */ GdkColormap *cmap = DEVICE_GTK_COLORMAP (d); GdkVisual *visual = DEVICE_GTK_VISUAL (d); #endif /* THIS_IS_GTK */ int result; xzero (*color); #ifndef THIS_IS_GTK result = XParseColor (dpy, cmap, NEW_LISP_STRING_TO_EXTERNAL (name, Qx_color_name_encoding), color); #else /* THIS_IS_GTK */ result = gdk_color_parse (LISP_STRING_TO_GTK_TEXT (name), color); #endif /* THIS_IS_GTK */ if (!result) { maybe_signal_error (Qgui_error, "Unrecognized color", name, Qcolor, errb); return 0; } #ifndef THIS_IS_GTK result = ZZ (allocate_nearest_color) (dpy, cmap, visual, color); #else /* THIS_IS_GTK */ result = ZZ (allocate_nearest_color) (cmap, visual, color); #endif /* THIS_IS_GTK */ if (!result) { maybe_signal_error (Qgui_error, "Couldn't allocate color", name, Qcolor, errb); return 0; } return result; } static int ZZ (initialize_color_instance) (Lisp_Color_Instance *c, Lisp_Object name, Lisp_Object device, Error_Behavior errb) { ZZCOLOR_TYPE color; int result; result = ZZ (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 ZZ (color_instance_data)); if (result == 3) ZZCOLOR_INSTANCE (DEALLOC) (c) = 0; else ZZCOLOR_INSTANCE (DEALLOC) (c) = 1; #ifndef THIS_IS_GTK ZZCOLOR_INSTANCE (COLOR) (c) = color; #else /* THIS_IS_GTK */ ZZCOLOR_INSTANCE (COLOR) (c) = gdk_color_copy (&color); #endif /* THIS_IS_GTK */ return 1; } static void ZZ (print_color_instance) (Lisp_Color_Instance *c, Lisp_Object printcharfun, int UNUSED (escapeflag)) { #ifndef THIS_IS_GTK XColor color = COLOR_INSTANCE_X_COLOR (c); write_fmt_string (printcharfun, " %ld=(%X,%X,%X)", color.pixel, color.red, color.green, color.blue); #else /* THIS_IS_GTK */ GdkColor *color = COLOR_INSTANCE_GTK_COLOR (c); write_fmt_string (printcharfun, " %ld=(%X,%X,%X)", color->pixel, color->red, color->green, color->blue); #endif /* THIS_IS_GTK */ } static void ZZ (finalize_color_instance) (Lisp_Color_Instance *c) { if (c->data) { if (DEVICE_LIVE_P (XDEVICE (c->device))) { if (ZZCOLOR_INSTANCE (DEALLOC) (c)) { #ifndef THIS_IS_GTK XFreeColors (DEVICE_X_DISPLAY (XDEVICE (c->device)), DEVICE_X_COLORMAP (XDEVICE (c->device)), &COLOR_INSTANCE_X_COLOR (c).pixel, 1, 0); #else /* THIS_IS_GTK */ gdk_colormap_free_colors (DEVICE_GTK_COLORMAP (XDEVICE (c->device)), COLOR_INSTANCE_GTK_COLOR (c), 1); #endif /* THIS_IS_GTK */ } #ifdef THIS_IS_GTK gdk_color_free (COLOR_INSTANCE_GTK_COLOR (c)); #endif /* THIS_IS_GTK */ } xfree (c->data, void *); 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 ZZ (color_instance_equal) (Lisp_Color_Instance *c1, Lisp_Color_Instance *c2, int UNUSED (depth)) { #ifndef THIS_IS_GTK 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)); #else /* THIS_IS_GTK */ return (gdk_color_equal (COLOR_INSTANCE_GTK_COLOR (c1), COLOR_INSTANCE_GTK_COLOR (c2))); #endif /* THIS_IS_GTK */ } static Hashcode ZZ (color_instance_hash) (Lisp_Color_Instance *c, int UNUSED (depth)) { #ifndef THIS_IS_GTK XColor color = COLOR_INSTANCE_X_COLOR (c); return HASH3 (color.red, color.green, color.blue); #else /* THIS_IS_GTK */ return (gdk_color_hash (COLOR_INSTANCE_GTK_COLOR (c), NULL)); #endif /* THIS_IS_GTK */ } static Lisp_Object ZZ (color_instance_rgb_components) (Lisp_Color_Instance *c) { #ifndef THIS_IS_GTK XColor color = COLOR_INSTANCE_X_COLOR (c); return (list3 (make_int (color.red), make_int (color.green), make_int (color.blue))); #else /* THIS_IS_GTK */ GdkColor *color = COLOR_INSTANCE_GTK_COLOR (c); return (list3 (make_int (color->red), make_int (color->green), make_int (color->blue))); #endif /* THIS_IS_GTK */ } static int ZZ (valid_color_name_p) (struct device *UNUSED_IF_GTK (d), Lisp_Object color) { #ifndef THIS_IS_GTK XColor c; Display *dpy = DEVICE_X_DISPLAY (d); Colormap cmap = DEVICE_X_COLORMAP (d); const Extbyte *extname; LISP_STRING_TO_EXTERNAL (color, extname, Qx_color_name_encoding); return XParseColor (dpy, cmap, extname, &c); #else /* THIS_IS_GTK */ GdkColor c; const Extbyte *extname; LISP_STRING_TO_EXTERNAL (color, extname, Vgtk_text_encoding); if (gdk_color_parse (extname, &c) != TRUE) return 0; return 1; #endif /* THIS_IS_GTK */ } static Lisp_Object ZZ (color_list) (void) { #ifdef THIS_IS_GTK /* #### BILL!!! Is this correct? */ #endif /* THIS_IS_GTK */ return call0 (intern ("x-color-list-internal")); } /************************************************************************/ /* font instances */ /************************************************************************/ static int ZZ (initialize_font_instance) (Lisp_Font_Instance *f, Lisp_Object UNUSED (name), Lisp_Object UNUSED_IF_GTK (device), Error_Behavior errb) { XFontStruct *xf; const Extbyte *extname; #ifndef THIS_IS_GTK Display *dpy = DEVICE_X_DISPLAY (XDEVICE (device)); LISP_STRING_TO_EXTERNAL (f->name, extname, Qx_font_name_encoding); xf = XLoadQueryFont (dpy, extname); if (!xf) { maybe_signal_error (Qgui_error, "Couldn't load font", f->name, Qfont, errb); return 0; } if (!xf->max_bounds.width) { /* yes, this has been known to happen. */ XFreeFont (dpy, xf); maybe_signal_error (Qgui_error, "X font is too small", f->name, Qfont, errb); return 0; } #else /* THIS_IS_GTK */ GdkFont *gf; LISP_STRING_TO_EXTERNAL (f->name, extname, Vgtk_text_encoding); gf = gdk_font_load (extname); if (!gf) { maybe_signal_error (Qgui_error, "Couldn't load font", f->name, Qfont, errb); return 0; } xf = (XFontStruct *) GDK_FONT_XFONT (gf); #endif /* THIS_IS_GTK */ /* Don't allocate the data until we're sure that we will succeed, or the finalize method may get fucked. */ #ifndef THIS_IS_GTK f->data = xnew (struct x_font_instance_data); FONT_INSTANCE_X_FONT (f) = xf; f->ascent = xf->ascent; f->descent = xf->descent; f->height = xf->ascent + xf->descent; #else /* THIS_IS_GTK */ f->data = xnew (struct gtk_font_instance_data); FONT_INSTANCE_GTK_FONT (f) = gf; f->ascent = gf->ascent; f->descent = gf->descent; f->height = gf->ascent + gf->descent; #endif /* THIS_IS_GTK */ /* Now let's figure out the width of the font */ { /* following change suggested by Ted Phelps <phelps@dstc.edu.au> */ int def_char = 'n'; /*xf->default_char;*/ int byte1, byte2; once_more: byte1 = def_char >> 8; byte2 = def_char & 0xFF; if (xf->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) xf->min_byte1 || byte1 > (int) xf->max_byte1 || byte2 < (int) xf->min_char_or_byte2 || byte2 > (int) xf->max_char_or_byte2) f->width = 0; else f->width = xf->per_char[(byte1 - xf->min_byte1) * (xf->max_char_or_byte2 - xf->min_char_or_byte2 + 1) + (byte2 - xf->min_char_or_byte2)].width; } else f->width = xf->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) xf->default_char) f->width = xf->max_bounds.width; else { def_char = xf->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 = (xf->min_bounds.width != xf->max_bounds.width || ( #ifndef THIS_IS_GTK x_handle_non_fully_specified_fonts && #else /* THIS_IS_GTK */ /* x_handle_non_fully_specified_fonts */ 0 && #endif /* THIS_IS_GTK */ !xf->all_chars_exist)); #if 0 /* THIS_IS_GTK */ f->width = gdk_char_width (gf, 'n'); f->proportional_p = (gdk_char_width (gf, '|') != gdk_char_width (gf, 'W')); #endif return 1; } static void ZZ (print_font_instance) (Lisp_Font_Instance *f, Lisp_Object printcharfun, int UNUSED (escapeflag)) { write_fmt_string (printcharfun, " 0x%lx", #ifndef THIS_IS_GTK (unsigned long) FONT_INSTANCE_X_FONT (f)->fid); #else /* THIS_IS_GTK */ (unsigned long) gdk_font_id (FONT_INSTANCE_GTK_FONT (f))); #endif /* THIS_IS_GTK */ } static void ZZ (finalize_font_instance) (Lisp_Font_Instance *f) { if (f->data) { if (DEVICE_LIVE_P (XDEVICE (f->device))) { #ifndef THIS_IS_GTK XFreeFont (DEVICE_X_DISPLAY (XDEVICE (f->device)), FONT_INSTANCE_X_FONT (f)); #else /* THIS_IS_GTK */ gdk_font_unref (FONT_INSTANCE_GTK_FONT (f)); #endif /* THIS_IS_GTK */ } xfree (f->data, void *); f->data = 0; } } /* Unbounded, for sufficiently small values of infinity... */ #define MAX_FONT_COUNT 5000 #ifndef THIS_IS_GTK static Lisp_Object x_font_truename (Display *dpy, Extbyte *name, XFontStruct *font); #else Lisp_Object __get_gtk_font_truename (GdkFont *gdk_font, int expandp); #endif static Lisp_Object ZZ (font_instance_truename) (Lisp_Font_Instance *f, Error_Behavior errb) { if (NILP (FONT_INSTANCE_TRUENAME (f))) { #ifndef THIS_IS_GTK FONT_INSTANCE_TRUENAME (f) = x_font_truename (DEVICE_X_DISPLAY (XDEVICE (f->device)), NEW_LISP_STRING_TO_EXTERNAL (f->name, Qx_font_name_encoding), FONT_INSTANCE_X_FONT (f)); #else FONT_INSTANCE_TRUENAME (f) = __get_gtk_font_truename (FONT_INSTANCE_GTK_FONT (f), 1); #endif /* THIS_IS_GTK */ if (NILP (FONT_INSTANCE_TRUENAME (f))) { 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 FONT_INSTANCE_TRUENAME (f); } #ifdef MULE static int ZZ (font_spec_matches_charset) (struct device *UNUSED (d), Lisp_Object charset, const Ibyte *nonreloc, Lisp_Object reloc, Bytecount offset, Bytecount length, int stage) { if (stage) return 0; if (UNBOUNDP (charset)) return 1; /* Hack! Short font names don't have the registry in them, so we just assume the user knows what they're doing in the case of ASCII. For other charsets, you gotta give the long form; sorry buster. */ if (EQ (charset, Vcharset_ascii)) { const Ibyte *the_nonreloc = nonreloc; int i; Bytecount the_length = length; if (!the_nonreloc) the_nonreloc = XSTRING_DATA (reloc); fixup_internal_substring (nonreloc, reloc, offset, &the_length); the_nonreloc += offset; if (!memchr (the_nonreloc, '*', the_length)) { for (i = 0;; i++) { const Ibyte *new_nonreloc = (const Ibyte *) memchr (the_nonreloc, '-', the_length); if (!new_nonreloc) break; new_nonreloc++; the_length -= new_nonreloc - the_nonreloc; the_nonreloc = new_nonreloc; } /* If it has less than 5 dashes, it's a short font. Of course, long fonts always have 14 dashes or so, but short fonts never have more than 1 or 2 dashes, so this is some sort of reasonable heuristic. */ if (i < 5) return 1; } } return (fast_string_match (XCHARSET_REGISTRY (charset), nonreloc, reloc, offset, length, 1, ERROR_ME, 0) >= 0); } /* find a font spec that matches font spec FONT and also matches (the registry of) CHARSET. */ static Lisp_Object ZZ (find_charset_font) (Lisp_Object device, Lisp_Object font, Lisp_Object charset, int stage) { #ifdef THIS_IS_GTK /* #### copied from x_find_charset_font */ /* #### BILL!!! Try to make this go away eventually */ #endif /* THIS_IS_GTK */ Extbyte **names; int count = 0; Lisp_Object result = Qnil; const Extbyte *patternext; int i; if (stage) return Qnil; LISP_STRING_TO_EXTERNAL (font, patternext, Qx_font_name_encoding); names = XListFonts ( #ifndef THIS_IS_GTK DEVICE_X_DISPLAY (XDEVICE (device)), #else GDK_DISPLAY (), #endif patternext, MAX_FONT_COUNT, &count); /* #### This code seems awfully bogus -- mrb */ for (i = 0; i < count; i ++) { const Ibyte *intname; Bytecount intlen; EXTERNAL_TO_SIZED_C_STRING (names[i], intname, intlen, Qx_font_name_encoding); if (ZZ (font_spec_matches_charset) (XDEVICE (device), charset, intname, Qnil, 0, -1, stage)) { result = make_string (intname, intlen); break; } } if (names) XFreeFontNames (names); /* Check for a short font name. */ if (NILP (result) && ZZ (font_spec_matches_charset) (XDEVICE (device), charset, 0, font, 0, -1, stage)) return font; return result; } #endif /* MULE */ /************************************************************************/ /* initialization */ /************************************************************************/ void ZZEND (console_type_create_objects) (void) { /* object methods */ ZZCONSOLE_HAS_METHOD (initialize_color_instance); ZZCONSOLE_HAS_METHOD (print_color_instance); ZZCONSOLE_HAS_METHOD (finalize_color_instance); ZZCONSOLE_HAS_METHOD (color_instance_equal); ZZCONSOLE_HAS_METHOD (color_instance_hash); ZZCONSOLE_HAS_METHOD (color_instance_rgb_components); ZZCONSOLE_HAS_METHOD (valid_color_name_p); ZZCONSOLE_HAS_METHOD (color_list); ZZCONSOLE_HAS_METHOD (initialize_font_instance); ZZCONSOLE_HAS_METHOD (print_font_instance); ZZCONSOLE_HAS_METHOD (finalize_font_instance); ZZCONSOLE_HAS_METHOD (font_instance_truename); ZZCONSOLE_HAS_METHOD (font_instance_properties); ZZCONSOLE_HAS_METHOD (font_list); #ifdef MULE ZZCONSOLE_HAS_METHOD (find_charset_font); ZZCONSOLE_HAS_METHOD (font_spec_matches_charset); #endif }