xfaces.c 182 KB
Newer Older
Gerd Moellmann's avatar
Gerd Moellmann committed
1 2
/* xfaces.c -- "Face" primitives.
   Copyright (C) 1993, 1994, 1998, 1999 Free Software Foundation.
Jim Blandy's avatar
Jim Blandy committed
3

Jim Blandy's avatar
Jim Blandy committed
4 5 6 7
This file is part of GNU Emacs.

GNU Emacs is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Jim Blandy's avatar
Jim Blandy committed
8
the Free Software Foundation; either version 2, or (at your option)
Jim Blandy's avatar
Jim Blandy committed
9 10 11 12 13 14 15 16 17
any later version.

GNU Emacs 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 GNU Emacs; see the file COPYING.  If not, write to
18 19
the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.  */
Jim Blandy's avatar
Jim Blandy committed
20

Gerd Moellmann's avatar
Gerd Moellmann committed
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
/* New face implementation by Gerd Moellmann <gerd@gnu.org>.  */

/* Faces.

   When using Emacs with X, the display style of characters can be
   changed by defining `faces'.  Each face can specify the following
   display attributes:

   1. Font family or fontset alias name.
   
   2. Relative proportionate width, aka character set width or set
   width (swidth), e.g. `semi-compressed'.
   
   3. Font height in 1/10pt
   
   4. Font weight, e.g. `bold'.
   
   5. Font slant, e.g. `italic'.
   
   6. Foreground color.
   
   7. Background color.

   8. Whether or not characters should be underlined, and in what color.

   9. Whether or not characters should be displayed in inverse video.

   10. A background stipple, a bitmap.

   11. Whether or not characters should be overlined, and in what color.

   12. Whether or not characters should be strike-through, and in what
   color.

   13. Whether or not a box should be drawn around characters, the box
   type, and, for simple boxes, in what color.

   Faces are frame-local by nature because Emacs allows to define the
   same named face (face names are symbols) differently for different
   frames.  Each frame has an alist of face definitions for all named
   faces.  The value of a named face in such an alist is a Lisp vector
   with the symbol `face' in slot 0, and a slot for each each of the
   face attributes mentioned above.

   There is also a global face alist `Vface_new_frame_defaults'.  Face
   definitions from this list are used to initialize faces of newly
   created frames.
   
   A face doesn't have to specify all attributes.  Those not specified
   have a value of `unspecified'.  Faces specifying all attributes are
   called `fully-specified'.


   Face merging.

   The display style of a given character in the text is determined by
   combining several faces.  This process is called `face merging'.
   Any aspect of the display style that isn't specified by overlays or
   text properties is taken from the `default' face.  Since it is made
   sure that the default face is always fully-specified, face merging
   always results in a fully-specified face.


   Face realization.
   
   After all face attributes for a character have been determined by
   merging faces of that character, that face is `realized'.  The
   realization process maps face attributes to what is physically
   available on the system where Emacs runs.  The result is a
   `realized face' in form of a struct face which is stored in the
   face cache of the frame on which it was realized.

   Face realization is done in the context of the charset of the
   character to display because different fonts and encodings are used
   for different charsets.  In other words, for characters of
   different charsets, different realized faces are needed to display
   them.

   Except for composite characters (CHARSET_COMPOSITION), faces are
   always realized for a specific character set and contain a specific
   font, even if the face being realized specifies a fontset (see
   `font selection' below).  The reason is that the result of the new
   font selection stage is better than what can be done with
   statically defined font name patterns in fontsets.


   Unibyte text.

   In unibyte text, Emacs' charsets aren't applicable; function
   `char-charset' reports CHARSET_ASCII for all characters, including
   those > 0x7f.  The X registry and encoding of fonts to use is
   determined from the variable `x-unibyte-registry-and-encoding' in
   this case.  The variable is initialized at Emacs startup time from
   the font the user specified for Emacs.

   Currently all unibyte text, i.e. all buffers with
   enable_multibyte_characters nil are displayed with fonts of the
   same registry and encoding `x-unibyte-registry-and-encoding'.  This
   is consistent with the fact that languages can also be set
   globally, only.
   

   Font selection.

   Font selection tries to find the best available matching font for a
   given (charset, face) combination.  This is done slightly
   differently for faces specifying a fontset, or a font family name.

   If the face specifies a fontset alias name, that fontset determines
   a pattern for fonts of the given charset.  If the face specifies a
   font family, a font pattern is constructed.  Charset symbols have a
   property `x-charset-registry' for that purpose that maps a charset
   to an XLFD registry and encoding in the font pattern constructed.

   Available fonts on the system on which Emacs runs are then matched
   against the font pattern.  The result of font selection is the best
   match for the given face attributes in this font list.

   Font selection can be influenced by the user.

   1. The user can specify the relative importance he gives the face
   attributes width, height, weight, and slant by setting
   face-font-selection-order (faces.el) to a list of face attribute
   names.  The default is '(:width :height :weight :slant), and means
   that font selection first tries to find a good match for the font
   width specified by a face, then---within fonts with that
   width---tries to find a best match for the specified font height,
   etc.

   2. Setting face-alternative-font-family-alist allows the user to
   specify alternative font families to try if a family specified by a
   face doesn't exist.


   Composite characters.  
   
   Realized faces for composite characters are the only ones having a
   fontset id >= 0.  When a composite character is encoded into a
   sequence of non-composite characters (in xterm.c), a suitable font
   for the non-composite characters is then selected and realized,
   i.e.  the realization process is delayed but in principle the same.

   
   Initialization of basic faces.

   The faces `default', `modeline' are considered `basic faces'.
   When redisplay happens the first time for a newly created frame,
   basic faces are realized for CHARSET_ASCII.  Frame parameters are
   used to fill in unspecified attributes of the default face.  */

/* Define SCALABLE_FONTS to a non-zero value to enable scalable
   font use. Define it to zero to disable scalable font use.

   Use of too many or too large scalable fonts can crash XFree86
   servers.  That's why I've put the code dealing with scalable fonts
   in #if's.  */

#define SCALABLE_FONTS 1
Jim Blandy's avatar
Jim Blandy committed
179

Jim Blandy's avatar
Jim Blandy committed
180 181
#include <sys/types.h>
#include <sys/stat.h>
182
#include <config.h>
Jim Blandy's avatar
Jim Blandy committed
183
#include "lisp.h"
Karl Heuer's avatar
Karl Heuer committed
184
#include "charset.h"
185 186
#include "frame.h"

Morten Welinder's avatar
Morten Welinder committed
187
#ifdef HAVE_X_WINDOWS
Jim Blandy's avatar
Jim Blandy committed
188
#include "xterm.h"
Karl Heuer's avatar
Karl Heuer committed
189
#include "fontset.h"
Morten Welinder's avatar
Morten Welinder committed
190
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
191

