Mercurial > hg > xemacs-beta
diff 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 diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/objects-xlike-inc.c Tue Feb 15 01:21:24 2005 +0000 @@ -0,0 +1,613 @@ +/* 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 +}