comparison src/xfaces.c @ 2336:7aaafd275bec

Initial revision
author Jim Blandy <jimb@redhat.com>
date Tue, 23 Mar 1993 08:06:31 +0000
parents
children f881f2936eec
comparison
equal deleted inserted replaced
2335:e5a37be50b36 2336:7aaafd275bec
1 /* "Face" primitives
2 This file is part of GNU Emacs.
3
4 GNU Emacs is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 1, or (at your option)
7 any later version.
8
9 GNU Emacs is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Emacs; see the file COPYING. If not, write to
16 the 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. */
38 struct face **face_vector;
39 /* The length in use of the table. */
40 int nfaces;
41 /* The allocated length of the table. */
42 int nfaces_allocated;
43
44 /* The number of face-id's in use (same for all frames). */
45 int next_face_id;
46
47 static struct face *allocate_face ();
48 static void build_face ();
49
50 /* Make a new face that's a copy of an existing one. */
51
52 static struct face *
53 copy_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
67 static int
68 face_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
83 static struct face *
84 get_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
128 void
129 clear_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
148 /* Make a graphics context for face FACE, which is on frame F. */
149
150 static void
151 build_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
173 /* Given a frame face, return an equivalent display face
174 (one which has a graphics context). */
175
176 static struct face *
177 get_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
216 /* Allocate a new face */
217 static struct face *
218 allocate_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
227 void
228 ensure_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
248 /* Allocating, freeing, and duplicating fonts, colors, and pixmaps. */
249
250 #ifdef HAVE_X_WINDOWS
251
252 static XFontStruct *
253 load_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
270 static void
271 unload_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
280 static unsigned long
281 load_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
308 static void
309 unload_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
326 /* frames */
327
328 void
329 init_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
362 void
363 free_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
388 /* Lisp interface */
389
390 DEFUN ("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
399 DEFUN ("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
410 DEFUN ("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
431 DEFUN ("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
532 DEFUN ("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
539 void
540 syms_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 }