Morten Welinder's avatar
Morten Welinder committed
192 193 194
#ifdef MSDOS
#include "dosfns.h"
#endif
Gerd Moellmann's avatar
Gerd Moellmann committed
195

Jim Blandy's avatar
Jim Blandy committed
196
#include "buffer.h"
Jim Blandy's avatar
Jim Blandy committed
197
#include "dispextern.h"
Jim Blandy's avatar
Jim Blandy committed
198
#include "blockinput.h"
199
#include "window.h"
Karl Heuer's avatar
Karl Heuer committed
200
#include "intervals.h"
Jim Blandy's avatar
Jim Blandy committed
201

Morten Welinder's avatar
Morten Welinder committed
202
#ifdef HAVE_X_WINDOWS
Gerd Moellmann's avatar
Gerd Moellmann committed
203 204

/* Compensate for a bug in Xos.h on some systems, on which it requires
205 206 207 208
   time.h.  On some such systems, Xos.h tries to redefine struct
   timeval and struct timezone if USG is #defined while it is
   #included.  */

Gerd Moellmann's avatar
Gerd Moellmann committed
209
#ifdef XOS_NEEDS_TIME_H
210
#include <time.h>
211 212 213
#undef USG
#include <X11/Xos.h>
#define USG
214
#define __TIMEVAL__
Gerd Moellmann's avatar
Gerd Moellmann committed
215 216 217
#else /* not XOS_NEEDS_TIME_H */
#include <X11/Xos.h>
#endif /* not XOS_NEEDS_TIME_H */
218

Gerd Moellmann's avatar
Gerd Moellmann committed
219
#endif /* HAVE_X_WINDOWS */
220

Gerd Moellmann's avatar
Gerd Moellmann committed
221 222 223 224
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "keyboard.h"
Jim Blandy's avatar
Jim Blandy committed
225

Gerd Moellmann's avatar
Gerd Moellmann committed
226 227 228 229
#ifndef max
#define max(A, B)	((A) > (B) ? (A) : (B))
#define min(A, B)	((A) < (B) ? (A) : (B))
#define abs(X)		((X) < 0 ? -(X) : (X))
230
#endif
231

Gerd Moellmann's avatar
Gerd Moellmann committed
232 233 234 235 236 237 238 239 240 241 242 243
/* Non-zero if face attribute ATTR is unspecified.  */

#define UNSPECIFIEDP(ATTR) EQ ((ATTR), Qunspecified)

/* Value is the number of elements of VECTOR.  */

#define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))

/* Make a copy of string S on the stack using alloca.  Value is a pointer 
   to the copy.  */

#define STRDUPA(S) strcpy ((char *) alloca (strlen ((S)) + 1), (S))
244

Gerd Moellmann's avatar
Gerd Moellmann committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
/* Make a copy of the contents of Lisp string S on the stack using
   alloca.  Value is a pointer to the copy.  */

#define LSTRDUPA(S) STRDUPA (XSTRING ((S))->data)

/* Size of hash table of realized faces in face caches (should be a 
   prime number).  */

#define FACE_CACHE_BUCKETS_SIZE 1001

/* Keyword symbols used for face attribute names.  */

Lisp_Object QCfamily, QCheight, QCweight, QCslant, QCunderline;
Lisp_Object QCinverse_video, QCforeground, QCbackground, QCstipple;
Lisp_Object QCwidth, QCfont, QCbold, QCitalic;
Lisp_Object QCreverse_video;
Lisp_Object QCoverline, QCstrike_through, QCbox;

/* Symbols used for attribute values.  */

Lisp_Object Qnormal, Qbold, Qultra_light, Qextra_light, Qlight;
Lisp_Object Qsemi_light, Qsemi_bold, Qextra_bold, Qultra_bold;
Lisp_Object Qoblique, Qitalic, Qreverse_oblique, Qreverse_italic;
Lisp_Object Qultra_condensed, Qextra_condensed, Qcondensed;
Lisp_Object Qsemi_condensed, Qsemi_expanded, Qexpanded, Qextra_expanded;
Lisp_Object Qultra_expanded;
Lisp_Object Qreleased_button, Qpressed_button;
Lisp_Object QCstyle, QCcolor, QCline_width;
Lisp_Object Qunspecified;

/* The symbol `x-charset-registry'.  This property of charsets defines
   the X registry and encoding that fonts should have that are used to
   display characters of that charset.  */

Lisp_Object Qx_charset_registry;

/* Names of basic faces.  */

283 284 285 286 287 288 289
Lisp_Object Qdefault, Qmodeline, Qtool_bar, Qregion, Qfringe;
Lisp_Object Qheader_line, Qscroll_bar, Qcursor, Qborder, Qmouse;;

/* Names of frame parameters related to faces.  */

extern Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
extern Lisp_Object Qborder_color, Qcursor_color, Qmouse_color;
Gerd Moellmann's avatar
Gerd Moellmann committed
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318

/* Default stipple pattern used on monochrome displays.  This stipple
   pattern is used on monochrome displays instead of shades of gray
   for a face background color.  See `set-face-stipple' for possible
   values for this variable.  */

Lisp_Object Vface_default_stipple;

/* Default registry and encoding to use for charsets whose charset
   symbols don't specify one.  */

Lisp_Object Vface_default_registry;

/* Alist of alternative font families.  Each element is of the form
   (FAMILY FAMILY1 FAMILY2 ...).  If fonts of FAMILY can't be loaded,
   try FAMILY1, then FAMILY2, ...  */

Lisp_Object Vface_alternative_font_family_alist;

/* Allowed scalable fonts.  A value of nil means don't allow any
   scalable fonts.  A value of t means allow the use of any scalable
   font.  Otherwise, value must be a list of regular expressions.  A
   font may be scaled if its name matches a regular expression in the
   list.  */

#if SCALABLE_FONTS
Lisp_Object Vscalable_fonts_allowed;
#endif

Gerd Moellmann's avatar
Gerd Moellmann committed
319 320 321 322 323 324
/* Maximum number of fonts to consider in font_list.  If not an
   integer > 0, DEFAULT_FONT_LIST_LIMIT is used instead.  */

Lisp_Object Vfont_list_limit;
#define DEFAULT_FONT_LIST_LIMIT 100

Gerd Moellmann's avatar
Gerd Moellmann committed
325 326 327 328 329 330 331
/* The symbols `foreground-color' and `background-color' which can be
   used as part of a `face' property.  This is for compatibility with
   Emacs 20.2.  */

Lisp_Object Qforeground_color, Qbackground_color;

/* The symbols `face' and `mouse-face' used as text properties.  */
Jim Blandy's avatar
Jim Blandy committed
332

333
Lisp_Object Qface;
Gerd Moellmann's avatar
Gerd Moellmann committed
334 335 336 337
extern Lisp_Object Qmouse_face;

/* Error symbol for wrong_type_argument in load_pixmap.  */

338
Lisp_Object Qpixmap_spec_p;
Jim Blandy's avatar
Jim Blandy committed
339

