Initial revision
[bpt/emacs.git] / src / xfaces.c
CommitLineData
c115973b
JB
1/* "Face" primitives
2This file is part of GNU Emacs.
3
4GNU Emacs is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License as published by
6the Free Software Foundation; either version 1, or (at your option)
7any later version.
8
9GNU Emacs is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12GNU General Public License for more details.
13
14You should have received a copy of the GNU General Public License
15along with GNU Emacs; see the file COPYING. If not, write to
16the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
17
18#include <sys/types.h>
19#include <sys/stat.h>
20
21#include "config.h"
22#include "lisp.h"
23
24#include "xterm.h"
25#include "buffer.h"
26#include "extents.h"
27#include "screen.h"
28#include "window.h"
29#include "indent.h"
30
31/* Display Context for the icons */
32#include <X11/Intrinsic.h>
33#include <X11/StringDefs.h>
34#include <X11/Xmu/Drawing.h>
35#include <X11/Xos.h>
36
37/* A table of display faces. */
38struct face **face_vector;
39/* The length in use of the table. */
40int nfaces;
41/* The allocated length of the table. */
42int nfaces_allocated;
43
44/* The number of face-id's in use (same for all frames). */
45int next_face_id;
46
47static struct face *allocate_face ();
48static void build_face ();
49\f
50/* Make a new face that's a copy of an existing one. */
51
52static struct face *
53copy_face (face)
54 struct face *face;
55{
56 struct face *result = allocate_face ();
57
58 result->font = face->font;
59 result->foreground = face->foreground;
60 result->background = face->background;
61 result->back_pixmap = face->back_pixmap;
62 result->underline = face->underline;
63
64 return result;
65}
66
67static int
68face_eql (face1, face2)
69 struct face *face1, *face2;
70{
71 return (face1->font == face2->font
72 && face1->foreground == face2->foreground
73 && face1->background == face2->background
74 && face1->back_pixmap == face2->back_pixmap
75 && face1->underline == face2->underline);
76}
77
78/* Return the unique display face corresponding to the user-level face FACE.
79
80 If there isn't one, make one, and find a slot in the face_vector to
81 put it in. */
82
83static struct face *
84get_vector_face (f, face)
85 struct frame *f;
86 struct face *face;
87{
88 int i, empty = -1;
89
90 /* Look for an existing display face that does the job.
91 Also find an empty slot if any. */
92 for (i = 0; i < nfaces; i++)
93 {
94 if (face_eql (face_vector[i], face))
95 return face_vector[i];
96 if (face_vector[i] == 0)
97 empty = i;
98 }
99
100 /* If no empty slots, make one. */
101 if (empty < 0 && nfaces == nfaces_allocated)
102 {
103 int newsize = nfaces + 20;
104 face_vector
105 = (struct face **) xrealloc (face_vector,
106 newsize * sizeof (struct face *));
107 nfaces_allocated = newsize;
108 }
109
110 if (empty < 0)
111 empty = nfaces++;
112
113 /* Put a new display face in the empty slot. */
114 result = copy_face (face);
115 face_vector[empty] = result;
116
117 /* Make a graphics context for it. */
118 build_face (f, result);
119
120 return result;
121}
122
123/* Clear out face_vector and start anew.
124 This should be done from time to time just to avoid
125 keeping too many graphics contexts in face_vector
126 that are no longer needed. */
127
128void
129clear_face_vector ()
130{
131 Lisp_Object rest;
132 Display *dpy = x_current_display;
133
134 BLOCK_INPUT;
135 /* Free the display faces in the face_vector. */
136 for (i = 0; i < nfaces; i++)
137 {
138 struct face *face = face_vector[i];
139 if (face->facegc)
140 XFreeGC (dpy, face->facegc);
141 xfree (face);
142 }
143 nfaces = 0;
144
145 UNBLOCK_INPUT;
146}
147\f
148/* Make a graphics context for face FACE, which is on frame F. */
149
150static void
151build_face (f, face)
152 struct frame* f;
153 struct face* face;
154{
155 GC gc;
156 XGCValues xgcv;
157 unsigned long mask;
158
159 xgcv.foreground = face->foreground;
160 xgcv.background = face->background;
161 xgcv.font = face->font->fid;
162 xgcv.graphics_exposures = 0;
163 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
164 gc = XCreateGC (x_current_display, FRAME_X_WINDOW (f),
165 mask, &xgcv);
166#if 0
167 if (face->back_pixmap && face->back_pixmap != FACE_DEFAULT)
168 XSetStipple (XtDisplay (f->display.x->widget), gc, face->back_pixmap);
169#endif
170 face->facegc = gc;
171}
172\f
173/* Given a frame face, return an equivalent display face
174 (one which has a graphics context). */
175
176static struct face *
177get_display_face (f, face)
178 struct frame *f;
179 struct face *face;
180{
181 struct face *result;
182
183 /* Does the face have a GC already? */
184 if (face->facegc)
185 return face;
186
187 /* If it's equivalent to the normal face, use that. */
188 if (face->font == FRAME_NORMAL_FACE (f)->font
189 && face->foreground == FRAME_NORMAL_FACE (f)->foreground
190 && face->background == FRAME_NORMAL_FACE (f)->background
191 && face->back_pixmap == FRAME_NORMAL_FACE (f)->back_pixmap
192 && face->underline == FRAME_NORMAL_FACE (f)->underline)
193 {
194 if (!FRAME_NORMAL_FACE (f)->framegc)
195 build_frame (f, FRAME_NORMAL_FACE (f));
196 return FRAME_NORMAL_FACE (f);
197 }
198
199 /* If it's equivalent to the mode line face, use that. */
200 if (face->font == FRAME_MODELINE_FACE (f)->font
201 && face->foreground == FRAME_MODELINE_FACE (f)->foreground
202 && face->background == FRAME_MODELINE_FACE (f)->background
203 && face->back_pixmap == FRAME_MODELINE_FACE (f)->back_pixmap
204 && face->underline == FRAME_MODELINE_FACE (f)->underline)
205 {
206 if (!FRAME_MODELINE_FACE (f)->framegc)
207 build_frame (f, FRAME_MODELINE_FACE (f));
208 return FRAME_MODELINE_FACE (f);
209 }
210
211 /* Get a specialized display face. */
212 return get_cached_face (f, face);
213}
214
215\f
216/* Allocate a new face */
217static struct face *
218allocate_face ()
219{
220 struct face *result = (struct face *) xmalloc (sizeof (struct face));
221 bzero (result, sizeof (struct face));
222 return result;
223}
224
225/* Make face id ID valid on frame F. */
226
227void
228ensure_face_ready (f, id)
229 struct frame *f;
230 int id;
231{
232 if (f->n_faces <= id)
233 {
234 int n = id + 10;
235 int i;
236 if (!f->n_faces)
237 f->faces = (struct face **) xmalloc (sizeof (struct face *) * n);
238 else
239 f->faces
240 = (struct face **) xrealloc (f->faces, sizeof (struct face *) * n);
241
242 f->n_faces = n;
243 }
244
245 f->faces[id] = allocate_face ();
246}
247\f
248/* Allocating, freeing, and duplicating fonts, colors, and pixmaps. */
249
250#ifdef HAVE_X_WINDOWS
251
252static XFontStruct *
253load_font (f, name)
254 struct frame *f;
255 Lisp_Object name;
256{
257 XFontStruct *font;
258
259 CHECK_STRING (name, 0);
260 BLOCK_INPUT;
261 font = XLoadQueryFont (x_current_display, (char *) XSTRING (name)->data);
262 UNBLOCK_INPUT;
263
264 if (! font)
265 Fsignal (Qerror, Fcons (build_string ("undefined font"),
266 Fcons (name, Qnil)));
267 return font;
268}
269
270static void
271unload_font (f, font)
272 struct frame *f;
273 XFontStruct *font;
274{
275 if (!font || font == ((XFontStruct *) FACE_DEFAULT))
276 return;
277 XFreeFont (x_current_display, font);
278}
279
280static unsigned long
281load_color (f, name)
282 struct frame *f;
283 Lisp_Object name;
284{
285 Display *dpy = x_current_display;
286 Colormap cmap;
287 XColor color;
288 int result;
289
290 cmap = DefaultColormapOfScreen (x_screen);
291
292 CHECK_STRING (name, 0);
293 BLOCK_INPUT;
294 result = XParseColor (dpy, cmap, (char *) XSTRING (name)->data, &color);
295 UNBLOCK_INPUT;
296 if (! result)
297 Fsignal (Qerror, Fcons (build_string ("undefined color"),
298 Fcons (name, Qnil)));
299 BLOCK_INPUT;
300 result = XAllocColor (dpy, cmap, &color);
301 UNBLOCK_INPUT;
302 if (! result)
303 Fsignal (Qerror, Fcons (build_string ("X server cannot allocate color"),
304 Fcons (name, Qnil)));
305 return (unsigned long) color.pixel;
306}
307
308static void
309unload_color (f, pixel)
310 struct frame *f;
311 Pixel pixel;
312{
313 Colormap cmap;
314 Display *dpy = x_current_display;
315 if (pixel == FACE_DEFAULT)
316 return;
317 cmap = DefaultColormapOfScreen (x_screen);
318 BLOCK_INPUT;
319 XFreeColors (dpy, cmap, &pixel, 1, 0);
320 UNBLOCK_INPUT;
321}
322
323#endif /* HAVE_X_WINDOWS */
324
325\f
326/* frames */
327
328void
329init_frame_faces (f)
330 struct frame f;
331{
332 struct frame *other_frame = 0;
333 Lisp_Object rest;
334
335 for (rest = Vframe_list; !NILP (rest); rest = Fcdr (rest))
336 {
337 struct frame *f2 = XFRAME (Fcar (rest));
338 if (f2 != f && FRAME_IS_X (f2))
339 {
340 other_frame = f2;
341 break;
342 }
343 }
344
345 if (other_frame)
346 {
347 /* Make sure this frame's face vector is as big as the others. */
348 f->n_faces = other_frame->n_faces;
349 f->faces = (struct face **) xmalloc (f->n_faces * sizeof (struct face *));
350
351 /* Make sure the frame has the two basic faces. */
352 FRAME_NORMAL_FACE (f)
353 = copy_face (FRAME_NORMAL_FACE (other_frame));
354 FRAME_MODELINE_FACE (f)
355 = copy_face (FRAME_MODELINE_FACE (other_frame));
356 }
357}
358
359
360/* Called from Fdelete_frame? */
361
362void
363free_screen_faces (f)
364 struct frame *f;
365{
366 Display *dpy = x_current_display;
367 int i;
368
369 for (i = 0; i < f->n_faces; i++)
370 {
371 struct face *face = f->faces [i];
372 if (! face)
373 continue;
374 if (face->facegc)
375 XFreeGC (dpy, face->facegc);
376 unload_font (f, face->font);
377 unload_color (f, face->foreground);
378 unload_color (f, face->background);
379 unload_pixmap (f, face->back_pixmap);
380 xfree (face);
381 }
382 xfree (f->faces);
383 f->faces = 0;
384 f->n_faces = 0;
385}
386
387\f
388/* Lisp interface */
389
390DEFUN ("frame-face-alist", Fframe_face_alist, Sframe_face_alist, 1, 1, 0,
391 "")
392 (frame)
393 Lisp_Object frame;
394{
395 CHECK_FRAME (frame, 0);
396 return XFRAME (frame)->face_alist;
397}
398
399DEFUN ("set-frame-face-alist", Fset_frame_face_alist, Sset_frame_face_alist,
400 2, 2, 0, "")
401 (frame, value)
402 Lisp_Object frame, value;
403{
404 CHECK_FRAME (frame, 0);
405 XFRAME (frame)->face_alist = value;
406 return value;
407}
408
409
410DEFUN ("make-face-internal", Fmake_face_internal, Smake_face_internal, 1, 1, 0,
411 "Create face number FACE-ID on all frames.")
412 (face_id)
413 Lisp_Object face_id;
414{
415 Lisp_Object rest;
416 int id = XINT (face_id);
417
418 CHECK_FIXNUM (face_id, 0);
419 if (id < 0)
420 error ("Face id must be nonnegative");
421
422 for (rest = Vframe_list; !NILP (rest); rest = XCONS (rest)->cdr)
423 {
424 struct frame *f = XFRAME (XCONS (rest)->car);
425 ensure_face_ready (f, id);
426 }
427 return Qnil;
428}
429
430
431DEFUN ("set-face-attribute-internal", Fset_face_attribute_internal,
432 Sset_face_attribute_internal, 4, 4, 0, "")
433 (face_id, attr_name, attr_value, frame)
434 Lisp_Object face_id, attr_name, attr_value, frame;
435{
436 struct face *face;
437 struct frame *f;
438 int magic_p;
439 int id;
440
441 CHECK_FRAME (frame, 0);
442 CHECK_FIXNUM (face_id, 0);
443 CHECK_SYMBOL (attr_name, 0);
444
445 f = XFRAME (frame);
446 id = XINT (face_id);
447 if (id < 0)
448 Fsignal (Qerror, Fcons (build_string ("invalid face id"),
449 Fcons (face_id, Fcons (frame, Qnil))));
450
451 ensure_face_ready (f, id);
452 face = f->faces [XFASTINT (face_id)];
453 if (! face) abort ();
454
455 magic_p = (NILP (attr_value) && XFASTINT (face_id) <= 1);
456
457 if (EQ (attr_name, intern ("font")))
458 {
459#ifdef HAVE_X_WINDOWS
460 XFontStruct *font;
461 if (magic_p)
462 error ("font of the `normal' or `modeline' face may not be nil");
463 font = load_font (f, attr_value);
464 unload_font (f, face->font);
465 face->font = font;
466#endif /* HAVE_X_WINDOWS */
467 }
468 else if (EQ (attr_name, intern ("foreground")))
469 {
470#ifdef HAVE_X_WINDOWS
471 unsigned long new_color;
472 if (magic_p)
473 error ("forground color of the `normal' or `modeline' face may not be nil");
474 new_color = load_color (f, attr_value);
475 unload_color (f, face->foreground);
476 face->foreground = new_color;
477#endif /* HAVE_X_WINDOWS */
478 }
479 else if (EQ (attr_name, intern ("background")))
480 {
481#ifdef HAVE_X_WINDOWS
482 unsigned long new_color;
483 if (magic_p)
484 error ("background color of the `normal' or `modeline' face may not be nil");
485 new_color = load_color (f, attr_value);
486 unload_color (f, face->background);
487 face->background = new_color;
488#endif /* HAVE_X_WINDOWS */
489 }
490#if 0
491 else if (EQ (attr_name, intern ("background-pixmap")))
492 {
493#ifdef HAVE_X_WINDOWS
494 unsigned int w, h, d;
495 unsigned long new_pixmap = load_pixmap (f, attr_value, &w, &h, &d, 0);
496 unload_pixmap (f, face->back_pixmap);
497 if (magic_p) new_pixmap = 0;
498 face->back_pixmap = new_pixmap;
499 face->pixmap_w = w;
500 face->pixmap_h = h;
501/* face->pixmap_depth = d; */
502#endif /* HAVE_X_WINDOWS */
503 }
504#endif /* 0 */
505 else if (EQ (attr_name, intern ("underline")))
506 {
507 int new = !NILP (attr_value);
508 face->underline = new;
509 }
510 else
511 error ("unknown face attribute");
512
513 if (id == 0)
514 {
515 BLOCK_INPUT;
516 XFreeGC (dpy, FRAME_NORMAL_FACE (f)->facegc);
517 build_face (f, FRAME_NORMAL_FACE (f));
518 UNBLOCK_INPUT;
519 }
520
521 if (id == 1)
522 {
523 BLOCK_INPUT;
524 XFreeGC (dpy, FRAME_NORMAL_FACE (f)->facegc);
525 build_face (f, FRAME_NORMAL_FACE (f));
526 UNBLOCK_INPUT;
527 }
528
529 return Qnil;
530}
531
532DEFUN ("internal-next-face-id", Finternal_next_face_id, Sinternal_next_face_id,
533 0, 0, 0, "")
534 ()
535{
536 return make_number (next_face_id++);
537}
538\f
539void
540syms_of_faces ()
541{
542 defsubr (&Sframe_face_alist);
543 defsubr (&Sset_frame_face_alist);
544 defsubr (&Smake_face_internal);
545 defsubr (&Sset_face_attribute_internal);
546 defsubr (&Sinternal_next_face_id);
547}