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