Gerd Moellmann's avatar
Gerd Moellmann committed
340 341 342 343
/* Alist of global face definitions.  Each element is of the form
   (FACE . LFACE) where FACE is a symbol naming a face and LFACE
   is a Lisp vector of face attributes.  These faces are used
   to initialize faces for new frames.  */
344

Gerd Moellmann's avatar
Gerd Moellmann committed
345
Lisp_Object Vface_new_frame_defaults;
346

Gerd Moellmann's avatar
Gerd Moellmann committed
347
/* The next ID to assign to Lisp faces.  */
348

Gerd Moellmann's avatar
Gerd Moellmann committed
349
static int next_lface_id;
Jim Blandy's avatar
Jim Blandy committed
350

Gerd Moellmann's avatar
Gerd Moellmann committed
351
/* A vector mapping Lisp face Id's to face names.  */
Jim Blandy's avatar
Jim Blandy committed
352

Gerd Moellmann's avatar
Gerd Moellmann committed
353 354
static Lisp_Object *lface_id_to_name;
static int lface_id_to_name_size;
Jim Blandy's avatar
Jim Blandy committed
355

Gerd Moellmann's avatar
Gerd Moellmann committed
356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403
/* An alist of elements (COLOR-NAME . INDEX) mapping color names
   to color indices for tty frames.  */

Lisp_Object Vface_tty_color_alist;

/* Counter for calls to clear_face_cache.  If this counter reaches
   CLEAR_FONT_TABLE_COUNT, and a frame has more than
   CLEAR_FONT_TABLE_NFONTS load, unused fonts are freed.  */

static int clear_font_table_count;
#define CLEAR_FONT_TABLE_COUNT	100
#define CLEAR_FONT_TABLE_NFONTS	10

/* Non-zero means face attributes have been changed since the last
   redisplay.  Used in redisplay_internal.  */

int face_change_count;

/* The total number of colors currently allocated.  */

#if GLYPH_DEBUG
static int ncolors_allocated;
static int npixmaps_allocated;
static int ngcs;
#endif



/* Function prototypes.  */

struct font_name;
struct table_entry;

static int may_use_scalable_font_p P_ ((struct font_name *, char *));
static void set_font_frame_param P_ ((Lisp_Object, Lisp_Object));
static int better_font_p P_ ((int *, struct font_name *, struct font_name *,
			      int));
static int first_font_matching P_ ((struct frame *f, char *,
				    struct font_name *));
static int x_face_list_fonts P_ ((struct frame *, char *,
				  struct font_name *, int, int, int));
static int font_scalable_p P_ ((struct font_name *));
static Lisp_Object deduce_unibyte_registry P_ ((struct frame *, char *));
static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, int));
static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *));
static char *xstrdup P_ ((char *));
static unsigned char *xstrlwr P_ ((unsigned char *));
static void signal_error P_ ((char *, Lisp_Object));
404
static void add_to_log P_ ((struct frame *, char *, Lisp_Object, Lisp_Object));
Gerd Moellmann's avatar
Gerd Moellmann committed
405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481
static struct frame *frame_or_selected_frame P_ ((Lisp_Object, int));
static void load_face_font_or_fontset P_ ((struct frame *, struct face *, char *, int));
static void load_face_colors P_ ((struct frame *, struct face *, Lisp_Object *));
static void free_face_colors P_ ((struct frame *, struct face *));
static int face_color_gray_p P_ ((struct frame *, char *));
static char *build_font_name P_ ((struct font_name *));
static void free_font_names P_ ((struct font_name *, int));
static int sorted_font_list P_ ((struct frame *, char *,
				 int (*cmpfn) P_ ((const void *, const void *)),
				 struct font_name **));
static int font_list P_ ((struct frame *, char *, char *, char *, struct font_name **));
static int try_font_list P_ ((struct frame *, Lisp_Object *, char *, char *, char *,
			      struct font_name **));
static int cmp_font_names P_ ((const void *, const void *));
static struct face *realize_face P_ ((struct face_cache *,
				      Lisp_Object *, int));
static struct face *realize_x_face P_ ((struct face_cache *,
					Lisp_Object *, int));
static struct face *realize_tty_face P_ ((struct face_cache *,
					  Lisp_Object *, int));
static int realize_basic_faces P_ ((struct frame *));
static int realize_default_face P_ ((struct frame *));
static void realize_named_face P_ ((struct frame *, Lisp_Object, int));
static int lface_fully_specified_p P_ ((Lisp_Object *));
static int lface_equal_p P_ ((Lisp_Object *, Lisp_Object *));
static unsigned hash_string_case_insensitive P_ ((Lisp_Object));
static unsigned lface_hash P_ ((Lisp_Object *));
static int lface_same_font_attributes_p P_ ((Lisp_Object *, Lisp_Object *));
static struct face_cache *make_face_cache P_ ((struct frame *));
static void free_realized_face P_ ((struct frame *, struct face *));
static void clear_face_gcs P_ ((struct face_cache *));
static void free_face_cache P_ ((struct face_cache *));
static int face_numeric_weight P_ ((Lisp_Object));
static int face_numeric_slant P_ ((Lisp_Object));
static int face_numeric_swidth P_ ((Lisp_Object));
static int face_fontset P_ ((struct frame *, Lisp_Object *));
static char *choose_face_font P_ ((struct frame *, Lisp_Object *, int,
				   Lisp_Object));
static char *choose_face_fontset_font P_ ((struct frame *, Lisp_Object *,
					   int, int));
static void merge_face_vectors P_ ((Lisp_Object *from, Lisp_Object *));
static void merge_face_vector_with_property P_ ((struct frame *, Lisp_Object *,
						 Lisp_Object));
static int set_lface_from_font_name P_ ((struct frame *, Lisp_Object, char *,
					 int));
static Lisp_Object lface_from_face_name P_ ((struct frame *, Lisp_Object, int));
static struct face *make_realized_face P_ ((Lisp_Object *, int, Lisp_Object));
static void free_realized_faces P_ ((struct face_cache *));
static char *best_matching_font P_ ((struct frame *, Lisp_Object *,
				     struct font_name *, int));
static void cache_face P_ ((struct face_cache *, struct face *, unsigned));
static void uncache_face P_ ((struct face_cache *, struct face *));
static int xlfd_numeric_slant P_ ((struct font_name *));
static int xlfd_numeric_weight P_ ((struct font_name *));
static int xlfd_numeric_swidth P_ ((struct font_name *));
static Lisp_Object xlfd_symbolic_slant P_ ((struct font_name *));
static Lisp_Object xlfd_symbolic_weight P_ ((struct font_name *));
static Lisp_Object xlfd_symbolic_swidth P_ ((struct font_name *));
static int xlfd_fixed_p P_ ((struct font_name *));
static int xlfd_numeric_value P_ ((struct table_entry *, int, struct font_name *,
				   int, int));
