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