Mercurial > emacs
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 } |