static Lisp_Object xlfd_symbolic_value P_ ((struct table_entry *, int,
					    struct font_name *, int, int));
static struct table_entry *xlfd_lookup_field_contents P_ ((struct table_entry *, int,
							   struct font_name *, int));

#ifdef HAVE_X_WINDOWS

static int split_font_name P_ ((struct frame *, struct font_name *, int));
static int xlfd_point_size P_ ((struct frame *, struct font_name *));
static void sort_fonts P_ ((struct frame *, struct font_name *, int,
			       int (*cmpfn) P_ ((const void *, const void *))));
static GC x_create_gc P_ ((struct frame *, unsigned long, XGCValues *));
static void x_free_gc P_ ((struct frame *, GC));
static void clear_font_table P_ ((struct frame *));

#endif /* HAVE_X_WINDOWS */
Jim Blandy's avatar
Jim Blandy committed
482

483

Gerd Moellmann's avatar
Gerd Moellmann committed
484 485 486
/***********************************************************************
			      Utilities
 ***********************************************************************/
Jim Blandy's avatar
Jim Blandy committed
487

Morten Welinder's avatar
Morten Welinder committed
488
#ifdef HAVE_X_WINDOWS
489

Gerd Moellmann's avatar
Gerd Moellmann committed
490 491 492 493 494
/* Create and return a GC for use on frame F.  GC values and mask
   are given by XGCV and MASK.  */

static INLINE GC
x_create_gc (f, mask, xgcv)
495
     struct frame *f;
Gerd Moellmann's avatar
Gerd Moellmann committed
496 497
     unsigned long mask;
     XGCValues *xgcv;
Jim Blandy's avatar
Jim Blandy committed
498 499
{
  GC gc;
Gerd Moellmann's avatar
Gerd Moellmann committed
500 501 502 503 504 505
  BLOCK_INPUT;
  gc = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), mask, xgcv);
  UNBLOCK_INPUT;
  IF_DEBUG (++ngcs);
  return gc;
}
Jim Blandy's avatar
Jim Blandy committed
506

507

Gerd Moellmann's avatar
Gerd Moellmann committed
508 509 510 511 512 513 514
/* Free GC which was used on frame F.  */

static INLINE void
x_free_gc (f, gc)
     struct frame *f;
     GC gc;
{
515
  BLOCK_INPUT;
Gerd Moellmann's avatar
Gerd Moellmann committed
516 517 518 519
  xassert (--ngcs >= 0);
  XFreeGC (FRAME_X_DISPLAY (f), gc);
  UNBLOCK_INPUT;
}
520

Gerd Moellmann's avatar
Gerd Moellmann committed
521
#endif /* HAVE_X_WINDOWS */
522 523


Gerd Moellmann's avatar
Gerd Moellmann committed
524 525 526 527 528 529 530 531 532 533 534
/* Like strdup, but uses xmalloc.  */

static char *
xstrdup (s)
     char *s;
{
  int len = strlen (s) + 1;
  char *p = (char *) xmalloc (len);
  bcopy (s, p, len);
  return p;
}
535 536


Gerd Moellmann's avatar
Gerd Moellmann committed
537 538 539 540 541 542 543 544
/* Like stricmp.  Used to compare parts of font names which are in
   ISO8859-1.  */

int
xstricmp (s1, s2)
     unsigned char *s1, *s2;
{
  while (*s1 && *s2)
545
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
546 547 548 549 550
      unsigned char c1 = tolower (*s1);
      unsigned char c2 = tolower (*s2);
      if (c1 != c2)
	return c1 < c2 ? -1 : 1;
      ++s1, ++s2;
551
    }
552

Gerd Moellmann's avatar
Gerd Moellmann committed
553 554 555 556
  if (*s1 == 0)
    return *s2 == 0 ? 0 : -1;
  return 1;
}
557 558


Gerd Moellmann's avatar
Gerd Moellmann committed
559
/* Like strlwr, which might not always be available.  */
560

Gerd Moellmann's avatar
Gerd Moellmann committed
561 562 563 564 565 566 567 568 569 570
static unsigned char *
xstrlwr (s)
     unsigned char *s;
{
  unsigned char *p = s;

  for (p = s; *p; ++p)
    *p = tolower (*p);

  return s;
Jim Blandy's avatar
Jim Blandy committed
571
}
572

573

Gerd Moellmann's avatar
Gerd Moellmann committed
574 575 576 577 578 579
/* Signal `error' with message S, and additional argument ARG.  */

static void
signal_error (s, arg)
     char *s;
     Lisp_Object arg;
580
{
Gerd Moellmann's avatar
Gerd Moellmann committed
581 582
  Fsignal (Qerror, Fcons (build_string (s), Fcons (arg, Qnil)));
}
583

Gerd Moellmann's avatar
Gerd Moellmann committed
584 585 586 587 588 589 590 591 592 593 594 595 596 597

/* Display a message with format string FORMAT and arguments ARG1 and
   ARG2 on frame F.  Used to display errors if fonts, bitmaps, colors 
   etc. for a realized face on frame F cannot be loaded.  (If we would
   signal an error in these cases, we would end up in an infinite
   recursion because this would stop realization, and the redisplay
   triggered by the signal would try to realize that same face again.)

   If basic faces of F are not realized, just add the message to the
   messages buffer "*Messages*".  Because Fmessage calls
   echo_area_display which tries to realize basic faces again, we would
   otherwise also end in an infinite recursion.  */

static void
598
add_to_log (f, format, arg1, arg2)
Gerd Moellmann's avatar
Gerd Moellmann committed
599 600 601 602 603 604
     struct frame *f;
     char *format;
     Lisp_Object arg1, arg2;
{
  Lisp_Object args[3];
  Lisp_Object nargs;
605 606
  Lisp_Object msg;
  char *buffer;
Gerd Moellmann's avatar
Gerd Moellmann committed
607 608 609 610 611 612 613 614 615 616 617 618 619
  extern int waiting_for_input;

  /* Function note_mouse_highlight calls face_at_buffer_position which
     may realize a face.  If some attribute of that face is invalid,
     say an invalid color, don't display an error to avoid calling
     Lisp from XTread_socket.  */
  if (waiting_for_input)
    return;

  nargs = make_number (DIM (args));
  args[0] = build_string (format);
  args[1] = arg1;
  args[2] = arg2;
620 621 622 623 624 625
  msg = Fformat (nargs, args);

  /* Log the error, but don't display it in the echo area.  This
     proves to be annoying in many cases.  */
  buffer = LSTRDUPA (msg);
  message_dolog (buffer, strlen (buffer), 1, 0);
Gerd Moellmann's avatar
Gerd Moellmann committed
626
}
627

Gerd Moellmann's avatar
Gerd Moellmann committed
628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646

/* If FRAME is nil, return selected_frame.  Otherwise, check that
   FRAME is a live frame, and return a pointer to it.  NPARAM
   is the parameter number of FRAME, for CHECK_LIVE_FRAME.  This is
   here because it's a frequent pattern in Lisp function definitions.  */

