Commit f211082d authored by Jim Blandy's avatar Jim Blandy
Browse files

*** empty log message ***

parent 440d350c
/* Must define frame->faces, frame->n_faces,
FRAME_NORMAL_FACE, FRAME_MODELINE_FACE. */
/* "Face" primitives
Copyright (C) 1992, 1993 Free Software Foundation.
......@@ -20,18 +17,7 @@ You should have received a copy of the GNU General Public License
along with GNU Emacs; see the file COPYING. If not, write to
the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
struct face
{
unsigned char underline;
unsigned char hilited;
unsigned char modif;
GC facegc;
XFontStruct * font;
unsigned long foreground;
unsigned long background;
Pixmap back_pixmap;
unsigned int pixmap_w, pixmap_h /* , pixmap_depth */;
};
/* This derived from work by Lucid (some parts very loosely so). */
#include <sys/types.h>
#include <sys/stat.h>
......@@ -41,9 +27,9 @@ struct face
#include "xterm.h"
#include "buffer.h"
#include "dispextern.h"
#include "frame.h"
#include "window.h"
#include "indent.h"
/* #include "window.h" */
/* Display Context for the icons */
#include <X11/Intrinsic.h>
......@@ -52,8 +38,8 @@ struct face
#include <X11/Xos.h>
/* We use face structures in two ways:
At the frame level, each frame has a vector of faces. (f->faces).
Face number 0 is the normal face (for normal text).
At the frame level, each frame has a vector of faces (FRAME_FACES).
Face number 0 is the default face (for normal text).
Face number 1 is the mode line face.
Higher face numbers have no built-in meaning.
The faces in these vectors are called "frame faces".
......@@ -81,8 +67,15 @@ int next_face_id;
#define FACE_DEFAULT (~0)
#define xfree free
Lisp_Object Qface, Qwindow, Qpriority;
static struct face *allocate_face ();
static void build_face ();
static int sort_overlays ();
static struct face *get_display_face ();
static Lisp_Object face_name_id_number ();
/* Make a new face that's a copy of an existing one. */
......@@ -95,7 +88,7 @@ copy_face (face)
result->font = face->font;
result->foreground = face->foreground;
result->background = face->background;
result->back_pixmap = face->back_pixmap;
result->stipple = face->stipple;
result->underline = face->underline;
return result;
......@@ -108,7 +101,7 @@ face_eql (face1, face2)
return (face1->font == face2->font
&& face1->foreground == face2->foreground
&& face1->background == face2->background
&& face1->back_pixmap == face2->back_pixmap
&& face1->stipple == face2->stipple
&& face1->underline == face2->underline);
}
......@@ -123,6 +116,7 @@ get_cached_face (f, face)
struct face *face;
{
int i, empty = -1;
struct face *result;
/* Look for an existing display face that does the job.
Also find an empty slot if any. */
......@@ -167,14 +161,15 @@ clear_face_vector ()
{
Lisp_Object rest;
Display *dpy = x_current_display;
int i;
BLOCK_INPUT;
/* Free the display faces in the face_vector. */
for (i = 0; i < nfaces; i++)
{
struct face *face = face_vector[i];
if (face->facegc)
XFreeGC (dpy, face->facegc);
if (face->gc)
XFreeGC (dpy, face->gc);
xfree (face);
}
nfaces = 0;
......@@ -182,7 +177,8 @@ clear_face_vector ()
UNBLOCK_INPUT;
}
/* Make a graphics context for face FACE, which is on frame F. */
/* Make a graphics context for face FACE, which is on frame F,
if that can be done. */
static void
build_face (f, face)
......@@ -193,18 +189,27 @@ build_face (f, face)
XGCValues xgcv;
unsigned long mask;
xgcv.foreground = face->foreground;
xgcv.background = face->background;
xgcv.font = face->font->fid;
if (face->foreground != FACE_DEFAULT)
xgcv.foreground = face->foreground;
else
xgcv. foreground = f->display.x->foreground_pixel;
if (face->background != FACE_DEFAULT)
xgcv.background = face->background;
else
xgcv. background = f->display.x->background_pixel;
if (face->font && (int) face->font != FACE_DEFAULT)
xgcv.font = face->font->fid;
else
xgcv.font = f->display.x->font->fid;
xgcv.graphics_exposures = 0;
mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
mask, &xgcv);
#if 0
if (face->back_pixmap && face->back_pixmap != FACE_DEFAULT)
XSetStipple (XtDisplay (f->display.x->widget), gc, face->back_pixmap);
if (face->stipple && face->stipple != FACE_DEFAULT)
XSetStipple (x_current_display, gc, face->stipple);
#endif
face->facegc = gc;
face->gc = gc;
}
/* Modify face TO by copying from FROM all properties which have
......@@ -222,20 +227,28 @@ merge_faces (from, to)
to->foreground = from->foreground;
if (from->background != FACE_DEFAULT)
to->background = from->background;
if (from->back_pixmap != FACE_DEFAULT)
to->back_pixmap = from->back_pixmap;
if (from->stipple != FACE_DEFAULT)
to->stipple = from->stipple;
if (from->underline)
to->underline = from->underline;
}
struct sortvec
{
Lisp_Object overlay;
int beg, end;
int priority;
};
/* Return the display face associated with a buffer position POS.
Store into *ENDPTR the position at which a different face is needed.
This does not take account of glyphs that specify their own face codes.
F is the frame in use for display. */
F is the frame in use for display, and W is the window. */
struct face *
compute_char_face (f, pos, endptr)
compute_char_face (f, w, pos, endptr)
struct frame *f;
struct window *w;
int pos;
int *endptr;
{
......@@ -247,6 +260,10 @@ compute_char_face (f, pos, endptr)
int endpos;
Lisp_Object *overlay_vec;
int len;
struct sortvec *sortvec;
Lisp_Object frame;
XSET (frame, Lisp_Frame, f);
XFASTINT (position) = pos;
prop = Fget_text_property (position, Qface);
......@@ -257,18 +274,21 @@ compute_char_face (f, pos, endptr)
/* Optimize the default case. */
if (noverlays == 0 && NILP (prop))
return FRAME_NORMAL_FACE (f);
return FRAME_DEFAULT_FACE (f);
bcopy (FRAME_NORMAL_FACE (f), &face, sizeof (struct face));
bcopy (FRAME_DEFAULT_FACE (f), &face, sizeof (struct face));
if (!NILP (prop))
{
facecode = Fface_name_id_number (prop);
if (facecode >= 0 && facecode < f->n_faces && f->faces[facecode] != 0)
merge_faces (f->faces[facecode], &face);
facecode = face_name_id_number (frame, prop);
if (facecode >= 0 && facecode < FRAME_N_FACES (f)
&& FRAME_FACES (f) [facecode] != 0)
merge_faces (FRAME_FACES (f) [facecode], &face);
}
/* Discard invalid overlays from the vector. */
/* Put the valid and relevant overlays into sortvec. */
sortvec = (struct sortvec *) alloca (noverlays * sizeof (struct sortvec));
for (i = 0, j = 0; i < noverlays; i++)
{
overlay = overlay_vec[i];
......@@ -276,11 +296,35 @@ compute_char_face (f, pos, endptr)
if (OVERLAY_VALID (overlay)
&& OVERLAY_POSITION (OVERLAY_START (overlay)) > 0
&& OVERLAY_POSITION (OVERLAY_END (overlay)) > 0)
overlay_vec[j++] = overlay;
{
Lisp_Object window;
window = Foverlay_get (overlay, Qwindow);
/* Also ignore overlays limited to one window
if it's not the window we are using. */
if (NILP (window) || XWINDOW (window) == w)
{
Lisp_Object tem;
/* This overlay is good and counts:
put it in sortvec. */
sortvec[j].overlay = overlay;
sortvec[j].beg = OVERLAY_POSITION (OVERLAY_START (overlay));
sortvec[j].end = OVERLAY_POSITION (OVERLAY_END (overlay));
tem = Foverlay_get (overlay, Qpriority);
if (INTEGERP (tem))
sortvec[j].priority = XINT (tem);
else
sortvec[j].priority = 0;
j++;
}
}
}
noverlays = j;
/* Sort the overlays into the proper order. */
/* Sort the overlays into the proper order: increasing priority. */
qsort (sortvec, noverlays, sizeof (struct sortvec), sort_overlays);
/* Now merge the overlay data in that order. */
......@@ -292,10 +336,10 @@ compute_char_face (f, pos, endptr)
Lisp_Object oend;
int oendpos;
facecode = Fface_name_id_number (prop);
if (facecode >= 0 && facecode < f->n_faces
&& f->faces[facecode] != 0)
merge_faces (f->faces[facecode], &face);
facecode = face_name_id_number (frame, prop);
if (facecode >= 0 && facecode < FRAME_N_FACES (f)
&& FRAME_FACES (f) [facecode] != 0)
merge_faces (FRAME_FACES (f) [facecode], &face);
oend = OVERLAY_END (overlay_vec[i]);
oendpos = OVERLAY_POSITION (oend);
......@@ -311,6 +355,19 @@ compute_char_face (f, pos, endptr)
return get_display_face (f, &face);
}
int
sort_overlays (s1, s2)
struct sortvec *s1, *s2;
{
if (s1->priority != s2->priority)
return s1->priority - s2->priority;
if (s1->beg != s2->beg)
return s1->beg - s2->beg;
if (s1->end != s2->end)
return s2->end - s1->end;
return 0;
}
/* Return the display face to use to display a special glyph
which selects FACE_CODE as the face ID,
assuming that ordinarily the face would be BASIC_FACE.
......@@ -326,8 +383,9 @@ compute_glyph_face (f, basic_face, face_code)
bcopy (basic_face, &face, sizeof (struct face));
if (face_code >= 0 && face_code < f->n_faces && f->faces[face_code] != 0)
merge_faces (f->faces[face_code], &face);
if (face_code >= 0 && face_code < FRAME_N_FACES (f)
&& FRAME_FACES (f) [face_code] != 0)
merge_faces (FRAME_FACES (f) [face_code], &face);
return get_display_face (f, &face);
}
......@@ -343,31 +401,31 @@ get_display_face (f, face)
struct face *result;
/* Does the face have a GC already? */
if (face->facegc)
if (face->gc)
return face;
/* If it's equivalent to the normal face, use that. */
if (face->font == FRAME_NORMAL_FACE (f)->font
&& face->foreground == FRAME_NORMAL_FACE (f)->foreground
&& face->background == FRAME_NORMAL_FACE (f)->background
&& face->back_pixmap == FRAME_NORMAL_FACE (f)->back_pixmap
&& face->underline == FRAME_NORMAL_FACE (f)->underline)
/* If it's equivalent to the default face, use that. */
if (face->font == FRAME_DEFAULT_FACE (f)->font
&& face->foreground == FRAME_DEFAULT_FACE (f)->foreground
&& face->background == FRAME_DEFAULT_FACE (f)->background
&& face->stipple == FRAME_DEFAULT_FACE (f)->stipple
&& face->underline == FRAME_DEFAULT_FACE (f)->underline)
{
if (!FRAME_NORMAL_FACE (f)->framegc)
build_frame (f, FRAME_NORMAL_FACE (f));
return FRAME_NORMAL_FACE (f);
if (!FRAME_DEFAULT_FACE (f)->gc)
build_face (f, FRAME_DEFAULT_FACE (f));
return FRAME_DEFAULT_FACE (f);
}
/* If it's equivalent to the mode line face, use that. */
if (face->font == FRAME_MODELINE_FACE (f)->font
&& face->foreground == FRAME_MODELINE_FACE (f)->foreground
&& face->background == FRAME_MODELINE_FACE (f)->background
&& face->back_pixmap == FRAME_MODELINE_FACE (f)->back_pixmap
&& face->underline == FRAME_MODELINE_FACE (f)->underline)
if (face->font == FRAME_MODE_LINE_FACE (f)->font
&& face->foreground == FRAME_MODE_LINE_FACE (f)->foreground
&& face->background == FRAME_MODE_LINE_FACE (f)->background
&& face->stipple == FRAME_MODE_LINE_FACE (f)->stipple
&& face->underline == FRAME_MODE_LINE_FACE (f)->underline)
{
if (!FRAME_MODELINE_FACE (f)->framegc)
build_frame (f, FRAME_MODELINE_FACE (f));
return FRAME_MODELINE_FACE (f);
if (!FRAME_MODE_LINE_FACE (f)->gc)
build_face (f, FRAME_MODE_LINE_FACE (f));
return FRAME_MODE_LINE_FACE (f);
}
/* Get a specialized display face. */
......@@ -384,7 +442,7 @@ allocate_face ()
result->font = (XFontStruct *) FACE_DEFAULT;
result->foreground = FACE_DEFAULT;
result->background = FACE_DEFAULT;
result->back_pixmap = FACE_DEFAULT;
result->stipple = FACE_DEFAULT;
return result;
}
......@@ -395,20 +453,25 @@ ensure_face_ready (f, id)
struct frame *f;
int id;
{
if (f->n_faces <= id)
if (FRAME_N_FACES (f) <= id)
{
int n = id + 10;
int i;
if (!f->n_faces)
f->faces = (struct face **) xmalloc (sizeof (struct face *) * n);
if (!FRAME_N_FACES (f))
FRAME_FACES (f)
= (struct face **) xmalloc (sizeof (struct face *) * n);
else
f->faces
= (struct face **) xrealloc (f->faces, sizeof (struct face *) * n);
FRAME_FACES (f)
= (struct face **) xrealloc (FRAME_FACES (f),
sizeof (struct face *) * n);
f->n_faces = n;
bzero (FRAME_FACES (f) + FRAME_N_FACES (f),
(n - FRAME_N_FACES (f)) * sizeof (struct face *));
FRAME_N_FACES (f) = n;
}
f->faces[id] = allocate_face ();
if (FRAME_FACES (f) [id] == 0)
FRAME_FACES (f) [id] = allocate_face ();
}
/* Allocating, freeing, and duplicating fonts, colors, and pixmaps. */
......@@ -459,7 +522,7 @@ load_color (f, name)
if (NILP (name))
return FACE_DEFAULT;
cmap = DefaultColormapOfScreen (x_screen);
cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
CHECK_STRING (name, 0);
BLOCK_INPUT;
......@@ -486,7 +549,7 @@ unload_color (f, pixel)
Display *dpy = x_current_display;
if (pixel == FACE_DEFAULT)
return;
cmap = DefaultColormapOfScreen (x_screen);
cmap = DefaultColormapOfScreen (DefaultScreenOfDisplay (x_current_display));
BLOCK_INPUT;
XFreeColors (dpy, cmap, &pixel, 1, 0);
UNBLOCK_INPUT;
......@@ -499,7 +562,7 @@ unload_color (f, pixel)
void
init_frame_faces (f)
struct frame f;
struct frame *f;
{
struct frame *other_frame = 0;
Lisp_Object rest;
......@@ -507,7 +570,7 @@ init_frame_faces (f)
for (rest = Vframe_list; !NILP (rest); rest = Fcdr (rest))
{
struct frame *f2 = XFRAME (Fcar (rest));
if (f2 != f && FRAME_IS_X (f2))
if (f2 != f && FRAME_X_P (f2))
{
other_frame = f2;
break;
......@@ -517,14 +580,15 @@ init_frame_faces (f)
if (other_frame)
{
/* Make sure this frame's face vector is as big as the others. */
f->n_faces = other_frame->n_faces;
f->faces = (struct face **) xmalloc (f->n_faces * sizeof (struct face *));
FRAME_N_FACES (f) = FRAME_N_FACES (other_frame);
FRAME_FACES (f)
= (struct face **) xmalloc (FRAME_N_FACES (f) * sizeof (struct face *));
/* Make sure the frame has the two basic faces. */
FRAME_NORMAL_FACE (f)
= copy_face (FRAME_NORMAL_FACE (other_frame));
FRAME_MODELINE_FACE (f)
= copy_face (FRAME_MODELINE_FACE (other_frame));
FRAME_DEFAULT_FACE (f)
= copy_face (FRAME_DEFAULT_FACE (other_frame));
FRAME_MODE_LINE_FACE (f)
= copy_face (FRAME_MODE_LINE_FACE (other_frame));
}
}
......@@ -538,22 +602,24 @@ free_screen_faces (f)
Display *dpy = x_current_display;
int i;
for (i = 0; i < f->n_faces; i++)
for (i = 0; i < FRAME_N_FACES (f); i++)
{
struct face *face = f->faces [i];
struct face *face = FRAME_FACES (f) [i];
if (! face)
continue;
if (face->facegc)
XFreeGC (dpy, face->facegc);
if (face->gc)
XFreeGC (dpy, face->gc);
unload_font (f, face->font);
unload_color (f, face->foreground);
unload_color (f, face->background);
unload_pixmap (f, face->back_pixmap);
#if 0
unload_pixmap (f, face->stipple);
#endif
xfree (face);
}
xfree (f->faces);
f->faces = 0;
f->n_faces = 0;
xfree (FRAME_FACES (f));
FRAME_FACES (f) = 0;
FRAME_N_FACES (f) = 0;
}
......@@ -587,9 +653,9 @@ DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
Lisp_Object rest;
int id = XINT (face_id);
CHECK_FIXNUM (face_id, 0);
if (id < 0)
error ("Face id must be nonnegative");
CHECK_NUMBER (face_id, 0);
if (id < 0 || id >= next_face_id)
error ("Face id out of range");
for (rest = Vframe_list; !NILP (rest); rest = XCONS (rest)->cdr)
{
......@@ -611,67 +677,47 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
int id;
CHECK_FRAME (frame, 0);
CHECK_FIXNUM (face_id, 0);
CHECK_NUMBER (face_id, 0);
CHECK_SYMBOL (attr_name, 0);
f = XFRAME (frame);
id = XINT (face_id);
if (id < 0)
Fsignal (Qerror, Fcons (build_string ("invalid face id"),
Fcons (face_id, Fcons (frame, Qnil))));
if (id < 0 || id >= next_face_id)
error ("Face id out of range");
ensure_face_ready (f, id);
face = f->faces [XFASTINT (face_id)];
if (! face) abort ();
magic_p = (NILP (attr_value) && XFASTINT (face_id) <= 1);
face = FRAME_FACES (f) [XFASTINT (face_id)];
if (EQ (attr_name, intern ("font")))
{
#ifdef HAVE_X_WINDOWS
XFontStruct *font;
if (magic_p)
error ("font of the `normal' or `modeline' face may not be nil");
font = load_font (f, attr_value);
XFontStruct *font = load_font (f, attr_value);
unload_font (f, face->font);
face->font = font;
#endif /* HAVE_X_WINDOWS */
}
else if (EQ (attr_name, intern ("foreground")))
{
#ifdef HAVE_X_WINDOWS
unsigned long new_color;
if (magic_p)
error ("forground color of the `normal' or `modeline' face may not be nil");
new_color = load_color (f, attr_value);
unsigned long new_color = load_color (f, attr_value);
unload_color (f, face->foreground);
face->foreground = new_color;
#endif /* HAVE_X_WINDOWS */
}
else if (EQ (attr_name, intern ("background")))
{
#ifdef HAVE_X_WINDOWS
unsigned long new_color;
if (magic_p)
error ("background color of the `normal' or `modeline' face may not be nil");
new_color = load_color (f, attr_value);
unsigned long new_color = load_color (f, attr_value);
unload_color (f, face->background);
face->background = new_color;
#endif /* HAVE_X_WINDOWS */
}
#if 0
else if (EQ (attr_name, intern ("background-pixmap")))
{
#ifdef HAVE_X_WINDOWS
unsigned int w, h, d;
unsigned long new_pixmap = load_pixmap (f, attr_value, &w, &h, &d, 0);
unload_pixmap (f, face->back_pixmap);
if (magic_p) new_pixmap = 0;
face->back_pixmap = new_pixmap;
unload_pixmap (f, face->stipple);
if (NILP (attr_value))
new_pixmap = 0;
face->stipple = new_pixmap;
face->pixmap_w = w;
face->pixmap_h = h;
/* face->pixmap_depth = d; */
#endif /* HAVE_X_WINDOWS */
}
#endif /* 0 */
else if (EQ (attr_name, intern ("underline")))
......@@ -685,16 +731,18 @@ DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
if (id == 0)
{
BLOCK_INPUT;
XFreeGC (dpy, FRAME_NORMAL_FACE (f)->facegc);
build_face (f, FRAME_NORMAL_FACE (f));
if (FRAME_DEFAULT_FACE (f)->gc != 0)
XFreeGC (x_current_display, FRAME_DEFAULT_FACE (f)->gc);
build_face (f, FRAME_DEFAULT_FACE (f));
UNBLOCK_INPUT;
}
if (id == 1)
{
BLOCK_INPUT;
XFreeGC (dpy, FRAME_NORMAL_FACE (f)->facegc);
build_face (f, FRAME_NORMAL_FACE (f));
if (FRAME_MODE_LINE_FACE (f)->gc != 0)
XFreeGC (x_current_display, FRAME_MODE_LINE_FACE (f)->gc);
build_face (f, FRAME_MODE_LINE_FACE (f));
UNBLOCK_INPUT;
}
......@@ -707,10 +755,36 @@ DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
{
return make_number (next_face_id++);
}
/* Return the face id for name NAME on frame FRAME.
(It should be the same for all frames,
but it's as easy to use the "right" frame to look it up
as to use any other one.) */
static Lisp_Object
face_name_id_number (frame, name)
Lisp_Object frame, name;
{
Lisp_Object tem;
CHECK_FRAME (frame, 0);
tem = Fcdr (Fassq (name, XFRAME (frame)->face_alist));
CHECK_VECTOR (tem, 0);
tem = XVECTOR (tem)->contents[2];
CHECK_NUMBER (tem, 0);
return XINT (tem);
}
void
syms_of_faces ()
syms_of_xfaces ()
{
Qwindow = intern ("window");
staticpro (&Qwindow);
Qface = intern ("face");
staticpro (&Qface);
Qpriority = intern ("priority");
staticpro (&Qpriority);
defsubr (&Sframe_face_alist);
defsubr (&Sset_frame_face_alist);
defsubr (&Smake_face_internal);
......