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