static INLINE struct frame *
frame_or_selected_frame (frame, nparam)
     Lisp_Object frame;
     int nparam;
{
  struct frame *f;
  
  if (NILP (frame))
    f = selected_frame;
  else
    {
      CHECK_LIVE_FRAME (frame, nparam);
      f = XFRAME (frame);
647 648
    }

Gerd Moellmann's avatar
Gerd Moellmann committed
649
  return f;
650
}
Gerd Moellmann's avatar
Gerd Moellmann committed
651

652

Gerd Moellmann's avatar
Gerd Moellmann committed
653 654 655
/***********************************************************************
			   Frames and faces
 ***********************************************************************/
656

Gerd Moellmann's avatar
Gerd Moellmann committed
657
/* Initialize face cache and basic faces for frame F.  */
658

Gerd Moellmann's avatar
Gerd Moellmann committed
659 660
void
init_frame_faces (f)
661 662
     struct frame *f;
{
Gerd Moellmann's avatar
Gerd Moellmann committed
663 664 665 666 667 668 669 670 671 672 673 674 675
  /* Make a face cache, if F doesn't have one.  */
  if (FRAME_FACE_CACHE (f) == NULL)
    FRAME_FACE_CACHE (f) = make_face_cache (f);
      
#ifdef HAVE_X_WINDOWS
  /* Make the image cache.  */
  if (FRAME_X_P (f))
    {
      if (FRAME_X_IMAGE_CACHE (f) == NULL)
	FRAME_X_IMAGE_CACHE (f) = make_image_cache ();
      ++FRAME_X_IMAGE_CACHE (f)->refcount;
    }
#endif /* HAVE_X_WINDOWS */
676

Gerd Moellmann's avatar
Gerd Moellmann committed
677 678 679 680 681 682 683 684
  /* Realize basic faces.  Must have enough information in frame 
     parameters to realize basic faces at this point.  */
#ifdef HAVE_X_WINDOWS
  if (!FRAME_X_P (f) || FRAME_X_WINDOW (f))
#endif
    if (!realize_basic_faces (f))
      abort ();
}
685 686


Gerd Moellmann's avatar
Gerd Moellmann committed
687
/* Free face cache of frame F.  Called from Fdelete_frame.  */
688

Gerd Moellmann's avatar
Gerd Moellmann committed
689 690
void
free_frame_faces (f)
691 692
     struct frame *f;
{
Gerd Moellmann's avatar
Gerd Moellmann committed
693 694 695 696 697 698 699
  struct face_cache *face_cache = FRAME_FACE_CACHE (f);
  
  if (face_cache)
    {
      free_face_cache (face_cache);
      FRAME_FACE_CACHE (f) = NULL;
    }
700

Gerd Moellmann's avatar
Gerd Moellmann committed
701 702
#ifdef HAVE_X_WINDOWS
  if (FRAME_X_P (f))
703
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
704 705
      struct image_cache *image_cache = FRAME_X_IMAGE_CACHE (f);
      if (image_cache)
706
	{
Gerd Moellmann's avatar
Gerd Moellmann committed
707 708 709
	  --image_cache->refcount;
	  if (image_cache->refcount == 0)
	    free_image_cache (f);
710 711
	}
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
712
#endif /* HAVE_X_WINDOWS */
713 714
}

Gerd Moellmann's avatar
Gerd Moellmann committed
715

716 717 718 719
/* Clear face caches, and recompute basic faces for frame F.  Call
   this after changing frame parameters on which those faces depend,
   or when realized faces have been freed due to changing attributes
   of named faces. */
Gerd Moellmann's avatar
Gerd Moellmann committed
720 721 722

void
recompute_basic_faces (f)
723 724
     struct frame *f;
{
Gerd Moellmann's avatar
Gerd Moellmann committed
725 726
  if (FRAME_FACE_CACHE (f))
    {
727 728 729
      int realized_p;
      clear_face_cache (0);
      realized_p = realize_basic_faces (f);
Gerd Moellmann's avatar
Gerd Moellmann committed
730 731 732
      xassert (realized_p);
    }
}
733 734


Gerd Moellmann's avatar
Gerd Moellmann committed
735 736
/* Clear the face caches of all frames.  CLEAR_FONTS_P non-zero means
   try to free unused fonts, too.  */
737

738
void
Gerd Moellmann's avatar
Gerd Moellmann committed
739 740
clear_face_cache (clear_fonts_p)
     int clear_fonts_p;
741
{
Gerd Moellmann's avatar
Gerd Moellmann committed
742 743 744
#ifdef HAVE_X_WINDOWS
  Lisp_Object tail, frame;
  struct frame *f;
745

Gerd Moellmann's avatar
Gerd Moellmann committed
746 747
  if (clear_fonts_p
      || ++clear_font_table_count == CLEAR_FONT_TABLE_COUNT)
748
    {
Gerd Moellmann's avatar
Gerd Moellmann committed
749 750 751 752
      /* From time to time see if we can unload some fonts.  This also
	 frees all realized faces on all frames.  Fonts needed by
	 faces will be loaded again when faces are realized again.  */
      clear_font_table_count = 0;
753

Gerd Moellmann's avatar
Gerd Moellmann committed
754
      FOR_EACH_FRAME (tail, frame)
755
	{
Gerd Moellmann's avatar
Gerd Moellmann committed
756 757 758
	  f = XFRAME (frame);
	  if (FRAME_X_P (f)
	      && FRAME_X_DISPLAY_INFO (f)->n_fonts > CLEAR_FONT_TABLE_NFONTS)
759
	    {
Gerd Moellmann's avatar
Gerd Moellmann committed
760 761 762 763 764 765 766 767 768 769 770 771 772 773 774
	      free_all_realized_faces (frame);
	      clear_font_table (f);
	    }
	}
    }
  else
    {
      /* Clear GCs of realized faces.  */
      FOR_EACH_FRAME (tail, frame)
	{
	  f = XFRAME (frame);
	  if (FRAME_X_P (f))
	    {
	      clear_face_gcs (FRAME_FACE_CACHE (f));
	      clear_image_cache (f, 0);
775 776
	    }
	}
777
    }
Gerd Moellmann's avatar
Gerd Moellmann committed
778
#endif /* HAVE_X_WINDOWS */
779 780
}

Gerd Moellmann's avatar
Gerd Moellmann committed
781 782 783 784 785 786

DEFUN ("clear-face-cache", Fclear_face_cache, Sclear_face_cache, 0, 1, 0,
  "Clear face caches on all frames.\n\
Optional THOROUGHLY non-nil means try to free unused fonts, too.")
  (thorougly)
     Lisp_Object thorougly;
787
{
Gerd Moellmann's avatar
Gerd Moellmann committed
788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883
  clear_face_cache (!NILP (thorougly));
  return Qnil;
}



