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