* frame.c (Vdelete_frame_functions): New variable.
[bpt/emacs.git] / src / macfns.c
1 /* Graphical user interface functions for Mac OS.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Emacs.
5
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
22
23 #include <config.h>
24
25 #include <signal.h>
26 #include <stdio.h>
27 #include <math.h>
28 #include <limits.h>
29 #include <errno.h>
30
31 #include "lisp.h"
32 #include "charset.h"
33 #include "macterm.h"
34 #include "frame.h"
35 #include "window.h"
36 #include "buffer.h"
37 #include "dispextern.h"
38 #include "fontset.h"
39 #include "intervals.h"
40 #include "keyboard.h"
41 #include "blockinput.h"
42 #include "epaths.h"
43 #include "termhooks.h"
44 #include "coding.h"
45 #include "ccl.h"
46 #include "systime.h"
47
48 /* #include "bitmaps/gray.xbm" */
49 #define gray_width 2
50 #define gray_height 2
51 static unsigned char gray_bits[] = {
52 0x01, 0x02};
53
54 /*#include <commdlg.h>
55 #include <shellapi.h>*/
56 #include <ctype.h>
57
58 #include <stdlib.h>
59 #include <string.h>
60 #ifndef MAC_OSX
61 #include <alloca.h>
62 #endif
63
64 #ifdef MAC_OSX
65 #undef mktime
66 #undef DEBUG
67 #undef Z
68 #undef free
69 #undef malloc
70 #undef realloc
71 /* Macros max and min defined in lisp.h conflict with those in
72 precompiled header Carbon.h. */
73 #undef max
74 #undef min
75 #undef init_process
76 #include <Carbon/Carbon.h>
77 #undef Z
78 #define Z (current_buffer->text->z)
79 #undef free
80 #define free unexec_free
81 #undef malloc
82 #define malloc unexec_malloc
83 #undef realloc
84 #define realloc unexec_realloc
85 #undef min
86 #define min(a, b) ((a) < (b) ? (a) : (b))
87 #undef max
88 #define max(a, b) ((a) > (b) ? (a) : (b))
89 #undef init_process
90 #define init_process emacs_init_process
91 #else /* not MAC_OSX */
92 #include <Windows.h>
93 #include <Gestalt.h>
94 #include <TextUtils.h>
95 #endif /* not MAC_OSX */
96
97 /*extern void free_frame_menubar ();
98 extern double atof ();
99 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
100 extern int quit_char;*/
101
102 /* A definition of XColor for non-X frames. */
103 #ifndef HAVE_X_WINDOWS
104 typedef struct {
105 unsigned long pixel;
106 unsigned short red, green, blue;
107 char flags;
108 char pad;
109 } XColor;
110 #endif
111
112 extern char *lispy_function_keys[];
113
114 /* The gray bitmap `bitmaps/gray'. This is done because macterm.c uses
115 it, and including `bitmaps/gray' more than once is a problem when
116 config.h defines `static' as an empty replacement string. */
117
118 int gray_bitmap_width = gray_width;
119 int gray_bitmap_height = gray_height;
120 unsigned char *gray_bitmap_bits = gray_bits;
121
122 /* The name we're using in resource queries. */
123
124 Lisp_Object Vx_resource_name;
125
126 /* Non-zero means we're allowed to display an hourglass cursor. */
127
128 int display_hourglass_p;
129
130 /* The background and shape of the mouse pointer, and shape when not
131 over text or in the modeline. */
132
133 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
134 Lisp_Object Vx_hourglass_pointer_shape;
135
136 /* The shape when over mouse-sensitive text. */
137
138 Lisp_Object Vx_sensitive_text_pointer_shape;
139
140 /* If non-nil, the pointer shape to indicate that windows can be
141 dragged horizontally. */
142
143 Lisp_Object Vx_window_horizontal_drag_shape;
144
145 /* Color of chars displayed in cursor box. */
146
147 Lisp_Object Vx_cursor_fore_pixel;
148
149 /* Nonzero if using Windows. */
150
151 static int mac_in_use;
152
153 /* Non nil if no window manager is in use. */
154
155 Lisp_Object Vx_no_window_manager;
156
157 /* Search path for bitmap files. */
158
159 Lisp_Object Vx_bitmap_file_path;
160
161 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
162
163 Lisp_Object Vx_pixel_size_width_font_regexp;
164
165 /* Evaluate this expression to rebuild the section of syms_of_macfns
166 that initializes and staticpros the symbols declared below. Note
167 that Emacs 18 has a bug that keeps C-x C-e from being able to
168 evaluate this expression.
169
170 (progn
171 ;; Accumulate a list of the symbols we want to initialize from the
172 ;; declarations at the top of the file.
173 (goto-char (point-min))
174 (search-forward "/\*&&& symbols declared here &&&*\/\n")
175 (let (symbol-list)
176 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
177 (setq symbol-list
178 (cons (buffer-substring (match-beginning 1) (match-end 1))
179 symbol-list))
180 (forward-line 1))
181 (setq symbol-list (nreverse symbol-list))
182 ;; Delete the section of syms_of_... where we initialize the symbols.
183 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
184 (let ((start (point)))
185 (while (looking-at "^ Q")
186 (forward-line 2))
187 (kill-region start (point)))
188 ;; Write a new symbol initialization section.
189 (while symbol-list
190 (insert (format " %s = intern (\"" (car symbol-list)))
191 (let ((start (point)))
192 (insert (substring (car symbol-list) 1))
193 (subst-char-in-region start (point) ?_ ?-))
194 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
195 (setq symbol-list (cdr symbol-list)))))
196
197 */
198
199 /*&&& symbols declared here &&&*/
200 Lisp_Object Qauto_raise;
201 Lisp_Object Qauto_lower;
202 Lisp_Object Qborder_color;
203 Lisp_Object Qborder_width;
204 Lisp_Object Qcursor_color;
205 Lisp_Object Qcursor_type;
206 Lisp_Object Qgeometry;
207 Lisp_Object Qicon_left;
208 Lisp_Object Qicon_top;
209 Lisp_Object Qicon_type;
210 Lisp_Object Qicon_name;
211 Lisp_Object Qinternal_border_width;
212 Lisp_Object Qleft;
213 Lisp_Object Qright;
214 Lisp_Object Qmouse_color;
215 Lisp_Object Qnone;
216 Lisp_Object Qparent_id;
217 Lisp_Object Qscroll_bar_width;
218 Lisp_Object Qsuppress_icon;
219 Lisp_Object Qundefined_color;
220 Lisp_Object Qvertical_scroll_bars;
221 Lisp_Object Qvisibility;
222 Lisp_Object Qwindow_id;
223 Lisp_Object Qx_frame_parameter;
224 Lisp_Object Qx_resource_name;
225 Lisp_Object Quser_position;
226 Lisp_Object Quser_size;
227 Lisp_Object Qscreen_gamma;
228 Lisp_Object Qline_spacing;
229 Lisp_Object Qcenter;
230 Lisp_Object Qcancel_timer;
231 Lisp_Object Qhyper;
232 Lisp_Object Qsuper;
233 Lisp_Object Qmeta;
234 Lisp_Object Qalt;
235 Lisp_Object Qctrl;
236 Lisp_Object Qcontrol;
237 Lisp_Object Qshift;
238
239 extern Lisp_Object Qtop;
240 extern Lisp_Object Qdisplay;
241 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
242 extern Lisp_Object Qtool_bar_lines;
243
244 /* These are defined in frame.c. */
245 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
246 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
247 extern Lisp_Object Qtool_bar_lines;
248
249 extern Lisp_Object Vwindow_system_version;
250
251 extern Lisp_Object Qbox;
252
253 Lisp_Object Qface_set_after_frame_default;
254
255 extern int mac_initialized;
256
257 /* Functions in macterm.c. */
258 extern void x_set_offset (struct frame *, int, int, int);
259 extern void x_wm_set_icon_position (struct frame *, int, int);
260 extern void x_display_cursor (struct window *, int, int, int, int, int);
261 extern void x_set_window_size (struct frame *, int, int, int);
262 extern void x_make_frame_visible (struct frame *);
263 extern struct mac_display_info *mac_term_init (Lisp_Object, char *, char *);
264 extern struct font_info *x_get_font_info (FRAME_PTR, int);
265 extern struct font_info *x_load_font (struct frame *, char *, int);
266 extern void x_find_ccl_program (struct font_info *);
267 extern struct font_info *x_query_font (struct frame *, char *);
268 extern void mac_initialize ();
269
270 /* compare two strings ignoring case */
271
272 static int
273 stricmp (const char *s, const char *t)
274 {
275 for ( ; tolower (*s) == tolower (*t); s++, t++)
276 if (*s == '\0')
277 return 0;
278 return tolower (*s) - tolower (*t);
279 }
280
281 /* compare two strings up to n characters, ignoring case */
282
283 static int
284 strnicmp (const char *s, const char *t, unsigned int n)
285 {
286 for ( ; n-- > 0 && tolower (*s) == tolower (*t); s++, t++)
287 if (*s == '\0')
288 return 0;
289 return n == 0 ? 0 : tolower (*s) - tolower (*t);
290 }
291
292 \f
293 /* Error if we are not running on Mac OS. */
294
295 void
296 check_mac ()
297 {
298 if (! mac_in_use)
299 error ("Mac OS not in use or not initialized");
300 }
301
302 /* Nonzero if we can use mouse menus.
303 You should not call this unless HAVE_MENUS is defined. */
304
305 int
306 have_menus_p ()
307 {
308 return mac_in_use;
309 }
310
311 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
312 and checking validity for Mac. */
313
314 FRAME_PTR
315 check_x_frame (frame)
316 Lisp_Object frame;
317 {
318 FRAME_PTR f;
319
320 if (NILP (frame))
321 frame = selected_frame;
322 CHECK_LIVE_FRAME (frame);
323 f = XFRAME (frame);
324 if (! FRAME_MAC_P (f))
325 error ("non-mac frame used");
326 return f;
327 }
328
329 /* Let the user specify an display with a frame.
330 nil stands for the selected frame--or, if that is not a mac frame,
331 the first display on the list. */
332
333 static struct mac_display_info *
334 check_x_display_info (frame)
335 Lisp_Object frame;
336 {
337 if (!mac_initialized)
338 {
339 mac_initialize ();
340 mac_initialized = 1;
341 }
342
343 if (NILP (frame))
344 {
345 struct frame *sf = XFRAME (selected_frame);
346
347 if (FRAME_MAC_P (sf) && FRAME_LIVE_P (sf))
348 return FRAME_MAC_DISPLAY_INFO (sf);
349 else
350 return &one_mac_display_info;
351 }
352 else if (STRINGP (frame))
353 return x_display_info_for_name (frame);
354 else
355 {
356 FRAME_PTR f;
357
358 CHECK_LIVE_FRAME (frame);
359 f = XFRAME (frame);
360 if (! FRAME_MAC_P (f))
361 error ("non-mac frame used");
362 return FRAME_MAC_DISPLAY_INFO (f);
363 }
364 }
365 \f
366 /* Return the Emacs frame-object corresponding to an mac window.
367 It could be the frame's main window or an icon window. */
368
369 /* This function can be called during GC, so use GC_xxx type test macros. */
370
371 struct frame *
372 x_window_to_frame (dpyinfo, wdesc)
373 struct mac_display_info *dpyinfo;
374 WindowPtr wdesc;
375 {
376 Lisp_Object tail, frame;
377 struct frame *f;
378
379 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
380 {
381 frame = XCAR (tail);
382 if (!GC_FRAMEP (frame))
383 continue;
384 f = XFRAME (frame);
385 if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo)
386 continue;
387 /*if (f->output_data.w32->hourglass_window == wdesc)
388 return f;*/
389
390 /* MAC_TODO: Check tooltips when supported. */
391 if (FRAME_MAC_WINDOW (f) == wdesc)
392 return f;
393 }
394 return 0;
395 }
396
397 \f
398
399 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
400 id, which is just an int that this section returns. Bitmaps are
401 reference counted so they can be shared among frames.
402
403 Bitmap indices are guaranteed to be > 0, so a negative number can
404 be used to indicate no bitmap.
405
406 If you use x_create_bitmap_from_data, then you must keep track of
407 the bitmaps yourself. That is, creating a bitmap from the same
408 data more than once will not be caught. */
409
410
411 /* Functions to access the contents of a bitmap, given an id. */
412
413 int
414 x_bitmap_height (f, id)
415 FRAME_PTR f;
416 int id;
417 {
418 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
419 }
420
421 int
422 x_bitmap_width (f, id)
423 FRAME_PTR f;
424 int id;
425 {
426 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
427 }
428
429 #if 0 /* MAC_TODO : not used anywhere (?) */
430 int
431 x_bitmap_pixmap (f, id)
432 FRAME_PTR f;
433 int id;
434 {
435 return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
436 }
437 #endif
438
439 /* Allocate a new bitmap record. Returns index of new record. */
440
441 static int
442 x_allocate_bitmap_record (f)
443 FRAME_PTR f;
444 {
445 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
446 int i;
447
448 if (dpyinfo->bitmaps == NULL)
449 {
450 dpyinfo->bitmaps_size = 10;
451 dpyinfo->bitmaps = (struct mac_bitmap_record *)
452 xmalloc (dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
453 dpyinfo->bitmaps_last = 1;
454 return 1;
455 }
456
457 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
458 return ++dpyinfo->bitmaps_last;
459
460 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
461 if (dpyinfo->bitmaps[i].refcount == 0)
462 return i + 1;
463
464 dpyinfo->bitmaps_size *= 2;
465 dpyinfo->bitmaps = (struct mac_bitmap_record *)
466 xrealloc (dpyinfo->bitmaps,
467 dpyinfo->bitmaps_size * sizeof (struct mac_bitmap_record));
468 return ++dpyinfo->bitmaps_last;
469 }
470
471 /* Add one reference to the reference count of the bitmap with id
472 ID. */
473
474 void
475 x_reference_bitmap (f, id)
476 FRAME_PTR f;
477 int id;
478 {
479 ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
480 }
481
482 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
483 BITS. */
484
485 int
486 x_create_bitmap_from_data (f, bits, width, height)
487 struct frame *f;
488 char *bits;
489 unsigned int width, height;
490 {
491 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
492 int id;
493
494 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
495
496 id = x_allocate_bitmap_record (f);
497
498 if (width % 16 != 0)
499 return -1;
500
501 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
502 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
503 return -1;
504
505 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
506
507 dpyinfo->bitmaps[id - 1].refcount = 1;
508 dpyinfo->bitmaps[id - 1].height = height;
509 dpyinfo->bitmaps[id - 1].width = width;
510
511 return id;
512 }
513
514 /* Create bitmap from file FILE for frame F. */
515
516 int
517 x_create_bitmap_from_file (f, file)
518 struct frame *f;
519 Lisp_Object file;
520 {
521 return -1;
522 #if 0 /* MAC_TODO : bitmap support */
523 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
524 unsigned int width, height;
525 HBITMAP bitmap;
526 int xhot, yhot, result, id;
527 Lisp_Object found;
528 int fd;
529 char *filename;
530 HINSTANCE hinst;
531
532 /* Look for an existing bitmap with the same name. */
533 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
534 {
535 if (dpyinfo->bitmaps[id].refcount
536 && dpyinfo->bitmaps[id].file
537 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
538 {
539 ++dpyinfo->bitmaps[id].refcount;
540 return id + 1;
541 }
542 }
543
544 /* Search bitmap-file-path for the file, if appropriate. */
545 fd = openp (Vx_bitmap_file_path, file, "", &found, Qnil);
546 if (fd < 0)
547 return -1;
548 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
549 if (fd == 0)
550 return -1;
551 emacs_close (fd);
552
553 filename = (char *) SDATA (found);
554
555 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
556
557 if (hinst == NULL)
558 return -1;
559
560
561 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
562 filename, &width, &height, &bitmap, &xhot, &yhot);
563 if (result != BitmapSuccess)
564 return -1;
565
566 id = x_allocate_bitmap_record (f);
567 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
568 dpyinfo->bitmaps[id - 1].refcount = 1;
569 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
570 dpyinfo->bitmaps[id - 1].depth = 1;
571 dpyinfo->bitmaps[id - 1].height = height;
572 dpyinfo->bitmaps[id - 1].width = width;
573 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
574
575 return id;
576 #endif /* MAC_TODO */
577 }
578
579 /* Remove reference to bitmap with id number ID. */
580
581 void
582 x_destroy_bitmap (f, id)
583 FRAME_PTR f;
584 int id;
585 {
586 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
587
588 if (id > 0)
589 {
590 --dpyinfo->bitmaps[id - 1].refcount;
591 if (dpyinfo->bitmaps[id - 1].refcount == 0)
592 {
593 BLOCK_INPUT;
594 dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
595 UNBLOCK_INPUT;
596 }
597 }
598 }
599
600 /* Free all the bitmaps for the display specified by DPYINFO. */
601
602 static void
603 x_destroy_all_bitmaps (dpyinfo)
604 struct mac_display_info *dpyinfo;
605 {
606 int i;
607 for (i = 0; i < dpyinfo->bitmaps_last; i++)
608 if (dpyinfo->bitmaps[i].refcount > 0)
609 xfree (dpyinfo->bitmaps[i].bitmap_data);
610 dpyinfo->bitmaps_last = 0;
611 }
612 \f
613 /* Connect the frame-parameter names for W32 frames
614 to the ways of passing the parameter values to the window system.
615
616 The name of a parameter, as a Lisp symbol,
617 has an `x-frame-parameter' property which is an integer in Lisp
618 but can be interpreted as an `enum x_frame_parm' in C. */
619
620 struct x_frame_parm_table
621 {
622 char *name;
623 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
624 };
625
626 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
627 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
628 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
629 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
630 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
631 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
632 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
633 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
634 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
635 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
636 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
637 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
638 Lisp_Object));
639 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
640 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
641 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
642 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
643 Lisp_Object));
644 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
645 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
646 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
647 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
648 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
649 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
650 void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
651 Lisp_Object));
652 void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
653 Lisp_Object));
654 static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
655 Lisp_Object,
656 Lisp_Object,
657 char *, char *,
658 int));
659 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
660
661 static struct x_frame_parm_table x_frame_parms[] =
662 {
663 "auto-raise", x_set_autoraise,
664 "auto-lower", x_set_autolower,
665 "background-color", x_set_background_color,
666 "border-color", x_set_border_color,
667 "border-width", x_set_border_width,
668 "cursor-color", x_set_cursor_color,
669 "cursor-type", x_set_cursor_type,
670 "font", x_set_font,
671 "foreground-color", x_set_foreground_color,
672 "icon-name", x_set_icon_name,
673 #if 0 /* MAC_TODO: no icons for Mac */
674 "icon-type", x_set_icon_type,
675 #endif
676 "internal-border-width", x_set_internal_border_width,
677 "menu-bar-lines", x_set_menu_bar_lines,
678 "mouse-color", x_set_mouse_color,
679 "name", x_explicitly_set_name,
680 "scroll-bar-width", x_set_scroll_bar_width,
681 "title", x_set_title,
682 "unsplittable", x_set_unsplittable,
683 "vertical-scroll-bars", x_set_vertical_scroll_bars,
684 "visibility", x_set_visibility,
685 "tool-bar-lines", x_set_tool_bar_lines,
686 #if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */
687 "scroll-bar-foreground", x_set_scroll_bar_foreground,
688 "scroll-bar-background", x_set_scroll_bar_background,
689 #endif
690 "screen-gamma", x_set_screen_gamma,
691 "line-spacing", x_set_line_spacing
692 };
693
694 /* Attach the `x-frame-parameter' properties to
695 the Lisp symbol names of parameters relevant to Mac. */
696
697 void
698 init_x_parm_symbols ()
699 {
700 int i;
701
702 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
703 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
704 make_number (i));
705 }
706 \f
707 /* Change the parameters of frame F as specified by ALIST.
708 If a parameter is not specially recognized, do nothing;
709 otherwise call the `x_set_...' function for that parameter. */
710
711 void
712 x_set_frame_parameters (f, alist)
713 FRAME_PTR f;
714 Lisp_Object alist;
715 {
716 Lisp_Object tail;
717
718 /* If both of these parameters are present, it's more efficient to
719 set them both at once. So we wait until we've looked at the
720 entire list before we set them. */
721 int width, height;
722
723 /* Same here. */
724 Lisp_Object left, top;
725
726 /* Same with these. */
727 Lisp_Object icon_left, icon_top;
728
729 /* Record in these vectors all the parms specified. */
730 Lisp_Object *parms;
731 Lisp_Object *values;
732 int i, p;
733 int left_no_change = 0, top_no_change = 0;
734 int icon_left_no_change = 0, icon_top_no_change = 0;
735
736 struct gcpro gcpro1, gcpro2;
737
738 i = 0;
739 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
740 i++;
741
742 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
743 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
744
745 /* Extract parm names and values into those vectors. */
746
747 i = 0;
748 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
749 {
750 Lisp_Object elt;
751
752 elt = Fcar (tail);
753 parms[i] = Fcar (elt);
754 values[i] = Fcdr (elt);
755 i++;
756 }
757 /* TAIL and ALIST are not used again below here. */
758 alist = tail = Qnil;
759
760 GCPRO2 (*parms, *values);
761 gcpro1.nvars = i;
762 gcpro2.nvars = i;
763
764 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
765 because their values appear in VALUES and strings are not valid. */
766 top = left = Qunbound;
767 icon_left = icon_top = Qunbound;
768
769 /* Provide default values for HEIGHT and WIDTH. */
770 if (FRAME_NEW_WIDTH (f))
771 width = FRAME_NEW_WIDTH (f);
772 else
773 width = FRAME_WIDTH (f);
774
775 if (FRAME_NEW_HEIGHT (f))
776 height = FRAME_NEW_HEIGHT (f);
777 else
778 height = FRAME_HEIGHT (f);
779
780 /* Process foreground_color and background_color before anything else.
781 They are independent of other properties, but other properties (e.g.,
782 cursor_color) are dependent upon them. */
783 for (p = 0; p < i; p++)
784 {
785 Lisp_Object prop, val;
786
787 prop = parms[p];
788 val = values[p];
789 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
790 {
791 register Lisp_Object param_index, old_value;
792
793 param_index = Fget (prop, Qx_frame_parameter);
794 old_value = get_frame_param (f, prop);
795 store_frame_param (f, prop, val);
796 if (NATNUMP (param_index)
797 && (XFASTINT (param_index)
798 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
799 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
800 }
801 }
802
803 /* Now process them in reverse of specified order. */
804 for (i--; i >= 0; i--)
805 {
806 Lisp_Object prop, val;
807
808 prop = parms[i];
809 val = values[i];
810
811 if (EQ (prop, Qwidth) && NUMBERP (val))
812 width = XFASTINT (val);
813 else if (EQ (prop, Qheight) && NUMBERP (val))
814 height = XFASTINT (val);
815 else if (EQ (prop, Qtop))
816 top = val;
817 else if (EQ (prop, Qleft))
818 left = val;
819 else if (EQ (prop, Qicon_top))
820 icon_top = val;
821 else if (EQ (prop, Qicon_left))
822 icon_left = val;
823 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
824 /* Processed above. */
825 continue;
826 else
827 {
828 register Lisp_Object param_index, old_value;
829
830 param_index = Fget (prop, Qx_frame_parameter);
831 old_value = get_frame_param (f, prop);
832 store_frame_param (f, prop, val);
833 if (NATNUMP (param_index)
834 && (XFASTINT (param_index)
835 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
836 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
837 }
838 }
839
840 /* Don't die if just one of these was set. */
841 if (EQ (left, Qunbound))
842 {
843 left_no_change = 1;
844 if (f->output_data.mac->left_pos < 0)
845 left = Fcons (Qplus,
846 Fcons (make_number (f->output_data.mac->left_pos),
847 Qnil));
848 else
849 XSETINT (left, f->output_data.mac->left_pos);
850 }
851 if (EQ (top, Qunbound))
852 {
853 top_no_change = 1;
854 if (f->output_data.mac->top_pos < 0)
855 top = Fcons (Qplus,
856 Fcons (make_number (f->output_data.mac->top_pos), Qnil));
857 else
858 XSETINT (top, f->output_data.mac->top_pos);
859 }
860
861 /* If one of the icon positions was not set, preserve or default it. */
862 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
863 {
864 icon_left_no_change = 1;
865 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
866 if (NILP (icon_left))
867 XSETINT (icon_left, 0);
868 }
869 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
870 {
871 icon_top_no_change = 1;
872 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
873 if (NILP (icon_top))
874 XSETINT (icon_top, 0);
875 }
876
877 /* Don't set these parameters unless they've been explicitly
878 specified. The window might be mapped or resized while we're in
879 this function, and we don't want to override that unless the lisp
880 code has asked for it.
881
882 Don't set these parameters unless they actually differ from the
883 window's current parameters; the window may not actually exist
884 yet. */
885 {
886 Lisp_Object frame;
887
888 check_frame_size (f, &height, &width);
889
890 XSETFRAME (frame, f);
891
892 if (width != FRAME_WIDTH (f)
893 || height != FRAME_HEIGHT (f)
894 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
895 Fset_frame_size (frame, make_number (width), make_number (height));
896
897 if ((!NILP (left) || !NILP (top))
898 && ! (left_no_change && top_no_change)
899 && ! (NUMBERP (left) && XINT (left) == f->output_data.mac->left_pos
900 && NUMBERP (top) && XINT (top) == f->output_data.mac->top_pos))
901 {
902 int leftpos = 0;
903 int toppos = 0;
904
905 /* Record the signs. */
906 f->output_data.mac->size_hint_flags &= ~ (XNegative | YNegative);
907 if (EQ (left, Qminus))
908 f->output_data.mac->size_hint_flags |= XNegative;
909 else if (INTEGERP (left))
910 {
911 leftpos = XINT (left);
912 if (leftpos < 0)
913 f->output_data.mac->size_hint_flags |= XNegative;
914 }
915 else if (CONSP (left) && EQ (XCAR (left), Qminus)
916 && CONSP (XCDR (left))
917 && INTEGERP (XCAR (XCDR (left))))
918 {
919 leftpos = - XINT (XCAR (XCDR (left)));
920 f->output_data.mac->size_hint_flags |= XNegative;
921 }
922 else if (CONSP (left) && EQ (XCAR (left), Qplus)
923 && CONSP (XCDR (left))
924 && INTEGERP (XCAR (XCDR (left))))
925 {
926 leftpos = XINT (XCAR (XCDR (left)));
927 }
928
929 if (EQ (top, Qminus))
930 f->output_data.mac->size_hint_flags |= YNegative;
931 else if (INTEGERP (top))
932 {
933 toppos = XINT (top);
934 if (toppos < 0)
935 f->output_data.mac->size_hint_flags |= YNegative;
936 }
937 else if (CONSP (top) && EQ (XCAR (top), Qminus)
938 && CONSP (XCDR (top))
939 && INTEGERP (XCAR (XCDR (top))))
940 {
941 toppos = - XINT (XCAR (XCDR (top)));
942 f->output_data.mac->size_hint_flags |= YNegative;
943 }
944 else if (CONSP (top) && EQ (XCAR (top), Qplus)
945 && CONSP (XCDR (top))
946 && INTEGERP (XCAR (XCDR (top))))
947 {
948 toppos = XINT (XCAR (XCDR (top)));
949 }
950
951
952 /* Store the numeric value of the position. */
953 f->output_data.mac->top_pos = toppos;
954 f->output_data.mac->left_pos = leftpos;
955
956 f->output_data.mac->win_gravity = NorthWestGravity;
957
958 /* Actually set that position, and convert to absolute. */
959 x_set_offset (f, leftpos, toppos, -1);
960 }
961
962 if ((!NILP (icon_left) || !NILP (icon_top))
963 && ! (icon_left_no_change && icon_top_no_change))
964 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
965 }
966
967 UNGCPRO;
968 }
969
970 /* Store the screen positions of frame F into XPTR and YPTR.
971 These are the positions of the containing window manager window,
972 not Emacs's own window. */
973
974 void
975 x_real_positions (f, xptr, yptr)
976 FRAME_PTR f;
977 int *xptr, *yptr;
978 {
979 Point pt;
980 GrafPtr oldport;
981
982 #ifdef TARGET_API_MAC_CARBON
983 {
984 Rect r;
985
986 GetWindowPortBounds (f->output_data.mac->mWP, &r);
987 SetPt (&pt, r.left, r.top);
988 }
989 #else /* not TARGET_API_MAC_CARBON */
990 SetPt (&pt,
991 f->output_data.mac->mWP->portRect.left,
992 f->output_data.mac->mWP->portRect.top);
993 #endif /* not TARGET_API_MAC_CARBON */
994 GetPort (&oldport);
995 LocalToGlobal (&pt);
996 SetPort (oldport);
997
998 *xptr = pt.h;
999 *yptr = pt.v;
1000 }
1001
1002 /* Insert a description of internally-recorded parameters of frame X
1003 into the parameter alist *ALISTPTR that is to be given to the user.
1004 Only parameters that are specific to Mac and whose values are not
1005 correctly recorded in the frame's param_alist need to be considered
1006 here. */
1007
1008 void
1009 x_report_frame_params (f, alistptr)
1010 struct frame *f;
1011 Lisp_Object *alistptr;
1012 {
1013 char buf[16];
1014 Lisp_Object tem;
1015
1016 /* Represent negative positions (off the top or left screen edge)
1017 in a way that Fmodify_frame_parameters will understand correctly. */
1018 XSETINT (tem, f->output_data.mac->left_pos);
1019 if (f->output_data.mac->left_pos >= 0)
1020 store_in_alist (alistptr, Qleft, tem);
1021 else
1022 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1023
1024 XSETINT (tem, f->output_data.mac->top_pos);
1025 if (f->output_data.mac->top_pos >= 0)
1026 store_in_alist (alistptr, Qtop, tem);
1027 else
1028 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1029
1030 store_in_alist (alistptr, Qborder_width,
1031 make_number (f->output_data.mac->border_width));
1032 store_in_alist (alistptr, Qinternal_border_width,
1033 make_number (f->output_data.mac->internal_border_width));
1034 sprintf (buf, "%ld", (long) FRAME_MAC_WINDOW (f));
1035 store_in_alist (alistptr, Qwindow_id,
1036 build_string (buf));
1037 store_in_alist (alistptr, Qicon_name, f->icon_name);
1038 FRAME_SAMPLE_VISIBILITY (f);
1039 store_in_alist (alistptr, Qvisibility,
1040 (FRAME_VISIBLE_P (f) ? Qt
1041 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1042 store_in_alist (alistptr, Qdisplay,
1043 XCAR (FRAME_MAC_DISPLAY_INFO (f)->name_list_element));
1044 }
1045 \f
1046 /* The default colors for the Mac color map */
1047 typedef struct colormap_t
1048 {
1049 unsigned long color;
1050 char *name;
1051 } colormap_t;
1052
1053 colormap_t mac_color_map[] =
1054 {
1055 { RGB_TO_ULONG(255, 250, 250), "snow" },
1056 { RGB_TO_ULONG(248, 248, 255), "ghost white" },
1057 { RGB_TO_ULONG(248, 248, 255), "GhostWhite" },
1058 { RGB_TO_ULONG(245, 245, 245), "white smoke" },
1059 { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" },
1060 { RGB_TO_ULONG(220, 220, 220), "gainsboro" },
1061 { RGB_TO_ULONG(255, 250, 240), "floral white" },
1062 { RGB_TO_ULONG(255, 250, 240), "FloralWhite" },
1063 { RGB_TO_ULONG(253, 245, 230), "old lace" },
1064 { RGB_TO_ULONG(253, 245, 230), "OldLace" },
1065 { RGB_TO_ULONG(250, 240, 230), "linen" },
1066 { RGB_TO_ULONG(250, 235, 215), "antique white" },
1067 { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" },
1068 { RGB_TO_ULONG(255, 239, 213), "papaya whip" },
1069 { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" },
1070 { RGB_TO_ULONG(255, 235, 205), "blanched almond" },
1071 { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" },
1072 { RGB_TO_ULONG(255, 228, 196), "bisque" },
1073 { RGB_TO_ULONG(255, 218, 185), "peach puff" },
1074 { RGB_TO_ULONG(255, 218, 185), "PeachPuff" },
1075 { RGB_TO_ULONG(255, 222, 173), "navajo white" },
1076 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" },
1077 { RGB_TO_ULONG(255, 228, 181), "moccasin" },
1078 { RGB_TO_ULONG(255, 248, 220), "cornsilk" },
1079 { RGB_TO_ULONG(255, 255, 240), "ivory" },
1080 { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" },
1081 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" },
1082 { RGB_TO_ULONG(255, 245, 238), "seashell" },
1083 { RGB_TO_ULONG(240, 255, 240), "honeydew" },
1084 { RGB_TO_ULONG(245, 255, 250), "mint cream" },
1085 { RGB_TO_ULONG(245, 255, 250), "MintCream" },
1086 { RGB_TO_ULONG(240, 255, 255), "azure" },
1087 { RGB_TO_ULONG(240, 248, 255), "alice blue" },
1088 { RGB_TO_ULONG(240, 248, 255), "AliceBlue" },
1089 { RGB_TO_ULONG(230, 230, 250), "lavender" },
1090 { RGB_TO_ULONG(255, 240, 245), "lavender blush" },
1091 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" },
1092 { RGB_TO_ULONG(255, 228, 225), "misty rose" },
1093 { RGB_TO_ULONG(255, 228, 225), "MistyRose" },
1094 { RGB_TO_ULONG(255, 255, 255), "white" },
1095 { RGB_TO_ULONG(0 , 0 , 0 ), "black" },
1096 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" },
1097 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" },
1098 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" },
1099 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" },
1100 { RGB_TO_ULONG(105, 105, 105), "dim gray" },
1101 { RGB_TO_ULONG(105, 105, 105), "DimGray" },
1102 { RGB_TO_ULONG(105, 105, 105), "dim grey" },
1103 { RGB_TO_ULONG(105, 105, 105), "DimGrey" },
1104 { RGB_TO_ULONG(112, 128, 144), "slate gray" },
1105 { RGB_TO_ULONG(112, 128, 144), "SlateGray" },
1106 { RGB_TO_ULONG(112, 128, 144), "slate grey" },
1107 { RGB_TO_ULONG(112, 128, 144), "SlateGrey" },
1108 { RGB_TO_ULONG(119, 136, 153), "light slate gray" },
1109 { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" },
1110 { RGB_TO_ULONG(119, 136, 153), "light slate grey" },
1111 { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" },
1112 { RGB_TO_ULONG(190, 190, 190), "gray" },
1113 { RGB_TO_ULONG(190, 190, 190), "grey" },
1114 { RGB_TO_ULONG(211, 211, 211), "light grey" },
1115 { RGB_TO_ULONG(211, 211, 211), "LightGrey" },
1116 { RGB_TO_ULONG(211, 211, 211), "light gray" },
1117 { RGB_TO_ULONG(211, 211, 211), "LightGray" },
1118 { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" },
1119 { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" },
1120 { RGB_TO_ULONG(0 , 0 , 128), "navy" },
1121 { RGB_TO_ULONG(0 , 0 , 128), "navy blue" },
1122 { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" },
1123 { RGB_TO_ULONG(100, 149, 237), "cornflower blue" },
1124 { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" },
1125 { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" },
1126 { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" },
1127 { RGB_TO_ULONG(106, 90 , 205), "slate blue" },
1128 { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" },
1129 { RGB_TO_ULONG(123, 104, 238), "medium slate blue" },
1130 { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" },
1131 { RGB_TO_ULONG(132, 112, 255), "light slate blue" },
1132 { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" },
1133 { RGB_TO_ULONG(0 , 0 , 205), "medium blue" },
1134 { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" },
1135 { RGB_TO_ULONG(65 , 105, 225), "royal blue" },
1136 { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" },
1137 { RGB_TO_ULONG(0 , 0 , 255), "blue" },
1138 { RGB_TO_ULONG(30 , 144, 255), "dodger blue" },
1139 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" },
1140 { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" },
1141 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" },
1142 { RGB_TO_ULONG(135, 206, 235), "sky blue" },
1143 { RGB_TO_ULONG(135, 206, 235), "SkyBlue" },
1144 { RGB_TO_ULONG(135, 206, 250), "light sky blue" },
1145 { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" },
1146 { RGB_TO_ULONG(70 , 130, 180), "steel blue" },
1147 { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" },
1148 { RGB_TO_ULONG(176, 196, 222), "light steel blue" },
1149 { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" },
1150 { RGB_TO_ULONG(173, 216, 230), "light blue" },
1151 { RGB_TO_ULONG(173, 216, 230), "LightBlue" },
1152 { RGB_TO_ULONG(176, 224, 230), "powder blue" },
1153 { RGB_TO_ULONG(176, 224, 230), "PowderBlue" },
1154 { RGB_TO_ULONG(175, 238, 238), "pale turquoise" },
1155 { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" },
1156 { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" },
1157 { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" },
1158 { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" },
1159 { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" },
1160 { RGB_TO_ULONG(64 , 224, 208), "turquoise" },
1161 { RGB_TO_ULONG(0 , 255, 255), "cyan" },
1162 { RGB_TO_ULONG(224, 255, 255), "light cyan" },
1163 { RGB_TO_ULONG(224, 255, 255), "LightCyan" },
1164 { RGB_TO_ULONG(95 , 158, 160), "cadet blue" },
1165 { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" },
1166 { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" },
1167 { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" },
1168 { RGB_TO_ULONG(127, 255, 212), "aquamarine" },
1169 { RGB_TO_ULONG(0 , 100, 0 ), "dark green" },
1170 { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" },
1171 { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" },
1172 { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" },
1173 { RGB_TO_ULONG(143, 188, 143), "dark sea green" },
1174 { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" },
1175 { RGB_TO_ULONG(46 , 139, 87 ), "sea green" },
1176 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" },
1177 { RGB_TO_ULONG(60 , 179, 113), "medium sea green" },
1178 { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" },
1179 { RGB_TO_ULONG(32 , 178, 170), "light sea green" },
1180 { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" },
1181 { RGB_TO_ULONG(152, 251, 152), "pale green" },
1182 { RGB_TO_ULONG(152, 251, 152), "PaleGreen" },
1183 { RGB_TO_ULONG(0 , 255, 127), "spring green" },
1184 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" },
1185 { RGB_TO_ULONG(124, 252, 0 ), "lawn green" },
1186 { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" },
1187 { RGB_TO_ULONG(0 , 255, 0 ), "green" },
1188 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" },
1189 { RGB_TO_ULONG(0 , 250, 154), "medium spring green" },
1190 { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" },
1191 { RGB_TO_ULONG(173, 255, 47 ), "green yellow" },
1192 { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" },
1193 { RGB_TO_ULONG(50 , 205, 50 ), "lime green" },
1194 { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" },
1195 { RGB_TO_ULONG(154, 205, 50 ), "yellow green" },
1196 { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" },
1197 { RGB_TO_ULONG(34 , 139, 34 ), "forest green" },
1198 { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" },
1199 { RGB_TO_ULONG(107, 142, 35 ), "olive drab" },
1200 { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" },
1201 { RGB_TO_ULONG(189, 183, 107), "dark khaki" },
1202 { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" },
1203 { RGB_TO_ULONG(240, 230, 140), "khaki" },
1204 { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" },
1205 { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" },
1206 { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" },
1207 { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" },
1208 { RGB_TO_ULONG(255, 255, 224), "light yellow" },
1209 { RGB_TO_ULONG(255, 255, 224), "LightYellow" },
1210 { RGB_TO_ULONG(255, 255, 0 ), "yellow" },
1211 { RGB_TO_ULONG(255, 215, 0 ), "gold" },
1212 { RGB_TO_ULONG(238, 221, 130), "light goldenrod" },
1213 { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" },
1214 { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" },
1215 { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" },
1216 { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" },
1217 { RGB_TO_ULONG(188, 143, 143), "rosy brown" },
1218 { RGB_TO_ULONG(188, 143, 143), "RosyBrown" },
1219 { RGB_TO_ULONG(205, 92 , 92 ), "indian red" },
1220 { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" },
1221 { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" },
1222 { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" },
1223 { RGB_TO_ULONG(160, 82 , 45 ), "sienna" },
1224 { RGB_TO_ULONG(205, 133, 63 ), "peru" },
1225 { RGB_TO_ULONG(222, 184, 135), "burlywood" },
1226 { RGB_TO_ULONG(245, 245, 220), "beige" },
1227 { RGB_TO_ULONG(245, 222, 179), "wheat" },
1228 { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" },
1229 { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" },
1230 { RGB_TO_ULONG(210, 180, 140), "tan" },
1231 { RGB_TO_ULONG(210, 105, 30 ), "chocolate" },
1232 { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" },
1233 { RGB_TO_ULONG(165, 42 , 42 ), "brown" },
1234 { RGB_TO_ULONG(233, 150, 122), "dark salmon" },
1235 { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" },
1236 { RGB_TO_ULONG(250, 128, 114), "salmon" },
1237 { RGB_TO_ULONG(255, 160, 122), "light salmon" },
1238 { RGB_TO_ULONG(255, 160, 122), "LightSalmon" },
1239 { RGB_TO_ULONG(255, 165, 0 ), "orange" },
1240 { RGB_TO_ULONG(255, 140, 0 ), "dark orange" },
1241 { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" },
1242 { RGB_TO_ULONG(255, 127, 80 ), "coral" },
1243 { RGB_TO_ULONG(240, 128, 128), "light coral" },
1244 { RGB_TO_ULONG(240, 128, 128), "LightCoral" },
1245 { RGB_TO_ULONG(255, 99 , 71 ), "tomato" },
1246 { RGB_TO_ULONG(255, 69 , 0 ), "orange red" },
1247 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" },
1248 { RGB_TO_ULONG(255, 0 , 0 ), "red" },
1249 { RGB_TO_ULONG(255, 105, 180), "hot pink" },
1250 { RGB_TO_ULONG(255, 105, 180), "HotPink" },
1251 { RGB_TO_ULONG(255, 20 , 147), "deep pink" },
1252 { RGB_TO_ULONG(255, 20 , 147), "DeepPink" },
1253 { RGB_TO_ULONG(255, 192, 203), "pink" },
1254 { RGB_TO_ULONG(255, 182, 193), "light pink" },
1255 { RGB_TO_ULONG(255, 182, 193), "LightPink" },
1256 { RGB_TO_ULONG(219, 112, 147), "pale violet red" },
1257 { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" },
1258 { RGB_TO_ULONG(176, 48 , 96 ), "maroon" },
1259 { RGB_TO_ULONG(199, 21 , 133), "medium violet red" },
1260 { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" },
1261 { RGB_TO_ULONG(208, 32 , 144), "violet red" },
1262 { RGB_TO_ULONG(208, 32 , 144), "VioletRed" },
1263 { RGB_TO_ULONG(255, 0 , 255), "magenta" },
1264 { RGB_TO_ULONG(238, 130, 238), "violet" },
1265 { RGB_TO_ULONG(221, 160, 221), "plum" },
1266 { RGB_TO_ULONG(218, 112, 214), "orchid" },
1267 { RGB_TO_ULONG(186, 85 , 211), "medium orchid" },
1268 { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" },
1269 { RGB_TO_ULONG(153, 50 , 204), "dark orchid" },
1270 { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" },
1271 { RGB_TO_ULONG(148, 0 , 211), "dark violet" },
1272 { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" },
1273 { RGB_TO_ULONG(138, 43 , 226), "blue violet" },
1274 { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" },
1275 { RGB_TO_ULONG(160, 32 , 240), "purple" },
1276 { RGB_TO_ULONG(147, 112, 219), "medium purple" },
1277 { RGB_TO_ULONG(147, 112, 219), "MediumPurple" },
1278 { RGB_TO_ULONG(216, 191, 216), "thistle" },
1279 { RGB_TO_ULONG(255, 250, 250), "snow1" },
1280 { RGB_TO_ULONG(238, 233, 233), "snow2" },
1281 { RGB_TO_ULONG(205, 201, 201), "snow3" },
1282 { RGB_TO_ULONG(139, 137, 137), "snow4" },
1283 { RGB_TO_ULONG(255, 245, 238), "seashell1" },
1284 { RGB_TO_ULONG(238, 229, 222), "seashell2" },
1285 { RGB_TO_ULONG(205, 197, 191), "seashell3" },
1286 { RGB_TO_ULONG(139, 134, 130), "seashell4" },
1287 { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" },
1288 { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" },
1289 { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" },
1290 { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" },
1291 { RGB_TO_ULONG(255, 228, 196), "bisque1" },
1292 { RGB_TO_ULONG(238, 213, 183), "bisque2" },
1293 { RGB_TO_ULONG(205, 183, 158), "bisque3" },
1294 { RGB_TO_ULONG(139, 125, 107), "bisque4" },
1295 { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" },
1296 { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" },
1297 { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" },
1298 { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" },
1299 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" },
1300 { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" },
1301 { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" },
1302 { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" },
1303 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" },
1304 { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" },
1305 { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" },
1306 { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" },
1307 { RGB_TO_ULONG(255, 248, 220), "cornsilk1" },
1308 { RGB_TO_ULONG(238, 232, 205), "cornsilk2" },
1309 { RGB_TO_ULONG(205, 200, 177), "cornsilk3" },
1310 { RGB_TO_ULONG(139, 136, 120), "cornsilk4" },
1311 { RGB_TO_ULONG(255, 255, 240), "ivory1" },
1312 { RGB_TO_ULONG(238, 238, 224), "ivory2" },
1313 { RGB_TO_ULONG(205, 205, 193), "ivory3" },
1314 { RGB_TO_ULONG(139, 139, 131), "ivory4" },
1315 { RGB_TO_ULONG(240, 255, 240), "honeydew1" },
1316 { RGB_TO_ULONG(224, 238, 224), "honeydew2" },
1317 { RGB_TO_ULONG(193, 205, 193), "honeydew3" },
1318 { RGB_TO_ULONG(131, 139, 131), "honeydew4" },
1319 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" },
1320 { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" },
1321 { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" },
1322 { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" },
1323 { RGB_TO_ULONG(255, 228, 225), "MistyRose1" },
1324 { RGB_TO_ULONG(238, 213, 210), "MistyRose2" },
1325 { RGB_TO_ULONG(205, 183, 181), "MistyRose3" },
1326 { RGB_TO_ULONG(139, 125, 123), "MistyRose4" },
1327 { RGB_TO_ULONG(240, 255, 255), "azure1" },
1328 { RGB_TO_ULONG(224, 238, 238), "azure2" },
1329 { RGB_TO_ULONG(193, 205, 205), "azure3" },
1330 { RGB_TO_ULONG(131, 139, 139), "azure4" },
1331 { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" },
1332 { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" },
1333 { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" },
1334 { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" },
1335 { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" },
1336 { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" },
1337 { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" },
1338 { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" },
1339 { RGB_TO_ULONG(0 , 0 , 255), "blue1" },
1340 { RGB_TO_ULONG(0 , 0 , 238), "blue2" },
1341 { RGB_TO_ULONG(0 , 0 , 205), "blue3" },
1342 { RGB_TO_ULONG(0 , 0 , 139), "blue4" },
1343 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" },
1344 { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" },
1345 { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" },
1346 { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" },
1347 { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" },
1348 { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" },
1349 { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" },
1350 { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" },
1351 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" },
1352 { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" },
1353 { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" },
1354 { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" },
1355 { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" },
1356 { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" },
1357 { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" },
1358 { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" },
1359 { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" },
1360 { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" },
1361 { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" },
1362 { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" },
1363 { RGB_TO_ULONG(198, 226, 255), "SlateGray1" },
1364 { RGB_TO_ULONG(185, 211, 238), "SlateGray2" },
1365 { RGB_TO_ULONG(159, 182, 205), "SlateGray3" },
1366 { RGB_TO_ULONG(108, 123, 139), "SlateGray4" },
1367 { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" },
1368 { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" },
1369 { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" },
1370 { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" },
1371 { RGB_TO_ULONG(191, 239, 255), "LightBlue1" },
1372 { RGB_TO_ULONG(178, 223, 238), "LightBlue2" },
1373 { RGB_TO_ULONG(154, 192, 205), "LightBlue3" },
1374 { RGB_TO_ULONG(104, 131, 139), "LightBlue4" },
1375 { RGB_TO_ULONG(224, 255, 255), "LightCyan1" },
1376 { RGB_TO_ULONG(209, 238, 238), "LightCyan2" },
1377 { RGB_TO_ULONG(180, 205, 205), "LightCyan3" },
1378 { RGB_TO_ULONG(122, 139, 139), "LightCyan4" },
1379 { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" },
1380 { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" },
1381 { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" },
1382 { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" },
1383 { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" },
1384 { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" },
1385 { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" },
1386 { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" },
1387 { RGB_TO_ULONG(0 , 245, 255), "turquoise1" },
1388 { RGB_TO_ULONG(0 , 229, 238), "turquoise2" },
1389 { RGB_TO_ULONG(0 , 197, 205), "turquoise3" },
1390 { RGB_TO_ULONG(0 , 134, 139), "turquoise4" },
1391 { RGB_TO_ULONG(0 , 255, 255), "cyan1" },
1392 { RGB_TO_ULONG(0 , 238, 238), "cyan2" },
1393 { RGB_TO_ULONG(0 , 205, 205), "cyan3" },
1394 { RGB_TO_ULONG(0 , 139, 139), "cyan4" },
1395 { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" },
1396 { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" },
1397 { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" },
1398 { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" },
1399 { RGB_TO_ULONG(127, 255, 212), "aquamarine1" },
1400 { RGB_TO_ULONG(118, 238, 198), "aquamarine2" },
1401 { RGB_TO_ULONG(102, 205, 170), "aquamarine3" },
1402 { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" },
1403 { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" },
1404 { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" },
1405 { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" },
1406 { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" },
1407 { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" },
1408 { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" },
1409 { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" },
1410 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" },
1411 { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" },
1412 { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" },
1413 { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" },
1414 { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" },
1415 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" },
1416 { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" },
1417 { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" },
1418 { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" },
1419 { RGB_TO_ULONG(0 , 255, 0 ), "green1" },
1420 { RGB_TO_ULONG(0 , 238, 0 ), "green2" },
1421 { RGB_TO_ULONG(0 , 205, 0 ), "green3" },
1422 { RGB_TO_ULONG(0 , 139, 0 ), "green4" },
1423 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" },
1424 { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" },
1425 { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" },
1426 { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" },
1427 { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" },
1428 { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" },
1429 { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" },
1430 { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" },
1431 { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" },
1432 { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" },
1433 { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" },
1434 { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" },
1435 { RGB_TO_ULONG(255, 246, 143), "khaki1" },
1436 { RGB_TO_ULONG(238, 230, 133), "khaki2" },
1437 { RGB_TO_ULONG(205, 198, 115), "khaki3" },
1438 { RGB_TO_ULONG(139, 134, 78 ), "khaki4" },
1439 { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" },
1440 { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" },
1441 { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" },
1442 { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" },
1443 { RGB_TO_ULONG(255, 255, 224), "LightYellow1" },
1444 { RGB_TO_ULONG(238, 238, 209), "LightYellow2" },
1445 { RGB_TO_ULONG(205, 205, 180), "LightYellow3" },
1446 { RGB_TO_ULONG(139, 139, 122), "LightYellow4" },
1447 { RGB_TO_ULONG(255, 255, 0 ), "yellow1" },
1448 { RGB_TO_ULONG(238, 238, 0 ), "yellow2" },
1449 { RGB_TO_ULONG(205, 205, 0 ), "yellow3" },
1450 { RGB_TO_ULONG(139, 139, 0 ), "yellow4" },
1451 { RGB_TO_ULONG(255, 215, 0 ), "gold1" },
1452 { RGB_TO_ULONG(238, 201, 0 ), "gold2" },
1453 { RGB_TO_ULONG(205, 173, 0 ), "gold3" },
1454 { RGB_TO_ULONG(139, 117, 0 ), "gold4" },
1455 { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" },
1456 { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" },
1457 { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" },
1458 { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" },
1459 { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" },
1460 { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" },
1461 { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" },
1462 { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" },
1463 { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" },
1464 { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" },
1465 { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" },
1466 { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" },
1467 { RGB_TO_ULONG(255, 106, 106), "IndianRed1" },
1468 { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" },
1469 { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" },
1470 { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" },
1471 { RGB_TO_ULONG(255, 130, 71 ), "sienna1" },
1472 { RGB_TO_ULONG(238, 121, 66 ), "sienna2" },
1473 { RGB_TO_ULONG(205, 104, 57 ), "sienna3" },
1474 { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" },
1475 { RGB_TO_ULONG(255, 211, 155), "burlywood1" },
1476 { RGB_TO_ULONG(238, 197, 145), "burlywood2" },
1477 { RGB_TO_ULONG(205, 170, 125), "burlywood3" },
1478 { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" },
1479 { RGB_TO_ULONG(255, 231, 186), "wheat1" },
1480 { RGB_TO_ULONG(238, 216, 174), "wheat2" },
1481 { RGB_TO_ULONG(205, 186, 150), "wheat3" },
1482 { RGB_TO_ULONG(139, 126, 102), "wheat4" },
1483 { RGB_TO_ULONG(255, 165, 79 ), "tan1" },
1484 { RGB_TO_ULONG(238, 154, 73 ), "tan2" },
1485 { RGB_TO_ULONG(205, 133, 63 ), "tan3" },
1486 { RGB_TO_ULONG(139, 90 , 43 ), "tan4" },
1487 { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" },
1488 { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" },
1489 { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" },
1490 { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" },
1491 { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" },
1492 { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" },
1493 { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" },
1494 { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" },
1495 { RGB_TO_ULONG(255, 64 , 64 ), "brown1" },
1496 { RGB_TO_ULONG(238, 59 , 59 ), "brown2" },
1497 { RGB_TO_ULONG(205, 51 , 51 ), "brown3" },
1498 { RGB_TO_ULONG(139, 35 , 35 ), "brown4" },
1499 { RGB_TO_ULONG(255, 140, 105), "salmon1" },
1500 { RGB_TO_ULONG(238, 130, 98 ), "salmon2" },
1501 { RGB_TO_ULONG(205, 112, 84 ), "salmon3" },
1502 { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" },
1503 { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" },
1504 { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" },
1505 { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" },
1506 { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" },
1507 { RGB_TO_ULONG(255, 165, 0 ), "orange1" },
1508 { RGB_TO_ULONG(238, 154, 0 ), "orange2" },
1509 { RGB_TO_ULONG(205, 133, 0 ), "orange3" },
1510 { RGB_TO_ULONG(139, 90 , 0 ), "orange4" },
1511 { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" },
1512 { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" },
1513 { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" },
1514 { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" },
1515 { RGB_TO_ULONG(255, 114, 86 ), "coral1" },
1516 { RGB_TO_ULONG(238, 106, 80 ), "coral2" },
1517 { RGB_TO_ULONG(205, 91 , 69 ), "coral3" },
1518 { RGB_TO_ULONG(139, 62 , 47 ), "coral4" },
1519 { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" },
1520 { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" },
1521 { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" },
1522 { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" },
1523 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" },
1524 { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" },
1525 { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" },
1526 { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" },
1527 { RGB_TO_ULONG(255, 0 , 0 ), "red1" },
1528 { RGB_TO_ULONG(238, 0 , 0 ), "red2" },
1529 { RGB_TO_ULONG(205, 0 , 0 ), "red3" },
1530 { RGB_TO_ULONG(139, 0 , 0 ), "red4" },
1531 { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" },
1532 { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" },
1533 { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" },
1534 { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" },
1535 { RGB_TO_ULONG(255, 110, 180), "HotPink1" },
1536 { RGB_TO_ULONG(238, 106, 167), "HotPink2" },
1537 { RGB_TO_ULONG(205, 96 , 144), "HotPink3" },
1538 { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" },
1539 { RGB_TO_ULONG(255, 181, 197), "pink1" },
1540 { RGB_TO_ULONG(238, 169, 184), "pink2" },
1541 { RGB_TO_ULONG(205, 145, 158), "pink3" },
1542 { RGB_TO_ULONG(139, 99 , 108), "pink4" },
1543 { RGB_TO_ULONG(255, 174, 185), "LightPink1" },
1544 { RGB_TO_ULONG(238, 162, 173), "LightPink2" },
1545 { RGB_TO_ULONG(205, 140, 149), "LightPink3" },
1546 { RGB_TO_ULONG(139, 95 , 101), "LightPink4" },
1547 { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" },
1548 { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" },
1549 { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" },
1550 { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" },
1551 { RGB_TO_ULONG(255, 52 , 179), "maroon1" },
1552 { RGB_TO_ULONG(238, 48 , 167), "maroon2" },
1553 { RGB_TO_ULONG(205, 41 , 144), "maroon3" },
1554 { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" },
1555 { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" },
1556 { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" },
1557 { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" },
1558 { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" },
1559 { RGB_TO_ULONG(255, 0 , 255), "magenta1" },
1560 { RGB_TO_ULONG(238, 0 , 238), "magenta2" },
1561 { RGB_TO_ULONG(205, 0 , 205), "magenta3" },
1562 { RGB_TO_ULONG(139, 0 , 139), "magenta4" },
1563 { RGB_TO_ULONG(255, 131, 250), "orchid1" },
1564 { RGB_TO_ULONG(238, 122, 233), "orchid2" },
1565 { RGB_TO_ULONG(205, 105, 201), "orchid3" },
1566 { RGB_TO_ULONG(139, 71 , 137), "orchid4" },
1567 { RGB_TO_ULONG(255, 187, 255), "plum1" },
1568 { RGB_TO_ULONG(238, 174, 238), "plum2" },
1569 { RGB_TO_ULONG(205, 150, 205), "plum3" },
1570 { RGB_TO_ULONG(139, 102, 139), "plum4" },
1571 { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" },
1572 { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" },
1573 { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" },
1574 { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" },
1575 { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" },
1576 { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" },
1577 { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" },
1578 { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" },
1579 { RGB_TO_ULONG(155, 48 , 255), "purple1" },
1580 { RGB_TO_ULONG(145, 44 , 238), "purple2" },
1581 { RGB_TO_ULONG(125, 38 , 205), "purple3" },
1582 { RGB_TO_ULONG(85 , 26 , 139), "purple4" },
1583 { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" },
1584 { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" },
1585 { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" },
1586 { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" },
1587 { RGB_TO_ULONG(255, 225, 255), "thistle1" },
1588 { RGB_TO_ULONG(238, 210, 238), "thistle2" },
1589 { RGB_TO_ULONG(205, 181, 205), "thistle3" },
1590 { RGB_TO_ULONG(139, 123, 139), "thistle4" },
1591 { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" },
1592 { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" },
1593 { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" },
1594 { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" },
1595 { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" },
1596 { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" },
1597 { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" },
1598 { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" },
1599 { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" },
1600 { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" },
1601 { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" },
1602 { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" },
1603 { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" },
1604 { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" },
1605 { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" },
1606 { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" },
1607 { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" },
1608 { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" },
1609 { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" },
1610 { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" },
1611 { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" },
1612 { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" },
1613 { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" },
1614 { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" },
1615 { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" },
1616 { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" },
1617 { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" },
1618 { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" },
1619 { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" },
1620 { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" },
1621 { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" },
1622 { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" },
1623 { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" },
1624 { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" },
1625 { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" },
1626 { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" },
1627 { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" },
1628 { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" },
1629 { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" },
1630 { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" },
1631 { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" },
1632 { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" },
1633 { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" },
1634 { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" },
1635 { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" },
1636 { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" },
1637 { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" },
1638 { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" },
1639 { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" },
1640 { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" },
1641 { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" },
1642 { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" },
1643 { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" },
1644 { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" },
1645 { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" },
1646 { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" },
1647 { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" },
1648 { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" },
1649 { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" },
1650 { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" },
1651 { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" },
1652 { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" },
1653 { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" },
1654 { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" },
1655 { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" },
1656 { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" },
1657 { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" },
1658 { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" },
1659 { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" },
1660 { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" },
1661 { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" },
1662 { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" },
1663 { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" },
1664 { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" },
1665 { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" },
1666 { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" },
1667 { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" },
1668 { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" },
1669 { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" },
1670 { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" },
1671 { RGB_TO_ULONG(102, 102, 102), "gray40" },
1672 { RGB_TO_ULONG(102, 102, 102), "grey40" },
1673 { RGB_TO_ULONG(105, 105, 105), "gray41" },
1674 { RGB_TO_ULONG(105, 105, 105), "grey41" },
1675 { RGB_TO_ULONG(107, 107, 107), "gray42" },
1676 { RGB_TO_ULONG(107, 107, 107), "grey42" },
1677 { RGB_TO_ULONG(110, 110, 110), "gray43" },
1678 { RGB_TO_ULONG(110, 110, 110), "grey43" },
1679 { RGB_TO_ULONG(112, 112, 112), "gray44" },
1680 { RGB_TO_ULONG(112, 112, 112), "grey44" },
1681 { RGB_TO_ULONG(115, 115, 115), "gray45" },
1682 { RGB_TO_ULONG(115, 115, 115), "grey45" },
1683 { RGB_TO_ULONG(117, 117, 117), "gray46" },
1684 { RGB_TO_ULONG(117, 117, 117), "grey46" },
1685 { RGB_TO_ULONG(120, 120, 120), "gray47" },
1686 { RGB_TO_ULONG(120, 120, 120), "grey47" },
1687 { RGB_TO_ULONG(122, 122, 122), "gray48" },
1688 { RGB_TO_ULONG(122, 122, 122), "grey48" },
1689 { RGB_TO_ULONG(125, 125, 125), "gray49" },
1690 { RGB_TO_ULONG(125, 125, 125), "grey49" },
1691 { RGB_TO_ULONG(127, 127, 127), "gray50" },
1692 { RGB_TO_ULONG(127, 127, 127), "grey50" },
1693 { RGB_TO_ULONG(130, 130, 130), "gray51" },
1694 { RGB_TO_ULONG(130, 130, 130), "grey51" },
1695 { RGB_TO_ULONG(133, 133, 133), "gray52" },
1696 { RGB_TO_ULONG(133, 133, 133), "grey52" },
1697 { RGB_TO_ULONG(135, 135, 135), "gray53" },
1698 { RGB_TO_ULONG(135, 135, 135), "grey53" },
1699 { RGB_TO_ULONG(138, 138, 138), "gray54" },
1700 { RGB_TO_ULONG(138, 138, 138), "grey54" },
1701 { RGB_TO_ULONG(140, 140, 140), "gray55" },
1702 { RGB_TO_ULONG(140, 140, 140), "grey55" },
1703 { RGB_TO_ULONG(143, 143, 143), "gray56" },
1704 { RGB_TO_ULONG(143, 143, 143), "grey56" },
1705 { RGB_TO_ULONG(145, 145, 145), "gray57" },
1706 { RGB_TO_ULONG(145, 145, 145), "grey57" },
1707 { RGB_TO_ULONG(148, 148, 148), "gray58" },
1708 { RGB_TO_ULONG(148, 148, 148), "grey58" },
1709 { RGB_TO_ULONG(150, 150, 150), "gray59" },
1710 { RGB_TO_ULONG(150, 150, 150), "grey59" },
1711 { RGB_TO_ULONG(153, 153, 153), "gray60" },
1712 { RGB_TO_ULONG(153, 153, 153), "grey60" },
1713 { RGB_TO_ULONG(156, 156, 156), "gray61" },
1714 { RGB_TO_ULONG(156, 156, 156), "grey61" },
1715 { RGB_TO_ULONG(158, 158, 158), "gray62" },
1716 { RGB_TO_ULONG(158, 158, 158), "grey62" },
1717 { RGB_TO_ULONG(161, 161, 161), "gray63" },
1718 { RGB_TO_ULONG(161, 161, 161), "grey63" },
1719 { RGB_TO_ULONG(163, 163, 163), "gray64" },
1720 { RGB_TO_ULONG(163, 163, 163), "grey64" },
1721 { RGB_TO_ULONG(166, 166, 166), "gray65" },
1722 { RGB_TO_ULONG(166, 166, 166), "grey65" },
1723 { RGB_TO_ULONG(168, 168, 168), "gray66" },
1724 { RGB_TO_ULONG(168, 168, 168), "grey66" },
1725 { RGB_TO_ULONG(171, 171, 171), "gray67" },
1726 { RGB_TO_ULONG(171, 171, 171), "grey67" },
1727 { RGB_TO_ULONG(173, 173, 173), "gray68" },
1728 { RGB_TO_ULONG(173, 173, 173), "grey68" },
1729 { RGB_TO_ULONG(176, 176, 176), "gray69" },
1730 { RGB_TO_ULONG(176, 176, 176), "grey69" },
1731 { RGB_TO_ULONG(179, 179, 179), "gray70" },
1732 { RGB_TO_ULONG(179, 179, 179), "grey70" },
1733 { RGB_TO_ULONG(181, 181, 181), "gray71" },
1734 { RGB_TO_ULONG(181, 181, 181), "grey71" },
1735 { RGB_TO_ULONG(184, 184, 184), "gray72" },
1736 { RGB_TO_ULONG(184, 184, 184), "grey72" },
1737 { RGB_TO_ULONG(186, 186, 186), "gray73" },
1738 { RGB_TO_ULONG(186, 186, 186), "grey73" },
1739 { RGB_TO_ULONG(189, 189, 189), "gray74" },
1740 { RGB_TO_ULONG(189, 189, 189), "grey74" },
1741 { RGB_TO_ULONG(191, 191, 191), "gray75" },
1742 { RGB_TO_ULONG(191, 191, 191), "grey75" },
1743 { RGB_TO_ULONG(194, 194, 194), "gray76" },
1744 { RGB_TO_ULONG(194, 194, 194), "grey76" },
1745 { RGB_TO_ULONG(196, 196, 196), "gray77" },
1746 { RGB_TO_ULONG(196, 196, 196), "grey77" },
1747 { RGB_TO_ULONG(199, 199, 199), "gray78" },
1748 { RGB_TO_ULONG(199, 199, 199), "grey78" },
1749 { RGB_TO_ULONG(201, 201, 201), "gray79" },
1750 { RGB_TO_ULONG(201, 201, 201), "grey79" },
1751 { RGB_TO_ULONG(204, 204, 204), "gray80" },
1752 { RGB_TO_ULONG(204, 204, 204), "grey80" },
1753 { RGB_TO_ULONG(207, 207, 207), "gray81" },
1754 { RGB_TO_ULONG(207, 207, 207), "grey81" },
1755 { RGB_TO_ULONG(209, 209, 209), "gray82" },
1756 { RGB_TO_ULONG(209, 209, 209), "grey82" },
1757 { RGB_TO_ULONG(212, 212, 212), "gray83" },
1758 { RGB_TO_ULONG(212, 212, 212), "grey83" },
1759 { RGB_TO_ULONG(214, 214, 214), "gray84" },
1760 { RGB_TO_ULONG(214, 214, 214), "grey84" },
1761 { RGB_TO_ULONG(217, 217, 217), "gray85" },
1762 { RGB_TO_ULONG(217, 217, 217), "grey85" },
1763 { RGB_TO_ULONG(219, 219, 219), "gray86" },
1764 { RGB_TO_ULONG(219, 219, 219), "grey86" },
1765 { RGB_TO_ULONG(222, 222, 222), "gray87" },
1766 { RGB_TO_ULONG(222, 222, 222), "grey87" },
1767 { RGB_TO_ULONG(224, 224, 224), "gray88" },
1768 { RGB_TO_ULONG(224, 224, 224), "grey88" },
1769 { RGB_TO_ULONG(227, 227, 227), "gray89" },
1770 { RGB_TO_ULONG(227, 227, 227), "grey89" },
1771 { RGB_TO_ULONG(229, 229, 229), "gray90" },
1772 { RGB_TO_ULONG(229, 229, 229), "grey90" },
1773 { RGB_TO_ULONG(232, 232, 232), "gray91" },
1774 { RGB_TO_ULONG(232, 232, 232), "grey91" },
1775 { RGB_TO_ULONG(235, 235, 235), "gray92" },
1776 { RGB_TO_ULONG(235, 235, 235), "grey92" },
1777 { RGB_TO_ULONG(237, 237, 237), "gray93" },
1778 { RGB_TO_ULONG(237, 237, 237), "grey93" },
1779 { RGB_TO_ULONG(240, 240, 240), "gray94" },
1780 { RGB_TO_ULONG(240, 240, 240), "grey94" },
1781 { RGB_TO_ULONG(242, 242, 242), "gray95" },
1782 { RGB_TO_ULONG(242, 242, 242), "grey95" },
1783 { RGB_TO_ULONG(245, 245, 245), "gray96" },
1784 { RGB_TO_ULONG(245, 245, 245), "grey96" },
1785 { RGB_TO_ULONG(247, 247, 247), "gray97" },
1786 { RGB_TO_ULONG(247, 247, 247), "grey97" },
1787 { RGB_TO_ULONG(250, 250, 250), "gray98" },
1788 { RGB_TO_ULONG(250, 250, 250), "grey98" },
1789 { RGB_TO_ULONG(252, 252, 252), "gray99" },
1790 { RGB_TO_ULONG(252, 252, 252), "grey99" },
1791 { RGB_TO_ULONG(255, 255, 255), "gray100" },
1792 { RGB_TO_ULONG(255, 255, 255), "grey100" },
1793 { RGB_TO_ULONG(169, 169, 169), "dark grey" },
1794 { RGB_TO_ULONG(169, 169, 169), "DarkGrey" },
1795 { RGB_TO_ULONG(169, 169, 169), "dark gray" },
1796 { RGB_TO_ULONG(169, 169, 169), "DarkGray" },
1797 { RGB_TO_ULONG(0 , 0 , 139), "dark blue" },
1798 { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" },
1799 { RGB_TO_ULONG(0 , 139, 139), "dark cyan" },
1800 { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" },
1801 { RGB_TO_ULONG(139, 0 , 139), "dark magenta" },
1802 { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" },
1803 { RGB_TO_ULONG(139, 0 , 0 ), "dark red" },
1804 { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" },
1805 { RGB_TO_ULONG(144, 238, 144), "light green" },
1806 { RGB_TO_ULONG(144, 238, 144), "LightGreen" }
1807 };
1808
1809 unsigned long
1810 mac_color_map_lookup (colorname)
1811 char *colorname;
1812 {
1813 Lisp_Object ret = Qnil;
1814 int i;
1815
1816 BLOCK_INPUT;
1817
1818 for (i = 0; i < sizeof (mac_color_map) / sizeof (mac_color_map[0]); i++)
1819 if (stricmp (colorname, mac_color_map[i].name) == 0)
1820 {
1821 ret = mac_color_map[i].color;
1822 break;
1823 }
1824
1825 UNBLOCK_INPUT;
1826
1827 return ret;
1828 }
1829
1830 Lisp_Object
1831 x_to_mac_color (colorname)
1832 char * colorname;
1833 {
1834 register Lisp_Object tail, ret = Qnil;
1835
1836 BLOCK_INPUT;
1837
1838 if (colorname[0] == '#')
1839 {
1840 /* Could be an old-style RGB Device specification. */
1841 char *color;
1842 int size;
1843 color = colorname + 1;
1844
1845 size = strlen(color);
1846 if (size == 3 || size == 6 || size == 9 || size == 12)
1847 {
1848 unsigned long colorval;
1849 int i, pos;
1850 pos = 0;
1851 size /= 3;
1852 colorval = 0;
1853
1854 for (i = 0; i < 3; i++)
1855 {
1856 char *end;
1857 char t;
1858 unsigned long value;
1859
1860 /* The check for 'x' in the following conditional takes into
1861 account the fact that strtol allows a "0x" in front of
1862 our numbers, and we don't. */
1863 if (!isxdigit(color[0]) || color[1] == 'x')
1864 break;
1865 t = color[size];
1866 color[size] = '\0';
1867 value = strtoul(color, &end, 16);
1868 color[size] = t;
1869 if (errno == ERANGE || end - color != size)
1870 break;
1871 switch (size)
1872 {
1873 case 1:
1874 value = value * 0x10;
1875 break;
1876 case 2:
1877 break;
1878 case 3:
1879 value /= 0x10;
1880 break;
1881 case 4:
1882 value /= 0x100;
1883 break;
1884 }
1885 colorval |= (value << pos);
1886 pos += 0x8;
1887 if (i == 2)
1888 {
1889 UNBLOCK_INPUT;
1890 return (colorval);
1891 }
1892 color = end;
1893 }
1894 }
1895 }
1896 else if (strnicmp(colorname, "rgb:", 4) == 0)
1897 {
1898 char *color;
1899 unsigned long colorval;
1900 int i, pos;
1901 pos = 0;
1902
1903 colorval = 0;
1904 color = colorname + 4;
1905 for (i = 0; i < 3; i++)
1906 {
1907 char *end;
1908 unsigned long value;
1909
1910 /* The check for 'x' in the following conditional takes into
1911 account the fact that strtol allows a "0x" in front of
1912 our numbers, and we don't. */
1913 if (!isxdigit(color[0]) || color[1] == 'x')
1914 break;
1915 value = strtoul(color, &end, 16);
1916 if (errno == ERANGE)
1917 break;
1918 switch (end - color)
1919 {
1920 case 1:
1921 value = value * 0x10 + value;
1922 break;
1923 case 2:
1924 break;
1925 case 3:
1926 value /= 0x10;
1927 break;
1928 case 4:
1929 value /= 0x100;
1930 break;
1931 default:
1932 value = ULONG_MAX;
1933 }
1934 if (value == ULONG_MAX)
1935 break;
1936 colorval |= (value << pos);
1937 pos += 0x8;
1938 if (i == 2)
1939 {
1940 if (*end != '\0')
1941 break;
1942 UNBLOCK_INPUT;
1943 return (colorval);
1944 }
1945 if (*end != '/')
1946 break;
1947 color = end + 1;
1948 }
1949 }
1950 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1951 {
1952 /* This is an RGB Intensity specification. */
1953 char *color;
1954 unsigned long colorval;
1955 int i, pos;
1956 pos = 0;
1957
1958 colorval = 0;
1959 color = colorname + 5;
1960 for (i = 0; i < 3; i++)
1961 {
1962 char *end;
1963 double value;
1964 unsigned long val;
1965
1966 value = strtod(color, &end);
1967 if (errno == ERANGE)
1968 break;
1969 if (value < 0.0 || value > 1.0)
1970 break;
1971 val = (unsigned long)(0x100 * value);
1972 /* We used 0x100 instead of 0xFF to give an continuous
1973 range between 0.0 and 1.0 inclusive. The next statement
1974 fixes the 1.0 case. */
1975 if (val == 0x100)
1976 val = 0xFF;
1977 colorval |= (val << pos);
1978 pos += 0x8;
1979 if (i == 2)
1980 {
1981 if (*end != '\0')
1982 break;
1983 UNBLOCK_INPUT;
1984 return (colorval);
1985 }
1986 if (*end != '/')
1987 break;
1988 color = end + 1;
1989 }
1990 }
1991
1992 ret = mac_color_map_lookup (colorname);
1993
1994 UNBLOCK_INPUT;
1995 return ret;
1996 }
1997
1998 /* Gamma-correct COLOR on frame F. */
1999
2000 void
2001 gamma_correct (f, color)
2002 struct frame *f;
2003 unsigned long *color;
2004 {
2005 if (f->gamma)
2006 {
2007 unsigned long red, green, blue;
2008
2009 red = pow (RED_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
2010 green = pow (GREEN_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
2011 blue = pow (BLUE_FROM_ULONG (*color) / 255.0, f->gamma) * 255.0 + 0.5;
2012 *color = RGB_TO_ULONG (red, green, blue);
2013 }
2014 }
2015
2016 /* Decide if color named COLOR is valid for the display associated
2017 with the selected frame; if so, return the rgb values in COLOR_DEF.
2018 If ALLOC is nonzero, allocate a new colormap cell. */
2019
2020 int
2021 mac_defined_color (f, color, color_def, alloc)
2022 FRAME_PTR f;
2023 char *color;
2024 XColor *color_def;
2025 int alloc;
2026 {
2027 register Lisp_Object tem;
2028 unsigned long mac_color_ref;
2029
2030 tem = x_to_mac_color (color);
2031
2032 if (!NILP (tem))
2033 {
2034 if (f)
2035 {
2036 /* Apply gamma correction. */
2037 mac_color_ref = XUINT (tem);
2038 gamma_correct (f, &mac_color_ref);
2039 XSETINT (tem, mac_color_ref);
2040 }
2041
2042 color_def->pixel = mac_color_ref;
2043 color_def->red = RED_FROM_ULONG (mac_color_ref);
2044 color_def->green = GREEN_FROM_ULONG (mac_color_ref);
2045 color_def->blue = BLUE_FROM_ULONG (mac_color_ref);
2046
2047 return 1;
2048 }
2049 else
2050 {
2051 return 0;
2052 }
2053 }
2054
2055 /* Given a string ARG naming a color, compute a pixel value from it
2056 suitable for screen F.
2057 If F is not a color screen, return DEF (default) regardless of what
2058 ARG says. */
2059
2060 int
2061 x_decode_color (f, arg, def)
2062 FRAME_PTR f;
2063 Lisp_Object arg;
2064 int def;
2065 {
2066 XColor cdef;
2067
2068 CHECK_STRING (arg);
2069
2070 if (strcmp (SDATA (arg), "black") == 0)
2071 return BLACK_PIX_DEFAULT (f);
2072 else if (strcmp (SDATA (arg), "white") == 0)
2073 return WHITE_PIX_DEFAULT (f);
2074
2075 #if 0
2076 if ((FRAME_MAC_DISPLAY_INFO (f)->n_planes
2077 * FRAME_MAC_DISPLAY_INFO (f)->n_cbits) == 1)
2078 return def;
2079 #endif
2080
2081 if (mac_defined_color (f, SDATA (arg), &cdef, 1))
2082 return cdef.pixel;
2083
2084 /* defined_color failed; return an ultimate default. */
2085 return def;
2086 }
2087 \f
2088 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2089 the previous value of that parameter, NEW_VALUE is the new value. */
2090
2091 static void
2092 x_set_line_spacing (f, new_value, old_value)
2093 struct frame *f;
2094 Lisp_Object new_value, old_value;
2095 {
2096 if (NILP (new_value))
2097 f->extra_line_spacing = 0;
2098 else if (NATNUMP (new_value))
2099 f->extra_line_spacing = XFASTINT (new_value);
2100 else
2101 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
2102 Fcons (new_value, Qnil)));
2103 if (FRAME_VISIBLE_P (f))
2104 redraw_frame (f);
2105 }
2106
2107
2108 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2109 the previous value of that parameter, NEW_VALUE is the new value. */
2110
2111 static void
2112 x_set_screen_gamma (f, new_value, old_value)
2113 struct frame *f;
2114 Lisp_Object new_value, old_value;
2115 {
2116 if (NILP (new_value))
2117 f->gamma = 0;
2118 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2119 /* The value 0.4545 is the normal viewing gamma. */
2120 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2121 else
2122 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
2123 Fcons (new_value, Qnil)));
2124
2125 clear_face_cache (0);
2126 }
2127
2128
2129 /* Functions called only from `x_set_frame_param'
2130 to set individual parameters.
2131
2132 If FRAME_MAC_WINDOW (f) is 0,
2133 the frame is being created and its window does not exist yet.
2134 In that case, just record the parameter's new value
2135 in the standard place; do not attempt to change the window. */
2136
2137 void
2138 x_set_foreground_color (f, arg, oldval)
2139 struct frame *f;
2140 Lisp_Object arg, oldval;
2141 {
2142 FRAME_FOREGROUND_PIXEL (f)
2143 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2144
2145 if (FRAME_MAC_WINDOW (f) != 0)
2146 {
2147 update_face_from_frame_parameter (f, Qforeground_color, arg);
2148 if (FRAME_VISIBLE_P (f))
2149 redraw_frame (f);
2150 }
2151 }
2152
2153 void
2154 x_set_background_color (f, arg, oldval)
2155 struct frame *f;
2156 Lisp_Object arg, oldval;
2157 {
2158 FRAME_BACKGROUND_PIXEL (f)
2159 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2160
2161 if (FRAME_MAC_WINDOW (f) != 0)
2162 {
2163 update_face_from_frame_parameter (f, Qbackground_color, arg);
2164
2165 if (FRAME_VISIBLE_P (f))
2166 redraw_frame (f);
2167 }
2168 }
2169
2170 void
2171 x_set_mouse_color (f, arg, oldval)
2172 struct frame *f;
2173 Lisp_Object arg, oldval;
2174 {
2175 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2176 int count;
2177 int mask_color;
2178
2179 if (!EQ (Qnil, arg))
2180 f->output_data.mac->mouse_pixel
2181 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2182 mask_color = FRAME_BACKGROUND_PIXEL (f);
2183
2184 /* Don't let pointers be invisible. */
2185 if (mask_color == f->output_data.mac->mouse_pixel
2186 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2187 f->output_data.mac->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2188
2189 #if 0 /* MAC_TODO : cursor changes */
2190 BLOCK_INPUT;
2191
2192 /* It's not okay to crash if the user selects a screwy cursor. */
2193 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2194
2195 if (!EQ (Qnil, Vx_pointer_shape))
2196 {
2197 CHECK_NUMBER (Vx_pointer_shape);
2198 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2199 }
2200 else
2201 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2202 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2203
2204 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2205 {
2206 CHECK_NUMBER (Vx_nontext_pointer_shape);
2207 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2208 XINT (Vx_nontext_pointer_shape));
2209 }
2210 else
2211 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2212 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2213
2214 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2215 {
2216 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2217 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2218 XINT (Vx_hourglass_pointer_shape));
2219 }
2220 else
2221 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2222 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2223
2224 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2225 if (!EQ (Qnil, Vx_mode_pointer_shape))
2226 {
2227 CHECK_NUMBER (Vx_mode_pointer_shape);
2228 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2229 XINT (Vx_mode_pointer_shape));
2230 }
2231 else
2232 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2233 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2234
2235 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2236 {
2237 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2238 cross_cursor
2239 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2240 XINT (Vx_sensitive_text_pointer_shape));
2241 }
2242 else
2243 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2244
2245 if (!NILP (Vx_window_horizontal_drag_shape))
2246 {
2247 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2248 horizontal_drag_cursor
2249 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2250 XINT (Vx_window_horizontal_drag_shape));
2251 }
2252 else
2253 horizontal_drag_cursor
2254 = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_h_double_arrow);
2255
2256 /* Check and report errors with the above calls. */
2257 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2258 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2259
2260 {
2261 XColor fore_color, back_color;
2262
2263 fore_color.pixel = f->output_data.w32->mouse_pixel;
2264 back_color.pixel = mask_color;
2265 XQueryColor (FRAME_W32_DISPLAY (f),
2266 DefaultColormap (FRAME_W32_DISPLAY (f),
2267 DefaultScreen (FRAME_W32_DISPLAY (f))),
2268 &fore_color);
2269 XQueryColor (FRAME_W32_DISPLAY (f),
2270 DefaultColormap (FRAME_W32_DISPLAY (f),
2271 DefaultScreen (FRAME_W32_DISPLAY (f))),
2272 &back_color);
2273 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2274 &fore_color, &back_color);
2275 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2276 &fore_color, &back_color);
2277 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2278 &fore_color, &back_color);
2279 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2280 &fore_color, &back_color);
2281 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2282 &fore_color, &back_color);
2283 }
2284
2285 if (FRAME_W32_WINDOW (f) != 0)
2286 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2287
2288 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2289 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2290 f->output_data.w32->text_cursor = cursor;
2291
2292 if (nontext_cursor != f->output_data.w32->nontext_cursor
2293 && f->output_data.w32->nontext_cursor != 0)
2294 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2295 f->output_data.w32->nontext_cursor = nontext_cursor;
2296
2297 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2298 && f->output_data.w32->hourglass_cursor != 0)
2299 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2300 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2301
2302 if (mode_cursor != f->output_data.w32->modeline_cursor
2303 && f->output_data.w32->modeline_cursor != 0)
2304 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2305 f->output_data.w32->modeline_cursor = mode_cursor;
2306
2307 if (cross_cursor != f->output_data.w32->cross_cursor
2308 && f->output_data.w32->cross_cursor != 0)
2309 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2310 f->output_data.w32->cross_cursor = cross_cursor;
2311
2312 XFlush (FRAME_W32_DISPLAY (f));
2313 UNBLOCK_INPUT;
2314
2315 update_face_from_frame_parameter (f, Qmouse_color, arg);
2316 #endif /* MAC_TODO */
2317 }
2318
2319 void
2320 x_set_cursor_color (f, arg, oldval)
2321 struct frame *f;
2322 Lisp_Object arg, oldval;
2323 {
2324 unsigned long fore_pixel;
2325
2326 if (!NILP (Vx_cursor_fore_pixel))
2327 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2328 WHITE_PIX_DEFAULT (f));
2329 else
2330 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2331 f->output_data.mac->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2332
2333 /* Make sure that the cursor color differs from the background color. */
2334 if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2335 {
2336 f->output_data.mac->cursor_pixel = f->output_data.mac->mouse_pixel;
2337 if (f->output_data.mac->cursor_pixel == fore_pixel)
2338 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2339 }
2340 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2341
2342 #if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */
2343 if (FRAME_MAC_WINDOW (f) != 0)
2344 {
2345 if (FRAME_VISIBLE_P (f))
2346 {
2347 x_display_cursor (f, 0);
2348 x_display_cursor (f, 1);
2349 }
2350 }
2351 #endif
2352
2353 update_face_from_frame_parameter (f, Qcursor_color, arg);
2354 }
2355
2356 /* Set the border-color of frame F to pixel value PIX.
2357 Note that this does not fully take effect if done before
2358 F has an window. */
2359 void
2360 x_set_border_pixel (f, pix)
2361 struct frame *f;
2362 int pix;
2363 {
2364 f->output_data.mac->border_pixel = pix;
2365
2366 if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0)
2367 {
2368 if (FRAME_VISIBLE_P (f))
2369 redraw_frame (f);
2370 }
2371 }
2372
2373 /* Set the border-color of frame F to value described by ARG.
2374 ARG can be a string naming a color.
2375 The border-color is used for the border that is drawn by the server.
2376 Note that this does not fully take effect if done before
2377 F has a window; it must be redone when the window is created. */
2378
2379 void
2380 x_set_border_color (f, arg, oldval)
2381 struct frame *f;
2382 Lisp_Object arg, oldval;
2383 {
2384 int pix;
2385
2386 CHECK_STRING (arg);
2387 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2388 x_set_border_pixel (f, pix);
2389 update_face_from_frame_parameter (f, Qborder_color, arg);
2390 }
2391
2392 void
2393 x_set_cursor_type (f, arg, oldval)
2394 FRAME_PTR f;
2395 Lisp_Object arg, oldval;
2396 {
2397 set_frame_cursor_types (f, arg);
2398
2399 /* Make sure the cursor gets redrawn. This is overkill, but how
2400 often do people change cursor types? */
2401 update_mode_lines++;
2402 }
2403 \f
2404 #if 0 /* MAC_TODO: really no icon for Mac */
2405 void
2406 x_set_icon_type (f, arg, oldval)
2407 struct frame *f;
2408 Lisp_Object arg, oldval;
2409 {
2410 int result;
2411
2412 if (NILP (arg) && NILP (oldval))
2413 return;
2414
2415 if (STRINGP (arg) && STRINGP (oldval)
2416 && EQ (Fstring_equal (oldval, arg), Qt))
2417 return;
2418
2419 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2420 return;
2421
2422 BLOCK_INPUT;
2423
2424 result = x_bitmap_icon (f, arg);
2425 if (result)
2426 {
2427 UNBLOCK_INPUT;
2428 error ("No icon window available");
2429 }
2430
2431 UNBLOCK_INPUT;
2432 }
2433 #endif /* MAC_TODO */
2434
2435 /* Return non-nil if frame F wants a bitmap icon. */
2436
2437 Lisp_Object
2438 x_icon_type (f)
2439 FRAME_PTR f;
2440 {
2441 Lisp_Object tem;
2442
2443 tem = assq_no_quit (Qicon_type, f->param_alist);
2444 if (CONSP (tem))
2445 return XCDR (tem);
2446 else
2447 return Qnil;
2448 }
2449
2450 void
2451 x_set_icon_name (f, arg, oldval)
2452 struct frame *f;
2453 Lisp_Object arg, oldval;
2454 {
2455 int result;
2456
2457 if (STRINGP (arg))
2458 {
2459 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2460 return;
2461 }
2462 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2463 return;
2464
2465 f->icon_name = arg;
2466
2467 #if 0 /* MAC_TODO */
2468 if (f->output_data.w32->icon_bitmap != 0)
2469 return;
2470
2471 BLOCK_INPUT;
2472
2473 result = x_text_icon (f,
2474 (char *) SDATA ((!NILP (f->icon_name)
2475 ? f->icon_name
2476 : !NILP (f->title)
2477 ? f->title
2478 : f->name)));
2479
2480 if (result)
2481 {
2482 UNBLOCK_INPUT;
2483 error ("No icon window available");
2484 }
2485
2486 /* If the window was unmapped (and its icon was mapped),
2487 the new icon is not mapped, so map the window in its stead. */
2488 if (FRAME_VISIBLE_P (f))
2489 {
2490 #ifdef USE_X_TOOLKIT
2491 XtPopup (f->output_data.w32->widget, XtGrabNone);
2492 #endif
2493 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2494 }
2495
2496 XFlush (FRAME_W32_DISPLAY (f));
2497 UNBLOCK_INPUT;
2498 #endif /* MAC_TODO */
2499 }
2500
2501 extern Lisp_Object x_new_font ();
2502 extern Lisp_Object x_new_fontset();
2503
2504 void
2505 x_set_font (f, arg, oldval)
2506 struct frame *f;
2507 Lisp_Object arg, oldval;
2508 {
2509 Lisp_Object result;
2510 Lisp_Object fontset_name;
2511 Lisp_Object frame;
2512 int old_fontset = FRAME_FONTSET(f);
2513
2514 CHECK_STRING (arg);
2515
2516 fontset_name = Fquery_fontset (arg, Qnil);
2517
2518 BLOCK_INPUT;
2519 result = (STRINGP (fontset_name)
2520 ? x_new_fontset (f, SDATA (fontset_name))
2521 : x_new_font (f, SDATA (arg)));
2522 UNBLOCK_INPUT;
2523
2524 if (EQ (result, Qnil))
2525 error ("Font `%s' is not defined", SDATA (arg));
2526 else if (EQ (result, Qt))
2527 error ("The characters of the given font have varying widths");
2528 else if (STRINGP (result))
2529 {
2530 if (STRINGP (fontset_name))
2531 {
2532 /* Fontset names are built from ASCII font names, so the
2533 names may be equal despite there was a change. */
2534 if (old_fontset == FRAME_FONTSET (f))
2535 return;
2536 }
2537 else if (!NILP (Fequal (result, oldval)))
2538 return;
2539
2540 store_frame_param (f, Qfont, result);
2541 recompute_basic_faces (f);
2542 }
2543 else
2544 abort ();
2545
2546 do_pending_window_change (0);
2547
2548 /* Don't call `face-set-after-frame-default' when faces haven't been
2549 initialized yet. This is the case when called from
2550 Fx_create_frame. In that case, the X widget or window doesn't
2551 exist either, and we can end up in x_report_frame_params with a
2552 null widget which gives a segfault. */
2553 if (FRAME_FACE_CACHE (f))
2554 {
2555 XSETFRAME (frame, f);
2556 call1 (Qface_set_after_frame_default, frame);
2557 }
2558 }
2559
2560 void
2561 x_set_border_width (f, arg, oldval)
2562 struct frame *f;
2563 Lisp_Object arg, oldval;
2564 {
2565 CHECK_NUMBER (arg);
2566
2567 if (XINT (arg) == f->output_data.mac->border_width)
2568 return;
2569
2570 #if 0 /* MAC_TODO */
2571 if (FRAME_MAC_WINDOW (f) != 0)
2572 error ("Cannot change the border width of a window");
2573 #endif
2574
2575 f->output_data.mac->border_width = XINT (arg);
2576 }
2577
2578 void
2579 x_set_internal_border_width (f, arg, oldval)
2580 struct frame *f;
2581 Lisp_Object arg, oldval;
2582 {
2583 int old = f->output_data.mac->internal_border_width;
2584
2585 CHECK_NUMBER (arg);
2586 f->output_data.mac->internal_border_width = XINT (arg);
2587 if (f->output_data.mac->internal_border_width < 0)
2588 f->output_data.mac->internal_border_width = 0;
2589
2590 if (f->output_data.mac->internal_border_width == old)
2591 return;
2592
2593 if (FRAME_MAC_WINDOW (f) != 0)
2594 {
2595 x_set_window_size (f, 0, f->width, f->height);
2596 SET_FRAME_GARBAGED (f);
2597 do_pending_window_change (0);
2598 }
2599 else
2600 SET_FRAME_GARBAGED (f);
2601 }
2602
2603 void
2604 x_set_visibility (f, value, oldval)
2605 struct frame *f;
2606 Lisp_Object value, oldval;
2607 {
2608 Lisp_Object frame;
2609 XSETFRAME (frame, f);
2610
2611 if (NILP (value))
2612 Fmake_frame_invisible (frame, Qt);
2613 else if (EQ (value, Qicon))
2614 Ficonify_frame (frame);
2615 else
2616 Fmake_frame_visible (frame);
2617 }
2618
2619 \f
2620 /* Change window heights in windows rooted in WINDOW by N lines. */
2621
2622 static void
2623 x_change_window_heights (window, n)
2624 Lisp_Object window;
2625 int n;
2626 {
2627 struct window *w = XWINDOW (window);
2628
2629 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2630 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2631
2632 if (INTEGERP (w->orig_top))
2633 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2634 if (INTEGERP (w->orig_height))
2635 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2636
2637 /* Handle just the top child in a vertical split. */
2638 if (!NILP (w->vchild))
2639 x_change_window_heights (w->vchild, n);
2640
2641 /* Adjust all children in a horizontal split. */
2642 for (window = w->hchild; !NILP (window); window = w->next)
2643 {
2644 w = XWINDOW (window);
2645 x_change_window_heights (window, n);
2646 }
2647 }
2648
2649 void
2650 x_set_menu_bar_lines (f, value, oldval)
2651 struct frame *f;
2652 Lisp_Object value, oldval;
2653 {
2654 int nlines;
2655 int olines = FRAME_MENU_BAR_LINES (f);
2656
2657 /* Right now, menu bars don't work properly in minibuf-only frames;
2658 most of the commands try to apply themselves to the minibuffer
2659 frame itself, and get an error because you can't switch buffers
2660 in or split the minibuffer window. */
2661 if (FRAME_MINIBUF_ONLY_P (f))
2662 return;
2663
2664 if (INTEGERP (value))
2665 nlines = XINT (value);
2666 else
2667 nlines = 0;
2668
2669 FRAME_MENU_BAR_LINES (f) = 0;
2670 if (nlines)
2671 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2672 else
2673 {
2674 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2675 free_frame_menubar (f);
2676 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2677
2678 /* Adjust the frame size so that the client (text) dimensions
2679 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2680 set correctly. */
2681 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2682 do_pending_window_change (0);
2683 }
2684 adjust_glyphs (f);
2685 }
2686
2687
2688 /* Set the number of lines used for the tool bar of frame F to VALUE.
2689 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2690 is the old number of tool bar lines. This function changes the
2691 height of all windows on frame F to match the new tool bar height.
2692 The frame's height doesn't change. */
2693
2694 void
2695 x_set_tool_bar_lines (f, value, oldval)
2696 struct frame *f;
2697 Lisp_Object value, oldval;
2698 {
2699 int delta, nlines, root_height;
2700 Lisp_Object root_window;
2701
2702 /* Treat tool bars like menu bars. */
2703 if (FRAME_MINIBUF_ONLY_P (f))
2704 return;
2705
2706 /* Use VALUE only if an integer >= 0. */
2707 if (INTEGERP (value) && XINT (value) >= 0)
2708 nlines = XFASTINT (value);
2709 else
2710 nlines = 0;
2711
2712 /* Make sure we redisplay all windows in this frame. */
2713 ++windows_or_buffers_changed;
2714
2715 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2716
2717 /* Don't resize the tool-bar to more than we have room for. */
2718 root_window = FRAME_ROOT_WINDOW (f);
2719 root_height = XINT (XWINDOW (root_window)->height);
2720 if (root_height - delta < 1)
2721 {
2722 delta = root_height - 1;
2723 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2724 }
2725
2726 FRAME_TOOL_BAR_LINES (f) = nlines;
2727 x_change_window_heights (root_window, delta);
2728 adjust_glyphs (f);
2729
2730 /* We also have to make sure that the internal border at the top of
2731 the frame, below the menu bar or tool bar, is redrawn when the
2732 tool bar disappears. This is so because the internal border is
2733 below the tool bar if one is displayed, but is below the menu bar
2734 if there isn't a tool bar. The tool bar draws into the area
2735 below the menu bar. */
2736 if (FRAME_MAC_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2737 {
2738 updating_frame = f;
2739 clear_frame ();
2740 clear_current_matrices (f);
2741 updating_frame = NULL;
2742 }
2743
2744 /* If the tool bar gets smaller, the internal border below it
2745 has to be cleared. It was formerly part of the display
2746 of the larger tool bar, and updating windows won't clear it. */
2747 if (delta < 0)
2748 {
2749 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2750 int width = PIXEL_WIDTH (f);
2751 int y = nlines * CANON_Y_UNIT (f);
2752
2753 BLOCK_INPUT;
2754 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
2755 0, y, width, height, 0);
2756 UNBLOCK_INPUT;
2757
2758 if (WINDOWP (f->tool_bar_window))
2759 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2760 }
2761 }
2762
2763
2764 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2765 w32_id_name.
2766
2767 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2768 name; if NAME is a string, set F's name to NAME and set
2769 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2770
2771 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2772 suggesting a new name, which lisp code should override; if
2773 F->explicit_name is set, ignore the new name; otherwise, set it. */
2774
2775 void
2776 x_set_name (f, name, explicit)
2777 struct frame *f;
2778 Lisp_Object name;
2779 int explicit;
2780 {
2781 /* Make sure that requests from lisp code override requests from
2782 Emacs redisplay code. */
2783 if (explicit)
2784 {
2785 /* If we're switching from explicit to implicit, we had better
2786 update the mode lines and thereby update the title. */
2787 if (f->explicit_name && NILP (name))
2788 update_mode_lines = 1;
2789
2790 f->explicit_name = ! NILP (name);
2791 }
2792 else if (f->explicit_name)
2793 return;
2794
2795 /* If NAME is nil, set the name to the w32_id_name. */
2796 if (NILP (name))
2797 {
2798 /* Check for no change needed in this very common case
2799 before we do any consing. */
2800 if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name,
2801 SDATA (f->name)))
2802 return;
2803 name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name);
2804 }
2805 else
2806 CHECK_STRING (name);
2807
2808 /* Don't change the name if it's already NAME. */
2809 if (! NILP (Fstring_equal (name, f->name)))
2810 return;
2811
2812 f->name = name;
2813
2814 /* For setting the frame title, the title parameter should override
2815 the name parameter. */
2816 if (! NILP (f->title))
2817 name = f->title;
2818
2819 if (FRAME_MAC_WINDOW (f))
2820 {
2821 if (STRING_MULTIBYTE (name))
2822 #if 0 /* MAC_TODO: encoding title string */
2823 name = ENCODE_SYSTEM (name);
2824 #else
2825 return;
2826 #endif
2827
2828 BLOCK_INPUT;
2829
2830 {
2831 Str255 windowTitle;
2832 if (strlen (SDATA (name)) < 255)
2833 {
2834 strcpy (windowTitle, SDATA (name));
2835 c2pstr (windowTitle);
2836 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2837 }
2838 }
2839
2840 UNBLOCK_INPUT;
2841 }
2842 }
2843
2844 /* This function should be called when the user's lisp code has
2845 specified a name for the frame; the name will override any set by the
2846 redisplay code. */
2847 void
2848 x_explicitly_set_name (f, arg, oldval)
2849 FRAME_PTR f;
2850 Lisp_Object arg, oldval;
2851 {
2852 x_set_name (f, arg, 1);
2853 }
2854
2855 /* This function should be called by Emacs redisplay code to set the
2856 name; names set this way will never override names set by the user's
2857 lisp code. */
2858 void
2859 x_implicitly_set_name (f, arg, oldval)
2860 FRAME_PTR f;
2861 Lisp_Object arg, oldval;
2862 {
2863 x_set_name (f, arg, 0);
2864 }
2865 \f
2866 /* Change the title of frame F to NAME.
2867 If NAME is nil, use the frame name as the title.
2868
2869 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2870 name; if NAME is a string, set F's name to NAME and set
2871 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2872
2873 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2874 suggesting a new name, which lisp code should override; if
2875 F->explicit_name is set, ignore the new name; otherwise, set it. */
2876
2877 void
2878 x_set_title (f, name, old_name)
2879 struct frame *f;
2880 Lisp_Object name, old_name;
2881 {
2882 /* Don't change the title if it's already NAME. */
2883 if (EQ (name, f->title))
2884 return;
2885
2886 update_mode_lines = 1;
2887
2888 f->title = name;
2889
2890 if (NILP (name))
2891 name = f->name;
2892
2893 if (FRAME_MAC_WINDOW (f))
2894 {
2895 if (STRING_MULTIBYTE (name))
2896 #if 0 /* MAC_TODO: encoding title string */
2897 name = ENCODE_SYSTEM (name);
2898 #else
2899 return;
2900 #endif
2901
2902 BLOCK_INPUT;
2903
2904 {
2905 Str255 windowTitle;
2906 if (strlen (SDATA (name)) < 255)
2907 {
2908 strcpy (windowTitle, SDATA (name));
2909 c2pstr (windowTitle);
2910 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2911 }
2912 }
2913
2914 UNBLOCK_INPUT;
2915 }
2916 }
2917 \f
2918 void
2919 x_set_autoraise (f, arg, oldval)
2920 struct frame *f;
2921 Lisp_Object arg, oldval;
2922 {
2923 f->auto_raise = !EQ (Qnil, arg);
2924 }
2925
2926 void
2927 x_set_autolower (f, arg, oldval)
2928 struct frame *f;
2929 Lisp_Object arg, oldval;
2930 {
2931 f->auto_lower = !EQ (Qnil, arg);
2932 }
2933
2934 void
2935 x_set_unsplittable (f, arg, oldval)
2936 struct frame *f;
2937 Lisp_Object arg, oldval;
2938 {
2939 f->no_split = !NILP (arg);
2940 }
2941
2942 void
2943 x_set_vertical_scroll_bars (f, arg, oldval)
2944 struct frame *f;
2945 Lisp_Object arg, oldval;
2946 {
2947 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2948 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2949 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2950 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2951 {
2952 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2953 = (NILP (arg)
2954 ? vertical_scroll_bar_none
2955 : EQ (Qright, arg)
2956 ? vertical_scroll_bar_right
2957 : vertical_scroll_bar_left);
2958
2959 /* We set this parameter before creating the window for the
2960 frame, so we can get the geometry right from the start.
2961 However, if the window hasn't been created yet, we shouldn't
2962 call x_set_window_size. */
2963 if (FRAME_MAC_WINDOW (f))
2964 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2965 do_pending_window_change (0);
2966 }
2967 }
2968
2969 void
2970 x_set_scroll_bar_width (f, arg, oldval)
2971 struct frame *f;
2972 Lisp_Object arg, oldval;
2973 {
2974 /* Imitate X without X Toolkit */
2975
2976 int wid = FONT_WIDTH (f->output_data.mac->font);
2977
2978 if (NILP (arg))
2979 {
2980 #ifdef MAC_OSX
2981 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 16; /* Aqua scroll bars. */
2982 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2983 wid - 1) / wid;
2984 #else /* not MAC_OSX */
2985 /* Make the actual width at least 14 pixels and a multiple of a
2986 character width. */
2987 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
2988
2989 /* Use all of that space (aside from required margins) for the
2990 scroll bar. */
2991 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2992 #endif /* not MAC_OSX */
2993 if (FRAME_MAC_WINDOW (f))
2994 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2995 do_pending_window_change (0);
2996 }
2997 else if (INTEGERP (arg) && XINT (arg) > 0
2998 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2999 {
3000 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
3001 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
3002
3003 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
3004 FRAME_SCROLL_BAR_COLS (f) = (XFASTINT (arg) + wid-1) / wid;
3005 if (FRAME_MAC_WINDOW (f))
3006 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
3007 do_pending_window_change (0);
3008 }
3009 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
3010 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
3011 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
3012 }
3013 \f
3014 /* Subroutines of creating an frame. */
3015
3016 /* Make sure that Vx_resource_name is set to a reasonable value.
3017 Fix it up, or set it to `emacs' if it is too hopeless. */
3018
3019 static void
3020 validate_x_resource_name ()
3021 {
3022 int len = 0;
3023 /* Number of valid characters in the resource name. */
3024 int good_count = 0;
3025 /* Number of invalid characters in the resource name. */
3026 int bad_count = 0;
3027 Lisp_Object new;
3028 int i;
3029
3030 if (STRINGP (Vx_resource_name))
3031 {
3032 unsigned char *p = SDATA (Vx_resource_name);
3033 int i;
3034
3035 len = SBYTES (Vx_resource_name);
3036
3037 /* Only letters, digits, - and _ are valid in resource names.
3038 Count the valid characters and count the invalid ones. */
3039 for (i = 0; i < len; i++)
3040 {
3041 int c = p[i];
3042 if (! ((c >= 'a' && c <= 'z')
3043 || (c >= 'A' && c <= 'Z')
3044 || (c >= '0' && c <= '9')
3045 || c == '-' || c == '_'))
3046 bad_count++;
3047 else
3048 good_count++;
3049 }
3050 }
3051 else
3052 /* Not a string => completely invalid. */
3053 bad_count = 5, good_count = 0;
3054
3055 /* If name is valid already, return. */
3056 if (bad_count == 0)
3057 return;
3058
3059 /* If name is entirely invalid, or nearly so, use `emacs'. */
3060 if (good_count == 0
3061 || (good_count == 1 && bad_count > 0))
3062 {
3063 Vx_resource_name = build_string ("emacs");
3064 return;
3065 }
3066
3067 /* Name is partly valid. Copy it and replace the invalid characters
3068 with underscores. */
3069
3070 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3071
3072 for (i = 0; i < len; i++)
3073 {
3074 int c = SREF (new, i);
3075 if (! ((c >= 'a' && c <= 'z')
3076 || (c >= 'A' && c <= 'Z')
3077 || (c >= '0' && c <= '9')
3078 || c == '-' || c == '_'))
3079 SSET (new, i, '_');
3080 }
3081 }
3082
3083
3084 #if 0 /* MAC_TODO: implement resource strings */
3085 extern char *x_get_string_resource ();
3086
3087 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3088 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3089 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3090 class, where INSTANCE is the name under which Emacs was invoked, or
3091 the name specified by the `-name' or `-rn' command-line arguments.
3092
3093 The optional arguments COMPONENT and SUBCLASS add to the key and the
3094 class, respectively. You must specify both of them or neither.
3095 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3096 and the class is `Emacs.CLASS.SUBCLASS'. */)
3097 (attribute, class, component, subclass)
3098 Lisp_Object attribute, class, component, subclass;
3099 {
3100 register char *value;
3101 char *name_key;
3102 char *class_key;
3103
3104 CHECK_STRING (attribute);
3105 CHECK_STRING (class);
3106
3107 if (!NILP (component))
3108 CHECK_STRING (component);
3109 if (!NILP (subclass))
3110 CHECK_STRING (subclass);
3111 if (NILP (component) != NILP (subclass))
3112 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3113
3114 validate_x_resource_name ();
3115
3116 /* Allocate space for the components, the dots which separate them,
3117 and the final '\0'. Make them big enough for the worst case. */
3118 name_key = (char *) alloca (SBYTES (Vx_resource_name)
3119 + (STRINGP (component)
3120 ? SBYTES (component) : 0)
3121 + SBYTES (attribute)
3122 + 3);
3123
3124 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3125 + SBYTES (class)
3126 + (STRINGP (subclass)
3127 ? SBYTES (subclass) : 0)
3128 + 3);
3129
3130 /* Start with emacs.FRAMENAME for the name (the specific one)
3131 and with `Emacs' for the class key (the general one). */
3132 strcpy (name_key, SDATA (Vx_resource_name));
3133 strcpy (class_key, EMACS_CLASS);
3134
3135 strcat (class_key, ".");
3136 strcat (class_key, SDATA (class));
3137
3138 if (!NILP (component))
3139 {
3140 strcat (class_key, ".");
3141 strcat (class_key, SDATA (subclass));
3142
3143 strcat (name_key, ".");
3144 strcat (name_key, SDATA (component));
3145 }
3146
3147 strcat (name_key, ".");
3148 strcat (name_key, SDATA (attribute));
3149
3150 value = x_get_string_resource (Qnil,
3151 name_key, class_key);
3152
3153 if (value != (char *) 0)
3154 return build_string (value);
3155 else
3156 return Qnil;
3157 }
3158
3159 /* Used when C code wants a resource value. */
3160
3161 char *
3162 x_get_resource_string (attribute, class)
3163 char *attribute, *class;
3164 {
3165 char *name_key;
3166 char *class_key;
3167 struct frame *sf = SELECTED_FRAME ();
3168
3169 /* Allocate space for the components, the dots which separate them,
3170 and the final '\0'. */
3171 name_key = (char *) alloca (SBYTES (Vinvocation_name)
3172 + strlen (attribute) + 2);
3173 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3174 + strlen (class) + 2);
3175
3176 sprintf (name_key, "%s.%s",
3177 SDATA (Vinvocation_name),
3178 attribute);
3179 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3180
3181 return x_get_string_resource (sf, name_key, class_key);
3182 }
3183 #endif /* MAC_TODO */
3184
3185 /* Types we might convert a resource string into. */
3186 enum resource_types
3187 {
3188 RES_TYPE_NUMBER,
3189 RES_TYPE_FLOAT,
3190 RES_TYPE_BOOLEAN,
3191 RES_TYPE_STRING,
3192 RES_TYPE_SYMBOL
3193 };
3194
3195 /* Return the value of parameter PARAM.
3196
3197 First search ALIST, then Vdefault_frame_alist, then the X defaults
3198 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3199
3200 Convert the resource to the type specified by desired_type.
3201
3202 If no default is specified, return Qunbound. If you call
3203 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3204 and don't let it get stored in any Lisp-visible variables! */
3205
3206 static Lisp_Object
3207 mac_get_arg (alist, param, attribute, class, type)
3208 Lisp_Object alist, param;
3209 char *attribute;
3210 char *class;
3211 enum resource_types type;
3212 {
3213 register Lisp_Object tem;
3214
3215 tem = Fassq (param, alist);
3216 if (EQ (tem, Qnil))
3217 tem = Fassq (param, Vdefault_frame_alist);
3218 if (EQ (tem, Qnil))
3219 {
3220
3221 #if 0 /* MAC_TODO: search resource also */
3222 if (attribute)
3223 {
3224 tem = Fx_get_resource (build_string (attribute),
3225 build_string (class),
3226 Qnil, Qnil);
3227
3228 if (NILP (tem))
3229 return Qunbound;
3230
3231 switch (type)
3232 {
3233 case RES_TYPE_NUMBER:
3234 return make_number (atoi (SDATA (tem)));
3235
3236 case RES_TYPE_FLOAT:
3237 return make_float (atof (SDATA (tem)));
3238
3239 case RES_TYPE_BOOLEAN:
3240 tem = Fdowncase (tem);
3241 if (!strcmp (SDATA (tem), "on")
3242 || !strcmp (SDATA (tem), "true"))
3243 return Qt;
3244 else
3245 return Qnil;
3246
3247 case RES_TYPE_STRING:
3248 return tem;
3249
3250 case RES_TYPE_SYMBOL:
3251 /* As a special case, we map the values `true' and `on'
3252 to Qt, and `false' and `off' to Qnil. */
3253 {
3254 Lisp_Object lower;
3255 lower = Fdowncase (tem);
3256 if (!strcmp (SDATA (lower), "on")
3257 || !strcmp (SDATA (lower), "true"))
3258 return Qt;
3259 else if (!strcmp (SDATA (lower), "off")
3260 || !strcmp (SDATA (lower), "false"))
3261 return Qnil;
3262 else
3263 return Fintern (tem, Qnil);
3264 }
3265
3266 default:
3267 abort ();
3268 }
3269 }
3270 else
3271 #endif /* MAC_TODO */
3272 return Qunbound;
3273 }
3274 return Fcdr (tem);
3275 }
3276
3277 /* Record in frame F the specified or default value according to ALIST
3278 of the parameter named PROP (a Lisp symbol).
3279 If no value is specified for PROP, look for an X default for XPROP
3280 on the frame named NAME.
3281 If that is not found either, use the value DEFLT. */
3282
3283 static Lisp_Object
3284 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3285 struct frame *f;
3286 Lisp_Object alist;
3287 Lisp_Object prop;
3288 Lisp_Object deflt;
3289 char *xprop;
3290 char *xclass;
3291 enum resource_types type;
3292 {
3293 Lisp_Object tem;
3294
3295 tem = mac_get_arg (alist, prop, xprop, xclass, type);
3296 if (EQ (tem, Qunbound))
3297 tem = deflt;
3298 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3299 return tem;
3300 }
3301 \f
3302 /* XParseGeometry copied from w32xfns.c */
3303
3304 /*
3305 * XParseGeometry parses strings of the form
3306 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
3307 * width, height, xoffset, and yoffset are unsigned integers.
3308 * Example: "=80x24+300-49"
3309 * The equal sign is optional.
3310 * It returns a bitmask that indicates which of the four values
3311 * were actually found in the string. For each value found,
3312 * the corresponding argument is updated; for each value
3313 * not found, the corresponding argument is left unchanged.
3314 */
3315
3316 static int
3317 read_integer (string, NextString)
3318 register char *string;
3319 char **NextString;
3320 {
3321 register int Result = 0;
3322 int Sign = 1;
3323
3324 if (*string == '+')
3325 string++;
3326 else if (*string == '-')
3327 {
3328 string++;
3329 Sign = -1;
3330 }
3331 for (; (*string >= '0') && (*string <= '9'); string++)
3332 {
3333 Result = (Result * 10) + (*string - '0');
3334 }
3335 *NextString = string;
3336 if (Sign >= 0)
3337 return (Result);
3338 else
3339 return (-Result);
3340 }
3341
3342 int
3343 XParseGeometry (string, x, y, width, height)
3344 char *string;
3345 int *x, *y;
3346 unsigned int *width, *height; /* RETURN */
3347 {
3348 int mask = NoValue;
3349 register char *strind;
3350 unsigned int tempWidth, tempHeight;
3351 int tempX, tempY;
3352 char *nextCharacter;
3353
3354 if ((string == NULL) || (*string == '\0')) return (mask);
3355 if (*string == '=')
3356 string++; /* ignore possible '=' at beg of geometry spec */
3357
3358 strind = (char *)string;
3359 if (*strind != '+' && *strind != '-' && *strind != 'x')
3360 {
3361 tempWidth = read_integer (strind, &nextCharacter);
3362 if (strind == nextCharacter)
3363 return (0);
3364 strind = nextCharacter;
3365 mask |= WidthValue;
3366 }
3367
3368 if (*strind == 'x' || *strind == 'X')
3369 {
3370 strind++;
3371 tempHeight = read_integer (strind, &nextCharacter);
3372 if (strind == nextCharacter)
3373 return (0);
3374 strind = nextCharacter;
3375 mask |= HeightValue;
3376 }
3377
3378 if ((*strind == '+') || (*strind == '-'))
3379 {
3380 if (*strind == '-')
3381 {
3382 strind++;
3383 tempX = -read_integer (strind, &nextCharacter);
3384 if (strind == nextCharacter)
3385 return (0);
3386 strind = nextCharacter;
3387 mask |= XNegative;
3388
3389 }
3390 else
3391 {
3392 strind++;
3393 tempX = read_integer (strind, &nextCharacter);
3394 if (strind == nextCharacter)
3395 return (0);
3396 strind = nextCharacter;
3397 }
3398 mask |= XValue;
3399 if ((*strind == '+') || (*strind == '-'))
3400 {
3401 if (*strind == '-')
3402 {
3403 strind++;
3404 tempY = -read_integer (strind, &nextCharacter);
3405 if (strind == nextCharacter)
3406 return (0);
3407 strind = nextCharacter;
3408 mask |= YNegative;
3409
3410 }
3411 else
3412 {
3413 strind++;
3414 tempY = read_integer (strind, &nextCharacter);
3415 if (strind == nextCharacter)
3416 return (0);
3417 strind = nextCharacter;
3418 }
3419 mask |= YValue;
3420 }
3421 }
3422
3423 /* If strind isn't at the end of the string the it's an invalid
3424 geometry specification. */
3425
3426 if (*strind != '\0') return (0);
3427
3428 if (mask & XValue)
3429 *x = tempX;
3430 if (mask & YValue)
3431 *y = tempY;
3432 if (mask & WidthValue)
3433 *width = tempWidth;
3434 if (mask & HeightValue)
3435 *height = tempHeight;
3436 return (mask);
3437 }
3438
3439 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3440 doc: /* Parse an X-style geometry string STRING.
3441 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3442 The properties returned may include `top', `left', `height', and `width'.
3443 The value of `left' or `top' may be an integer,
3444 or a list (+ N) meaning N pixels relative to top/left corner,
3445 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3446 (string)
3447 Lisp_Object string;
3448 {
3449 int geometry, x, y;
3450 unsigned int width, height;
3451 Lisp_Object result;
3452
3453 CHECK_STRING (string);
3454
3455 geometry = XParseGeometry ((char *) SDATA (string),
3456 &x, &y, &width, &height);
3457
3458 result = Qnil;
3459 if (geometry & XValue)
3460 {
3461 Lisp_Object element;
3462
3463 if (x >= 0 && (geometry & XNegative))
3464 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3465 else if (x < 0 && ! (geometry & XNegative))
3466 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3467 else
3468 element = Fcons (Qleft, make_number (x));
3469 result = Fcons (element, result);
3470 }
3471
3472 if (geometry & YValue)
3473 {
3474 Lisp_Object element;
3475
3476 if (y >= 0 && (geometry & YNegative))
3477 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3478 else if (y < 0 && ! (geometry & YNegative))
3479 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3480 else
3481 element = Fcons (Qtop, make_number (y));
3482 result = Fcons (element, result);
3483 }
3484
3485 if (geometry & WidthValue)
3486 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3487 if (geometry & HeightValue)
3488 result = Fcons (Fcons (Qheight, make_number (height)), result);
3489
3490 return result;
3491 }
3492
3493 /* Calculate the desired size and position of this window,
3494 and return the flags saying which aspects were specified.
3495
3496 This function does not make the coordinates positive. */
3497
3498 #define DEFAULT_ROWS 40
3499 #define DEFAULT_COLS 80
3500
3501 static int
3502 x_figure_window_size (f, parms)
3503 struct frame *f;
3504 Lisp_Object parms;
3505 {
3506 register Lisp_Object tem0, tem1, tem2;
3507 long window_prompting = 0;
3508
3509 /* Default values if we fall through.
3510 Actually, if that happens we should get
3511 window manager prompting. */
3512 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3513 f->height = DEFAULT_ROWS;
3514 /* Window managers expect that if program-specified
3515 positions are not (0,0), they're intentional, not defaults. */
3516 f->output_data.mac->top_pos = 0;
3517 f->output_data.mac->left_pos = 0;
3518
3519 tem0 = mac_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3520 tem1 = mac_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3521 tem2 = mac_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3522 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3523 {
3524 if (!EQ (tem0, Qunbound))
3525 {
3526 CHECK_NUMBER (tem0);
3527 f->height = XINT (tem0);
3528 }
3529 if (!EQ (tem1, Qunbound))
3530 {
3531 CHECK_NUMBER (tem1);
3532 SET_FRAME_WIDTH (f, XINT (tem1));
3533 }
3534 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3535 window_prompting |= USSize;
3536 else
3537 window_prompting |= PSize;
3538 }
3539
3540 f->output_data.mac->vertical_scroll_bar_extra
3541 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3542 ? 0
3543 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3544 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3545 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.mac->font)));
3546
3547 x_compute_fringe_widths (f, 0);
3548
3549 f->output_data.mac->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3550 f->output_data.mac->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3551
3552 tem0 = mac_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3553 tem1 = mac_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3554 tem2 = mac_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3555 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3556 {
3557 if (EQ (tem0, Qminus))
3558 {
3559 f->output_data.mac->top_pos = 0;
3560 window_prompting |= YNegative;
3561 }
3562 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3563 && CONSP (XCDR (tem0))
3564 && INTEGERP (XCAR (XCDR (tem0))))
3565 {
3566 f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0)));
3567 window_prompting |= YNegative;
3568 }
3569 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3570 && CONSP (XCDR (tem0))
3571 && INTEGERP (XCAR (XCDR (tem0))))
3572 {
3573 f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0)));
3574 }
3575 else if (EQ (tem0, Qunbound))
3576 f->output_data.mac->top_pos = 0;
3577 else
3578 {
3579 CHECK_NUMBER (tem0);
3580 f->output_data.mac->top_pos = XINT (tem0);
3581 if (f->output_data.mac->top_pos < 0)
3582 window_prompting |= YNegative;
3583 }
3584
3585 if (EQ (tem1, Qminus))
3586 {
3587 f->output_data.mac->left_pos = 0;
3588 window_prompting |= XNegative;
3589 }
3590 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3591 && CONSP (XCDR (tem1))
3592 && INTEGERP (XCAR (XCDR (tem1))))
3593 {
3594 f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1)));
3595 window_prompting |= XNegative;
3596 }
3597 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3598 && CONSP (XCDR (tem1))
3599 && INTEGERP (XCAR (XCDR (tem1))))
3600 {
3601 f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1)));
3602 }
3603 else if (EQ (tem1, Qunbound))
3604 f->output_data.mac->left_pos = 0;
3605 else
3606 {
3607 CHECK_NUMBER (tem1);
3608 f->output_data.mac->left_pos = XINT (tem1);
3609 if (f->output_data.mac->left_pos < 0)
3610 window_prompting |= XNegative;
3611 }
3612
3613 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3614 window_prompting |= USPosition;
3615 else
3616 window_prompting |= PPosition;
3617 }
3618
3619 return window_prompting;
3620 }
3621
3622 \f
3623 #if 0 /* MAC_TODO */
3624 /* Create and set up the Mac window for frame F. */
3625
3626 static void
3627 mac_window (f, window_prompting, minibuffer_only)
3628 struct frame *f;
3629 long window_prompting;
3630 int minibuffer_only;
3631 {
3632 Rect r;
3633
3634 BLOCK_INPUT;
3635
3636 /* Use the resource name as the top-level window name
3637 for looking up resources. Make a non-Lisp copy
3638 for the window manager, so GC relocation won't bother it.
3639
3640 Elsewhere we specify the window name for the window manager. */
3641
3642 {
3643 char *str = (char *) SDATA (Vx_resource_name);
3644 f->namebuf = (char *) xmalloc (strlen (str) + 1);
3645 strcpy (f->namebuf, str);
3646 }
3647
3648 SetRect (&r, f->output_data.mac->left_pos, f->output_data.mac->top_pos,
3649 f->output_data.mac->left_pos + PIXEL_WIDTH (f),
3650 f->output_data.mac->top_pos + PIXEL_HEIGHT (f));
3651 FRAME_MAC_WINDOW (f)
3652 = NewCWindow (NULL, &r, "\p", 1, zoomDocProc, (WindowPtr) -1, 1, (long) f->output_data.mac);
3653
3654 validate_x_resource_name ();
3655
3656 /* x_set_name normally ignores requests to set the name if the
3657 requested name is the same as the current name. This is the one
3658 place where that assumption isn't correct; f->name is set, but
3659 the server hasn't been told. */
3660 {
3661 Lisp_Object name;
3662 int explicit = f->explicit_name;
3663
3664 f->explicit_name = 0;
3665 name = f->name;
3666 f->name = Qnil;
3667 x_set_name (f, name, explicit);
3668 }
3669
3670 ShowWindow (FRAME_MAC_WINDOW (f));
3671
3672 UNBLOCK_INPUT;
3673
3674 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
3675 initialize_frame_menubar (f);
3676
3677 if (FRAME_MAC_WINDOW (f) == 0)
3678 error ("Unable to create window");
3679 }
3680 #endif /* MAC_TODO */
3681
3682 /* Handle the icon stuff for this window. Perhaps later we might
3683 want an x_set_icon_position which can be called interactively as
3684 well. */
3685
3686 static void
3687 x_icon (f, parms)
3688 struct frame *f;
3689 Lisp_Object parms;
3690 {
3691 Lisp_Object icon_x, icon_y;
3692
3693 /* Set the position of the icon. Note that Windows 95 groups all
3694 icons in the tray. */
3695 icon_x = mac_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
3696 icon_y = mac_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
3697 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
3698 {
3699 CHECK_NUMBER (icon_x);
3700 CHECK_NUMBER (icon_y);
3701 }
3702 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
3703 error ("Both left and top icon corners of icon must be specified");
3704
3705 BLOCK_INPUT;
3706
3707 if (! EQ (icon_x, Qunbound))
3708 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
3709
3710 #if 0 /* TODO */
3711 /* Start up iconic or window? */
3712 x_wm_set_window_state
3713 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
3714 ? IconicState
3715 : NormalState));
3716
3717 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
3718 ? f->icon_name
3719 : f->name)));
3720 #endif
3721
3722 UNBLOCK_INPUT;
3723 }
3724
3725
3726 void
3727 x_make_gc (f)
3728 struct frame *f;
3729 {
3730 XGCValues gc_values;
3731
3732 BLOCK_INPUT;
3733
3734 /* Create the GC's of this frame.
3735 Note that many default values are used. */
3736
3737 /* Normal video */
3738 gc_values.font = f->output_data.mac->font;
3739 gc_values.foreground = FRAME_FOREGROUND_PIXEL (f);
3740 gc_values.background = FRAME_BACKGROUND_PIXEL (f);
3741 f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3742 FRAME_MAC_WINDOW (f),
3743 GCFont | GCForeground | GCBackground,
3744 &gc_values);
3745
3746 /* Reverse video style. */
3747 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
3748 gc_values.background = FRAME_FOREGROUND_PIXEL (f);
3749 f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3750 FRAME_MAC_WINDOW (f),
3751 GCFont | GCForeground | GCBackground,
3752 &gc_values);
3753
3754 /* Cursor has cursor-color background, background-color foreground. */
3755 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
3756 gc_values.background = f->output_data.mac->cursor_pixel;
3757 f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3758 FRAME_MAC_WINDOW (f),
3759 GCFont | GCForeground | GCBackground,
3760 &gc_values);
3761
3762 /* Reliefs. */
3763 f->output_data.mac->white_relief.gc = 0;
3764 f->output_data.mac->black_relief.gc = 0;
3765
3766 UNBLOCK_INPUT;
3767 }
3768
3769
3770 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
3771 1, 1, 0,
3772 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
3773 Returns an Emacs frame object.
3774 ALIST is an alist of frame parameters.
3775 If the parameters specify that the frame should not have a minibuffer,
3776 and do not specify a specific minibuffer window to use,
3777 then `default-minibuffer-frame' must be a frame whose minibuffer can
3778 be shared by the new frame.
3779
3780 This function is an internal primitive--use `make-frame' instead. */)
3781 (parms)
3782 Lisp_Object parms;
3783 {
3784 struct frame *f;
3785 Lisp_Object frame, tem;
3786 Lisp_Object name;
3787 int minibuffer_only = 0;
3788 long window_prompting = 0;
3789 int width, height;
3790 int count = SPECPDL_INDEX ();
3791 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3792 Lisp_Object display;
3793 struct mac_display_info *dpyinfo = NULL;
3794 Lisp_Object parent;
3795 struct kboard *kb;
3796 char x_frame_name[10];
3797 static int x_frame_count = 2; /* begins at 2 because terminal frame is F1 */
3798
3799 check_mac ();
3800
3801 /* Use this general default value to start with
3802 until we know if this frame has a specified name. */
3803 Vx_resource_name = Vinvocation_name;
3804
3805 display = mac_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
3806 if (EQ (display, Qunbound))
3807 display = Qnil;
3808 dpyinfo = check_x_display_info (display);
3809 #ifdef MULTI_KBOARD
3810 kb = dpyinfo->kboard;
3811 #else
3812 kb = &the_only_kboard;
3813 #endif
3814
3815 name = mac_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
3816 if (!STRINGP (name)
3817 && ! EQ (name, Qunbound)
3818 && ! NILP (name))
3819 error ("Invalid frame name--not a string or nil");
3820
3821 if (STRINGP (name))
3822 Vx_resource_name = name;
3823
3824 /* See if parent window is specified. */
3825 parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
3826 if (EQ (parent, Qunbound))
3827 parent = Qnil;
3828 if (! NILP (parent))
3829 CHECK_NUMBER (parent);
3830
3831 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
3832 /* No need to protect DISPLAY because that's not used after passing
3833 it to make_frame_without_minibuffer. */
3834 frame = Qnil;
3835 GCPRO4 (parms, parent, name, frame);
3836 tem = mac_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
3837 RES_TYPE_SYMBOL);
3838 if (EQ (tem, Qnone) || NILP (tem))
3839 f = make_frame_without_minibuffer (Qnil, kb, display);
3840 else if (EQ (tem, Qonly))
3841 {
3842 f = make_minibuffer_frame ();
3843 minibuffer_only = 1;
3844 }
3845 else if (WINDOWP (tem))
3846 f = make_frame_without_minibuffer (tem, kb, display);
3847 else
3848 f = make_frame (1);
3849
3850 if (EQ (name, Qunbound) || NILP (name))
3851 {
3852 sprintf (x_frame_name, "F%d", x_frame_count++);
3853 f->name = build_string (x_frame_name);
3854 f->explicit_name = 0;
3855 }
3856 else
3857 {
3858 f->name = name;
3859 f->explicit_name = 1;
3860 }
3861
3862 XSETFRAME (frame, f);
3863
3864 /* Note that X Windows does support scroll bars. */
3865 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
3866
3867 f->output_method = output_mac;
3868 f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
3869 bzero (f->output_data.mac, sizeof (struct mac_output));
3870 FRAME_FONTSET (f) = -1;
3871 f->output_data.mac->scroll_bar_foreground_pixel = -1;
3872 f->output_data.mac->scroll_bar_background_pixel = -1;
3873
3874 #if 0
3875 FRAME_FONTSET (f) = -1;
3876 #endif
3877
3878 f->icon_name
3879 = mac_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
3880 if (! STRINGP (f->icon_name))
3881 f->icon_name = Qnil;
3882
3883 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
3884 #ifdef MULTI_KBOARD
3885 FRAME_KBOARD (f) = kb;
3886 #endif
3887
3888 /* Specify the parent under which to make this window. */
3889
3890 if (!NILP (parent))
3891 {
3892 f->output_data.mac->parent_desc = (Window) parent;
3893 f->output_data.mac->explicit_parent = 1;
3894 }
3895 else
3896 {
3897 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3898 f->output_data.mac->explicit_parent = 0;
3899 }
3900
3901 /* Set the name; the functions to which we pass f expect the name to
3902 be set. */
3903 if (EQ (name, Qunbound) || NILP (name))
3904 {
3905 f->name = build_string (dpyinfo->mac_id_name);
3906 f->explicit_name = 0;
3907 }
3908 else
3909 {
3910 f->name = name;
3911 f->explicit_name = 1;
3912 /* use the frame's title when getting resources for this frame. */
3913 specbind (Qx_resource_name, name);
3914 }
3915
3916 /* Extract the window parameters from the supplied values
3917 that are needed to determine window geometry. */
3918 {
3919 Lisp_Object font;
3920
3921 font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
3922
3923 BLOCK_INPUT;
3924 /* First, try whatever font the caller has specified. */
3925 if (STRINGP (font))
3926 {
3927 tem = Fquery_fontset (font, Qnil);
3928 if (STRINGP (tem))
3929 font = x_new_fontset (f, SDATA (tem));
3930 else
3931 font = x_new_font (f, SDATA (font));
3932 }
3933 /* Try out a font which we hope has bold and italic variations. */
3934 if (! STRINGP (font))
3935 font = x_new_font (f, "-ETL-fixed-medium-r-*--*-160-*-*-*-*-iso8859-1");
3936 /* If those didn't work, look for something which will at least work. */
3937 if (!STRINGP (font))
3938 font = x_new_font (f, "-*-monaco-*-12-*-mac-roman");
3939 if (! STRINGP (font))
3940 font = x_new_font (f, "-*-courier-*-10-*-mac-roman");
3941 if (! STRINGP (font))
3942 error ("Cannot find any usable font");
3943 UNBLOCK_INPUT;
3944
3945 x_default_parameter (f, parms, Qfont, font,
3946 "font", "Font", RES_TYPE_STRING);
3947 }
3948
3949 x_default_parameter (f, parms, Qborder_width, make_number (0),
3950 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
3951 /* This defaults to 2 in order to match xterm. We recognize either
3952 internalBorderWidth or internalBorder (which is what xterm calls
3953 it). */
3954 if (NILP (Fassq (Qinternal_border_width, parms)))
3955 {
3956 Lisp_Object value;
3957
3958 value = mac_get_arg (parms, Qinternal_border_width,
3959 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
3960 if (! EQ (value, Qunbound))
3961 parms = Fcons (Fcons (Qinternal_border_width, value),
3962 parms);
3963 }
3964 /* Default internalBorderWidth to 0 on Windows to match other programs. */
3965 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
3966 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
3967 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
3968 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
3969
3970 /* Also do the stuff which must be set before the window exists. */
3971 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
3972 "foreground", "Foreground", RES_TYPE_STRING);
3973 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
3974 "background", "Background", RES_TYPE_STRING);
3975 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
3976 "pointerColor", "Foreground", RES_TYPE_STRING);
3977 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
3978 "cursorColor", "Foreground", RES_TYPE_STRING);
3979 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
3980 "borderColor", "BorderColor", RES_TYPE_STRING);
3981 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
3982 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
3983 x_default_parameter (f, parms, Qline_spacing, Qnil,
3984 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
3985 x_default_parameter (f, parms, Qleft_fringe, Qnil,
3986 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
3987 x_default_parameter (f, parms, Qright_fringe, Qnil,
3988 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
3989
3990
3991 /* Init faces before x_default_parameter is called for scroll-bar
3992 parameters because that function calls x_set_scroll_bar_width,
3993 which calls change_frame_size, which calls Fset_window_buffer,
3994 which runs hooks, which call Fvertical_motion. At the end, we
3995 end up in init_iterator with a null face cache, which should not
3996 happen. */
3997 init_frame_faces (f);
3998
3999 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
4000 "menuBar", "MenuBar", RES_TYPE_NUMBER);
4001 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
4002 "toolBar", "ToolBar", RES_TYPE_NUMBER);
4003 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
4004 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
4005 x_default_parameter (f, parms, Qtitle, Qnil,
4006 "title", "Title", RES_TYPE_STRING);
4007
4008 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
4009 window_prompting = x_figure_window_size (f, parms);
4010
4011 if (window_prompting & XNegative)
4012 {
4013 if (window_prompting & YNegative)
4014 f->output_data.mac->win_gravity = SouthEastGravity;
4015 else
4016 f->output_data.mac->win_gravity = NorthEastGravity;
4017 }
4018 else
4019 {
4020 if (window_prompting & YNegative)
4021 f->output_data.mac->win_gravity = SouthWestGravity;
4022 else
4023 f->output_data.mac->win_gravity = NorthWestGravity;
4024 }
4025
4026 f->output_data.mac->size_hint_flags = window_prompting;
4027
4028 tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4029 f->no_split = minibuffer_only || EQ (tem, Qt);
4030
4031 /* Create the window. Add the tool-bar height to the initial frame
4032 height so that the user gets a text display area of the size he
4033 specified with -g or via the registry. Later changes of the
4034 tool-bar height don't change the frame size. This is done so that
4035 users can create tall Emacs frames without having to guess how
4036 tall the tool-bar will get. */
4037 f->height += FRAME_TOOL_BAR_LINES (f);
4038
4039 /* mac_window (f, window_prompting, minibuffer_only); */
4040 make_mac_frame (f);
4041
4042 x_icon (f, parms);
4043
4044 x_make_gc (f);
4045
4046 /* Now consider the frame official. */
4047 FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
4048 Vframe_list = Fcons (frame, Vframe_list);
4049
4050 /* We need to do this after creating the window, so that the
4051 icon-creation functions can say whose icon they're describing. */
4052 x_default_parameter (f, parms, Qicon_type, Qnil,
4053 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
4054
4055 x_default_parameter (f, parms, Qauto_raise, Qnil,
4056 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4057 x_default_parameter (f, parms, Qauto_lower, Qnil,
4058 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4059 x_default_parameter (f, parms, Qcursor_type, Qbox,
4060 "cursorType", "CursorType", RES_TYPE_SYMBOL);
4061 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
4062 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
4063
4064 /* Dimensions, especially f->height, must be done via change_frame_size.
4065 Change will not be effected unless different from the current
4066 f->height. */
4067 width = f->width;
4068 height = f->height;
4069
4070 f->height = 0;
4071 SET_FRAME_WIDTH (f, 0);
4072 change_frame_size (f, height, width, 1, 0, 0);
4073
4074 /* Set up faces after all frame parameters are known. */
4075 call1 (Qface_set_after_frame_default, frame);
4076
4077 #if 0 /* MAC_TODO: when we have window manager hints */
4078 /* Tell the server what size and position, etc, we want, and how
4079 badly we want them. This should be done after we have the menu
4080 bar so that its size can be taken into account. */
4081 BLOCK_INPUT;
4082 x_wm_set_size_hint (f, window_prompting, 0);
4083 UNBLOCK_INPUT;
4084 #endif
4085
4086 /* Make the window appear on the frame and enable display, unless
4087 the caller says not to. However, with explicit parent, Emacs
4088 cannot control visibility, so don't try. */
4089 if (! f->output_data.mac->explicit_parent)
4090 {
4091 Lisp_Object visibility;
4092
4093 visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
4094 if (EQ (visibility, Qunbound))
4095 visibility = Qt;
4096
4097 #if 0 /* MAC_TODO: really no iconify on Mac */
4098 if (EQ (visibility, Qicon))
4099 x_iconify_frame (f);
4100 else
4101 #endif
4102 if (! NILP (visibility))
4103 x_make_frame_visible (f);
4104 else
4105 /* Must have been Qnil. */
4106 ;
4107 }
4108 UNGCPRO;
4109
4110 /* Make sure windows on this frame appear in calls to next-window
4111 and similar functions. */
4112 Vwindow_list = Qnil;
4113
4114 return unbind_to (count, frame);
4115 }
4116
4117 /* FRAME is used only to get a handle on the X display. We don't pass the
4118 display info directly because we're called from frame.c, which doesn't
4119 know about that structure. */
4120 Lisp_Object
4121 x_get_focus_frame (frame)
4122 struct frame *frame;
4123 {
4124 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4125 Lisp_Object xfocus;
4126 if (! dpyinfo->x_focus_frame)
4127 return Qnil;
4128
4129 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
4130 return xfocus;
4131 }
4132 \f
4133 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
4134 doc: /* Internal function called by `color-defined-p', which see. */)
4135 (color, frame)
4136 Lisp_Object color, frame;
4137 {
4138 XColor foo;
4139 FRAME_PTR f = check_x_frame (frame);
4140
4141 CHECK_STRING (color);
4142
4143 if (mac_defined_color (f, SDATA (color), &foo, 0))
4144 return Qt;
4145 else
4146 return Qnil;
4147 }
4148
4149 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
4150 doc: /* Internal function called by `color-values', which see. */)
4151 (color, frame)
4152 Lisp_Object color, frame;
4153 {
4154 XColor foo;
4155 FRAME_PTR f = check_x_frame (frame);
4156
4157 CHECK_STRING (color);
4158
4159 if (mac_defined_color (f, SDATA (color), &foo, 0))
4160 {
4161 Lisp_Object rgb[3];
4162
4163 rgb[0] = make_number ((RED_FROM_ULONG (foo.pixel) << 8)
4164 | RED_FROM_ULONG (foo.pixel));
4165 rgb[1] = make_number ((GREEN_FROM_ULONG (foo.pixel) << 8)
4166 | GREEN_FROM_ULONG (foo.pixel));
4167 rgb[2] = make_number ((BLUE_FROM_ULONG (foo.pixel) << 8)
4168 | BLUE_FROM_ULONG (foo.pixel));
4169 return Flist (3, rgb);
4170 }
4171 else
4172 return Qnil;
4173 }
4174
4175 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
4176 doc: /* Internal function called by `display-color-p', which see. */)
4177 (display)
4178 Lisp_Object display;
4179 {
4180 struct mac_display_info *dpyinfo = check_x_display_info (display);
4181
4182 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
4183 return Qnil;
4184
4185 return Qt;
4186 }
4187
4188 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
4189 0, 1, 0,
4190 doc: /* Return t if the X display supports shades of gray.
4191 Note that color displays do support shades of gray.
4192 The optional argument DISPLAY specifies which display to ask about.
4193 DISPLAY should be either a frame or a display name (a string).
4194 If omitted or nil, that stands for the selected frame's display. */)
4195 (display)
4196 Lisp_Object display;
4197 {
4198 struct mac_display_info *dpyinfo = check_x_display_info (display);
4199
4200 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
4201 return Qnil;
4202
4203 return Qt;
4204 }
4205
4206 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
4207 0, 1, 0,
4208 doc: /* Returns the width in pixels of the X display DISPLAY.
4209 The optional argument DISPLAY specifies which display to ask about.
4210 DISPLAY should be either a frame or a display name (a string).
4211 If omitted or nil, that stands for the selected frame's display. */)
4212 (display)
4213 Lisp_Object display;
4214 {
4215 struct mac_display_info *dpyinfo = check_x_display_info (display);
4216
4217 return make_number (dpyinfo->width);
4218 }
4219
4220 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
4221 Sx_display_pixel_height, 0, 1, 0,
4222 doc: /* Returns the height in pixels of the X display DISPLAY.
4223 The optional argument DISPLAY specifies which display to ask about.
4224 DISPLAY should be either a frame or a display name (a string).
4225 If omitted or nil, that stands for the selected frame's display. */)
4226 (display)
4227 Lisp_Object display;
4228 {
4229 struct mac_display_info *dpyinfo = check_x_display_info (display);
4230
4231 return make_number (dpyinfo->height);
4232 }
4233
4234 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
4235 0, 1, 0,
4236 doc: /* Returns the number of bitplanes of the display DISPLAY.
4237 The optional argument DISPLAY specifies which display to ask about.
4238 DISPLAY should be either a frame or a display name (a string).
4239 If omitted or nil, that stands for the selected frame's display. */)
4240 (display)
4241 Lisp_Object display;
4242 {
4243 struct mac_display_info *dpyinfo = check_x_display_info (display);
4244
4245 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
4246 }
4247
4248 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
4249 0, 1, 0,
4250 doc: /* Returns the number of color cells of the display DISPLAY.
4251 The optional argument DISPLAY specifies which display to ask about.
4252 DISPLAY should be either a frame or a display name (a string).
4253 If omitted or nil, that stands for the selected frame's display. */)
4254 (display)
4255 Lisp_Object display;
4256 {
4257 struct mac_display_info *dpyinfo = check_x_display_info (display);
4258
4259 /* MAC_TODO: check whether this is right */
4260 return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits)));
4261 }
4262
4263 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4264 Sx_server_max_request_size,
4265 0, 1, 0,
4266 doc: /* Returns the maximum request size of the server of display DISPLAY.
4267 The optional argument DISPLAY specifies which display to ask about.
4268 DISPLAY should be either a frame or a display name (a string).
4269 If omitted or nil, that stands for the selected frame's display. */)
4270 (display)
4271 Lisp_Object display;
4272 {
4273 struct mac_display_info *dpyinfo = check_x_display_info (display);
4274
4275 return make_number (1);
4276 }
4277
4278 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4279 doc: /* Returns the vendor ID string of the Mac OS system (Apple).
4280 The optional argument DISPLAY specifies which display to ask about.
4281 DISPLAY should be either a frame or a display name (a string).
4282 If omitted or nil, that stands for the selected frame's display. */)
4283 (display)
4284 Lisp_Object display;
4285 {
4286 return build_string ("Apple Computers");
4287 }
4288
4289 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4290 doc: /* Returns the version numbers of the server of display DISPLAY.
4291 The value is a list of three integers: the major and minor
4292 version numbers, and the vendor-specific release
4293 number. See also the function `x-server-vendor'.
4294
4295 The optional argument DISPLAY specifies which display to ask about.
4296 DISPLAY should be either a frame or a display name (a string).
4297 If omitted or nil, that stands for the selected frame's display. */)
4298 (display)
4299 Lisp_Object display;
4300 {
4301 int mac_major_version, mac_minor_version;
4302 SInt32 response;
4303
4304 if (Gestalt (gestaltSystemVersion, &response) != noErr)
4305 error ("Cannot get Mac OS version");
4306
4307 mac_major_version = (response >> 8) & 0xf;
4308 mac_minor_version = (response >> 4) & 0xf;
4309
4310 return Fcons (make_number (mac_major_version),
4311 Fcons (make_number (mac_minor_version), Qnil));
4312 }
4313
4314 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4315 doc: /* Return the number of screens on the server of display DISPLAY.
4316 The optional argument DISPLAY specifies which display to ask about.
4317 DISPLAY should be either a frame or a display name (a string).
4318 If omitted or nil, that stands for the selected frame's display. */)
4319 (display)
4320 Lisp_Object display;
4321 {
4322 return make_number (1);
4323 }
4324
4325 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4326 doc: /* Return the height in millimeters of the X display DISPLAY.
4327 The optional argument DISPLAY specifies which display to ask about.
4328 DISPLAY should be either a frame or a display name (a string).
4329 If omitted or nil, that stands for the selected frame's display. */)
4330 (display)
4331 Lisp_Object display;
4332 {
4333 /* MAC_TODO: this is an approximation, and only of the main display */
4334
4335 struct mac_display_info *dpyinfo = check_x_display_info (display);
4336 short h, v;
4337
4338 ScreenRes (&h, &v);
4339
4340 return make_number ((int) (v / 72.0 * 25.4));
4341 }
4342
4343 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4344 doc: /* Return the width in millimeters of the X display DISPLAY.
4345 The optional argument DISPLAY specifies which display to ask about.
4346 DISPLAY should be either a frame or a display name (a string).
4347 If omitted or nil, that stands for the selected frame's display. */)
4348 (display)
4349 Lisp_Object display;
4350 {
4351 /* MAC_TODO: this is an approximation, and only of the main display */
4352
4353 struct mac_display_info *dpyinfo = check_x_display_info (display);
4354 short h, v;
4355
4356 ScreenRes (&h, &v);
4357
4358 return make_number ((int) (h / 72.0 * 25.4));
4359 }
4360
4361 DEFUN ("x-display-backing-store", Fx_display_backing_store,
4362 Sx_display_backing_store, 0, 1, 0,
4363 doc: /* Returns an indication of whether display DISPLAY does backing store.
4364 The value may be `always', `when-mapped', or `not-useful'.
4365 The optional argument DISPLAY specifies which display to ask about.
4366 DISPLAY should be either a frame or a display name (a string).
4367 If omitted or nil, that stands for the selected frame's display. */)
4368 (display)
4369 Lisp_Object display;
4370 {
4371 return intern ("not-useful");
4372 }
4373
4374 DEFUN ("x-display-visual-class", Fx_display_visual_class,
4375 Sx_display_visual_class, 0, 1, 0,
4376 doc: /* Returns the visual class of the display DISPLAY.
4377 The value is one of the symbols `static-gray', `gray-scale',
4378 `static-color', `pseudo-color', `true-color', or `direct-color'.
4379
4380 The optional argument DISPLAY specifies which display to ask about.
4381 DISPLAY should be either a frame or a display name (a string).
4382 If omitted or nil, that stands for the selected frame's display. */)
4383 (display)
4384 Lisp_Object display;
4385 {
4386 struct mac_display_info *dpyinfo = check_x_display_info (display);
4387
4388 #if 0
4389 switch (dpyinfo->visual->class)
4390 {
4391 case StaticGray: return (intern ("static-gray"));
4392 case GrayScale: return (intern ("gray-scale"));
4393 case StaticColor: return (intern ("static-color"));
4394 case PseudoColor: return (intern ("pseudo-color"));
4395 case TrueColor: return (intern ("true-color"));
4396 case DirectColor: return (intern ("direct-color"));
4397 default:
4398 error ("Display has an unknown visual class");
4399 }
4400 #endif /* 0 */
4401
4402 return (intern ("true-color"));
4403 }
4404
4405 DEFUN ("x-display-save-under", Fx_display_save_under,
4406 Sx_display_save_under, 0, 1, 0,
4407 doc: /* Returns t if the display DISPLAY supports the save-under feature.
4408 The optional argument DISPLAY specifies which display to ask about.
4409 DISPLAY should be either a frame or a display name (a string).
4410 If omitted or nil, that stands for the selected frame's display. */)
4411 (display)
4412 Lisp_Object display;
4413 {
4414 return Qnil;
4415 }
4416 \f
4417 int
4418 x_pixel_width (f)
4419 register struct frame *f;
4420 {
4421 return PIXEL_WIDTH (f);
4422 }
4423
4424 int
4425 x_pixel_height (f)
4426 register struct frame *f;
4427 {
4428 return PIXEL_HEIGHT (f);
4429 }
4430
4431 int
4432 x_char_width (f)
4433 register struct frame *f;
4434 {
4435 return FONT_WIDTH (f->output_data.mac->font);
4436 }
4437
4438 int
4439 x_char_height (f)
4440 register struct frame *f;
4441 {
4442 return f->output_data.mac->line_height;
4443 }
4444
4445 int
4446 x_screen_planes (f)
4447 register struct frame *f;
4448 {
4449 return FRAME_MAC_DISPLAY_INFO (f)->n_planes;
4450 }
4451 \f
4452 /* Return the display structure for the display named NAME.
4453 Open a new connection if necessary. */
4454
4455 struct mac_display_info *
4456 x_display_info_for_name (name)
4457 Lisp_Object name;
4458 {
4459 Lisp_Object names;
4460 struct mac_display_info *dpyinfo;
4461
4462 CHECK_STRING (name);
4463
4464 for (dpyinfo = &one_mac_display_info, names = x_display_name_list;
4465 dpyinfo;
4466 dpyinfo = dpyinfo->next, names = XCDR (names))
4467 {
4468 Lisp_Object tem;
4469 tem = Fstring_equal (XCAR (XCAR (names)), name);
4470 if (!NILP (tem))
4471 return dpyinfo;
4472 }
4473
4474 /* Use this general default value to start with. */
4475 Vx_resource_name = Vinvocation_name;
4476
4477 validate_x_resource_name ();
4478
4479 dpyinfo = mac_term_init (name, (unsigned char *) 0,
4480 (char *) SDATA (Vx_resource_name));
4481
4482 if (dpyinfo == 0)
4483 error ("Cannot connect to server %s", SDATA (name));
4484
4485 mac_in_use = 1;
4486 XSETFASTINT (Vwindow_system_version, 3);
4487
4488 return dpyinfo;
4489 }
4490
4491 #if 0 /* MAC_TODO: implement network support */
4492 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
4493 1, 3, 0,
4494 doc: /* Open a connection to a server.
4495 DISPLAY is the name of the display to connect to.
4496 Optional second arg XRM-STRING is a string of resources in xrdb format.
4497 If the optional third arg MUST-SUCCEED is non-nil,
4498 terminate Emacs if we can't open the connection. */)
4499 (display, xrm_string, must_succeed)
4500 Lisp_Object display, xrm_string, must_succeed;
4501 {
4502 unsigned char *xrm_option;
4503 struct mac_display_info *dpyinfo;
4504
4505 CHECK_STRING (display);
4506 if (! NILP (xrm_string))
4507 CHECK_STRING (xrm_string);
4508
4509 if (! EQ (Vwindow_system, intern ("mac")))
4510 error ("Not using Mac OS");
4511
4512 if (! NILP (xrm_string))
4513 xrm_option = (unsigned char *) SDATA (xrm_string);
4514 else
4515 xrm_option = (unsigned char *) 0;
4516
4517 validate_x_resource_name ();
4518
4519 /* This is what opens the connection and sets x_current_display.
4520 This also initializes many symbols, such as those used for input. */
4521 dpyinfo = mac_term_init (display, xrm_option,
4522 (char *) SDATA (Vx_resource_name));
4523
4524 if (dpyinfo == 0)
4525 {
4526 if (!NILP (must_succeed))
4527 fatal ("Cannot connect to server %s.\n",
4528 SDATA (display));
4529 else
4530 error ("Cannot connect to server %s", SDATA (display));
4531 }
4532
4533 mac_in_use = 1;
4534
4535 XSETFASTINT (Vwindow_system_version, 3);
4536 return Qnil;
4537 }
4538
4539 DEFUN ("x-close-connection", Fx_close_connection,
4540 Sx_close_connection, 1, 1, 0,
4541 doc: /* Close the connection to DISPLAY's server.
4542 For DISPLAY, specify either a frame or a display name (a string).
4543 If DISPLAY is nil, that stands for the selected frame's display. */)
4544 (display)
4545 Lisp_Object display;
4546 {
4547 struct mac_display_info *dpyinfo = check_x_display_info (display);
4548 int i;
4549
4550 if (dpyinfo->reference_count > 0)
4551 error ("Display still has frames on it");
4552
4553 BLOCK_INPUT;
4554 /* Free the fonts in the font table. */
4555 for (i = 0; i < dpyinfo->n_fonts; i++)
4556 if (dpyinfo->font_table[i].name)
4557 {
4558 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
4559 xfree (dpyinfo->font_table[i].full_name);
4560 xfree (dpyinfo->font_table[i].name);
4561 x_unload_font (dpyinfo, dpyinfo->font_table[i].font);
4562 }
4563 x_destroy_all_bitmaps (dpyinfo);
4564
4565 x_delete_display (dpyinfo);
4566 UNBLOCK_INPUT;
4567
4568 return Qnil;
4569 }
4570 #endif /* 0 */
4571
4572 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
4573 doc: /* Return the list of display names that Emacs has connections to. */)
4574 ()
4575 {
4576 Lisp_Object tail, result;
4577
4578 result = Qnil;
4579 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
4580 result = Fcons (XCAR (XCAR (tail)), result);
4581
4582 return result;
4583 }
4584
4585 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
4586 doc: /* If ON is non-nil, report errors as soon as the erring request is made.
4587 If ON is nil, allow buffering of requests.
4588 This is a noop on Mac OS systems.
4589 The optional second argument DISPLAY specifies which display to act on.
4590 DISPLAY should be either a frame or a display name (a string).
4591 If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
4592 (on, display)
4593 Lisp_Object display, on;
4594 {
4595 return Qnil;
4596 }
4597
4598 \f
4599 /***********************************************************************
4600 Image types
4601 ***********************************************************************/
4602
4603 /* Value is the number of elements of vector VECTOR. */
4604
4605 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
4606
4607 /* List of supported image types. Use define_image_type to add new
4608 types. Use lookup_image_type to find a type for a given symbol. */
4609
4610 static struct image_type *image_types;
4611
4612 /* The symbol `image' which is the car of the lists used to represent
4613 images in Lisp. */
4614
4615 extern Lisp_Object Qimage;
4616
4617 /* The symbol `xbm' which is used as the type symbol for XBM images. */
4618
4619 Lisp_Object Qxbm;
4620
4621 /* Keywords. */
4622
4623 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
4624 extern Lisp_Object QCdata, QCtype;
4625 Lisp_Object QCascent, QCmargin, QCrelief;
4626 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4627 Lisp_Object QCindex;
4628
4629 /* Other symbols. */
4630
4631 Lisp_Object Qlaplace;
4632
4633 /* Time in seconds after which images should be removed from the cache
4634 if not displayed. */
4635
4636 Lisp_Object Vimage_cache_eviction_delay;
4637
4638 /* Function prototypes. */
4639
4640 static void define_image_type P_ ((struct image_type *type));
4641 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
4642 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
4643 static void x_laplace P_ ((struct frame *, struct image *));
4644 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
4645 Lisp_Object));
4646
4647
4648 /* Define a new image type from TYPE. This adds a copy of TYPE to
4649 image_types and adds the symbol *TYPE->type to Vimage_types. */
4650
4651 static void
4652 define_image_type (type)
4653 struct image_type *type;
4654 {
4655 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
4656 The initialized data segment is read-only. */
4657 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
4658 bcopy (type, p, sizeof *p);
4659 p->next = image_types;
4660 image_types = p;
4661 Vimage_types = Fcons (*p->type, Vimage_types);
4662 }
4663
4664
4665 /* Look up image type SYMBOL, and return a pointer to its image_type
4666 structure. Value is null if SYMBOL is not a known image type. */
4667
4668 static INLINE struct image_type *
4669 lookup_image_type (symbol)
4670 Lisp_Object symbol;
4671 {
4672 struct image_type *type;
4673
4674 for (type = image_types; type; type = type->next)
4675 if (EQ (symbol, *type->type))
4676 break;
4677
4678 return type;
4679 }
4680
4681
4682 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
4683 valid image specification is a list whose car is the symbol
4684 `image', and whose rest is a property list. The property list must
4685 contain a value for key `:type'. That value must be the name of a
4686 supported image type. The rest of the property list depends on the
4687 image type. */
4688
4689 int
4690 valid_image_p (object)
4691 Lisp_Object object;
4692 {
4693 int valid_p = 0;
4694
4695 if (CONSP (object) && EQ (XCAR (object), Qimage))
4696 {
4697 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
4698 struct image_type *type = lookup_image_type (symbol);
4699
4700 if (type)
4701 valid_p = type->valid_p (object);
4702 }
4703
4704 return valid_p;
4705 }
4706
4707
4708 /* Log error message with format string FORMAT and argument ARG.
4709 Signaling an error, e.g. when an image cannot be loaded, is not a
4710 good idea because this would interrupt redisplay, and the error
4711 message display would lead to another redisplay. This function
4712 therefore simply displays a message. */
4713
4714 static void
4715 image_error (format, arg1, arg2)
4716 char *format;
4717 Lisp_Object arg1, arg2;
4718 {
4719 add_to_log (format, arg1, arg2);
4720 }
4721
4722
4723 \f
4724 /***********************************************************************
4725 Image specifications
4726 ***********************************************************************/
4727
4728 enum image_value_type
4729 {
4730 IMAGE_DONT_CHECK_VALUE_TYPE,
4731 IMAGE_STRING_VALUE,
4732 IMAGE_SYMBOL_VALUE,
4733 IMAGE_POSITIVE_INTEGER_VALUE,
4734 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
4735 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
4736 IMAGE_ASCENT_VALUE,
4737 IMAGE_INTEGER_VALUE,
4738 IMAGE_FUNCTION_VALUE,
4739 IMAGE_NUMBER_VALUE,
4740 IMAGE_BOOL_VALUE
4741 };
4742
4743 /* Structure used when parsing image specifications. */
4744
4745 struct image_keyword
4746 {
4747 /* Name of keyword. */
4748 char *name;
4749
4750 /* The type of value allowed. */
4751 enum image_value_type type;
4752
4753 /* Non-zero means key must be present. */
4754 int mandatory_p;
4755
4756 /* Used to recognize duplicate keywords in a property list. */
4757 int count;
4758
4759 /* The value that was found. */
4760 Lisp_Object value;
4761 };
4762
4763
4764 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
4765 int, Lisp_Object));
4766 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
4767
4768
4769 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
4770 has the format (image KEYWORD VALUE ...). One of the keyword/
4771 value pairs must be `:type TYPE'. KEYWORDS is a vector of
4772 image_keywords structures of size NKEYWORDS describing other
4773 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
4774
4775 static int
4776 parse_image_spec (spec, keywords, nkeywords, type)
4777 Lisp_Object spec;
4778 struct image_keyword *keywords;
4779 int nkeywords;
4780 Lisp_Object type;
4781 {
4782 int i;
4783 Lisp_Object plist;
4784
4785 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
4786 return 0;
4787
4788 plist = XCDR (spec);
4789 while (CONSP (plist))
4790 {
4791 Lisp_Object key, value;
4792
4793 /* First element of a pair must be a symbol. */
4794 key = XCAR (plist);
4795 plist = XCDR (plist);
4796 if (!SYMBOLP (key))
4797 return 0;
4798
4799 /* There must follow a value. */
4800 if (!CONSP (plist))
4801 return 0;
4802 value = XCAR (plist);
4803 plist = XCDR (plist);
4804
4805 /* Find key in KEYWORDS. Error if not found. */
4806 for (i = 0; i < nkeywords; ++i)
4807 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
4808 break;
4809
4810 if (i == nkeywords)
4811 continue;
4812
4813 /* Record that we recognized the keyword. If a keywords
4814 was found more than once, it's an error. */
4815 keywords[i].value = value;
4816 ++keywords[i].count;
4817
4818 if (keywords[i].count > 1)
4819 return 0;
4820
4821 /* Check type of value against allowed type. */
4822 switch (keywords[i].type)
4823 {
4824 case IMAGE_STRING_VALUE:
4825 if (!STRINGP (value))
4826 return 0;
4827 break;
4828
4829 case IMAGE_SYMBOL_VALUE:
4830 if (!SYMBOLP (value))
4831 return 0;
4832 break;
4833
4834 case IMAGE_POSITIVE_INTEGER_VALUE:
4835 if (!INTEGERP (value) || XINT (value) <= 0)
4836 return 0;
4837 break;
4838
4839 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
4840 if (INTEGERP (value) && XINT (value) >= 0)
4841 break;
4842 if (CONSP (value)
4843 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
4844 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
4845 break;
4846 return 0;
4847
4848 case IMAGE_ASCENT_VALUE:
4849 if (SYMBOLP (value) && EQ (value, Qcenter))
4850 break;
4851 else if (INTEGERP (value)
4852 && XINT (value) >= 0
4853 && XINT (value) <= 100)
4854 break;
4855 return 0;
4856
4857 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
4858 if (!INTEGERP (value) || XINT (value) < 0)
4859 return 0;
4860 break;
4861
4862 case IMAGE_DONT_CHECK_VALUE_TYPE:
4863 break;
4864
4865 case IMAGE_FUNCTION_VALUE:
4866 value = indirect_function (value);
4867 if (SUBRP (value)
4868 || COMPILEDP (value)
4869 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
4870 break;
4871 return 0;
4872
4873 case IMAGE_NUMBER_VALUE:
4874 if (!INTEGERP (value) && !FLOATP (value))
4875 return 0;
4876 break;
4877
4878 case IMAGE_INTEGER_VALUE:
4879 if (!INTEGERP (value))
4880 return 0;
4881 break;
4882
4883 case IMAGE_BOOL_VALUE:
4884 if (!NILP (value) && !EQ (value, Qt))
4885 return 0;
4886 break;
4887
4888 default:
4889 abort ();
4890 break;
4891 }
4892
4893 if (EQ (key, QCtype) && !EQ (type, value))
4894 return 0;
4895 }
4896
4897 /* Check that all mandatory fields are present. */
4898 for (i = 0; i < nkeywords; ++i)
4899 if (keywords[i].mandatory_p && keywords[i].count == 0)
4900 return 0;
4901
4902 return NILP (plist);
4903 }
4904
4905
4906 /* Return the value of KEY in image specification SPEC. Value is nil
4907 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
4908 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
4909
4910 static Lisp_Object
4911 image_spec_value (spec, key, found)
4912 Lisp_Object spec, key;
4913 int *found;
4914 {
4915 Lisp_Object tail;
4916
4917 xassert (valid_image_p (spec));
4918
4919 for (tail = XCDR (spec);
4920 CONSP (tail) && CONSP (XCDR (tail));
4921 tail = XCDR (XCDR (tail)))
4922 {
4923 if (EQ (XCAR (tail), key))
4924 {
4925 if (found)
4926 *found = 1;
4927 return XCAR (XCDR (tail));
4928 }
4929 }
4930
4931 if (found)
4932 *found = 0;
4933 return Qnil;
4934 }
4935
4936
4937
4938 \f
4939 /***********************************************************************
4940 Image type independent image structures
4941 ***********************************************************************/
4942
4943 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4944 static void free_image P_ ((struct frame *f, struct image *img));
4945
4946
4947 /* Allocate and return a new image structure for image specification
4948 SPEC. SPEC has a hash value of HASH. */
4949
4950 static struct image *
4951 make_image (spec, hash)
4952 Lisp_Object spec;
4953 unsigned hash;
4954 {
4955 struct image *img = (struct image *) xmalloc (sizeof *img);
4956
4957 xassert (valid_image_p (spec));
4958 bzero (img, sizeof *img);
4959 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
4960 xassert (img->type != NULL);
4961 img->spec = spec;
4962 img->data.lisp_val = Qnil;
4963 img->ascent = DEFAULT_IMAGE_ASCENT;
4964 img->hash = hash;
4965 return img;
4966 }
4967
4968
4969 /* Free image IMG which was used on frame F, including its resources. */
4970
4971 static void
4972 free_image (f, img)
4973 struct frame *f;
4974 struct image *img;
4975 {
4976 if (img)
4977 {
4978 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
4979
4980 /* Remove IMG from the hash table of its cache. */
4981 if (img->prev)
4982 img->prev->next = img->next;
4983 else
4984 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
4985
4986 if (img->next)
4987 img->next->prev = img->prev;
4988
4989 c->images[img->id] = NULL;
4990
4991 /* Free resources, then free IMG. */
4992 img->type->free (f, img);
4993 xfree (img);
4994 }
4995 }
4996
4997
4998 /* Prepare image IMG for display on frame F. Must be called before
4999 drawing an image. */
5000
5001 void
5002 prepare_image_for_display (f, img)
5003 struct frame *f;
5004 struct image *img;
5005 {
5006 EMACS_TIME t;
5007
5008 /* We're about to display IMG, so set its timestamp to `now'. */
5009 EMACS_GET_TIME (t);
5010 img->timestamp = EMACS_SECS (t);
5011
5012 /* If IMG doesn't have a pixmap yet, load it now, using the image
5013 type dependent loader function. */
5014 if (img->pixmap == 0 && !img->load_failed_p)
5015 img->load_failed_p = img->type->load (f, img) == 0;
5016 }
5017
5018
5019 /* Value is the number of pixels for the ascent of image IMG when
5020 drawn in face FACE. */
5021
5022 int
5023 image_ascent (img, face)
5024 struct image *img;
5025 struct face *face;
5026 {
5027 int height = img->height + img->vmargin;
5028 int ascent;
5029
5030 if (img->ascent == CENTERED_IMAGE_ASCENT)
5031 {
5032 if (face->font)
5033 ascent = height / 2 - (FONT_DESCENT(face->font)
5034 - FONT_BASE(face->font)) / 2;
5035 else
5036 ascent = height / 2;
5037 }
5038 else
5039 ascent = height * img->ascent / 100.0;
5040
5041 return ascent;
5042 }
5043
5044
5045 \f
5046 /***********************************************************************
5047 Helper functions for X image types
5048 ***********************************************************************/
5049
5050 static void x_clear_image P_ ((struct frame *f, struct image *img));
5051 static unsigned long x_alloc_image_color P_ ((struct frame *f,
5052 struct image *img,
5053 Lisp_Object color_name,
5054 unsigned long dflt));
5055
5056 /* Free X resources of image IMG which is used on frame F. */
5057
5058 static void
5059 x_clear_image (f, img)
5060 struct frame *f;
5061 struct image *img;
5062 {
5063 #if 0 /* MAC_TODO: W32 image support */
5064
5065 if (img->pixmap)
5066 {
5067 BLOCK_INPUT;
5068 XFreePixmap (NULL, img->pixmap);
5069 img->pixmap = 0;
5070 UNBLOCK_INPUT;
5071 }
5072
5073 if (img->ncolors)
5074 {
5075 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
5076
5077 /* If display has an immutable color map, freeing colors is not
5078 necessary and some servers don't allow it. So don't do it. */
5079 if (class != StaticColor
5080 && class != StaticGray
5081 && class != TrueColor)
5082 {
5083 Colormap cmap;
5084 BLOCK_INPUT;
5085 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
5086 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
5087 img->ncolors, 0);
5088 UNBLOCK_INPUT;
5089 }
5090
5091 xfree (img->colors);
5092 img->colors = NULL;
5093 img->ncolors = 0;
5094 }
5095 #endif /* MAC_TODO */
5096 }
5097
5098
5099 /* Allocate color COLOR_NAME for image IMG on frame F. If color
5100 cannot be allocated, use DFLT. Add a newly allocated color to
5101 IMG->colors, so that it can be freed again. Value is the pixel
5102 color. */
5103
5104 static unsigned long
5105 x_alloc_image_color (f, img, color_name, dflt)
5106 struct frame *f;
5107 struct image *img;
5108 Lisp_Object color_name;
5109 unsigned long dflt;
5110 {
5111 #if 0 /* MAC_TODO: allocing colors. */
5112 XColor color;
5113 unsigned long result;
5114
5115 xassert (STRINGP (color_name));
5116
5117 if (w32_defined_color (f, SDATA (color_name), &color, 1))
5118 {
5119 /* This isn't called frequently so we get away with simply
5120 reallocating the color vector to the needed size, here. */
5121 ++img->ncolors;
5122 img->colors =
5123 (unsigned long *) xrealloc (img->colors,
5124 img->ncolors * sizeof *img->colors);
5125 img->colors[img->ncolors - 1] = color.pixel;
5126 result = color.pixel;
5127 }
5128 else
5129 result = dflt;
5130 return result;
5131 #endif /* MAC_TODO */
5132 return 0;
5133 }
5134
5135
5136 \f
5137 /***********************************************************************
5138 Image Cache
5139 ***********************************************************************/
5140
5141 static void cache_image P_ ((struct frame *f, struct image *img));
5142
5143
5144 /* Return a new, initialized image cache that is allocated from the
5145 heap. Call free_image_cache to free an image cache. */
5146
5147 struct image_cache *
5148 make_image_cache ()
5149 {
5150 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5151 int size;
5152
5153 bzero (c, sizeof *c);
5154 c->size = 50;
5155 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
5156 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
5157 c->buckets = (struct image **) xmalloc (size);
5158 bzero (c->buckets, size);
5159 return c;
5160 }
5161
5162
5163 /* Free image cache of frame F. Be aware that X frames share images
5164 caches. */
5165
5166 void
5167 free_image_cache (f)
5168 struct frame *f;
5169 {
5170 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5171 if (c)
5172 {
5173 int i;
5174
5175 /* Cache should not be referenced by any frame when freed. */
5176 xassert (c->refcount == 0);
5177
5178 for (i = 0; i < c->used; ++i)
5179 free_image (f, c->images[i]);
5180 xfree (c->images);
5181 xfree (c->buckets);
5182 xfree (c);
5183 FRAME_X_IMAGE_CACHE (f) = NULL;
5184 }
5185 }
5186
5187
5188 /* Clear image cache of frame F. FORCE_P non-zero means free all
5189 images. FORCE_P zero means clear only images that haven't been
5190 displayed for some time. Should be called from time to time to
5191 reduce the number of loaded images. If image-eviction-seconds is
5192 non-nil, this frees images in the cache which weren't displayed for
5193 at least that many seconds. */
5194
5195 void
5196 clear_image_cache (f, force_p)
5197 struct frame *f;
5198 int force_p;
5199 {
5200 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5201
5202 if (c && INTEGERP (Vimage_cache_eviction_delay))
5203 {
5204 EMACS_TIME t;
5205 unsigned long old;
5206 int i, any_freed_p = 0;
5207
5208 EMACS_GET_TIME (t);
5209 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
5210
5211 for (i = 0; i < c->used; ++i)
5212 {
5213 struct image *img = c->images[i];
5214 if (img != NULL
5215 && (force_p
5216 || (img->timestamp > old)))
5217 {
5218 free_image (f, img);
5219 any_freed_p = 1;
5220 }
5221 }
5222
5223 /* We may be clearing the image cache because, for example,
5224 Emacs was iconified for a longer period of time. In that
5225 case, current matrices may still contain references to
5226 images freed above. So, clear these matrices. */
5227 if (any_freed_p)
5228 {
5229 clear_current_matrices (f);
5230 ++windows_or_buffers_changed;
5231 }
5232 }
5233 }
5234
5235
5236 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
5237 0, 1, 0,
5238 doc: /* Clear the image cache of FRAME.
5239 FRAME nil or omitted means use the selected frame.
5240 FRAME t means clear the image caches of all frames. */)
5241 (frame)
5242 Lisp_Object frame;
5243 {
5244 if (EQ (frame, Qt))
5245 {
5246 Lisp_Object tail;
5247
5248 FOR_EACH_FRAME (tail, frame)
5249 if (FRAME_MAC_P (XFRAME (frame)))
5250 clear_image_cache (XFRAME (frame), 1);
5251 }
5252 else
5253 clear_image_cache (check_x_frame (frame), 1);
5254
5255 return Qnil;
5256 }
5257
5258
5259 /* Return the id of image with Lisp specification SPEC on frame F.
5260 SPEC must be a valid Lisp image specification (see valid_image_p). */
5261
5262 int
5263 lookup_image (f, spec)
5264 struct frame *f;
5265 Lisp_Object spec;
5266 {
5267 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5268 struct image *img;
5269 int i;
5270 unsigned hash;
5271 struct gcpro gcpro1;
5272 EMACS_TIME now;
5273
5274 /* F must be a window-system frame, and SPEC must be a valid image
5275 specification. */
5276 xassert (FRAME_WINDOW_P (f));
5277 xassert (valid_image_p (spec));
5278
5279 GCPRO1 (spec);
5280
5281 /* Look up SPEC in the hash table of the image cache. */
5282 hash = sxhash (spec, 0);
5283 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
5284
5285 for (img = c->buckets[i]; img; img = img->next)
5286 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
5287 break;
5288
5289 /* If not found, create a new image and cache it. */
5290 if (img == NULL)
5291 {
5292 BLOCK_INPUT;
5293 img = make_image (spec, hash);
5294 cache_image (f, img);
5295 img->load_failed_p = img->type->load (f, img) == 0;
5296 xassert (!interrupt_input_blocked);
5297
5298 /* If we can't load the image, and we don't have a width and
5299 height, use some arbitrary width and height so that we can
5300 draw a rectangle for it. */
5301 if (img->load_failed_p)
5302 {
5303 Lisp_Object value;
5304
5305 value = image_spec_value (spec, QCwidth, NULL);
5306 img->width = (INTEGERP (value)
5307 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
5308 value = image_spec_value (spec, QCheight, NULL);
5309 img->height = (INTEGERP (value)
5310 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
5311 }
5312 else
5313 {
5314 /* Handle image type independent image attributes
5315 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
5316 Lisp_Object ascent, margin, relief;
5317
5318 ascent = image_spec_value (spec, QCascent, NULL);
5319 if (INTEGERP (ascent))
5320 img->ascent = XFASTINT (ascent);
5321 else if (EQ (ascent, Qcenter))
5322 img->ascent = CENTERED_IMAGE_ASCENT;
5323
5324 margin = image_spec_value (spec, QCmargin, NULL);
5325 if (INTEGERP (margin) && XINT (margin) >= 0)
5326 img->vmargin = img->hmargin = XFASTINT (margin);
5327 else if (CONSP (margin) && INTEGERP (XCAR (margin))
5328 && INTEGERP (XCDR (margin)))
5329 {
5330 if (XINT (XCAR (margin)) > 0)
5331 img->hmargin = XFASTINT (XCAR (margin));
5332 if (XINT (XCDR (margin)) > 0)
5333 img->vmargin = XFASTINT (XCDR (margin));
5334 }
5335
5336 relief = image_spec_value (spec, QCrelief, NULL);
5337 if (INTEGERP (relief))
5338 {
5339 img->relief = XINT (relief);
5340 img->hmargin += abs (img->relief);
5341 img->vmargin += abs (img->relief);
5342 }
5343 }
5344 }
5345
5346 /* We're using IMG, so set its timestamp to `now'. */
5347 EMACS_GET_TIME (now);
5348 img->timestamp = EMACS_SECS (now);
5349
5350 UNGCPRO;
5351
5352 /* Value is the image id. */
5353 return img->id;
5354 }
5355
5356
5357 /* Cache image IMG in the image cache of frame F. */
5358
5359 static void
5360 cache_image (f, img)
5361 struct frame *f;
5362 struct image *img;
5363 {
5364 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5365 int i;
5366
5367 /* Find a free slot in c->images. */
5368 for (i = 0; i < c->used; ++i)
5369 if (c->images[i] == NULL)
5370 break;
5371
5372 /* If no free slot found, maybe enlarge c->images. */
5373 if (i == c->used && c->used == c->size)
5374 {
5375 c->size *= 2;
5376 c->images = (struct image **) xrealloc (c->images,
5377 c->size * sizeof *c->images);
5378 }
5379
5380 /* Add IMG to c->images, and assign IMG an id. */
5381 c->images[i] = img;
5382 img->id = i;
5383 if (i == c->used)
5384 ++c->used;
5385
5386 /* Add IMG to the cache's hash table. */
5387 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
5388 img->next = c->buckets[i];
5389 if (img->next)
5390 img->next->prev = img;
5391 img->prev = NULL;
5392 c->buckets[i] = img;
5393 }
5394
5395
5396 /* Call FN on every image in the image cache of frame F. Used to mark
5397 Lisp Objects in the image cache. */
5398
5399 void
5400 forall_images_in_image_cache (f, fn)
5401 struct frame *f;
5402 void (*fn) P_ ((struct image *img));
5403 {
5404 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
5405 {
5406 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5407 if (c)
5408 {
5409 int i;
5410 for (i = 0; i < c->used; ++i)
5411 if (c->images[i])
5412 fn (c->images[i]);
5413 }
5414 }
5415 }
5416
5417
5418 \f
5419 /***********************************************************************
5420 Mac support code
5421 ***********************************************************************/
5422
5423 #if 0 /* MAC_TODO: Mac specific image code. */
5424
5425 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
5426 XImage **, Pixmap *));
5427 static void x_destroy_x_image P_ ((XImage *));
5428 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
5429
5430
5431 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
5432 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
5433 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
5434 via xmalloc. Print error messages via image_error if an error
5435 occurs. Value is non-zero if successful. */
5436
5437 static int
5438 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
5439 struct frame *f;
5440 int width, height, depth;
5441 XImage **ximg;
5442 Pixmap *pixmap;
5443 {
5444 #if 0 /* MAC_TODO: Image support for Mac */
5445 Display *display = FRAME_W32_DISPLAY (f);
5446 Screen *screen = FRAME_X_SCREEN (f);
5447 Window window = FRAME_W32_WINDOW (f);
5448
5449 xassert (interrupt_input_blocked);
5450
5451 if (depth <= 0)
5452 depth = DefaultDepthOfScreen (screen);
5453 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
5454 depth, ZPixmap, 0, NULL, width, height,
5455 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
5456 if (*ximg == NULL)
5457 {
5458 image_error ("Unable to allocate X image", Qnil, Qnil);
5459 return 0;
5460 }
5461
5462 /* Allocate image raster. */
5463 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
5464
5465 /* Allocate a pixmap of the same size. */
5466 *pixmap = XCreatePixmap (display, window, width, height, depth);
5467 if (*pixmap == 0)
5468 {
5469 x_destroy_x_image (*ximg);
5470 *ximg = NULL;
5471 image_error ("Unable to create X pixmap", Qnil, Qnil);
5472 return 0;
5473 }
5474 #endif /* MAC_TODO */
5475 return 1;
5476 }
5477
5478
5479 /* Destroy XImage XIMG. Free XIMG->data. */
5480
5481 static void
5482 x_destroy_x_image (ximg)
5483 XImage *ximg;
5484 {
5485 xassert (interrupt_input_blocked);
5486 if (ximg)
5487 {
5488 xfree (ximg->data);
5489 ximg->data = NULL;
5490 XDestroyImage (ximg);
5491 }
5492 }
5493
5494
5495 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
5496 are width and height of both the image and pixmap. */
5497
5498 static void
5499 x_put_x_image (f, ximg, pixmap, width, height)
5500 struct frame *f;
5501 XImage *ximg;
5502 Pixmap pixmap;
5503 {
5504 GC gc;
5505
5506 xassert (interrupt_input_blocked);
5507 gc = XCreateGC (NULL, pixmap, 0, NULL);
5508 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
5509 XFreeGC (NULL, gc);
5510 }
5511
5512 #endif /* MAC_TODO */
5513
5514 \f
5515 /***********************************************************************
5516 Searching files
5517 ***********************************************************************/
5518
5519 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
5520
5521 /* Find image file FILE. Look in data-directory, then
5522 x-bitmap-file-path. Value is the full name of the file found, or
5523 nil if not found. */
5524
5525 static Lisp_Object
5526 x_find_image_file (file)
5527 Lisp_Object file;
5528 {
5529 Lisp_Object file_found, search_path;
5530 struct gcpro gcpro1, gcpro2;
5531 int fd;
5532
5533 file_found = Qnil;
5534 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
5535 GCPRO2 (file_found, search_path);
5536
5537 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
5538 fd = openp (search_path, file, Qnil, &file_found, Qnil);
5539
5540 if (fd < 0)
5541 file_found = Qnil;
5542 else
5543 close (fd);
5544
5545 UNGCPRO;
5546 return file_found;
5547 }
5548
5549 \f
5550 /***********************************************************************
5551 XBM images
5552 ***********************************************************************/
5553
5554 static int xbm_load P_ ((struct frame *f, struct image *img));
5555 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
5556 Lisp_Object file));
5557 static int xbm_image_p P_ ((Lisp_Object object));
5558 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
5559 unsigned char **));
5560
5561
5562 /* Indices of image specification fields in xbm_format, below. */
5563
5564 enum xbm_keyword_index
5565 {
5566 XBM_TYPE,
5567 XBM_FILE,
5568 XBM_WIDTH,
5569 XBM_HEIGHT,
5570 XBM_DATA,
5571 XBM_FOREGROUND,
5572 XBM_BACKGROUND,
5573 XBM_ASCENT,
5574 XBM_MARGIN,
5575 XBM_RELIEF,
5576 XBM_ALGORITHM,
5577 XBM_HEURISTIC_MASK,
5578 XBM_LAST
5579 };
5580
5581 /* Vector of image_keyword structures describing the format
5582 of valid XBM image specifications. */
5583
5584 static struct image_keyword xbm_format[XBM_LAST] =
5585 {
5586 {":type", IMAGE_SYMBOL_VALUE, 1},
5587 {":file", IMAGE_STRING_VALUE, 0},
5588 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5589 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5590 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5591 {":foreground", IMAGE_STRING_VALUE, 0},
5592 {":background", IMAGE_STRING_VALUE, 0},
5593 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
5594 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5595 {":relief", IMAGE_INTEGER_VALUE, 0},
5596 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5597 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5598 };
5599
5600 /* Structure describing the image type XBM. */
5601
5602 static struct image_type xbm_type =
5603 {
5604 &Qxbm,
5605 xbm_image_p,
5606 xbm_load,
5607 x_clear_image,
5608 NULL
5609 };
5610
5611 /* Tokens returned from xbm_scan. */
5612
5613 enum xbm_token
5614 {
5615 XBM_TK_IDENT = 256,
5616 XBM_TK_NUMBER
5617 };
5618
5619
5620 /* Return non-zero if OBJECT is a valid XBM-type image specification.
5621 A valid specification is a list starting with the symbol `image'
5622 The rest of the list is a property list which must contain an
5623 entry `:type xbm..
5624
5625 If the specification specifies a file to load, it must contain
5626 an entry `:file FILENAME' where FILENAME is a string.
5627
5628 If the specification is for a bitmap loaded from memory it must
5629 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
5630 WIDTH and HEIGHT are integers > 0. DATA may be:
5631
5632 1. a string large enough to hold the bitmap data, i.e. it must
5633 have a size >= (WIDTH + 7) / 8 * HEIGHT
5634
5635 2. a bool-vector of size >= WIDTH * HEIGHT
5636
5637 3. a vector of strings or bool-vectors, one for each line of the
5638 bitmap.
5639
5640 Both the file and data forms may contain the additional entries
5641 `:background COLOR' and `:foreground COLOR'. If not present,
5642 foreground and background of the frame on which the image is
5643 displayed, is used. */
5644
5645 static int
5646 xbm_image_p (object)
5647 Lisp_Object object;
5648 {
5649 struct image_keyword kw[XBM_LAST];
5650
5651 bcopy (xbm_format, kw, sizeof kw);
5652 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
5653 return 0;
5654
5655 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5656
5657 if (kw[XBM_FILE].count)
5658 {
5659 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5660 return 0;
5661 }
5662 else
5663 {
5664 Lisp_Object data;
5665 int width, height;
5666
5667 /* Entries for `:width', `:height' and `:data' must be present. */
5668 if (!kw[XBM_WIDTH].count
5669 || !kw[XBM_HEIGHT].count
5670 || !kw[XBM_DATA].count)
5671 return 0;
5672
5673 data = kw[XBM_DATA].value;
5674 width = XFASTINT (kw[XBM_WIDTH].value);
5675 height = XFASTINT (kw[XBM_HEIGHT].value);
5676
5677 /* Check type of data, and width and height against contents of
5678 data. */
5679 if (VECTORP (data))
5680 {
5681 int i;
5682
5683 /* Number of elements of the vector must be >= height. */
5684 if (XVECTOR (data)->size < height)
5685 return 0;
5686
5687 /* Each string or bool-vector in data must be large enough
5688 for one line of the image. */
5689 for (i = 0; i < height; ++i)
5690 {
5691 Lisp_Object elt = XVECTOR (data)->contents[i];
5692
5693 if (STRINGP (elt))
5694 {
5695 if (SCHARS (elt)
5696 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5697 return 0;
5698 }
5699 else if (BOOL_VECTOR_P (elt))
5700 {
5701 if (XBOOL_VECTOR (elt)->size < width)
5702 return 0;
5703 }
5704 else
5705 return 0;
5706 }
5707 }
5708 else if (STRINGP (data))
5709 {
5710 if (SCHARS (data)
5711 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5712 return 0;
5713 }
5714 else if (BOOL_VECTOR_P (data))
5715 {
5716 if (XBOOL_VECTOR (data)->size < width * height)
5717 return 0;
5718 }
5719 else
5720 return 0;
5721 }
5722
5723 /* Baseline must be a value between 0 and 100 (a percentage). */
5724 if (kw[XBM_ASCENT].count
5725 && XFASTINT (kw[XBM_ASCENT].value) > 100)
5726 return 0;
5727
5728 return 1;
5729 }
5730
5731
5732 /* Scan a bitmap file. FP is the stream to read from. Value is
5733 either an enumerator from enum xbm_token, or a character for a
5734 single-character token, or 0 at end of file. If scanning an
5735 identifier, store the lexeme of the identifier in SVAL. If
5736 scanning a number, store its value in *IVAL. */
5737
5738 static int
5739 xbm_scan (fp, sval, ival)
5740 FILE *fp;
5741 char *sval;
5742 int *ival;
5743 {
5744 int c;
5745
5746 /* Skip white space. */
5747 while ((c = fgetc (fp)) != EOF && isspace (c))
5748 ;
5749
5750 if (c == EOF)
5751 c = 0;
5752 else if (isdigit (c))
5753 {
5754 int value = 0, digit;
5755
5756 if (c == '0')
5757 {
5758 c = fgetc (fp);
5759 if (c == 'x' || c == 'X')
5760 {
5761 while ((c = fgetc (fp)) != EOF)
5762 {
5763 if (isdigit (c))
5764 digit = c - '0';
5765 else if (c >= 'a' && c <= 'f')
5766 digit = c - 'a' + 10;
5767 else if (c >= 'A' && c <= 'F')
5768 digit = c - 'A' + 10;
5769 else
5770 break;
5771 value = 16 * value + digit;
5772 }
5773 }
5774 else if (isdigit (c))
5775 {
5776 value = c - '0';
5777 while ((c = fgetc (fp)) != EOF
5778 && isdigit (c))
5779 value = 8 * value + c - '0';
5780 }
5781 }
5782 else
5783 {
5784 value = c - '0';
5785 while ((c = fgetc (fp)) != EOF
5786 && isdigit (c))
5787 value = 10 * value + c - '0';
5788 }
5789
5790 if (c != EOF)
5791 ungetc (c, fp);
5792 *ival = value;
5793 c = XBM_TK_NUMBER;
5794 }
5795 else if (isalpha (c) || c == '_')
5796 {
5797 *sval++ = c;
5798 while ((c = fgetc (fp)) != EOF
5799 && (isalnum (c) || c == '_'))
5800 *sval++ = c;
5801 *sval = 0;
5802 if (c != EOF)
5803 ungetc (c, fp);
5804 c = XBM_TK_IDENT;
5805 }
5806
5807 return c;
5808 }
5809
5810
5811 /* Replacement for XReadBitmapFileData which isn't available under old
5812 X versions. FILE is the name of the bitmap file to read. Set
5813 *WIDTH and *HEIGHT to the width and height of the image. Return in
5814 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
5815 successful. */
5816
5817 static int
5818 xbm_read_bitmap_file_data (file, width, height, data)
5819 char *file;
5820 int *width, *height;
5821 unsigned char **data;
5822 {
5823 FILE *fp;
5824 char buffer[BUFSIZ];
5825 int padding_p = 0;
5826 int v10 = 0;
5827 int bytes_per_line, i, nbytes;
5828 unsigned char *p;
5829 int value;
5830 int LA1;
5831
5832 #define match() \
5833 LA1 = xbm_scan (fp, buffer, &value)
5834
5835 #define expect(TOKEN) \
5836 if (LA1 != (TOKEN)) \
5837 goto failure; \
5838 else \
5839 match ()
5840
5841 #define expect_ident(IDENT) \
5842 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5843 match (); \
5844 else \
5845 goto failure
5846
5847 fp = fopen (file, "r");
5848 if (fp == NULL)
5849 return 0;
5850
5851 *width = *height = -1;
5852 *data = NULL;
5853 LA1 = xbm_scan (fp, buffer, &value);
5854
5855 /* Parse defines for width, height and hot-spots. */
5856 while (LA1 == '#')
5857 {
5858 match ();
5859 expect_ident ("define");
5860 expect (XBM_TK_IDENT);
5861
5862 if (LA1 == XBM_TK_NUMBER);
5863 {
5864 char *p = strrchr (buffer, '_');
5865 p = p ? p + 1 : buffer;
5866 if (strcmp (p, "width") == 0)
5867 *width = value;
5868 else if (strcmp (p, "height") == 0)
5869 *height = value;
5870 }
5871 expect (XBM_TK_NUMBER);
5872 }
5873
5874 if (*width < 0 || *height < 0)
5875 goto failure;
5876
5877 /* Parse bits. Must start with `static'. */
5878 expect_ident ("static");
5879 if (LA1 == XBM_TK_IDENT)
5880 {
5881 if (strcmp (buffer, "unsigned") == 0)
5882 {
5883 match ();
5884 expect_ident ("char");
5885 }
5886 else if (strcmp (buffer, "short") == 0)
5887 {
5888 match ();
5889 v10 = 1;
5890 if (*width % 16 && *width % 16 < 9)
5891 padding_p = 1;
5892 }
5893 else if (strcmp (buffer, "char") == 0)
5894 match ();
5895 else
5896 goto failure;
5897 }
5898 else
5899 goto failure;
5900
5901 expect (XBM_TK_IDENT);
5902 expect ('[');
5903 expect (']');
5904 expect ('=');
5905 expect ('{');
5906
5907 bytes_per_line = (*width + 7) / 8 + padding_p;
5908 nbytes = bytes_per_line * *height;
5909 p = *data = (char *) xmalloc (nbytes);
5910
5911 if (v10)
5912 {
5913
5914 for (i = 0; i < nbytes; i += 2)
5915 {
5916 int val = value;
5917 expect (XBM_TK_NUMBER);
5918
5919 *p++ = val;
5920 if (!padding_p || ((i + 2) % bytes_per_line))
5921 *p++ = value >> 8;
5922
5923 if (LA1 == ',' || LA1 == '}')
5924 match ();
5925 else
5926 goto failure;
5927 }
5928 }
5929 else
5930 {
5931 for (i = 0; i < nbytes; ++i)
5932 {
5933 int val = value;
5934 expect (XBM_TK_NUMBER);
5935
5936 *p++ = val;
5937
5938 if (LA1 == ',' || LA1 == '}')
5939 match ();
5940 else
5941 goto failure;
5942 }
5943 }
5944
5945 fclose (fp);
5946 return 1;
5947
5948 failure:
5949
5950 fclose (fp);
5951 if (*data)
5952 {
5953 xfree (*data);
5954 *data = NULL;
5955 }
5956 return 0;
5957
5958 #undef match
5959 #undef expect
5960 #undef expect_ident
5961 }
5962
5963
5964 /* Load XBM image IMG which will be displayed on frame F from file
5965 SPECIFIED_FILE. Value is non-zero if successful. */
5966
5967 static int
5968 xbm_load_image_from_file (f, img, specified_file)
5969 struct frame *f;
5970 struct image *img;
5971 Lisp_Object specified_file;
5972 {
5973 int rc;
5974 unsigned char *data;
5975 int success_p = 0;
5976 Lisp_Object file;
5977 struct gcpro gcpro1;
5978
5979 xassert (STRINGP (specified_file));
5980 file = Qnil;
5981 GCPRO1 (file);
5982
5983 file = x_find_image_file (specified_file);
5984 if (!STRINGP (file))
5985 {
5986 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5987 UNGCPRO;
5988 return 0;
5989 }
5990
5991 rc = xbm_read_bitmap_file_data (SDATA (file), &img->width,
5992 &img->height, &data);
5993 if (rc)
5994 {
5995 int depth = one_mac_display_info.n_cbits;
5996 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
5997 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
5998 Lisp_Object value;
5999
6000 xassert (img->width > 0 && img->height > 0);
6001
6002 /* Get foreground and background colors, maybe allocate colors. */
6003 value = image_spec_value (img->spec, QCforeground, NULL);
6004 if (!NILP (value))
6005 foreground = x_alloc_image_color (f, img, value, foreground);
6006
6007 value = image_spec_value (img->spec, QCbackground, NULL);
6008 if (!NILP (value))
6009 background = x_alloc_image_color (f, img, value, background);
6010
6011 #if 0 /* MAC_TODO : Port image display to Mac */
6012 BLOCK_INPUT;
6013 img->pixmap
6014 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
6015 FRAME_W32_WINDOW (f),
6016 data,
6017 img->width, img->height,
6018 foreground, background,
6019 depth);
6020 xfree (data);
6021
6022 if (img->pixmap == 0)
6023 {
6024 x_clear_image (f, img);
6025 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
6026 }
6027 else
6028 success_p = 1;
6029
6030 UNBLOCK_INPUT;
6031 #endif /* MAC_TODO */
6032 }
6033 else
6034 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
6035
6036 UNGCPRO;
6037 return success_p;
6038 }
6039
6040
6041 /* Fill image IMG which is used on frame F with pixmap data. Value is
6042 non-zero if successful. */
6043
6044 static int
6045 xbm_load (f, img)
6046 struct frame *f;
6047 struct image *img;
6048 {
6049 int success_p = 0;
6050 Lisp_Object file_name;
6051
6052 xassert (xbm_image_p (img->spec));
6053
6054 /* If IMG->spec specifies a file name, create a non-file spec from it. */
6055 file_name = image_spec_value (img->spec, QCfile, NULL);
6056 if (STRINGP (file_name))
6057 success_p = xbm_load_image_from_file (f, img, file_name);
6058 else
6059 {
6060 struct image_keyword fmt[XBM_LAST];
6061 Lisp_Object data;
6062 int depth;
6063 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
6064 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
6065 char *bits;
6066 int parsed_p;
6067
6068 /* Parse the list specification. */
6069 bcopy (xbm_format, fmt, sizeof fmt);
6070 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
6071 xassert (parsed_p);
6072
6073 /* Get specified width, and height. */
6074 img->width = XFASTINT (fmt[XBM_WIDTH].value);
6075 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
6076 xassert (img->width > 0 && img->height > 0);
6077
6078 BLOCK_INPUT;
6079
6080 if (fmt[XBM_ASCENT].count)
6081 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
6082
6083 /* Get foreground and background colors, maybe allocate colors. */
6084 if (fmt[XBM_FOREGROUND].count)
6085 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
6086 foreground);
6087 if (fmt[XBM_BACKGROUND].count)
6088 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
6089 background);
6090
6091 /* Set bits to the bitmap image data. */
6092 data = fmt[XBM_DATA].value;
6093 if (VECTORP (data))
6094 {
6095 int i;
6096 char *p;
6097 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6098
6099 p = bits = (char *) alloca (nbytes * img->height);
6100 for (i = 0; i < img->height; ++i, p += nbytes)
6101 {
6102 Lisp_Object line = XVECTOR (data)->contents[i];
6103 if (STRINGP (line))
6104 bcopy (SDATA (line), p, nbytes);
6105 else
6106 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
6107 }
6108 }
6109 else if (STRINGP (data))
6110 bits = SDATA (data);
6111 else
6112 bits = XBOOL_VECTOR (data)->data;
6113
6114 #if 0 /* MAC_TODO : port Mac display code */
6115 /* Create the pixmap. */
6116 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
6117 img->pixmap
6118 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
6119 FRAME_W32_WINDOW (f),
6120 bits,
6121 img->width, img->height,
6122 foreground, background,
6123 depth);
6124 #endif /* MAC_TODO */
6125
6126 if (img->pixmap)
6127 success_p = 1;
6128 else
6129 {
6130 image_error ("Unable to create pixmap for XBM image `%s'",
6131 img->spec, Qnil);
6132 x_clear_image (f, img);
6133 }
6134
6135 UNBLOCK_INPUT;
6136 }
6137
6138 return success_p;
6139 }
6140
6141
6142 \f
6143 /***********************************************************************
6144 XPM images
6145 ***********************************************************************/
6146
6147 #if HAVE_XPM
6148
6149 static int xpm_image_p P_ ((Lisp_Object object));
6150 static int xpm_load P_ ((struct frame *f, struct image *img));
6151 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
6152
6153 #include "X11/xpm.h"
6154
6155 /* The symbol `xpm' identifying XPM-format images. */
6156
6157 Lisp_Object Qxpm;
6158
6159 /* Indices of image specification fields in xpm_format, below. */
6160
6161 enum xpm_keyword_index
6162 {
6163 XPM_TYPE,
6164 XPM_FILE,
6165 XPM_DATA,
6166 XPM_ASCENT,
6167 XPM_MARGIN,
6168 XPM_RELIEF,
6169 XPM_ALGORITHM,
6170 XPM_HEURISTIC_MASK,
6171 XPM_COLOR_SYMBOLS,
6172 XPM_LAST
6173 };
6174
6175 /* Vector of image_keyword structures describing the format
6176 of valid XPM image specifications. */
6177
6178 static struct image_keyword xpm_format[XPM_LAST] =
6179 {
6180 {":type", IMAGE_SYMBOL_VALUE, 1},
6181 {":file", IMAGE_STRING_VALUE, 0},
6182 {":data", IMAGE_STRING_VALUE, 0},
6183 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6184 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6185 {":relief", IMAGE_INTEGER_VALUE, 0},
6186 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6187 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6188 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6189 };
6190
6191 /* Structure describing the image type XBM. */
6192
6193 static struct image_type xpm_type =
6194 {
6195 &Qxpm,
6196 xpm_image_p,
6197 xpm_load,
6198 x_clear_image,
6199 NULL
6200 };
6201
6202
6203 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
6204 for XPM images. Such a list must consist of conses whose car and
6205 cdr are strings. */
6206
6207 static int
6208 xpm_valid_color_symbols_p (color_symbols)
6209 Lisp_Object color_symbols;
6210 {
6211 while (CONSP (color_symbols))
6212 {
6213 Lisp_Object sym = XCAR (color_symbols);
6214 if (!CONSP (sym)
6215 || !STRINGP (XCAR (sym))
6216 || !STRINGP (XCDR (sym)))
6217 break;
6218 color_symbols = XCDR (color_symbols);
6219 }
6220
6221 return NILP (color_symbols);
6222 }
6223
6224
6225 /* Value is non-zero if OBJECT is a valid XPM image specification. */
6226
6227 static int
6228 xpm_image_p (object)
6229 Lisp_Object object;
6230 {
6231 struct image_keyword fmt[XPM_LAST];
6232 bcopy (xpm_format, fmt, sizeof fmt);
6233 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
6234 /* Either `:file' or `:data' must be present. */
6235 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
6236 /* Either no `:color-symbols' or it's a list of conses
6237 whose car and cdr are strings. */
6238 && (fmt[XPM_COLOR_SYMBOLS].count == 0
6239 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
6240 && (fmt[XPM_ASCENT].count == 0
6241 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
6242 }
6243
6244
6245 /* Load image IMG which will be displayed on frame F. Value is
6246 non-zero if successful. */
6247
6248 static int
6249 xpm_load (f, img)
6250 struct frame *f;
6251 struct image *img;
6252 {
6253 int rc, i;
6254 XpmAttributes attrs;
6255 Lisp_Object specified_file, color_symbols;
6256
6257 /* Configure the XPM lib. Use the visual of frame F. Allocate
6258 close colors. Return colors allocated. */
6259 bzero (&attrs, sizeof attrs);
6260 attrs.visual = FRAME_X_VISUAL (f);
6261 attrs.colormap = FRAME_X_COLORMAP (f);
6262 attrs.valuemask |= XpmVisual;
6263 attrs.valuemask |= XpmColormap;
6264 attrs.valuemask |= XpmReturnAllocPixels;
6265 #ifdef XpmAllocCloseColors
6266 attrs.alloc_close_colors = 1;
6267 attrs.valuemask |= XpmAllocCloseColors;
6268 #else
6269 attrs.closeness = 600;
6270 attrs.valuemask |= XpmCloseness;
6271 #endif
6272
6273 /* If image specification contains symbolic color definitions, add
6274 these to `attrs'. */
6275 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
6276 if (CONSP (color_symbols))
6277 {
6278 Lisp_Object tail;
6279 XpmColorSymbol *xpm_syms;
6280 int i, size;
6281
6282 attrs.valuemask |= XpmColorSymbols;
6283
6284 /* Count number of symbols. */
6285 attrs.numsymbols = 0;
6286 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
6287 ++attrs.numsymbols;
6288
6289 /* Allocate an XpmColorSymbol array. */
6290 size = attrs.numsymbols * sizeof *xpm_syms;
6291 xpm_syms = (XpmColorSymbol *) alloca (size);
6292 bzero (xpm_syms, size);
6293 attrs.colorsymbols = xpm_syms;
6294
6295 /* Fill the color symbol array. */
6296 for (tail = color_symbols, i = 0;
6297 CONSP (tail);
6298 ++i, tail = XCDR (tail))
6299 {
6300 Lisp_Object name = XCAR (XCAR (tail));
6301 Lisp_Object color = XCDR (XCAR (tail));
6302 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
6303 strcpy (xpm_syms[i].name, SDATA (name));
6304 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
6305 strcpy (xpm_syms[i].value, SDATA (color));
6306 }
6307 }
6308
6309 /* Create a pixmap for the image, either from a file, or from a
6310 string buffer containing data in the same format as an XPM file. */
6311 BLOCK_INPUT;
6312 specified_file = image_spec_value (img->spec, QCfile, NULL);
6313 if (STRINGP (specified_file))
6314 {
6315 Lisp_Object file = x_find_image_file (specified_file);
6316 if (!STRINGP (file))
6317 {
6318 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6319 UNBLOCK_INPUT;
6320 return 0;
6321 }
6322
6323 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
6324 SDATA (file), &img->pixmap, &img->mask,
6325 &attrs);
6326 }
6327 else
6328 {
6329 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6330 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
6331 SDATA (buffer),
6332 &img->pixmap, &img->mask,
6333 &attrs);
6334 }
6335 UNBLOCK_INPUT;
6336
6337 if (rc == XpmSuccess)
6338 {
6339 /* Remember allocated colors. */
6340 img->ncolors = attrs.nalloc_pixels;
6341 img->colors = (unsigned long *) xmalloc (img->ncolors
6342 * sizeof *img->colors);
6343 for (i = 0; i < attrs.nalloc_pixels; ++i)
6344 img->colors[i] = attrs.alloc_pixels[i];
6345
6346 img->width = attrs.width;
6347 img->height = attrs.height;
6348 xassert (img->width > 0 && img->height > 0);
6349
6350 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
6351 BLOCK_INPUT;
6352 XpmFreeAttributes (&attrs);
6353 UNBLOCK_INPUT;
6354 }
6355 else
6356 {
6357 switch (rc)
6358 {
6359 case XpmOpenFailed:
6360 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6361 break;
6362
6363 case XpmFileInvalid:
6364 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6365 break;
6366
6367 case XpmNoMemory:
6368 image_error ("Out of memory (%s)", img->spec, Qnil);
6369 break;
6370
6371 case XpmColorFailed:
6372 image_error ("Color allocation error (%s)", img->spec, Qnil);
6373 break;
6374
6375 default:
6376 image_error ("Unknown error (%s)", img->spec, Qnil);
6377 break;
6378 }
6379 }
6380
6381 return rc == XpmSuccess;
6382 }
6383
6384 #endif /* HAVE_XPM != 0 */
6385
6386 \f
6387 #if 0 /* MAC_TODO : Color tables on Mac. */
6388 /***********************************************************************
6389 Color table
6390 ***********************************************************************/
6391
6392 /* An entry in the color table mapping an RGB color to a pixel color. */
6393
6394 struct ct_color
6395 {
6396 int r, g, b;
6397 unsigned long pixel;
6398
6399 /* Next in color table collision list. */
6400 struct ct_color *next;
6401 };
6402
6403 /* The bucket vector size to use. Must be prime. */
6404
6405 #define CT_SIZE 101
6406
6407 /* Value is a hash of the RGB color given by R, G, and B. */
6408
6409 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6410
6411 /* The color hash table. */
6412
6413 struct ct_color **ct_table;
6414
6415 /* Number of entries in the color table. */
6416
6417 int ct_colors_allocated;
6418
6419 /* Function prototypes. */
6420
6421 static void init_color_table P_ ((void));
6422 static void free_color_table P_ ((void));
6423 static unsigned long *colors_in_color_table P_ ((int *n));
6424 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
6425 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
6426
6427
6428 /* Initialize the color table. */
6429
6430 static void
6431 init_color_table ()
6432 {
6433 int size = CT_SIZE * sizeof (*ct_table);
6434 ct_table = (struct ct_color **) xmalloc (size);
6435 bzero (ct_table, size);
6436 ct_colors_allocated = 0;
6437 }
6438
6439
6440 /* Free memory associated with the color table. */
6441
6442 static void
6443 free_color_table ()
6444 {
6445 int i;
6446 struct ct_color *p, *next;
6447
6448 for (i = 0; i < CT_SIZE; ++i)
6449 for (p = ct_table[i]; p; p = next)
6450 {
6451 next = p->next;
6452 xfree (p);
6453 }
6454
6455 xfree (ct_table);
6456 ct_table = NULL;
6457 }
6458
6459
6460 /* Value is a pixel color for RGB color R, G, B on frame F. If an
6461 entry for that color already is in the color table, return the
6462 pixel color of that entry. Otherwise, allocate a new color for R,
6463 G, B, and make an entry in the color table. */
6464
6465 static unsigned long
6466 lookup_rgb_color (f, r, g, b)
6467 struct frame *f;
6468 int r, g, b;
6469 {
6470 unsigned hash = CT_HASH_RGB (r, g, b);
6471 int i = hash % CT_SIZE;
6472 struct ct_color *p;
6473
6474 for (p = ct_table[i]; p; p = p->next)
6475 if (p->r == r && p->g == g && p->b == b)
6476 break;
6477
6478 if (p == NULL)
6479 {
6480 COLORREF color;
6481 Colormap cmap;
6482 int rc;
6483
6484 color = RGB_TO_ULONG (r, g, b);
6485
6486 ++ct_colors_allocated;
6487
6488 p = (struct ct_color *) xmalloc (sizeof *p);
6489 p->r = r;
6490 p->g = g;
6491 p->b = b;
6492 p->pixel = color;
6493 p->next = ct_table[i];
6494 ct_table[i] = p;
6495 }
6496
6497 return p->pixel;
6498 }
6499
6500
6501 /* Look up pixel color PIXEL which is used on frame F in the color
6502 table. If not already present, allocate it. Value is PIXEL. */
6503
6504 static unsigned long
6505 lookup_pixel_color (f, pixel)
6506 struct frame *f;
6507 unsigned long pixel;
6508 {
6509 int i = pixel % CT_SIZE;
6510 struct ct_color *p;
6511
6512 for (p = ct_table[i]; p; p = p->next)
6513 if (p->pixel == pixel)
6514 break;
6515
6516 if (p == NULL)
6517 {
6518 XColor color;
6519 Colormap cmap;
6520 int rc;
6521
6522 BLOCK_INPUT;
6523
6524 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6525 color.pixel = pixel;
6526 XQueryColor (NULL, cmap, &color);
6527 rc = x_alloc_nearest_color (f, cmap, &color);
6528 UNBLOCK_INPUT;
6529
6530 if (rc)
6531 {
6532 ++ct_colors_allocated;
6533
6534 p = (struct ct_color *) xmalloc (sizeof *p);
6535 p->r = color.red;
6536 p->g = color.green;
6537 p->b = color.blue;
6538 p->pixel = pixel;
6539 p->next = ct_table[i];
6540 ct_table[i] = p;
6541 }
6542 else
6543 return FRAME_FOREGROUND_PIXEL (f);
6544 }
6545 return p->pixel;
6546 }
6547
6548
6549 /* Value is a vector of all pixel colors contained in the color table,
6550 allocated via xmalloc. Set *N to the number of colors. */
6551
6552 static unsigned long *
6553 colors_in_color_table (n)
6554 int *n;
6555 {
6556 int i, j;
6557 struct ct_color *p;
6558 unsigned long *colors;
6559
6560 if (ct_colors_allocated == 0)
6561 {
6562 *n = 0;
6563 colors = NULL;
6564 }
6565 else
6566 {
6567 colors = (unsigned long *) xmalloc (ct_colors_allocated
6568 * sizeof *colors);
6569 *n = ct_colors_allocated;
6570
6571 for (i = j = 0; i < CT_SIZE; ++i)
6572 for (p = ct_table[i]; p; p = p->next)
6573 colors[j++] = p->pixel;
6574 }
6575
6576 return colors;
6577 }
6578
6579 #endif /* MAC_TODO */
6580
6581 \f
6582 /***********************************************************************
6583 Algorithms
6584 ***********************************************************************/
6585
6586 #if 0 /* MAC_TODO : Mac versions of low level algorithms */
6587 static void x_laplace_write_row P_ ((struct frame *, long *,
6588 int, XImage *, int));
6589 static void x_laplace_read_row P_ ((struct frame *, Colormap,
6590 XColor *, int, XImage *, int));
6591
6592
6593 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
6594 frame we operate on, CMAP is the color-map in effect, and WIDTH is
6595 the width of one row in the image. */
6596
6597 static void
6598 x_laplace_read_row (f, cmap, colors, width, ximg, y)
6599 struct frame *f;
6600 Colormap cmap;
6601 XColor *colors;
6602 int width;
6603 XImage *ximg;
6604 int y;
6605 {
6606 int x;
6607
6608 for (x = 0; x < width; ++x)
6609 colors[x].pixel = XGetPixel (ximg, x, y);
6610
6611 XQueryColors (NULL, cmap, colors, width);
6612 }
6613
6614
6615 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
6616 containing the pixel colors to write. F is the frame we are
6617 working on. */
6618
6619 static void
6620 x_laplace_write_row (f, pixels, width, ximg, y)
6621 struct frame *f;
6622 long *pixels;
6623 int width;
6624 XImage *ximg;
6625 int y;
6626 {
6627 int x;
6628
6629 for (x = 0; x < width; ++x)
6630 XPutPixel (ximg, x, y, pixels[x]);
6631 }
6632 #endif /* MAC_TODO */
6633
6634 /* Transform image IMG which is used on frame F with a Laplace
6635 edge-detection algorithm. The result is an image that can be used
6636 to draw disabled buttons, for example. */
6637
6638 static void
6639 x_laplace (f, img)
6640 struct frame *f;
6641 struct image *img;
6642 {
6643 #if 0 /* MAC_TODO : Mac version */
6644 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6645 XImage *ximg, *oimg;
6646 XColor *in[3];
6647 long *out;
6648 Pixmap pixmap;
6649 int x, y, i;
6650 long pixel;
6651 int in_y, out_y, rc;
6652 int mv2 = 45000;
6653
6654 BLOCK_INPUT;
6655
6656 /* Get the X image IMG->pixmap. */
6657 ximg = XGetImage (NULL, img->pixmap,
6658 0, 0, img->width, img->height, ~0, ZPixmap);
6659
6660 /* Allocate 3 input rows, and one output row of colors. */
6661 for (i = 0; i < 3; ++i)
6662 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
6663 out = (long *) alloca (img->width * sizeof (long));
6664
6665 /* Create an X image for output. */
6666 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6667 &oimg, &pixmap);
6668
6669 /* Fill first two rows. */
6670 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
6671 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
6672 in_y = 2;
6673
6674 /* Write first row, all zeros. */
6675 init_color_table ();
6676 pixel = lookup_rgb_color (f, 0, 0, 0);
6677 for (x = 0; x < img->width; ++x)
6678 out[x] = pixel;
6679 x_laplace_write_row (f, out, img->width, oimg, 0);
6680 out_y = 1;
6681
6682 for (y = 2; y < img->height; ++y)
6683 {
6684 int rowa = y % 3;
6685 int rowb = (y + 2) % 3;
6686
6687 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
6688
6689 for (x = 0; x < img->width - 2; ++x)
6690 {
6691 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
6692 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
6693 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
6694
6695 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
6696 b & 0xffff);
6697 }
6698
6699 x_laplace_write_row (f, out, img->width, oimg, out_y++);
6700 }
6701
6702 /* Write last line, all zeros. */
6703 for (x = 0; x < img->width; ++x)
6704 out[x] = pixel;
6705 x_laplace_write_row (f, out, img->width, oimg, out_y);
6706
6707 /* Free the input image, and free resources of IMG. */
6708 XDestroyImage (ximg);
6709 x_clear_image (f, img);
6710
6711 /* Put the output image into pixmap, and destroy it. */
6712 x_put_x_image (f, oimg, pixmap, img->width, img->height);
6713 x_destroy_x_image (oimg);
6714
6715 /* Remember new pixmap and colors in IMG. */
6716 img->pixmap = pixmap;
6717 img->colors = colors_in_color_table (&img->ncolors);
6718 free_color_table ();
6719
6720 UNBLOCK_INPUT;
6721 #endif /* MAC_TODO */
6722 }
6723
6724
6725 /* Build a mask for image IMG which is used on frame F. FILE is the
6726 name of an image file, for error messages. HOW determines how to
6727 determine the background color of IMG. If it is a list '(R G B)',
6728 with R, G, and B being integers >= 0, take that as the color of the
6729 background. Otherwise, determine the background color of IMG
6730 heuristically. Value is non-zero if successful. */
6731
6732 static int
6733 x_build_heuristic_mask (f, img, how)
6734 struct frame *f;
6735 struct image *img;
6736 Lisp_Object how;
6737 {
6738 #if 0 /* MAC_TODO : Mac version */
6739 Display *dpy = FRAME_W32_DISPLAY (f);
6740 XImage *ximg, *mask_img;
6741 int x, y, rc, look_at_corners_p;
6742 unsigned long bg;
6743
6744 BLOCK_INPUT;
6745
6746 /* Create an image and pixmap serving as mask. */
6747 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
6748 &mask_img, &img->mask);
6749 if (!rc)
6750 {
6751 UNBLOCK_INPUT;
6752 return 0;
6753 }
6754
6755 /* Get the X image of IMG->pixmap. */
6756 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
6757 ~0, ZPixmap);
6758
6759 /* Determine the background color of ximg. If HOW is `(R G B)'
6760 take that as color. Otherwise, try to determine the color
6761 heuristically. */
6762 look_at_corners_p = 1;
6763
6764 if (CONSP (how))
6765 {
6766 int rgb[3], i = 0;
6767
6768 while (i < 3
6769 && CONSP (how)
6770 && NATNUMP (XCAR (how)))
6771 {
6772 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
6773 how = XCDR (how);
6774 }
6775
6776 if (i == 3 && NILP (how))
6777 {
6778 char color_name[30];
6779 XColor exact, color;
6780 Colormap cmap;
6781
6782 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
6783
6784 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6785 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
6786 {
6787 bg = color.pixel;
6788 look_at_corners_p = 0;
6789 }
6790 }
6791 }
6792
6793 if (look_at_corners_p)
6794 {
6795 unsigned long corners[4];
6796 int i, best_count;
6797
6798 /* Get the colors at the corners of ximg. */
6799 corners[0] = XGetPixel (ximg, 0, 0);
6800 corners[1] = XGetPixel (ximg, img->width - 1, 0);
6801 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
6802 corners[3] = XGetPixel (ximg, 0, img->height - 1);
6803
6804 /* Choose the most frequently found color as background. */
6805 for (i = best_count = 0; i < 4; ++i)
6806 {
6807 int j, n;
6808
6809 for (j = n = 0; j < 4; ++j)
6810 if (corners[i] == corners[j])
6811 ++n;
6812
6813 if (n > best_count)
6814 bg = corners[i], best_count = n;
6815 }
6816 }
6817
6818 /* Set all bits in mask_img to 1 whose color in ximg is different
6819 from the background color bg. */
6820 for (y = 0; y < img->height; ++y)
6821 for (x = 0; x < img->width; ++x)
6822 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
6823
6824 /* Put mask_img into img->mask. */
6825 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
6826 x_destroy_x_image (mask_img);
6827 XDestroyImage (ximg);
6828
6829 UNBLOCK_INPUT;
6830 #endif /* MAC_TODO */
6831
6832 return 1;
6833 }
6834
6835
6836 \f
6837 /***********************************************************************
6838 PBM (mono, gray, color)
6839 ***********************************************************************/
6840 #ifdef HAVE_PBM
6841
6842 static int pbm_image_p P_ ((Lisp_Object object));
6843 static int pbm_load P_ ((struct frame *f, struct image *img));
6844 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
6845
6846 /* The symbol `pbm' identifying images of this type. */
6847
6848 Lisp_Object Qpbm;
6849
6850 /* Indices of image specification fields in gs_format, below. */
6851
6852 enum pbm_keyword_index
6853 {
6854 PBM_TYPE,
6855 PBM_FILE,
6856 PBM_DATA,
6857 PBM_ASCENT,
6858 PBM_MARGIN,
6859 PBM_RELIEF,
6860 PBM_ALGORITHM,
6861 PBM_HEURISTIC_MASK,
6862 PBM_LAST
6863 };
6864
6865 /* Vector of image_keyword structures describing the format
6866 of valid user-defined image specifications. */
6867
6868 static struct image_keyword pbm_format[PBM_LAST] =
6869 {
6870 {":type", IMAGE_SYMBOL_VALUE, 1},
6871 {":file", IMAGE_STRING_VALUE, 0},
6872 {":data", IMAGE_STRING_VALUE, 0},
6873 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6874 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6875 {":relief", IMAGE_INTEGER_VALUE, 0},
6876 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6877 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6878 };
6879
6880 /* Structure describing the image type `pbm'. */
6881
6882 static struct image_type pbm_type =
6883 {
6884 &Qpbm,
6885 pbm_image_p,
6886 pbm_load,
6887 x_clear_image,
6888 NULL
6889 };
6890
6891
6892 /* Return non-zero if OBJECT is a valid PBM image specification. */
6893
6894 static int
6895 pbm_image_p (object)
6896 Lisp_Object object;
6897 {
6898 struct image_keyword fmt[PBM_LAST];
6899
6900 bcopy (pbm_format, fmt, sizeof fmt);
6901
6902 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
6903 || (fmt[PBM_ASCENT].count
6904 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
6905 return 0;
6906
6907 /* Must specify either :data or :file. */
6908 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
6909 }
6910
6911
6912 /* Scan a decimal number from *S and return it. Advance *S while
6913 reading the number. END is the end of the string. Value is -1 at
6914 end of input. */
6915
6916 static int
6917 pbm_scan_number (s, end)
6918 unsigned char **s, *end;
6919 {
6920 int c, val = -1;
6921
6922 while (*s < end)
6923 {
6924 /* Skip white-space. */
6925 while (*s < end && (c = *(*s)++, isspace (c)))
6926 ;
6927
6928 if (c == '#')
6929 {
6930 /* Skip comment to end of line. */
6931 while (*s < end && (c = *(*s)++, c != '\n'))
6932 ;
6933 }
6934 else if (isdigit (c))
6935 {
6936 /* Read decimal number. */
6937 val = c - '0';
6938 while (*s < end && (c = *(*s)++, isdigit (c)))
6939 val = 10 * val + c - '0';
6940 break;
6941 }
6942 else
6943 break;
6944 }
6945
6946 return val;
6947 }
6948
6949
6950 /* Read FILE into memory. Value is a pointer to a buffer allocated
6951 with xmalloc holding FILE's contents. Value is null if an error
6952 occurred. *SIZE is set to the size of the file. */
6953
6954 static char *
6955 pbm_read_file (file, size)
6956 Lisp_Object file;
6957 int *size;
6958 {
6959 FILE *fp = NULL;
6960 char *buf = NULL;
6961 struct stat st;
6962
6963 if (stat (SDATA (file), &st) == 0
6964 && (fp = fopen (SDATA (file), "r")) != NULL
6965 && (buf = (char *) xmalloc (st.st_size),
6966 fread (buf, 1, st.st_size, fp) == st.st_size))
6967 {
6968 *size = st.st_size;
6969 fclose (fp);
6970 }
6971 else
6972 {
6973 if (fp)
6974 fclose (fp);
6975 if (buf)
6976 {
6977 xfree (buf);
6978 buf = NULL;
6979 }
6980 }
6981
6982 return buf;
6983 }
6984
6985
6986 /* Load PBM image IMG for use on frame F. */
6987
6988 static int
6989 pbm_load (f, img)
6990 struct frame *f;
6991 struct image *img;
6992 {
6993 int raw_p, x, y;
6994 int width, height, max_color_idx = 0;
6995 XImage *ximg;
6996 Lisp_Object file, specified_file;
6997 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
6998 struct gcpro gcpro1;
6999 unsigned char *contents = NULL;
7000 unsigned char *end, *p;
7001 int size;
7002
7003 specified_file = image_spec_value (img->spec, QCfile, NULL);
7004 file = Qnil;
7005 GCPRO1 (file);
7006
7007 if (STRINGP (specified_file))
7008 {
7009 file = x_find_image_file (specified_file);
7010 if (!STRINGP (file))
7011 {
7012 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7013 UNGCPRO;
7014 return 0;
7015 }
7016
7017 contents = pbm_read_file (file, &size);
7018 if (contents == NULL)
7019 {
7020 image_error ("Error reading `%s'", file, Qnil);
7021 UNGCPRO;
7022 return 0;
7023 }
7024
7025 p = contents;
7026 end = contents + size;
7027 }
7028 else
7029 {
7030 Lisp_Object data;
7031 data = image_spec_value (img->spec, QCdata, NULL);
7032 p = SDATA (data);
7033 end = p + SBYTES (data);
7034 }
7035
7036 /* Check magic number. */
7037 if (end - p < 2 || *p++ != 'P')
7038 {
7039 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
7040 error:
7041 xfree (contents);
7042 UNGCPRO;
7043 return 0;
7044 }
7045
7046 switch (*p++)
7047 {
7048 case '1':
7049 raw_p = 0, type = PBM_MONO;
7050 break;
7051
7052 case '2':
7053 raw_p = 0, type = PBM_GRAY;
7054 break;
7055
7056 case '3':
7057 raw_p = 0, type = PBM_COLOR;
7058 break;
7059
7060 case '4':
7061 raw_p = 1, type = PBM_MONO;
7062 break;
7063
7064 case '5':
7065 raw_p = 1, type = PBM_GRAY;
7066 break;
7067
7068 case '6':
7069 raw_p = 1, type = PBM_COLOR;
7070 break;
7071
7072 default:
7073 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
7074 goto error;
7075 }
7076
7077 /* Read width, height, maximum color-component. Characters
7078 starting with `#' up to the end of a line are ignored. */
7079 width = pbm_scan_number (&p, end);
7080 height = pbm_scan_number (&p, end);
7081
7082 if (type != PBM_MONO)
7083 {
7084 max_color_idx = pbm_scan_number (&p, end);
7085 if (raw_p && max_color_idx > 255)
7086 max_color_idx = 255;
7087 }
7088
7089 if (width < 0
7090 || height < 0
7091 || (type != PBM_MONO && max_color_idx < 0))
7092 goto error;
7093
7094 BLOCK_INPUT;
7095 if (!x_create_x_image_and_pixmap (f, width, height, 0,
7096 &ximg, &img->pixmap))
7097 {
7098 UNBLOCK_INPUT;
7099 goto error;
7100 }
7101
7102 /* Initialize the color hash table. */
7103 init_color_table ();
7104
7105 if (type == PBM_MONO)
7106 {
7107 int c = 0, g;
7108
7109 for (y = 0; y < height; ++y)
7110 for (x = 0; x < width; ++x)
7111 {
7112 if (raw_p)
7113 {
7114 if ((x & 7) == 0)
7115 c = *p++;
7116 g = c & 0x80;
7117 c <<= 1;
7118 }
7119 else
7120 g = pbm_scan_number (&p, end);
7121
7122 XPutPixel (ximg, x, y, (g
7123 ? FRAME_FOREGROUND_PIXEL (f)
7124 : FRAME_BACKGROUND_PIXEL (f)));
7125 }
7126 }
7127 else
7128 {
7129 for (y = 0; y < height; ++y)
7130 for (x = 0; x < width; ++x)
7131 {
7132 int r, g, b;
7133
7134 if (type == PBM_GRAY)
7135 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
7136 else if (raw_p)
7137 {
7138 r = *p++;
7139 g = *p++;
7140 b = *p++;
7141 }
7142 else
7143 {
7144 r = pbm_scan_number (&p, end);
7145 g = pbm_scan_number (&p, end);
7146 b = pbm_scan_number (&p, end);
7147 }
7148
7149 if (r < 0 || g < 0 || b < 0)
7150 {
7151 xfree (ximg->data);
7152 ximg->data = NULL;
7153 XDestroyImage (ximg);
7154 UNBLOCK_INPUT;
7155 image_error ("Invalid pixel value in image `%s'",
7156 img->spec, Qnil);
7157 goto error;
7158 }
7159
7160 /* RGB values are now in the range 0..max_color_idx.
7161 Scale this to the range 0..0xffff supported by X. */
7162 r = (double) r * 65535 / max_color_idx;
7163 g = (double) g * 65535 / max_color_idx;
7164 b = (double) b * 65535 / max_color_idx;
7165 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7166 }
7167 }
7168
7169 /* Store in IMG->colors the colors allocated for the image, and
7170 free the color table. */
7171 img->colors = colors_in_color_table (&img->ncolors);
7172 free_color_table ();
7173
7174 /* Put the image into a pixmap. */
7175 x_put_x_image (f, ximg, img->pixmap, width, height);
7176 x_destroy_x_image (ximg);
7177 UNBLOCK_INPUT;
7178
7179 img->width = width;
7180 img->height = height;
7181
7182 UNGCPRO;
7183 xfree (contents);
7184 return 1;
7185 }
7186 #endif /* HAVE_PBM */
7187
7188 \f
7189 /***********************************************************************
7190 PNG
7191 ***********************************************************************/
7192
7193 #if HAVE_PNG
7194
7195 #include <png.h>
7196
7197 /* Function prototypes. */
7198
7199 static int png_image_p P_ ((Lisp_Object object));
7200 static int png_load P_ ((struct frame *f, struct image *img));
7201
7202 /* The symbol `png' identifying images of this type. */
7203
7204 Lisp_Object Qpng;
7205
7206 /* Indices of image specification fields in png_format, below. */
7207
7208 enum png_keyword_index
7209 {
7210 PNG_TYPE,
7211 PNG_DATA,
7212 PNG_FILE,
7213 PNG_ASCENT,
7214 PNG_MARGIN,
7215 PNG_RELIEF,
7216 PNG_ALGORITHM,
7217 PNG_HEURISTIC_MASK,
7218 PNG_LAST
7219 };
7220
7221 /* Vector of image_keyword structures describing the format
7222 of valid user-defined image specifications. */
7223
7224 static struct image_keyword png_format[PNG_LAST] =
7225 {
7226 {":type", IMAGE_SYMBOL_VALUE, 1},
7227 {":data", IMAGE_STRING_VALUE, 0},
7228 {":file", IMAGE_STRING_VALUE, 0},
7229 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7230 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7231 {":relief", IMAGE_INTEGER_VALUE, 0},
7232 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7233 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7234 };
7235
7236 /* Structure describing the image type `png'. */
7237
7238 static struct image_type png_type =
7239 {
7240 &Qpng,
7241 png_image_p,
7242 png_load,
7243 x_clear_image,
7244 NULL
7245 };
7246
7247
7248 /* Return non-zero if OBJECT is a valid PNG image specification. */
7249
7250 static int
7251 png_image_p (object)
7252 Lisp_Object object;
7253 {
7254 struct image_keyword fmt[PNG_LAST];
7255 bcopy (png_format, fmt, sizeof fmt);
7256
7257 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
7258 || (fmt[PNG_ASCENT].count
7259 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
7260 return 0;
7261
7262 /* Must specify either the :data or :file keyword. */
7263 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
7264 }
7265
7266
7267 /* Error and warning handlers installed when the PNG library
7268 is initialized. */
7269
7270 static void
7271 my_png_error (png_ptr, msg)
7272 png_struct *png_ptr;
7273 char *msg;
7274 {
7275 xassert (png_ptr != NULL);
7276 image_error ("PNG error: %s", build_string (msg), Qnil);
7277 longjmp (png_ptr->jmpbuf, 1);
7278 }
7279
7280
7281 static void
7282 my_png_warning (png_ptr, msg)
7283 png_struct *png_ptr;
7284 char *msg;
7285 {
7286 xassert (png_ptr != NULL);
7287 image_error ("PNG warning: %s", build_string (msg), Qnil);
7288 }
7289
7290 /* Memory source for PNG decoding. */
7291
7292 struct png_memory_storage
7293 {
7294 unsigned char *bytes; /* The data */
7295 size_t len; /* How big is it? */
7296 int index; /* Where are we? */
7297 };
7298
7299
7300 /* Function set as reader function when reading PNG image from memory.
7301 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
7302 bytes from the input to DATA. */
7303
7304 static void
7305 png_read_from_memory (png_ptr, data, length)
7306 png_structp png_ptr;
7307 png_bytep data;
7308 png_size_t length;
7309 {
7310 struct png_memory_storage *tbr
7311 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
7312
7313 if (length > tbr->len - tbr->index)
7314 png_error (png_ptr, "Read error");
7315
7316 bcopy (tbr->bytes + tbr->index, data, length);
7317 tbr->index = tbr->index + length;
7318 }
7319
7320 /* Load PNG image IMG for use on frame F. Value is non-zero if
7321 successful. */
7322
7323 static int
7324 png_load (f, img)
7325 struct frame *f;
7326 struct image *img;
7327 {
7328 Lisp_Object file, specified_file;
7329 Lisp_Object specified_data;
7330 int x, y, i;
7331 XImage *ximg, *mask_img = NULL;
7332 struct gcpro gcpro1;
7333 png_struct *png_ptr = NULL;
7334 png_info *info_ptr = NULL, *end_info = NULL;
7335 FILE *fp = NULL;
7336 png_byte sig[8];
7337 png_byte *pixels = NULL;
7338 png_byte **rows = NULL;
7339 png_uint_32 width, height;
7340 int bit_depth, color_type, interlace_type;
7341 png_byte channels;
7342 png_uint_32 row_bytes;
7343 int transparent_p;
7344 char *gamma_str;
7345 double screen_gamma, image_gamma;
7346 int intent;
7347 struct png_memory_storage tbr; /* Data to be read */
7348
7349 /* Find out what file to load. */
7350 specified_file = image_spec_value (img->spec, QCfile, NULL);
7351 specified_data = image_spec_value (img->spec, QCdata, NULL);
7352 file = Qnil;
7353 GCPRO1 (file);
7354
7355 if (NILP (specified_data))
7356 {
7357 file = x_find_image_file (specified_file);
7358 if (!STRINGP (file))
7359 {
7360 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7361 UNGCPRO;
7362 return 0;
7363 }
7364
7365 /* Open the image file. */
7366 fp = fopen (SDATA (file), "rb");
7367 if (!fp)
7368 {
7369 image_error ("Cannot open image file `%s'", file, Qnil);
7370 UNGCPRO;
7371 fclose (fp);
7372 return 0;
7373 }
7374
7375 /* Check PNG signature. */
7376 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7377 || !png_check_sig (sig, sizeof sig))
7378 {
7379 image_error ("Not a PNG file:` %s'", file, Qnil);
7380 UNGCPRO;
7381 fclose (fp);
7382 return 0;
7383 }
7384 }
7385 else
7386 {
7387 /* Read from memory. */
7388 tbr.bytes = SDATA (specified_data);
7389 tbr.len = SBYTES (specified_data);
7390 tbr.index = 0;
7391
7392 /* Check PNG signature. */
7393 if (tbr.len < sizeof sig
7394 || !png_check_sig (tbr.bytes, sizeof sig))
7395 {
7396 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
7397 UNGCPRO;
7398 return 0;
7399 }
7400
7401 /* Need to skip past the signature. */
7402 tbr.bytes += sizeof (sig);
7403 }
7404
7405 /* Initialize read and info structs for PNG lib. */
7406 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
7407 my_png_error, my_png_warning);
7408 if (!png_ptr)
7409 {
7410 if (fp) fclose (fp);
7411 UNGCPRO;
7412 return 0;
7413 }
7414
7415 info_ptr = png_create_info_struct (png_ptr);
7416 if (!info_ptr)
7417 {
7418 png_destroy_read_struct (&png_ptr, NULL, NULL);
7419 if (fp) fclose (fp);
7420 UNGCPRO;
7421 return 0;
7422 }
7423
7424 end_info = png_create_info_struct (png_ptr);
7425 if (!end_info)
7426 {
7427 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
7428 if (fp) fclose (fp);
7429 UNGCPRO;
7430 return 0;
7431 }
7432
7433 /* Set error jump-back. We come back here when the PNG library
7434 detects an error. */
7435 if (setjmp (png_ptr->jmpbuf))
7436 {
7437 error:
7438 if (png_ptr)
7439 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7440 xfree (pixels);
7441 xfree (rows);
7442 if (fp) fclose (fp);
7443 UNGCPRO;
7444 return 0;
7445 }
7446
7447 /* Read image info. */
7448 if (!NILP (specified_data))
7449 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
7450 else
7451 png_init_io (png_ptr, fp);
7452
7453 png_set_sig_bytes (png_ptr, sizeof sig);
7454 png_read_info (png_ptr, info_ptr);
7455 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
7456 &interlace_type, NULL, NULL);
7457
7458 /* If image contains simply transparency data, we prefer to
7459 construct a clipping mask. */
7460 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7461 transparent_p = 1;
7462 else
7463 transparent_p = 0;
7464
7465 /* This function is easier to write if we only have to handle
7466 one data format: RGB or RGBA with 8 bits per channel. Let's
7467 transform other formats into that format. */
7468
7469 /* Strip more than 8 bits per channel. */
7470 if (bit_depth == 16)
7471 png_set_strip_16 (png_ptr);
7472
7473 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7474 if available. */
7475 png_set_expand (png_ptr);
7476
7477 /* Convert grayscale images to RGB. */
7478 if (color_type == PNG_COLOR_TYPE_GRAY
7479 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7480 png_set_gray_to_rgb (png_ptr);
7481
7482 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
7483 gamma_str = getenv ("SCREEN_GAMMA");
7484 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
7485
7486 /* Tell the PNG lib to handle gamma correction for us. */
7487
7488 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
7489 if (png_get_sRGB (png_ptr, info_ptr, &intent))
7490 /* There is a special chunk in the image specifying the gamma. */
7491 png_set_sRGB (png_ptr, info_ptr, intent);
7492 else
7493 #endif
7494 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
7495 /* Image contains gamma information. */
7496 png_set_gamma (png_ptr, screen_gamma, image_gamma);
7497 else
7498 /* Use a default of 0.5 for the image gamma. */
7499 png_set_gamma (png_ptr, screen_gamma, 0.5);
7500
7501 /* Handle alpha channel by combining the image with a background
7502 color. Do this only if a real alpha channel is supplied. For
7503 simple transparency, we prefer a clipping mask. */
7504 if (!transparent_p)
7505 {
7506 png_color_16 *image_background;
7507
7508 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
7509 /* Image contains a background color with which to
7510 combine the image. */
7511 png_set_background (png_ptr, image_background,
7512 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7513 else
7514 {
7515 /* Image does not contain a background color with which
7516 to combine the image data via an alpha channel. Use
7517 the frame's background instead. */
7518 XColor color;
7519 Colormap cmap;
7520 png_color_16 frame_background;
7521
7522 BLOCK_INPUT;
7523 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
7524 color.pixel = FRAME_BACKGROUND_PIXEL (f);
7525 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
7526 UNBLOCK_INPUT;
7527
7528 bzero (&frame_background, sizeof frame_background);
7529 frame_background.red = color.red;
7530 frame_background.green = color.green;
7531 frame_background.blue = color.blue;
7532
7533 png_set_background (png_ptr, &frame_background,
7534 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7535 }
7536 }
7537
7538 /* Update info structure. */
7539 png_read_update_info (png_ptr, info_ptr);
7540
7541 /* Get number of channels. Valid values are 1 for grayscale images
7542 and images with a palette, 2 for grayscale images with transparency
7543 information (alpha channel), 3 for RGB images, and 4 for RGB
7544 images with alpha channel, i.e. RGBA. If conversions above were
7545 sufficient we should only have 3 or 4 channels here. */
7546 channels = png_get_channels (png_ptr, info_ptr);
7547 xassert (channels == 3 || channels == 4);
7548
7549 /* Number of bytes needed for one row of the image. */
7550 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
7551
7552 /* Allocate memory for the image. */
7553 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
7554 rows = (png_byte **) xmalloc (height * sizeof *rows);
7555 for (i = 0; i < height; ++i)
7556 rows[i] = pixels + i * row_bytes;
7557
7558 /* Read the entire image. */
7559 png_read_image (png_ptr, rows);
7560 png_read_end (png_ptr, info_ptr);
7561 if (fp)
7562 {
7563 fclose (fp);
7564 fp = NULL;
7565 }
7566
7567 BLOCK_INPUT;
7568
7569 /* Create the X image and pixmap. */
7570 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7571 &img->pixmap))
7572 {
7573 UNBLOCK_INPUT;
7574 goto error;
7575 }
7576
7577 /* Create an image and pixmap serving as mask if the PNG image
7578 contains an alpha channel. */
7579 if (channels == 4
7580 && !transparent_p
7581 && !x_create_x_image_and_pixmap (f, width, height, 1,
7582 &mask_img, &img->mask))
7583 {
7584 x_destroy_x_image (ximg);
7585 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
7586 img->pixmap = 0;
7587 UNBLOCK_INPUT;
7588 goto error;
7589 }
7590
7591 /* Fill the X image and mask from PNG data. */
7592 init_color_table ();
7593
7594 for (y = 0; y < height; ++y)
7595 {
7596 png_byte *p = rows[y];
7597
7598 for (x = 0; x < width; ++x)
7599 {
7600 unsigned r, g, b;
7601
7602 r = *p++ << 8;
7603 g = *p++ << 8;
7604 b = *p++ << 8;
7605 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7606
7607 /* An alpha channel, aka mask channel, associates variable
7608 transparency with an image. Where other image formats
7609 support binary transparency---fully transparent or fully
7610 opaque---PNG allows up to 254 levels of partial transparency.
7611 The PNG library implements partial transparency by combining
7612 the image with a specified background color.
7613
7614 I'm not sure how to handle this here nicely: because the
7615 background on which the image is displayed may change, for
7616 real alpha channel support, it would be necessary to create
7617 a new image for each possible background.
7618
7619 What I'm doing now is that a mask is created if we have
7620 boolean transparency information. Otherwise I'm using
7621 the frame's background color to combine the image with. */
7622
7623 if (channels == 4)
7624 {
7625 if (mask_img)
7626 XPutPixel (mask_img, x, y, *p > 0);
7627 ++p;
7628 }
7629 }
7630 }
7631
7632 /* Remember colors allocated for this image. */
7633 img->colors = colors_in_color_table (&img->ncolors);
7634 free_color_table ();
7635
7636 /* Clean up. */
7637 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7638 xfree (rows);
7639 xfree (pixels);
7640
7641 img->width = width;
7642 img->height = height;
7643
7644 /* Put the image into the pixmap, then free the X image and its buffer. */
7645 x_put_x_image (f, ximg, img->pixmap, width, height);
7646 x_destroy_x_image (ximg);
7647
7648 /* Same for the mask. */
7649 if (mask_img)
7650 {
7651 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7652 x_destroy_x_image (mask_img);
7653 }
7654
7655 UNBLOCK_INPUT;
7656 UNGCPRO;
7657 return 1;
7658 }
7659
7660 #endif /* HAVE_PNG != 0 */
7661
7662
7663 \f
7664 /***********************************************************************
7665 JPEG
7666 ***********************************************************************/
7667
7668 #if HAVE_JPEG
7669
7670 /* Work around a warning about HAVE_STDLIB_H being redefined in
7671 jconfig.h. */
7672 #ifdef HAVE_STDLIB_H
7673 #define HAVE_STDLIB_H_1
7674 #undef HAVE_STDLIB_H
7675 #endif /* HAVE_STLIB_H */
7676
7677 #include <jpeglib.h>
7678 #include <jerror.h>
7679 #include <setjmp.h>
7680
7681 #ifdef HAVE_STLIB_H_1
7682 #define HAVE_STDLIB_H 1
7683 #endif
7684
7685 static int jpeg_image_p P_ ((Lisp_Object object));
7686 static int jpeg_load P_ ((struct frame *f, struct image *img));
7687
7688 /* The symbol `jpeg' identifying images of this type. */
7689
7690 Lisp_Object Qjpeg;
7691
7692 /* Indices of image specification fields in gs_format, below. */
7693
7694 enum jpeg_keyword_index
7695 {
7696 JPEG_TYPE,
7697 JPEG_DATA,
7698 JPEG_FILE,
7699 JPEG_ASCENT,
7700 JPEG_MARGIN,
7701 JPEG_RELIEF,
7702 JPEG_ALGORITHM,
7703 JPEG_HEURISTIC_MASK,
7704 JPEG_LAST
7705 };
7706
7707 /* Vector of image_keyword structures describing the format
7708 of valid user-defined image specifications. */
7709
7710 static struct image_keyword jpeg_format[JPEG_LAST] =
7711 {
7712 {":type", IMAGE_SYMBOL_VALUE, 1},
7713 {":data", IMAGE_STRING_VALUE, 0},
7714 {":file", IMAGE_STRING_VALUE, 0},
7715 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7716 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7717 {":relief", IMAGE_INTEGER_VALUE, 0},
7718 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7719 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7720 };
7721
7722 /* Structure describing the image type `jpeg'. */
7723
7724 static struct image_type jpeg_type =
7725 {
7726 &Qjpeg,
7727 jpeg_image_p,
7728 jpeg_load,
7729 x_clear_image,
7730 NULL
7731 };
7732
7733
7734 /* Return non-zero if OBJECT is a valid JPEG image specification. */
7735
7736 static int
7737 jpeg_image_p (object)
7738 Lisp_Object object;
7739 {
7740 struct image_keyword fmt[JPEG_LAST];
7741
7742 bcopy (jpeg_format, fmt, sizeof fmt);
7743
7744 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
7745 || (fmt[JPEG_ASCENT].count
7746 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
7747 return 0;
7748
7749 /* Must specify either the :data or :file keyword. */
7750 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7751 }
7752
7753
7754 struct my_jpeg_error_mgr
7755 {
7756 struct jpeg_error_mgr pub;
7757 jmp_buf setjmp_buffer;
7758 };
7759
7760 static void
7761 my_error_exit (cinfo)
7762 j_common_ptr cinfo;
7763 {
7764 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7765 longjmp (mgr->setjmp_buffer, 1);
7766 }
7767
7768 /* Init source method for JPEG data source manager. Called by
7769 jpeg_read_header() before any data is actually read. See
7770 libjpeg.doc from the JPEG lib distribution. */
7771
7772 static void
7773 our_init_source (cinfo)
7774 j_decompress_ptr cinfo;
7775 {
7776 }
7777
7778
7779 /* Fill input buffer method for JPEG data source manager. Called
7780 whenever more data is needed. We read the whole image in one step,
7781 so this only adds a fake end of input marker at the end. */
7782
7783 static boolean
7784 our_fill_input_buffer (cinfo)
7785 j_decompress_ptr cinfo;
7786 {
7787 /* Insert a fake EOI marker. */
7788 struct jpeg_source_mgr *src = cinfo->src;
7789 static JOCTET buffer[2];
7790
7791 buffer[0] = (JOCTET) 0xFF;
7792 buffer[1] = (JOCTET) JPEG_EOI;
7793
7794 src->next_input_byte = buffer;
7795 src->bytes_in_buffer = 2;
7796 return TRUE;
7797 }
7798
7799
7800 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
7801 is the JPEG data source manager. */
7802
7803 static void
7804 our_skip_input_data (cinfo, num_bytes)
7805 j_decompress_ptr cinfo;
7806 long num_bytes;
7807 {
7808 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
7809
7810 if (src)
7811 {
7812 if (num_bytes > src->bytes_in_buffer)
7813 ERREXIT (cinfo, JERR_INPUT_EOF);
7814
7815 src->bytes_in_buffer -= num_bytes;
7816 src->next_input_byte += num_bytes;
7817 }
7818 }
7819
7820
7821 /* Method to terminate data source. Called by
7822 jpeg_finish_decompress() after all data has been processed. */
7823
7824 static void
7825 our_term_source (cinfo)
7826 j_decompress_ptr cinfo;
7827 {
7828 }
7829
7830
7831 /* Set up the JPEG lib for reading an image from DATA which contains
7832 LEN bytes. CINFO is the decompression info structure created for
7833 reading the image. */
7834
7835 static void
7836 jpeg_memory_src (cinfo, data, len)
7837 j_decompress_ptr cinfo;
7838 JOCTET *data;
7839 unsigned int len;
7840 {
7841 struct jpeg_source_mgr *src;
7842
7843 if (cinfo->src == NULL)
7844 {
7845 /* First time for this JPEG object? */
7846 cinfo->src = (struct jpeg_source_mgr *)
7847 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
7848 sizeof (struct jpeg_source_mgr));
7849 src = (struct jpeg_source_mgr *) cinfo->src;
7850 src->next_input_byte = data;
7851 }
7852
7853 src = (struct jpeg_source_mgr *) cinfo->src;
7854 src->init_source = our_init_source;
7855 src->fill_input_buffer = our_fill_input_buffer;
7856 src->skip_input_data = our_skip_input_data;
7857 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
7858 src->term_source = our_term_source;
7859 src->bytes_in_buffer = len;
7860 src->next_input_byte = data;
7861 }
7862
7863
7864 /* Load image IMG for use on frame F. Patterned after example.c
7865 from the JPEG lib. */
7866
7867 static int
7868 jpeg_load (f, img)
7869 struct frame *f;
7870 struct image *img;
7871 {
7872 struct jpeg_decompress_struct cinfo;
7873 struct my_jpeg_error_mgr mgr;
7874 Lisp_Object file, specified_file;
7875 Lisp_Object specified_data;
7876 FILE *fp = NULL;
7877 JSAMPARRAY buffer;
7878 int row_stride, x, y;
7879 XImage *ximg = NULL;
7880 int rc;
7881 unsigned long *colors;
7882 int width, height;
7883 struct gcpro gcpro1;
7884
7885 /* Open the JPEG file. */
7886 specified_file = image_spec_value (img->spec, QCfile, NULL);
7887 specified_data = image_spec_value (img->spec, QCdata, NULL);
7888 file = Qnil;
7889 GCPRO1 (file);
7890
7891 if (NILP (specified_data))
7892 {
7893 file = x_find_image_file (specified_file);
7894 if (!STRINGP (file))
7895 {
7896 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7897 UNGCPRO;
7898 return 0;
7899 }
7900
7901 fp = fopen (SDATA (file), "r");
7902 if (fp == NULL)
7903 {
7904 image_error ("Cannot open `%s'", file, Qnil);
7905 UNGCPRO;
7906 return 0;
7907 }
7908 }
7909
7910 /* Customize libjpeg's error handling to call my_error_exit when an
7911 error is detected. This function will perform a longjmp. */
7912 mgr.pub.error_exit = my_error_exit;
7913 cinfo.err = jpeg_std_error (&mgr.pub);
7914
7915 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
7916 {
7917 if (rc == 1)
7918 {
7919 /* Called from my_error_exit. Display a JPEG error. */
7920 char buffer[JMSG_LENGTH_MAX];
7921 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
7922 image_error ("Error reading JPEG image `%s': %s", img->spec,
7923 build_string (buffer));
7924 }
7925
7926 /* Close the input file and destroy the JPEG object. */
7927 if (fp)
7928 fclose (fp);
7929 jpeg_destroy_decompress (&cinfo);
7930
7931 BLOCK_INPUT;
7932
7933 /* If we already have an XImage, free that. */
7934 x_destroy_x_image (ximg);
7935
7936 /* Free pixmap and colors. */
7937 x_clear_image (f, img);
7938
7939 UNBLOCK_INPUT;
7940 UNGCPRO;
7941 return 0;
7942 }
7943
7944 /* Create the JPEG decompression object. Let it read from fp.
7945 Read the JPEG image header. */
7946 jpeg_create_decompress (&cinfo);
7947
7948 if (NILP (specified_data))
7949 jpeg_stdio_src (&cinfo, fp);
7950 else
7951 jpeg_memory_src (&cinfo, SDATA (specified_data),
7952 SBYTES (specified_data));
7953
7954 jpeg_read_header (&cinfo, TRUE);
7955
7956 /* Customize decompression so that color quantization will be used.
7957 Start decompression. */
7958 cinfo.quantize_colors = TRUE;
7959 jpeg_start_decompress (&cinfo);
7960 width = img->width = cinfo.output_width;
7961 height = img->height = cinfo.output_height;
7962
7963 BLOCK_INPUT;
7964
7965 /* Create X image and pixmap. */
7966 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7967 &img->pixmap))
7968 {
7969 UNBLOCK_INPUT;
7970 longjmp (mgr.setjmp_buffer, 2);
7971 }
7972
7973 /* Allocate colors. When color quantization is used,
7974 cinfo.actual_number_of_colors has been set with the number of
7975 colors generated, and cinfo.colormap is a two-dimensional array
7976 of color indices in the range 0..cinfo.actual_number_of_colors.
7977 No more than 255 colors will be generated. */
7978 {
7979 int i, ir, ig, ib;
7980
7981 if (cinfo.out_color_components > 2)
7982 ir = 0, ig = 1, ib = 2;
7983 else if (cinfo.out_color_components > 1)
7984 ir = 0, ig = 1, ib = 0;
7985 else
7986 ir = 0, ig = 0, ib = 0;
7987
7988 /* Use the color table mechanism because it handles colors that
7989 cannot be allocated nicely. Such colors will be replaced with
7990 a default color, and we don't have to care about which colors
7991 can be freed safely, and which can't. */
7992 init_color_table ();
7993 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
7994 * sizeof *colors);
7995
7996 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
7997 {
7998 /* Multiply RGB values with 255 because X expects RGB values
7999 in the range 0..0xffff. */
8000 int r = cinfo.colormap[ir][i] << 8;
8001 int g = cinfo.colormap[ig][i] << 8;
8002 int b = cinfo.colormap[ib][i] << 8;
8003 colors[i] = lookup_rgb_color (f, r, g, b);
8004 }
8005
8006 /* Remember those colors actually allocated. */
8007 img->colors = colors_in_color_table (&img->ncolors);
8008 free_color_table ();
8009 }
8010
8011 /* Read pixels. */
8012 row_stride = width * cinfo.output_components;
8013 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
8014 row_stride, 1);
8015 for (y = 0; y < height; ++y)
8016 {
8017 jpeg_read_scanlines (&cinfo, buffer, 1);
8018 for (x = 0; x < cinfo.output_width; ++x)
8019 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
8020 }
8021
8022 /* Clean up. */
8023 jpeg_finish_decompress (&cinfo);
8024 jpeg_destroy_decompress (&cinfo);
8025 if (fp)
8026 fclose (fp);
8027
8028 /* Put the image into the pixmap. */
8029 x_put_x_image (f, ximg, img->pixmap, width, height);
8030 x_destroy_x_image (ximg);
8031 UNBLOCK_INPUT;
8032 UNGCPRO;
8033 return 1;
8034 }
8035
8036 #endif /* HAVE_JPEG */
8037
8038
8039 \f
8040 /***********************************************************************
8041 TIFF
8042 ***********************************************************************/
8043
8044 #if HAVE_TIFF
8045
8046 #include <tiffio.h>
8047
8048 static int tiff_image_p P_ ((Lisp_Object object));
8049 static int tiff_load P_ ((struct frame *f, struct image *img));
8050
8051 /* The symbol `tiff' identifying images of this type. */
8052
8053 Lisp_Object Qtiff;
8054
8055 /* Indices of image specification fields in tiff_format, below. */
8056
8057 enum tiff_keyword_index
8058 {
8059 TIFF_TYPE,
8060 TIFF_DATA,
8061 TIFF_FILE,
8062 TIFF_ASCENT,
8063 TIFF_MARGIN,
8064 TIFF_RELIEF,
8065 TIFF_ALGORITHM,
8066 TIFF_HEURISTIC_MASK,
8067 TIFF_LAST
8068 };
8069
8070 /* Vector of image_keyword structures describing the format
8071 of valid user-defined image specifications. */
8072
8073 static struct image_keyword tiff_format[TIFF_LAST] =
8074 {
8075 {":type", IMAGE_SYMBOL_VALUE, 1},
8076 {":data", IMAGE_STRING_VALUE, 0},
8077 {":file", IMAGE_STRING_VALUE, 0},
8078 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8079 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8080 {":relief", IMAGE_INTEGER_VALUE, 0},
8081 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8082 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8083 };
8084
8085 /* Structure describing the image type `tiff'. */
8086
8087 static struct image_type tiff_type =
8088 {
8089 &Qtiff,
8090 tiff_image_p,
8091 tiff_load,
8092 x_clear_image,
8093 NULL
8094 };
8095
8096
8097 /* Return non-zero if OBJECT is a valid TIFF image specification. */
8098
8099 static int
8100 tiff_image_p (object)
8101 Lisp_Object object;
8102 {
8103 struct image_keyword fmt[TIFF_LAST];
8104 bcopy (tiff_format, fmt, sizeof fmt);
8105
8106 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
8107 || (fmt[TIFF_ASCENT].count
8108 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
8109 return 0;
8110
8111 /* Must specify either the :data or :file keyword. */
8112 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
8113 }
8114
8115
8116 /* Reading from a memory buffer for TIFF images Based on the PNG
8117 memory source, but we have to provide a lot of extra functions.
8118 Blah.
8119
8120 We really only need to implement read and seek, but I am not
8121 convinced that the TIFF library is smart enough not to destroy
8122 itself if we only hand it the function pointers we need to
8123 override. */
8124
8125 typedef struct
8126 {
8127 unsigned char *bytes;
8128 size_t len;
8129 int index;
8130 }
8131 tiff_memory_source;
8132
8133 static size_t
8134 tiff_read_from_memory (data, buf, size)
8135 thandle_t data;
8136 tdata_t buf;
8137 tsize_t size;
8138 {
8139 tiff_memory_source *src = (tiff_memory_source *) data;
8140
8141 if (size > src->len - src->index)
8142 return (size_t) -1;
8143 bcopy (src->bytes + src->index, buf, size);
8144 src->index += size;
8145 return size;
8146 }
8147
8148 static size_t
8149 tiff_write_from_memory (data, buf, size)
8150 thandle_t data;
8151 tdata_t buf;
8152 tsize_t size;
8153 {
8154 return (size_t) -1;
8155 }
8156
8157 static toff_t
8158 tiff_seek_in_memory (data, off, whence)
8159 thandle_t data;
8160 toff_t off;
8161 int whence;
8162 {
8163 tiff_memory_source *src = (tiff_memory_source *) data;
8164 int idx;
8165
8166 switch (whence)
8167 {
8168 case SEEK_SET: /* Go from beginning of source. */
8169 idx = off;
8170 break;
8171
8172 case SEEK_END: /* Go from end of source. */
8173 idx = src->len + off;
8174 break;
8175
8176 case SEEK_CUR: /* Go from current position. */
8177 idx = src->index + off;
8178 break;
8179
8180 default: /* Invalid `whence'. */
8181 return -1;
8182 }
8183
8184 if (idx > src->len || idx < 0)
8185 return -1;
8186
8187 src->index = idx;
8188 return src->index;
8189 }
8190
8191 static int
8192 tiff_close_memory (data)
8193 thandle_t data;
8194 {
8195 /* NOOP */
8196 return 0;
8197 }
8198
8199 static int
8200 tiff_mmap_memory (data, pbase, psize)
8201 thandle_t data;
8202 tdata_t *pbase;
8203 toff_t *psize;
8204 {
8205 /* It is already _IN_ memory. */
8206 return 0;
8207 }
8208
8209 static void
8210 tiff_unmap_memory (data, base, size)
8211 thandle_t data;
8212 tdata_t base;
8213 toff_t size;
8214 {
8215 /* We don't need to do this. */
8216 }
8217
8218 static toff_t
8219 tiff_size_of_memory (data)
8220 thandle_t data;
8221 {
8222 return ((tiff_memory_source *) data)->len;
8223 }
8224
8225 /* Load TIFF image IMG for use on frame F. Value is non-zero if
8226 successful. */
8227
8228 static int
8229 tiff_load (f, img)
8230 struct frame *f;
8231 struct image *img;
8232 {
8233 Lisp_Object file, specified_file;
8234 Lisp_Object specified_data;
8235 TIFF *tiff;
8236 int width, height, x, y;
8237 uint32 *buf;
8238 int rc;
8239 XImage *ximg;
8240 struct gcpro gcpro1;
8241 tiff_memory_source memsrc;
8242
8243 specified_file = image_spec_value (img->spec, QCfile, NULL);
8244 specified_data = image_spec_value (img->spec, QCdata, NULL);
8245 file = Qnil;
8246 GCPRO1 (file);
8247
8248 if (NILP (specified_data))
8249 {
8250 /* Read from a file */
8251 file = x_find_image_file (specified_file);
8252 if (!STRINGP (file))
8253 {
8254 image_error ("Cannot find image file `%s'", file, Qnil);
8255 UNGCPRO;
8256 return 0;
8257 }
8258
8259 /* Try to open the image file. */
8260 tiff = TIFFOpen (SDATA (file), "r");
8261 if (tiff == NULL)
8262 {
8263 image_error ("Cannot open `%s'", file, Qnil);
8264 UNGCPRO;
8265 return 0;
8266 }
8267 }
8268 else
8269 {
8270 /* Memory source! */
8271 memsrc.bytes = SDATA (specified_data);
8272 memsrc.len = SBYTES (specified_data);
8273 memsrc.index = 0;
8274
8275 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
8276 (TIFFReadWriteProc) tiff_read_from_memory,
8277 (TIFFReadWriteProc) tiff_write_from_memory,
8278 tiff_seek_in_memory,
8279 tiff_close_memory,
8280 tiff_size_of_memory,
8281 tiff_mmap_memory,
8282 tiff_unmap_memory);
8283
8284 if (!tiff)
8285 {
8286 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
8287 UNGCPRO;
8288 return 0;
8289 }
8290 }
8291
8292 /* Get width and height of the image, and allocate a raster buffer
8293 of width x height 32-bit values. */
8294 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
8295 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
8296 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
8297
8298 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8299 TIFFClose (tiff);
8300 if (!rc)
8301 {
8302 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
8303 xfree (buf);
8304 UNGCPRO;
8305 return 0;
8306 }
8307
8308 BLOCK_INPUT;
8309
8310 /* Create the X image and pixmap. */
8311 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8312 {
8313 UNBLOCK_INPUT;
8314 xfree (buf);
8315 UNGCPRO;
8316 return 0;
8317 }
8318
8319 /* Initialize the color table. */
8320 init_color_table ();
8321
8322 /* Process the pixel raster. Origin is in the lower-left corner. */
8323 for (y = 0; y < height; ++y)
8324 {
8325 uint32 *row = buf + y * width;
8326
8327 for (x = 0; x < width; ++x)
8328 {
8329 uint32 abgr = row[x];
8330 int r = TIFFGetR (abgr) << 8;
8331 int g = TIFFGetG (abgr) << 8;
8332 int b = TIFFGetB (abgr) << 8;
8333 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
8334 }
8335 }
8336
8337 /* Remember the colors allocated for the image. Free the color table. */
8338 img->colors = colors_in_color_table (&img->ncolors);
8339 free_color_table ();
8340
8341 /* Put the image into the pixmap, then free the X image and its buffer. */
8342 x_put_x_image (f, ximg, img->pixmap, width, height);
8343 x_destroy_x_image (ximg);
8344 xfree (buf);
8345 UNBLOCK_INPUT;
8346
8347 img->width = width;
8348 img->height = height;
8349
8350 UNGCPRO;
8351 return 1;
8352 }
8353
8354 #endif /* HAVE_TIFF != 0 */
8355
8356
8357 \f
8358 /***********************************************************************
8359 GIF
8360 ***********************************************************************/
8361
8362 #if HAVE_GIF
8363
8364 #include <gif_lib.h>
8365
8366 static int gif_image_p P_ ((Lisp_Object object));
8367 static int gif_load P_ ((struct frame *f, struct image *img));
8368
8369 /* The symbol `gif' identifying images of this type. */
8370
8371 Lisp_Object Qgif;
8372
8373 /* Indices of image specification fields in gif_format, below. */
8374
8375 enum gif_keyword_index
8376 {
8377 GIF_TYPE,
8378 GIF_DATA,
8379 GIF_FILE,
8380 GIF_ASCENT,
8381 GIF_MARGIN,
8382 GIF_RELIEF,
8383 GIF_ALGORITHM,
8384 GIF_HEURISTIC_MASK,
8385 GIF_IMAGE,
8386 GIF_LAST
8387 };
8388
8389 /* Vector of image_keyword structures describing the format
8390 of valid user-defined image specifications. */
8391
8392 static struct image_keyword gif_format[GIF_LAST] =
8393 {
8394 {":type", IMAGE_SYMBOL_VALUE, 1},
8395 {":data", IMAGE_STRING_VALUE, 0},
8396 {":file", IMAGE_STRING_VALUE, 0},
8397 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8398 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8399 {":relief", IMAGE_INTEGER_VALUE, 0},
8400 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8401 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8402 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8403 };
8404
8405 /* Structure describing the image type `gif'. */
8406
8407 static struct image_type gif_type =
8408 {
8409 &Qgif,
8410 gif_image_p,
8411 gif_load,
8412 x_clear_image,
8413 NULL
8414 };
8415
8416 /* Return non-zero if OBJECT is a valid GIF image specification. */
8417
8418 static int
8419 gif_image_p (object)
8420 Lisp_Object object;
8421 {
8422 struct image_keyword fmt[GIF_LAST];
8423 bcopy (gif_format, fmt, sizeof fmt);
8424
8425 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
8426 || (fmt[GIF_ASCENT].count
8427 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
8428 return 0;
8429
8430 /* Must specify either the :data or :file keyword. */
8431 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8432 }
8433
8434 /* Reading a GIF image from memory
8435 Based on the PNG memory stuff to a certain extent. */
8436
8437 typedef struct
8438 {
8439 unsigned char *bytes;
8440 size_t len;
8441 int index;
8442 }
8443 gif_memory_source;
8444
8445 /* Make the current memory source available to gif_read_from_memory.
8446 It's done this way because not all versions of libungif support
8447 a UserData field in the GifFileType structure. */
8448 static gif_memory_source *current_gif_memory_src;
8449
8450 static int
8451 gif_read_from_memory (file, buf, len)
8452 GifFileType *file;
8453 GifByteType *buf;
8454 int len;
8455 {
8456 gif_memory_source *src = current_gif_memory_src;
8457
8458 if (len > src->len - src->index)
8459 return -1;
8460
8461 bcopy (src->bytes + src->index, buf, len);
8462 src->index += len;
8463 return len;
8464 }
8465
8466
8467 /* Load GIF image IMG for use on frame F. Value is non-zero if
8468 successful. */
8469
8470 static int
8471 gif_load (f, img)
8472 struct frame *f;
8473 struct image *img;
8474 {
8475 Lisp_Object file, specified_file;
8476 Lisp_Object specified_data;
8477 int rc, width, height, x, y, i;
8478 XImage *ximg;
8479 ColorMapObject *gif_color_map;
8480 unsigned long pixel_colors[256];
8481 GifFileType *gif;
8482 struct gcpro gcpro1;
8483 Lisp_Object image;
8484 int ino, image_left, image_top, image_width, image_height;
8485 gif_memory_source memsrc;
8486 unsigned char *raster;
8487
8488 specified_file = image_spec_value (img->spec, QCfile, NULL);
8489 specified_data = image_spec_value (img->spec, QCdata, NULL);
8490 file = Qnil;
8491 GCPRO1 (file);
8492
8493 if (NILP (specified_data))
8494 {
8495 file = x_find_image_file (specified_file);
8496 if (!STRINGP (file))
8497 {
8498 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8499 UNGCPRO;
8500 return 0;
8501 }
8502
8503 /* Open the GIF file. */
8504 gif = DGifOpenFileName (SDATA (file));
8505 if (gif == NULL)
8506 {
8507 image_error ("Cannot open `%s'", file, Qnil);
8508 UNGCPRO;
8509 return 0;
8510 }
8511 }
8512 else
8513 {
8514 /* Read from memory! */
8515 current_gif_memory_src = &memsrc;
8516 memsrc.bytes = SDATA (specified_data);
8517 memsrc.len = SBYTES (specified_data);
8518 memsrc.index = 0;
8519
8520 gif = DGifOpen(&memsrc, gif_read_from_memory);
8521 if (!gif)
8522 {
8523 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
8524 UNGCPRO;
8525 return 0;
8526 }
8527 }
8528
8529 /* Read entire contents. */
8530 rc = DGifSlurp (gif);
8531 if (rc == GIF_ERROR)
8532 {
8533 image_error ("Error reading `%s'", img->spec, Qnil);
8534 DGifCloseFile (gif);
8535 UNGCPRO;
8536 return 0;
8537 }
8538
8539 image = image_spec_value (img->spec, QCindex, NULL);
8540 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8541 if (ino >= gif->ImageCount)
8542 {
8543 image_error ("Invalid image number `%s' in image `%s'",
8544 image, img->spec);
8545 DGifCloseFile (gif);
8546 UNGCPRO;
8547 return 0;
8548 }
8549
8550 width = img->width = gif->SWidth;
8551 height = img->height = gif->SHeight;
8552
8553 BLOCK_INPUT;
8554
8555 /* Create the X image and pixmap. */
8556 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8557 {
8558 UNBLOCK_INPUT;
8559 DGifCloseFile (gif);
8560 UNGCPRO;
8561 return 0;
8562 }
8563
8564 /* Allocate colors. */
8565 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
8566 if (!gif_color_map)
8567 gif_color_map = gif->SColorMap;
8568 init_color_table ();
8569 bzero (pixel_colors, sizeof pixel_colors);
8570
8571 for (i = 0; i < gif_color_map->ColorCount; ++i)
8572 {
8573 int r = gif_color_map->Colors[i].Red << 8;
8574 int g = gif_color_map->Colors[i].Green << 8;
8575 int b = gif_color_map->Colors[i].Blue << 8;
8576 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
8577 }
8578
8579 img->colors = colors_in_color_table (&img->ncolors);
8580 free_color_table ();
8581
8582 /* Clear the part of the screen image that are not covered by
8583 the image from the GIF file. Full animated GIF support
8584 requires more than can be done here (see the gif89 spec,
8585 disposal methods). Let's simply assume that the part
8586 not covered by a sub-image is in the frame's background color. */
8587 image_top = gif->SavedImages[ino].ImageDesc.Top;
8588 image_left = gif->SavedImages[ino].ImageDesc.Left;
8589 image_width = gif->SavedImages[ino].ImageDesc.Width;
8590 image_height = gif->SavedImages[ino].ImageDesc.Height;
8591
8592 for (y = 0; y < image_top; ++y)
8593 for (x = 0; x < width; ++x)
8594 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8595
8596 for (y = image_top + image_height; y < height; ++y)
8597 for (x = 0; x < width; ++x)
8598 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8599
8600 for (y = image_top; y < image_top + image_height; ++y)
8601 {
8602 for (x = 0; x < image_left; ++x)
8603 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8604 for (x = image_left + image_width; x < width; ++x)
8605 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
8606 }
8607
8608 /* Read the GIF image into the X image. We use a local variable
8609 `raster' here because RasterBits below is a char *, and invites
8610 problems with bytes >= 0x80. */
8611 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
8612
8613 if (gif->SavedImages[ino].ImageDesc.Interlace)
8614 {
8615 static int interlace_start[] = {0, 4, 2, 1};
8616 static int interlace_increment[] = {8, 8, 4, 2};
8617 int pass, inc;
8618 int row = interlace_start[0];
8619
8620 pass = 0;
8621
8622 for (y = 0; y < image_height; y++)
8623 {
8624 if (row >= image_height)
8625 {
8626 row = interlace_start[++pass];
8627 while (row >= image_height)
8628 row = interlace_start[++pass];
8629 }
8630
8631 for (x = 0; x < image_width; x++)
8632 {
8633 int i = raster[(y * image_width) + x];
8634 XPutPixel (ximg, x + image_left, row + image_top,
8635 pixel_colors[i]);
8636 }
8637
8638 row += interlace_increment[pass];
8639 }
8640 }
8641 else
8642 {
8643 for (y = 0; y < image_height; ++y)
8644 for (x = 0; x < image_width; ++x)
8645 {
8646 int i = raster[y* image_width + x];
8647 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8648 }
8649 }
8650
8651 DGifCloseFile (gif);
8652
8653 /* Put the image into the pixmap, then free the X image and its buffer. */
8654 x_put_x_image (f, ximg, img->pixmap, width, height);
8655 x_destroy_x_image (ximg);
8656 UNBLOCK_INPUT;
8657
8658 UNGCPRO;
8659 return 1;
8660 }
8661
8662 #endif /* HAVE_GIF != 0 */
8663
8664
8665 \f
8666 /***********************************************************************
8667 Ghostscript
8668 ***********************************************************************/
8669
8670 #ifdef HAVE_GHOSTSCRIPT
8671 static int gs_image_p P_ ((Lisp_Object object));
8672 static int gs_load P_ ((struct frame *f, struct image *img));
8673 static void gs_clear_image P_ ((struct frame *f, struct image *img));
8674
8675 /* The symbol `postscript' identifying images of this type. */
8676
8677 Lisp_Object Qpostscript;
8678
8679 /* Keyword symbols. */
8680
8681 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8682
8683 /* Indices of image specification fields in gs_format, below. */
8684
8685 enum gs_keyword_index
8686 {
8687 GS_TYPE,
8688 GS_PT_WIDTH,
8689 GS_PT_HEIGHT,
8690 GS_FILE,
8691 GS_LOADER,
8692 GS_BOUNDING_BOX,
8693 GS_ASCENT,
8694 GS_MARGIN,
8695 GS_RELIEF,
8696 GS_ALGORITHM,
8697 GS_HEURISTIC_MASK,
8698 GS_LAST
8699 };
8700
8701 /* Vector of image_keyword structures describing the format
8702 of valid user-defined image specifications. */
8703
8704 static struct image_keyword gs_format[GS_LAST] =
8705 {
8706 {":type", IMAGE_SYMBOL_VALUE, 1},
8707 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8708 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8709 {":file", IMAGE_STRING_VALUE, 1},
8710 {":loader", IMAGE_FUNCTION_VALUE, 0},
8711 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8712 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8713 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8714 {":relief", IMAGE_INTEGER_VALUE, 0},
8715 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8716 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8717 };
8718
8719 /* Structure describing the image type `ghostscript'. */
8720
8721 static struct image_type gs_type =
8722 {
8723 &Qpostscript,
8724 gs_image_p,
8725 gs_load,
8726 gs_clear_image,
8727 NULL
8728 };
8729
8730
8731 /* Free X resources of Ghostscript image IMG which is used on frame F. */
8732
8733 static void
8734 gs_clear_image (f, img)
8735 struct frame *f;
8736 struct image *img;
8737 {
8738 /* IMG->data.ptr_val may contain a recorded colormap. */
8739 xfree (img->data.ptr_val);
8740 x_clear_image (f, img);
8741 }
8742
8743
8744 /* Return non-zero if OBJECT is a valid Ghostscript image
8745 specification. */
8746
8747 static int
8748 gs_image_p (object)
8749 Lisp_Object object;
8750 {
8751 struct image_keyword fmt[GS_LAST];
8752 Lisp_Object tem;
8753 int i;
8754
8755 bcopy (gs_format, fmt, sizeof fmt);
8756
8757 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
8758 || (fmt[GS_ASCENT].count
8759 && XFASTINT (fmt[GS_ASCENT].value) > 100))
8760 return 0;
8761
8762 /* Bounding box must be a list or vector containing 4 integers. */
8763 tem = fmt[GS_BOUNDING_BOX].value;
8764 if (CONSP (tem))
8765 {
8766 for (i = 0; i < 4; ++i, tem = XCDR (tem))
8767 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
8768 return 0;
8769 if (!NILP (tem))
8770 return 0;
8771 }
8772 else if (VECTORP (tem))
8773 {
8774 if (XVECTOR (tem)->size != 4)
8775 return 0;
8776 for (i = 0; i < 4; ++i)
8777 if (!INTEGERP (XVECTOR (tem)->contents[i]))
8778 return 0;
8779 }
8780 else
8781 return 0;
8782
8783 return 1;
8784 }
8785
8786
8787 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
8788 if successful. */
8789
8790 static int
8791 gs_load (f, img)
8792 struct frame *f;
8793 struct image *img;
8794 {
8795 char buffer[100];
8796 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
8797 struct gcpro gcpro1, gcpro2;
8798 Lisp_Object frame;
8799 double in_width, in_height;
8800 Lisp_Object pixel_colors = Qnil;
8801
8802 /* Compute pixel size of pixmap needed from the given size in the
8803 image specification. Sizes in the specification are in pt. 1 pt
8804 = 1/72 in, xdpi and ydpi are stored in the frame's X display
8805 info. */
8806 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
8807 in_width = XFASTINT (pt_width) / 72.0;
8808 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
8809 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
8810 in_height = XFASTINT (pt_height) / 72.0;
8811 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
8812
8813 /* Create the pixmap. */
8814 BLOCK_INPUT;
8815 xassert (img->pixmap == 0);
8816 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8817 img->width, img->height,
8818 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
8819 UNBLOCK_INPUT;
8820
8821 if (!img->pixmap)
8822 {
8823 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8824 return 0;
8825 }
8826
8827 /* Call the loader to fill the pixmap. It returns a process object
8828 if successful. We do not record_unwind_protect here because
8829 other places in redisplay like calling window scroll functions
8830 don't either. Let the Lisp loader use `unwind-protect' instead. */
8831 GCPRO2 (window_and_pixmap_id, pixel_colors);
8832
8833 sprintf (buffer, "%lu %lu",
8834 (unsigned long) FRAME_W32_WINDOW (f),
8835 (unsigned long) img->pixmap);
8836 window_and_pixmap_id = build_string (buffer);
8837
8838 sprintf (buffer, "%lu %lu",
8839 FRAME_FOREGROUND_PIXEL (f),
8840 FRAME_BACKGROUND_PIXEL (f));
8841 pixel_colors = build_string (buffer);
8842
8843 XSETFRAME (frame, f);
8844 loader = image_spec_value (img->spec, QCloader, NULL);
8845 if (NILP (loader))
8846 loader = intern ("gs-load-image");
8847
8848 img->data.lisp_val = call6 (loader, frame, img->spec,
8849 make_number (img->width),
8850 make_number (img->height),
8851 window_and_pixmap_id,
8852 pixel_colors);
8853 UNGCPRO;
8854 return PROCESSP (img->data.lisp_val);
8855 }
8856
8857
8858 /* Kill the Ghostscript process that was started to fill PIXMAP on
8859 frame F. Called from XTread_socket when receiving an event
8860 telling Emacs that Ghostscript has finished drawing. */
8861
8862 void
8863 x_kill_gs_process (pixmap, f)
8864 Pixmap pixmap;
8865 struct frame *f;
8866 {
8867 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8868 int class, i;
8869 struct image *img;
8870
8871 /* Find the image containing PIXMAP. */
8872 for (i = 0; i < c->used; ++i)
8873 if (c->images[i]->pixmap == pixmap)
8874 break;
8875
8876 /* Kill the GS process. We should have found PIXMAP in the image
8877 cache and its image should contain a process object. */
8878 xassert (i < c->used);
8879 img = c->images[i];
8880 xassert (PROCESSP (img->data.lisp_val));
8881 Fkill_process (img->data.lisp_val, Qnil);
8882 img->data.lisp_val = Qnil;
8883
8884 /* On displays with a mutable colormap, figure out the colors
8885 allocated for the image by looking at the pixels of an XImage for
8886 img->pixmap. */
8887 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8888 if (class != StaticColor && class != StaticGray && class != TrueColor)
8889 {
8890 XImage *ximg;
8891
8892 BLOCK_INPUT;
8893
8894 /* Try to get an XImage for img->pixmep. */
8895 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
8896 0, 0, img->width, img->height, ~0, ZPixmap);
8897 if (ximg)
8898 {
8899 int x, y;
8900
8901 /* Initialize the color table. */
8902 init_color_table ();
8903
8904 /* For each pixel of the image, look its color up in the
8905 color table. After having done so, the color table will
8906 contain an entry for each color used by the image. */
8907 for (y = 0; y < img->height; ++y)
8908 for (x = 0; x < img->width; ++x)
8909 {
8910 unsigned long pixel = XGetPixel (ximg, x, y);
8911 lookup_pixel_color (f, pixel);
8912 }
8913
8914 /* Record colors in the image. Free color table and XImage. */
8915 img->colors = colors_in_color_table (&img->ncolors);
8916 free_color_table ();
8917 XDestroyImage (ximg);
8918
8919 #if 0 /* This doesn't seem to be the case. If we free the colors
8920 here, we get a BadAccess later in x_clear_image when
8921 freeing the colors. */
8922 /* We have allocated colors once, but Ghostscript has also
8923 allocated colors on behalf of us. So, to get the
8924 reference counts right, free them once. */
8925 if (img->ncolors)
8926 {
8927 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8928 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
8929 img->colors, img->ncolors, 0);
8930 }
8931 #endif
8932 }
8933 else
8934 image_error ("Cannot get X image of `%s'; colors will not be freed",
8935 img->spec, Qnil);
8936
8937 UNBLOCK_INPUT;
8938 }
8939 }
8940
8941 #endif /* HAVE_GHOSTSCRIPT */
8942
8943 \f
8944 /***********************************************************************
8945 Window properties
8946 ***********************************************************************/
8947
8948 DEFUN ("x-change-window-property", Fx_change_window_property,
8949 Sx_change_window_property, 2, 3, 0,
8950 doc: /* Change window property PROP to VALUE on the X window of FRAME.
8951 PROP and VALUE must be strings. FRAME nil or omitted means use the
8952 selected frame. Value is VALUE. */)
8953 (prop, value, frame)
8954 Lisp_Object frame, prop, value;
8955 {
8956 #if 0 /* MAC_TODO : port window properties to Mac */
8957 struct frame *f = check_x_frame (frame);
8958 Atom prop_atom;
8959
8960 CHECK_STRING (prop);
8961 CHECK_STRING (value);
8962
8963 BLOCK_INPUT;
8964 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
8965 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8966 prop_atom, XA_STRING, 8, PropModeReplace,
8967 SDATA (value), SCHARS (value));
8968
8969 /* Make sure the property is set when we return. */
8970 XFlush (FRAME_W32_DISPLAY (f));
8971 UNBLOCK_INPUT;
8972
8973 #endif /* MAC_TODO */
8974
8975 return value;
8976 }
8977
8978
8979 DEFUN ("x-delete-window-property", Fx_delete_window_property,
8980 Sx_delete_window_property, 1, 2, 0,
8981 doc: /* Remove window property PROP from X window of FRAME.
8982 FRAME nil or omitted means use the selected frame. Value is PROP. */)
8983 (prop, frame)
8984 Lisp_Object prop, frame;
8985 {
8986 #if 0 /* MAC_TODO : port window properties to Mac */
8987
8988 struct frame *f = check_x_frame (frame);
8989 Atom prop_atom;
8990
8991 CHECK_STRING (prop);
8992 BLOCK_INPUT;
8993 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
8994 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
8995
8996 /* Make sure the property is removed when we return. */
8997 XFlush (FRAME_W32_DISPLAY (f));
8998 UNBLOCK_INPUT;
8999 #endif /* MAC_TODO */
9000
9001 return prop;
9002 }
9003
9004
9005 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
9006 1, 2, 0,
9007 doc: /* Value is the value of window property PROP on FRAME.
9008 If FRAME is nil or omitted, use the selected frame. Value is nil
9009 if FRAME hasn't a property with name PROP or if PROP has no string
9010 value. */)
9011 (prop, frame)
9012 Lisp_Object prop, frame;
9013 {
9014 #if 0 /* MAC_TODO : port window properties to Mac */
9015
9016 struct frame *f = check_x_frame (frame);
9017 Atom prop_atom;
9018 int rc;
9019 Lisp_Object prop_value = Qnil;
9020 char *tmp_data = NULL;
9021 Atom actual_type;
9022 int actual_format;
9023 unsigned long actual_size, bytes_remaining;
9024
9025 CHECK_STRING (prop);
9026 BLOCK_INPUT;
9027 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
9028 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9029 prop_atom, 0, 0, False, XA_STRING,
9030 &actual_type, &actual_format, &actual_size,
9031 &bytes_remaining, (unsigned char **) &tmp_data);
9032 if (rc == Success)
9033 {
9034 int size = bytes_remaining;
9035
9036 XFree (tmp_data);
9037 tmp_data = NULL;
9038
9039 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9040 prop_atom, 0, bytes_remaining,
9041 False, XA_STRING,
9042 &actual_type, &actual_format,
9043 &actual_size, &bytes_remaining,
9044 (unsigned char **) &tmp_data);
9045 if (rc == Success)
9046 prop_value = make_string (tmp_data, size);
9047
9048 XFree (tmp_data);
9049 }
9050
9051 UNBLOCK_INPUT;
9052
9053 return prop_value;
9054
9055 #endif /* MAC_TODO */
9056 return Qnil;
9057 }
9058
9059
9060 \f
9061 /***********************************************************************
9062 Hourglass cursor
9063 ***********************************************************************/
9064
9065 /* If non-null, an asynchronous timer that, when it expires, displays
9066 an hourglass cursor on all frames. */
9067
9068 static struct atimer *hourglass_atimer;
9069
9070 /* Non-zero means an hourglass cursor is currently shown. */
9071
9072 static int hourglass_shown_p;
9073
9074 /* Number of seconds to wait before displaying an hourglass cursor. */
9075
9076 static Lisp_Object Vhourglass_delay;
9077
9078 /* Default number of seconds to wait before displaying an hourglass
9079 cursor. */
9080
9081 #define DEFAULT_HOURGLASS_DELAY 1
9082
9083 /* Function prototypes. */
9084
9085 static void show_hourglass P_ ((struct atimer *));
9086 static void hide_hourglass P_ ((void));
9087
9088
9089 /* Cancel a currently active hourglass timer, and start a new one. */
9090
9091 void
9092 start_hourglass ()
9093 {
9094 #if 0 /* MAC_TODO: cursor shape changes. */
9095 EMACS_TIME delay;
9096 int secs, usecs = 0;
9097
9098 cancel_hourglass ();
9099
9100 if (INTEGERP (Vhourglass_delay)
9101 && XINT (Vhourglass_delay) > 0)
9102 secs = XFASTINT (Vhourglass_delay);
9103 else if (FLOATP (Vhourglass_delay)
9104 && XFLOAT_DATA (Vhourglass_delay) > 0)
9105 {
9106 Lisp_Object tem;
9107 tem = Ftruncate (Vhourglass_delay, Qnil);
9108 secs = XFASTINT (tem);
9109 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
9110 }
9111 else
9112 secs = DEFAULT_HOURGLASS_DELAY;
9113
9114 EMACS_SET_SECS_USECS (delay, secs, usecs);
9115 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
9116 show_hourglass, NULL);
9117 #endif /* MAC_TODO */
9118 }
9119
9120
9121 /* Cancel the hourglass cursor timer if active, hide an hourglass
9122 cursor if shown. */
9123
9124 void
9125 cancel_hourglass ()
9126 {
9127 if (hourglass_atimer)
9128 {
9129 cancel_atimer (hourglass_atimer);
9130 hourglass_atimer = NULL;
9131 }
9132
9133 if (hourglass_shown_p)
9134 hide_hourglass ();
9135 }
9136
9137
9138 /* Timer function of hourglass_atimer. TIMER is equal to
9139 hourglass_atimer.
9140
9141 Display an hourglass cursor on all frames by mapping the frames'
9142 hourglass_window. Set the hourglass_p flag in the frames'
9143 output_data.x structure to indicate that an hourglass cursor is
9144 shown on the frames. */
9145
9146 static void
9147 show_hourglass (timer)
9148 struct atimer *timer;
9149 {
9150 #if 0 /* MAC_TODO: cursor shape changes. */
9151 /* The timer implementation will cancel this timer automatically
9152 after this function has run. Set hourglass_atimer to null
9153 so that we know the timer doesn't have to be canceled. */
9154 hourglass_atimer = NULL;
9155
9156 if (!hourglass_shown_p)
9157 {
9158 Lisp_Object rest, frame;
9159
9160 BLOCK_INPUT;
9161
9162 FOR_EACH_FRAME (rest, frame)
9163 if (FRAME_W32_P (XFRAME (frame)))
9164 {
9165 struct frame *f = XFRAME (frame);
9166
9167 f->output_data.w32->hourglass_p = 1;
9168
9169 if (!f->output_data.w32->hourglass_window)
9170 {
9171 unsigned long mask = CWCursor;
9172 XSetWindowAttributes attrs;
9173
9174 attrs.cursor = f->output_data.w32->hourglass_cursor;
9175
9176 f->output_data.w32->hourglass_window
9177 = XCreateWindow (FRAME_X_DISPLAY (f),
9178 FRAME_OUTER_WINDOW (f),
9179 0, 0, 32000, 32000, 0, 0,
9180 InputOnly,
9181 CopyFromParent,
9182 mask, &attrs);
9183 }
9184
9185 XMapRaised (FRAME_X_DISPLAY (f),
9186 f->output_data.w32->hourglass_window);
9187 XFlush (FRAME_X_DISPLAY (f));
9188 }
9189
9190 hourglass_shown_p = 1;
9191 UNBLOCK_INPUT;
9192 }
9193 #endif /* MAC_TODO */
9194 }
9195
9196
9197 /* Hide the hourglass cursor on all frames, if it is currently shown. */
9198
9199 static void
9200 hide_hourglass ()
9201 {
9202 #if 0 /* MAC_TODO: cursor shape changes. */
9203 if (hourglass_shown_p)
9204 {
9205 Lisp_Object rest, frame;
9206
9207 BLOCK_INPUT;
9208 FOR_EACH_FRAME (rest, frame)
9209 {
9210 struct frame *f = XFRAME (frame);
9211
9212 if (FRAME_W32_P (f)
9213 /* Watch out for newly created frames. */
9214 && f->output_data.x->hourglass_window)
9215 {
9216 XUnmapWindow (FRAME_X_DISPLAY (f),
9217 f->output_data.x->hourglass_window);
9218 /* Sync here because XTread_socket looks at the
9219 hourglass_p flag that is reset to zero below. */
9220 XSync (FRAME_X_DISPLAY (f), False);
9221 f->output_data.x->hourglass_p = 0;
9222 }
9223 }
9224
9225 hourglass_shown_p = 0;
9226 UNBLOCK_INPUT;
9227 }
9228 #endif /* MAC_TODO */
9229 }
9230
9231
9232 \f
9233 /***********************************************************************
9234 Tool tips
9235 ***********************************************************************/
9236
9237 static Lisp_Object x_create_tip_frame P_ ((struct mac_display_info *,
9238 Lisp_Object));
9239
9240 /* The frame of a currently visible tooltip, or null. */
9241
9242 Lisp_Object tip_frame;
9243
9244 /* If non-nil, a timer started that hides the last tooltip when it
9245 fires. */
9246
9247 Lisp_Object tip_timer;
9248 Window tip_window;
9249
9250 /* If non-nil, a vector of 3 elements containing the last args
9251 with which x-show-tip was called. See there. */
9252
9253 Lisp_Object last_show_tip_args;
9254
9255 /* Create a frame for a tooltip on the display described by DPYINFO.
9256 PARMS is a list of frame parameters. Value is the frame. */
9257
9258 static Lisp_Object
9259 x_create_tip_frame (dpyinfo, parms)
9260 struct mac_display_info *dpyinfo;
9261 Lisp_Object parms;
9262 {
9263 #if 0 /* MAC_TODO : Mac version */
9264 struct frame *f;
9265 Lisp_Object frame, tem;
9266 Lisp_Object name;
9267 long window_prompting = 0;
9268 int width, height;
9269 int count = SPECPDL_INDEX ();
9270 struct gcpro gcpro1, gcpro2, gcpro3;
9271 struct kboard *kb;
9272
9273 check_x ();
9274
9275 /* Use this general default value to start with until we know if
9276 this frame has a specified name. */
9277 Vx_resource_name = Vinvocation_name;
9278
9279 #ifdef MULTI_KBOARD
9280 kb = dpyinfo->kboard;
9281 #else
9282 kb = &the_only_kboard;
9283 #endif
9284
9285 /* Get the name of the frame to use for resource lookup. */
9286 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
9287 if (!STRINGP (name)
9288 && !EQ (name, Qunbound)
9289 && !NILP (name))
9290 error ("Invalid frame name--not a string or nil");
9291 Vx_resource_name = name;
9292
9293 frame = Qnil;
9294 GCPRO3 (parms, name, frame);
9295 tip_frame = f = make_frame (1);
9296 XSETFRAME (frame, f);
9297 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
9298
9299 f->output_method = output_w32;
9300 f->output_data.w32 =
9301 (struct w32_output *) xmalloc (sizeof (struct w32_output));
9302 bzero (f->output_data.w32, sizeof (struct w32_output));
9303 #if 0
9304 f->output_data.w32->icon_bitmap = -1;
9305 #endif
9306 f->output_data.w32->fontset = -1;
9307 f->icon_name = Qnil;
9308
9309 #ifdef MULTI_KBOARD
9310 FRAME_KBOARD (f) = kb;
9311 #endif
9312 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9313 f->output_data.w32->explicit_parent = 0;
9314
9315 /* Set the name; the functions to which we pass f expect the name to
9316 be set. */
9317 if (EQ (name, Qunbound) || NILP (name))
9318 {
9319 f->name = build_string (dpyinfo->x_id_name);
9320 f->explicit_name = 0;
9321 }
9322 else
9323 {
9324 f->name = name;
9325 f->explicit_name = 1;
9326 /* use the frame's title when getting resources for this frame. */
9327 specbind (Qx_resource_name, name);
9328 }
9329
9330 /* Extract the window parameters from the supplied values
9331 that are needed to determine window geometry. */
9332 {
9333 Lisp_Object font;
9334
9335 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
9336
9337 BLOCK_INPUT;
9338 /* First, try whatever font the caller has specified. */
9339 if (STRINGP (font))
9340 {
9341 tem = Fquery_fontset (font, Qnil);
9342 if (STRINGP (tem))
9343 font = x_new_fontset (f, SDATA (tem));
9344 else
9345 font = x_new_font (f, SDATA (font));
9346 }
9347
9348 /* Try out a font which we hope has bold and italic variations. */
9349 if (!STRINGP (font))
9350 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
9351 if (!STRINGP (font))
9352 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9353 if (! STRINGP (font))
9354 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
9355 if (! STRINGP (font))
9356 /* This was formerly the first thing tried, but it finds too many fonts
9357 and takes too long. */
9358 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
9359 /* If those didn't work, look for something which will at least work. */
9360 if (! STRINGP (font))
9361 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
9362 UNBLOCK_INPUT;
9363 if (! STRINGP (font))
9364 font = build_string ("fixed");
9365
9366 x_default_parameter (f, parms, Qfont, font,
9367 "font", "Font", RES_TYPE_STRING);
9368 }
9369
9370 x_default_parameter (f, parms, Qborder_width, make_number (2),
9371 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
9372
9373 /* This defaults to 2 in order to match xterm. We recognize either
9374 internalBorderWidth or internalBorder (which is what xterm calls
9375 it). */
9376 if (NILP (Fassq (Qinternal_border_width, parms)))
9377 {
9378 Lisp_Object value;
9379
9380 value = w32_get_arg (parms, Qinternal_border_width,
9381 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
9382 if (! EQ (value, Qunbound))
9383 parms = Fcons (Fcons (Qinternal_border_width, value),
9384 parms);
9385 }
9386
9387 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9388 "internalBorderWidth", "internalBorderWidth",
9389 RES_TYPE_NUMBER);
9390
9391 /* Also do the stuff which must be set before the window exists. */
9392 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
9393 "foreground", "Foreground", RES_TYPE_STRING);
9394 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
9395 "background", "Background", RES_TYPE_STRING);
9396 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
9397 "pointerColor", "Foreground", RES_TYPE_STRING);
9398 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
9399 "cursorColor", "Foreground", RES_TYPE_STRING);
9400 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
9401 "borderColor", "BorderColor", RES_TYPE_STRING);
9402
9403 /* Init faces before x_default_parameter is called for scroll-bar
9404 parameters because that function calls x_set_scroll_bar_width,
9405 which calls change_frame_size, which calls Fset_window_buffer,
9406 which runs hooks, which call Fvertical_motion. At the end, we
9407 end up in init_iterator with a null face cache, which should not
9408 happen. */
9409 init_frame_faces (f);
9410
9411 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9412 window_prompting = x_figure_window_size (f, parms);
9413
9414 if (window_prompting & XNegative)
9415 {
9416 if (window_prompting & YNegative)
9417 f->output_data.w32->win_gravity = SouthEastGravity;
9418 else
9419 f->output_data.w32->win_gravity = NorthEastGravity;
9420 }
9421 else
9422 {
9423 if (window_prompting & YNegative)
9424 f->output_data.w32->win_gravity = SouthWestGravity;
9425 else
9426 f->output_data.w32->win_gravity = NorthWestGravity;
9427 }
9428
9429 f->output_data.w32->size_hint_flags = window_prompting;
9430 {
9431 XSetWindowAttributes attrs;
9432 unsigned long mask;
9433
9434 BLOCK_INPUT;
9435 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
9436 /* Window managers looks at the override-redirect flag to
9437 determine whether or net to give windows a decoration (Xlib
9438 3.2.8). */
9439 attrs.override_redirect = True;
9440 attrs.save_under = True;
9441 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
9442 /* Arrange for getting MapNotify and UnmapNotify events. */
9443 attrs.event_mask = StructureNotifyMask;
9444 tip_window
9445 = FRAME_W32_WINDOW (f)
9446 = XCreateWindow (FRAME_W32_DISPLAY (f),
9447 FRAME_W32_DISPLAY_INFO (f)->root_window,
9448 /* x, y, width, height */
9449 0, 0, 1, 1,
9450 /* Border. */
9451 1,
9452 CopyFromParent, InputOutput, CopyFromParent,
9453 mask, &attrs);
9454 UNBLOCK_INPUT;
9455 }
9456
9457 x_make_gc (f);
9458
9459 x_default_parameter (f, parms, Qauto_raise, Qnil,
9460 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9461 x_default_parameter (f, parms, Qauto_lower, Qnil,
9462 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
9463 x_default_parameter (f, parms, Qcursor_type, Qbox,
9464 "cursorType", "CursorType", RES_TYPE_SYMBOL);
9465
9466 /* Dimensions, especially f->height, must be done via change_frame_size.
9467 Change will not be effected unless different from the current
9468 f->height. */
9469 width = f->width;
9470 height = f->height;
9471 f->height = 0;
9472 SET_FRAME_WIDTH (f, 0);
9473 change_frame_size (f, height, width, 1, 0, 0);
9474
9475 /* Add `tooltip' frame parameter's default value. */
9476 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
9477 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
9478 Qnil));
9479
9480 f->no_split = 1;
9481
9482 UNGCPRO;
9483
9484 /* It is now ok to make the frame official even if we get an error
9485 below. And the frame needs to be on Vframe_list or making it
9486 visible won't work. */
9487 Vframe_list = Fcons (frame, Vframe_list);
9488
9489 /* Now that the frame is official, it counts as a reference to
9490 its display. */
9491 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
9492
9493 return unbind_to (count, frame);
9494 #endif /* MAC_TODO */
9495 return Qnil;
9496 }
9497
9498
9499 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
9500 doc : /* Show STRING in a "tooltip" window on frame FRAME.
9501 A tooltip window is a small window displaying a string.
9502
9503 FRAME nil or omitted means use the selected frame.
9504
9505 PARMS is an optional list of frame parameters which can be used to
9506 change the tooltip's appearance.
9507
9508 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
9509 means use the default timeout of 5 seconds.
9510
9511 If the list of frame parameters PARAMS contains a `left' parameters,
9512 the tooltip is displayed at that x-position. Otherwise it is
9513 displayed at the mouse position, with offset DX added (default is 5 if
9514 DX isn't specified). Likewise for the y-position; if a `top' frame
9515 parameter is specified, it determines the y-position of the tooltip
9516 window, otherwise it is displayed at the mouse position, with offset
9517 DY added (default is 10). */)
9518 (string, frame, parms, timeout, dx, dy)
9519 Lisp_Object string, frame, parms, timeout, dx, dy;
9520 {
9521 struct frame *f;
9522 struct window *w;
9523 Window root, child;
9524 Lisp_Object buffer, top, left;
9525 struct buffer *old_buffer;
9526 struct text_pos pos;
9527 int i, width, height;
9528 int root_x, root_y, win_x, win_y;
9529 unsigned pmask;
9530 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
9531 int old_windows_or_buffers_changed = windows_or_buffers_changed;
9532 int count = SPECPDL_INDEX ();
9533
9534 specbind (Qinhibit_redisplay, Qt);
9535
9536 GCPRO4 (string, parms, frame, timeout);
9537
9538 CHECK_STRING (string);
9539 f = check_x_frame (frame);
9540 if (NILP (timeout))
9541 timeout = make_number (5);
9542 else
9543 CHECK_NATNUM (timeout);
9544
9545 if (NILP (dx))
9546 dx = make_number (5);
9547 else
9548 CHECK_NUMBER (dx);
9549
9550 if (NILP (dy))
9551 dy = make_number (-10);
9552 else
9553 CHECK_NUMBER (dy);
9554
9555 if (NILP (last_show_tip_args))
9556 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
9557
9558 if (!NILP (tip_frame))
9559 {
9560 Lisp_Object last_string = AREF (last_show_tip_args, 0);
9561 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
9562 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
9563
9564 if (EQ (frame, last_frame)
9565 && !NILP (Fequal (last_string, string))
9566 && !NILP (Fequal (last_parms, parms)))
9567 {
9568 struct frame *f = XFRAME (tip_frame);
9569
9570 /* Only DX and DY have changed. */
9571 if (!NILP (tip_timer))
9572 {
9573 Lisp_Object timer = tip_timer;
9574 tip_timer = Qnil;
9575 call1 (Qcancel_timer, timer);
9576 }
9577
9578 #if 0 /* MAC_TODO : Mac specifics */
9579 BLOCK_INPUT;
9580 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9581 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9582 root_x, root_y - PIXEL_HEIGHT (f));
9583 UNBLOCK_INPUT;
9584 #endif /* MAC_TODO */
9585 goto start_timer;
9586 }
9587 }
9588
9589 /* Hide a previous tip, if any. */
9590 Fx_hide_tip ();
9591
9592 ASET (last_show_tip_args, 0, string);
9593 ASET (last_show_tip_args, 1, frame);
9594 ASET (last_show_tip_args, 2, parms);
9595
9596 /* Add default values to frame parameters. */
9597 if (NILP (Fassq (Qname, parms)))
9598 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
9599 if (NILP (Fassq (Qinternal_border_width, parms)))
9600 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
9601 if (NILP (Fassq (Qborder_width, parms)))
9602 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
9603 if (NILP (Fassq (Qborder_color, parms)))
9604 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
9605 if (NILP (Fassq (Qbackground_color, parms)))
9606 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
9607 parms);
9608
9609 /* Create a frame for the tooltip, and record it in the global
9610 variable tip_frame. */
9611 frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms);
9612 f = XFRAME (frame);
9613
9614 /* Set up the frame's root window. Currently we use a size of 80
9615 columns x 40 lines. If someone wants to show a larger tip, he
9616 will loose. I don't think this is a realistic case. */
9617 w = XWINDOW (FRAME_ROOT_WINDOW (f));
9618 w->left = w->top = make_number (0);
9619 w->width = make_number (80);
9620 w->height = make_number (40);
9621 adjust_glyphs (f);
9622 w->pseudo_window_p = 1;
9623
9624 /* Display the tooltip text in a temporary buffer. */
9625 buffer = Fget_buffer_create (build_string (" *tip*"));
9626 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
9627 old_buffer = current_buffer;
9628 set_buffer_internal_1 (XBUFFER (buffer));
9629 Ferase_buffer ();
9630 Finsert (1, &string);
9631 clear_glyph_matrix (w->desired_matrix);
9632 clear_glyph_matrix (w->current_matrix);
9633 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
9634 try_window (FRAME_ROOT_WINDOW (f), pos);
9635
9636 /* Compute width and height of the tooltip. */
9637 width = height = 0;
9638 for (i = 0; i < w->desired_matrix->nrows; ++i)
9639 {
9640 struct glyph_row *row = &w->desired_matrix->rows[i];
9641 struct glyph *last;
9642 int row_width;
9643
9644 /* Stop at the first empty row at the end. */
9645 if (!row->enabled_p || !row->displays_text_p)
9646 break;
9647
9648 /* Let the row go over the full width of the frame. */
9649 row->full_width_p = 1;
9650
9651 /* There's a glyph at the end of rows that is use to place
9652 the cursor there. Don't include the width of this glyph. */
9653 if (row->used[TEXT_AREA])
9654 {
9655 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
9656 row_width = row->pixel_width - last->pixel_width;
9657 }
9658 else
9659 row_width = row->pixel_width;
9660
9661 height += row->height;
9662 width = max (width, row_width);
9663 }
9664
9665 /* Add the frame's internal border to the width and height the X
9666 window should have. */
9667 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9668 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
9669
9670 /* Move the tooltip window where the mouse pointer is. Resize and
9671 show it. */
9672 #if 0 /* TODO : Mac specifics */
9673 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9674
9675 BLOCK_INPUT;
9676 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
9677 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
9678 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9679 root_x + 5, root_y - height - 5, width, height);
9680 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
9681 UNBLOCK_INPUT;
9682 #endif /* MAC_TODO */
9683
9684 /* Draw into the window. */
9685 w->must_be_updated_p = 1;
9686 update_single_window (w, 1);
9687
9688 /* Restore original current buffer. */
9689 set_buffer_internal_1 (old_buffer);
9690 windows_or_buffers_changed = old_windows_or_buffers_changed;
9691
9692 start_timer:
9693 /* Let the tip disappear after timeout seconds. */
9694 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
9695 intern ("x-hide-tip"));
9696
9697 UNGCPRO;
9698 return unbind_to (count, Qnil);
9699 }
9700
9701
9702 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
9703 doc: /* Hide the current tooltip window, if there is any.
9704 Value is t is tooltip was open, nil otherwise. */)
9705 ()
9706 {
9707 int count;
9708 Lisp_Object deleted, frame, timer;
9709 struct gcpro gcpro1, gcpro2;
9710
9711 /* Return quickly if nothing to do. */
9712 if (NILP (tip_timer) && NILP (tip_frame))
9713 return Qnil;
9714
9715 frame = tip_frame;
9716 timer = tip_timer;
9717 GCPRO2 (frame, timer);
9718 tip_frame = tip_timer = deleted = Qnil;
9719
9720 count = SPECPDL_INDEX ();
9721 specbind (Qinhibit_redisplay, Qt);
9722 specbind (Qinhibit_quit, Qt);
9723
9724 if (!NILP (timer))
9725 call1 (Qcancel_timer, timer);
9726
9727 if (FRAMEP (frame))
9728 {
9729 Fdelete_frame (frame, Qnil);
9730 deleted = Qt;
9731 }
9732
9733 UNGCPRO;
9734 return unbind_to (count, deleted);
9735 }
9736
9737
9738 \f
9739 /***********************************************************************
9740 File selection dialog
9741 ***********************************************************************/
9742
9743 #if 0 /* MAC_TODO: can standard file dialog */
9744 extern Lisp_Object Qfile_name_history;
9745
9746 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
9747 doc: /* Read file name, prompting with PROMPT in directory DIR.
9748 Use a file selection dialog.
9749 Select DEFAULT-FILENAME in the dialog's file selection box, if
9750 specified. Don't let the user enter a file name in the file
9751 selection dialog's entry field, if MUSTMATCH is non-nil. */)
9752 (prompt, dir, default_filename, mustmatch)
9753 Lisp_Object prompt, dir, default_filename, mustmatch;
9754 {
9755 struct frame *f = SELECTED_FRAME ();
9756 Lisp_Object file = Qnil;
9757 int count = SPECPDL_INDEX ();
9758 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
9759 char filename[MAX_PATH + 1];
9760 char init_dir[MAX_PATH + 1];
9761 int use_dialog_p = 1;
9762
9763 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
9764 CHECK_STRING (prompt);
9765 CHECK_STRING (dir);
9766
9767 /* Create the dialog with PROMPT as title, using DIR as initial
9768 directory and using "*" as pattern. */
9769 dir = Fexpand_file_name (dir, Qnil);
9770 strncpy (init_dir, SDATA (dir), MAX_PATH);
9771 init_dir[MAX_PATH] = '\0';
9772 unixtodos_filename (init_dir);
9773
9774 if (STRINGP (default_filename))
9775 {
9776 char *file_name_only;
9777 char *full_path_name = SDATA (default_filename);
9778
9779 unixtodos_filename (full_path_name);
9780
9781 file_name_only = strrchr (full_path_name, '\\');
9782 if (!file_name_only)
9783 file_name_only = full_path_name;
9784 else
9785 {
9786 file_name_only++;
9787
9788 /* If default_file_name is a directory, don't use the open
9789 file dialog, as it does not support selecting
9790 directories. */
9791 if (!(*file_name_only))
9792 use_dialog_p = 0;
9793 }
9794
9795 strncpy (filename, file_name_only, MAX_PATH);
9796 filename[MAX_PATH] = '\0';
9797 }
9798 else
9799 filename[0] = '\0';
9800
9801 if (use_dialog_p)
9802 {
9803 OPENFILENAME file_details;
9804 char *filename_file;
9805
9806 /* Prevent redisplay. */
9807 specbind (Qinhibit_redisplay, Qt);
9808 BLOCK_INPUT;
9809
9810 bzero (&file_details, sizeof (file_details));
9811 file_details.lStructSize = sizeof (file_details);
9812 file_details.hwndOwner = FRAME_W32_WINDOW (f);
9813 file_details.lpstrFile = filename;
9814 file_details.nMaxFile = sizeof (filename);
9815 file_details.lpstrInitialDir = init_dir;
9816 file_details.lpstrTitle = SDATA (prompt);
9817 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
9818
9819 if (!NILP (mustmatch))
9820 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
9821
9822 if (GetOpenFileName (&file_details))
9823 {
9824 dostounix_filename (filename);
9825 file = build_string (filename);
9826 }
9827 else
9828 file = Qnil;
9829
9830 UNBLOCK_INPUT;
9831 file = unbind_to (count, file);
9832 }
9833 /* Open File dialog will not allow folders to be selected, so resort
9834 to minibuffer completing reads for directories. */
9835 else
9836 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
9837 dir, mustmatch, dir, Qfile_name_history,
9838 default_filename, Qnil);
9839
9840 UNGCPRO;
9841
9842 /* Make "Cancel" equivalent to C-g. */
9843 if (NILP (file))
9844 Fsignal (Qquit, Qnil);
9845
9846 return unbind_to (count, file);
9847 }
9848 #endif /* MAC_TODO */
9849
9850
9851 \f
9852 /***********************************************************************
9853 Tests
9854 ***********************************************************************/
9855
9856 #if GLYPH_DEBUG
9857
9858 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
9859 doc: /* Value is non-nil if SPEC is a valid image specification. */)
9860 (spec)
9861 Lisp_Object spec;
9862 {
9863 return valid_image_p (spec) ? Qt : Qnil;
9864 }
9865
9866
9867 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
9868 (spec)
9869 Lisp_Object spec;
9870 {
9871 int id = -1;
9872
9873 if (valid_image_p (spec))
9874 id = lookup_image (SELECTED_FRAME (), spec);
9875
9876 debug_print (spec);
9877 return make_number (id);
9878 }
9879
9880 #endif /* GLYPH_DEBUG != 0 */
9881
9882
9883 \f
9884 void
9885 syms_of_macfns ()
9886 {
9887 /* Certainly running on Mac. */
9888 mac_in_use = 1;
9889
9890 /* The section below is built by the lisp expression at the top of the file,
9891 just above where these variables are declared. */
9892 /*&&& init symbols here &&&*/
9893 Qauto_raise = intern ("auto-raise");
9894 staticpro (&Qauto_raise);
9895 Qauto_lower = intern ("auto-lower");
9896 staticpro (&Qauto_lower);
9897 Qborder_color = intern ("border-color");
9898 staticpro (&Qborder_color);
9899 Qborder_width = intern ("border-width");
9900 staticpro (&Qborder_width);
9901 Qcursor_color = intern ("cursor-color");
9902 staticpro (&Qcursor_color);
9903 Qcursor_type = intern ("cursor-type");
9904 staticpro (&Qcursor_type);
9905 Qgeometry = intern ("geometry");
9906 staticpro (&Qgeometry);
9907 Qicon_left = intern ("icon-left");
9908 staticpro (&Qicon_left);
9909 Qicon_top = intern ("icon-top");
9910 staticpro (&Qicon_top);
9911 Qicon_type = intern ("icon-type");
9912 staticpro (&Qicon_type);
9913 Qicon_name = intern ("icon-name");
9914 staticpro (&Qicon_name);
9915 Qinternal_border_width = intern ("internal-border-width");
9916 staticpro (&Qinternal_border_width);
9917 Qleft = intern ("left");
9918 staticpro (&Qleft);
9919 Qright = intern ("right");
9920 staticpro (&Qright);
9921 Qmouse_color = intern ("mouse-color");
9922 staticpro (&Qmouse_color);
9923 Qnone = intern ("none");
9924 staticpro (&Qnone);
9925 Qparent_id = intern ("parent-id");
9926 staticpro (&Qparent_id);
9927 Qscroll_bar_width = intern ("scroll-bar-width");
9928 staticpro (&Qscroll_bar_width);
9929 Qsuppress_icon = intern ("suppress-icon");
9930 staticpro (&Qsuppress_icon);
9931 Qundefined_color = intern ("undefined-color");
9932 staticpro (&Qundefined_color);
9933 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
9934 staticpro (&Qvertical_scroll_bars);
9935 Qvisibility = intern ("visibility");
9936 staticpro (&Qvisibility);
9937 Qwindow_id = intern ("window-id");
9938 staticpro (&Qwindow_id);
9939 Qx_frame_parameter = intern ("x-frame-parameter");
9940 staticpro (&Qx_frame_parameter);
9941 Qx_resource_name = intern ("x-resource-name");
9942 staticpro (&Qx_resource_name);
9943 Quser_position = intern ("user-position");
9944 staticpro (&Quser_position);
9945 Quser_size = intern ("user-size");
9946 staticpro (&Quser_size);
9947 Qscreen_gamma = intern ("screen-gamma");
9948 staticpro (&Qscreen_gamma);
9949 Qline_spacing = intern ("line-spacing");
9950 staticpro (&Qline_spacing);
9951 Qcenter = intern ("center");
9952 staticpro (&Qcenter);
9953 /* This is the end of symbol initialization. */
9954
9955 Qhyper = intern ("hyper");
9956 staticpro (&Qhyper);
9957 Qsuper = intern ("super");
9958 staticpro (&Qsuper);
9959 Qmeta = intern ("meta");
9960 staticpro (&Qmeta);
9961 Qalt = intern ("alt");
9962 staticpro (&Qalt);
9963 Qctrl = intern ("ctrl");
9964 staticpro (&Qctrl);
9965 Qcontrol = intern ("control");
9966 staticpro (&Qcontrol);
9967 Qshift = intern ("shift");
9968 staticpro (&Qshift);
9969
9970 /* Text property `display' should be nonsticky by default. */
9971 Vtext_property_default_nonsticky
9972 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
9973
9974
9975 Qlaplace = intern ("laplace");
9976 staticpro (&Qlaplace);
9977
9978 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
9979 staticpro (&Qface_set_after_frame_default);
9980
9981 Fput (Qundefined_color, Qerror_conditions,
9982 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
9983 Fput (Qundefined_color, Qerror_message,
9984 build_string ("Undefined color"));
9985
9986 init_x_parm_symbols ();
9987
9988 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
9989 doc: /* List of directories to search for bitmap files for w32. */);
9990 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
9991
9992 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
9993 doc: /* The shape of the pointer when over text.
9994 Changing the value does not affect existing frames
9995 unless you set the mouse color. */);
9996 Vx_pointer_shape = Qnil;
9997
9998 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
9999 doc: /* The name Emacs uses to look up resources; for internal use only.
10000 `x-get-resource' uses this as the first component of the instance name
10001 when requesting resource values.
10002 Emacs initially sets `x-resource-name' to the name under which Emacs
10003 was invoked, or to the value specified with the `-name' or `-rn'
10004 switches, if present. */);
10005 Vx_resource_name = Qnil;
10006
10007 Vx_nontext_pointer_shape = Qnil;
10008
10009 Vx_mode_pointer_shape = Qnil;
10010
10011 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
10012 doc: /* The shape of the pointer when Emacs is hourglass.
10013 This variable takes effect when you create a new frame
10014 or when you set the mouse color. */);
10015 Vx_hourglass_pointer_shape = Qnil;
10016
10017 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
10018 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
10019 display_hourglass_p = 1;
10020
10021 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
10022 doc: /* *Seconds to wait before displaying an hourglass pointer.
10023 Value must be an integer or float. */);
10024 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
10025
10026 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
10027 &Vx_sensitive_text_pointer_shape,
10028 doc: /* The shape of the pointer when over mouse-sensitive text.
10029 This variable takes effect when you create a new frame
10030 or when you set the mouse color. */);
10031 Vx_sensitive_text_pointer_shape = Qnil;
10032
10033 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
10034 doc: /* A string indicating the foreground color of the cursor box. */);
10035 Vx_cursor_fore_pixel = Qnil;
10036
10037 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
10038 doc: /* Non-nil if no window manager is in use.
10039 Emacs doesn't try to figure this out; this is always nil
10040 unless you set it to something else. */);
10041 /* We don't have any way to find this out, so set it to nil
10042 and maybe the user would like to set it to t. */
10043 Vx_no_window_manager = Qnil;
10044
10045 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
10046 &Vx_pixel_size_width_font_regexp,
10047 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
10048
10049 Since Emacs gets width of a font matching with this regexp from
10050 PIXEL_SIZE field of the name, font finding mechanism gets faster for
10051 such a font. This is especially effective for such large fonts as
10052 Chinese, Japanese, and Korean. */);
10053 Vx_pixel_size_width_font_regexp = Qnil;
10054
10055 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
10056 doc: /* Time after which cached images are removed from the cache.
10057 When an image has not been displayed this many seconds, remove it
10058 from the image cache. Value must be an integer or nil with nil
10059 meaning don't clear the cache. */);
10060 Vimage_cache_eviction_delay = make_number (30 * 60);
10061
10062 #if 0 /* MAC_TODO: implement get X resource */
10063 defsubr (&Sx_get_resource);
10064 #endif
10065 defsubr (&Sx_change_window_property);
10066 defsubr (&Sx_delete_window_property);
10067 defsubr (&Sx_window_property);
10068 defsubr (&Sxw_display_color_p);
10069 defsubr (&Sx_display_grayscale_p);
10070 defsubr (&Sxw_color_defined_p);
10071 defsubr (&Sxw_color_values);
10072 defsubr (&Sx_server_max_request_size);
10073 defsubr (&Sx_server_vendor);
10074 defsubr (&Sx_server_version);
10075 defsubr (&Sx_display_pixel_width);
10076 defsubr (&Sx_display_pixel_height);
10077 defsubr (&Sx_display_mm_width);
10078 defsubr (&Sx_display_mm_height);
10079 defsubr (&Sx_display_screens);
10080 defsubr (&Sx_display_planes);
10081 defsubr (&Sx_display_color_cells);
10082 defsubr (&Sx_display_visual_class);
10083 defsubr (&Sx_display_backing_store);
10084 defsubr (&Sx_display_save_under);
10085 #if 0 /* MAC_TODO: implement XParseGeometry */
10086 defsubr (&Sx_parse_geometry);
10087 #endif
10088 defsubr (&Sx_create_frame);
10089 #if 0 /* MAC_TODO: implement network support */
10090 defsubr (&Sx_open_connection);
10091 defsubr (&Sx_close_connection);
10092 #endif
10093 defsubr (&Sx_display_list);
10094 defsubr (&Sx_synchronize);
10095
10096 /* Setting callback functions for fontset handler. */
10097 get_font_info_func = x_get_font_info;
10098
10099 #if 0 /* This function pointer doesn't seem to be used anywhere.
10100 And the pointer assigned has the wrong type, anyway. */
10101 list_fonts_func = x_list_fonts;
10102 #endif
10103
10104 load_font_func = x_load_font;
10105 find_ccl_program_func = x_find_ccl_program;
10106 query_font_func = x_query_font;
10107
10108 set_frame_fontset_func = x_set_font;
10109 check_window_system_func = check_mac;
10110
10111 #if 0 /* MAC_TODO: Image support for Mac Images. */
10112 Qxbm = intern ("xbm");
10113 staticpro (&Qxbm);
10114 QCtype = intern (":type");
10115 staticpro (&QCtype);
10116 QCconversion = intern (":conversion");
10117 staticpro (&QCconversion);
10118 QCheuristic_mask = intern (":heuristic-mask");
10119 staticpro (&QCheuristic_mask);
10120 QCcolor_symbols = intern (":color-symbols");
10121 staticpro (&QCcolor_symbols);
10122 QCascent = intern (":ascent");
10123 staticpro (&QCascent);
10124 QCmargin = intern (":margin");
10125 staticpro (&QCmargin);
10126 QCrelief = intern (":relief");
10127 staticpro (&QCrelief);
10128 Qpostscript = intern ("postscript");
10129 staticpro (&Qpostscript);
10130 QCloader = intern (":loader");
10131 staticpro (&QCloader);
10132 QCbounding_box = intern (":bounding-box");
10133 staticpro (&QCbounding_box);
10134 QCpt_width = intern (":pt-width");
10135 staticpro (&QCpt_width);
10136 QCpt_height = intern (":pt-height");
10137 staticpro (&QCpt_height);
10138 QCindex = intern (":index");
10139 staticpro (&QCindex);
10140 Qpbm = intern ("pbm");
10141 staticpro (&Qpbm);
10142
10143 #if HAVE_XPM
10144 Qxpm = intern ("xpm");
10145 staticpro (&Qxpm);
10146 #endif
10147
10148 #if HAVE_JPEG
10149 Qjpeg = intern ("jpeg");
10150 staticpro (&Qjpeg);
10151 #endif
10152
10153 #if HAVE_TIFF
10154 Qtiff = intern ("tiff");
10155 staticpro (&Qtiff);
10156 #endif
10157
10158 #if HAVE_GIF
10159 Qgif = intern ("gif");
10160 staticpro (&Qgif);
10161 #endif
10162
10163 #if HAVE_PNG
10164 Qpng = intern ("png");
10165 staticpro (&Qpng);
10166 #endif
10167
10168 defsubr (&Sclear_image_cache);
10169
10170 #if GLYPH_DEBUG
10171 defsubr (&Simagep);
10172 defsubr (&Slookup_image);
10173 #endif
10174 #endif /* MAC_TODO */
10175
10176 hourglass_atimer = NULL;
10177 hourglass_shown_p = 0;
10178
10179 defsubr (&Sx_show_tip);
10180 defsubr (&Sx_hide_tip);
10181 staticpro (&tip_timer);
10182 tip_timer = Qnil;
10183
10184 #if 0 /* MAC_TODO */
10185 defsubr (&Sx_file_dialog);
10186 #endif
10187 }
10188
10189
10190 void
10191 init_xfns ()
10192 {
10193 image_types = NULL;
10194 Vimage_types = Qnil;
10195
10196 define_image_type (&xbm_type);
10197 #if 0 /* NTEMACS_TODO : Image support for W32 */
10198 define_image_type (&gs_type);
10199 define_image_type (&pbm_type);
10200
10201 #if HAVE_XPM
10202 define_image_type (&xpm_type);
10203 #endif
10204
10205 #if HAVE_JPEG
10206 define_image_type (&jpeg_type);
10207 #endif
10208
10209 #if HAVE_TIFF
10210 define_image_type (&tiff_type);
10211 #endif
10212
10213 #if HAVE_GIF
10214 define_image_type (&gif_type);
10215 #endif
10216
10217 #if HAVE_PNG
10218 define_image_type (&png_type);
10219 #endif
10220 #endif /* NTEMACS_TODO */
10221 }