#ifdef HAVE_X_WINDOWS


/* Remove those fonts from the font table of frame F that are not used
   by fontsets.  Called from clear_face_cache from time to time.  */

static void
clear_font_table (f)
     struct frame *f;
{
  struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
  char *used;
  Lisp_Object rest, frame;
  int i;

  xassert (FRAME_X_P (f));

  used = (char *) alloca (dpyinfo->n_fonts * sizeof *used);
  bzero (used, dpyinfo->n_fonts * sizeof *used);

  /* For all frames with the same x_display_info as F, record
     in `used' those fonts that are in use by fontsets.  */
  FOR_EACH_FRAME (rest, frame)
    if (FRAME_X_DISPLAY_INFO (XFRAME (frame)) == dpyinfo)
      {
	struct frame *f = XFRAME (frame);
	struct fontset_data *fontset_data = FRAME_FONTSET_DATA (f);

	for (i = 0; i < fontset_data->n_fontsets; ++i)
	  {
	    struct fontset_info *info = fontset_data->fontset_table[i];
	    int j;
	    
	    for (j = 0; j <= MAX_CHARSET; ++j)
	      {
		int idx = info->font_indexes[j];
		if (idx >= 0)
		  used[idx] = 1;
	      }
	  }
      }

  /* Free those fonts that are not used by fontsets.  */
  for (i = 0; i < dpyinfo->n_fonts; ++i)
    if (used[i] == 0 && dpyinfo->font_table[i].name)
      {
	struct font_info *font_info = dpyinfo->font_table + i;

	/* Free names.  In xfns.c there is a comment that full_name
	   should never be freed because it is always shared with
	   something else.  I don't think this is true anymore---see
	   x_load_font.  It's either equal to font_info->name or
	   allocated via xmalloc, and there seems to be no place in
	   the source files where full_name is transferred to another
	   data structure.  */
	if (font_info->full_name != font_info->name)
	  xfree (font_info->full_name);
	xfree (font_info->name);

	/* Free the font.  */
	BLOCK_INPUT;
	XFreeFont (dpyinfo->display, font_info->font);
	UNBLOCK_INPUT;

	/* Mark font table slot free.  */
	font_info->font = NULL;
	font_info->name = font_info->full_name = NULL;
      }
}


#endif /* HAVE_X_WINDOWS */



/***********************************************************************
			      X Pixmaps
 ***********************************************************************/

#ifdef HAVE_X_WINDOWS

DEFUN ("pixmap-spec-p", Fpixmap_spec_p, Spixmap_spec_p, 1, 1, 0,
  "Non-nil if OBJECT is a valid pixmap specification.\n\
A pixmap specification is either a string, or a list (WIDTH HEIGHT DATA)\n\
where WIDTH is the pixel width of the pixmap, HEIGHT is its height,\n\
and DATA contains the bits of the pixmap.")
  (object)
     Lisp_Object object;
{
  Lisp_Object height, width;
884

885 886 887 888 889 890
  return ((STRINGP (object)
	   || (CONSP (object)
	       && CONSP (XCONS (object)->cdr)
	       && CONSP (XCONS (XCONS (object)->cdr)->cdr)
	       && NILP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->cdr)
	       && (width = XCONS (object)->car, INTEGERP (width))
Gerd Moellmann's avatar
Gerd Moellmann committed
891 892
	       && (height = XCONS (XCONS (object)->cdr)->car,
		   INTEGERP (height))
893
	       && STRINGP (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)
894 895 896
	       && XINT (width) > 0
	       && XINT (height) > 0
	       /* The string must have enough bits for width * height.  */
897
	       && ((XSTRING (XCONS (XCONS (XCONS (object)->cdr)->cdr)->car)->size
898
		    * (BITS_PER_INT / sizeof (int)))
899
		   >= XFASTINT (width) * XFASTINT (height))))
900 901 902 903
	  ? Qt : Qnil);
}


Gerd Moellmann's avatar
Gerd Moellmann committed
904 905 906 907 908 909
/* Load a bitmap according to NAME (which is either a file name or a
   pixmap spec) for use on frame F.  Value is the bitmap_id (see
   xfns.c).  If NAME is nil, return with a bitmap id of zero.  If
   bitmap cannot be loaded, display a message saying so, and return
   zero.  Store the bitmap width in *W_PTR and its height in *H_PTR,
   if these pointers are not null.  */
910

Gerd Moellmann's avatar
Gerd Moellmann committed
911
static int
912
load_pixmap (f, name, w_ptr, h_ptr)
913
     FRAME_PTR f;
914 915 916 917 918 919 920
     Lisp_Object name;
     unsigned int *w_ptr, *h_ptr;
{
  int bitmap_id;
  Lisp_Object tem;

  if (NILP (name))
Gerd Moellmann's avatar
Gerd Moellmann committed
921
    return 0;
922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948

  tem = Fpixmap_spec_p (name);
  if (NILP (tem))
    wrong_type_argument (Qpixmap_spec_p, name);

  BLOCK_INPUT;
  if (CONSP (name))
    {
      /* Decode a bitmap spec into a bitmap.  */

      int h, w;
      Lisp_Object bits;

      w = XINT (Fcar (name));
      h = XINT (Fcar (Fcdr (name)));
      bits = Fcar (Fcdr (Fcdr (name)));

      bitmap_id = x_create_bitmap_from_data (f, XSTRING (bits)->data,
					     w, h);
    }
  else
    {
      /* It must be a string -- a file name.  */
      bitmap_id = x_create_bitmap_from_file (f, name);
    }
  UNBLOCK_INPUT;

949
  if (bitmap_id < 0)
Gerd Moellmann's avatar
Gerd Moellmann committed
950
    {
951
      add_to_log (f, "Invalid or undefined bitmap %s", name, Qnil);
Gerd Moellmann's avatar
Gerd Moellmann committed
952
      bitmap_id = 0;
953

Gerd Moellmann's avatar
Gerd Moellmann committed
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969
      if (w_ptr)
	*w_ptr = 0;
      if (h_ptr)
	*h_ptr = 0;
    }
  else
    {
#if GLYPH_DEBUG
      ++npixmaps_allocated;
#endif
      if (w_ptr)
	*w_ptr = x_bitmap_width (f, bitmap_id);

      if (h_ptr)
	*h_ptr = x_bitmap_height (f, bitmap_id);
    }
970 971

  return bitmap_id;
972
}
Morten Welinder's avatar
Morten Welinder committed
973

Gerd Moellmann's avatar
Gerd Moellmann committed
974 975
#endif /* HAVE_X_WINDOWS */

Morten Welinder's avatar
Morten Welinder committed
976

Gerd Moellmann's avatar
Gerd Moellmann committed
977 978 979 980 981 982 983

/***********************************************************************
			 Minimum font bounds
 ***********************************************************************/

#ifdef HAVE_X_WINDOWS

984 985
/* Update the line_height of frame F.  Return non-zero if line height
   changes.  */
