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