*** empty log message ***
[emacs.git] / src / macfns.c
blob38afebe0c91ca5185296a593cb87928e091197f6
1 /* Graphical user interface functions for Mac OS.
2 Copyright (C) 2000, 2001 Free Software Foundation, Inc.
4 This file is part of GNU Emacs.
6 GNU Emacs is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Emacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Emacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
21 /* Contributed by Andrew Choi (akochoi@mac.com). */
23 #include <config.h>
25 #include <signal.h>
26 #include <stdio.h>
27 #include <math.h>
28 #include <limits.h>
29 #include <errno.h>
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"
48 /* #include "bitmaps/gray.xbm" */
49 #define gray_width 2
50 #define gray_height 2
51 static unsigned char gray_bits[] = {
52 0x01, 0x02};
54 /*#include <commdlg.h>
55 #include <shellapi.h>*/
56 #include <ctype.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #ifndef MAC_OSX
61 #include <alloca.h>
62 #endif
64 #ifdef MAC_OSX
65 #undef mktime
66 #undef DEBUG
67 #undef Z
68 #undef free
69 #undef malloc
70 #undef realloc
71 /* Macros max and min defined in lisp.h conflict with those in
72 precompiled header Carbon.h. */
73 #undef max
74 #undef min
75 #undef init_process
76 #include <Carbon/Carbon.h>
77 #undef Z
78 #define Z (current_buffer->text->z)
79 #undef free
80 #define free unexec_free
81 #undef malloc
82 #define malloc unexec_malloc
83 #undef realloc
84 #define realloc unexec_realloc
85 #undef min
86 #define min(a, b) ((a) < (b) ? (a) : (b))
87 #undef max
88 #define max(a, b) ((a) > (b) ? (a) : (b))
89 #undef init_process
90 #define init_process emacs_init_process
91 #else /* not MAC_OSX */
92 #include <Windows.h>
93 #include <Gestalt.h>
94 #include <TextUtils.h>
95 #endif /* not MAC_OSX */
97 /*extern void free_frame_menubar ();
98 extern double atof ();
99 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
100 extern int quit_char;*/
102 extern char *lispy_function_keys[];
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. */
108 int gray_bitmap_width = gray_width;
109 int gray_bitmap_height = gray_height;
110 unsigned char *gray_bitmap_bits = gray_bits;
112 /* The name we're using in resource queries. */
114 Lisp_Object Vx_resource_name;
116 /* Non-zero means we're allowed to display an hourglass cursor. */
118 int display_hourglass_p;
120 /* The background and shape of the mouse pointer, and shape when not
121 over text or in the modeline. */
123 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
124 Lisp_Object Vx_hourglass_pointer_shape;
126 /* The shape when over mouse-sensitive text. */
128 Lisp_Object Vx_sensitive_text_pointer_shape;
130 /* If non-nil, the pointer shape to indicate that windows can be
131 dragged horizontally. */
133 Lisp_Object Vx_window_horizontal_drag_shape;
135 /* Color of chars displayed in cursor box. */
137 Lisp_Object Vx_cursor_fore_pixel;
139 /* Nonzero if using Windows. */
141 static int mac_in_use;
143 /* Non nil if no window manager is in use. */
145 Lisp_Object Vx_no_window_manager;
147 /* Search path for bitmap files. */
149 Lisp_Object Vx_bitmap_file_path;
151 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
153 Lisp_Object Vx_pixel_size_width_font_regexp;
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.
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)))))
189 /*&&& symbols declared here &&&*/
190 Lisp_Object Qauto_raise;
191 Lisp_Object Qauto_lower;
192 Lisp_Object Qborder_color;
193 Lisp_Object Qborder_width;
194 Lisp_Object Qcursor_color;
195 Lisp_Object Qcursor_type;
196 Lisp_Object Qgeometry;
197 Lisp_Object Qicon_left;
198 Lisp_Object Qicon_top;
199 Lisp_Object Qicon_type;
200 Lisp_Object Qicon_name;
201 Lisp_Object Qinternal_border_width;
202 Lisp_Object Qleft;
203 Lisp_Object Qright;
204 Lisp_Object Qmouse_color;
205 Lisp_Object Qnone;
206 Lisp_Object Qparent_id;
207 Lisp_Object Qscroll_bar_width;
208 Lisp_Object Qsuppress_icon;
209 Lisp_Object Qundefined_color;
210 Lisp_Object Qvertical_scroll_bars;
211 Lisp_Object Qvisibility;
212 Lisp_Object Qwindow_id;
213 Lisp_Object Qx_frame_parameter;
214 Lisp_Object Qx_resource_name;
215 Lisp_Object Quser_position;
216 Lisp_Object Quser_size;
217 Lisp_Object Qscreen_gamma;
218 Lisp_Object Qline_spacing;
219 Lisp_Object Qcenter;
220 Lisp_Object Qcancel_timer;
221 Lisp_Object Qhyper;
222 Lisp_Object Qsuper;
223 Lisp_Object Qmeta;
224 Lisp_Object Qalt;
225 Lisp_Object Qctrl;
226 Lisp_Object Qcontrol;
227 Lisp_Object Qshift;
229 extern Lisp_Object Qtop;
230 extern Lisp_Object Qdisplay;
231 Lisp_Object Qscroll_bar_foreground, Qscroll_bar_background;
232 extern Lisp_Object Qtool_bar_lines;
234 /* These are defined in frame.c. */
235 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
236 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
237 extern Lisp_Object Qtool_bar_lines;
239 extern Lisp_Object Vwindow_system_version;
241 extern Lisp_Object Qbox;
243 Lisp_Object Qface_set_after_frame_default;
245 extern int mac_initialized;
247 /* Functions in macterm.c. */
248 extern void x_set_offset (struct frame *, int, int, int);
249 extern void x_wm_set_icon_position (struct frame *, int, int);
250 extern void x_display_cursor (struct window *, int, int, int, int, int);
251 extern void x_set_window_size (struct frame *, int, int, int);
252 extern void x_make_frame_visible (struct frame *);
253 extern struct mac_display_info *mac_term_init (Lisp_Object, char *, char *);
254 extern struct font_info *x_get_font_info (FRAME_PTR, int);
255 extern struct font_info *x_load_font (struct frame *, char *, int);
256 extern void x_find_ccl_program (struct font_info *);
257 extern struct font_info *x_query_font (struct frame *, char *);
258 extern void mac_initialize ();
260 /* compare two strings ignoring case */
262 static int
263 stricmp (const char *s, const char *t)
265 for ( ; tolower (*s) == tolower (*t); s++, t++)
266 if (*s == '\0')
267 return 0;
268 return tolower (*s) - tolower (*t);
271 /* compare two strings up to n characters, ignoring case */
273 static int
274 strnicmp (const char *s, const char *t, unsigned int n)
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);
283 /* Error if we are not running on Mac OS. */
285 void
286 check_mac ()
288 if (! mac_in_use)
289 error ("Mac OS not in use or not initialized");
292 /* Nonzero if we can use mouse menus.
293 You should not call this unless HAVE_MENUS is defined. */
296 have_menus_p ()
298 return mac_in_use;
301 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
302 and checking validity for Mac. */
304 FRAME_PTR
305 check_x_frame (frame)
306 Lisp_Object frame;
308 FRAME_PTR f;
310 if (NILP (frame))
311 frame = selected_frame;
312 CHECK_LIVE_FRAME (frame);
313 f = XFRAME (frame);
314 if (! FRAME_MAC_P (f))
315 error ("non-mac frame used");
316 return f;
319 /* Let the user specify a display with a frame.
320 nil stands for the selected frame--or, if that is not a mac frame,
321 the first display on the list. */
323 static struct mac_display_info *
324 check_x_display_info (frame)
325 Lisp_Object frame;
327 if (!mac_initialized)
329 mac_initialize ();
330 mac_initialized = 1;
333 if (NILP (frame))
335 struct frame *sf = XFRAME (selected_frame);
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;
342 else if (STRINGP (frame))
343 return x_display_info_for_name (frame);
344 else
346 FRAME_PTR f;
348 CHECK_LIVE_FRAME (frame);
349 f = XFRAME (frame);
350 if (! FRAME_MAC_P (f))
351 error ("non-mac frame used");
352 return FRAME_MAC_DISPLAY_INFO (f);
356 /* Return the Emacs frame-object corresponding to a mac window.
357 It could be the frame's main window or an icon window. */
359 /* This function can be called during GC, so use GC_xxx type test macros. */
361 struct frame *
362 x_window_to_frame (dpyinfo, wdesc)
363 struct mac_display_info *dpyinfo;
364 WindowPtr wdesc;
366 Lisp_Object tail, frame;
367 struct frame *f;
369 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
371 frame = XCAR (tail);
372 if (!GC_FRAMEP (frame))
373 continue;
374 f = XFRAME (frame);
375 if (!FRAME_W32_P (f) || FRAME_MAC_DISPLAY_INFO (f) != dpyinfo)
376 continue;
377 /*if (f->output_data.w32->hourglass_window == wdesc)
378 return f;*/
380 /* MAC_TODO: Check tooltips when supported. */
381 if (FRAME_MAC_WINDOW (f) == wdesc)
382 return f;
384 return 0;
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.
393 Bitmap indices are guaranteed to be > 0, so a negative number can
394 be used to indicate no bitmap.
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. */
401 /* Functions to access the contents of a bitmap, given an id. */
404 x_bitmap_height (f, id)
405 FRAME_PTR f;
406 int id;
408 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].height;
412 x_bitmap_width (f, id)
413 FRAME_PTR f;
414 int id;
416 return FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].width;
419 #if 0 /* MAC_TODO : not used anywhere (?) */
421 x_bitmap_pixmap (f, id)
422 FRAME_PTR f;
423 int id;
425 return (int) FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
427 #endif
429 /* Allocate a new bitmap record. Returns index of new record. */
431 static int
432 x_allocate_bitmap_record (f)
433 FRAME_PTR f;
435 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
436 int i;
438 if (dpyinfo->bitmaps == NULL)
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;
447 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
448 return ++dpyinfo->bitmaps_last;
450 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
451 if (dpyinfo->bitmaps[i].refcount == 0)
452 return i + 1;
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;
461 /* Add one reference to the reference count of the bitmap with id
462 ID. */
464 void
465 x_reference_bitmap (f, id)
466 FRAME_PTR f;
467 int id;
469 ++FRAME_MAC_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
472 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at
473 BITS. */
476 x_create_bitmap_from_data (f, bits, width, height)
477 struct frame *f;
478 char *bits;
479 unsigned int width, height;
481 struct x_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
482 int id;
484 /* MAC_TODO: for now fail if width is not mod 16 (toolbox requires it) */
486 id = x_allocate_bitmap_record (f);
488 if (width % 16 != 0)
489 return -1;
491 dpyinfo->bitmaps[id - 1].bitmap_data = (char *) xmalloc (height * width);
492 if (! dpyinfo->bitmaps[id - 1].bitmap_data)
493 return -1;
495 bcopy (bits, dpyinfo->bitmaps[id - 1].bitmap_data, height * width);
497 dpyinfo->bitmaps[id - 1].refcount = 1;
498 dpyinfo->bitmaps[id - 1].height = height;
499 dpyinfo->bitmaps[id - 1].width = width;
501 return id;
504 /* Create bitmap from file FILE for frame F. */
507 x_create_bitmap_from_file (f, file)
508 struct frame *f;
509 Lisp_Object file;
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;
522 /* Look for an existing bitmap with the same name. */
523 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
525 if (dpyinfo->bitmaps[id].refcount
526 && dpyinfo->bitmaps[id].file
527 && !strcmp (dpyinfo->bitmaps[id].file, (char *) SDATA (file)))
529 ++dpyinfo->bitmaps[id].refcount;
530 return id + 1;
534 /* Search bitmap-file-path for the file, if appropriate. */
535 fd = openp (Vx_bitmap_file_path, file, "", &found, Qnil);
536 if (fd < 0)
537 return -1;
538 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
539 if (fd == 0)
540 return -1;
541 emacs_close (fd);
543 filename = (char *) SDATA (found);
545 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
547 if (hinst == NULL)
548 return -1;
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;
556 id = x_allocate_bitmap_record (f);
557 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
558 dpyinfo->bitmaps[id - 1].refcount = 1;
559 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (SCHARS (file) + 1);
560 dpyinfo->bitmaps[id - 1].depth = 1;
561 dpyinfo->bitmaps[id - 1].height = height;
562 dpyinfo->bitmaps[id - 1].width = width;
563 strcpy (dpyinfo->bitmaps[id - 1].file, SDATA (file));
565 return id;
566 #endif /* MAC_TODO */
569 /* Remove reference to bitmap with id number ID. */
571 void
572 x_destroy_bitmap (f, id)
573 FRAME_PTR f;
574 int id;
576 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (f);
578 if (id > 0)
580 --dpyinfo->bitmaps[id - 1].refcount;
581 if (dpyinfo->bitmaps[id - 1].refcount == 0)
583 BLOCK_INPUT;
584 dpyinfo->bitmaps[id - 1].bitmap_data = NULL;
585 UNBLOCK_INPUT;
590 /* Free all the bitmaps for the display specified by DPYINFO. */
592 static void
593 x_destroy_all_bitmaps (dpyinfo)
594 struct mac_display_info *dpyinfo;
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;
603 /* Connect the frame-parameter names for W32 frames
604 to the ways of passing the parameter values to the window system.
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. */
610 struct x_frame_parm_table
612 char *name;
613 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
616 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
617 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
618 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
619 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
620 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
621 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
622 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
623 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
624 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
625 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
626 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
627 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
628 Lisp_Object));
629 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
630 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
631 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
632 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
633 Lisp_Object));
634 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
635 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
636 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
637 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
638 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
639 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
640 void x_set_scroll_bar_foreground P_ ((struct frame *, Lisp_Object,
641 Lisp_Object));
642 void x_set_scroll_bar_background P_ ((struct frame *, Lisp_Object,
643 Lisp_Object));
644 static Lisp_Object x_default_scroll_bar_color_parameter P_ ((struct frame *,
645 Lisp_Object,
646 Lisp_Object,
647 char *, char *,
648 int));
649 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
651 static struct x_frame_parm_table x_frame_parms[] =
653 "auto-raise", x_set_autoraise,
654 "auto-lower", x_set_autolower,
655 "background-color", x_set_background_color,
656 "border-color", x_set_border_color,
657 "border-width", x_set_border_width,
658 "cursor-color", x_set_cursor_color,
659 "cursor-type", x_set_cursor_type,
660 "font", x_set_font,
661 "foreground-color", x_set_foreground_color,
662 "icon-name", x_set_icon_name,
663 #if 0 /* MAC_TODO: no icons for Mac */
664 "icon-type", x_set_icon_type,
665 #endif
666 "internal-border-width", x_set_internal_border_width,
667 "menu-bar-lines", x_set_menu_bar_lines,
668 "mouse-color", x_set_mouse_color,
669 "name", x_explicitly_set_name,
670 "scroll-bar-width", x_set_scroll_bar_width,
671 "title", x_set_title,
672 "unsplittable", x_set_unsplittable,
673 "vertical-scroll-bars", x_set_vertical_scroll_bars,
674 "visibility", x_set_visibility,
675 "tool-bar-lines", x_set_tool_bar_lines,
676 #if 0 /* MAC_TODO: cannot set color of scroll bar on the Mac? */
677 "scroll-bar-foreground", x_set_scroll_bar_foreground,
678 "scroll-bar-background", x_set_scroll_bar_background,
679 #endif
680 "screen-gamma", x_set_screen_gamma,
681 "line-spacing", x_set_line_spacing
684 /* Attach the `x-frame-parameter' properties to
685 the Lisp symbol names of parameters relevant to Mac. */
687 void
688 init_x_parm_symbols ()
690 int i;
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));
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. */
701 void
702 x_set_frame_parameters (f, alist)
703 FRAME_PTR f;
704 Lisp_Object alist;
706 Lisp_Object tail;
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;
713 /* Same here. */
714 Lisp_Object left, top;
716 /* Same with these. */
717 Lisp_Object icon_left, icon_top;
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;
726 struct gcpro gcpro1, gcpro2;
728 i = 0;
729 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
730 i++;
732 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
733 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
735 /* Extract parm names and values into those vectors. */
737 i = 0;
738 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
740 Lisp_Object elt;
742 elt = Fcar (tail);
743 parms[i] = Fcar (elt);
744 values[i] = Fcdr (elt);
745 i++;
747 /* TAIL and ALIST are not used again below here. */
748 alist = tail = Qnil;
750 GCPRO2 (*parms, *values);
751 gcpro1.nvars = i;
752 gcpro2.nvars = i;
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;
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);
765 if (FRAME_NEW_HEIGHT (f))
766 height = FRAME_NEW_HEIGHT (f);
767 else
768 height = FRAME_HEIGHT (f);
770 /* Process foreground_color and background_color before anything else.
771 They are independent of other properties, but other properties (e.g.,
772 cursor_color) are dependent upon them. */
773 for (p = 0; p < i; p++)
775 Lisp_Object prop, val;
777 prop = parms[p];
778 val = values[p];
779 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
781 register Lisp_Object param_index, old_value;
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);
793 /* Now process them in reverse of specified order. */
794 for (i--; i >= 0; i--)
796 Lisp_Object prop, val;
798 prop = parms[i];
799 val = values[i];
801 if (EQ (prop, Qwidth) && NUMBERP (val))
802 width = XFASTINT (val);
803 else if (EQ (prop, Qheight) && NUMBERP (val))
804 height = XFASTINT (val);
805 else if (EQ (prop, Qtop))
806 top = val;
807 else if (EQ (prop, Qleft))
808 left = val;
809 else if (EQ (prop, Qicon_top))
810 icon_top = val;
811 else if (EQ (prop, Qicon_left))
812 icon_left = val;
813 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
814 /* Processed above. */
815 continue;
816 else
818 register Lisp_Object param_index, old_value;
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);
830 /* Don't die if just one of these was set. */
831 if (EQ (left, Qunbound))
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);
841 if (EQ (top, Qunbound))
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);
851 /* If one of the icon positions was not set, preserve or default it. */
852 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
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);
859 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
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);
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.
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. */
876 Lisp_Object frame;
878 check_frame_size (f, &height, &width);
880 XSETFRAME (frame, f);
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));
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))
892 int leftpos = 0;
893 int toppos = 0;
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))
901 leftpos = XINT (left);
902 if (leftpos < 0)
903 f->output_data.mac->size_hint_flags |= XNegative;
905 else if (CONSP (left) && EQ (XCAR (left), Qminus)
906 && CONSP (XCDR (left))
907 && INTEGERP (XCAR (XCDR (left))))
909 leftpos = - XINT (XCAR (XCDR (left)));
910 f->output_data.mac->size_hint_flags |= XNegative;
912 else if (CONSP (left) && EQ (XCAR (left), Qplus)
913 && CONSP (XCDR (left))
914 && INTEGERP (XCAR (XCDR (left))))
916 leftpos = XINT (XCAR (XCDR (left)));
919 if (EQ (top, Qminus))
920 f->output_data.mac->size_hint_flags |= YNegative;
921 else if (INTEGERP (top))
923 toppos = XINT (top);
924 if (toppos < 0)
925 f->output_data.mac->size_hint_flags |= YNegative;
927 else if (CONSP (top) && EQ (XCAR (top), Qminus)
928 && CONSP (XCDR (top))
929 && INTEGERP (XCAR (XCDR (top))))
931 toppos = - XINT (XCAR (XCDR (top)));
932 f->output_data.mac->size_hint_flags |= YNegative;
934 else if (CONSP (top) && EQ (XCAR (top), Qplus)
935 && CONSP (XCDR (top))
936 && INTEGERP (XCAR (XCDR (top))))
938 toppos = XINT (XCAR (XCDR (top)));
942 /* Store the numeric value of the position. */
943 f->output_data.mac->top_pos = toppos;
944 f->output_data.mac->left_pos = leftpos;
946 f->output_data.mac->win_gravity = NorthWestGravity;
948 /* Actually set that position, and convert to absolute. */
949 x_set_offset (f, leftpos, toppos, -1);
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));
957 UNGCPRO;
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. */
964 void
965 x_real_positions (f, xptr, yptr)
966 FRAME_PTR f;
967 int *xptr, *yptr;
969 Point pt;
970 GrafPtr oldport;
972 #ifdef TARGET_API_MAC_CARBON
974 Rect r;
976 GetWindowPortBounds (f->output_data.mac->mWP, &r);
977 SetPt (&pt, r.left, r.top);
979 #else /* not TARGET_API_MAC_CARBON */
980 SetPt (&pt,
981 f->output_data.mac->mWP->portRect.left,
982 f->output_data.mac->mWP->portRect.top);
983 #endif /* not TARGET_API_MAC_CARBON */
984 GetPort (&oldport);
985 LocalToGlobal (&pt);
986 SetPort (oldport);
988 *xptr = pt.h;
989 *yptr = pt.v;
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. */
998 void
999 x_report_frame_params (f, alistptr)
1000 struct frame *f;
1001 Lisp_Object *alistptr;
1003 char buf[16];
1004 Lisp_Object tem;
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)));
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)));
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));
1036 /* The default colors for the Mac color map */
1037 typedef struct colormap_t
1039 unsigned long color;
1040 char *name;
1041 } colormap_t;
1043 colormap_t mac_color_map[] =
1045 { RGB_TO_ULONG(255, 250, 250), "snow" },
1046 { RGB_TO_ULONG(248, 248, 255), "ghost white" },
1047 { RGB_TO_ULONG(248, 248, 255), "GhostWhite" },
1048 { RGB_TO_ULONG(245, 245, 245), "white smoke" },
1049 { RGB_TO_ULONG(245, 245, 245), "WhiteSmoke" },
1050 { RGB_TO_ULONG(220, 220, 220), "gainsboro" },
1051 { RGB_TO_ULONG(255, 250, 240), "floral white" },
1052 { RGB_TO_ULONG(255, 250, 240), "FloralWhite" },
1053 { RGB_TO_ULONG(253, 245, 230), "old lace" },
1054 { RGB_TO_ULONG(253, 245, 230), "OldLace" },
1055 { RGB_TO_ULONG(250, 240, 230), "linen" },
1056 { RGB_TO_ULONG(250, 235, 215), "antique white" },
1057 { RGB_TO_ULONG(250, 235, 215), "AntiqueWhite" },
1058 { RGB_TO_ULONG(255, 239, 213), "papaya whip" },
1059 { RGB_TO_ULONG(255, 239, 213), "PapayaWhip" },
1060 { RGB_TO_ULONG(255, 235, 205), "blanched almond" },
1061 { RGB_TO_ULONG(255, 235, 205), "BlanchedAlmond" },
1062 { RGB_TO_ULONG(255, 228, 196), "bisque" },
1063 { RGB_TO_ULONG(255, 218, 185), "peach puff" },
1064 { RGB_TO_ULONG(255, 218, 185), "PeachPuff" },
1065 { RGB_TO_ULONG(255, 222, 173), "navajo white" },
1066 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite" },
1067 { RGB_TO_ULONG(255, 228, 181), "moccasin" },
1068 { RGB_TO_ULONG(255, 248, 220), "cornsilk" },
1069 { RGB_TO_ULONG(255, 255, 240), "ivory" },
1070 { RGB_TO_ULONG(255, 250, 205), "lemon chiffon" },
1071 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon" },
1072 { RGB_TO_ULONG(255, 245, 238), "seashell" },
1073 { RGB_TO_ULONG(240, 255, 240), "honeydew" },
1074 { RGB_TO_ULONG(245, 255, 250), "mint cream" },
1075 { RGB_TO_ULONG(245, 255, 250), "MintCream" },
1076 { RGB_TO_ULONG(240, 255, 255), "azure" },
1077 { RGB_TO_ULONG(240, 248, 255), "alice blue" },
1078 { RGB_TO_ULONG(240, 248, 255), "AliceBlue" },
1079 { RGB_TO_ULONG(230, 230, 250), "lavender" },
1080 { RGB_TO_ULONG(255, 240, 245), "lavender blush" },
1081 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush" },
1082 { RGB_TO_ULONG(255, 228, 225), "misty rose" },
1083 { RGB_TO_ULONG(255, 228, 225), "MistyRose" },
1084 { RGB_TO_ULONG(255, 255, 255), "white" },
1085 { RGB_TO_ULONG(0 , 0 , 0 ), "black" },
1086 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate gray" },
1087 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGray" },
1088 { RGB_TO_ULONG(47 , 79 , 79 ), "dark slate grey" },
1089 { RGB_TO_ULONG(47 , 79 , 79 ), "DarkSlateGrey" },
1090 { RGB_TO_ULONG(105, 105, 105), "dim gray" },
1091 { RGB_TO_ULONG(105, 105, 105), "DimGray" },
1092 { RGB_TO_ULONG(105, 105, 105), "dim grey" },
1093 { RGB_TO_ULONG(105, 105, 105), "DimGrey" },
1094 { RGB_TO_ULONG(112, 128, 144), "slate gray" },
1095 { RGB_TO_ULONG(112, 128, 144), "SlateGray" },
1096 { RGB_TO_ULONG(112, 128, 144), "slate grey" },
1097 { RGB_TO_ULONG(112, 128, 144), "SlateGrey" },
1098 { RGB_TO_ULONG(119, 136, 153), "light slate gray" },
1099 { RGB_TO_ULONG(119, 136, 153), "LightSlateGray" },
1100 { RGB_TO_ULONG(119, 136, 153), "light slate grey" },
1101 { RGB_TO_ULONG(119, 136, 153), "LightSlateGrey" },
1102 { RGB_TO_ULONG(190, 190, 190), "gray" },
1103 { RGB_TO_ULONG(190, 190, 190), "grey" },
1104 { RGB_TO_ULONG(211, 211, 211), "light grey" },
1105 { RGB_TO_ULONG(211, 211, 211), "LightGrey" },
1106 { RGB_TO_ULONG(211, 211, 211), "light gray" },
1107 { RGB_TO_ULONG(211, 211, 211), "LightGray" },
1108 { RGB_TO_ULONG(25 , 25 , 112), "midnight blue" },
1109 { RGB_TO_ULONG(25 , 25 , 112), "MidnightBlue" },
1110 { RGB_TO_ULONG(0 , 0 , 128), "navy" },
1111 { RGB_TO_ULONG(0 , 0 , 128), "navy blue" },
1112 { RGB_TO_ULONG(0 , 0 , 128), "NavyBlue" },
1113 { RGB_TO_ULONG(100, 149, 237), "cornflower blue" },
1114 { RGB_TO_ULONG(100, 149, 237), "CornflowerBlue" },
1115 { RGB_TO_ULONG(72 , 61 , 139), "dark slate blue" },
1116 { RGB_TO_ULONG(72 , 61 , 139), "DarkSlateBlue" },
1117 { RGB_TO_ULONG(106, 90 , 205), "slate blue" },
1118 { RGB_TO_ULONG(106, 90 , 205), "SlateBlue" },
1119 { RGB_TO_ULONG(123, 104, 238), "medium slate blue" },
1120 { RGB_TO_ULONG(123, 104, 238), "MediumSlateBlue" },
1121 { RGB_TO_ULONG(132, 112, 255), "light slate blue" },
1122 { RGB_TO_ULONG(132, 112, 255), "LightSlateBlue" },
1123 { RGB_TO_ULONG(0 , 0 , 205), "medium blue" },
1124 { RGB_TO_ULONG(0 , 0 , 205), "MediumBlue" },
1125 { RGB_TO_ULONG(65 , 105, 225), "royal blue" },
1126 { RGB_TO_ULONG(65 , 105, 225), "RoyalBlue" },
1127 { RGB_TO_ULONG(0 , 0 , 255), "blue" },
1128 { RGB_TO_ULONG(30 , 144, 255), "dodger blue" },
1129 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue" },
1130 { RGB_TO_ULONG(0 , 191, 255), "deep sky blue" },
1131 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue" },
1132 { RGB_TO_ULONG(135, 206, 235), "sky blue" },
1133 { RGB_TO_ULONG(135, 206, 235), "SkyBlue" },
1134 { RGB_TO_ULONG(135, 206, 250), "light sky blue" },
1135 { RGB_TO_ULONG(135, 206, 250), "LightSkyBlue" },
1136 { RGB_TO_ULONG(70 , 130, 180), "steel blue" },
1137 { RGB_TO_ULONG(70 , 130, 180), "SteelBlue" },
1138 { RGB_TO_ULONG(176, 196, 222), "light steel blue" },
1139 { RGB_TO_ULONG(176, 196, 222), "LightSteelBlue" },
1140 { RGB_TO_ULONG(173, 216, 230), "light blue" },
1141 { RGB_TO_ULONG(173, 216, 230), "LightBlue" },
1142 { RGB_TO_ULONG(176, 224, 230), "powder blue" },
1143 { RGB_TO_ULONG(176, 224, 230), "PowderBlue" },
1144 { RGB_TO_ULONG(175, 238, 238), "pale turquoise" },
1145 { RGB_TO_ULONG(175, 238, 238), "PaleTurquoise" },
1146 { RGB_TO_ULONG(0 , 206, 209), "dark turquoise" },
1147 { RGB_TO_ULONG(0 , 206, 209), "DarkTurquoise" },
1148 { RGB_TO_ULONG(72 , 209, 204), "medium turquoise" },
1149 { RGB_TO_ULONG(72 , 209, 204), "MediumTurquoise" },
1150 { RGB_TO_ULONG(64 , 224, 208), "turquoise" },
1151 { RGB_TO_ULONG(0 , 255, 255), "cyan" },
1152 { RGB_TO_ULONG(224, 255, 255), "light cyan" },
1153 { RGB_TO_ULONG(224, 255, 255), "LightCyan" },
1154 { RGB_TO_ULONG(95 , 158, 160), "cadet blue" },
1155 { RGB_TO_ULONG(95 , 158, 160), "CadetBlue" },
1156 { RGB_TO_ULONG(102, 205, 170), "medium aquamarine" },
1157 { RGB_TO_ULONG(102, 205, 170), "MediumAquamarine" },
1158 { RGB_TO_ULONG(127, 255, 212), "aquamarine" },
1159 { RGB_TO_ULONG(0 , 100, 0 ), "dark green" },
1160 { RGB_TO_ULONG(0 , 100, 0 ), "DarkGreen" },
1161 { RGB_TO_ULONG(85 , 107, 47 ), "dark olive green" },
1162 { RGB_TO_ULONG(85 , 107, 47 ), "DarkOliveGreen" },
1163 { RGB_TO_ULONG(143, 188, 143), "dark sea green" },
1164 { RGB_TO_ULONG(143, 188, 143), "DarkSeaGreen" },
1165 { RGB_TO_ULONG(46 , 139, 87 ), "sea green" },
1166 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen" },
1167 { RGB_TO_ULONG(60 , 179, 113), "medium sea green" },
1168 { RGB_TO_ULONG(60 , 179, 113), "MediumSeaGreen" },
1169 { RGB_TO_ULONG(32 , 178, 170), "light sea green" },
1170 { RGB_TO_ULONG(32 , 178, 170), "LightSeaGreen" },
1171 { RGB_TO_ULONG(152, 251, 152), "pale green" },
1172 { RGB_TO_ULONG(152, 251, 152), "PaleGreen" },
1173 { RGB_TO_ULONG(0 , 255, 127), "spring green" },
1174 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen" },
1175 { RGB_TO_ULONG(124, 252, 0 ), "lawn green" },
1176 { RGB_TO_ULONG(124, 252, 0 ), "LawnGreen" },
1177 { RGB_TO_ULONG(0 , 255, 0 ), "green" },
1178 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse" },
1179 { RGB_TO_ULONG(0 , 250, 154), "medium spring green" },
1180 { RGB_TO_ULONG(0 , 250, 154), "MediumSpringGreen" },
1181 { RGB_TO_ULONG(173, 255, 47 ), "green yellow" },
1182 { RGB_TO_ULONG(173, 255, 47 ), "GreenYellow" },
1183 { RGB_TO_ULONG(50 , 205, 50 ), "lime green" },
1184 { RGB_TO_ULONG(50 , 205, 50 ), "LimeGreen" },
1185 { RGB_TO_ULONG(154, 205, 50 ), "yellow green" },
1186 { RGB_TO_ULONG(154, 205, 50 ), "YellowGreen" },
1187 { RGB_TO_ULONG(34 , 139, 34 ), "forest green" },
1188 { RGB_TO_ULONG(34 , 139, 34 ), "ForestGreen" },
1189 { RGB_TO_ULONG(107, 142, 35 ), "olive drab" },
1190 { RGB_TO_ULONG(107, 142, 35 ), "OliveDrab" },
1191 { RGB_TO_ULONG(189, 183, 107), "dark khaki" },
1192 { RGB_TO_ULONG(189, 183, 107), "DarkKhaki" },
1193 { RGB_TO_ULONG(240, 230, 140), "khaki" },
1194 { RGB_TO_ULONG(238, 232, 170), "pale goldenrod" },
1195 { RGB_TO_ULONG(238, 232, 170), "PaleGoldenrod" },
1196 { RGB_TO_ULONG(250, 250, 210), "light goldenrod yellow" },
1197 { RGB_TO_ULONG(250, 250, 210), "LightGoldenrodYellow" },
1198 { RGB_TO_ULONG(255, 255, 224), "light yellow" },
1199 { RGB_TO_ULONG(255, 255, 224), "LightYellow" },
1200 { RGB_TO_ULONG(255, 255, 0 ), "yellow" },
1201 { RGB_TO_ULONG(255, 215, 0 ), "gold" },
1202 { RGB_TO_ULONG(238, 221, 130), "light goldenrod" },
1203 { RGB_TO_ULONG(238, 221, 130), "LightGoldenrod" },
1204 { RGB_TO_ULONG(218, 165, 32 ), "goldenrod" },
1205 { RGB_TO_ULONG(184, 134, 11 ), "dark goldenrod" },
1206 { RGB_TO_ULONG(184, 134, 11 ), "DarkGoldenrod" },
1207 { RGB_TO_ULONG(188, 143, 143), "rosy brown" },
1208 { RGB_TO_ULONG(188, 143, 143), "RosyBrown" },
1209 { RGB_TO_ULONG(205, 92 , 92 ), "indian red" },
1210 { RGB_TO_ULONG(205, 92 , 92 ), "IndianRed" },
1211 { RGB_TO_ULONG(139, 69 , 19 ), "saddle brown" },
1212 { RGB_TO_ULONG(139, 69 , 19 ), "SaddleBrown" },
1213 { RGB_TO_ULONG(160, 82 , 45 ), "sienna" },
1214 { RGB_TO_ULONG(205, 133, 63 ), "peru" },
1215 { RGB_TO_ULONG(222, 184, 135), "burlywood" },
1216 { RGB_TO_ULONG(245, 245, 220), "beige" },
1217 { RGB_TO_ULONG(245, 222, 179), "wheat" },
1218 { RGB_TO_ULONG(244, 164, 96 ), "sandy brown" },
1219 { RGB_TO_ULONG(244, 164, 96 ), "SandyBrown" },
1220 { RGB_TO_ULONG(210, 180, 140), "tan" },
1221 { RGB_TO_ULONG(210, 105, 30 ), "chocolate" },
1222 { RGB_TO_ULONG(178, 34 , 34 ), "firebrick" },
1223 { RGB_TO_ULONG(165, 42 , 42 ), "brown" },
1224 { RGB_TO_ULONG(233, 150, 122), "dark salmon" },
1225 { RGB_TO_ULONG(233, 150, 122), "DarkSalmon" },
1226 { RGB_TO_ULONG(250, 128, 114), "salmon" },
1227 { RGB_TO_ULONG(255, 160, 122), "light salmon" },
1228 { RGB_TO_ULONG(255, 160, 122), "LightSalmon" },
1229 { RGB_TO_ULONG(255, 165, 0 ), "orange" },
1230 { RGB_TO_ULONG(255, 140, 0 ), "dark orange" },
1231 { RGB_TO_ULONG(255, 140, 0 ), "DarkOrange" },
1232 { RGB_TO_ULONG(255, 127, 80 ), "coral" },
1233 { RGB_TO_ULONG(240, 128, 128), "light coral" },
1234 { RGB_TO_ULONG(240, 128, 128), "LightCoral" },
1235 { RGB_TO_ULONG(255, 99 , 71 ), "tomato" },
1236 { RGB_TO_ULONG(255, 69 , 0 ), "orange red" },
1237 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed" },
1238 { RGB_TO_ULONG(255, 0 , 0 ), "red" },
1239 { RGB_TO_ULONG(255, 105, 180), "hot pink" },
1240 { RGB_TO_ULONG(255, 105, 180), "HotPink" },
1241 { RGB_TO_ULONG(255, 20 , 147), "deep pink" },
1242 { RGB_TO_ULONG(255, 20 , 147), "DeepPink" },
1243 { RGB_TO_ULONG(255, 192, 203), "pink" },
1244 { RGB_TO_ULONG(255, 182, 193), "light pink" },
1245 { RGB_TO_ULONG(255, 182, 193), "LightPink" },
1246 { RGB_TO_ULONG(219, 112, 147), "pale violet red" },
1247 { RGB_TO_ULONG(219, 112, 147), "PaleVioletRed" },
1248 { RGB_TO_ULONG(176, 48 , 96 ), "maroon" },
1249 { RGB_TO_ULONG(199, 21 , 133), "medium violet red" },
1250 { RGB_TO_ULONG(199, 21 , 133), "MediumVioletRed" },
1251 { RGB_TO_ULONG(208, 32 , 144), "violet red" },
1252 { RGB_TO_ULONG(208, 32 , 144), "VioletRed" },
1253 { RGB_TO_ULONG(255, 0 , 255), "magenta" },
1254 { RGB_TO_ULONG(238, 130, 238), "violet" },
1255 { RGB_TO_ULONG(221, 160, 221), "plum" },
1256 { RGB_TO_ULONG(218, 112, 214), "orchid" },
1257 { RGB_TO_ULONG(186, 85 , 211), "medium orchid" },
1258 { RGB_TO_ULONG(186, 85 , 211), "MediumOrchid" },
1259 { RGB_TO_ULONG(153, 50 , 204), "dark orchid" },
1260 { RGB_TO_ULONG(153, 50 , 204), "DarkOrchid" },
1261 { RGB_TO_ULONG(148, 0 , 211), "dark violet" },
1262 { RGB_TO_ULONG(148, 0 , 211), "DarkViolet" },
1263 { RGB_TO_ULONG(138, 43 , 226), "blue violet" },
1264 { RGB_TO_ULONG(138, 43 , 226), "BlueViolet" },
1265 { RGB_TO_ULONG(160, 32 , 240), "purple" },
1266 { RGB_TO_ULONG(147, 112, 219), "medium purple" },
1267 { RGB_TO_ULONG(147, 112, 219), "MediumPurple" },
1268 { RGB_TO_ULONG(216, 191, 216), "thistle" },
1269 { RGB_TO_ULONG(255, 250, 250), "snow1" },
1270 { RGB_TO_ULONG(238, 233, 233), "snow2" },
1271 { RGB_TO_ULONG(205, 201, 201), "snow3" },
1272 { RGB_TO_ULONG(139, 137, 137), "snow4" },
1273 { RGB_TO_ULONG(255, 245, 238), "seashell1" },
1274 { RGB_TO_ULONG(238, 229, 222), "seashell2" },
1275 { RGB_TO_ULONG(205, 197, 191), "seashell3" },
1276 { RGB_TO_ULONG(139, 134, 130), "seashell4" },
1277 { RGB_TO_ULONG(255, 239, 219), "AntiqueWhite1" },
1278 { RGB_TO_ULONG(238, 223, 204), "AntiqueWhite2" },
1279 { RGB_TO_ULONG(205, 192, 176), "AntiqueWhite3" },
1280 { RGB_TO_ULONG(139, 131, 120), "AntiqueWhite4" },
1281 { RGB_TO_ULONG(255, 228, 196), "bisque1" },
1282 { RGB_TO_ULONG(238, 213, 183), "bisque2" },
1283 { RGB_TO_ULONG(205, 183, 158), "bisque3" },
1284 { RGB_TO_ULONG(139, 125, 107), "bisque4" },
1285 { RGB_TO_ULONG(255, 218, 185), "PeachPuff1" },
1286 { RGB_TO_ULONG(238, 203, 173), "PeachPuff2" },
1287 { RGB_TO_ULONG(205, 175, 149), "PeachPuff3" },
1288 { RGB_TO_ULONG(139, 119, 101), "PeachPuff4" },
1289 { RGB_TO_ULONG(255, 222, 173), "NavajoWhite1" },
1290 { RGB_TO_ULONG(238, 207, 161), "NavajoWhite2" },
1291 { RGB_TO_ULONG(205, 179, 139), "NavajoWhite3" },
1292 { RGB_TO_ULONG(139, 121, 94), "NavajoWhite4" },
1293 { RGB_TO_ULONG(255, 250, 205), "LemonChiffon1" },
1294 { RGB_TO_ULONG(238, 233, 191), "LemonChiffon2" },
1295 { RGB_TO_ULONG(205, 201, 165), "LemonChiffon3" },
1296 { RGB_TO_ULONG(139, 137, 112), "LemonChiffon4" },
1297 { RGB_TO_ULONG(255, 248, 220), "cornsilk1" },
1298 { RGB_TO_ULONG(238, 232, 205), "cornsilk2" },
1299 { RGB_TO_ULONG(205, 200, 177), "cornsilk3" },
1300 { RGB_TO_ULONG(139, 136, 120), "cornsilk4" },
1301 { RGB_TO_ULONG(255, 255, 240), "ivory1" },
1302 { RGB_TO_ULONG(238, 238, 224), "ivory2" },
1303 { RGB_TO_ULONG(205, 205, 193), "ivory3" },
1304 { RGB_TO_ULONG(139, 139, 131), "ivory4" },
1305 { RGB_TO_ULONG(240, 255, 240), "honeydew1" },
1306 { RGB_TO_ULONG(224, 238, 224), "honeydew2" },
1307 { RGB_TO_ULONG(193, 205, 193), "honeydew3" },
1308 { RGB_TO_ULONG(131, 139, 131), "honeydew4" },
1309 { RGB_TO_ULONG(255, 240, 245), "LavenderBlush1" },
1310 { RGB_TO_ULONG(238, 224, 229), "LavenderBlush2" },
1311 { RGB_TO_ULONG(205, 193, 197), "LavenderBlush3" },
1312 { RGB_TO_ULONG(139, 131, 134), "LavenderBlush4" },
1313 { RGB_TO_ULONG(255, 228, 225), "MistyRose1" },
1314 { RGB_TO_ULONG(238, 213, 210), "MistyRose2" },
1315 { RGB_TO_ULONG(205, 183, 181), "MistyRose3" },
1316 { RGB_TO_ULONG(139, 125, 123), "MistyRose4" },
1317 { RGB_TO_ULONG(240, 255, 255), "azure1" },
1318 { RGB_TO_ULONG(224, 238, 238), "azure2" },
1319 { RGB_TO_ULONG(193, 205, 205), "azure3" },
1320 { RGB_TO_ULONG(131, 139, 139), "azure4" },
1321 { RGB_TO_ULONG(131, 111, 255), "SlateBlue1" },
1322 { RGB_TO_ULONG(122, 103, 238), "SlateBlue2" },
1323 { RGB_TO_ULONG(105, 89 , 205), "SlateBlue3" },
1324 { RGB_TO_ULONG(71 , 60 , 139), "SlateBlue4" },
1325 { RGB_TO_ULONG(72 , 118, 255), "RoyalBlue1" },
1326 { RGB_TO_ULONG(67 , 110, 238), "RoyalBlue2" },
1327 { RGB_TO_ULONG(58 , 95 , 205), "RoyalBlue3" },
1328 { RGB_TO_ULONG(39 , 64 , 139), "RoyalBlue4" },
1329 { RGB_TO_ULONG(0 , 0 , 255), "blue1" },
1330 { RGB_TO_ULONG(0 , 0 , 238), "blue2" },
1331 { RGB_TO_ULONG(0 , 0 , 205), "blue3" },
1332 { RGB_TO_ULONG(0 , 0 , 139), "blue4" },
1333 { RGB_TO_ULONG(30 , 144, 255), "DodgerBlue1" },
1334 { RGB_TO_ULONG(28 , 134, 238), "DodgerBlue2" },
1335 { RGB_TO_ULONG(24 , 116, 205), "DodgerBlue3" },
1336 { RGB_TO_ULONG(16 , 78 , 139), "DodgerBlue4" },
1337 { RGB_TO_ULONG(99 , 184, 255), "SteelBlue1" },
1338 { RGB_TO_ULONG(92 , 172, 238), "SteelBlue2" },
1339 { RGB_TO_ULONG(79 , 148, 205), "SteelBlue3" },
1340 { RGB_TO_ULONG(54 , 100, 139), "SteelBlue4" },
1341 { RGB_TO_ULONG(0 , 191, 255), "DeepSkyBlue1" },
1342 { RGB_TO_ULONG(0 , 178, 238), "DeepSkyBlue2" },
1343 { RGB_TO_ULONG(0 , 154, 205), "DeepSkyBlue3" },
1344 { RGB_TO_ULONG(0 , 104, 139), "DeepSkyBlue4" },
1345 { RGB_TO_ULONG(135, 206, 255), "SkyBlue1" },
1346 { RGB_TO_ULONG(126, 192, 238), "SkyBlue2" },
1347 { RGB_TO_ULONG(108, 166, 205), "SkyBlue3" },
1348 { RGB_TO_ULONG(74 , 112, 139), "SkyBlue4" },
1349 { RGB_TO_ULONG(176, 226, 255), "LightSkyBlue1" },
1350 { RGB_TO_ULONG(164, 211, 238), "LightSkyBlue2" },
1351 { RGB_TO_ULONG(141, 182, 205), "LightSkyBlue3" },
1352 { RGB_TO_ULONG(96 , 123, 139), "LightSkyBlue4" },
1353 { RGB_TO_ULONG(198, 226, 255), "SlateGray1" },
1354 { RGB_TO_ULONG(185, 211, 238), "SlateGray2" },
1355 { RGB_TO_ULONG(159, 182, 205), "SlateGray3" },
1356 { RGB_TO_ULONG(108, 123, 139), "SlateGray4" },
1357 { RGB_TO_ULONG(202, 225, 255), "LightSteelBlue1" },
1358 { RGB_TO_ULONG(188, 210, 238), "LightSteelBlue2" },
1359 { RGB_TO_ULONG(162, 181, 205), "LightSteelBlue3" },
1360 { RGB_TO_ULONG(110, 123, 139), "LightSteelBlue4" },
1361 { RGB_TO_ULONG(191, 239, 255), "LightBlue1" },
1362 { RGB_TO_ULONG(178, 223, 238), "LightBlue2" },
1363 { RGB_TO_ULONG(154, 192, 205), "LightBlue3" },
1364 { RGB_TO_ULONG(104, 131, 139), "LightBlue4" },
1365 { RGB_TO_ULONG(224, 255, 255), "LightCyan1" },
1366 { RGB_TO_ULONG(209, 238, 238), "LightCyan2" },
1367 { RGB_TO_ULONG(180, 205, 205), "LightCyan3" },
1368 { RGB_TO_ULONG(122, 139, 139), "LightCyan4" },
1369 { RGB_TO_ULONG(187, 255, 255), "PaleTurquoise1" },
1370 { RGB_TO_ULONG(174, 238, 238), "PaleTurquoise2" },
1371 { RGB_TO_ULONG(150, 205, 205), "PaleTurquoise3" },
1372 { RGB_TO_ULONG(102, 139, 139), "PaleTurquoise4" },
1373 { RGB_TO_ULONG(152, 245, 255), "CadetBlue1" },
1374 { RGB_TO_ULONG(142, 229, 238), "CadetBlue2" },
1375 { RGB_TO_ULONG(122, 197, 205), "CadetBlue3" },
1376 { RGB_TO_ULONG(83 , 134, 139), "CadetBlue4" },
1377 { RGB_TO_ULONG(0 , 245, 255), "turquoise1" },
1378 { RGB_TO_ULONG(0 , 229, 238), "turquoise2" },
1379 { RGB_TO_ULONG(0 , 197, 205), "turquoise3" },
1380 { RGB_TO_ULONG(0 , 134, 139), "turquoise4" },
1381 { RGB_TO_ULONG(0 , 255, 255), "cyan1" },
1382 { RGB_TO_ULONG(0 , 238, 238), "cyan2" },
1383 { RGB_TO_ULONG(0 , 205, 205), "cyan3" },
1384 { RGB_TO_ULONG(0 , 139, 139), "cyan4" },
1385 { RGB_TO_ULONG(151, 255, 255), "DarkSlateGray1" },
1386 { RGB_TO_ULONG(141, 238, 238), "DarkSlateGray2" },
1387 { RGB_TO_ULONG(121, 205, 205), "DarkSlateGray3" },
1388 { RGB_TO_ULONG(82 , 139, 139), "DarkSlateGray4" },
1389 { RGB_TO_ULONG(127, 255, 212), "aquamarine1" },
1390 { RGB_TO_ULONG(118, 238, 198), "aquamarine2" },
1391 { RGB_TO_ULONG(102, 205, 170), "aquamarine3" },
1392 { RGB_TO_ULONG(69 , 139, 116), "aquamarine4" },
1393 { RGB_TO_ULONG(193, 255, 193), "DarkSeaGreen1" },
1394 { RGB_TO_ULONG(180, 238, 180), "DarkSeaGreen2" },
1395 { RGB_TO_ULONG(155, 205, 155), "DarkSeaGreen3" },
1396 { RGB_TO_ULONG(105, 139, 105), "DarkSeaGreen4" },
1397 { RGB_TO_ULONG(84 , 255, 159), "SeaGreen1" },
1398 { RGB_TO_ULONG(78 , 238, 148), "SeaGreen2" },
1399 { RGB_TO_ULONG(67 , 205, 128), "SeaGreen3" },
1400 { RGB_TO_ULONG(46 , 139, 87 ), "SeaGreen4" },
1401 { RGB_TO_ULONG(154, 255, 154), "PaleGreen1" },
1402 { RGB_TO_ULONG(144, 238, 144), "PaleGreen2" },
1403 { RGB_TO_ULONG(124, 205, 124), "PaleGreen3" },
1404 { RGB_TO_ULONG(84 , 139, 84 ), "PaleGreen4" },
1405 { RGB_TO_ULONG(0 , 255, 127), "SpringGreen1" },
1406 { RGB_TO_ULONG(0 , 238, 118), "SpringGreen2" },
1407 { RGB_TO_ULONG(0 , 205, 102), "SpringGreen3" },
1408 { RGB_TO_ULONG(0 , 139, 69 ), "SpringGreen4" },
1409 { RGB_TO_ULONG(0 , 255, 0 ), "green1" },
1410 { RGB_TO_ULONG(0 , 238, 0 ), "green2" },
1411 { RGB_TO_ULONG(0 , 205, 0 ), "green3" },
1412 { RGB_TO_ULONG(0 , 139, 0 ), "green4" },
1413 { RGB_TO_ULONG(127, 255, 0 ), "chartreuse1" },
1414 { RGB_TO_ULONG(118, 238, 0 ), "chartreuse2" },
1415 { RGB_TO_ULONG(102, 205, 0 ), "chartreuse3" },
1416 { RGB_TO_ULONG(69 , 139, 0 ), "chartreuse4" },
1417 { RGB_TO_ULONG(192, 255, 62 ), "OliveDrab1" },
1418 { RGB_TO_ULONG(179, 238, 58 ), "OliveDrab2" },
1419 { RGB_TO_ULONG(154, 205, 50 ), "OliveDrab3" },
1420 { RGB_TO_ULONG(105, 139, 34 ), "OliveDrab4" },
1421 { RGB_TO_ULONG(202, 255, 112), "DarkOliveGreen1" },
1422 { RGB_TO_ULONG(188, 238, 104), "DarkOliveGreen2" },
1423 { RGB_TO_ULONG(162, 205, 90 ), "DarkOliveGreen3" },
1424 { RGB_TO_ULONG(110, 139, 61 ), "DarkOliveGreen4" },
1425 { RGB_TO_ULONG(255, 246, 143), "khaki1" },
1426 { RGB_TO_ULONG(238, 230, 133), "khaki2" },
1427 { RGB_TO_ULONG(205, 198, 115), "khaki3" },
1428 { RGB_TO_ULONG(139, 134, 78 ), "khaki4" },
1429 { RGB_TO_ULONG(255, 236, 139), "LightGoldenrod1" },
1430 { RGB_TO_ULONG(238, 220, 130), "LightGoldenrod2" },
1431 { RGB_TO_ULONG(205, 190, 112), "LightGoldenrod3" },
1432 { RGB_TO_ULONG(139, 129, 76 ), "LightGoldenrod4" },
1433 { RGB_TO_ULONG(255, 255, 224), "LightYellow1" },
1434 { RGB_TO_ULONG(238, 238, 209), "LightYellow2" },
1435 { RGB_TO_ULONG(205, 205, 180), "LightYellow3" },
1436 { RGB_TO_ULONG(139, 139, 122), "LightYellow4" },
1437 { RGB_TO_ULONG(255, 255, 0 ), "yellow1" },
1438 { RGB_TO_ULONG(238, 238, 0 ), "yellow2" },
1439 { RGB_TO_ULONG(205, 205, 0 ), "yellow3" },
1440 { RGB_TO_ULONG(139, 139, 0 ), "yellow4" },
1441 { RGB_TO_ULONG(255, 215, 0 ), "gold1" },
1442 { RGB_TO_ULONG(238, 201, 0 ), "gold2" },
1443 { RGB_TO_ULONG(205, 173, 0 ), "gold3" },
1444 { RGB_TO_ULONG(139, 117, 0 ), "gold4" },
1445 { RGB_TO_ULONG(255, 193, 37 ), "goldenrod1" },
1446 { RGB_TO_ULONG(238, 180, 34 ), "goldenrod2" },
1447 { RGB_TO_ULONG(205, 155, 29 ), "goldenrod3" },
1448 { RGB_TO_ULONG(139, 105, 20 ), "goldenrod4" },
1449 { RGB_TO_ULONG(255, 185, 15 ), "DarkGoldenrod1" },
1450 { RGB_TO_ULONG(238, 173, 14 ), "DarkGoldenrod2" },
1451 { RGB_TO_ULONG(205, 149, 12 ), "DarkGoldenrod3" },
1452 { RGB_TO_ULONG(139, 101, 8 ), "DarkGoldenrod4" },
1453 { RGB_TO_ULONG(255, 193, 193), "RosyBrown1" },
1454 { RGB_TO_ULONG(238, 180, 180), "RosyBrown2" },
1455 { RGB_TO_ULONG(205, 155, 155), "RosyBrown3" },
1456 { RGB_TO_ULONG(139, 105, 105), "RosyBrown4" },
1457 { RGB_TO_ULONG(255, 106, 106), "IndianRed1" },
1458 { RGB_TO_ULONG(238, 99 , 99 ), "IndianRed2" },
1459 { RGB_TO_ULONG(205, 85 , 85 ), "IndianRed3" },
1460 { RGB_TO_ULONG(139, 58 , 58 ), "IndianRed4" },
1461 { RGB_TO_ULONG(255, 130, 71 ), "sienna1" },
1462 { RGB_TO_ULONG(238, 121, 66 ), "sienna2" },
1463 { RGB_TO_ULONG(205, 104, 57 ), "sienna3" },
1464 { RGB_TO_ULONG(139, 71 , 38 ), "sienna4" },
1465 { RGB_TO_ULONG(255, 211, 155), "burlywood1" },
1466 { RGB_TO_ULONG(238, 197, 145), "burlywood2" },
1467 { RGB_TO_ULONG(205, 170, 125), "burlywood3" },
1468 { RGB_TO_ULONG(139, 115, 85 ), "burlywood4" },
1469 { RGB_TO_ULONG(255, 231, 186), "wheat1" },
1470 { RGB_TO_ULONG(238, 216, 174), "wheat2" },
1471 { RGB_TO_ULONG(205, 186, 150), "wheat3" },
1472 { RGB_TO_ULONG(139, 126, 102), "wheat4" },
1473 { RGB_TO_ULONG(255, 165, 79 ), "tan1" },
1474 { RGB_TO_ULONG(238, 154, 73 ), "tan2" },
1475 { RGB_TO_ULONG(205, 133, 63 ), "tan3" },
1476 { RGB_TO_ULONG(139, 90 , 43 ), "tan4" },
1477 { RGB_TO_ULONG(255, 127, 36 ), "chocolate1" },
1478 { RGB_TO_ULONG(238, 118, 33 ), "chocolate2" },
1479 { RGB_TO_ULONG(205, 102, 29 ), "chocolate3" },
1480 { RGB_TO_ULONG(139, 69 , 19 ), "chocolate4" },
1481 { RGB_TO_ULONG(255, 48 , 48 ), "firebrick1" },
1482 { RGB_TO_ULONG(238, 44 , 44 ), "firebrick2" },
1483 { RGB_TO_ULONG(205, 38 , 38 ), "firebrick3" },
1484 { RGB_TO_ULONG(139, 26 , 26 ), "firebrick4" },
1485 { RGB_TO_ULONG(255, 64 , 64 ), "brown1" },
1486 { RGB_TO_ULONG(238, 59 , 59 ), "brown2" },
1487 { RGB_TO_ULONG(205, 51 , 51 ), "brown3" },
1488 { RGB_TO_ULONG(139, 35 , 35 ), "brown4" },
1489 { RGB_TO_ULONG(255, 140, 105), "salmon1" },
1490 { RGB_TO_ULONG(238, 130, 98 ), "salmon2" },
1491 { RGB_TO_ULONG(205, 112, 84 ), "salmon3" },
1492 { RGB_TO_ULONG(139, 76 , 57 ), "salmon4" },
1493 { RGB_TO_ULONG(255, 160, 122), "LightSalmon1" },
1494 { RGB_TO_ULONG(238, 149, 114), "LightSalmon2" },
1495 { RGB_TO_ULONG(205, 129, 98 ), "LightSalmon3" },
1496 { RGB_TO_ULONG(139, 87 , 66 ), "LightSalmon4" },
1497 { RGB_TO_ULONG(255, 165, 0 ), "orange1" },
1498 { RGB_TO_ULONG(238, 154, 0 ), "orange2" },
1499 { RGB_TO_ULONG(205, 133, 0 ), "orange3" },
1500 { RGB_TO_ULONG(139, 90 , 0 ), "orange4" },
1501 { RGB_TO_ULONG(255, 127, 0 ), "DarkOrange1" },
1502 { RGB_TO_ULONG(238, 118, 0 ), "DarkOrange2" },
1503 { RGB_TO_ULONG(205, 102, 0 ), "DarkOrange3" },
1504 { RGB_TO_ULONG(139, 69 , 0 ), "DarkOrange4" },
1505 { RGB_TO_ULONG(255, 114, 86 ), "coral1" },
1506 { RGB_TO_ULONG(238, 106, 80 ), "coral2" },
1507 { RGB_TO_ULONG(205, 91 , 69 ), "coral3" },
1508 { RGB_TO_ULONG(139, 62 , 47 ), "coral4" },
1509 { RGB_TO_ULONG(255, 99 , 71 ), "tomato1" },
1510 { RGB_TO_ULONG(238, 92 , 66 ), "tomato2" },
1511 { RGB_TO_ULONG(205, 79 , 57 ), "tomato3" },
1512 { RGB_TO_ULONG(139, 54 , 38 ), "tomato4" },
1513 { RGB_TO_ULONG(255, 69 , 0 ), "OrangeRed1" },
1514 { RGB_TO_ULONG(238, 64 , 0 ), "OrangeRed2" },
1515 { RGB_TO_ULONG(205, 55 , 0 ), "OrangeRed3" },
1516 { RGB_TO_ULONG(139, 37 , 0 ), "OrangeRed4" },
1517 { RGB_TO_ULONG(255, 0 , 0 ), "red1" },
1518 { RGB_TO_ULONG(238, 0 , 0 ), "red2" },
1519 { RGB_TO_ULONG(205, 0 , 0 ), "red3" },
1520 { RGB_TO_ULONG(139, 0 , 0 ), "red4" },
1521 { RGB_TO_ULONG(255, 20 , 147), "DeepPink1" },
1522 { RGB_TO_ULONG(238, 18 , 137), "DeepPink2" },
1523 { RGB_TO_ULONG(205, 16 , 118), "DeepPink3" },
1524 { RGB_TO_ULONG(139, 10 , 80 ), "DeepPink4" },
1525 { RGB_TO_ULONG(255, 110, 180), "HotPink1" },
1526 { RGB_TO_ULONG(238, 106, 167), "HotPink2" },
1527 { RGB_TO_ULONG(205, 96 , 144), "HotPink3" },
1528 { RGB_TO_ULONG(139, 58 , 98 ), "HotPink4" },
1529 { RGB_TO_ULONG(255, 181, 197), "pink1" },
1530 { RGB_TO_ULONG(238, 169, 184), "pink2" },
1531 { RGB_TO_ULONG(205, 145, 158), "pink3" },
1532 { RGB_TO_ULONG(139, 99 , 108), "pink4" },
1533 { RGB_TO_ULONG(255, 174, 185), "LightPink1" },
1534 { RGB_TO_ULONG(238, 162, 173), "LightPink2" },
1535 { RGB_TO_ULONG(205, 140, 149), "LightPink3" },
1536 { RGB_TO_ULONG(139, 95 , 101), "LightPink4" },
1537 { RGB_TO_ULONG(255, 130, 171), "PaleVioletRed1" },
1538 { RGB_TO_ULONG(238, 121, 159), "PaleVioletRed2" },
1539 { RGB_TO_ULONG(205, 104, 137), "PaleVioletRed3" },
1540 { RGB_TO_ULONG(139, 71 , 93 ), "PaleVioletRed4" },
1541 { RGB_TO_ULONG(255, 52 , 179), "maroon1" },
1542 { RGB_TO_ULONG(238, 48 , 167), "maroon2" },
1543 { RGB_TO_ULONG(205, 41 , 144), "maroon3" },
1544 { RGB_TO_ULONG(139, 28 , 98 ), "maroon4" },
1545 { RGB_TO_ULONG(255, 62 , 150), "VioletRed1" },
1546 { RGB_TO_ULONG(238, 58 , 140), "VioletRed2" },
1547 { RGB_TO_ULONG(205, 50 , 120), "VioletRed3" },
1548 { RGB_TO_ULONG(139, 34 , 82 ), "VioletRed4" },
1549 { RGB_TO_ULONG(255, 0 , 255), "magenta1" },
1550 { RGB_TO_ULONG(238, 0 , 238), "magenta2" },
1551 { RGB_TO_ULONG(205, 0 , 205), "magenta3" },
1552 { RGB_TO_ULONG(139, 0 , 139), "magenta4" },
1553 { RGB_TO_ULONG(255, 131, 250), "orchid1" },
1554 { RGB_TO_ULONG(238, 122, 233), "orchid2" },
1555 { RGB_TO_ULONG(205, 105, 201), "orchid3" },
1556 { RGB_TO_ULONG(139, 71 , 137), "orchid4" },
1557 { RGB_TO_ULONG(255, 187, 255), "plum1" },
1558 { RGB_TO_ULONG(238, 174, 238), "plum2" },
1559 { RGB_TO_ULONG(205, 150, 205), "plum3" },
1560 { RGB_TO_ULONG(139, 102, 139), "plum4" },
1561 { RGB_TO_ULONG(224, 102, 255), "MediumOrchid1" },
1562 { RGB_TO_ULONG(209, 95 , 238), "MediumOrchid2" },
1563 { RGB_TO_ULONG(180, 82 , 205), "MediumOrchid3" },
1564 { RGB_TO_ULONG(122, 55 , 139), "MediumOrchid4" },
1565 { RGB_TO_ULONG(191, 62 , 255), "DarkOrchid1" },
1566 { RGB_TO_ULONG(178, 58 , 238), "DarkOrchid2" },
1567 { RGB_TO_ULONG(154, 50 , 205), "DarkOrchid3" },
1568 { RGB_TO_ULONG(104, 34 , 139), "DarkOrchid4" },
1569 { RGB_TO_ULONG(155, 48 , 255), "purple1" },
1570 { RGB_TO_ULONG(145, 44 , 238), "purple2" },
1571 { RGB_TO_ULONG(125, 38 , 205), "purple3" },
1572 { RGB_TO_ULONG(85 , 26 , 139), "purple4" },
1573 { RGB_TO_ULONG(171, 130, 255), "MediumPurple1" },
1574 { RGB_TO_ULONG(159, 121, 238), "MediumPurple2" },
1575 { RGB_TO_ULONG(137, 104, 205), "MediumPurple3" },
1576 { RGB_TO_ULONG(93 , 71 , 139), "MediumPurple4" },
1577 { RGB_TO_ULONG(255, 225, 255), "thistle1" },
1578 { RGB_TO_ULONG(238, 210, 238), "thistle2" },
1579 { RGB_TO_ULONG(205, 181, 205), "thistle3" },
1580 { RGB_TO_ULONG(139, 123, 139), "thistle4" },
1581 { RGB_TO_ULONG(0 , 0 , 0 ), "gray0" },
1582 { RGB_TO_ULONG(0 , 0 , 0 ), "grey0" },
1583 { RGB_TO_ULONG(3 , 3 , 3 ), "gray1" },
1584 { RGB_TO_ULONG(3 , 3 , 3 ), "grey1" },
1585 { RGB_TO_ULONG(5 , 5 , 5 ), "gray2" },
1586 { RGB_TO_ULONG(5 , 5 , 5 ), "grey2" },
1587 { RGB_TO_ULONG(8 , 8 , 8 ), "gray3" },
1588 { RGB_TO_ULONG(8 , 8 , 8 ), "grey3" },
1589 { RGB_TO_ULONG(10 , 10 , 10 ), "gray4" },
1590 { RGB_TO_ULONG(10 , 10 , 10 ), "grey4" },
1591 { RGB_TO_ULONG(13 , 13 , 13 ), "gray5" },
1592 { RGB_TO_ULONG(13 , 13 , 13 ), "grey5" },
1593 { RGB_TO_ULONG(15 , 15 , 15 ), "gray6" },
1594 { RGB_TO_ULONG(15 , 15 , 15 ), "grey6" },
1595 { RGB_TO_ULONG(18 , 18 , 18 ), "gray7" },
1596 { RGB_TO_ULONG(18 , 18 , 18 ), "grey7" },
1597 { RGB_TO_ULONG(20 , 20 , 20 ), "gray8" },
1598 { RGB_TO_ULONG(20 , 20 , 20 ), "grey8" },
1599 { RGB_TO_ULONG(23 , 23 , 23 ), "gray9" },
1600 { RGB_TO_ULONG(23 , 23 , 23 ), "grey9" },
1601 { RGB_TO_ULONG(26 , 26 , 26 ), "gray10" },
1602 { RGB_TO_ULONG(26 , 26 , 26 ), "grey10" },
1603 { RGB_TO_ULONG(28 , 28 , 28 ), "gray11" },
1604 { RGB_TO_ULONG(28 , 28 , 28 ), "grey11" },
1605 { RGB_TO_ULONG(31 , 31 , 31 ), "gray12" },
1606 { RGB_TO_ULONG(31 , 31 , 31 ), "grey12" },
1607 { RGB_TO_ULONG(33 , 33 , 33 ), "gray13" },
1608 { RGB_TO_ULONG(33 , 33 , 33 ), "grey13" },
1609 { RGB_TO_ULONG(36 , 36 , 36 ), "gray14" },
1610 { RGB_TO_ULONG(36 , 36 , 36 ), "grey14" },
1611 { RGB_TO_ULONG(38 , 38 , 38 ), "gray15" },
1612 { RGB_TO_ULONG(38 , 38 , 38 ), "grey15" },
1613 { RGB_TO_ULONG(41 , 41 , 41 ), "gray16" },
1614 { RGB_TO_ULONG(41 , 41 , 41 ), "grey16" },
1615 { RGB_TO_ULONG(43 , 43 , 43 ), "gray17" },
1616 { RGB_TO_ULONG(43 , 43 , 43 ), "grey17" },
1617 { RGB_TO_ULONG(46 , 46 , 46 ), "gray18" },
1618 { RGB_TO_ULONG(46 , 46 , 46 ), "grey18" },
1619 { RGB_TO_ULONG(48 , 48 , 48 ), "gray19" },
1620 { RGB_TO_ULONG(48 , 48 , 48 ), "grey19" },
1621 { RGB_TO_ULONG(51 , 51 , 51 ), "gray20" },
1622 { RGB_TO_ULONG(51 , 51 , 51 ), "grey20" },
1623 { RGB_TO_ULONG(54 , 54 , 54 ), "gray21" },
1624 { RGB_TO_ULONG(54 , 54 , 54 ), "grey21" },
1625 { RGB_TO_ULONG(56 , 56 , 56 ), "gray22" },
1626 { RGB_TO_ULONG(56 , 56 , 56 ), "grey22" },
1627 { RGB_TO_ULONG(59 , 59 , 59 ), "gray23" },
1628 { RGB_TO_ULONG(59 , 59 , 59 ), "grey23" },
1629 { RGB_TO_ULONG(61 , 61 , 61 ), "gray24" },
1630 { RGB_TO_ULONG(61 , 61 , 61 ), "grey24" },
1631 { RGB_TO_ULONG(64 , 64 , 64 ), "gray25" },
1632 { RGB_TO_ULONG(64 , 64 , 64 ), "grey25" },
1633 { RGB_TO_ULONG(66 , 66 , 66 ), "gray26" },
1634 { RGB_TO_ULONG(66 , 66 , 66 ), "grey26" },
1635 { RGB_TO_ULONG(69 , 69 , 69 ), "gray27" },
1636 { RGB_TO_ULONG(69 , 69 , 69 ), "grey27" },
1637 { RGB_TO_ULONG(71 , 71 , 71 ), "gray28" },
1638 { RGB_TO_ULONG(71 , 71 , 71 ), "grey28" },
1639 { RGB_TO_ULONG(74 , 74 , 74 ), "gray29" },
1640 { RGB_TO_ULONG(74 , 74 , 74 ), "grey29" },
1641 { RGB_TO_ULONG(77 , 77 , 77 ), "gray30" },
1642 { RGB_TO_ULONG(77 , 77 , 77 ), "grey30" },
1643 { RGB_TO_ULONG(79 , 79 , 79 ), "gray31" },
1644 { RGB_TO_ULONG(79 , 79 , 79 ), "grey31" },
1645 { RGB_TO_ULONG(82 , 82 , 82 ), "gray32" },
1646 { RGB_TO_ULONG(82 , 82 , 82 ), "grey32" },
1647 { RGB_TO_ULONG(84 , 84 , 84 ), "gray33" },
1648 { RGB_TO_ULONG(84 , 84 , 84 ), "grey33" },
1649 { RGB_TO_ULONG(87 , 87 , 87 ), "gray34" },
1650 { RGB_TO_ULONG(87 , 87 , 87 ), "grey34" },
1651 { RGB_TO_ULONG(89 , 89 , 89 ), "gray35" },
1652 { RGB_TO_ULONG(89 , 89 , 89 ), "grey35" },
1653 { RGB_TO_ULONG(92 , 92 , 92 ), "gray36" },
1654 { RGB_TO_ULONG(92 , 92 , 92 ), "grey36" },
1655 { RGB_TO_ULONG(94 , 94 , 94 ), "gray37" },
1656 { RGB_TO_ULONG(94 , 94 , 94 ), "grey37" },
1657 { RGB_TO_ULONG(97 , 97 , 97 ), "gray38" },
1658 { RGB_TO_ULONG(97 , 97 , 97 ), "grey38" },
1659 { RGB_TO_ULONG(99 , 99 , 99 ), "gray39" },
1660 { RGB_TO_ULONG(99 , 99 , 99 ), "grey39" },
1661 { RGB_TO_ULONG(102, 102, 102), "gray40" },
1662 { RGB_TO_ULONG(102, 102, 102), "grey40" },
1663 { RGB_TO_ULONG(105, 105, 105), "gray41" },
1664 { RGB_TO_ULONG(105, 105, 105), "grey41" },
1665 { RGB_TO_ULONG(107, 107, 107), "gray42" },
1666 { RGB_TO_ULONG(107, 107, 107), "grey42" },
1667 { RGB_TO_ULONG(110, 110, 110), "gray43" },
1668 { RGB_TO_ULONG(110, 110, 110), "grey43" },
1669 { RGB_TO_ULONG(112, 112, 112), "gray44" },
1670 { RGB_TO_ULONG(112, 112, 112), "grey44" },
1671 { RGB_TO_ULONG(115, 115, 115), "gray45" },
1672 { RGB_TO_ULONG(115, 115, 115), "grey45" },
1673 { RGB_TO_ULONG(117, 117, 117), "gray46" },
1674 { RGB_TO_ULONG(117, 117, 117), "grey46" },
1675 { RGB_TO_ULONG(120, 120, 120), "gray47" },
1676 { RGB_TO_ULONG(120, 120, 120), "grey47" },
1677 { RGB_TO_ULONG(122, 122, 122), "gray48" },
1678 { RGB_TO_ULONG(122, 122, 122), "grey48" },
1679 { RGB_TO_ULONG(125, 125, 125), "gray49" },
1680 { RGB_TO_ULONG(125, 125, 125), "grey49" },
1681 { RGB_TO_ULONG(127, 127, 127), "gray50" },
1682 { RGB_TO_ULONG(127, 127, 127), "grey50" },
1683 { RGB_TO_ULONG(130, 130, 130), "gray51" },
1684 { RGB_TO_ULONG(130, 130, 130), "grey51" },
1685 { RGB_TO_ULONG(133, 133, 133), "gray52" },
1686 { RGB_TO_ULONG(133, 133, 133), "grey52" },
1687 { RGB_TO_ULONG(135, 135, 135), "gray53" },
1688 { RGB_TO_ULONG(135, 135, 135), "grey53" },
1689 { RGB_TO_ULONG(138, 138, 138), "gray54" },
1690 { RGB_TO_ULONG(138, 138, 138), "grey54" },
1691 { RGB_TO_ULONG(140, 140, 140), "gray55" },
1692 { RGB_TO_ULONG(140, 140, 140), "grey55" },
1693 { RGB_TO_ULONG(143, 143, 143), "gray56" },
1694 { RGB_TO_ULONG(143, 143, 143), "grey56" },
1695 { RGB_TO_ULONG(145, 145, 145), "gray57" },
1696 { RGB_TO_ULONG(145, 145, 145), "grey57" },
1697 { RGB_TO_ULONG(148, 148, 148), "gray58" },
1698 { RGB_TO_ULONG(148, 148, 148), "grey58" },
1699 { RGB_TO_ULONG(150, 150, 150), "gray59" },
1700 { RGB_TO_ULONG(150, 150, 150), "grey59" },
1701 { RGB_TO_ULONG(153, 153, 153), "gray60" },
1702 { RGB_TO_ULONG(153, 153, 153), "grey60" },
1703 { RGB_TO_ULONG(156, 156, 156), "gray61" },
1704 { RGB_TO_ULONG(156, 156, 156), "grey61" },
1705 { RGB_TO_ULONG(158, 158, 158), "gray62" },
1706 { RGB_TO_ULONG(158, 158, 158), "grey62" },
1707 { RGB_TO_ULONG(161, 161, 161), "gray63" },
1708 { RGB_TO_ULONG(161, 161, 161), "grey63" },
1709 { RGB_TO_ULONG(163, 163, 163), "gray64" },
1710 { RGB_TO_ULONG(163, 163, 163), "grey64" },
1711 { RGB_TO_ULONG(166, 166, 166), "gray65" },
1712 { RGB_TO_ULONG(166, 166, 166), "grey65" },
1713 { RGB_TO_ULONG(168, 168, 168), "gray66" },
1714 { RGB_TO_ULONG(168, 168, 168), "grey66" },
1715 { RGB_TO_ULONG(171, 171, 171), "gray67" },
1716 { RGB_TO_ULONG(171, 171, 171), "grey67" },
1717 { RGB_TO_ULONG(173, 173, 173), "gray68" },
1718 { RGB_TO_ULONG(173, 173, 173), "grey68" },
1719 { RGB_TO_ULONG(176, 176, 176), "gray69" },
1720 { RGB_TO_ULONG(176, 176, 176), "grey69" },
1721 { RGB_TO_ULONG(179, 179, 179), "gray70" },
1722 { RGB_TO_ULONG(179, 179, 179), "grey70" },
1723 { RGB_TO_ULONG(181, 181, 181), "gray71" },
1724 { RGB_TO_ULONG(181, 181, 181), "grey71" },
1725 { RGB_TO_ULONG(184, 184, 184), "gray72" },
1726 { RGB_TO_ULONG(184, 184, 184), "grey72" },
1727 { RGB_TO_ULONG(186, 186, 186), "gray73" },
1728 { RGB_TO_ULONG(186, 186, 186), "grey73" },
1729 { RGB_TO_ULONG(189, 189, 189), "gray74" },
1730 { RGB_TO_ULONG(189, 189, 189), "grey74" },
1731 { RGB_TO_ULONG(191, 191, 191), "gray75" },
1732 { RGB_TO_ULONG(191, 191, 191), "grey75" },
1733 { RGB_TO_ULONG(194, 194, 194), "gray76" },
1734 { RGB_TO_ULONG(194, 194, 194), "grey76" },
1735 { RGB_TO_ULONG(196, 196, 196), "gray77" },
1736 { RGB_TO_ULONG(196, 196, 196), "grey77" },
1737 { RGB_TO_ULONG(199, 199, 199), "gray78" },
1738 { RGB_TO_ULONG(199, 199, 199), "grey78" },
1739 { RGB_TO_ULONG(201, 201, 201), "gray79" },
1740 { RGB_TO_ULONG(201, 201, 201), "grey79" },
1741 { RGB_TO_ULONG(204, 204, 204), "gray80" },
1742 { RGB_TO_ULONG(204, 204, 204), "grey80" },
1743 { RGB_TO_ULONG(207, 207, 207), "gray81" },
1744 { RGB_TO_ULONG(207, 207, 207), "grey81" },
1745 { RGB_TO_ULONG(209, 209, 209), "gray82" },
1746 { RGB_TO_ULONG(209, 209, 209), "grey82" },
1747 { RGB_TO_ULONG(212, 212, 212), "gray83" },
1748 { RGB_TO_ULONG(212, 212, 212), "grey83" },
1749 { RGB_TO_ULONG(214, 214, 214), "gray84" },
1750 { RGB_TO_ULONG(214, 214, 214), "grey84" },
1751 { RGB_TO_ULONG(217, 217, 217), "gray85" },
1752 { RGB_TO_ULONG(217, 217, 217), "grey85" },
1753 { RGB_TO_ULONG(219, 219, 219), "gray86" },
1754 { RGB_TO_ULONG(219, 219, 219), "grey86" },
1755 { RGB_TO_ULONG(222, 222, 222), "gray87" },
1756 { RGB_TO_ULONG(222, 222, 222), "grey87" },
1757 { RGB_TO_ULONG(224, 224, 224), "gray88" },
1758 { RGB_TO_ULONG(224, 224, 224), "grey88" },
1759 { RGB_TO_ULONG(227, 227, 227), "gray89" },
1760 { RGB_TO_ULONG(227, 227, 227), "grey89" },
1761 { RGB_TO_ULONG(229, 229, 229), "gray90" },
1762 { RGB_TO_ULONG(229, 229, 229), "grey90" },
1763 { RGB_TO_ULONG(232, 232, 232), "gray91" },
1764 { RGB_TO_ULONG(232, 232, 232), "grey91" },
1765 { RGB_TO_ULONG(235, 235, 235), "gray92" },
1766 { RGB_TO_ULONG(235, 235, 235), "grey92" },
1767 { RGB_TO_ULONG(237, 237, 237), "gray93" },
1768 { RGB_TO_ULONG(237, 237, 237), "grey93" },
1769 { RGB_TO_ULONG(240, 240, 240), "gray94" },
1770 { RGB_TO_ULONG(240, 240, 240), "grey94" },
1771 { RGB_TO_ULONG(242, 242, 242), "gray95" },
1772 { RGB_TO_ULONG(242, 242, 242), "grey95" },
1773 { RGB_TO_ULONG(245, 245, 245), "gray96" },
1774 { RGB_TO_ULONG(245, 245, 245), "grey96" },
1775 { RGB_TO_ULONG(247, 247, 247), "gray97" },
1776 { RGB_TO_ULONG(247, 247, 247), "grey97" },
1777 { RGB_TO_ULONG(250, 250, 250), "gray98" },
1778 { RGB_TO_ULONG(250, 250, 250), "grey98" },
1779 { RGB_TO_ULONG(252, 252, 252), "gray99" },
1780 { RGB_TO_ULONG(252, 252, 252), "grey99" },
1781 { RGB_TO_ULONG(255, 255, 255), "gray100" },
1782 { RGB_TO_ULONG(255, 255, 255), "grey100" },
1783 { RGB_TO_ULONG(169, 169, 169), "dark grey" },
1784 { RGB_TO_ULONG(169, 169, 169), "DarkGrey" },
1785 { RGB_TO_ULONG(169, 169, 169), "dark gray" },
1786 { RGB_TO_ULONG(169, 169, 169), "DarkGray" },
1787 { RGB_TO_ULONG(0 , 0 , 139), "dark blue" },
1788 { RGB_TO_ULONG(0 , 0 , 139), "DarkBlue" },
1789 { RGB_TO_ULONG(0 , 139, 139), "dark cyan" },
1790 { RGB_TO_ULONG(0 , 139, 139), "DarkCyan" },
1791 { RGB_TO_ULONG(139, 0 , 139), "dark magenta" },
1792 { RGB_TO_ULONG(139, 0 , 139), "DarkMagenta" },
1793 { RGB_TO_ULONG(139, 0 , 0 ), "dark red" },
1794 { RGB_TO_ULONG(139, 0 , 0 ), "DarkRed" },
1795 { RGB_TO_ULONG(144, 238, 144), "light green" },
1796 { RGB_TO_ULONG(144, 238, 144), "LightGreen" }
1799 unsigned long
1800 mac_color_map_lookup (colorname)
1801 char *colorname;
1803 Lisp_Object ret = Qnil;
1804 int i;
1806 BLOCK_INPUT;
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)
1811 ret = mac_color_map[i].color;
1812 break;
1815 UNBLOCK_INPUT;
1817 return ret;
1820 Lisp_Object
1821 x_to_mac_color (colorname)
1822 char * colorname;
1824 register Lisp_Object tail, ret = Qnil;
1826 BLOCK_INPUT;
1828 if (colorname[0] == '#')
1830 /* Could be an old-style RGB Device specification. */
1831 char *color;
1832 int size;
1833 color = colorname + 1;
1835 size = strlen(color);
1836 if (size == 3 || size == 6 || size == 9 || size == 12)
1838 unsigned long colorval;
1839 int i, pos;
1840 pos = 0;
1841 size /= 3;
1842 colorval = 0;
1844 for (i = 0; i < 3; i++)
1846 char *end;
1847 char t;
1848 unsigned long value;
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)
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;
1875 colorval |= (value << pos);
1876 pos += 0x8;
1877 if (i == 2)
1879 UNBLOCK_INPUT;
1880 return (colorval);
1882 color = end;
1886 else if (strnicmp(colorname, "rgb:", 4) == 0)
1888 char *color;
1889 unsigned long colorval;
1890 int i, pos;
1891 pos = 0;
1893 colorval = 0;
1894 color = colorname + 4;
1895 for (i = 0; i < 3; i++)
1897 char *end;
1898 unsigned long value;
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)
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;
1924 if (value == ULONG_MAX)
1925 break;
1926 colorval |= (value << pos);
1927 pos += 0x8;
1928 if (i == 2)
1930 if (*end != '\0')
1931 break;
1932 UNBLOCK_INPUT;
1933 return (colorval);
1935 if (*end != '/')
1936 break;
1937 color = end + 1;
1940 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1942 /* This is an RGB Intensity specification. */
1943 char *color;
1944 unsigned long colorval;
1945 int i, pos;
1946 pos = 0;
1948 colorval = 0;
1949 color = colorname + 5;
1950 for (i = 0; i < 3; i++)
1952 char *end;
1953 double value;
1954 unsigned long val;
1956 value = strtod(color, &end);
1957 if (errno == ERANGE)
1958 break;
1959 if (value < 0.0 || value > 1.0)
1960 break;
1961 val = (unsigned long)(0x100 * value);
1962 /* We used 0x100 instead of 0xFF to give a continuous
1963 range between 0.0 and 1.0 inclusive. The next statement
1964 fixes the 1.0 case. */
1965 if (val == 0x100)
1966 val = 0xFF;
1967 colorval |= (val << pos);
1968 pos += 0x8;
1969 if (i == 2)
1971 if (*end != '\0')
1972 break;
1973 UNBLOCK_INPUT;
1974 return (colorval);
1976 if (*end != '/')
1977 break;
1978 color = end + 1;
1982 ret = mac_color_map_lookup (colorname);
1984 UNBLOCK_INPUT;
1985 return ret;
1988 /* Gamma-correct COLOR on frame F. */
1990 void
1991 gamma_correct (f, color)
1992 struct frame *f;
1993 unsigned long *color;
1995 if (f->gamma)
1997 unsigned long red, green, blue;
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);
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. */
2011 mac_defined_color (f, color, color_def, alloc)
2012 FRAME_PTR f;
2013 char *color;
2014 XColor *color_def;
2015 int alloc;
2017 register Lisp_Object tem;
2018 unsigned long mac_color_ref;
2020 tem = x_to_mac_color (color);
2022 if (!NILP (tem))
2024 if (f)
2026 /* Apply gamma correction. */
2027 mac_color_ref = XUINT (tem);
2028 gamma_correct (f, &mac_color_ref);
2029 XSETINT (tem, mac_color_ref);
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);
2037 return 1;
2039 else
2041 return 0;
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. */
2051 x_decode_color (f, arg, def)
2052 FRAME_PTR f;
2053 Lisp_Object arg;
2054 int def;
2056 XColor cdef;
2058 CHECK_STRING (arg);
2060 if (strcmp (SDATA (arg), "black") == 0)
2061 return BLACK_PIX_DEFAULT (f);
2062 else if (strcmp (SDATA (arg), "white") == 0)
2063 return WHITE_PIX_DEFAULT (f);
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
2071 if (mac_defined_color (f, SDATA (arg), &cdef, 1))
2072 return cdef.pixel;
2074 /* defined_color failed; return an ultimate default. */
2075 return def;
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. */
2081 static void
2082 x_set_line_spacing (f, new_value, old_value)
2083 struct frame *f;
2084 Lisp_Object new_value, old_value;
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);
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. */
2101 static void
2102 x_set_screen_gamma (f, new_value, old_value)
2103 struct frame *f;
2104 Lisp_Object new_value, old_value;
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)));
2115 clear_face_cache (0);
2119 /* Functions called only from `x_set_frame_param'
2120 to set individual parameters.
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. */
2127 void
2128 x_set_foreground_color (f, arg, oldval)
2129 struct frame *f;
2130 Lisp_Object arg, oldval;
2132 FRAME_FOREGROUND_PIXEL (f)
2133 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2135 if (FRAME_MAC_WINDOW (f) != 0)
2137 update_face_from_frame_parameter (f, Qforeground_color, arg);
2138 if (FRAME_VISIBLE_P (f))
2139 redraw_frame (f);
2143 void
2144 x_set_background_color (f, arg, oldval)
2145 struct frame *f;
2146 Lisp_Object arg, oldval;
2148 FRAME_BACKGROUND_PIXEL (f)
2149 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2151 if (FRAME_MAC_WINDOW (f) != 0)
2153 update_face_from_frame_parameter (f, Qbackground_color, arg);
2155 if (FRAME_VISIBLE_P (f))
2156 redraw_frame (f);
2160 void
2161 x_set_mouse_color (f, arg, oldval)
2162 struct frame *f;
2163 Lisp_Object arg, oldval;
2165 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2166 int count;
2167 int mask_color;
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);
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);
2179 #if 0 /* MAC_TODO : cursor changes */
2180 BLOCK_INPUT;
2182 /* It's not okay to crash if the user selects a screwy cursor. */
2183 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2185 if (!EQ (Qnil, Vx_pointer_shape))
2187 CHECK_NUMBER (Vx_pointer_shape);
2188 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2190 else
2191 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2192 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2194 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2196 CHECK_NUMBER (Vx_nontext_pointer_shape);
2197 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2198 XINT (Vx_nontext_pointer_shape));
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");
2204 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2206 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2207 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2208 XINT (Vx_hourglass_pointer_shape));
2210 else
2211 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2212 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2214 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2215 if (!EQ (Qnil, Vx_mode_pointer_shape))
2217 CHECK_NUMBER (Vx_mode_pointer_shape);
2218 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2219 XINT (Vx_mode_pointer_shape));
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");
2225 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2227 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2228 cross_cursor
2229 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2230 XINT (Vx_sensitive_text_pointer_shape));
2232 else
2233 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2235 if (!NILP (Vx_window_horizontal_drag_shape))
2237 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2238 horizontal_drag_cursor
2239 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2240 XINT (Vx_window_horizontal_drag_shape));
2242 else
2243 horizontal_drag_cursor
2244 = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_sb_h_double_arrow);
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);
2251 XColor fore_color, back_color;
2253 fore_color.pixel = f->output_data.w32->mouse_pixel;
2254 back_color.pixel = mask_color;
2255 XQueryColor (FRAME_W32_DISPLAY (f),
2256 DefaultColormap (FRAME_W32_DISPLAY (f),
2257 DefaultScreen (FRAME_W32_DISPLAY (f))),
2258 &fore_color);
2259 XQueryColor (FRAME_W32_DISPLAY (f),
2260 DefaultColormap (FRAME_W32_DISPLAY (f),
2261 DefaultScreen (FRAME_W32_DISPLAY (f))),
2262 &back_color);
2263 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2264 &fore_color, &back_color);
2265 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2266 &fore_color, &back_color);
2267 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2268 &fore_color, &back_color);
2269 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2270 &fore_color, &back_color);
2271 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2272 &fore_color, &back_color);
2275 if (FRAME_W32_WINDOW (f) != 0)
2276 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
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;
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;
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;
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;
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;
2302 XFlush (FRAME_W32_DISPLAY (f));
2303 UNBLOCK_INPUT;
2305 update_face_from_frame_parameter (f, Qmouse_color, arg);
2306 #endif /* MAC_TODO */
2309 void
2310 x_set_cursor_color (f, arg, oldval)
2311 struct frame *f;
2312 Lisp_Object arg, oldval;
2314 unsigned long fore_pixel;
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));
2323 /* Make sure that the cursor color differs from the background color. */
2324 if (f->output_data.mac->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
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);
2330 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2332 #if 0 /* MAC_TODO: cannot figure out what to do (wrong number of params) */
2333 if (FRAME_MAC_WINDOW (f) != 0)
2335 if (FRAME_VISIBLE_P (f))
2337 x_display_cursor (f, 0);
2338 x_display_cursor (f, 1);
2341 #endif
2343 update_face_from_frame_parameter (f, Qcursor_color, arg);
2346 /* Set the border-color of frame F to pixel value PIX.
2347 Note that this does not fully take effect if done before
2348 F has a window. */
2349 void
2350 x_set_border_pixel (f, pix)
2351 struct frame *f;
2352 int pix;
2354 f->output_data.mac->border_pixel = pix;
2356 if (FRAME_MAC_WINDOW (f) != 0 && f->output_data.mac->border_width > 0)
2358 if (FRAME_VISIBLE_P (f))
2359 redraw_frame (f);
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. */
2369 void
2370 x_set_border_color (f, arg, oldval)
2371 struct frame *f;
2372 Lisp_Object arg, oldval;
2374 int pix;
2376 CHECK_STRING (arg);
2377 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2378 x_set_border_pixel (f, pix);
2379 update_face_from_frame_parameter (f, Qborder_color, arg);
2382 void
2383 x_set_cursor_type (f, arg, oldval)
2384 FRAME_PTR f;
2385 Lisp_Object arg, oldval;
2387 set_frame_cursor_types (f, arg);
2389 /* Make sure the cursor gets redrawn. This is overkill, but how
2390 often do people change cursor types? */
2391 update_mode_lines++;
2394 #if 0 /* MAC_TODO: really no icon for Mac */
2395 void
2396 x_set_icon_type (f, arg, oldval)
2397 struct frame *f;
2398 Lisp_Object arg, oldval;
2400 int result;
2402 if (NILP (arg) && NILP (oldval))
2403 return;
2405 if (STRINGP (arg) && STRINGP (oldval)
2406 && EQ (Fstring_equal (oldval, arg), Qt))
2407 return;
2409 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2410 return;
2412 BLOCK_INPUT;
2414 result = x_bitmap_icon (f, arg);
2415 if (result)
2417 UNBLOCK_INPUT;
2418 error ("No icon window available");
2421 UNBLOCK_INPUT;
2423 #endif /* MAC_TODO */
2425 /* Return non-nil if frame F wants a bitmap icon. */
2427 Lisp_Object
2428 x_icon_type (f)
2429 FRAME_PTR f;
2431 Lisp_Object tem;
2433 tem = assq_no_quit (Qicon_type, f->param_alist);
2434 if (CONSP (tem))
2435 return XCDR (tem);
2436 else
2437 return Qnil;
2440 void
2441 x_set_icon_name (f, arg, oldval)
2442 struct frame *f;
2443 Lisp_Object arg, oldval;
2445 int result;
2447 if (STRINGP (arg))
2449 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2450 return;
2452 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2453 return;
2455 f->icon_name = arg;
2457 #if 0 /* MAC_TODO */
2458 if (f->output_data.w32->icon_bitmap != 0)
2459 return;
2461 BLOCK_INPUT;
2463 result = x_text_icon (f,
2464 (char *) SDATA ((!NILP (f->icon_name)
2465 ? f->icon_name
2466 : !NILP (f->title)
2467 ? f->title
2468 : f->name)));
2470 if (result)
2472 UNBLOCK_INPUT;
2473 error ("No icon window available");
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))
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));
2486 XFlush (FRAME_W32_DISPLAY (f));
2487 UNBLOCK_INPUT;
2488 #endif /* MAC_TODO */
2491 extern Lisp_Object x_new_font ();
2492 extern Lisp_Object x_new_fontset();
2494 void
2495 x_set_font (f, arg, oldval)
2496 struct frame *f;
2497 Lisp_Object arg, oldval;
2499 Lisp_Object result;
2500 Lisp_Object fontset_name;
2501 Lisp_Object frame;
2502 int old_fontset = FRAME_FONTSET(f);
2504 CHECK_STRING (arg);
2506 fontset_name = Fquery_fontset (arg, Qnil);
2508 BLOCK_INPUT;
2509 result = (STRINGP (fontset_name)
2510 ? x_new_fontset (f, SDATA (fontset_name))
2511 : x_new_font (f, SDATA (arg)));
2512 UNBLOCK_INPUT;
2514 if (EQ (result, Qnil))
2515 error ("Font `%s' is not defined", SDATA (arg));
2516 else if (EQ (result, Qt))
2517 error ("The characters of the given font have varying widths");
2518 else if (STRINGP (result))
2520 if (STRINGP (fontset_name))
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;
2527 else if (!NILP (Fequal (result, oldval)))
2528 return;
2530 store_frame_param (f, Qfont, result);
2531 recompute_basic_faces (f);
2533 else
2534 abort ();
2536 do_pending_window_change (0);
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))
2545 XSETFRAME (frame, f);
2546 call1 (Qface_set_after_frame_default, frame);
2550 void
2551 x_set_border_width (f, arg, oldval)
2552 struct frame *f;
2553 Lisp_Object arg, oldval;
2555 CHECK_NUMBER (arg);
2557 if (XINT (arg) == f->output_data.mac->border_width)
2558 return;
2560 #if 0 /* MAC_TODO */
2561 if (FRAME_MAC_WINDOW (f) != 0)
2562 error ("Cannot change the border width of a window");
2563 #endif
2565 f->output_data.mac->border_width = XINT (arg);
2568 void
2569 x_set_internal_border_width (f, arg, oldval)
2570 struct frame *f;
2571 Lisp_Object arg, oldval;
2573 int old = f->output_data.mac->internal_border_width;
2575 CHECK_NUMBER (arg);
2576 f->output_data.mac->internal_border_width = XINT (arg);
2577 if (f->output_data.mac->internal_border_width < 0)
2578 f->output_data.mac->internal_border_width = 0;
2580 if (f->output_data.mac->internal_border_width == old)
2581 return;
2583 if (FRAME_MAC_WINDOW (f) != 0)
2585 x_set_window_size (f, 0, f->width, f->height);
2586 SET_FRAME_GARBAGED (f);
2587 do_pending_window_change (0);
2589 else
2590 SET_FRAME_GARBAGED (f);
2593 void
2594 x_set_visibility (f, value, oldval)
2595 struct frame *f;
2596 Lisp_Object value, oldval;
2598 Lisp_Object frame;
2599 XSETFRAME (frame, f);
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);
2610 /* Change window heights in windows rooted in WINDOW by N lines. */
2612 static void
2613 x_change_window_heights (window, n)
2614 Lisp_Object window;
2615 int n;
2617 struct window *w = XWINDOW (window);
2619 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2620 XSETFASTINT (w->height, XFASTINT (w->height) - n);
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);
2627 /* Handle just the top child in a vertical split. */
2628 if (!NILP (w->vchild))
2629 x_change_window_heights (w->vchild, n);
2631 /* Adjust all children in a horizontal split. */
2632 for (window = w->hchild; !NILP (window); window = w->next)
2634 w = XWINDOW (window);
2635 x_change_window_heights (window, n);
2639 void
2640 x_set_menu_bar_lines (f, value, oldval)
2641 struct frame *f;
2642 Lisp_Object value, oldval;
2644 int nlines;
2645 int olines = FRAME_MENU_BAR_LINES (f);
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;
2654 if (INTEGERP (value))
2655 nlines = XINT (value);
2656 else
2657 nlines = 0;
2659 FRAME_MENU_BAR_LINES (f) = 0;
2660 if (nlines)
2661 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2662 else
2664 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2665 free_frame_menubar (f);
2666 FRAME_EXTERNAL_MENU_BAR (f) = 0;
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);
2674 adjust_glyphs (f);
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. */
2684 void
2685 x_set_tool_bar_lines (f, value, oldval)
2686 struct frame *f;
2687 Lisp_Object value, oldval;
2689 int delta, nlines, root_height;
2690 Lisp_Object root_window;
2692 /* Treat tool bars like menu bars. */
2693 if (FRAME_MINIBUF_ONLY_P (f))
2694 return;
2696 /* Use VALUE only if an integer >= 0. */
2697 if (INTEGERP (value) && XINT (value) >= 0)
2698 nlines = XFASTINT (value);
2699 else
2700 nlines = 0;
2702 /* Make sure we redisplay all windows in this frame. */
2703 ++windows_or_buffers_changed;
2705 delta = nlines - FRAME_TOOL_BAR_LINES (f);
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)
2712 delta = root_height - 1;
2713 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2716 FRAME_TOOL_BAR_LINES (f) = nlines;
2717 x_change_window_heights (root_window, delta);
2718 adjust_glyphs (f);
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)
2728 updating_frame = f;
2729 clear_frame ();
2730 clear_current_matrices (f);
2731 updating_frame = NULL;
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)
2739 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2740 int width = PIXEL_WIDTH (f);
2741 int y = nlines * CANON_Y_UNIT (f);
2743 BLOCK_INPUT;
2744 XClearArea (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f),
2745 0, y, width, height, 0);
2746 UNBLOCK_INPUT;
2748 if (WINDOWP (f->tool_bar_window))
2749 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2754 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2755 w32_id_name.
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.
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. */
2765 void
2766 x_set_name (f, name, explicit)
2767 struct frame *f;
2768 Lisp_Object name;
2769 int explicit;
2771 /* Make sure that requests from lisp code override requests from
2772 Emacs redisplay code. */
2773 if (explicit)
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;
2780 f->explicit_name = ! NILP (name);
2782 else if (f->explicit_name)
2783 return;
2785 /* If NAME is nil, set the name to the w32_id_name. */
2786 if (NILP (name))
2788 /* Check for no change needed in this very common case
2789 before we do any consing. */
2790 if (!strcmp (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name,
2791 SDATA (f->name)))
2792 return;
2793 name = build_string (FRAME_MAC_DISPLAY_INFO (f)->mac_id_name);
2795 else
2796 CHECK_STRING (name);
2798 /* Don't change the name if it's already NAME. */
2799 if (! NILP (Fstring_equal (name, f->name)))
2800 return;
2802 f->name = name;
2804 /* For setting the frame title, the title parameter should override
2805 the name parameter. */
2806 if (! NILP (f->title))
2807 name = f->title;
2809 if (FRAME_MAC_WINDOW (f))
2811 if (STRING_MULTIBYTE (name))
2812 #if 0 /* MAC_TODO: encoding title string */
2813 name = ENCODE_SYSTEM (name);
2814 #else
2815 return;
2816 #endif
2818 BLOCK_INPUT;
2821 Str255 windowTitle;
2822 if (strlen (SDATA (name)) < 255)
2824 strcpy (windowTitle, SDATA (name));
2825 c2pstr (windowTitle);
2826 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2830 UNBLOCK_INPUT;
2834 /* This function should be called when the user's lisp code has
2835 specified a name for the frame; the name will override any set by the
2836 redisplay code. */
2837 void
2838 x_explicitly_set_name (f, arg, oldval)
2839 FRAME_PTR f;
2840 Lisp_Object arg, oldval;
2842 x_set_name (f, arg, 1);
2845 /* This function should be called by Emacs redisplay code to set the
2846 name; names set this way will never override names set by the user's
2847 lisp code. */
2848 void
2849 x_implicitly_set_name (f, arg, oldval)
2850 FRAME_PTR f;
2851 Lisp_Object arg, oldval;
2853 x_set_name (f, arg, 0);
2856 /* Change the title of frame F to NAME.
2857 If NAME is nil, use the frame name as the title.
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.
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. */
2867 void
2868 x_set_title (f, name, old_name)
2869 struct frame *f;
2870 Lisp_Object name, old_name;
2872 /* Don't change the title if it's already NAME. */
2873 if (EQ (name, f->title))
2874 return;
2876 update_mode_lines = 1;
2878 f->title = name;
2880 if (NILP (name))
2881 name = f->name;
2883 if (FRAME_MAC_WINDOW (f))
2885 if (STRING_MULTIBYTE (name))
2886 #if 0 /* MAC_TODO: encoding title string */
2887 name = ENCODE_SYSTEM (name);
2888 #else
2889 return;
2890 #endif
2892 BLOCK_INPUT;
2895 Str255 windowTitle;
2896 if (strlen (SDATA (name)) < 255)
2898 strcpy (windowTitle, SDATA (name));
2899 c2pstr (windowTitle);
2900 SetWTitle (FRAME_MAC_WINDOW (f), windowTitle);
2904 UNBLOCK_INPUT;
2908 void
2909 x_set_autoraise (f, arg, oldval)
2910 struct frame *f;
2911 Lisp_Object arg, oldval;
2913 f->auto_raise = !EQ (Qnil, arg);
2916 void
2917 x_set_autolower (f, arg, oldval)
2918 struct frame *f;
2919 Lisp_Object arg, oldval;
2921 f->auto_lower = !EQ (Qnil, arg);
2924 void
2925 x_set_unsplittable (f, arg, oldval)
2926 struct frame *f;
2927 Lisp_Object arg, oldval;
2929 f->no_split = !NILP (arg);
2932 void
2933 x_set_vertical_scroll_bars (f, arg, oldval)
2934 struct frame *f;
2935 Lisp_Object arg, oldval;
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)))
2942 FRAME_VERTICAL_SCROLL_BAR_TYPE (f)
2943 = (NILP (arg)
2944 ? vertical_scroll_bar_none
2945 : EQ (Qright, arg)
2946 ? vertical_scroll_bar_right
2947 : vertical_scroll_bar_left);
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);
2959 void
2960 x_set_scroll_bar_width (f, arg, oldval)
2961 struct frame *f;
2962 Lisp_Object arg, oldval;
2964 /* Imitate X without X Toolkit */
2966 int wid = FONT_WIDTH (f->output_data.mac->font);
2968 if (NILP (arg))
2970 #ifdef MAC_OSX
2971 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 16; /* Aqua scroll bars. */
2972 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2973 wid - 1) / wid;
2974 #else /* not MAC_OSX */
2975 /* Make the actual width at least 14 pixels and a multiple of a
2976 character width. */
2977 FRAME_SCROLL_BAR_COLS (f) = (14 + wid - 1) / wid;
2979 /* Use all of that space (aside from required margins) for the
2980 scroll bar. */
2981 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = 0;
2982 #endif /* not MAC_OSX */
2983 if (FRAME_MAC_WINDOW (f))
2984 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2985 do_pending_window_change (0);
2987 else if (INTEGERP (arg) && XINT (arg) > 0
2988 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2990 if (XFASTINT (arg) <= 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM)
2991 XSETINT (arg, 2 * VERTICAL_SCROLL_BAR_WIDTH_TRIM + 1);
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);
2999 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
3000 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
3001 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
3004 /* Subroutines of creating a frame. */
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. */
3009 static void
3010 validate_x_resource_name ()
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;
3020 if (STRINGP (Vx_resource_name))
3022 unsigned char *p = SDATA (Vx_resource_name);
3023 int i;
3025 len = SBYTES (Vx_resource_name);
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++)
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++;
3041 else
3042 /* Not a string => completely invalid. */
3043 bad_count = 5, good_count = 0;
3045 /* If name is valid already, return. */
3046 if (bad_count == 0)
3047 return;
3049 /* If name is entirely invalid, or nearly so, use `emacs'. */
3050 if (good_count == 0
3051 || (good_count == 1 && bad_count > 0))
3053 Vx_resource_name = build_string ("emacs");
3054 return;
3057 /* Name is partly valid. Copy it and replace the invalid characters
3058 with underscores. */
3060 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3062 for (i = 0; i < len; i++)
3064 int c = SREF (new, i);
3065 if (! ((c >= 'a' && c <= 'z')
3066 || (c >= 'A' && c <= 'Z')
3067 || (c >= '0' && c <= '9')
3068 || c == '-' || c == '_'))
3069 SSET (new, i, '_');
3074 #if 0 /* MAC_TODO: implement resource strings */
3075 extern char *x_get_string_resource ();
3077 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3078 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3079 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3080 class, where INSTANCE is the name under which Emacs was invoked, or
3081 the name specified by the `-name' or `-rn' command-line arguments.
3083 The optional arguments COMPONENT and SUBCLASS add to the key and the
3084 class, respectively. You must specify both of them or neither.
3085 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3086 and the class is `Emacs.CLASS.SUBCLASS'. */)
3087 (attribute, class, component, subclass)
3088 Lisp_Object attribute, class, component, subclass;
3090 register char *value;
3091 char *name_key;
3092 char *class_key;
3094 CHECK_STRING (attribute);
3095 CHECK_STRING (class);
3097 if (!NILP (component))
3098 CHECK_STRING (component);
3099 if (!NILP (subclass))
3100 CHECK_STRING (subclass);
3101 if (NILP (component) != NILP (subclass))
3102 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3104 validate_x_resource_name ();
3106 /* Allocate space for the components, the dots which separate them,
3107 and the final '\0'. Make them big enough for the worst case. */
3108 name_key = (char *) alloca (SBYTES (Vx_resource_name)
3109 + (STRINGP (component)
3110 ? SBYTES (component) : 0)
3111 + SBYTES (attribute)
3112 + 3);
3114 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3115 + SBYTES (class)
3116 + (STRINGP (subclass)
3117 ? SBYTES (subclass) : 0)
3118 + 3);
3120 /* Start with emacs.FRAMENAME for the name (the specific one)
3121 and with `Emacs' for the class key (the general one). */
3122 strcpy (name_key, SDATA (Vx_resource_name));
3123 strcpy (class_key, EMACS_CLASS);
3125 strcat (class_key, ".");
3126 strcat (class_key, SDATA (class));
3128 if (!NILP (component))
3130 strcat (class_key, ".");
3131 strcat (class_key, SDATA (subclass));
3133 strcat (name_key, ".");
3134 strcat (name_key, SDATA (component));
3137 strcat (name_key, ".");
3138 strcat (name_key, SDATA (attribute));
3140 value = x_get_string_resource (Qnil,
3141 name_key, class_key);
3143 if (value != (char *) 0)
3144 return build_string (value);
3145 else
3146 return Qnil;
3149 /* Used when C code wants a resource value. */
3151 char *
3152 x_get_resource_string (attribute, class)
3153 char *attribute, *class;
3155 char *name_key;
3156 char *class_key;
3157 struct frame *sf = SELECTED_FRAME ();
3159 /* Allocate space for the components, the dots which separate them,
3160 and the final '\0'. */
3161 name_key = (char *) alloca (SBYTES (Vinvocation_name)
3162 + strlen (attribute) + 2);
3163 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3164 + strlen (class) + 2);
3166 sprintf (name_key, "%s.%s",
3167 SDATA (Vinvocation_name),
3168 attribute);
3169 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3171 return x_get_string_resource (sf, name_key, class_key);
3173 #endif /* MAC_TODO */
3175 /* Types we might convert a resource string into. */
3176 enum resource_types
3178 RES_TYPE_NUMBER,
3179 RES_TYPE_FLOAT,
3180 RES_TYPE_BOOLEAN,
3181 RES_TYPE_STRING,
3182 RES_TYPE_SYMBOL
3185 /* Return the value of parameter PARAM.
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.
3190 Convert the resource to the type specified by desired_type.
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! */
3196 static Lisp_Object
3197 mac_get_arg (alist, param, attribute, class, type)
3198 Lisp_Object alist, param;
3199 char *attribute;
3200 char *class;
3201 enum resource_types type;
3203 register Lisp_Object tem;
3205 tem = Fassq (param, alist);
3206 if (EQ (tem, Qnil))
3207 tem = Fassq (param, Vdefault_frame_alist);
3208 if (EQ (tem, Qnil))
3211 #if 0 /* MAC_TODO: search resource also */
3212 if (attribute)
3214 tem = Fx_get_resource (build_string (attribute),
3215 build_string (class),
3216 Qnil, Qnil);
3218 if (NILP (tem))
3219 return Qunbound;
3221 switch (type)
3223 case RES_TYPE_NUMBER:
3224 return make_number (atoi (SDATA (tem)));
3226 case RES_TYPE_FLOAT:
3227 return make_float (atof (SDATA (tem)));
3229 case RES_TYPE_BOOLEAN:
3230 tem = Fdowncase (tem);
3231 if (!strcmp (SDATA (tem), "on")
3232 || !strcmp (SDATA (tem), "true"))
3233 return Qt;
3234 else
3235 return Qnil;
3237 case RES_TYPE_STRING:
3238 return tem;
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. */
3244 Lisp_Object lower;
3245 lower = Fdowncase (tem);
3246 if (!strcmp (SDATA (lower), "on")
3247 || !strcmp (SDATA (lower), "true"))
3248 return Qt;
3249 else if (!strcmp (SDATA (lower), "off")
3250 || !strcmp (SDATA (lower), "false"))
3251 return Qnil;
3252 else
3253 return Fintern (tem, Qnil);
3256 default:
3257 abort ();
3260 else
3261 #endif /* MAC_TODO */
3262 return Qunbound;
3264 return Fcdr (tem);
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. */
3273 static Lisp_Object
3274 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3275 struct frame *f;
3276 Lisp_Object alist;
3277 Lisp_Object prop;
3278 Lisp_Object deflt;
3279 char *xprop;
3280 char *xclass;
3281 enum resource_types type;
3283 Lisp_Object tem;
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;
3292 /* XParseGeometry copied from w32xfns.c */
3295 * XParseGeometry parses strings of the form
3296 * "=<width>x<height>{+-}<xoffset>{+-}<yoffset>", where
3297 * width, height, xoffset, and yoffset are unsigned integers.
3298 * Example: "=80x24+300-49"
3299 * The equal sign is optional.
3300 * It returns a bitmask that indicates which of the four values
3301 * were actually found in the string. For each value found,
3302 * the corresponding argument is updated; for each value
3303 * not found, the corresponding argument is left unchanged.
3306 static int
3307 read_integer (string, NextString)
3308 register char *string;
3309 char **NextString;
3311 register int Result = 0;
3312 int Sign = 1;
3314 if (*string == '+')
3315 string++;
3316 else if (*string == '-')
3318 string++;
3319 Sign = -1;
3321 for (; (*string >= '0') && (*string <= '9'); string++)
3323 Result = (Result * 10) + (*string - '0');
3325 *NextString = string;
3326 if (Sign >= 0)
3327 return (Result);
3328 else
3329 return (-Result);
3333 XParseGeometry (string, x, y, width, height)
3334 char *string;
3335 int *x, *y;
3336 unsigned int *width, *height; /* RETURN */
3338 int mask = NoValue;
3339 register char *strind;
3340 unsigned int tempWidth, tempHeight;
3341 int tempX, tempY;
3342 char *nextCharacter;
3344 if ((string == NULL) || (*string == '\0')) return (mask);
3345 if (*string == '=')
3346 string++; /* ignore possible '=' at beg of geometry spec */
3348 strind = (char *)string;
3349 if (*strind != '+' && *strind != '-' && *strind != 'x')
3351 tempWidth = read_integer (strind, &nextCharacter);
3352 if (strind == nextCharacter)
3353 return (0);
3354 strind = nextCharacter;
3355 mask |= WidthValue;
3358 if (*strind == 'x' || *strind == 'X')
3360 strind++;
3361 tempHeight = read_integer (strind, &nextCharacter);
3362 if (strind == nextCharacter)
3363 return (0);
3364 strind = nextCharacter;
3365 mask |= HeightValue;
3368 if ((*strind == '+') || (*strind == '-'))
3370 if (*strind == '-')
3372 strind++;
3373 tempX = -read_integer (strind, &nextCharacter);
3374 if (strind == nextCharacter)
3375 return (0);
3376 strind = nextCharacter;
3377 mask |= XNegative;
3380 else
3382 strind++;
3383 tempX = read_integer (strind, &nextCharacter);
3384 if (strind == nextCharacter)
3385 return (0);
3386 strind = nextCharacter;
3388 mask |= XValue;
3389 if ((*strind == '+') || (*strind == '-'))
3391 if (*strind == '-')
3393 strind++;
3394 tempY = -read_integer (strind, &nextCharacter);
3395 if (strind == nextCharacter)
3396 return (0);
3397 strind = nextCharacter;
3398 mask |= YNegative;
3401 else
3403 strind++;
3404 tempY = read_integer (strind, &nextCharacter);
3405 if (strind == nextCharacter)
3406 return (0);
3407 strind = nextCharacter;
3409 mask |= YValue;
3413 /* If strind isn't at the end of the string the it's an invalid
3414 geometry specification. */
3416 if (*strind != '\0') return (0);
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);
3429 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3430 doc: /* Parse an X-style geometry string STRING.
3431 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3432 The properties returned may include `top', `left', `height', and `width'.
3433 The value of `left' or `top' may be an integer,
3434 or a list (+ N) meaning N pixels relative to top/left corner,
3435 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3436 (string)
3437 Lisp_Object string;
3439 int geometry, x, y;
3440 unsigned int width, height;
3441 Lisp_Object result;
3443 CHECK_STRING (string);
3445 geometry = XParseGeometry ((char *) SDATA (string),
3446 &x, &y, &width, &height);
3448 result = Qnil;
3449 if (geometry & XValue)
3451 Lisp_Object element;
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);
3462 if (geometry & YValue)
3464 Lisp_Object element;
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);
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);
3480 return result;
3483 /* Calculate the desired size and position of this window,
3484 and return the flags saying which aspects were specified.
3486 This function does not make the coordinates positive. */
3488 #define DEFAULT_ROWS 40
3489 #define DEFAULT_COLS 80
3491 static int
3492 x_figure_window_size (f, parms)
3493 struct frame *f;
3494 Lisp_Object parms;
3496 register Lisp_Object tem0, tem1, tem2;
3497 long window_prompting = 0;
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;
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))
3514 if (!EQ (tem0, Qunbound))
3516 CHECK_NUMBER (tem0);
3517 f->height = XINT (tem0);
3519 if (!EQ (tem1, Qunbound))
3521 CHECK_NUMBER (tem1);
3522 SET_FRAME_WIDTH (f, XINT (tem1));
3524 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3525 window_prompting |= USSize;
3526 else
3527 window_prompting |= PSize;
3530 f->output_data.mac->vertical_scroll_bar_extra
3531 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
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)));
3537 x_compute_fringe_widths (f, 0);
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);
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))
3547 if (EQ (tem0, Qminus))
3549 f->output_data.mac->top_pos = 0;
3550 window_prompting |= YNegative;
3552 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3553 && CONSP (XCDR (tem0))
3554 && INTEGERP (XCAR (XCDR (tem0))))
3556 f->output_data.mac->top_pos = - XINT (XCAR (XCDR (tem0)));
3557 window_prompting |= YNegative;
3559 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3560 && CONSP (XCDR (tem0))
3561 && INTEGERP (XCAR (XCDR (tem0))))
3563 f->output_data.mac->top_pos = XINT (XCAR (XCDR (tem0)));
3565 else if (EQ (tem0, Qunbound))
3566 f->output_data.mac->top_pos = 0;
3567 else
3569 CHECK_NUMBER (tem0);
3570 f->output_data.mac->top_pos = XINT (tem0);
3571 if (f->output_data.mac->top_pos < 0)
3572 window_prompting |= YNegative;
3575 if (EQ (tem1, Qminus))
3577 f->output_data.mac->left_pos = 0;
3578 window_prompting |= XNegative;
3580 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3581 && CONSP (XCDR (tem1))
3582 && INTEGERP (XCAR (XCDR (tem1))))
3584 f->output_data.mac->left_pos = - XINT (XCAR (XCDR (tem1)));
3585 window_prompting |= XNegative;
3587 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3588 && CONSP (XCDR (tem1))
3589 && INTEGERP (XCAR (XCDR (tem1))))
3591 f->output_data.mac->left_pos = XINT (XCAR (XCDR (tem1)));
3593 else if (EQ (tem1, Qunbound))
3594 f->output_data.mac->left_pos = 0;
3595 else
3597 CHECK_NUMBER (tem1);
3598 f->output_data.mac->left_pos = XINT (tem1);
3599 if (f->output_data.mac->left_pos < 0)
3600 window_prompting |= XNegative;
3603 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3604 window_prompting |= USPosition;
3605 else
3606 window_prompting |= PPosition;
3609 return window_prompting;
3613 #if 0 /* MAC_TODO */
3614 /* Create and set up the Mac window for frame F. */
3616 static void
3617 mac_window (f, window_prompting, minibuffer_only)
3618 struct frame *f;
3619 long window_prompting;
3620 int minibuffer_only;
3622 Rect r;
3624 BLOCK_INPUT;
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.
3630 Elsewhere we specify the window name for the window manager. */
3633 char *str = (char *) SDATA (Vx_resource_name);
3634 f->namebuf = (char *) xmalloc (strlen (str) + 1);
3635 strcpy (f->namebuf, str);
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);
3644 validate_x_resource_name ();
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. */
3651 Lisp_Object name;
3652 int explicit = f->explicit_name;
3654 f->explicit_name = 0;
3655 name = f->name;
3656 f->name = Qnil;
3657 x_set_name (f, name, explicit);
3660 ShowWindow (FRAME_MAC_WINDOW (f));
3662 UNBLOCK_INPUT;
3664 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
3665 initialize_frame_menubar (f);
3667 if (FRAME_MAC_WINDOW (f) == 0)
3668 error ("Unable to create window");
3670 #endif /* MAC_TODO */
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. */
3676 static void
3677 x_icon (f, parms)
3678 struct frame *f;
3679 Lisp_Object parms;
3681 Lisp_Object icon_x, icon_y;
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))
3689 CHECK_NUMBER (icon_x);
3690 CHECK_NUMBER (icon_y);
3692 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
3693 error ("Both left and top icon corners of icon must be specified");
3695 BLOCK_INPUT;
3697 if (! EQ (icon_x, Qunbound))
3698 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
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));
3707 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
3708 ? f->icon_name
3709 : f->name)));
3710 #endif
3712 UNBLOCK_INPUT;
3716 void
3717 x_make_gc (f)
3718 struct frame *f;
3720 XGCValues gc_values;
3722 BLOCK_INPUT;
3724 /* Create the GC's of this frame.
3725 Note that many default values are used. */
3727 /* Normal video */
3728 gc_values.font = f->output_data.mac->font;
3729 gc_values.foreground = FRAME_FOREGROUND_PIXEL (f);
3730 gc_values.background = FRAME_BACKGROUND_PIXEL (f);
3731 f->output_data.mac->normal_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3732 FRAME_MAC_WINDOW (f),
3733 GCFont | GCForeground | GCBackground,
3734 &gc_values);
3736 /* Reverse video style. */
3737 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
3738 gc_values.background = FRAME_FOREGROUND_PIXEL (f);
3739 f->output_data.mac->reverse_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3740 FRAME_MAC_WINDOW (f),
3741 GCFont | GCForeground | GCBackground,
3742 &gc_values);
3744 /* Cursor has cursor-color background, background-color foreground. */
3745 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
3746 gc_values.background = f->output_data.mac->cursor_pixel;
3747 f->output_data.mac->cursor_gc = XCreateGC (FRAME_MAC_DISPLAY (f),
3748 FRAME_MAC_WINDOW (f),
3749 GCFont | GCForeground | GCBackground,
3750 &gc_values);
3752 /* Reliefs. */
3753 f->output_data.mac->white_relief.gc = 0;
3754 f->output_data.mac->black_relief.gc = 0;
3756 UNBLOCK_INPUT;
3760 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
3761 1, 1, 0,
3762 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
3763 Returns an Emacs frame object.
3764 ALIST is an alist of frame parameters.
3765 If the parameters specify that the frame should not have a minibuffer,
3766 and do not specify a specific minibuffer window to use,
3767 then `default-minibuffer-frame' must be a frame whose minibuffer can
3768 be shared by the new frame.
3770 This function is an internal primitive--use `make-frame' instead. */)
3771 (parms)
3772 Lisp_Object parms;
3774 struct frame *f;
3775 Lisp_Object frame, tem;
3776 Lisp_Object name;
3777 int minibuffer_only = 0;
3778 long window_prompting = 0;
3779 int width, height;
3780 int count = SPECPDL_INDEX ();
3781 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
3782 Lisp_Object display;
3783 struct mac_display_info *dpyinfo = NULL;
3784 Lisp_Object parent;
3785 struct kboard *kb;
3786 char x_frame_name[10];
3787 static int x_frame_count = 2; /* begins at 2 because terminal frame is F1 */
3789 check_mac ();
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;
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
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");
3811 if (STRINGP (name))
3812 Vx_resource_name = name;
3814 /* See if parent window is specified. */
3815 parent = mac_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
3816 if (EQ (parent, Qunbound))
3817 parent = Qnil;
3818 if (! NILP (parent))
3819 CHECK_NUMBER (parent);
3821 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
3822 /* No need to protect DISPLAY because that's not used after passing
3823 it to make_frame_without_minibuffer. */
3824 frame = Qnil;
3825 GCPRO4 (parms, parent, name, frame);
3826 tem = mac_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
3827 RES_TYPE_SYMBOL);
3828 if (EQ (tem, Qnone) || NILP (tem))
3829 f = make_frame_without_minibuffer (Qnil, kb, display);
3830 else if (EQ (tem, Qonly))
3832 f = make_minibuffer_frame ();
3833 minibuffer_only = 1;
3835 else if (WINDOWP (tem))
3836 f = make_frame_without_minibuffer (tem, kb, display);
3837 else
3838 f = make_frame (1);
3840 if (EQ (name, Qunbound) || NILP (name))
3842 sprintf (x_frame_name, "F%d", x_frame_count++);
3843 f->name = build_string (x_frame_name);
3844 f->explicit_name = 0;
3846 else
3848 f->name = name;
3849 f->explicit_name = 1;
3852 XSETFRAME (frame, f);
3854 /* Note that X Windows does support scroll bars. */
3855 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
3857 f->output_method = output_mac;
3858 f->output_data.mac = (struct mac_output *) xmalloc (sizeof (struct mac_output));
3859 bzero (f->output_data.mac, sizeof (struct mac_output));
3860 FRAME_FONTSET (f) = -1;
3861 f->output_data.mac->scroll_bar_foreground_pixel = -1;
3862 f->output_data.mac->scroll_bar_background_pixel = -1;
3864 #if 0
3865 FRAME_FONTSET (f) = -1;
3866 #endif
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;
3873 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
3874 #ifdef MULTI_KBOARD
3875 FRAME_KBOARD (f) = kb;
3876 #endif
3878 /* Specify the parent under which to make this window. */
3880 if (!NILP (parent))
3882 f->output_data.mac->parent_desc = (Window) parent;
3883 f->output_data.mac->explicit_parent = 1;
3885 else
3887 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3888 f->output_data.mac->explicit_parent = 0;
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))
3895 f->name = build_string (dpyinfo->mac_id_name);
3896 f->explicit_name = 0;
3898 else
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);
3906 /* Extract the window parameters from the supplied values
3907 that are needed to determine window geometry. */
3909 Lisp_Object font;
3911 font = mac_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
3913 BLOCK_INPUT;
3914 /* First, try whatever font the caller has specified. */
3915 if (STRINGP (font))
3917 tem = Fquery_fontset (font, Qnil);
3918 if (STRINGP (tem))
3919 font = x_new_fontset (f, SDATA (tem));
3920 else
3921 font = x_new_font (f, SDATA (font));
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;
3935 x_default_parameter (f, parms, Qfont, font,
3936 "font", "Font", RES_TYPE_STRING);
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)))
3946 Lisp_Object value;
3948 value = mac_get_arg (parms, Qinternal_border_width,
3949 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
3950 if (! EQ (value, Qunbound))
3951 parms = Fcons (Fcons (Qinternal_border_width, value),
3952 parms);
3954 /* Default internalBorderWidth to 0 on Windows to match other programs. */
3955 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
3956 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
3957 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
3958 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
3960 /* Also do the stuff which must be set before the window exists. */
3961 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
3962 "foreground", "Foreground", RES_TYPE_STRING);
3963 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
3964 "background", "Background", RES_TYPE_STRING);
3965 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
3966 "pointerColor", "Foreground", RES_TYPE_STRING);
3967 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
3968 "cursorColor", "Foreground", RES_TYPE_STRING);
3969 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
3970 "borderColor", "BorderColor", RES_TYPE_STRING);
3971 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
3972 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
3973 x_default_parameter (f, parms, Qline_spacing, Qnil,
3974 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
3975 x_default_parameter (f, parms, Qleft_fringe, Qnil,
3976 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
3977 x_default_parameter (f, parms, Qright_fringe, Qnil,
3978 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
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);
3989 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
3990 "menuBar", "MenuBar", RES_TYPE_NUMBER);
3991 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
3992 "toolBar", "ToolBar", RES_TYPE_NUMBER);
3993 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
3994 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
3995 x_default_parameter (f, parms, Qtitle, Qnil,
3996 "title", "Title", RES_TYPE_STRING);
3998 f->output_data.mac->parent_desc = FRAME_MAC_DISPLAY_INFO (f)->root_window;
3999 window_prompting = x_figure_window_size (f, parms);
4001 if (window_prompting & XNegative)
4003 if (window_prompting & YNegative)
4004 f->output_data.mac->win_gravity = SouthEastGravity;
4005 else
4006 f->output_data.mac->win_gravity = NorthEastGravity;
4008 else
4010 if (window_prompting & YNegative)
4011 f->output_data.mac->win_gravity = SouthWestGravity;
4012 else
4013 f->output_data.mac->win_gravity = NorthWestGravity;
4016 f->output_data.mac->size_hint_flags = window_prompting;
4018 tem = mac_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4019 f->no_split = minibuffer_only || EQ (tem, Qt);
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);
4029 /* mac_window (f, window_prompting, minibuffer_only); */
4030 make_mac_frame (f);
4032 x_icon (f, parms);
4034 x_make_gc (f);
4036 /* Now consider the frame official. */
4037 FRAME_MAC_DISPLAY_INFO (f)->reference_count++;
4038 Vframe_list = Fcons (frame, Vframe_list);
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);
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);
4054 /* Dimensions, especially f->height, must be done via change_frame_size.
4055 Change will not be effected unless different from the current
4056 f->height. */
4057 width = f->width;
4058 height = f->height;
4060 f->height = 0;
4061 SET_FRAME_WIDTH (f, 0);
4062 change_frame_size (f, height, width, 1, 0, 0);
4064 /* Set up faces after all frame parameters are known. */
4065 call1 (Qface_set_after_frame_default, frame);
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
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)
4081 Lisp_Object visibility;
4083 visibility = mac_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
4084 if (EQ (visibility, Qunbound))
4085 visibility = Qt;
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. */
4098 UNGCPRO;
4100 /* Make sure windows on this frame appear in calls to next-window
4101 and similar functions. */
4102 Vwindow_list = Qnil;
4104 return unbind_to (count, frame);
4107 /* FRAME is used only to get a handle on the X display. We don't pass the
4108 display info directly because we're called from frame.c, which doesn't
4109 know about that structure. */
4110 Lisp_Object
4111 x_get_focus_frame (frame)
4112 struct frame *frame;
4114 struct mac_display_info *dpyinfo = FRAME_MAC_DISPLAY_INFO (frame);
4115 Lisp_Object xfocus;
4116 if (! dpyinfo->x_focus_frame)
4117 return Qnil;
4119 XSETFRAME (xfocus, dpyinfo->x_focus_frame);
4120 return xfocus;
4123 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
4124 doc: /* Internal function called by `color-defined-p', which see. */)
4125 (color, frame)
4126 Lisp_Object color, frame;
4128 XColor foo;
4129 FRAME_PTR f = check_x_frame (frame);
4131 CHECK_STRING (color);
4133 if (mac_defined_color (f, SDATA (color), &foo, 0))
4134 return Qt;
4135 else
4136 return Qnil;
4139 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
4140 doc: /* Internal function called by `color-values', which see. */)
4141 (color, frame)
4142 Lisp_Object color, frame;
4144 XColor foo;
4145 FRAME_PTR f = check_x_frame (frame);
4147 CHECK_STRING (color);
4149 if (mac_defined_color (f, SDATA (color), &foo, 0))
4151 Lisp_Object rgb[3];
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);
4161 else
4162 return Qnil;
4165 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
4166 doc: /* Internal function called by `display-color-p', which see. */)
4167 (display)
4168 Lisp_Object display;
4170 struct mac_display_info *dpyinfo = check_x_display_info (display);
4172 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
4173 return Qnil;
4175 return Qt;
4178 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
4179 0, 1, 0,
4180 doc: /* Return t if the X display supports shades of gray.
4181 Note that color displays do support shades of gray.
4182 The optional argument DISPLAY specifies which display to ask about.
4183 DISPLAY should be either a frame or a display name (a string).
4184 If omitted or nil, that stands for the selected frame's display. */)
4185 (display)
4186 Lisp_Object display;
4188 struct mac_display_info *dpyinfo = check_x_display_info (display);
4190 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
4191 return Qnil;
4193 return Qt;
4196 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
4197 0, 1, 0,
4198 doc: /* Returns the width in pixels of the X display DISPLAY.
4199 The optional argument DISPLAY specifies which display to ask about.
4200 DISPLAY should be either a frame or a display name (a string).
4201 If omitted or nil, that stands for the selected frame's display. */)
4202 (display)
4203 Lisp_Object display;
4205 struct mac_display_info *dpyinfo = check_x_display_info (display);
4207 return make_number (dpyinfo->width);
4210 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
4211 Sx_display_pixel_height, 0, 1, 0,
4212 doc: /* Returns the height in pixels of the X display DISPLAY.
4213 The optional argument DISPLAY specifies which display to ask about.
4214 DISPLAY should be either a frame or a display name (a string).
4215 If omitted or nil, that stands for the selected frame's display. */)
4216 (display)
4217 Lisp_Object display;
4219 struct mac_display_info *dpyinfo = check_x_display_info (display);
4221 return make_number (dpyinfo->height);
4224 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
4225 0, 1, 0,
4226 doc: /* Returns the number of bitplanes of the display DISPLAY.
4227 The optional argument DISPLAY specifies which display to ask about.
4228 DISPLAY should be either a frame or a display name (a string).
4229 If omitted or nil, that stands for the selected frame's display. */)
4230 (display)
4231 Lisp_Object display;
4233 struct mac_display_info *dpyinfo = check_x_display_info (display);
4235 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
4238 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
4239 0, 1, 0,
4240 doc: /* Returns the number of color cells of the display DISPLAY.
4241 The optional argument DISPLAY specifies which display to ask about.
4242 DISPLAY should be either a frame or a display name (a string).
4243 If omitted or nil, that stands for the selected frame's display. */)
4244 (display)
4245 Lisp_Object display;
4247 struct mac_display_info *dpyinfo = check_x_display_info (display);
4249 /* MAC_TODO: check whether this is right */
4250 return make_number ((unsigned long) (pow (2, dpyinfo->n_cbits)));
4253 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4254 Sx_server_max_request_size,
4255 0, 1, 0,
4256 doc: /* Returns the maximum request size of the server of display DISPLAY.
4257 The optional argument DISPLAY specifies which display to ask about.
4258 DISPLAY should be either a frame or a display name (a string).
4259 If omitted or nil, that stands for the selected frame's display. */)
4260 (display)
4261 Lisp_Object display;
4263 struct mac_display_info *dpyinfo = check_x_display_info (display);
4265 return make_number (1);
4268 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4269 doc: /* Returns the vendor ID string of the Mac OS system (Apple).
4270 The optional argument DISPLAY specifies which display to ask about.
4271 DISPLAY should be either a frame or a display name (a string).
4272 If omitted or nil, that stands for the selected frame's display. */)
4273 (display)
4274 Lisp_Object display;
4276 return build_string ("Apple Computers");
4279 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4280 doc: /* Returns the version numbers of the server of display DISPLAY.
4281 The value is a list of three integers: the major and minor
4282 version numbers, and the vendor-specific release
4283 number. See also the function `x-server-vendor'.
4285 The optional argument DISPLAY specifies which display to ask about.
4286 DISPLAY should be either a frame or a display name (a string).
4287 If omitted or nil, that stands for the selected frame's display. */)
4288 (display)
4289 Lisp_Object display;
4291 int mac_major_version, mac_minor_version;
4292 SInt32 response;
4294 if (Gestalt (gestaltSystemVersion, &response) != noErr)
4295 error ("Cannot get Mac OS version");
4297 mac_major_version = (response >> 8) & 0xf;
4298 mac_minor_version = (response >> 4) & 0xf;
4300 return Fcons (make_number (mac_major_version),
4301 Fcons (make_number (mac_minor_version), Qnil));
4304 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4305 doc: /* Return the number of screens on the server of display DISPLAY.
4306 The optional argument DISPLAY specifies which display to ask about.
4307 DISPLAY should be either a frame or a display name (a string).
4308 If omitted or nil, that stands for the selected frame's display. */)
4309 (display)
4310 Lisp_Object display;
4312 return make_number (1);
4315 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
4316 doc: /* Return the height in millimeters of the X display DISPLAY.
4317 The optional argument DISPLAY specifies which display to ask about.
4318 DISPLAY should be either a frame or a display name (a string).
4319 If omitted or nil, that stands for the selected frame's display. */)
4320 (display)
4321 Lisp_Object display;
4323 /* MAC_TODO: this is an approximation, and only of the main display */
4325 struct mac_display_info *dpyinfo = check_x_display_info (display);
4326 short h, v;
4328 ScreenRes (&h, &v);
4330 return make_number ((int) (v / 72.0 * 25.4));
4333 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4334 doc: /* Return the width in millimeters of the X display DISPLAY.
4335 The optional argument DISPLAY specifies which display to ask about.
4336 DISPLAY should be either a frame or a display name (a string).
4337 If omitted or nil, that stands for the selected frame's display. */)
4338 (display)
4339 Lisp_Object display;
4341 /* MAC_TODO: this is an approximation, and only of the main display */
4343 struct mac_display_info *dpyinfo = check_x_display_info (display);
4344 short h, v;
4346 ScreenRes (&h, &v);
4348 return make_number ((int) (h / 72.0 * 25.4));
4351 DEFUN ("x-display-backing-store", Fx_display_backing_store,
4352 Sx_display_backing_store, 0, 1, 0,
4353 doc: /* Returns an indication of whether display DISPLAY does backing store.
4354 The value may be `always', `when-mapped', or `not-useful'.
4355 The optional argument DISPLAY specifies which display to ask about.
4356 DISPLAY should be either a frame or a display name (a string).
4357 If omitted or nil, that stands for the selected frame's display. */)
4358 (display)
4359 Lisp_Object display;
4361 return intern ("not-useful");
4364 DEFUN ("x-display-visual-class", Fx_display_visual_class,
4365 Sx_display_visual_class, 0, 1, 0,
4366 doc: /* Returns the visual class of the display DISPLAY.
4367 The value is one of the symbols `static-gray', `gray-scale',
4368 `static-color', `pseudo-color', `true-color', or `direct-color'.
4370 The optional argument DISPLAY specifies which display to ask about.
4371 DISPLAY should be either a frame or a display name (a string).
4372 If omitted or nil, that stands for the selected frame's display. */)
4373 (display)
4374 Lisp_Object display;
4376 struct mac_display_info *dpyinfo = check_x_display_info (display);
4378 #if 0
4379 switch (dpyinfo->visual->class)
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");
4390 #endif /* 0 */
4392 return (intern ("true-color"));
4395 DEFUN ("x-display-save-under", Fx_display_save_under,
4396 Sx_display_save_under, 0, 1, 0,
4397 doc: /* Returns t if the display DISPLAY supports the save-under feature.
4398 The optional argument DISPLAY specifies which display to ask about.
4399 DISPLAY should be either a frame or a display name (a string).
4400 If omitted or nil, that stands for the selected frame's display. */)
4401 (display)
4402 Lisp_Object display;
4404 return Qnil;
4408 x_pixel_width (f)
4409 register struct frame *f;
4411 return PIXEL_WIDTH (f);
4415 x_pixel_height (f)
4416 register struct frame *f;
4418 return PIXEL_HEIGHT (f);
4422 x_char_width (f)
4423 register struct frame *f;
4425 return FONT_WIDTH (f->output_data.mac->font);
4429 x_char_height (f)
4430 register struct frame *f;
4432 return f->output_data.mac->line_height;
4436 x_screen_planes (f)
4437 register struct frame *f;
4439 return FRAME_MAC_DISPLAY_INFO (f)->n_planes;
4442 /* Return the display structure for the display named NAME.
4443 Open a new connection if necessary. */
4445 struct mac_display_info *
4446 x_display_info_for_name (name)
4447 Lisp_Object name;
4449 Lisp_Object names;
4450 struct mac_display_info *dpyinfo;
4452 CHECK_STRING (name);
4454 for (dpyinfo = &one_mac_display_info, names = x_display_name_list;
4455 dpyinfo;
4456 dpyinfo = dpyinfo->next, names = XCDR (names))
4458 Lisp_Object tem;
4459 tem = Fstring_equal (XCAR (XCAR (names)), name);
4460 if (!NILP (tem))
4461 return dpyinfo;
4464 /* Use this general default value to start with. */
4465 Vx_resource_name = Vinvocation_name;
4467 validate_x_resource_name ();
4469 dpyinfo = mac_term_init (name, (unsigned char *) 0,
4470 (char *) SDATA (Vx_resource_name));
4472 if (dpyinfo == 0)
4473 error ("Cannot connect to server %s", SDATA (name));
4475 mac_in_use = 1;
4476 XSETFASTINT (Vwindow_system_version, 3);
4478 return dpyinfo;
4481 #if 0 /* MAC_TODO: implement network support */
4482 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
4483 1, 3, 0,
4484 doc: /* Open a connection to a server.
4485 DISPLAY is the name of the display to connect to.
4486 Optional second arg XRM-STRING is a string of resources in xrdb format.
4487 If the optional third arg MUST-SUCCEED is non-nil,
4488 terminate Emacs if we can't open the connection. */)
4489 (display, xrm_string, must_succeed)
4490 Lisp_Object display, xrm_string, must_succeed;
4492 unsigned char *xrm_option;
4493 struct mac_display_info *dpyinfo;
4495 CHECK_STRING (display);
4496 if (! NILP (xrm_string))
4497 CHECK_STRING (xrm_string);
4499 if (! EQ (Vwindow_system, intern ("mac")))
4500 error ("Not using Mac OS");
4502 if (! NILP (xrm_string))
4503 xrm_option = (unsigned char *) SDATA (xrm_string);
4504 else
4505 xrm_option = (unsigned char *) 0;
4507 validate_x_resource_name ();
4509 /* This is what opens the connection and sets x_current_display.
4510 This also initializes many symbols, such as those used for input. */
4511 dpyinfo = mac_term_init (display, xrm_option,
4512 (char *) SDATA (Vx_resource_name));
4514 if (dpyinfo == 0)
4516 if (!NILP (must_succeed))
4517 fatal ("Cannot connect to server %s.\n",
4518 SDATA (display));
4519 else
4520 error ("Cannot connect to server %s", SDATA (display));
4523 mac_in_use = 1;
4525 XSETFASTINT (Vwindow_system_version, 3);
4526 return Qnil;
4529 DEFUN ("x-close-connection", Fx_close_connection,
4530 Sx_close_connection, 1, 1, 0,
4531 doc: /* Close the connection to DISPLAY's server.
4532 For DISPLAY, specify either a frame or a display name (a string).
4533 If DISPLAY is nil, that stands for the selected frame's display. */)
4534 (display)
4535 Lisp_Object display;
4537 struct mac_display_info *dpyinfo = check_x_display_info (display);
4538 int i;
4540 if (dpyinfo->reference_count > 0)
4541 error ("Display still has frames on it");
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)
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);
4553 x_destroy_all_bitmaps (dpyinfo);
4555 x_delete_display (dpyinfo);
4556 UNBLOCK_INPUT;
4558 return Qnil;
4560 #endif /* 0 */
4562 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
4563 doc: /* Return the list of display names that Emacs has connections to. */)
4566 Lisp_Object tail, result;
4568 result = Qnil;
4569 for (tail = x_display_name_list; ! NILP (tail); tail = XCDR (tail))
4570 result = Fcons (XCAR (XCAR (tail)), result);
4572 return result;
4575 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
4576 doc: /* If ON is non-nil, report errors as soon as the erring request is made.
4577 If ON is nil, allow buffering of requests.
4578 This is a noop on Mac OS systems.
4579 The optional second argument DISPLAY specifies which display to act on.
4580 DISPLAY should be either a frame or a display name (a string).
4581 If DISPLAY is omitted or nil, that stands for the selected frame's display. */)
4582 (on, display)
4583 Lisp_Object display, on;
4585 return Qnil;
4589 /***********************************************************************
4590 Image types
4591 ***********************************************************************/
4593 /* Value is the number of elements of vector VECTOR. */
4595 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
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. */
4600 static struct image_type *image_types;
4602 /* The symbol `image' which is the car of the lists used to represent
4603 images in Lisp. */
4605 extern Lisp_Object Qimage;
4607 /* The symbol `xbm' which is used as the type symbol for XBM images. */
4609 Lisp_Object Qxbm;
4611 /* Keywords. */
4613 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
4614 extern Lisp_Object QCdata, QCtype;
4615 Lisp_Object QCascent, QCmargin, QCrelief;
4616 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
4617 Lisp_Object QCindex;
4619 /* Other symbols. */
4621 Lisp_Object Qlaplace;
4623 /* Time in seconds after which images should be removed from the cache
4624 if not displayed. */
4626 Lisp_Object Vimage_cache_eviction_delay;
4628 /* Function prototypes. */
4630 static void define_image_type P_ ((struct image_type *type));
4631 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
4632 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
4633 static void x_laplace P_ ((struct frame *, struct image *));
4634 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
4635 Lisp_Object));
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. */
4641 static void
4642 define_image_type (type)
4643 struct image_type *type;
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);
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. */
4658 static INLINE struct image_type *
4659 lookup_image_type (symbol)
4660 Lisp_Object symbol;
4662 struct image_type *type;
4664 for (type = image_types; type; type = type->next)
4665 if (EQ (symbol, *type->type))
4666 break;
4668 return type;
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. */
4680 valid_image_p (object)
4681 Lisp_Object object;
4683 int valid_p = 0;
4685 if (CONSP (object) && EQ (XCAR (object), Qimage))
4687 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
4688 struct image_type *type = lookup_image_type (symbol);
4690 if (type)
4691 valid_p = type->valid_p (object);
4694 return valid_p;
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. */
4704 static void
4705 image_error (format, arg1, arg2)
4706 char *format;
4707 Lisp_Object arg1, arg2;
4709 add_to_log (format, arg1, arg2);
4714 /***********************************************************************
4715 Image specifications
4716 ***********************************************************************/
4718 enum image_value_type
4720 IMAGE_DONT_CHECK_VALUE_TYPE,
4721 IMAGE_STRING_VALUE,
4722 IMAGE_SYMBOL_VALUE,
4723 IMAGE_POSITIVE_INTEGER_VALUE,
4724 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
4725 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
4726 IMAGE_ASCENT_VALUE,
4727 IMAGE_INTEGER_VALUE,
4728 IMAGE_FUNCTION_VALUE,
4729 IMAGE_NUMBER_VALUE,
4730 IMAGE_BOOL_VALUE
4733 /* Structure used when parsing image specifications. */
4735 struct image_keyword
4737 /* Name of keyword. */
4738 char *name;
4740 /* The type of value allowed. */
4741 enum image_value_type type;
4743 /* Non-zero means key must be present. */
4744 int mandatory_p;
4746 /* Used to recognize duplicate keywords in a property list. */
4747 int count;
4749 /* The value that was found. */
4750 Lisp_Object value;
4754 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
4755 int, Lisp_Object));
4756 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
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. */
4765 static int
4766 parse_image_spec (spec, keywords, nkeywords, type)
4767 Lisp_Object spec;
4768 struct image_keyword *keywords;
4769 int nkeywords;
4770 Lisp_Object type;
4772 int i;
4773 Lisp_Object plist;
4775 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
4776 return 0;
4778 plist = XCDR (spec);
4779 while (CONSP (plist))
4781 Lisp_Object key, value;
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;
4789 /* There must follow a value. */
4790 if (!CONSP (plist))
4791 return 0;
4792 value = XCAR (plist);
4793 plist = XCDR (plist);
4795 /* Find key in KEYWORDS. Error if not found. */
4796 for (i = 0; i < nkeywords; ++i)
4797 if (strcmp (keywords[i].name, SDATA (SYMBOL_NAME (key))) == 0)
4798 break;
4800 if (i == nkeywords)
4801 continue;
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;
4808 if (keywords[i].count > 1)
4809 return 0;
4811 /* Check type of value against allowed type. */
4812 switch (keywords[i].type)
4814 case IMAGE_STRING_VALUE:
4815 if (!STRINGP (value))
4816 return 0;
4817 break;
4819 case IMAGE_SYMBOL_VALUE:
4820 if (!SYMBOLP (value))
4821 return 0;
4822 break;
4824 case IMAGE_POSITIVE_INTEGER_VALUE:
4825 if (!INTEGERP (value) || XINT (value) <= 0)
4826 return 0;
4827 break;
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;
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;
4847 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
4848 if (!INTEGERP (value) || XINT (value) < 0)
4849 return 0;
4850 break;
4852 case IMAGE_DONT_CHECK_VALUE_TYPE:
4853 break;
4855 case IMAGE_FUNCTION_VALUE:
4856 value = indirect_function (value);
4857 if (SUBRP (value)
4858 || COMPILEDP (value)
4859 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
4860 break;
4861 return 0;
4863 case IMAGE_NUMBER_VALUE:
4864 if (!INTEGERP (value) && !FLOATP (value))
4865 return 0;
4866 break;
4868 case IMAGE_INTEGER_VALUE:
4869 if (!INTEGERP (value))
4870 return 0;
4871 break;
4873 case IMAGE_BOOL_VALUE:
4874 if (!NILP (value) && !EQ (value, Qt))
4875 return 0;
4876 break;
4878 default:
4879 abort ();
4880 break;
4883 if (EQ (key, QCtype) && !EQ (type, value))
4884 return 0;
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;
4892 return NILP (plist);
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. */
4900 static Lisp_Object
4901 image_spec_value (spec, key, found)
4902 Lisp_Object spec, key;
4903 int *found;
4905 Lisp_Object tail;
4907 xassert (valid_image_p (spec));
4909 for (tail = XCDR (spec);
4910 CONSP (tail) && CONSP (XCDR (tail));
4911 tail = XCDR (XCDR (tail)))
4913 if (EQ (XCAR (tail), key))
4915 if (found)
4916 *found = 1;
4917 return XCAR (XCDR (tail));
4921 if (found)
4922 *found = 0;
4923 return Qnil;
4929 /***********************************************************************
4930 Image type independent image structures
4931 ***********************************************************************/
4933 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
4934 static void free_image P_ ((struct frame *f, struct image *img));
4937 /* Allocate and return a new image structure for image specification
4938 SPEC. SPEC has a hash value of HASH. */
4940 static struct image *
4941 make_image (spec, hash)
4942 Lisp_Object spec;
4943 unsigned hash;
4945 struct image *img = (struct image *) xmalloc (sizeof *img);
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;
4959 /* Free image IMG which was used on frame F, including its resources. */
4961 static void
4962 free_image (f, img)
4963 struct frame *f;
4964 struct image *img;
4966 if (img)
4968 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
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;
4976 if (img->next)
4977 img->next->prev = img->prev;
4979 c->images[img->id] = NULL;
4981 /* Free resources, then free IMG. */
4982 img->type->free (f, img);
4983 xfree (img);
4988 /* Prepare image IMG for display on frame F. Must be called before
4989 drawing an image. */
4991 void
4992 prepare_image_for_display (f, img)
4993 struct frame *f;
4994 struct image *img;
4996 EMACS_TIME t;
4998 /* We're about to display IMG, so set its timestamp to `now'. */
4999 EMACS_GET_TIME (t);
5000 img->timestamp = EMACS_SECS (t);
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;
5009 /* Value is the number of pixels for the ascent of image IMG when
5010 drawn in face FACE. */
5013 image_ascent (img, face)
5014 struct image *img;
5015 struct face *face;
5017 int height = img->height + img->vmargin;
5018 int ascent;
5020 if (img->ascent == CENTERED_IMAGE_ASCENT)
5022 if (face->font)
5023 ascent = height / 2 - (FONT_DESCENT(face->font)
5024 - FONT_BASE(face->font)) / 2;
5025 else
5026 ascent = height / 2;
5028 else
5029 ascent = height * img->ascent / 100.0;
5031 return ascent;
5036 /***********************************************************************
5037 Helper functions for X image types
5038 ***********************************************************************/
5040 static void x_clear_image P_ ((struct frame *f, struct image *img));
5041 static unsigned long x_alloc_image_color P_ ((struct frame *f,
5042 struct image *img,
5043 Lisp_Object color_name,
5044 unsigned long dflt));
5046 /* Free X resources of image IMG which is used on frame F. */
5048 static void
5049 x_clear_image (f, img)
5050 struct frame *f;
5051 struct image *img;
5053 #if 0 /* MAC_TODO: W32 image support */
5055 if (img->pixmap)
5057 BLOCK_INPUT;
5058 XFreePixmap (NULL, img->pixmap);
5059 img->pixmap = 0;
5060 UNBLOCK_INPUT;
5063 if (img->ncolors)
5065 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
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)
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;
5081 xfree (img->colors);
5082 img->colors = NULL;
5083 img->ncolors = 0;
5085 #endif /* MAC_TODO */
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. */
5094 static unsigned long
5095 x_alloc_image_color (f, img, color_name, dflt)
5096 struct frame *f;
5097 struct image *img;
5098 Lisp_Object color_name;
5099 unsigned long dflt;
5101 #if 0 /* MAC_TODO: allocing colors. */
5102 XColor color;
5103 unsigned long result;
5105 xassert (STRINGP (color_name));
5107 if (w32_defined_color (f, SDATA (color_name), &color, 1))
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;
5118 else
5119 result = dflt;
5120 return result;
5121 #endif /* MAC_TODO */
5122 return 0;
5127 /***********************************************************************
5128 Image Cache
5129 ***********************************************************************/
5131 static void cache_image P_ ((struct frame *f, struct image *img));
5134 /* Return a new, initialized image cache that is allocated from the
5135 heap. Call free_image_cache to free an image cache. */
5137 struct image_cache *
5138 make_image_cache ()
5140 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
5141 int size;
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;
5153 /* Free image cache of frame F. Be aware that X frames share images
5154 caches. */
5156 void
5157 free_image_cache (f)
5158 struct frame *f;
5160 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5161 if (c)
5163 int i;
5165 /* Cache should not be referenced by any frame when freed. */
5166 xassert (c->refcount == 0);
5168 for (i = 0; i < c->used; ++i)
5169 free_image (f, c->images[i]);
5170 xfree (c->images);
5171 xfree (c->buckets);
5172 xfree (c);
5173 FRAME_X_IMAGE_CACHE (f) = NULL;
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. */
5185 void
5186 clear_image_cache (f, force_p)
5187 struct frame *f;
5188 int force_p;
5190 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5192 if (c && INTEGERP (Vimage_cache_eviction_delay))
5194 EMACS_TIME t;
5195 unsigned long old;
5196 int i, any_freed_p = 0;
5198 EMACS_GET_TIME (t);
5199 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
5201 for (i = 0; i < c->used; ++i)
5203 struct image *img = c->images[i];
5204 if (img != NULL
5205 && (force_p
5206 || (img->timestamp > old)))
5208 free_image (f, img);
5209 any_freed_p = 1;
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)
5219 clear_current_matrices (f);
5220 ++windows_or_buffers_changed;
5226 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
5227 0, 1, 0,
5228 doc: /* Clear the image cache of FRAME.
5229 FRAME nil or omitted means use the selected frame.
5230 FRAME t means clear the image caches of all frames. */)
5231 (frame)
5232 Lisp_Object frame;
5234 if (EQ (frame, Qt))
5236 Lisp_Object tail;
5238 FOR_EACH_FRAME (tail, frame)
5239 if (FRAME_MAC_P (XFRAME (frame)))
5240 clear_image_cache (XFRAME (frame), 1);
5242 else
5243 clear_image_cache (check_x_frame (frame), 1);
5245 return Qnil;
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). */
5253 lookup_image (f, spec)
5254 struct frame *f;
5255 Lisp_Object spec;
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;
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));
5269 GCPRO1 (spec);
5271 /* Look up SPEC in the hash table of the image cache. */
5272 hash = sxhash (spec, 0);
5273 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
5275 for (img = c->buckets[i]; img; img = img->next)
5276 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
5277 break;
5279 /* If not found, create a new image and cache it. */
5280 if (img == NULL)
5282 BLOCK_INPUT;
5283 img = make_image (spec, hash);
5284 cache_image (f, img);
5285 img->load_failed_p = img->type->load (f, img) == 0;
5286 xassert (!interrupt_input_blocked);
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)
5293 Lisp_Object value;
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);
5302 else
5304 /* Handle image type independent image attributes
5305 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
5306 Lisp_Object ascent, margin, relief;
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;
5314 margin = image_spec_value (spec, QCmargin, NULL);
5315 if (INTEGERP (margin) && XINT (margin) >= 0)
5316 img->vmargin = img->hmargin = XFASTINT (margin);
5317 else if (CONSP (margin) && INTEGERP (XCAR (margin))
5318 && INTEGERP (XCDR (margin)))
5320 if (XINT (XCAR (margin)) > 0)
5321 img->hmargin = XFASTINT (XCAR (margin));
5322 if (XINT (XCDR (margin)) > 0)
5323 img->vmargin = XFASTINT (XCDR (margin));
5326 relief = image_spec_value (spec, QCrelief, NULL);
5327 if (INTEGERP (relief))
5329 img->relief = XINT (relief);
5330 img->hmargin += abs (img->relief);
5331 img->vmargin += abs (img->relief);
5336 /* We're using IMG, so set its timestamp to `now'. */
5337 EMACS_GET_TIME (now);
5338 img->timestamp = EMACS_SECS (now);
5340 UNGCPRO;
5342 /* Value is the image id. */
5343 return img->id;
5347 /* Cache image IMG in the image cache of frame F. */
5349 static void
5350 cache_image (f, img)
5351 struct frame *f;
5352 struct image *img;
5354 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5355 int i;
5357 /* Find a free slot in c->images. */
5358 for (i = 0; i < c->used; ++i)
5359 if (c->images[i] == NULL)
5360 break;
5362 /* If no free slot found, maybe enlarge c->images. */
5363 if (i == c->used && c->used == c->size)
5365 c->size *= 2;
5366 c->images = (struct image **) xrealloc (c->images,
5367 c->size * sizeof *c->images);
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;
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;
5386 /* Call FN on every image in the image cache of frame F. Used to mark
5387 Lisp Objects in the image cache. */
5389 void
5390 forall_images_in_image_cache (f, fn)
5391 struct frame *f;
5392 void (*fn) P_ ((struct image *img));
5394 if (FRAME_LIVE_P (f) && FRAME_MAC_P (f))
5396 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
5397 if (c)
5399 int i;
5400 for (i = 0; i < c->used; ++i)
5401 if (c->images[i])
5402 fn (c->images[i]);
5409 /***********************************************************************
5410 Mac support code
5411 ***********************************************************************/
5413 #if 0 /* MAC_TODO: Mac specific image code. */
5415 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
5416 XImage **, Pixmap *));
5417 static void x_destroy_x_image P_ ((XImage *));
5418 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
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. */
5427 static int
5428 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
5429 struct frame *f;
5430 int width, height, depth;
5431 XImage **ximg;
5432 Pixmap *pixmap;
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);
5439 xassert (interrupt_input_blocked);
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)
5448 image_error ("Unable to allocate X image", Qnil, Qnil);
5449 return 0;
5452 /* Allocate image raster. */
5453 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
5455 /* Allocate a pixmap of the same size. */
5456 *pixmap = XCreatePixmap (display, window, width, height, depth);
5457 if (*pixmap == 0)
5459 x_destroy_x_image (*ximg);
5460 *ximg = NULL;
5461 image_error ("Unable to create X pixmap", Qnil, Qnil);
5462 return 0;
5464 #endif /* MAC_TODO */
5465 return 1;
5469 /* Destroy XImage XIMG. Free XIMG->data. */
5471 static void
5472 x_destroy_x_image (ximg)
5473 XImage *ximg;
5475 xassert (interrupt_input_blocked);
5476 if (ximg)
5478 xfree (ximg->data);
5479 ximg->data = NULL;
5480 XDestroyImage (ximg);
5485 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
5486 are width and height of both the image and pixmap. */
5488 static void
5489 x_put_x_image (f, ximg, pixmap, width, height)
5490 struct frame *f;
5491 XImage *ximg;
5492 Pixmap pixmap;
5494 GC gc;
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);
5502 #endif /* MAC_TODO */
5505 /***********************************************************************
5506 Searching files
5507 ***********************************************************************/
5509 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
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. */
5515 static Lisp_Object
5516 x_find_image_file (file)
5517 Lisp_Object file;
5519 Lisp_Object file_found, search_path;
5520 struct gcpro gcpro1, gcpro2;
5521 int fd;
5523 file_found = Qnil;
5524 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
5525 GCPRO2 (file_found, search_path);
5527 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
5528 fd = openp (search_path, file, Qnil, &file_found, Qnil);
5530 if (fd < 0)
5531 file_found = Qnil;
5532 else
5533 close (fd);
5535 UNGCPRO;
5536 return file_found;
5540 /***********************************************************************
5541 XBM images
5542 ***********************************************************************/
5544 static int xbm_load P_ ((struct frame *f, struct image *img));
5545 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
5546 Lisp_Object file));
5547 static int xbm_image_p P_ ((Lisp_Object object));
5548 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
5549 unsigned char **));
5552 /* Indices of image specification fields in xbm_format, below. */
5554 enum xbm_keyword_index
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
5571 /* Vector of image_keyword structures describing the format
5572 of valid XBM image specifications. */
5574 static struct image_keyword xbm_format[XBM_LAST] =
5576 {":type", IMAGE_SYMBOL_VALUE, 1},
5577 {":file", IMAGE_STRING_VALUE, 0},
5578 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5579 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
5580 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5581 {":foreground", IMAGE_STRING_VALUE, 0},
5582 {":background", IMAGE_STRING_VALUE, 0},
5583 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
5584 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
5585 {":relief", IMAGE_INTEGER_VALUE, 0},
5586 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
5587 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
5590 /* Structure describing the image type XBM. */
5592 static struct image_type xbm_type =
5594 &Qxbm,
5595 xbm_image_p,
5596 xbm_load,
5597 x_clear_image,
5598 NULL
5601 /* Tokens returned from xbm_scan. */
5603 enum xbm_token
5605 XBM_TK_IDENT = 256,
5606 XBM_TK_NUMBER
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..
5615 If the specification specifies a file to load, it must contain
5616 an entry `:file FILENAME' where FILENAME is a string.
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:
5622 1. a string large enough to hold the bitmap data, i.e. it must
5623 have a size >= (WIDTH + 7) / 8 * HEIGHT
5625 2. a bool-vector of size >= WIDTH * HEIGHT
5627 3. a vector of strings or bool-vectors, one for each line of the
5628 bitmap.
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. */
5635 static int
5636 xbm_image_p (object)
5637 Lisp_Object object;
5639 struct image_keyword kw[XBM_LAST];
5641 bcopy (xbm_format, kw, sizeof kw);
5642 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
5643 return 0;
5645 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
5647 if (kw[XBM_FILE].count)
5649 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
5650 return 0;
5652 else
5654 Lisp_Object data;
5655 int width, height;
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;
5663 data = kw[XBM_DATA].value;
5664 width = XFASTINT (kw[XBM_WIDTH].value);
5665 height = XFASTINT (kw[XBM_HEIGHT].value);
5667 /* Check type of data, and width and height against contents of
5668 data. */
5669 if (VECTORP (data))
5671 int i;
5673 /* Number of elements of the vector must be >= height. */
5674 if (XVECTOR (data)->size < height)
5675 return 0;
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)
5681 Lisp_Object elt = XVECTOR (data)->contents[i];
5683 if (STRINGP (elt))
5685 if (SCHARS (elt)
5686 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
5687 return 0;
5689 else if (BOOL_VECTOR_P (elt))
5691 if (XBOOL_VECTOR (elt)->size < width)
5692 return 0;
5694 else
5695 return 0;
5698 else if (STRINGP (data))
5700 if (SCHARS (data)
5701 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
5702 return 0;
5704 else if (BOOL_VECTOR_P (data))
5706 if (XBOOL_VECTOR (data)->size < width * height)
5707 return 0;
5709 else
5710 return 0;
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;
5718 return 1;
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. */
5728 static int
5729 xbm_scan (fp, sval, ival)
5730 FILE *fp;
5731 char *sval;
5732 int *ival;
5734 int c;
5736 /* Skip white space. */
5737 while ((c = fgetc (fp)) != EOF && isspace (c))
5740 if (c == EOF)
5741 c = 0;
5742 else if (isdigit (c))
5744 int value = 0, digit;
5746 if (c == '0')
5748 c = fgetc (fp);
5749 if (c == 'x' || c == 'X')
5751 while ((c = fgetc (fp)) != EOF)
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;
5764 else if (isdigit (c))
5766 value = c - '0';
5767 while ((c = fgetc (fp)) != EOF
5768 && isdigit (c))
5769 value = 8 * value + c - '0';
5772 else
5774 value = c - '0';
5775 while ((c = fgetc (fp)) != EOF
5776 && isdigit (c))
5777 value = 10 * value + c - '0';
5780 if (c != EOF)
5781 ungetc (c, fp);
5782 *ival = value;
5783 c = XBM_TK_NUMBER;
5785 else if (isalpha (c) || c == '_')
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;
5797 return c;
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. */
5807 static int
5808 xbm_read_bitmap_file_data (file, width, height, data)
5809 char *file;
5810 int *width, *height;
5811 unsigned char **data;
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;
5822 #define match() \
5823 LA1 = xbm_scan (fp, buffer, &value)
5825 #define expect(TOKEN) \
5826 if (LA1 != (TOKEN)) \
5827 goto failure; \
5828 else \
5829 match ()
5831 #define expect_ident(IDENT) \
5832 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
5833 match (); \
5834 else \
5835 goto failure
5837 fp = fopen (file, "r");
5838 if (fp == NULL)
5839 return 0;
5841 *width = *height = -1;
5842 *data = NULL;
5843 LA1 = xbm_scan (fp, buffer, &value);
5845 /* Parse defines for width, height and hot-spots. */
5846 while (LA1 == '#')
5848 match ();
5849 expect_ident ("define");
5850 expect (XBM_TK_IDENT);
5852 if (LA1 == XBM_TK_NUMBER);
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;
5861 expect (XBM_TK_NUMBER);
5864 if (*width < 0 || *height < 0)
5865 goto failure;
5867 /* Parse bits. Must start with `static'. */
5868 expect_ident ("static");
5869 if (LA1 == XBM_TK_IDENT)
5871 if (strcmp (buffer, "unsigned") == 0)
5873 match ();
5874 expect_ident ("char");
5876 else if (strcmp (buffer, "short") == 0)
5878 match ();
5879 v10 = 1;
5880 if (*width % 16 && *width % 16 < 9)
5881 padding_p = 1;
5883 else if (strcmp (buffer, "char") == 0)
5884 match ();
5885 else
5886 goto failure;
5888 else
5889 goto failure;
5891 expect (XBM_TK_IDENT);
5892 expect ('[');
5893 expect (']');
5894 expect ('=');
5895 expect ('{');
5897 bytes_per_line = (*width + 7) / 8 + padding_p;
5898 nbytes = bytes_per_line * *height;
5899 p = *data = (char *) xmalloc (nbytes);
5901 if (v10)
5904 for (i = 0; i < nbytes; i += 2)
5906 int val = value;
5907 expect (XBM_TK_NUMBER);
5909 *p++ = val;
5910 if (!padding_p || ((i + 2) % bytes_per_line))
5911 *p++ = value >> 8;
5913 if (LA1 == ',' || LA1 == '}')
5914 match ();
5915 else
5916 goto failure;
5919 else
5921 for (i = 0; i < nbytes; ++i)
5923 int val = value;
5924 expect (XBM_TK_NUMBER);
5926 *p++ = val;
5928 if (LA1 == ',' || LA1 == '}')
5929 match ();
5930 else
5931 goto failure;
5935 fclose (fp);
5936 return 1;
5938 failure:
5940 fclose (fp);
5941 if (*data)
5943 xfree (*data);
5944 *data = NULL;
5946 return 0;
5948 #undef match
5949 #undef expect
5950 #undef expect_ident
5954 /* Load XBM image IMG which will be displayed on frame F from file
5955 SPECIFIED_FILE. Value is non-zero if successful. */
5957 static int
5958 xbm_load_image_from_file (f, img, specified_file)
5959 struct frame *f;
5960 struct image *img;
5961 Lisp_Object specified_file;
5963 int rc;
5964 unsigned char *data;
5965 int success_p = 0;
5966 Lisp_Object file;
5967 struct gcpro gcpro1;
5969 xassert (STRINGP (specified_file));
5970 file = Qnil;
5971 GCPRO1 (file);
5973 file = x_find_image_file (specified_file);
5974 if (!STRINGP (file))
5976 image_error ("Cannot find image file `%s'", specified_file, Qnil);
5977 UNGCPRO;
5978 return 0;
5981 rc = xbm_read_bitmap_file_data (SDATA (file), &img->width,
5982 &img->height, &data);
5983 if (rc)
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;
5990 xassert (img->width > 0 && img->height > 0);
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);
5997 value = image_spec_value (img->spec, QCbackground, NULL);
5998 if (!NILP (value))
5999 background = x_alloc_image_color (f, img, value, background);
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);
6012 if (img->pixmap == 0)
6014 x_clear_image (f, img);
6015 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
6017 else
6018 success_p = 1;
6020 UNBLOCK_INPUT;
6021 #endif /* MAC_TODO */
6023 else
6024 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
6026 UNGCPRO;
6027 return success_p;
6031 /* Fill image IMG which is used on frame F with pixmap data. Value is
6032 non-zero if successful. */
6034 static int
6035 xbm_load (f, img)
6036 struct frame *f;
6037 struct image *img;
6039 int success_p = 0;
6040 Lisp_Object file_name;
6042 xassert (xbm_image_p (img->spec));
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
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;
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);
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);
6068 BLOCK_INPUT;
6070 if (fmt[XBM_ASCENT].count)
6071 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
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);
6081 /* Set bits to the bitmap image data. */
6082 data = fmt[XBM_DATA].value;
6083 if (VECTORP (data))
6085 int i;
6086 char *p;
6087 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
6089 p = bits = (char *) alloca (nbytes * img->height);
6090 for (i = 0; i < img->height; ++i, p += nbytes)
6092 Lisp_Object line = XVECTOR (data)->contents[i];
6093 if (STRINGP (line))
6094 bcopy (SDATA (line), p, nbytes);
6095 else
6096 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
6099 else if (STRINGP (data))
6100 bits = SDATA (data);
6101 else
6102 bits = XBOOL_VECTOR (data)->data;
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 */
6116 if (img->pixmap)
6117 success_p = 1;
6118 else
6120 image_error ("Unable to create pixmap for XBM image `%s'",
6121 img->spec, Qnil);
6122 x_clear_image (f, img);
6125 UNBLOCK_INPUT;
6128 return success_p;
6133 /***********************************************************************
6134 XPM images
6135 ***********************************************************************/
6137 #if HAVE_XPM
6139 static int xpm_image_p P_ ((Lisp_Object object));
6140 static int xpm_load P_ ((struct frame *f, struct image *img));
6141 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
6143 #include "X11/xpm.h"
6145 /* The symbol `xpm' identifying XPM-format images. */
6147 Lisp_Object Qxpm;
6149 /* Indices of image specification fields in xpm_format, below. */
6151 enum xpm_keyword_index
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
6165 /* Vector of image_keyword structures describing the format
6166 of valid XPM image specifications. */
6168 static struct image_keyword xpm_format[XPM_LAST] =
6170 {":type", IMAGE_SYMBOL_VALUE, 1},
6171 {":file", IMAGE_STRING_VALUE, 0},
6172 {":data", IMAGE_STRING_VALUE, 0},
6173 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6174 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6175 {":relief", IMAGE_INTEGER_VALUE, 0},
6176 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6177 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6178 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6181 /* Structure describing the image type XBM. */
6183 static struct image_type xpm_type =
6185 &Qxpm,
6186 xpm_image_p,
6187 xpm_load,
6188 x_clear_image,
6189 NULL
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. */
6197 static int
6198 xpm_valid_color_symbols_p (color_symbols)
6199 Lisp_Object color_symbols;
6201 while (CONSP (color_symbols))
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);
6211 return NILP (color_symbols);
6215 /* Value is non-zero if OBJECT is a valid XPM image specification. */
6217 static int
6218 xpm_image_p (object)
6219 Lisp_Object object;
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));
6235 /* Load image IMG which will be displayed on frame F. Value is
6236 non-zero if successful. */
6238 static int
6239 xpm_load (f, img)
6240 struct frame *f;
6241 struct image *img;
6243 int rc, i;
6244 XpmAttributes attrs;
6245 Lisp_Object specified_file, color_symbols;
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
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))
6268 Lisp_Object tail;
6269 XpmColorSymbol *xpm_syms;
6270 int i, size;
6272 attrs.valuemask |= XpmColorSymbols;
6274 /* Count number of symbols. */
6275 attrs.numsymbols = 0;
6276 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
6277 ++attrs.numsymbols;
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;
6285 /* Fill the color symbol array. */
6286 for (tail = color_symbols, i = 0;
6287 CONSP (tail);
6288 ++i, tail = XCDR (tail))
6290 Lisp_Object name = XCAR (XCAR (tail));
6291 Lisp_Object color = XCDR (XCAR (tail));
6292 xpm_syms[i].name = (char *) alloca (SCHARS (name) + 1);
6293 strcpy (xpm_syms[i].name, SDATA (name));
6294 xpm_syms[i].value = (char *) alloca (SCHARS (color) + 1);
6295 strcpy (xpm_syms[i].value, SDATA (color));
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))
6305 Lisp_Object file = x_find_image_file (specified_file);
6306 if (!STRINGP (file))
6308 image_error ("Cannot find image file `%s'", specified_file, Qnil);
6309 UNBLOCK_INPUT;
6310 return 0;
6313 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
6314 SDATA (file), &img->pixmap, &img->mask,
6315 &attrs);
6317 else
6319 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
6320 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
6321 SDATA (buffer),
6322 &img->pixmap, &img->mask,
6323 &attrs);
6325 UNBLOCK_INPUT;
6327 if (rc == XpmSuccess)
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];
6336 img->width = attrs.width;
6337 img->height = attrs.height;
6338 xassert (img->width > 0 && img->height > 0);
6340 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
6341 BLOCK_INPUT;
6342 XpmFreeAttributes (&attrs);
6343 UNBLOCK_INPUT;
6345 else
6347 switch (rc)
6349 case XpmOpenFailed:
6350 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
6351 break;
6353 case XpmFileInvalid:
6354 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
6355 break;
6357 case XpmNoMemory:
6358 image_error ("Out of memory (%s)", img->spec, Qnil);
6359 break;
6361 case XpmColorFailed:
6362 image_error ("Color allocation error (%s)", img->spec, Qnil);
6363 break;
6365 default:
6366 image_error ("Unknown error (%s)", img->spec, Qnil);
6367 break;
6371 return rc == XpmSuccess;
6374 #endif /* HAVE_XPM != 0 */
6377 #if 0 /* MAC_TODO : Color tables on Mac. */
6378 /***********************************************************************
6379 Color table
6380 ***********************************************************************/
6382 /* An entry in the color table mapping an RGB color to a pixel color. */
6384 struct ct_color
6386 int r, g, b;
6387 unsigned long pixel;
6389 /* Next in color table collision list. */
6390 struct ct_color *next;
6393 /* The bucket vector size to use. Must be prime. */
6395 #define CT_SIZE 101
6397 /* Value is a hash of the RGB color given by R, G, and B. */
6399 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
6401 /* The color hash table. */
6403 struct ct_color **ct_table;
6405 /* Number of entries in the color table. */
6407 int ct_colors_allocated;
6409 /* Function prototypes. */
6411 static void init_color_table P_ ((void));
6412 static void free_color_table P_ ((void));
6413 static unsigned long *colors_in_color_table P_ ((int *n));
6414 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
6415 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
6418 /* Initialize the color table. */
6420 static void
6421 init_color_table ()
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;
6430 /* Free memory associated with the color table. */
6432 static void
6433 free_color_table ()
6435 int i;
6436 struct ct_color *p, *next;
6438 for (i = 0; i < CT_SIZE; ++i)
6439 for (p = ct_table[i]; p; p = next)
6441 next = p->next;
6442 xfree (p);
6445 xfree (ct_table);
6446 ct_table = NULL;
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. */
6455 static unsigned long
6456 lookup_rgb_color (f, r, g, b)
6457 struct frame *f;
6458 int r, g, b;
6460 unsigned hash = CT_HASH_RGB (r, g, b);
6461 int i = hash % CT_SIZE;
6462 struct ct_color *p;
6464 for (p = ct_table[i]; p; p = p->next)
6465 if (p->r == r && p->g == g && p->b == b)
6466 break;
6468 if (p == NULL)
6470 COLORREF color;
6471 Colormap cmap;
6472 int rc;
6474 color = RGB_TO_ULONG (r, g, b);
6476 ++ct_colors_allocated;
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;
6487 return p->pixel;
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. */
6494 static unsigned long
6495 lookup_pixel_color (f, pixel)
6496 struct frame *f;
6497 unsigned long pixel;
6499 int i = pixel % CT_SIZE;
6500 struct ct_color *p;
6502 for (p = ct_table[i]; p; p = p->next)
6503 if (p->pixel == pixel)
6504 break;
6506 if (p == NULL)
6508 XColor color;
6509 Colormap cmap;
6510 int rc;
6512 BLOCK_INPUT;
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;
6520 if (rc)
6522 ++ct_colors_allocated;
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;
6532 else
6533 return FRAME_FOREGROUND_PIXEL (f);
6535 return p->pixel;
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. */
6542 static unsigned long *
6543 colors_in_color_table (n)
6544 int *n;
6546 int i, j;
6547 struct ct_color *p;
6548 unsigned long *colors;
6550 if (ct_colors_allocated == 0)
6552 *n = 0;
6553 colors = NULL;
6555 else
6557 colors = (unsigned long *) xmalloc (ct_colors_allocated
6558 * sizeof *colors);
6559 *n = ct_colors_allocated;
6561 for (i = j = 0; i < CT_SIZE; ++i)
6562 for (p = ct_table[i]; p; p = p->next)
6563 colors[j++] = p->pixel;
6566 return colors;
6569 #endif /* MAC_TODO */
6572 /***********************************************************************
6573 Algorithms
6574 ***********************************************************************/
6576 #if 0 /* MAC_TODO : Mac versions of low level algorithms */
6577 static void x_laplace_write_row P_ ((struct frame *, long *,
6578 int, XImage *, int));
6579 static void x_laplace_read_row P_ ((struct frame *, Colormap,
6580 XColor *, int, XImage *, int));
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. */
6587 static void
6588 x_laplace_read_row (f, cmap, colors, width, ximg, y)
6589 struct frame *f;
6590 Colormap cmap;
6591 XColor *colors;
6592 int width;
6593 XImage *ximg;
6594 int y;
6596 int x;
6598 for (x = 0; x < width; ++x)
6599 colors[x].pixel = XGetPixel (ximg, x, y);
6601 XQueryColors (NULL, cmap, colors, width);
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. */
6609 static void
6610 x_laplace_write_row (f, pixels, width, ximg, y)
6611 struct frame *f;
6612 long *pixels;
6613 int width;
6614 XImage *ximg;
6615 int y;
6617 int x;
6619 for (x = 0; x < width; ++x)
6620 XPutPixel (ximg, x, y, pixels[x]);
6622 #endif /* MAC_TODO */
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. */
6628 static void
6629 x_laplace (f, img)
6630 struct frame *f;
6631 struct image *img;
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;
6644 BLOCK_INPUT;
6646 /* Get the X image IMG->pixmap. */
6647 ximg = XGetImage (NULL, img->pixmap,
6648 0, 0, img->width, img->height, ~0, ZPixmap);
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));
6655 /* Create an X image for output. */
6656 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
6657 &oimg, &pixmap);
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;
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;
6672 for (y = 2; y < img->height; ++y)
6674 int rowa = y % 3;
6675 int rowb = (y + 2) % 3;
6677 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
6679 for (x = 0; x < img->width - 2; ++x)
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;
6685 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
6686 b & 0xffff);
6689 x_laplace_write_row (f, out, img->width, oimg, out_y++);
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);
6697 /* Free the input image, and free resources of IMG. */
6698 XDestroyImage (ximg);
6699 x_clear_image (f, img);
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);
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 ();
6710 UNBLOCK_INPUT;
6711 #endif /* MAC_TODO */
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. */
6722 static int
6723 x_build_heuristic_mask (f, img, how)
6724 struct frame *f;
6725 struct image *img;
6726 Lisp_Object how;
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;
6734 BLOCK_INPUT;
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)
6741 UNBLOCK_INPUT;
6742 return 0;
6745 /* Get the X image of IMG->pixmap. */
6746 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
6747 ~0, ZPixmap);
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;
6754 if (CONSP (how))
6756 int rgb[3], i = 0;
6758 while (i < 3
6759 && CONSP (how)
6760 && NATNUMP (XCAR (how)))
6762 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
6763 how = XCDR (how);
6766 if (i == 3 && NILP (how))
6768 char color_name[30];
6769 XColor exact, color;
6770 Colormap cmap;
6772 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
6774 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
6775 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
6777 bg = color.pixel;
6778 look_at_corners_p = 0;
6783 if (look_at_corners_p)
6785 unsigned long corners[4];
6786 int i, best_count;
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);
6794 /* Choose the most frequently found color as background. */
6795 for (i = best_count = 0; i < 4; ++i)
6797 int j, n;
6799 for (j = n = 0; j < 4; ++j)
6800 if (corners[i] == corners[j])
6801 ++n;
6803 if (n > best_count)
6804 bg = corners[i], best_count = n;
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);
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);
6819 UNBLOCK_INPUT;
6820 #endif /* MAC_TODO */
6822 return 1;
6827 /***********************************************************************
6828 PBM (mono, gray, color)
6829 ***********************************************************************/
6830 #ifdef HAVE_PBM
6832 static int pbm_image_p P_ ((Lisp_Object object));
6833 static int pbm_load P_ ((struct frame *f, struct image *img));
6834 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
6836 /* The symbol `pbm' identifying images of this type. */
6838 Lisp_Object Qpbm;
6840 /* Indices of image specification fields in gs_format, below. */
6842 enum pbm_keyword_index
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
6855 /* Vector of image_keyword structures describing the format
6856 of valid user-defined image specifications. */
6858 static struct image_keyword pbm_format[PBM_LAST] =
6860 {":type", IMAGE_SYMBOL_VALUE, 1},
6861 {":file", IMAGE_STRING_VALUE, 0},
6862 {":data", IMAGE_STRING_VALUE, 0},
6863 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
6864 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
6865 {":relief", IMAGE_INTEGER_VALUE, 0},
6866 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
6867 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
6870 /* Structure describing the image type `pbm'. */
6872 static struct image_type pbm_type =
6874 &Qpbm,
6875 pbm_image_p,
6876 pbm_load,
6877 x_clear_image,
6878 NULL
6882 /* Return non-zero if OBJECT is a valid PBM image specification. */
6884 static int
6885 pbm_image_p (object)
6886 Lisp_Object object;
6888 struct image_keyword fmt[PBM_LAST];
6890 bcopy (pbm_format, fmt, sizeof fmt);
6892 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
6893 || (fmt[PBM_ASCENT].count
6894 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
6895 return 0;
6897 /* Must specify either :data or :file. */
6898 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
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. */
6906 static int
6907 pbm_scan_number (s, end)
6908 unsigned char **s, *end;
6910 int c, val = -1;
6912 while (*s < end)
6914 /* Skip white-space. */
6915 while (*s < end && (c = *(*s)++, isspace (c)))
6918 if (c == '#')
6920 /* Skip comment to end of line. */
6921 while (*s < end && (c = *(*s)++, c != '\n'))
6924 else if (isdigit (c))
6926 /* Read decimal number. */
6927 val = c - '0';
6928 while (*s < end && (c = *(*s)++, isdigit (c)))
6929 val = 10 * val + c - '0';
6930 break;
6932 else
6933 break;
6936 return val;
6940 /* Read FILE into memory. Value is a pointer to a buffer allocated
6941 with xmalloc holding FILE's contents. Value is null if an error
6942 occurred. *SIZE is set to the size of the file. */
6944 static char *
6945 pbm_read_file (file, size)
6946 Lisp_Object file;
6947 int *size;
6949 FILE *fp = NULL;
6950 char *buf = NULL;
6951 struct stat st;
6953 if (stat (SDATA (file), &st) == 0
6954 && (fp = fopen (SDATA (file), "r")) != NULL
6955 && (buf = (char *) xmalloc (st.st_size),
6956 fread (buf, 1, st.st_size, fp) == st.st_size))
6958 *size = st.st_size;
6959 fclose (fp);
6961 else
6963 if (fp)
6964 fclose (fp);
6965 if (buf)
6967 xfree (buf);
6968 buf = NULL;
6972 return buf;
6976 /* Load PBM image IMG for use on frame F. */
6978 static int
6979 pbm_load (f, img)
6980 struct frame *f;
6981 struct image *img;
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;
6993 specified_file = image_spec_value (img->spec, QCfile, NULL);
6994 file = Qnil;
6995 GCPRO1 (file);
6997 if (STRINGP (specified_file))
6999 file = x_find_image_file (specified_file);
7000 if (!STRINGP (file))
7002 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7003 UNGCPRO;
7004 return 0;
7007 contents = pbm_read_file (file, &size);
7008 if (contents == NULL)
7010 image_error ("Error reading `%s'", file, Qnil);
7011 UNGCPRO;
7012 return 0;
7015 p = contents;
7016 end = contents + size;
7018 else
7020 Lisp_Object data;
7021 data = image_spec_value (img->spec, QCdata, NULL);
7022 p = SDATA (data);
7023 end = p + SBYTES (data);
7026 /* Check magic number. */
7027 if (end - p < 2 || *p++ != 'P')
7029 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
7030 error:
7031 xfree (contents);
7032 UNGCPRO;
7033 return 0;
7036 switch (*p++)
7038 case '1':
7039 raw_p = 0, type = PBM_MONO;
7040 break;
7042 case '2':
7043 raw_p = 0, type = PBM_GRAY;
7044 break;
7046 case '3':
7047 raw_p = 0, type = PBM_COLOR;
7048 break;
7050 case '4':
7051 raw_p = 1, type = PBM_MONO;
7052 break;
7054 case '5':
7055 raw_p = 1, type = PBM_GRAY;
7056 break;
7058 case '6':
7059 raw_p = 1, type = PBM_COLOR;
7060 break;
7062 default:
7063 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
7064 goto error;
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);
7072 if (type != PBM_MONO)
7074 max_color_idx = pbm_scan_number (&p, end);
7075 if (raw_p && max_color_idx > 255)
7076 max_color_idx = 255;
7079 if (width < 0
7080 || height < 0
7081 || (type != PBM_MONO && max_color_idx < 0))
7082 goto error;
7084 BLOCK_INPUT;
7085 if (!x_create_x_image_and_pixmap (f, width, height, 0,
7086 &ximg, &img->pixmap))
7088 UNBLOCK_INPUT;
7089 goto error;
7092 /* Initialize the color hash table. */
7093 init_color_table ();
7095 if (type == PBM_MONO)
7097 int c = 0, g;
7099 for (y = 0; y < height; ++y)
7100 for (x = 0; x < width; ++x)
7102 if (raw_p)
7104 if ((x & 7) == 0)
7105 c = *p++;
7106 g = c & 0x80;
7107 c <<= 1;
7109 else
7110 g = pbm_scan_number (&p, end);
7112 XPutPixel (ximg, x, y, (g
7113 ? FRAME_FOREGROUND_PIXEL (f)
7114 : FRAME_BACKGROUND_PIXEL (f)));
7117 else
7119 for (y = 0; y < height; ++y)
7120 for (x = 0; x < width; ++x)
7122 int r, g, b;
7124 if (type == PBM_GRAY)
7125 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
7126 else if (raw_p)
7128 r = *p++;
7129 g = *p++;
7130 b = *p++;
7132 else
7134 r = pbm_scan_number (&p, end);
7135 g = pbm_scan_number (&p, end);
7136 b = pbm_scan_number (&p, end);
7139 if (r < 0 || g < 0 || b < 0)
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;
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));
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 ();
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;
7169 img->width = width;
7170 img->height = height;
7172 UNGCPRO;
7173 xfree (contents);
7174 return 1;
7176 #endif /* HAVE_PBM */
7179 /***********************************************************************
7181 ***********************************************************************/
7183 #if HAVE_PNG
7185 #include <png.h>
7187 /* Function prototypes. */
7189 static int png_image_p P_ ((Lisp_Object object));
7190 static int png_load P_ ((struct frame *f, struct image *img));
7192 /* The symbol `png' identifying images of this type. */
7194 Lisp_Object Qpng;
7196 /* Indices of image specification fields in png_format, below. */
7198 enum png_keyword_index
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
7211 /* Vector of image_keyword structures describing the format
7212 of valid user-defined image specifications. */
7214 static struct image_keyword png_format[PNG_LAST] =
7216 {":type", IMAGE_SYMBOL_VALUE, 1},
7217 {":data", IMAGE_STRING_VALUE, 0},
7218 {":file", IMAGE_STRING_VALUE, 0},
7219 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7220 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7221 {":relief", IMAGE_INTEGER_VALUE, 0},
7222 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7223 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7226 /* Structure describing the image type `png'. */
7228 static struct image_type png_type =
7230 &Qpng,
7231 png_image_p,
7232 png_load,
7233 x_clear_image,
7234 NULL
7238 /* Return non-zero if OBJECT is a valid PNG image specification. */
7240 static int
7241 png_image_p (object)
7242 Lisp_Object object;
7244 struct image_keyword fmt[PNG_LAST];
7245 bcopy (png_format, fmt, sizeof fmt);
7247 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
7248 || (fmt[PNG_ASCENT].count
7249 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
7250 return 0;
7252 /* Must specify either the :data or :file keyword. */
7253 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
7257 /* Error and warning handlers installed when the PNG library
7258 is initialized. */
7260 static void
7261 my_png_error (png_ptr, msg)
7262 png_struct *png_ptr;
7263 char *msg;
7265 xassert (png_ptr != NULL);
7266 image_error ("PNG error: %s", build_string (msg), Qnil);
7267 longjmp (png_ptr->jmpbuf, 1);
7271 static void
7272 my_png_warning (png_ptr, msg)
7273 png_struct *png_ptr;
7274 char *msg;
7276 xassert (png_ptr != NULL);
7277 image_error ("PNG warning: %s", build_string (msg), Qnil);
7280 /* Memory source for PNG decoding. */
7282 struct png_memory_storage
7284 unsigned char *bytes; /* The data */
7285 size_t len; /* How big is it? */
7286 int index; /* Where are we? */
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. */
7294 static void
7295 png_read_from_memory (png_ptr, data, length)
7296 png_structp png_ptr;
7297 png_bytep data;
7298 png_size_t length;
7300 struct png_memory_storage *tbr
7301 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
7303 if (length > tbr->len - tbr->index)
7304 png_error (png_ptr, "Read error");
7306 bcopy (tbr->bytes + tbr->index, data, length);
7307 tbr->index = tbr->index + length;
7310 /* Load PNG image IMG for use on frame F. Value is non-zero if
7311 successful. */
7313 static int
7314 png_load (f, img)
7315 struct frame *f;
7316 struct image *img;
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 */
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);
7345 if (NILP (specified_data))
7347 file = x_find_image_file (specified_file);
7348 if (!STRINGP (file))
7350 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7351 UNGCPRO;
7352 return 0;
7355 /* Open the image file. */
7356 fp = fopen (SDATA (file), "rb");
7357 if (!fp)
7359 image_error ("Cannot open image file `%s'", file, Qnil);
7360 UNGCPRO;
7361 fclose (fp);
7362 return 0;
7365 /* Check PNG signature. */
7366 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
7367 || !png_check_sig (sig, sizeof sig))
7369 image_error ("Not a PNG file:` %s'", file, Qnil);
7370 UNGCPRO;
7371 fclose (fp);
7372 return 0;
7375 else
7377 /* Read from memory. */
7378 tbr.bytes = SDATA (specified_data);
7379 tbr.len = SBYTES (specified_data);
7380 tbr.index = 0;
7382 /* Check PNG signature. */
7383 if (tbr.len < sizeof sig
7384 || !png_check_sig (tbr.bytes, sizeof sig))
7386 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
7387 UNGCPRO;
7388 return 0;
7391 /* Need to skip past the signature. */
7392 tbr.bytes += sizeof (sig);
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)
7400 if (fp) fclose (fp);
7401 UNGCPRO;
7402 return 0;
7405 info_ptr = png_create_info_struct (png_ptr);
7406 if (!info_ptr)
7408 png_destroy_read_struct (&png_ptr, NULL, NULL);
7409 if (fp) fclose (fp);
7410 UNGCPRO;
7411 return 0;
7414 end_info = png_create_info_struct (png_ptr);
7415 if (!end_info)
7417 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
7418 if (fp) fclose (fp);
7419 UNGCPRO;
7420 return 0;
7423 /* Set error jump-back. We come back here when the PNG library
7424 detects an error. */
7425 if (setjmp (png_ptr->jmpbuf))
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;
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);
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);
7448 /* If image contains simply transparency data, we prefer to
7449 construct a clipping mask. */
7450 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
7451 transparent_p = 1;
7452 else
7453 transparent_p = 0;
7455 /* This function is easier to write if we only have to handle
7456 one data format: RGB or RGBA with 8 bits per channel. Let's
7457 transform other formats into that format. */
7459 /* Strip more than 8 bits per channel. */
7460 if (bit_depth == 16)
7461 png_set_strip_16 (png_ptr);
7463 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
7464 if available. */
7465 png_set_expand (png_ptr);
7467 /* Convert grayscale images to RGB. */
7468 if (color_type == PNG_COLOR_TYPE_GRAY
7469 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
7470 png_set_gray_to_rgb (png_ptr);
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;
7476 /* Tell the PNG lib to handle gamma correction for us. */
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);
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)
7496 png_color_16 *image_background;
7498 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
7499 /* Image contains a background color with which to
7500 combine the image. */
7501 png_set_background (png_ptr, image_background,
7502 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
7503 else
7505 /* Image does not contain a background color with which
7506 to combine the image data via an alpha channel. Use
7507 the frame's background instead. */
7508 XColor color;
7509 Colormap cmap;
7510 png_color_16 frame_background;
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;
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;
7523 png_set_background (png_ptr, &frame_background,
7524 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
7528 /* Update info structure. */
7529 png_read_update_info (png_ptr, info_ptr);
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);
7539 /* Number of bytes needed for one row of the image. */
7540 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
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;
7548 /* Read the entire image. */
7549 png_read_image (png_ptr, rows);
7550 png_read_end (png_ptr, info_ptr);
7551 if (fp)
7553 fclose (fp);
7554 fp = NULL;
7557 BLOCK_INPUT;
7559 /* Create the X image and pixmap. */
7560 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7561 &img->pixmap))
7563 UNBLOCK_INPUT;
7564 goto error;
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))
7574 x_destroy_x_image (ximg);
7575 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
7576 img->pixmap = 0;
7577 UNBLOCK_INPUT;
7578 goto error;
7581 /* Fill the X image and mask from PNG data. */
7582 init_color_table ();
7584 for (y = 0; y < height; ++y)
7586 png_byte *p = rows[y];
7588 for (x = 0; x < width; ++x)
7590 unsigned r, g, b;
7592 r = *p++ << 8;
7593 g = *p++ << 8;
7594 b = *p++ << 8;
7595 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
7597 /* An alpha channel, aka mask channel, associates variable
7598 transparency with an image. Where other image formats
7599 support binary transparency---fully transparent or fully
7600 opaque---PNG allows up to 254 levels of partial transparency.
7601 The PNG library implements partial transparency by combining
7602 the image with a specified background color.
7604 I'm not sure how to handle this here nicely: because the
7605 background on which the image is displayed may change, for
7606 real alpha channel support, it would be necessary to create
7607 a new image for each possible background.
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. */
7613 if (channels == 4)
7615 if (mask_img)
7616 XPutPixel (mask_img, x, y, *p > 0);
7617 ++p;
7622 /* Remember colors allocated for this image. */
7623 img->colors = colors_in_color_table (&img->ncolors);
7624 free_color_table ();
7626 /* Clean up. */
7627 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
7628 xfree (rows);
7629 xfree (pixels);
7631 img->width = width;
7632 img->height = height;
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);
7638 /* Same for the mask. */
7639 if (mask_img)
7641 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
7642 x_destroy_x_image (mask_img);
7645 UNBLOCK_INPUT;
7646 UNGCPRO;
7647 return 1;
7650 #endif /* HAVE_PNG != 0 */
7654 /***********************************************************************
7655 JPEG
7656 ***********************************************************************/
7658 #if HAVE_JPEG
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 */
7667 #include <jpeglib.h>
7668 #include <jerror.h>
7669 #include <setjmp.h>
7671 #ifdef HAVE_STLIB_H_1
7672 #define HAVE_STDLIB_H 1
7673 #endif
7675 static int jpeg_image_p P_ ((Lisp_Object object));
7676 static int jpeg_load P_ ((struct frame *f, struct image *img));
7678 /* The symbol `jpeg' identifying images of this type. */
7680 Lisp_Object Qjpeg;
7682 /* Indices of image specification fields in gs_format, below. */
7684 enum jpeg_keyword_index
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
7697 /* Vector of image_keyword structures describing the format
7698 of valid user-defined image specifications. */
7700 static struct image_keyword jpeg_format[JPEG_LAST] =
7702 {":type", IMAGE_SYMBOL_VALUE, 1},
7703 {":data", IMAGE_STRING_VALUE, 0},
7704 {":file", IMAGE_STRING_VALUE, 0},
7705 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
7706 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
7707 {":relief", IMAGE_INTEGER_VALUE, 0},
7708 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
7709 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
7712 /* Structure describing the image type `jpeg'. */
7714 static struct image_type jpeg_type =
7716 &Qjpeg,
7717 jpeg_image_p,
7718 jpeg_load,
7719 x_clear_image,
7720 NULL
7724 /* Return non-zero if OBJECT is a valid JPEG image specification. */
7726 static int
7727 jpeg_image_p (object)
7728 Lisp_Object object;
7730 struct image_keyword fmt[JPEG_LAST];
7732 bcopy (jpeg_format, fmt, sizeof fmt);
7734 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
7735 || (fmt[JPEG_ASCENT].count
7736 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
7737 return 0;
7739 /* Must specify either the :data or :file keyword. */
7740 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
7744 struct my_jpeg_error_mgr
7746 struct jpeg_error_mgr pub;
7747 jmp_buf setjmp_buffer;
7750 static void
7751 my_error_exit (cinfo)
7752 j_common_ptr cinfo;
7754 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
7755 longjmp (mgr->setjmp_buffer, 1);
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. */
7762 static void
7763 our_init_source (cinfo)
7764 j_decompress_ptr cinfo;
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. */
7773 static boolean
7774 our_fill_input_buffer (cinfo)
7775 j_decompress_ptr cinfo;
7777 /* Insert a fake EOI marker. */
7778 struct jpeg_source_mgr *src = cinfo->src;
7779 static JOCTET buffer[2];
7781 buffer[0] = (JOCTET) 0xFF;
7782 buffer[1] = (JOCTET) JPEG_EOI;
7784 src->next_input_byte = buffer;
7785 src->bytes_in_buffer = 2;
7786 return TRUE;
7790 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
7791 is the JPEG data source manager. */
7793 static void
7794 our_skip_input_data (cinfo, num_bytes)
7795 j_decompress_ptr cinfo;
7796 long num_bytes;
7798 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
7800 if (src)
7802 if (num_bytes > src->bytes_in_buffer)
7803 ERREXIT (cinfo, JERR_INPUT_EOF);
7805 src->bytes_in_buffer -= num_bytes;
7806 src->next_input_byte += num_bytes;
7811 /* Method to terminate data source. Called by
7812 jpeg_finish_decompress() after all data has been processed. */
7814 static void
7815 our_term_source (cinfo)
7816 j_decompress_ptr cinfo;
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. */
7825 static void
7826 jpeg_memory_src (cinfo, data, len)
7827 j_decompress_ptr cinfo;
7828 JOCTET *data;
7829 unsigned int len;
7831 struct jpeg_source_mgr *src;
7833 if (cinfo->src == NULL)
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;
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;
7854 /* Load image IMG for use on frame F. Patterned after example.c
7855 from the JPEG lib. */
7857 static int
7858 jpeg_load (f, img)
7859 struct frame *f;
7860 struct image *img;
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;
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);
7881 if (NILP (specified_data))
7883 file = x_find_image_file (specified_file);
7884 if (!STRINGP (file))
7886 image_error ("Cannot find image file `%s'", specified_file, Qnil);
7887 UNGCPRO;
7888 return 0;
7891 fp = fopen (SDATA (file), "r");
7892 if (fp == NULL)
7894 image_error ("Cannot open `%s'", file, Qnil);
7895 UNGCPRO;
7896 return 0;
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);
7905 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
7907 if (rc == 1)
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));
7916 /* Close the input file and destroy the JPEG object. */
7917 if (fp)
7918 fclose (fp);
7919 jpeg_destroy_decompress (&cinfo);
7921 BLOCK_INPUT;
7923 /* If we already have an XImage, free that. */
7924 x_destroy_x_image (ximg);
7926 /* Free pixmap and colors. */
7927 x_clear_image (f, img);
7929 UNBLOCK_INPUT;
7930 UNGCPRO;
7931 return 0;
7934 /* Create the JPEG decompression object. Let it read from fp.
7935 Read the JPEG image header. */
7936 jpeg_create_decompress (&cinfo);
7938 if (NILP (specified_data))
7939 jpeg_stdio_src (&cinfo, fp);
7940 else
7941 jpeg_memory_src (&cinfo, SDATA (specified_data),
7942 SBYTES (specified_data));
7944 jpeg_read_header (&cinfo, TRUE);
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;
7953 BLOCK_INPUT;
7955 /* Create X image and pixmap. */
7956 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
7957 &img->pixmap))
7959 UNBLOCK_INPUT;
7960 longjmp (mgr.setjmp_buffer, 2);
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. */
7969 int i, ir, ig, ib;
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;
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);
7986 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
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);
7996 /* Remember those colors actually allocated. */
7997 img->colors = colors_in_color_table (&img->ncolors);
7998 free_color_table ();
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)
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]]);
8012 /* Clean up. */
8013 jpeg_finish_decompress (&cinfo);
8014 jpeg_destroy_decompress (&cinfo);
8015 if (fp)
8016 fclose (fp);
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;
8026 #endif /* HAVE_JPEG */
8030 /***********************************************************************
8031 TIFF
8032 ***********************************************************************/
8034 #if HAVE_TIFF
8036 #include <tiffio.h>
8038 static int tiff_image_p P_ ((Lisp_Object object));
8039 static int tiff_load P_ ((struct frame *f, struct image *img));
8041 /* The symbol `tiff' identifying images of this type. */
8043 Lisp_Object Qtiff;
8045 /* Indices of image specification fields in tiff_format, below. */
8047 enum tiff_keyword_index
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
8060 /* Vector of image_keyword structures describing the format
8061 of valid user-defined image specifications. */
8063 static struct image_keyword tiff_format[TIFF_LAST] =
8065 {":type", IMAGE_SYMBOL_VALUE, 1},
8066 {":data", IMAGE_STRING_VALUE, 0},
8067 {":file", IMAGE_STRING_VALUE, 0},
8068 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8069 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8070 {":relief", IMAGE_INTEGER_VALUE, 0},
8071 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8072 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8075 /* Structure describing the image type `tiff'. */
8077 static struct image_type tiff_type =
8079 &Qtiff,
8080 tiff_image_p,
8081 tiff_load,
8082 x_clear_image,
8083 NULL
8087 /* Return non-zero if OBJECT is a valid TIFF image specification. */
8089 static int
8090 tiff_image_p (object)
8091 Lisp_Object object;
8093 struct image_keyword fmt[TIFF_LAST];
8094 bcopy (tiff_format, fmt, sizeof fmt);
8096 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
8097 || (fmt[TIFF_ASCENT].count
8098 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
8099 return 0;
8101 /* Must specify either the :data or :file keyword. */
8102 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
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.
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. */
8115 typedef struct
8117 unsigned char *bytes;
8118 size_t len;
8119 int index;
8121 tiff_memory_source;
8123 static size_t
8124 tiff_read_from_memory (data, buf, size)
8125 thandle_t data;
8126 tdata_t buf;
8127 tsize_t size;
8129 tiff_memory_source *src = (tiff_memory_source *) data;
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;
8138 static size_t
8139 tiff_write_from_memory (data, buf, size)
8140 thandle_t data;
8141 tdata_t buf;
8142 tsize_t size;
8144 return (size_t) -1;
8147 static toff_t
8148 tiff_seek_in_memory (data, off, whence)
8149 thandle_t data;
8150 toff_t off;
8151 int whence;
8153 tiff_memory_source *src = (tiff_memory_source *) data;
8154 int idx;
8156 switch (whence)
8158 case SEEK_SET: /* Go from beginning of source. */
8159 idx = off;
8160 break;
8162 case SEEK_END: /* Go from end of source. */
8163 idx = src->len + off;
8164 break;
8166 case SEEK_CUR: /* Go from current position. */
8167 idx = src->index + off;
8168 break;
8170 default: /* Invalid `whence'. */
8171 return -1;
8174 if (idx > src->len || idx < 0)
8175 return -1;
8177 src->index = idx;
8178 return src->index;
8181 static int
8182 tiff_close_memory (data)
8183 thandle_t data;
8185 /* NOOP */
8186 return 0;
8189 static int
8190 tiff_mmap_memory (data, pbase, psize)
8191 thandle_t data;
8192 tdata_t *pbase;
8193 toff_t *psize;
8195 /* It is already _IN_ memory. */
8196 return 0;
8199 static void
8200 tiff_unmap_memory (data, base, size)
8201 thandle_t data;
8202 tdata_t base;
8203 toff_t size;
8205 /* We don't need to do this. */
8208 static toff_t
8209 tiff_size_of_memory (data)
8210 thandle_t data;
8212 return ((tiff_memory_source *) data)->len;
8215 /* Load TIFF image IMG for use on frame F. Value is non-zero if
8216 successful. */
8218 static int
8219 tiff_load (f, img)
8220 struct frame *f;
8221 struct image *img;
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;
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);
8238 if (NILP (specified_data))
8240 /* Read from a file */
8241 file = x_find_image_file (specified_file);
8242 if (!STRINGP (file))
8244 image_error ("Cannot find image file `%s'", file, Qnil);
8245 UNGCPRO;
8246 return 0;
8249 /* Try to open the image file. */
8250 tiff = TIFFOpen (SDATA (file), "r");
8251 if (tiff == NULL)
8253 image_error ("Cannot open `%s'", file, Qnil);
8254 UNGCPRO;
8255 return 0;
8258 else
8260 /* Memory source! */
8261 memsrc.bytes = SDATA (specified_data);
8262 memsrc.len = SBYTES (specified_data);
8263 memsrc.index = 0;
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);
8274 if (!tiff)
8276 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
8277 UNGCPRO;
8278 return 0;
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);
8288 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
8289 TIFFClose (tiff);
8290 if (!rc)
8292 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
8293 xfree (buf);
8294 UNGCPRO;
8295 return 0;
8298 BLOCK_INPUT;
8300 /* Create the X image and pixmap. */
8301 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8303 UNBLOCK_INPUT;
8304 xfree (buf);
8305 UNGCPRO;
8306 return 0;
8309 /* Initialize the color table. */
8310 init_color_table ();
8312 /* Process the pixel raster. Origin is in the lower-left corner. */
8313 for (y = 0; y < height; ++y)
8315 uint32 *row = buf + y * width;
8317 for (x = 0; x < width; ++x)
8319 uint32 abgr = row[x];
8320 int r = TIFFGetR (abgr) << 8;
8321 int g = TIFFGetG (abgr) << 8;
8322 int b = TIFFGetB (abgr) << 8;
8323 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
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 ();
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;
8337 img->width = width;
8338 img->height = height;
8340 UNGCPRO;
8341 return 1;
8344 #endif /* HAVE_TIFF != 0 */
8348 /***********************************************************************
8350 ***********************************************************************/
8352 #if HAVE_GIF
8354 #include <gif_lib.h>
8356 static int gif_image_p P_ ((Lisp_Object object));
8357 static int gif_load P_ ((struct frame *f, struct image *img));
8359 /* The symbol `gif' identifying images of this type. */
8361 Lisp_Object Qgif;
8363 /* Indices of image specification fields in gif_format, below. */
8365 enum gif_keyword_index
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
8379 /* Vector of image_keyword structures describing the format
8380 of valid user-defined image specifications. */
8382 static struct image_keyword gif_format[GIF_LAST] =
8384 {":type", IMAGE_SYMBOL_VALUE, 1},
8385 {":data", IMAGE_STRING_VALUE, 0},
8386 {":file", IMAGE_STRING_VALUE, 0},
8387 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8388 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8389 {":relief", IMAGE_INTEGER_VALUE, 0},
8390 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8391 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8392 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
8395 /* Structure describing the image type `gif'. */
8397 static struct image_type gif_type =
8399 &Qgif,
8400 gif_image_p,
8401 gif_load,
8402 x_clear_image,
8403 NULL
8406 /* Return non-zero if OBJECT is a valid GIF image specification. */
8408 static int
8409 gif_image_p (object)
8410 Lisp_Object object;
8412 struct image_keyword fmt[GIF_LAST];
8413 bcopy (gif_format, fmt, sizeof fmt);
8415 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
8416 || (fmt[GIF_ASCENT].count
8417 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
8418 return 0;
8420 /* Must specify either the :data or :file keyword. */
8421 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
8424 /* Reading a GIF image from memory
8425 Based on the PNG memory stuff to a certain extent. */
8427 typedef struct
8429 unsigned char *bytes;
8430 size_t len;
8431 int index;
8433 gif_memory_source;
8435 /* Make the current memory source available to gif_read_from_memory.
8436 It's done this way because not all versions of libungif support
8437 a UserData field in the GifFileType structure. */
8438 static gif_memory_source *current_gif_memory_src;
8440 static int
8441 gif_read_from_memory (file, buf, len)
8442 GifFileType *file;
8443 GifByteType *buf;
8444 int len;
8446 gif_memory_source *src = current_gif_memory_src;
8448 if (len > src->len - src->index)
8449 return -1;
8451 bcopy (src->bytes + src->index, buf, len);
8452 src->index += len;
8453 return len;
8457 /* Load GIF image IMG for use on frame F. Value is non-zero if
8458 successful. */
8460 static int
8461 gif_load (f, img)
8462 struct frame *f;
8463 struct image *img;
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;
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);
8483 if (NILP (specified_data))
8485 file = x_find_image_file (specified_file);
8486 if (!STRINGP (file))
8488 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8489 UNGCPRO;
8490 return 0;
8493 /* Open the GIF file. */
8494 gif = DGifOpenFileName (SDATA (file));
8495 if (gif == NULL)
8497 image_error ("Cannot open `%s'", file, Qnil);
8498 UNGCPRO;
8499 return 0;
8502 else
8504 /* Read from memory! */
8505 current_gif_memory_src = &memsrc;
8506 memsrc.bytes = SDATA (specified_data);
8507 memsrc.len = SBYTES (specified_data);
8508 memsrc.index = 0;
8510 gif = DGifOpen(&memsrc, gif_read_from_memory);
8511 if (!gif)
8513 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
8514 UNGCPRO;
8515 return 0;
8519 /* Read entire contents. */
8520 rc = DGifSlurp (gif);
8521 if (rc == GIF_ERROR)
8523 image_error ("Error reading `%s'", img->spec, Qnil);
8524 DGifCloseFile (gif);
8525 UNGCPRO;
8526 return 0;
8529 image = image_spec_value (img->spec, QCindex, NULL);
8530 ino = INTEGERP (image) ? XFASTINT (image) : 0;
8531 if (ino >= gif->ImageCount)
8533 image_error ("Invalid image number `%s' in image `%s'",
8534 image, img->spec);
8535 DGifCloseFile (gif);
8536 UNGCPRO;
8537 return 0;
8540 width = img->width = gif->SWidth;
8541 height = img->height = gif->SHeight;
8543 BLOCK_INPUT;
8545 /* Create the X image and pixmap. */
8546 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
8548 UNBLOCK_INPUT;
8549 DGifCloseFile (gif);
8550 UNGCPRO;
8551 return 0;
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);
8561 for (i = 0; i < gif_color_map->ColorCount; ++i)
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);
8569 img->colors = colors_in_color_table (&img->ncolors);
8570 free_color_table ();
8572 /* Clear the part of the screen image that are not covered by
8573 the image from the GIF file. Full animated GIF support
8574 requires more than can be done here (see the gif89 spec,
8575 disposal methods). Let's simply assume that the part
8576 not covered by a sub-image is in the frame's background color. */
8577 image_top = gif->SavedImages[ino].ImageDesc.Top;
8578 image_left = gif->SavedImages[ino].ImageDesc.Left;
8579 image_width = gif->SavedImages[ino].ImageDesc.Width;
8580 image_height = gif->SavedImages[ino].ImageDesc.Height;
8582 for (y = 0; y < image_top; ++y)
8583 for (x = 0; x < width; ++x)
8584 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
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));
8590 for (y = image_top; y < image_top + image_height; ++y)
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));
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;
8603 if (gif->SavedImages[ino].ImageDesc.Interlace)
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];
8610 pass = 0;
8612 for (y = 0; y < image_height; y++)
8614 if (row >= image_height)
8616 row = interlace_start[++pass];
8617 while (row >= image_height)
8618 row = interlace_start[++pass];
8621 for (x = 0; x < image_width; x++)
8623 int i = raster[(y * image_width) + x];
8624 XPutPixel (ximg, x + image_left, row + image_top,
8625 pixel_colors[i]);
8628 row += interlace_increment[pass];
8631 else
8633 for (y = 0; y < image_height; ++y)
8634 for (x = 0; x < image_width; ++x)
8636 int i = raster[y* image_width + x];
8637 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
8641 DGifCloseFile (gif);
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;
8648 UNGCPRO;
8649 return 1;
8652 #endif /* HAVE_GIF != 0 */
8656 /***********************************************************************
8657 Ghostscript
8658 ***********************************************************************/
8660 #ifdef HAVE_GHOSTSCRIPT
8661 static int gs_image_p P_ ((Lisp_Object object));
8662 static int gs_load P_ ((struct frame *f, struct image *img));
8663 static void gs_clear_image P_ ((struct frame *f, struct image *img));
8665 /* The symbol `postscript' identifying images of this type. */
8667 Lisp_Object Qpostscript;
8669 /* Keyword symbols. */
8671 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
8673 /* Indices of image specification fields in gs_format, below. */
8675 enum gs_keyword_index
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
8691 /* Vector of image_keyword structures describing the format
8692 of valid user-defined image specifications. */
8694 static struct image_keyword gs_format[GS_LAST] =
8696 {":type", IMAGE_SYMBOL_VALUE, 1},
8697 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8698 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
8699 {":file", IMAGE_STRING_VALUE, 1},
8700 {":loader", IMAGE_FUNCTION_VALUE, 0},
8701 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
8702 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8703 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8704 {":relief", IMAGE_INTEGER_VALUE, 0},
8705 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8706 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8709 /* Structure describing the image type `ghostscript'. */
8711 static struct image_type gs_type =
8713 &Qpostscript,
8714 gs_image_p,
8715 gs_load,
8716 gs_clear_image,
8717 NULL
8721 /* Free X resources of Ghostscript image IMG which is used on frame F. */
8723 static void
8724 gs_clear_image (f, img)
8725 struct frame *f;
8726 struct image *img;
8728 /* IMG->data.ptr_val may contain a recorded colormap. */
8729 xfree (img->data.ptr_val);
8730 x_clear_image (f, img);
8734 /* Return non-zero if OBJECT is a valid Ghostscript image
8735 specification. */
8737 static int
8738 gs_image_p (object)
8739 Lisp_Object object;
8741 struct image_keyword fmt[GS_LAST];
8742 Lisp_Object tem;
8743 int i;
8745 bcopy (gs_format, fmt, sizeof fmt);
8747 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
8748 || (fmt[GS_ASCENT].count
8749 && XFASTINT (fmt[GS_ASCENT].value) > 100))
8750 return 0;
8752 /* Bounding box must be a list or vector containing 4 integers. */
8753 tem = fmt[GS_BOUNDING_BOX].value;
8754 if (CONSP (tem))
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;
8762 else if (VECTORP (tem))
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;
8770 else
8771 return 0;
8773 return 1;
8777 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
8778 if successful. */
8780 static int
8781 gs_load (f, img)
8782 struct frame *f;
8783 struct image *img;
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;
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;
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;
8811 if (!img->pixmap)
8813 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
8814 return 0;
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);
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);
8828 sprintf (buffer, "%lu %lu",
8829 FRAME_FOREGROUND_PIXEL (f),
8830 FRAME_BACKGROUND_PIXEL (f));
8831 pixel_colors = build_string (buffer);
8833 XSETFRAME (frame, f);
8834 loader = image_spec_value (img->spec, QCloader, NULL);
8835 if (NILP (loader))
8836 loader = intern ("gs-load-image");
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);
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. */
8852 void
8853 x_kill_gs_process (pixmap, f)
8854 Pixmap pixmap;
8855 struct frame *f;
8857 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8858 int class, i;
8859 struct image *img;
8861 /* Find the image containing PIXMAP. */
8862 for (i = 0; i < c->used; ++i)
8863 if (c->images[i]->pixmap == pixmap)
8864 break;
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;
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)
8880 XImage *ximg;
8882 BLOCK_INPUT;
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)
8889 int x, y;
8891 /* Initialize the color table. */
8892 init_color_table ();
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)
8900 unsigned long pixel = XGetPixel (ximg, x, y);
8901 lookup_pixel_color (f, pixel);
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);
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)
8917 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
8918 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
8919 img->colors, img->ncolors, 0);
8921 #endif
8923 else
8924 image_error ("Cannot get X image of `%s'; colors will not be freed",
8925 img->spec, Qnil);
8927 UNBLOCK_INPUT;
8931 #endif /* HAVE_GHOSTSCRIPT */
8934 /***********************************************************************
8935 Window properties
8936 ***********************************************************************/
8938 DEFUN ("x-change-window-property", Fx_change_window_property,
8939 Sx_change_window_property, 2, 3, 0,
8940 doc: /* Change window property PROP to VALUE on the X window of FRAME.
8941 PROP and VALUE must be strings. FRAME nil or omitted means use the
8942 selected frame. Value is VALUE. */)
8943 (prop, value, frame)
8944 Lisp_Object frame, prop, value;
8946 #if 0 /* MAC_TODO : port window properties to Mac */
8947 struct frame *f = check_x_frame (frame);
8948 Atom prop_atom;
8950 CHECK_STRING (prop);
8951 CHECK_STRING (value);
8953 BLOCK_INPUT;
8954 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
8955 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
8956 prop_atom, XA_STRING, 8, PropModeReplace,
8957 SDATA (value), SCHARS (value));
8959 /* Make sure the property is set when we return. */
8960 XFlush (FRAME_W32_DISPLAY (f));
8961 UNBLOCK_INPUT;
8963 #endif /* MAC_TODO */
8965 return value;
8969 DEFUN ("x-delete-window-property", Fx_delete_window_property,
8970 Sx_delete_window_property, 1, 2, 0,
8971 doc: /* Remove window property PROP from X window of FRAME.
8972 FRAME nil or omitted means use the selected frame. Value is PROP. */)
8973 (prop, frame)
8974 Lisp_Object prop, frame;
8976 #if 0 /* MAC_TODO : port window properties to Mac */
8978 struct frame *f = check_x_frame (frame);
8979 Atom prop_atom;
8981 CHECK_STRING (prop);
8982 BLOCK_INPUT;
8983 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
8984 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
8986 /* Make sure the property is removed when we return. */
8987 XFlush (FRAME_W32_DISPLAY (f));
8988 UNBLOCK_INPUT;
8989 #endif /* MAC_TODO */
8991 return prop;
8995 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
8996 1, 2, 0,
8997 doc: /* Value is the value of window property PROP on FRAME.
8998 If FRAME is nil or omitted, use the selected frame. Value is nil
8999 if FRAME hasn't a property with name PROP or if PROP has no string
9000 value. */)
9001 (prop, frame)
9002 Lisp_Object prop, frame;
9004 #if 0 /* MAC_TODO : port window properties to Mac */
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;
9015 CHECK_STRING (prop);
9016 BLOCK_INPUT;
9017 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
9018 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9019 prop_atom, 0, 0, False, XA_STRING,
9020 &actual_type, &actual_format, &actual_size,
9021 &bytes_remaining, (unsigned char **) &tmp_data);
9022 if (rc == Success)
9024 int size = bytes_remaining;
9026 XFree (tmp_data);
9027 tmp_data = NULL;
9029 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9030 prop_atom, 0, bytes_remaining,
9031 False, XA_STRING,
9032 &actual_type, &actual_format,
9033 &actual_size, &bytes_remaining,
9034 (unsigned char **) &tmp_data);
9035 if (rc == Success)
9036 prop_value = make_string (tmp_data, size);
9038 XFree (tmp_data);
9041 UNBLOCK_INPUT;
9043 return prop_value;
9045 #endif /* MAC_TODO */
9046 return Qnil;
9051 /***********************************************************************
9052 Hourglass cursor
9053 ***********************************************************************/
9055 /* If non-null, an asynchronous timer that, when it expires, displays
9056 an hourglass cursor on all frames. */
9058 static struct atimer *hourglass_atimer;
9060 /* Non-zero means an hourglass cursor is currently shown. */
9062 static int hourglass_shown_p;
9064 /* Number of seconds to wait before displaying an hourglass cursor. */
9066 static Lisp_Object Vhourglass_delay;
9068 /* Default number of seconds to wait before displaying an hourglass
9069 cursor. */
9071 #define DEFAULT_HOURGLASS_DELAY 1
9073 /* Function prototypes. */
9075 static void show_hourglass P_ ((struct atimer *));
9076 static void hide_hourglass P_ ((void));
9079 /* Cancel a currently active hourglass timer, and start a new one. */
9081 void
9082 start_hourglass ()
9084 #if 0 /* MAC_TODO: cursor shape changes. */
9085 EMACS_TIME delay;
9086 int secs, usecs = 0;
9088 cancel_hourglass ();
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)
9096 Lisp_Object tem;
9097 tem = Ftruncate (Vhourglass_delay, Qnil);
9098 secs = XFASTINT (tem);
9099 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
9101 else
9102 secs = DEFAULT_HOURGLASS_DELAY;
9104 EMACS_SET_SECS_USECS (delay, secs, usecs);
9105 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
9106 show_hourglass, NULL);
9107 #endif /* MAC_TODO */
9111 /* Cancel the hourglass cursor timer if active, hide an hourglass
9112 cursor if shown. */
9114 void
9115 cancel_hourglass ()
9117 if (hourglass_atimer)
9119 cancel_atimer (hourglass_atimer);
9120 hourglass_atimer = NULL;
9123 if (hourglass_shown_p)
9124 hide_hourglass ();
9128 /* Timer function of hourglass_atimer. TIMER is equal to
9129 hourglass_atimer.
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. */
9136 static void
9137 show_hourglass (timer)
9138 struct atimer *timer;
9140 #if 0 /* MAC_TODO: cursor shape changes. */
9141 /* The timer implementation will cancel this timer automatically
9142 after this function has run. Set hourglass_atimer to null
9143 so that we know the timer doesn't have to be canceled. */
9144 hourglass_atimer = NULL;
9146 if (!hourglass_shown_p)
9148 Lisp_Object rest, frame;
9150 BLOCK_INPUT;
9152 FOR_EACH_FRAME (rest, frame)
9153 if (FRAME_W32_P (XFRAME (frame)))
9155 struct frame *f = XFRAME (frame);
9157 f->output_data.w32->hourglass_p = 1;
9159 if (!f->output_data.w32->hourglass_window)
9161 unsigned long mask = CWCursor;
9162 XSetWindowAttributes attrs;
9164 attrs.cursor = f->output_data.w32->hourglass_cursor;
9166 f->output_data.w32->hourglass_window
9167 = XCreateWindow (FRAME_X_DISPLAY (f),
9168 FRAME_OUTER_WINDOW (f),
9169 0, 0, 32000, 32000, 0, 0,
9170 InputOnly,
9171 CopyFromParent,
9172 mask, &attrs);
9175 XMapRaised (FRAME_X_DISPLAY (f),
9176 f->output_data.w32->hourglass_window);
9177 XFlush (FRAME_X_DISPLAY (f));
9180 hourglass_shown_p = 1;
9181 UNBLOCK_INPUT;
9183 #endif /* MAC_TODO */
9187 /* Hide the hourglass cursor on all frames, if it is currently shown. */
9189 static void
9190 hide_hourglass ()
9192 #if 0 /* MAC_TODO: cursor shape changes. */
9193 if (hourglass_shown_p)
9195 Lisp_Object rest, frame;
9197 BLOCK_INPUT;
9198 FOR_EACH_FRAME (rest, frame)
9200 struct frame *f = XFRAME (frame);
9202 if (FRAME_W32_P (f)
9203 /* Watch out for newly created frames. */
9204 && f->output_data.x->hourglass_window)
9206 XUnmapWindow (FRAME_X_DISPLAY (f),
9207 f->output_data.x->hourglass_window);
9208 /* Sync here because XTread_socket looks at the
9209 hourglass_p flag that is reset to zero below. */
9210 XSync (FRAME_X_DISPLAY (f), False);
9211 f->output_data.x->hourglass_p = 0;
9215 hourglass_shown_p = 0;
9216 UNBLOCK_INPUT;
9218 #endif /* MAC_TODO */
9223 /***********************************************************************
9224 Tool tips
9225 ***********************************************************************/
9227 static Lisp_Object x_create_tip_frame P_ ((struct mac_display_info *,
9228 Lisp_Object));
9230 /* The frame of a currently visible tooltip, or null. */
9232 Lisp_Object tip_frame;
9234 /* If non-nil, a timer started that hides the last tooltip when it
9235 fires. */
9237 Lisp_Object tip_timer;
9238 Window tip_window;
9240 /* If non-nil, a vector of 3 elements containing the last args
9241 with which x-show-tip was called. See there. */
9243 Lisp_Object last_show_tip_args;
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. */
9248 static Lisp_Object
9249 x_create_tip_frame (dpyinfo, parms)
9250 struct mac_display_info *dpyinfo;
9251 Lisp_Object parms;
9253 #if 0 /* MAC_TODO : Mac version */
9254 struct frame *f;
9255 Lisp_Object frame, tem;
9256 Lisp_Object name;
9257 long window_prompting = 0;
9258 int width, height;
9259 int count = SPECPDL_INDEX ();
9260 struct gcpro gcpro1, gcpro2, gcpro3;
9261 struct kboard *kb;
9263 check_x ();
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;
9269 #ifdef MULTI_KBOARD
9270 kb = dpyinfo->kboard;
9271 #else
9272 kb = &the_only_kboard;
9273 #endif
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;
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;
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;
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;
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))
9309 f->name = build_string (dpyinfo->x_id_name);
9310 f->explicit_name = 0;
9312 else
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);
9320 /* Extract the window parameters from the supplied values
9321 that are needed to determine window geometry. */
9323 Lisp_Object font;
9325 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
9327 BLOCK_INPUT;
9328 /* First, try whatever font the caller has specified. */
9329 if (STRINGP (font))
9331 tem = Fquery_fontset (font, Qnil);
9332 if (STRINGP (tem))
9333 font = x_new_fontset (f, SDATA (tem));
9334 else
9335 font = x_new_font (f, SDATA (font));
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");
9356 x_default_parameter (f, parms, Qfont, font,
9357 "font", "Font", RES_TYPE_STRING);
9360 x_default_parameter (f, parms, Qborder_width, make_number (2),
9361 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
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)))
9368 Lisp_Object value;
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);
9377 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
9378 "internalBorderWidth", "internalBorderWidth",
9379 RES_TYPE_NUMBER);
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);
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);
9401 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
9402 window_prompting = x_figure_window_size (f, parms);
9404 if (window_prompting & XNegative)
9406 if (window_prompting & YNegative)
9407 f->output_data.w32->win_gravity = SouthEastGravity;
9408 else
9409 f->output_data.w32->win_gravity = NorthEastGravity;
9411 else
9413 if (window_prompting & YNegative)
9414 f->output_data.w32->win_gravity = SouthWestGravity;
9415 else
9416 f->output_data.w32->win_gravity = NorthWestGravity;
9419 f->output_data.w32->size_hint_flags = window_prompting;
9421 XSetWindowAttributes attrs;
9422 unsigned long mask;
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. */
9442 CopyFromParent, InputOutput, CopyFromParent,
9443 mask, &attrs);
9444 UNBLOCK_INPUT;
9447 x_make_gc (f);
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);
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);
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));
9470 f->no_split = 1;
9472 UNGCPRO;
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);
9479 /* Now that the frame is official, it counts as a reference to
9480 its display. */
9481 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
9483 return unbind_to (count, frame);
9484 #endif /* MAC_TODO */
9485 return Qnil;
9489 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
9490 doc : /* Show STRING in a "tooltip" window on frame FRAME.
9491 A tooltip window is a small window displaying a string.
9493 FRAME nil or omitted means use the selected frame.
9495 PARMS is an optional list of frame parameters which can be used to
9496 change the tooltip's appearance.
9498 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
9499 means use the default timeout of 5 seconds.
9501 If the list of frame parameters PARAMS contains a `left' parameters,
9502 the tooltip is displayed at that x-position. Otherwise it is
9503 displayed at the mouse position, with offset DX added (default is 5 if
9504 DX isn't specified). Likewise for the y-position; if a `top' frame
9505 parameter is specified, it determines the y-position of the tooltip
9506 window, otherwise it is displayed at the mouse position, with offset
9507 DY added (default is 10). */)
9508 (string, frame, parms, timeout, dx, dy)
9509 Lisp_Object string, frame, parms, timeout, dx, dy;
9511 struct frame *f;
9512 struct window *w;
9513 Window root, child;
9514 Lisp_Object buffer, top, left;
9515 struct buffer *old_buffer;
9516 struct text_pos pos;
9517 int i, width, height;
9518 int root_x, root_y, win_x, win_y;
9519 unsigned pmask;
9520 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
9521 int old_windows_or_buffers_changed = windows_or_buffers_changed;
9522 int count = SPECPDL_INDEX ();
9524 specbind (Qinhibit_redisplay, Qt);
9526 GCPRO4 (string, parms, frame, timeout);
9528 CHECK_STRING (string);
9529 f = check_x_frame (frame);
9530 if (NILP (timeout))
9531 timeout = make_number (5);
9532 else
9533 CHECK_NATNUM (timeout);
9535 if (NILP (dx))
9536 dx = make_number (5);
9537 else
9538 CHECK_NUMBER (dx);
9540 if (NILP (dy))
9541 dy = make_number (-10);
9542 else
9543 CHECK_NUMBER (dy);
9545 if (NILP (last_show_tip_args))
9546 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
9548 if (!NILP (tip_frame))
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);
9554 if (EQ (frame, last_frame)
9555 && !NILP (Fequal (last_string, string))
9556 && !NILP (Fequal (last_parms, parms)))
9558 struct frame *f = XFRAME (tip_frame);
9560 /* Only DX and DY have changed. */
9561 if (!NILP (tip_timer))
9563 Lisp_Object timer = tip_timer;
9564 tip_timer = Qnil;
9565 call1 (Qcancel_timer, timer);
9568 #if 0 /* MAC_TODO : Mac specifics */
9569 BLOCK_INPUT;
9570 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9571 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
9572 root_x, root_y - PIXEL_HEIGHT (f));
9573 UNBLOCK_INPUT;
9574 #endif /* MAC_TODO */
9575 goto start_timer;
9579 /* Hide a previous tip, if any. */
9580 Fx_hide_tip ();
9582 ASET (last_show_tip_args, 0, string);
9583 ASET (last_show_tip_args, 1, frame);
9584 ASET (last_show_tip_args, 2, parms);
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);
9599 /* Create a frame for the tooltip, and record it in the global
9600 variable tip_frame. */
9601 frame = x_create_tip_frame (FRAME_MAC_DISPLAY_INFO (f), parms);
9602 f = XFRAME (frame);
9604 /* Set up the frame's root window. Currently we use a size of 80
9605 columns x 40 lines. If someone wants to show a larger tip, he
9606 will loose. I don't think this is a realistic case. */
9607 w = XWINDOW (FRAME_ROOT_WINDOW (f));
9608 w->left = w->top = make_number (0);
9609 w->width = make_number (80);
9610 w->height = make_number (40);
9611 adjust_glyphs (f);
9612 w->pseudo_window_p = 1;
9614 /* Display the tooltip text in a temporary buffer. */
9615 buffer = Fget_buffer_create (build_string (" *tip*"));
9616 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
9617 old_buffer = current_buffer;
9618 set_buffer_internal_1 (XBUFFER (buffer));
9619 Ferase_buffer ();
9620 Finsert (1, &string);
9621 clear_glyph_matrix (w->desired_matrix);
9622 clear_glyph_matrix (w->current_matrix);
9623 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
9624 try_window (FRAME_ROOT_WINDOW (f), pos);
9626 /* Compute width and height of the tooltip. */
9627 width = height = 0;
9628 for (i = 0; i < w->desired_matrix->nrows; ++i)
9630 struct glyph_row *row = &w->desired_matrix->rows[i];
9631 struct glyph *last;
9632 int row_width;
9634 /* Stop at the first empty row at the end. */
9635 if (!row->enabled_p || !row->displays_text_p)
9636 break;
9638 /* Let the row go over the full width of the frame. */
9639 row->full_width_p = 1;
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])
9645 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
9646 row_width = row->pixel_width - last->pixel_width;
9648 else
9649 row_width = row->pixel_width;
9651 height += row->height;
9652 width = max (width, row_width);
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);
9660 /* Move the tooltip window where the mouse pointer is. Resize and
9661 show it. */
9662 #if 0 /* TODO : Mac specifics */
9663 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
9665 BLOCK_INPUT;
9666 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
9667 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
9668 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
9669 root_x + 5, root_y - height - 5, width, height);
9670 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
9671 UNBLOCK_INPUT;
9672 #endif /* MAC_TODO */
9674 /* Draw into the window. */
9675 w->must_be_updated_p = 1;
9676 update_single_window (w, 1);
9678 /* Restore original current buffer. */
9679 set_buffer_internal_1 (old_buffer);
9680 windows_or_buffers_changed = old_windows_or_buffers_changed;
9682 start_timer:
9683 /* Let the tip disappear after timeout seconds. */
9684 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
9685 intern ("x-hide-tip"));
9687 UNGCPRO;
9688 return unbind_to (count, Qnil);
9692 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
9693 doc: /* Hide the current tooltip window, if there is any.
9694 Value is t is tooltip was open, nil otherwise. */)
9697 int count;
9698 Lisp_Object deleted, frame, timer;
9699 struct gcpro gcpro1, gcpro2;
9701 /* Return quickly if nothing to do. */
9702 if (NILP (tip_timer) && NILP (tip_frame))
9703 return Qnil;
9705 frame = tip_frame;
9706 timer = tip_timer;
9707 GCPRO2 (frame, timer);
9708 tip_frame = tip_timer = deleted = Qnil;
9710 count = SPECPDL_INDEX ();
9711 specbind (Qinhibit_redisplay, Qt);
9712 specbind (Qinhibit_quit, Qt);
9714 if (!NILP (timer))
9715 call1 (Qcancel_timer, timer);
9717 if (FRAMEP (frame))
9719 Fdelete_frame (frame, Qnil);
9720 deleted = Qt;
9723 UNGCPRO;
9724 return unbind_to (count, deleted);
9729 /***********************************************************************
9730 File selection dialog
9731 ***********************************************************************/
9733 #if 0 /* MAC_TODO: can standard file dialog */
9734 extern Lisp_Object Qfile_name_history;
9736 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
9737 doc: /* Read file name, prompting with PROMPT in directory DIR.
9738 Use a file selection dialog.
9739 Select DEFAULT-FILENAME in the dialog's file selection box, if
9740 specified. Don't let the user enter a file name in the file
9741 selection dialog's entry field, if MUSTMATCH is non-nil. */)
9742 (prompt, dir, default_filename, mustmatch)
9743 Lisp_Object prompt, dir, default_filename, mustmatch;
9745 struct frame *f = SELECTED_FRAME ();
9746 Lisp_Object file = Qnil;
9747 int count = SPECPDL_INDEX ();
9748 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
9749 char filename[MAX_PATH + 1];
9750 char init_dir[MAX_PATH + 1];
9751 int use_dialog_p = 1;
9753 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
9754 CHECK_STRING (prompt);
9755 CHECK_STRING (dir);
9757 /* Create the dialog with PROMPT as title, using DIR as initial
9758 directory and using "*" as pattern. */
9759 dir = Fexpand_file_name (dir, Qnil);
9760 strncpy (init_dir, SDATA (dir), MAX_PATH);
9761 init_dir[MAX_PATH] = '\0';
9762 unixtodos_filename (init_dir);
9764 if (STRINGP (default_filename))
9766 char *file_name_only;
9767 char *full_path_name = SDATA (default_filename);
9769 unixtodos_filename (full_path_name);
9771 file_name_only = strrchr (full_path_name, '\\');
9772 if (!file_name_only)
9773 file_name_only = full_path_name;
9774 else
9776 file_name_only++;
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;
9785 strncpy (filename, file_name_only, MAX_PATH);
9786 filename[MAX_PATH] = '\0';
9788 else
9789 filename[0] = '\0';
9791 if (use_dialog_p)
9793 OPENFILENAME file_details;
9794 char *filename_file;
9796 /* Prevent redisplay. */
9797 specbind (Qinhibit_redisplay, Qt);
9798 BLOCK_INPUT;
9800 bzero (&file_details, sizeof (file_details));
9801 file_details.lStructSize = sizeof (file_details);
9802 file_details.hwndOwner = FRAME_W32_WINDOW (f);
9803 file_details.lpstrFile = filename;
9804 file_details.nMaxFile = sizeof (filename);
9805 file_details.lpstrInitialDir = init_dir;
9806 file_details.lpstrTitle = SDATA (prompt);
9807 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
9809 if (!NILP (mustmatch))
9810 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
9812 if (GetOpenFileName (&file_details))
9814 dostounix_filename (filename);
9815 file = build_string (filename);
9817 else
9818 file = Qnil;
9820 UNBLOCK_INPUT;
9821 file = unbind_to (count, file);
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);
9830 UNGCPRO;
9832 /* Make "Cancel" equivalent to C-g. */
9833 if (NILP (file))
9834 Fsignal (Qquit, Qnil);
9836 return unbind_to (count, file);
9838 #endif /* MAC_TODO */
9842 /***********************************************************************
9843 Tests
9844 ***********************************************************************/
9846 #if GLYPH_DEBUG
9848 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
9849 doc: /* Value is non-nil if SPEC is a valid image specification. */)
9850 (spec)
9851 Lisp_Object spec;
9853 return valid_image_p (spec) ? Qt : Qnil;
9857 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
9858 (spec)
9859 Lisp_Object spec;
9861 int id = -1;
9863 if (valid_image_p (spec))
9864 id = lookup_image (SELECTED_FRAME (), spec);
9866 debug_print (spec);
9867 return make_number (id);
9870 #endif /* GLYPH_DEBUG != 0 */
9874 void
9875 syms_of_macfns ()
9877 /* Certainly running on Mac. */
9878 mac_in_use = 1;
9880 /* The section below is built by the lisp expression at the top of the file,
9881 just above where these variables are declared. */
9882 /*&&& init symbols here &&&*/
9883 Qauto_raise = intern ("auto-raise");
9884 staticpro (&Qauto_raise);
9885 Qauto_lower = intern ("auto-lower");
9886 staticpro (&Qauto_lower);
9887 Qborder_color = intern ("border-color");
9888 staticpro (&Qborder_color);
9889 Qborder_width = intern ("border-width");
9890 staticpro (&Qborder_width);
9891 Qcursor_color = intern ("cursor-color");
9892 staticpro (&Qcursor_color);
9893 Qcursor_type = intern ("cursor-type");
9894 staticpro (&Qcursor_type);
9895 Qgeometry = intern ("geometry");
9896 staticpro (&Qgeometry);
9897 Qicon_left = intern ("icon-left");
9898 staticpro (&Qicon_left);
9899 Qicon_top = intern ("icon-top");
9900 staticpro (&Qicon_top);
9901 Qicon_type = intern ("icon-type");
9902 staticpro (&Qicon_type);
9903 Qicon_name = intern ("icon-name");
9904 staticpro (&Qicon_name);
9905 Qinternal_border_width = intern ("internal-border-width");
9906 staticpro (&Qinternal_border_width);
9907 Qleft = intern ("left");
9908 staticpro (&Qleft);
9909 Qright = intern ("right");
9910 staticpro (&Qright);
9911 Qmouse_color = intern ("mouse-color");
9912 staticpro (&Qmouse_color);
9913 Qnone = intern ("none");
9914 staticpro (&Qnone);
9915 Qparent_id = intern ("parent-id");
9916 staticpro (&Qparent_id);
9917 Qscroll_bar_width = intern ("scroll-bar-width");
9918 staticpro (&Qscroll_bar_width);
9919 Qsuppress_icon = intern ("suppress-icon");
9920 staticpro (&Qsuppress_icon);
9921 Qundefined_color = intern ("undefined-color");
9922 staticpro (&Qundefined_color);
9923 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
9924 staticpro (&Qvertical_scroll_bars);
9925 Qvisibility = intern ("visibility");
9926 staticpro (&Qvisibility);
9927 Qwindow_id = intern ("window-id");
9928 staticpro (&Qwindow_id);
9929 Qx_frame_parameter = intern ("x-frame-parameter");
9930 staticpro (&Qx_frame_parameter);
9931 Qx_resource_name = intern ("x-resource-name");
9932 staticpro (&Qx_resource_name);
9933 Quser_position = intern ("user-position");
9934 staticpro (&Quser_position);
9935 Quser_size = intern ("user-size");
9936 staticpro (&Quser_size);
9937 Qscreen_gamma = intern ("screen-gamma");
9938 staticpro (&Qscreen_gamma);
9939 Qline_spacing = intern ("line-spacing");
9940 staticpro (&Qline_spacing);
9941 Qcenter = intern ("center");
9942 staticpro (&Qcenter);
9943 /* This is the end of symbol initialization. */
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);
9960 /* Text property `display' should be nonsticky by default. */
9961 Vtext_property_default_nonsticky
9962 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
9965 Qlaplace = intern ("laplace");
9966 staticpro (&Qlaplace);
9968 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
9969 staticpro (&Qface_set_after_frame_default);
9971 Fput (Qundefined_color, Qerror_conditions,
9972 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
9973 Fput (Qundefined_color, Qerror_message,
9974 build_string ("Undefined color"));
9976 init_x_parm_symbols ();
9978 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
9979 doc: /* List of directories to search for window system bitmap files. */);
9980 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
9982 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
9983 doc: /* The shape of the pointer when over text.
9984 Changing the value does not affect existing frames
9985 unless you set the mouse color. */);
9986 Vx_pointer_shape = Qnil;
9988 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
9989 doc: /* The name Emacs uses to look up resources; for internal use only.
9990 `x-get-resource' uses this as the first component of the instance name
9991 when requesting resource values.
9992 Emacs initially sets `x-resource-name' to the name under which Emacs
9993 was invoked, or to the value specified with the `-name' or `-rn'
9994 switches, if present. */);
9995 Vx_resource_name = Qnil;
9997 Vx_nontext_pointer_shape = Qnil;
9999 Vx_mode_pointer_shape = Qnil;
10001 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
10002 doc: /* The shape of the pointer when Emacs is hourglass.
10003 This variable takes effect when you create a new frame
10004 or when you set the mouse color. */);
10005 Vx_hourglass_pointer_shape = Qnil;
10007 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
10008 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
10009 display_hourglass_p = 1;
10011 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
10012 doc: /* *Seconds to wait before displaying an hourglass pointer.
10013 Value must be an integer or float. */);
10014 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
10016 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
10017 &Vx_sensitive_text_pointer_shape,
10018 doc: /* The shape of the pointer when over mouse-sensitive text.
10019 This variable takes effect when you create a new frame
10020 or when you set the mouse color. */);
10021 Vx_sensitive_text_pointer_shape = Qnil;
10023 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
10024 doc: /* A string indicating the foreground color of the cursor box. */);
10025 Vx_cursor_fore_pixel = Qnil;
10027 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
10028 doc: /* Non-nil if no window manager is in use.
10029 Emacs doesn't try to figure this out; this is always nil
10030 unless you set it to something else. */);
10031 /* We don't have any way to find this out, so set it to nil
10032 and maybe the user would like to set it to t. */
10033 Vx_no_window_manager = Qnil;
10035 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
10036 &Vx_pixel_size_width_font_regexp,
10037 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
10039 Since Emacs gets width of a font matching with this regexp from
10040 PIXEL_SIZE field of the name, font finding mechanism gets faster for
10041 such a font. This is especially effective for such large fonts as
10042 Chinese, Japanese, and Korean. */);
10043 Vx_pixel_size_width_font_regexp = Qnil;
10045 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
10046 doc: /* Time after which cached images are removed from the cache.
10047 When an image has not been displayed this many seconds, remove it
10048 from the image cache. Value must be an integer or nil with nil
10049 meaning don't clear the cache. */);
10050 Vimage_cache_eviction_delay = make_number (30 * 60);
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);
10086 /* Setting callback functions for fontset handler. */
10087 get_font_info_func = x_get_font_info;
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
10094 load_font_func = x_load_font;
10095 find_ccl_program_func = x_find_ccl_program;
10096 query_font_func = x_query_font;
10098 set_frame_fontset_func = x_set_font;
10099 check_window_system_func = check_mac;
10101 #if 0 /* MAC_TODO: Image support for Mac Images. */
10102 Qxbm = intern ("xbm");
10103 staticpro (&Qxbm);
10104 QCtype = intern (":type");
10105 staticpro (&QCtype);
10106 QCconversion = intern (":conversion");
10107 staticpro (&QCconversion);
10108 QCheuristic_mask = intern (":heuristic-mask");
10109 staticpro (&QCheuristic_mask);
10110 QCcolor_symbols = intern (":color-symbols");
10111 staticpro (&QCcolor_symbols);
10112 QCascent = intern (":ascent");
10113 staticpro (&QCascent);
10114 QCmargin = intern (":margin");
10115 staticpro (&QCmargin);
10116 QCrelief = intern (":relief");
10117 staticpro (&QCrelief);
10118 Qpostscript = intern ("postscript");
10119 staticpro (&Qpostscript);
10120 QCloader = intern (":loader");
10121 staticpro (&QCloader);
10122 QCbounding_box = intern (":bounding-box");
10123 staticpro (&QCbounding_box);
10124 QCpt_width = intern (":pt-width");
10125 staticpro (&QCpt_width);
10126 QCpt_height = intern (":pt-height");
10127 staticpro (&QCpt_height);
10128 QCindex = intern (":index");
10129 staticpro (&QCindex);
10130 Qpbm = intern ("pbm");
10131 staticpro (&Qpbm);
10133 #if HAVE_XPM
10134 Qxpm = intern ("xpm");
10135 staticpro (&Qxpm);
10136 #endif
10138 #if HAVE_JPEG
10139 Qjpeg = intern ("jpeg");
10140 staticpro (&Qjpeg);
10141 #endif
10143 #if HAVE_TIFF
10144 Qtiff = intern ("tiff");
10145 staticpro (&Qtiff);
10146 #endif
10148 #if HAVE_GIF
10149 Qgif = intern ("gif");
10150 staticpro (&Qgif);
10151 #endif
10153 #if HAVE_PNG
10154 Qpng = intern ("png");
10155 staticpro (&Qpng);
10156 #endif
10158 defsubr (&Sclear_image_cache);
10160 #if GLYPH_DEBUG
10161 defsubr (&Simagep);
10162 defsubr (&Slookup_image);
10163 #endif
10164 #endif /* MAC_TODO */
10166 hourglass_atimer = NULL;
10167 hourglass_shown_p = 0;
10169 defsubr (&Sx_show_tip);
10170 defsubr (&Sx_hide_tip);
10171 staticpro (&tip_timer);
10172 tip_timer = Qnil;
10174 #if 0 /* MAC_TODO */
10175 defsubr (&Sx_file_dialog);
10176 #endif
10180 void
10181 init_xfns ()
10183 image_types = NULL;
10184 Vimage_types = Qnil;
10186 define_image_type (&xbm_type);
10187 #if 0 /* NTEMACS_TODO : Image support for W32 */
10188 define_image_type (&gs_type);
10189 define_image_type (&pbm_type);
10191 #if HAVE_XPM
10192 define_image_type (&xpm_type);
10193 #endif
10195 #if HAVE_JPEG
10196 define_image_type (&jpeg_type);
10197 #endif
10199 #if HAVE_TIFF
10200 define_image_type (&tiff_type);
10201 #endif
10203 #if HAVE_GIF
10204 define_image_type (&gif_type);
10205 #endif
10207 #if HAVE_PNG
10208 define_image_type (&png_type);
10209 #endif
10210 #endif /* NTEMACS_TODO */