Morten Welinder's avatar
Morten Welinder committed
986

Gerd Moellmann's avatar
Gerd Moellmann committed
987 988
int
frame_update_line_height (f)
Morten Welinder's avatar
Morten Welinder committed
989 990
     struct frame *f;
{
991 992 993 994 995 996 997 998 999 1000
  int fontset, line_height, changed_p;
  
  fontset = f->output_data.x->fontset;
  if (fontset > 0)
    line_height = FRAME_FONTSET_DATA (f)->fontset_table[fontset]->height;
  else
    line_height = FONT_HEIGHT (f->output_data.x->font);
  
  changed_p = line_height != f->output_data.x->line_height;
  f->output_data.x->line_height = line_height;
Gerd Moellmann's avatar
Gerd Moellmann committed
1001
  return changed_p;
Morten Welinder's avatar
Morten Welinder committed
1002 1003
}

Gerd Moellmann's avatar
Gerd Moellmann committed
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024
#endif /* HAVE_X_WINDOWS */


/***********************************************************************
				Fonts
 ***********************************************************************/

#ifdef HAVE_X_WINDOWS

/* Load font or fontset of face FACE which is used on frame F.
   FONTSET is the fontset FACE should use or -1, if FACE doesn't use a
   fontset.  FONT_NAME is the name of the font to load, if no fontset
   is used.  It is null if no suitable font name could be determined
   for the face.  */

static void
load_face_font_or_fontset (f, face, font_name, fontset)
     struct frame *f;
     struct face *face;
     char *font_name;
     int fontset;
Morten Welinder's avatar
Morten Welinder committed
1025
{
Gerd Moellmann's avatar
Gerd Moellmann committed
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
  struct font_info *font_info = NULL;

  face->font_info_id = -1;
  face->fontset = fontset;
  face->font = NULL;
  
  BLOCK_INPUT;
  if (fontset >= 0)
    font_info = FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f), CHARSET_ASCII,
			      NULL, fontset);
  else if (font_name)
    font_info = FS_LOAD_FONT (f, FRAME_X_FONT_TABLE (f), face->charset,
			      font_name, -1);
  UNBLOCK_INPUT;

  if (font_info)
    {
      char *s;
      int i;
      
      face->font_info_id = FONT_INFO_ID (f, font_info);
      face->font = font_info->font;
      face->font_name = font_info->full_name;

      /* Make the registry part of the font name readily accessible.
	 The registry is used to find suitable faces for unibyte text.  */
      s = font_info->full_name + strlen (font_info->full_name);
      i = 0;
      while (i < 2 && --s >= font_info->full_name)
	if (*s == '-')
	  ++i;

      if (!STRINGP (face->registry)
	  || xstricmp (XSTRING (face->registry)->data, s + 1) != 0)
	{
	  if (STRINGP (Vface_default_registry)
	      && !xstricmp (XSTRING (Vface_default_registry)->data, s + 1))
	    face->registry = Vface_default_registry;
	  else
	    face->registry = build_string (s + 1);
	}
    }
  else if (fontset >= 0)
1069 1070
    add_to_log (f, "Unable to load ASCII font of fontset %d",
		make_number (fontset), Qnil);
Gerd Moellmann's avatar
Gerd Moellmann committed
1071
  else if (font_name)
1072 1073
    add_to_log (f, "Unable to load font %s",
		build_string (font_name), Qnil);
Morten Welinder's avatar
Morten Welinder committed
1074 1075
}

Gerd Moellmann's avatar
Gerd Moellmann committed
1076
#endif /* HAVE_X_WINDOWS */
Morten Welinder's avatar
Morten Welinder committed
1077 1078


Gerd Moellmann's avatar
Gerd Moellmann committed
1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103

/***********************************************************************
				X Colors
 ***********************************************************************/

#ifdef HAVE_X_WINDOWS

/* Return non-zero if COLOR_NAME is a shade of gray (or white or
   black) on frame F.  The algorithm is taken from 20.2 faces.el.  */

static int
face_color_gray_p (f, color_name)
     struct frame *f;
     char *color_name;
{
  XColor color;
  int gray_p;

  if (defined_color (f, color_name, &color, 0))
    gray_p = ((abs (color.red - color.green)
	       < max (color.red, color.green) / 20)
	      && (abs (color.green - color.blue)
		  < max (color.green, color.blue) / 20)
	      && (abs (color.blue - color.red)
		  < max (color.blue, color.red) / 20));
Morten Welinder's avatar
Morten Welinder committed
1104
  else
Gerd Moellmann's avatar
Gerd Moellmann committed
1105 1106 1107
    gray_p = 0;
  
  return gray_p;
Morten Welinder's avatar
Morten Welinder committed
1108 1109
}

1110

Gerd Moellmann's avatar
Gerd Moellmann committed
1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140
/* Return non-zero if color COLOR_NAME can be displayed on frame F.
   BACKGROUND_P non-zero means the color will be used as background
   color.  */

static int
face_color_supported_p (f, color_name, background_p)
     struct frame *f;
     char *color_name;
     int background_p;
{
  Lisp_Object frame;

  XSETFRAME (frame, f);
  return (!NILP (Vwindow_system)
	  && (!NILP (Fx_display_color_p (frame))
	      || xstricmp (color_name, "black") == 0
	      || xstricmp (color_name, "white") == 0
	      || (background_p
		  && face_color_gray_p (f, color_name))
	      || (!NILP (Fx_display_grayscale_p (frame))
		  && face_color_gray_p (f, color_name))));
}  


DEFUN ("face-color-gray-p", Fface_color_gray_p, Sface_color_gray_p, 1, 2, 0,
  "Return non-nil if COLOR is a shade of gray (or white or black).\n\
FRAME specifies the frame and thus the display for interpreting COLOR.\n\
If FRAME is nil or omitted, use the selected frame.")
   (color, frame)
     Lisp_Object color, frame;
1141
{
Gerd Moellmann's avatar
Gerd Moellmann committed
1142 1143 1144 1145
  struct frame *f = check_x_frame (frame);
  CHECK_STRING (color, 0);
  return face_color_gray_p (f, XSTRING (color)->data) ? Qt : Qnil;
}
1146

1147

Gerd Moellmann's avatar
Gerd Moellmann committed
1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162
DEFUN ("face-color-supported-p", Fface_color_supported_p,
       Sface_color_supported_p, 2, 3, 0,
  "Return non-nil if COLOR can be displayed on FRAME.\n\
BACKGROUND-P non-nil means COLOR is used as a background.\n\
If FRAME is nil or omitted, use the selected frame.\n\
COLOR must be a valid color name.")
   (frame, color, background_p)
     Lisp_Object frame, color, background_p;
{
  struct frame *f = check_x_frame (frame);
  CHECK_STRING (color, 0);
  if (face_color_supported_p (f, XSTRING (color)->data, !NILP (background_p)))
    return Qt;
  return Qnil;
}
1163

