OpenSSL build fixes from Nelson
[sxemacs] / src / objects.c
1 /* Generic Objects and Functions.
2    Copyright (C) 1995 Free Software Foundation, Inc.
3    Copyright (C) 1995 Board of Trustees, University of Illinois.
4    Copyright (C) 1995, 1996 Ben Wing.
5
6 This file is part of SXEmacs
7
8 SXEmacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 SXEmacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
20
21
22 /* Synched up with: Not in FSF. */
23
24 #include <config.h>
25 #include "lisp.h"
26
27 #include "ui/device.h"
28 #include "elhash.h"
29 #include "ui/faces.h"
30 #include "ui/frame.h"
31 #include "ui/objects.h"
32 #include "specifier.h"
33 #include "ui/window.h"
34
35 /* Objects that are substituted when an instantiation fails.
36    If we leave in the Qunbound value, we will probably get crashes. */
37 Lisp_Object Vthe_null_color_instance, Vthe_null_font_instance;
38
39 /* Authors: Ben Wing, Chuck Thompson */
40
41 void finalose(void *ptr)
42 {
43         Lisp_Object obj;
44         XSETOBJ(obj, ptr);
45
46         signal_simple_error
47             ("Can't dump an emacs containing window system objects", obj);
48 }
49 \f
50 /****************************************************************************
51  *                       Color-Instance Object                              *
52  ****************************************************************************/
53
54 Lisp_Object Qcolor_instancep;
55
56 static Lisp_Object mark_color_instance(Lisp_Object obj)
57 {
58         Lisp_Color_Instance *c = XCOLOR_INSTANCE(obj);
59         mark_object(c->name);
60         if (!NILP(c->device))   /* Vthe_null_color_instance */
61                 MAYBE_DEVMETH(XDEVICE(c->device), mark_color_instance, (c));
62
63         return c->device;
64 }
65
66 static void
67 print_color_instance(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
68 {
69         Lisp_Color_Instance *c = XCOLOR_INSTANCE(obj);
70         if (print_readably)
71                 error("printing unreadable object #<color-instance 0x%x>",
72                       c->header.uid);
73         write_c_string("#<color-instance ", printcharfun);
74         print_internal(c->name, printcharfun, 0);
75         write_c_string(" on ", printcharfun);
76         print_internal(c->device, printcharfun, 0);
77         if (!NILP(c->device))   /* Vthe_null_color_instance */
78                 MAYBE_DEVMETH(XDEVICE(c->device), print_color_instance,
79                               (c, printcharfun, escapeflag));
80         write_fmt_str(printcharfun, " 0x%x>", c->header.uid);
81 }
82
83 static void finalize_color_instance(void *header, int for_disksave)
84 {
85         Lisp_Color_Instance *c = (Lisp_Color_Instance *) header;
86
87         if (!NILP(c->device)) {
88                 if (for_disksave)
89                         finalose(c);
90                 MAYBE_DEVMETH(XDEVICE(c->device), finalize_color_instance, (c));
91         }
92 }
93
94 static int color_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
95 {
96         Lisp_Color_Instance *c1 = XCOLOR_INSTANCE(obj1);
97         Lisp_Color_Instance *c2 = XCOLOR_INSTANCE(obj2);
98
99         return (c1 == c2) ||
100             (EQ(c1->device, c2->device) &&
101              DEVICEP(c1->device) &&
102              HAS_DEVMETH_P(XDEVICE(c1->device), color_instance_equal) &&
103              DEVMETH(XDEVICE(c1->device), color_instance_equal,
104                      (c1, c2, depth)));
105 }
106
107 static unsigned long color_instance_hash(Lisp_Object obj, int depth)
108 {
109         Lisp_Color_Instance *c = XCOLOR_INSTANCE(obj);
110         struct device *d = DEVICEP(c->device) ? XDEVICE(c->device) : 0;
111
112         return HASH2((unsigned long)d, !d ? LISP_HASH(obj)
113                      : DEVMETH_OR_GIVEN(d, color_instance_hash, (c, depth),
114                                         LISP_HASH(obj)));
115 }
116
117 DEFINE_LRECORD_IMPLEMENTATION("color-instance", color_instance,
118                               mark_color_instance, print_color_instance,
119                               finalize_color_instance, color_instance_equal,
120                               color_instance_hash, 0, Lisp_Color_Instance);
121 \f
122 DEFUN("make-color-instance", Fmake_color_instance, 1, 3, 0,     /*
123 Return a new `color-instance' object named NAME (a string).
124
125 Optional argument DEVICE specifies the device this object applies to
126 and defaults to the selected device.
127
128 An error is signaled if the color is unknown or cannot be allocated;
129 however, if optional argument NOERROR is non-nil, nil is simply
130 returned in this case. (And if NOERROR is other than t, a warning may
131 be issued.)
132
133 The returned object is a normal, first-class lisp object.  The way you
134 `deallocate' the color is the way you deallocate any other lisp object:
135 you drop all pointers to it and allow it to be garbage collected.  When
136 these objects are GCed, the underlying window-system data (e.g. X object)
137 is deallocated as well.
138 */
139       (name, device, noerror))
140 {
141         Lisp_Color_Instance *c;
142         Lisp_Object val = Qnil;
143         Lisp_Object dev = Qnil;
144         int retval = 0;
145         int count = specpdl_depth();
146         struct gcpro gcpro1, gcpro2;
147
148         CHECK_STRING(name);
149         XSETDEVICE(dev, decode_device(device));
150
151         c = alloc_lcrecord_type(Lisp_Color_Instance, &lrecord_color_instance);
152         c->name = name;
153         c->device = dev;
154         c->data = 0;
155
156         XSETCOLOR_INSTANCE(val, c);
157         GCPRO2(val,dev);
158         retval = MAYBE_INT_DEVMETH(XDEVICE(dev), initialize_color_instance,
159                                    (c, name, dev,
160                                     decode_error_behavior_flag(noerror)));
161         if (!retval) {
162           unbind_to(count, Qnil);
163           UNGCPRO;
164           return Qnil;
165         }
166
167         XSETCOLOR_INSTANCE(val, c);
168         unbind_to(count, Qnil);
169         UNGCPRO;
170         return val;
171 }
172
173 DEFUN("color-instance-p", Fcolor_instance_p, 1, 1, 0,   /*
174 Return non-nil if OBJECT is a color instance.
175 */
176       (object))
177 {
178         return COLOR_INSTANCEP(object) ? Qt : Qnil;
179 }
180
181 DEFUN("color-instance-name", Fcolor_instance_name, 1, 1, 0,     /*
182 Return the name used to allocate COLOR-INSTANCE.
183 */
184       (color_instance))
185 {
186         CHECK_COLOR_INSTANCE(color_instance);
187         return XCOLOR_INSTANCE(color_instance)->name;
188 }
189
190 DEFUN("color-instance-rgb-components", Fcolor_instance_rgb_components, 1, 1, 0, /*
191 Return a three element list containing the red, green, and blue
192 color components of COLOR-INSTANCE, or nil if unknown.
193 Component values range from 0 to 65535.
194 */
195       (color_instance))
196 {
197         Lisp_Color_Instance *c;
198
199         CHECK_COLOR_INSTANCE(color_instance);
200         c = XCOLOR_INSTANCE(color_instance);
201
202         if (NILP(c->device))
203                 return Qnil;
204
205         return MAYBE_LISP_DEVMETH(XDEVICE(c->device),
206                                   color_instance_rgb_components, (c));
207 }
208
209 DEFUN("valid-color-name-p", Fvalid_color_name_p, 1, 2, 0,       /*
210 Return true if COLOR names a valid color for the current device.
211
212 Valid color names for X are listed in the file /usr/lib/X11/rgb.txt, or
213 whatever the equivalent is on your system.
214
215 Valid color names for TTY are those which have an ISO 6429 (ANSI) sequence.
216 In addition to being a color this may be one of a number of attributes
217 such as `blink'.
218 */
219       (color, device))
220 {
221         struct device *d = decode_device(device);
222
223         CHECK_STRING(color);
224         return MAYBE_INT_DEVMETH(d, valid_color_name_p, (d, color)) ? Qt : Qnil;
225 }
226 \f
227 /***************************************************************************
228  *                       Font-Instance Object                              *
229  ***************************************************************************/
230
231 Lisp_Object Qfont_instancep;
232
233 static Lisp_Object font_instance_truename_internal(Lisp_Object xfont,
234                                                    Error_behavior errb);
235
236 static Lisp_Object mark_font_instance(Lisp_Object obj)
237 {
238         Lisp_Font_Instance *f = XFONT_INSTANCE(obj);
239
240         mark_object(f->name);
241         if (!NILP(f->device))   /* Vthe_null_font_instance */
242                 MAYBE_DEVMETH(XDEVICE(f->device), mark_font_instance, (f));
243
244         return f->device;
245 }
246
247 static void
248 print_font_instance(Lisp_Object obj, Lisp_Object printcharfun, int escapeflag)
249 {
250         Lisp_Font_Instance *f = XFONT_INSTANCE(obj);
251         if (print_readably)
252                 error("printing unreadable object #<font-instance 0x%x>",
253                       f->header.uid);
254         write_c_string("#<font-instance ", printcharfun);
255         print_internal(f->name, printcharfun, 1);
256         write_c_string(" on ", printcharfun);
257         print_internal(f->device, printcharfun, 0);
258         if (!NILP(f->device))
259                 MAYBE_DEVMETH(XDEVICE(f->device), print_font_instance,
260                               (f, printcharfun, escapeflag));
261         write_fmt_str(printcharfun, " 0x%x>", f->header.uid);
262 }
263
264 static void finalize_font_instance(void *header, int for_disksave)
265 {
266         Lisp_Font_Instance *f = (Lisp_Font_Instance *) header;
267
268         if (!NILP(f->device)) {
269                 if (for_disksave)
270                         finalose(f);
271                 MAYBE_DEVMETH(XDEVICE(f->device), finalize_font_instance, (f));
272         }
273 }
274
275 /* Fonts are equal if they resolve to the same name.
276    Since we call `font-truename' to do this, and since font-truename is lazy,
277    this means the `equal' could cause XListFonts to be run the first time.
278  */
279 static int font_instance_equal(Lisp_Object obj1, Lisp_Object obj2, int depth)
280 {
281         /* #### should this be moved into a device method? */
282         return
283             internal_equal(font_instance_truename_internal(obj1, ERROR_ME_NOT),
284                            font_instance_truename_internal(obj2, ERROR_ME_NOT),
285                            depth + 1);
286 }
287
288 static unsigned long font_instance_hash(Lisp_Object obj, int depth)
289 {
290         return internal_hash(font_instance_truename_internal(obj, ERROR_ME_NOT),
291                              depth + 1);
292 }
293
294 DEFINE_LRECORD_IMPLEMENTATION("font-instance", font_instance,
295                               mark_font_instance, print_font_instance,
296                               finalize_font_instance, font_instance_equal,
297                               font_instance_hash, 0, Lisp_Font_Instance);
298 \f
299 DEFUN("make-font-instance", Fmake_font_instance, 1, 3, 0,       /*
300 Return a new `font-instance' object named NAME.
301 DEVICE specifies the device this object applies to and defaults to the
302 selected device.  An error is signalled if the font is unknown or cannot
303 be allocated; however, if NOERROR is non-nil, nil is simply returned in
304 this case.
305
306 The returned object is a normal, first-class lisp object.  The way you
307 `deallocate' the font is the way you deallocate any other lisp object:
308 you drop all pointers to it and allow it to be garbage collected.  When
309 these objects are GCed, the underlying X data is deallocated as well.
310 */
311       (name, device, noerror))
312 {
313         Lisp_Font_Instance *f;
314         Lisp_Object val;
315         int retval = 0;
316         Error_behavior errb = decode_error_behavior_flag(noerror);
317
318         if (ERRB_EQ(errb, ERROR_ME))
319                 CHECK_STRING(name);
320         else if (!STRINGP(name))
321                 return Qnil;
322
323         XSETDEVICE(device, decode_device(device));
324
325         f = alloc_lcrecord_type(Lisp_Font_Instance, &lrecord_font_instance);
326         f->name = name;
327         f->device = device;
328
329         f->data = 0;
330
331         /* Stick some default values here ... */
332         f->ascent = f->height = 1;
333         f->descent = 0;
334         f->width = 1;
335         f->proportional_p = 0;
336
337         retval = MAYBE_INT_DEVMETH(XDEVICE(device), initialize_font_instance,
338                                    (f, name, device, errb));
339
340         if (!retval)
341                 return Qnil;
342
343         XSETFONT_INSTANCE(val, f);
344         return val;
345 }
346
347 DEFUN("font-instance-p", Ffont_instance_p, 1, 1, 0,     /*
348 Return non-nil if OBJECT is a font instance.
349 */
350       (object))
351 {
352         return FONT_INSTANCEP(object) ? Qt : Qnil;
353 }
354
355 DEFUN("font-instance-name", Ffont_instance_name, 1, 1, 0,       /*
356 Return the name used to allocate FONT-INSTANCE.
357 */
358       (font_instance))
359 {
360         CHECK_FONT_INSTANCE(font_instance);
361         return XFONT_INSTANCE(font_instance)->name;
362 }
363
364 DEFUN("font-instance-ascent", Ffont_instance_ascent, 1, 1, 0,   /*
365 Return the ascent in pixels of FONT-INSTANCE.
366 The returned value is the maximum ascent for all characters in the font,
367 where a character's ascent is the number of pixels above (and including)
368 the baseline.
369 */
370       (font_instance))
371 {
372         CHECK_FONT_INSTANCE(font_instance);
373         return make_int(XFONT_INSTANCE(font_instance)->ascent);
374 }
375
376 DEFUN("font-instance-descent", Ffont_instance_descent, 1, 1, 0, /*
377 Return the descent in pixels of FONT-INSTANCE.
378 The returned value is the maximum descent for all characters in the font,
379 where a character's descent is the number of pixels below the baseline.
380 \(Many characters to do not have any descent.  Typical characters with a
381 descent are lowercase p and lowercase g.)
382 */
383       (font_instance))
384 {
385         CHECK_FONT_INSTANCE(font_instance);
386         return make_int(XFONT_INSTANCE(font_instance)->descent);
387 }
388
389 DEFUN("font-instance-width", Ffont_instance_width, 1, 1, 0,     /*
390 Return the width in pixels of FONT-INSTANCE.
391 The returned value is the average width for all characters in the font.
392 */
393       (font_instance))
394 {
395         CHECK_FONT_INSTANCE(font_instance);
396         return make_int(XFONT_INSTANCE(font_instance)->width);
397 }
398
399 DEFUN("font-instance-proportional-p", Ffont_instance_proportional_p, 1, 1, 0,   /*
400 Return whether FONT-INSTANCE is proportional.
401 This means that different characters in the font have different widths.
402 */
403       (font_instance))
404 {
405         CHECK_FONT_INSTANCE(font_instance);
406         return XFONT_INSTANCE(font_instance)->proportional_p ? Qt : Qnil;
407 }
408
409 static Lisp_Object
410 font_instance_truename_internal(Lisp_Object font_instance, Error_behavior errb)
411 {
412         Lisp_Font_Instance *f = XFONT_INSTANCE(font_instance);
413
414         if (NILP(f->device)) {
415                 maybe_signal_simple_error("Couldn't determine font truename",
416                                           font_instance, Qfont, errb);
417                 return Qnil;
418         }
419
420         return DEVMETH_OR_GIVEN(XDEVICE(f->device),
421                                 font_instance_truename, (f, errb), f->name);
422 }
423
424 DEFUN("font-instance-truename", Ffont_instance_truename, 1, 1, 0,       /*
425 Return the canonical name of FONT-INSTANCE.
426 Font names are patterns which may match any number of fonts, of which
427 the first found is used.  This returns an unambiguous name for that font
428 \(but not necessarily its only unambiguous name).
429 */
430       (font_instance))
431 {
432         CHECK_FONT_INSTANCE(font_instance);
433         return font_instance_truename_internal(font_instance, ERROR_ME);
434 }
435
436 DEFUN("font-instance-properties", Ffont_instance_properties, 1, 1, 0,   /*
437 Return the properties (an alist or nil) of FONT-INSTANCE.
438 */
439       (font_instance))
440 {
441         Lisp_Font_Instance *f;
442
443         CHECK_FONT_INSTANCE(font_instance);
444         f = XFONT_INSTANCE(font_instance);
445
446         if (NILP(f->device))
447                 return Qnil;
448
449         return MAYBE_LISP_DEVMETH(XDEVICE(f->device),
450                                   font_instance_properties, (f));
451 }
452
453 DEFUN("list-fonts", Flist_fonts, 1, 2, 0,       /*
454 Return a list of font names matching the given pattern.
455 DEVICE specifies which device to search for names, and defaults to the
456 currently selected device.
457 */
458       (pattern, device))
459 {
460         CHECK_STRING(pattern);
461         XSETDEVICE(device, decode_device(device));
462
463         return MAYBE_LISP_DEVMETH(XDEVICE(device), list_fonts,
464                                   (pattern, device));
465 }
466 \f
467 /****************************************************************************
468  Color Object
469  ***************************************************************************/
470 DEFINE_SPECIFIER_TYPE(color);
471 /* Qcolor defined in general.c */
472
473 static void color_create(Lisp_Object obj)
474 {
475         Lisp_Specifier *color = XCOLOR_SPECIFIER(obj);
476
477         COLOR_SPECIFIER_FACE(color) = Qnil;
478         COLOR_SPECIFIER_FACE_PROPERTY(color) = Qnil;
479 }
480
481 static void color_mark(Lisp_Object obj)
482 {
483         Lisp_Specifier *color = XCOLOR_SPECIFIER(obj);
484
485         mark_object(COLOR_SPECIFIER_FACE(color));
486         mark_object(COLOR_SPECIFIER_FACE_PROPERTY(color));
487 }
488
489 /* No equal or hash methods; ignore the face the color is based off
490    of for `equal' */
491
492 static Lisp_Object
493 color_instantiate(Lisp_Object specifier, Lisp_Object matchspec,
494                   Lisp_Object domain, Lisp_Object instantiator,
495                   Lisp_Object depth)
496 {
497         /* When called, we're inside of call_with_suspended_errors(),
498            so we can freely error. */
499         Lisp_Object device = DOMAIN_DEVICE(domain);
500         struct device *d = XDEVICE(device);
501
502         if (COLOR_INSTANCEP(instantiator)) {
503                 /* If we are on the same device then we're done.  Otherwise change
504                    the instantiator to the name used to generate the pixel and let the
505                    STRINGP case deal with it. */
506                 if (NILP(device)        /* Vthe_null_color_instance */
507                     ||EQ(device, XCOLOR_INSTANCE(instantiator)->device))
508                         return instantiator;
509                 else
510                         instantiator = Fcolor_instance_name(instantiator);
511         }
512
513         if (STRINGP(instantiator)) {
514                 /* First, look to see if we can retrieve a cached value. */
515                 Lisp_Object instance =
516                     Fgethash(instantiator, d->color_instance_cache, Qunbound);
517                 /* Otherwise, make a new one. */
518                 if (UNBOUNDP(instance)) {
519                         /* make sure we cache the failures, too. */
520                         instance =
521                             Fmake_color_instance(instantiator, device, Qt);
522                         Fputhash(instantiator, instance,
523                                  d->color_instance_cache);
524                 }
525
526                 return NILP(instance) ? Qunbound : instance;
527         } else if (VECTORP(instantiator)) {
528                 switch (XVECTOR_LENGTH(instantiator)) {
529                 case 0:
530                         if (DEVICE_TTY_P(d))
531                                 return Vthe_null_color_instance;
532                         else
533                                 signal_simple_error
534                                     ("Color instantiator [] only valid on TTY's",
535                                      device);
536
537                 case 1:
538                         if (NILP
539                             (COLOR_SPECIFIER_FACE(XCOLOR_SPECIFIER(specifier))))
540                                 signal_simple_error
541                                     ("Color specifier not attached to a face",
542                                      instantiator);
543                         return (FACE_PROPERTY_INSTANCE_1
544                                 (Fget_face(XVECTOR_DATA(instantiator)[0]),
545                                  COLOR_SPECIFIER_FACE_PROPERTY(XCOLOR_SPECIFIER
546                                                                (specifier)),
547                                  domain, ERROR_ME, 0, depth));
548
549                 case 2:
550                         return (FACE_PROPERTY_INSTANCE_1
551                                 (Fget_face(XVECTOR_DATA(instantiator)[0]),
552                                  XVECTOR_DATA(instantiator)[1], domain,
553                                  ERROR_ME, 0, depth));
554
555                 default:
556                         abort();
557                 }
558         } else if (NILP(instantiator)) {