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