Gerd Moellmann's avatar
Gerd Moellmann committed
1164 1165 1166 1167 1168 1169 1170 1171 1172
/* Load color with name NAME for use by face FACE on frame F.
   TARGET_INDEX must be one of LFACE_FOREGROUND_INDEX,
   LFACE_BACKGROUND_INDEX, LFACE_UNDERLINE_INDEX, LFACE_OVERLINE_INDEX,
   LFACE_STRIKE_THROUGH_INDEX, or LFACE_BOX_INDEX.  Value is the
   pixel color.  If color cannot be loaded, display a message, and
   return the foreground, background or underline color of F, but
   record that fact in flags of the face so that we don't try to free
   these colors.  */

1173
unsigned long
Gerd Moellmann's avatar
Gerd Moellmann committed
1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193
load_color (f, face, name, target_index)
     struct frame *f;
     struct face *face;
     Lisp_Object name;
     enum lface_attribute_index target_index;
{
  XColor color;
  
  xassert (STRINGP (name));
  xassert (target_index == LFACE_FOREGROUND_INDEX
	   || target_index == LFACE_BACKGROUND_INDEX
	   || target_index == LFACE_UNDERLINE_INDEX
	   || target_index == LFACE_OVERLINE_INDEX
	   || target_index == LFACE_STRIKE_THROUGH_INDEX
	   || target_index == LFACE_BOX_INDEX);
      
  /* if the color map is full, defined_color will return a best match
     to the values in an existing cell. */
  if (!defined_color (f, XSTRING (name)->data, &color, 1))
    {
1194
      add_to_log (f, "Unable to load color %s", name, Qnil);
Gerd Moellmann's avatar
Gerd Moellmann committed
1195 1196
      
      switch (target_index)
1197
	{
Gerd Moellmann's avatar
Gerd Moellmann committed
1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
	case LFACE_FOREGROUND_INDEX:
	  face->foreground_defaulted_p = 1;
	  color.pixel = FRAME_FOREGROUND_PIXEL (f);
	  break;
	  
	case LFACE_BACKGROUND_INDEX:
	  face->background_defaulted_p = 1;
	  color.pixel = FRAME_BACKGROUND_PIXEL (f);
	  break;
	  
	case LFACE_UNDERLINE_INDEX:
	  face->underline_defaulted_p = 1;
	  color.pixel = FRAME_FOREGROUND_PIXEL (f);
	  break;
	  
	case LFACE_OVERLINE_INDEX:
	  face->overline_color_defaulted_p = 1;
	  color.pixel = FRAME_FOREGROUND_PIXEL (f);
1216
	  break;
Gerd Moellmann's avatar
Gerd Moellmann committed
1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229
	  
	case LFACE_STRIKE_THROUGH_INDEX:
	  face->strike_through_color_defaulted_p = 1;
	  color.pixel = FRAME_FOREGROUND_PIXEL (f);
	  break;
	  
	case LFACE_BOX_INDEX:
	  face->box_color_defaulted_p = 1;
	  color.pixel = FRAME_FOREGROUND_PIXEL (f);
	  break;

	default:
	  abort ();
1230
	}
Gerd Moellmann's avatar
Gerd Moellmann committed
1231 1232 1233 1234 1235 1236 1237 1238
    }
#if GLYPH_DEBUG
  else
    ++ncolors_allocated;
#endif
  
  return color.pixel;
}
1239 1240


Gerd Moellmann's avatar
Gerd Moellmann committed
1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
/* Load colors for face FACE which is used on frame F.  Colors are
   specified by slots LFACE_BACKGROUND_INDEX and LFACE_FOREGROUND_INDEX
   of ATTRS.  If the background color specified is not supported on F,
   try to emulate gray colors with a stipple from Vface_default_stipple.  */

static void
load_face_colors (f, face, attrs)
     struct frame *f;
     struct face *face;
     Lisp_Object *attrs;
{
  Lisp_Object fg, bg;

  bg = attrs[LFACE_BACKGROUND_INDEX];
  fg = attrs[LFACE_FOREGROUND_INDEX];

  /* Swap colors if face is inverse-video.  */
  if (EQ (attrs[LFACE_INVERSE_INDEX], Qt))
    {
      Lisp_Object tmp;
      tmp = fg;
      fg = bg;
      bg = tmp;
    }

  /* Check for support for foreground, not for background because
     face_color_supported_p is smart enough to know that grays are
     "supported" as background because we are supposed to use stipple
     for them.  */
  if (!face_color_supported_p (f, XSTRING (bg)->data, 0)
      && !NILP (Fpixmap_spec_p (Vface_default_stipple)))
    {
      x_destroy_bitmap (f, face->stipple);
      face->stipple = load_pixmap (f, Vface_default_stipple,
				   &face->pixmap_w, &face->pixmap_h);
    }

1278
  face->background = load_color (f, face, bg, LFACE_BACKGROUND_INDEX);
Gerd Moellmann's avatar
Gerd Moellmann committed
1279
  face->foreground = load_color (f, face, fg, LFACE_FOREGROUND_INDEX);
1280 1281
}

1282

Gerd Moellmann's avatar
Gerd Moellmann committed
1283
/* Free color PIXEL on frame F.  */
1284

1285
void
Gerd Moellmann's avatar
Gerd Moellmann committed
1286
unload_color (f, pixel)
1287
     struct frame *f;
Gerd Moellmann's avatar
Gerd Moellmann committed
1288
     unsigned long pixel;
1289
{
1290
  Display *dpy = FRAME_X_DISPLAY (f);
Gerd Moellmann's avatar
Gerd Moellmann committed
1291 1292 1293 1294 1295
  int class = FRAME_X_DISPLAY_INFO (f)->visual->class;

  if (pixel == BLACK_PIX_DEFAULT (f)
      || pixel == WHITE_PIX_DEFAULT (f))
    return;
1296

1297
  BLOCK_INPUT;
Gerd Moellmann's avatar
Gerd Moellmann committed
1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388
  
  /* If display has an immutable color map, freeing colors is not
     necessary and some servers don't allow it.  So don't do it.  */
  if (! (class == StaticColor || class == StaticGray || class == TrueColor))
    {
      Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
      XFreeColors (dpy, cmap, &pixel, 1, 0);
    }
  
  UNBLOCK_INPUT;
}


/* Free colors allocated for FACE.  */

static void
free_face_colors (f, face)
     struct frame *f;
     struct face *face;
{
  int class = FRAME_X_DISPLAY_INFO (f)->visual->class;
  
  /* If display has an immutable color map, freeing colors is not
     necessary and some servers don't allow it.  So don't do it.  */
  if (class != StaticColor
      && class != StaticGray
      && class != TrueColor)
    {
      Display *dpy;
      Colormap cmap;
      
      BLOCK_INPUT;
      dpy = FRAME_X_DISPLAY (f);
      cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
      
      if (