Include errno.h, string.h, unistd.h. Don't declare errno, strerror.
[emacs.git] / src / w32fns.c
blobf02a1c43ebe5cede171670bd90265af8a7b00b42
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999
3 Free Software Foundation, Inc.
5 This file is part of GNU Emacs.
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
22 /* Added by Kevin Gallo */
24 #include <config.h>
26 #include <signal.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <errno.h>
31 #include "lisp.h"
32 #include "charset.h"
33 #include "w32term.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 "w32heap.h"
44 #include "termhooks.h"
45 #include "coding.h"
46 #include "ccl.h"
47 #include "systime.h"
49 #include "bitmaps/gray.xbm"
51 #include <commdlg.h>
52 #include <shellapi.h>
53 #include <ctype.h>
55 extern void free_frame_menubar ();
56 extern double atof ();
57 extern int w32_console_toggle_lock_key (int vk_code, Lisp_Object new_state);
58 extern int quit_char;
60 /* A definition of XColor for non-X frames. */
61 #ifndef HAVE_X_WINDOWS
62 typedef struct {
63 unsigned long pixel;
64 unsigned short red, green, blue;
65 char flags;
66 char pad;
67 } XColor;
68 #endif
70 extern char *lispy_function_keys[];
72 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
73 it, and including `bitmaps/gray' more than once is a problem when
74 config.h defines `static' as an empty replacement string. */
76 int gray_bitmap_width = gray_width;
77 int gray_bitmap_height = gray_height;
78 unsigned char *gray_bitmap_bits = gray_bits;
80 /* The colormap for converting color names to RGB values */
81 Lisp_Object Vw32_color_map;
83 /* Non nil if alt key presses are passed on to Windows. */
84 Lisp_Object Vw32_pass_alt_to_system;
86 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
87 to alt_modifier. */
88 Lisp_Object Vw32_alt_is_meta;
90 /* If non-zero, the windows virtual key code for an alternative quit key. */
91 Lisp_Object Vw32_quit_key;
93 /* Non nil if left window key events are passed on to Windows (this only
94 affects whether "tapping" the key opens the Start menu). */
95 Lisp_Object Vw32_pass_lwindow_to_system;
97 /* Non nil if right window key events are passed on to Windows (this
98 only affects whether "tapping" the key opens the Start menu). */
99 Lisp_Object Vw32_pass_rwindow_to_system;
101 /* Virtual key code used to generate "phantom" key presses in order
102 to stop system from acting on Windows key events. */
103 Lisp_Object Vw32_phantom_key_code;
105 /* Modifier associated with the left "Windows" key, or nil to act as a
106 normal key. */
107 Lisp_Object Vw32_lwindow_modifier;
109 /* Modifier associated with the right "Windows" key, or nil to act as a
110 normal key. */
111 Lisp_Object Vw32_rwindow_modifier;
113 /* Modifier associated with the "Apps" key, or nil to act as a normal
114 key. */
115 Lisp_Object Vw32_apps_modifier;
117 /* Value is nil if Num Lock acts as a function key. */
118 Lisp_Object Vw32_enable_num_lock;
120 /* Value is nil if Caps Lock acts as a function key. */
121 Lisp_Object Vw32_enable_caps_lock;
123 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
124 Lisp_Object Vw32_scroll_lock_modifier;
126 /* Switch to control whether we inhibit requests for synthesized bold
127 and italic versions of fonts. */
128 Lisp_Object Vw32_enable_synthesized_fonts;
130 /* Enable palette management. */
131 Lisp_Object Vw32_enable_palette;
133 /* Control how close left/right button down events must be to
134 be converted to a middle button down event. */
135 Lisp_Object Vw32_mouse_button_tolerance;
137 /* Minimum interval between mouse movement (and scroll bar drag)
138 events that are passed on to the event loop. */
139 Lisp_Object Vw32_mouse_move_interval;
141 /* The name we're using in resource queries. */
142 Lisp_Object Vx_resource_name;
144 /* Non nil if no window manager is in use. */
145 Lisp_Object Vx_no_window_manager;
147 /* Non-zero means we're allowed to display a busy cursor. */
149 int display_busy_cursor_p;
151 /* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
154 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
155 Lisp_Object Vx_busy_pointer_shape;
157 /* The shape when over mouse-sensitive text. */
159 Lisp_Object Vx_sensitive_text_pointer_shape;
161 /* Color of chars displayed in cursor box. */
163 Lisp_Object Vx_cursor_fore_pixel;
165 /* Nonzero if using Windows. */
167 static int w32_in_use;
169 /* Search path for bitmap files. */
171 Lisp_Object Vx_bitmap_file_path;
173 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
175 Lisp_Object Vx_pixel_size_width_font_regexp;
177 /* Alist of bdf fonts and the files that define them. */
178 Lisp_Object Vw32_bdf_filename_alist;
180 Lisp_Object Vw32_system_coding_system;
182 /* A flag to control whether fonts are matched strictly or not. */
183 int w32_strict_fontnames;
185 /* A flag to control whether we should only repaint if GetUpdateRect
186 indicates there is an update region. */
187 int w32_strict_painting;
189 /* Associative list linking character set strings to Windows codepages. */
190 Lisp_Object Vw32_charset_info_alist;
192 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
193 #ifndef VIETNAMESE_CHARSET
194 #define VIETNAMESE_CHARSET 163
195 #endif
198 /* Evaluate this expression to rebuild the section of syms_of_w32fns
199 that initializes and staticpros the symbols declared below. Note
200 that Emacs 18 has a bug that keeps C-x C-e from being able to
201 evaluate this expression.
203 (progn
204 ;; Accumulate a list of the symbols we want to initialize from the
205 ;; declarations at the top of the file.
206 (goto-char (point-min))
207 (search-forward "/\*&&& symbols declared here &&&*\/\n")
208 (let (symbol-list)
209 (while (looking-at "Lisp_Object \\(Q[a-z_]+\\)")
210 (setq symbol-list
211 (cons (buffer-substring (match-beginning 1) (match-end 1))
212 symbol-list))
213 (forward-line 1))
214 (setq symbol-list (nreverse symbol-list))
215 ;; Delete the section of syms_of_... where we initialize the symbols.
216 (search-forward "\n /\*&&& init symbols here &&&*\/\n")
217 (let ((start (point)))
218 (while (looking-at "^ Q")
219 (forward-line 2))
220 (kill-region start (point)))
221 ;; Write a new symbol initialization section.
222 (while symbol-list
223 (insert (format " %s = intern (\"" (car symbol-list)))
224 (let ((start (point)))
225 (insert (substring (car symbol-list) 1))
226 (subst-char-in-region start (point) ?_ ?-))
227 (insert (format "\");\n staticpro (&%s);\n" (car symbol-list)))
228 (setq symbol-list (cdr symbol-list)))))
232 /*&&& symbols declared here &&&*/
233 Lisp_Object Qauto_raise;
234 Lisp_Object Qauto_lower;
235 Lisp_Object Qbar;
236 Lisp_Object Qborder_color;
237 Lisp_Object Qborder_width;
238 Lisp_Object Qbox;
239 Lisp_Object Qcursor_color;
240 Lisp_Object Qcursor_type;
241 Lisp_Object Qgeometry;
242 Lisp_Object Qicon_left;
243 Lisp_Object Qicon_top;
244 Lisp_Object Qicon_type;
245 Lisp_Object Qicon_name;
246 Lisp_Object Qinternal_border_width;
247 Lisp_Object Qleft;
248 Lisp_Object Qright;
249 Lisp_Object Qmouse_color;
250 Lisp_Object Qnone;
251 Lisp_Object Qparent_id;
252 Lisp_Object Qscroll_bar_width;
253 Lisp_Object Qsuppress_icon;
254 Lisp_Object Qundefined_color;
255 Lisp_Object Qvertical_scroll_bars;
256 Lisp_Object Qvisibility;
257 Lisp_Object Qwindow_id;
258 Lisp_Object Qx_frame_parameter;
259 Lisp_Object Qx_resource_name;
260 Lisp_Object Quser_position;
261 Lisp_Object Quser_size;
262 Lisp_Object Qscreen_gamma;
263 Lisp_Object Qline_spacing;
264 Lisp_Object Qcenter;
265 Lisp_Object Qhyper;
266 Lisp_Object Qsuper;
267 Lisp_Object Qmeta;
268 Lisp_Object Qalt;
269 Lisp_Object Qctrl;
270 Lisp_Object Qcontrol;
271 Lisp_Object Qshift;
273 Lisp_Object Qw32_charset_ansi;
274 Lisp_Object Qw32_charset_default;
275 Lisp_Object Qw32_charset_symbol;
276 Lisp_Object Qw32_charset_shiftjis;
277 Lisp_Object Qw32_charset_hangul;
278 Lisp_Object Qw32_charset_gb2312;
279 Lisp_Object Qw32_charset_chinesebig5;
280 Lisp_Object Qw32_charset_oem;
282 #ifdef JOHAB_CHARSET
283 Lisp_Object Qw32_charset_easteurope;
284 Lisp_Object Qw32_charset_turkish;
285 Lisp_Object Qw32_charset_baltic;
286 Lisp_Object Qw32_charset_russian;
287 Lisp_Object Qw32_charset_arabic;
288 Lisp_Object Qw32_charset_greek;
289 Lisp_Object Qw32_charset_hebrew;
290 Lisp_Object Qw32_charset_thai;
291 Lisp_Object Qw32_charset_johab;
292 Lisp_Object Qw32_charset_mac;
293 #endif
295 #ifdef UNICODE_CHARSET
296 Lisp_Object Qw32_charset_unicode;
297 #endif
299 extern Lisp_Object Qtop;
300 extern Lisp_Object Qdisplay;
301 extern Lisp_Object Qtool_bar_lines;
303 /* State variables for emulating a three button mouse. */
304 #define LMOUSE 1
305 #define MMOUSE 2
306 #define RMOUSE 4
308 static int button_state = 0;
309 static W32Msg saved_mouse_button_msg;
310 static unsigned mouse_button_timer; /* non-zero when timer is active */
311 static W32Msg saved_mouse_move_msg;
312 static unsigned mouse_move_timer;
314 /* W95 mousewheel handler */
315 unsigned int msh_mousewheel = 0;
317 #define MOUSE_BUTTON_ID 1
318 #define MOUSE_MOVE_ID 2
320 /* The below are defined in frame.c. */
322 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
323 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
324 extern Lisp_Object Qtool_bar_lines;
326 extern Lisp_Object Vwindow_system_version;
328 Lisp_Object Qface_set_after_frame_default;
330 /* From w32term.c. */
331 extern Lisp_Object Vw32_num_mouse_buttons;
332 extern Lisp_Object Vw32_recognize_altgr;
335 /* Error if we are not connected to MS-Windows. */
336 void
337 check_w32 ()
339 if (! w32_in_use)
340 error ("MS-Windows not in use or not initialized");
343 /* Nonzero if we can use mouse menus.
344 You should not call this unless HAVE_MENUS is defined. */
347 have_menus_p ()
349 return w32_in_use;
352 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
353 and checking validity for W32. */
355 FRAME_PTR
356 check_x_frame (frame)
357 Lisp_Object frame;
359 FRAME_PTR f;
361 if (NILP (frame))
362 frame = selected_frame;
363 CHECK_LIVE_FRAME (frame, 0);
364 f = XFRAME (frame);
365 if (! FRAME_W32_P (f))
366 error ("non-w32 frame used");
367 return f;
370 /* Let the user specify an display with a frame.
371 nil stands for the selected frame--or, if that is not a w32 frame,
372 the first display on the list. */
374 static struct w32_display_info *
375 check_x_display_info (frame)
376 Lisp_Object frame;
378 if (NILP (frame))
380 struct frame *sf = XFRAME (selected_frame);
382 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
383 return FRAME_W32_DISPLAY_INFO (sf);
384 else
385 return &one_w32_display_info;
387 else if (STRINGP (frame))
388 return x_display_info_for_name (frame);
389 else
391 FRAME_PTR f;
393 CHECK_LIVE_FRAME (frame, 0);
394 f = XFRAME (frame);
395 if (! FRAME_W32_P (f))
396 error ("non-w32 frame used");
397 return FRAME_W32_DISPLAY_INFO (f);
401 /* Return the Emacs frame-object corresponding to an w32 window.
402 It could be the frame's main window or an icon window. */
404 /* This function can be called during GC, so use GC_xxx type test macros. */
406 struct frame *
407 x_window_to_frame (dpyinfo, wdesc)
408 struct w32_display_info *dpyinfo;
409 HWND wdesc;
411 Lisp_Object tail, frame;
412 struct frame *f;
414 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
416 frame = XCAR (tail);
417 if (!GC_FRAMEP (frame))
418 continue;
419 f = XFRAME (frame);
420 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
421 continue;
422 if (f->output_data.w32->busy_window == wdesc)
423 return f;
425 /* NTEMACS_TODO: Check tooltips when supported. */
426 if (FRAME_W32_WINDOW (f) == wdesc)
427 return f;
429 return 0;
434 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
435 id, which is just an int that this section returns. Bitmaps are
436 reference counted so they can be shared among frames.
438 Bitmap indices are guaranteed to be > 0, so a negative number can
439 be used to indicate no bitmap.
441 If you use x_create_bitmap_from_data, then you must keep track of
442 the bitmaps yourself. That is, creating a bitmap from the same
443 data more than once will not be caught. */
446 /* Functions to access the contents of a bitmap, given an id. */
449 x_bitmap_height (f, id)
450 FRAME_PTR f;
451 int id;
453 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
457 x_bitmap_width (f, id)
458 FRAME_PTR f;
459 int id;
461 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
465 x_bitmap_pixmap (f, id)
466 FRAME_PTR f;
467 int id;
469 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
473 /* Allocate a new bitmap record. Returns index of new record. */
475 static int
476 x_allocate_bitmap_record (f)
477 FRAME_PTR f;
479 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
480 int i;
482 if (dpyinfo->bitmaps == NULL)
484 dpyinfo->bitmaps_size = 10;
485 dpyinfo->bitmaps
486 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
487 dpyinfo->bitmaps_last = 1;
488 return 1;
491 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
492 return ++dpyinfo->bitmaps_last;
494 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
495 if (dpyinfo->bitmaps[i].refcount == 0)
496 return i + 1;
498 dpyinfo->bitmaps_size *= 2;
499 dpyinfo->bitmaps
500 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
501 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
502 return ++dpyinfo->bitmaps_last;
505 /* Add one reference to the reference count of the bitmap with id ID. */
507 void
508 x_reference_bitmap (f, id)
509 FRAME_PTR f;
510 int id;
512 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
515 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
518 x_create_bitmap_from_data (f, bits, width, height)
519 struct frame *f;
520 char *bits;
521 unsigned int width, height;
523 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
524 Pixmap bitmap;
525 int id;
527 bitmap = CreateBitmap (width, height,
528 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
529 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
530 bits);
532 if (! bitmap)
533 return -1;
535 id = x_allocate_bitmap_record (f);
536 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
537 dpyinfo->bitmaps[id - 1].file = NULL;
538 dpyinfo->bitmaps[id - 1].hinst = NULL;
539 dpyinfo->bitmaps[id - 1].refcount = 1;
540 dpyinfo->bitmaps[id - 1].depth = 1;
541 dpyinfo->bitmaps[id - 1].height = height;
542 dpyinfo->bitmaps[id - 1].width = width;
544 return id;
547 /* Create bitmap from file FILE for frame F. */
550 x_create_bitmap_from_file (f, file)
551 struct frame *f;
552 Lisp_Object file;
554 return -1;
555 #if 0 /* NTEMACS_TODO : bitmap support */
556 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
557 unsigned int width, height;
558 HBITMAP bitmap;
559 int xhot, yhot, result, id;
560 Lisp_Object found;
561 int fd;
562 char *filename;
563 HINSTANCE hinst;
565 /* Look for an existing bitmap with the same name. */
566 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
568 if (dpyinfo->bitmaps[id].refcount
569 && dpyinfo->bitmaps[id].file
570 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
572 ++dpyinfo->bitmaps[id].refcount;
573 return id + 1;
577 /* Search bitmap-file-path for the file, if appropriate. */
578 fd = openp (Vx_bitmap_file_path, file, "", &found, 0);
579 if (fd < 0)
580 return -1;
581 /* LoadLibraryEx won't handle special files handled by Emacs handler. */
582 if (fd == 0)
583 return -1;
584 emacs_close (fd);
586 filename = (char *) XSTRING (found)->data;
588 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
590 if (hinst == NULL)
591 return -1;
594 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
595 filename, &width, &height, &bitmap, &xhot, &yhot);
596 if (result != BitmapSuccess)
597 return -1;
599 id = x_allocate_bitmap_record (f);
600 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
601 dpyinfo->bitmaps[id - 1].refcount = 1;
602 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
603 dpyinfo->bitmaps[id - 1].depth = 1;
604 dpyinfo->bitmaps[id - 1].height = height;
605 dpyinfo->bitmaps[id - 1].width = width;
606 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
608 return id;
609 #endif /* NTEMACS_TODO */
612 /* Remove reference to bitmap with id number ID. */
614 void
615 x_destroy_bitmap (f, id)
616 FRAME_PTR f;
617 int id;
619 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
621 if (id > 0)
623 --dpyinfo->bitmaps[id - 1].refcount;
624 if (dpyinfo->bitmaps[id - 1].refcount == 0)
626 BLOCK_INPUT;
627 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
628 if (dpyinfo->bitmaps[id - 1].file)
630 xfree (dpyinfo->bitmaps[id - 1].file);
631 dpyinfo->bitmaps[id - 1].file = NULL;
633 UNBLOCK_INPUT;
638 /* Free all the bitmaps for the display specified by DPYINFO. */
640 static void
641 x_destroy_all_bitmaps (dpyinfo)
642 struct w32_display_info *dpyinfo;
644 int i;
645 for (i = 0; i < dpyinfo->bitmaps_last; i++)
646 if (dpyinfo->bitmaps[i].refcount > 0)
648 DeleteObject (dpyinfo->bitmaps[i].pixmap);
649 if (dpyinfo->bitmaps[i].file)
650 xfree (dpyinfo->bitmaps[i].file);
652 dpyinfo->bitmaps_last = 0;
655 /* Connect the frame-parameter names for W32 frames
656 to the ways of passing the parameter values to the window system.
658 The name of a parameter, as a Lisp symbol,
659 has an `x-frame-parameter' property which is an integer in Lisp
660 but can be interpreted as an `enum x_frame_parm' in C. */
662 enum x_frame_parm
664 X_PARM_FOREGROUND_COLOR,
665 X_PARM_BACKGROUND_COLOR,
666 X_PARM_MOUSE_COLOR,
667 X_PARM_CURSOR_COLOR,
668 X_PARM_BORDER_COLOR,
669 X_PARM_ICON_TYPE,
670 X_PARM_FONT,
671 X_PARM_BORDER_WIDTH,
672 X_PARM_INTERNAL_BORDER_WIDTH,
673 X_PARM_NAME,
674 X_PARM_AUTORAISE,
675 X_PARM_AUTOLOWER,
676 X_PARM_VERT_SCROLL_BAR,
677 X_PARM_VISIBILITY,
678 X_PARM_MENU_BAR_LINES
682 struct x_frame_parm_table
684 char *name;
685 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
688 /* NTEMACS_TODO: Native Input Method support; see x_create_im. */
689 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
690 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
691 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
692 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
693 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
695 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
701 Lisp_Object));
702 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
703 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
704 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
705 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
706 Lisp_Object));
707 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
708 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
709 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
710 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
711 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
712 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
713 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
715 static struct x_frame_parm_table x_frame_parms[] =
717 "auto-raise", x_set_autoraise,
718 "auto-lower", x_set_autolower,
719 "background-color", x_set_background_color,
720 "border-color", x_set_border_color,
721 "border-width", x_set_border_width,
722 "cursor-color", x_set_cursor_color,
723 "cursor-type", x_set_cursor_type,
724 "font", x_set_font,
725 "foreground-color", x_set_foreground_color,
726 "icon-name", x_set_icon_name,
727 "icon-type", x_set_icon_type,
728 "internal-border-width", x_set_internal_border_width,
729 "menu-bar-lines", x_set_menu_bar_lines,
730 "mouse-color", x_set_mouse_color,
731 "name", x_explicitly_set_name,
732 "scroll-bar-width", x_set_scroll_bar_width,
733 "title", x_set_title,
734 "unsplittable", x_set_unsplittable,
735 "vertical-scroll-bars", x_set_vertical_scroll_bars,
736 "visibility", x_set_visibility,
737 "tool-bar-lines", x_set_tool_bar_lines,
738 "screen-gamma", x_set_screen_gamma,
739 "line-spacing", x_set_line_spacing
742 /* Attach the `x-frame-parameter' properties to
743 the Lisp symbol names of parameters relevant to W32. */
745 void
746 init_x_parm_symbols ()
748 int i;
750 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
751 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
752 make_number (i));
755 /* Change the parameters of frame F as specified by ALIST.
756 If a parameter is not specially recognized, do nothing;
757 otherwise call the `x_set_...' function for that parameter. */
759 void
760 x_set_frame_parameters (f, alist)
761 FRAME_PTR f;
762 Lisp_Object alist;
764 Lisp_Object tail;
766 /* If both of these parameters are present, it's more efficient to
767 set them both at once. So we wait until we've looked at the
768 entire list before we set them. */
769 int width, height;
771 /* Same here. */
772 Lisp_Object left, top;
774 /* Same with these. */
775 Lisp_Object icon_left, icon_top;
777 /* Record in these vectors all the parms specified. */
778 Lisp_Object *parms;
779 Lisp_Object *values;
780 int i, p;
781 int left_no_change = 0, top_no_change = 0;
782 int icon_left_no_change = 0, icon_top_no_change = 0;
784 struct gcpro gcpro1, gcpro2;
786 i = 0;
787 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
788 i++;
790 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
791 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
793 /* Extract parm names and values into those vectors. */
795 i = 0;
796 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
798 Lisp_Object elt;
800 elt = Fcar (tail);
801 parms[i] = Fcar (elt);
802 values[i] = Fcdr (elt);
803 i++;
805 /* TAIL and ALIST are not used again below here. */
806 alist = tail = Qnil;
808 GCPRO2 (*parms, *values);
809 gcpro1.nvars = i;
810 gcpro2.nvars = i;
812 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
813 because their values appear in VALUES and strings are not valid. */
814 top = left = Qunbound;
815 icon_left = icon_top = Qunbound;
817 /* Provide default values for HEIGHT and WIDTH. */
818 if (FRAME_NEW_WIDTH (f))
819 width = FRAME_NEW_WIDTH (f);
820 else
821 width = FRAME_WIDTH (f);
823 if (FRAME_NEW_HEIGHT (f))
824 height = FRAME_NEW_HEIGHT (f);
825 else
826 height = FRAME_HEIGHT (f);
828 /* Process foreground_color and background_color before anything else.
829 They are independent of other properties, but other properties (e.g.,
830 cursor_color) are dependent upon them. */
831 for (p = 0; p < i; p++)
833 Lisp_Object prop, val;
835 prop = parms[p];
836 val = values[p];
837 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
839 register Lisp_Object param_index, old_value;
841 param_index = Fget (prop, Qx_frame_parameter);
842 old_value = get_frame_param (f, prop);
843 store_frame_param (f, prop, val);
844 if (NATNUMP (param_index)
845 && (XFASTINT (param_index)
846 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
847 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
851 /* Now process them in reverse of specified order. */
852 for (i--; i >= 0; i--)
854 Lisp_Object prop, val;
856 prop = parms[i];
857 val = values[i];
859 if (EQ (prop, Qwidth) && NUMBERP (val))
860 width = XFASTINT (val);
861 else if (EQ (prop, Qheight) && NUMBERP (val))
862 height = XFASTINT (val);
863 else if (EQ (prop, Qtop))
864 top = val;
865 else if (EQ (prop, Qleft))
866 left = val;
867 else if (EQ (prop, Qicon_top))
868 icon_top = val;
869 else if (EQ (prop, Qicon_left))
870 icon_left = val;
871 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
872 /* Processed above. */
873 continue;
874 else
876 register Lisp_Object param_index, old_value;
878 param_index = Fget (prop, Qx_frame_parameter);
879 old_value = get_frame_param (f, prop);
880 store_frame_param (f, prop, val);
881 if (NATNUMP (param_index)
882 && (XFASTINT (param_index)
883 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
884 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
888 /* Don't die if just one of these was set. */
889 if (EQ (left, Qunbound))
891 left_no_change = 1;
892 if (f->output_data.w32->left_pos < 0)
893 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
894 else
895 XSETINT (left, f->output_data.w32->left_pos);
897 if (EQ (top, Qunbound))
899 top_no_change = 1;
900 if (f->output_data.w32->top_pos < 0)
901 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
902 else
903 XSETINT (top, f->output_data.w32->top_pos);
906 /* If one of the icon positions was not set, preserve or default it. */
907 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
909 icon_left_no_change = 1;
910 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
911 if (NILP (icon_left))
912 XSETINT (icon_left, 0);
914 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
916 icon_top_no_change = 1;
917 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
918 if (NILP (icon_top))
919 XSETINT (icon_top, 0);
922 /* Don't set these parameters unless they've been explicitly
923 specified. The window might be mapped or resized while we're in
924 this function, and we don't want to override that unless the lisp
925 code has asked for it.
927 Don't set these parameters unless they actually differ from the
928 window's current parameters; the window may not actually exist
929 yet. */
931 Lisp_Object frame;
933 check_frame_size (f, &height, &width);
935 XSETFRAME (frame, f);
937 if (width != FRAME_WIDTH (f)
938 || height != FRAME_HEIGHT (f)
939 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
940 Fset_frame_size (frame, make_number (width), make_number (height));
942 if ((!NILP (left) || !NILP (top))
943 && ! (left_no_change && top_no_change)
944 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
945 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
947 int leftpos = 0;
948 int toppos = 0;
950 /* Record the signs. */
951 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
952 if (EQ (left, Qminus))
953 f->output_data.w32->size_hint_flags |= XNegative;
954 else if (INTEGERP (left))
956 leftpos = XINT (left);
957 if (leftpos < 0)
958 f->output_data.w32->size_hint_flags |= XNegative;
960 else if (CONSP (left) && EQ (XCAR (left), Qminus)
961 && CONSP (XCDR (left))
962 && INTEGERP (XCAR (XCDR (left))))
964 leftpos = - XINT (XCAR (XCDR (left)));
965 f->output_data.w32->size_hint_flags |= XNegative;
967 else if (CONSP (left) && EQ (XCAR (left), Qplus)
968 && CONSP (XCDR (left))
969 && INTEGERP (XCAR (XCDR (left))))
971 leftpos = XINT (XCAR (XCDR (left)));
974 if (EQ (top, Qminus))
975 f->output_data.w32->size_hint_flags |= YNegative;
976 else if (INTEGERP (top))
978 toppos = XINT (top);
979 if (toppos < 0)
980 f->output_data.w32->size_hint_flags |= YNegative;
982 else if (CONSP (top) && EQ (XCAR (top), Qminus)
983 && CONSP (XCDR (top))
984 && INTEGERP (XCAR (XCDR (top))))
986 toppos = - XINT (XCAR (XCDR (top)));
987 f->output_data.w32->size_hint_flags |= YNegative;
989 else if (CONSP (top) && EQ (XCAR (top), Qplus)
990 && CONSP (XCDR (top))
991 && INTEGERP (XCAR (XCDR (top))))
993 toppos = XINT (XCAR (XCDR (top)));
997 /* Store the numeric value of the position. */
998 f->output_data.w32->top_pos = toppos;
999 f->output_data.w32->left_pos = leftpos;
1001 f->output_data.w32->win_gravity = NorthWestGravity;
1003 /* Actually set that position, and convert to absolute. */
1004 x_set_offset (f, leftpos, toppos, -1);
1007 if ((!NILP (icon_left) || !NILP (icon_top))
1008 && ! (icon_left_no_change && icon_top_no_change))
1009 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1012 UNGCPRO;
1015 /* Store the screen positions of frame F into XPTR and YPTR.
1016 These are the positions of the containing window manager window,
1017 not Emacs's own window. */
1019 void
1020 x_real_positions (f, xptr, yptr)
1021 FRAME_PTR f;
1022 int *xptr, *yptr;
1024 POINT pt;
1027 RECT rect;
1029 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1030 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1032 pt.x = rect.left;
1033 pt.y = rect.top;
1036 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1038 *xptr = pt.x;
1039 *yptr = pt.y;
1042 /* Insert a description of internally-recorded parameters of frame X
1043 into the parameter alist *ALISTPTR that is to be given to the user.
1044 Only parameters that are specific to W32
1045 and whose values are not correctly recorded in the frame's
1046 param_alist need to be considered here. */
1048 void
1049 x_report_frame_params (f, alistptr)
1050 struct frame *f;
1051 Lisp_Object *alistptr;
1053 char buf[16];
1054 Lisp_Object tem;
1056 /* Represent negative positions (off the top or left screen edge)
1057 in a way that Fmodify_frame_parameters will understand correctly. */
1058 XSETINT (tem, f->output_data.w32->left_pos);
1059 if (f->output_data.w32->left_pos >= 0)
1060 store_in_alist (alistptr, Qleft, tem);
1061 else
1062 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1064 XSETINT (tem, f->output_data.w32->top_pos);
1065 if (f->output_data.w32->top_pos >= 0)
1066 store_in_alist (alistptr, Qtop, tem);
1067 else
1068 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1070 store_in_alist (alistptr, Qborder_width,
1071 make_number (f->output_data.w32->border_width));
1072 store_in_alist (alistptr, Qinternal_border_width,
1073 make_number (f->output_data.w32->internal_border_width));
1074 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1075 store_in_alist (alistptr, Qwindow_id,
1076 build_string (buf));
1077 store_in_alist (alistptr, Qicon_name, f->icon_name);
1078 FRAME_SAMPLE_VISIBILITY (f);
1079 store_in_alist (alistptr, Qvisibility,
1080 (FRAME_VISIBLE_P (f) ? Qt
1081 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1082 store_in_alist (alistptr, Qdisplay,
1083 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1087 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color, Sw32_define_rgb_color, 4, 4, 0,
1088 "Convert RGB numbers to a windows color reference and associate with NAME (a string).\n\
1089 This adds or updates a named color to w32-color-map, making it available for use.\n\
1090 The original entry's RGB ref is returned, or nil if the entry is new.")
1091 (red, green, blue, name)
1092 Lisp_Object red, green, blue, name;
1094 Lisp_Object rgb;
1095 Lisp_Object oldrgb = Qnil;
1096 Lisp_Object entry;
1098 CHECK_NUMBER (red, 0);
1099 CHECK_NUMBER (green, 0);
1100 CHECK_NUMBER (blue, 0);
1101 CHECK_STRING (name, 0);
1103 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1105 BLOCK_INPUT;
1107 /* replace existing entry in w32-color-map or add new entry. */
1108 entry = Fassoc (name, Vw32_color_map);
1109 if (NILP (entry))
1111 entry = Fcons (name, rgb);
1112 Vw32_color_map = Fcons (entry, Vw32_color_map);
1114 else
1116 oldrgb = Fcdr (entry);
1117 Fsetcdr (entry, rgb);
1120 UNBLOCK_INPUT;
1122 return (oldrgb);
1125 DEFUN ("w32-load-color-file", Fw32_load_color_file, Sw32_load_color_file, 1, 1, 0,
1126 "Create an alist of color entries from an external file (ie. rgb.txt).\n\
1127 Assign this value to w32-color-map to replace the existing color map.\n\
1129 The file should define one named RGB color per line like so:\
1130 R G B name\n\
1131 where R,G,B are numbers between 0 and 255 and name is an arbitrary string.")
1132 (filename)
1133 Lisp_Object filename;
1135 FILE *fp;
1136 Lisp_Object cmap = Qnil;
1137 Lisp_Object abspath;
1139 CHECK_STRING (filename, 0);
1140 abspath = Fexpand_file_name (filename, Qnil);
1142 fp = fopen (XSTRING (filename)->data, "rt");
1143 if (fp)
1145 char buf[512];
1146 int red, green, blue;
1147 int num;
1149 BLOCK_INPUT;
1151 while (fgets (buf, sizeof (buf), fp) != NULL) {
1152 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1154 char *name = buf + num;
1155 num = strlen (name) - 1;
1156 if (name[num] == '\n')
1157 name[num] = 0;
1158 cmap = Fcons (Fcons (build_string (name),
1159 make_number (RGB (red, green, blue))),
1160 cmap);
1163 fclose (fp);
1165 UNBLOCK_INPUT;
1168 return cmap;
1171 /* The default colors for the w32 color map */
1172 typedef struct colormap_t
1174 char *name;
1175 COLORREF colorref;
1176 } colormap_t;
1178 colormap_t w32_color_map[] =
1180 {"snow" , PALETTERGB (255,250,250)},
1181 {"ghost white" , PALETTERGB (248,248,255)},
1182 {"GhostWhite" , PALETTERGB (248,248,255)},
1183 {"white smoke" , PALETTERGB (245,245,245)},
1184 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1185 {"gainsboro" , PALETTERGB (220,220,220)},
1186 {"floral white" , PALETTERGB (255,250,240)},
1187 {"FloralWhite" , PALETTERGB (255,250,240)},
1188 {"old lace" , PALETTERGB (253,245,230)},
1189 {"OldLace" , PALETTERGB (253,245,230)},
1190 {"linen" , PALETTERGB (250,240,230)},
1191 {"antique white" , PALETTERGB (250,235,215)},
1192 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1193 {"papaya whip" , PALETTERGB (255,239,213)},
1194 {"PapayaWhip" , PALETTERGB (255,239,213)},
1195 {"blanched almond" , PALETTERGB (255,235,205)},
1196 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1197 {"bisque" , PALETTERGB (255,228,196)},
1198 {"peach puff" , PALETTERGB (255,218,185)},
1199 {"PeachPuff" , PALETTERGB (255,218,185)},
1200 {"navajo white" , PALETTERGB (255,222,173)},
1201 {"NavajoWhite" , PALETTERGB (255,222,173)},
1202 {"moccasin" , PALETTERGB (255,228,181)},
1203 {"cornsilk" , PALETTERGB (255,248,220)},
1204 {"ivory" , PALETTERGB (255,255,240)},
1205 {"lemon chiffon" , PALETTERGB (255,250,205)},
1206 {"LemonChiffon" , PALETTERGB (255,250,205)},
1207 {"seashell" , PALETTERGB (255,245,238)},
1208 {"honeydew" , PALETTERGB (240,255,240)},
1209 {"mint cream" , PALETTERGB (245,255,250)},
1210 {"MintCream" , PALETTERGB (245,255,250)},
1211 {"azure" , PALETTERGB (240,255,255)},
1212 {"alice blue" , PALETTERGB (240,248,255)},
1213 {"AliceBlue" , PALETTERGB (240,248,255)},
1214 {"lavender" , PALETTERGB (230,230,250)},
1215 {"lavender blush" , PALETTERGB (255,240,245)},
1216 {"LavenderBlush" , PALETTERGB (255,240,245)},
1217 {"misty rose" , PALETTERGB (255,228,225)},
1218 {"MistyRose" , PALETTERGB (255,228,225)},
1219 {"white" , PALETTERGB (255,255,255)},
1220 {"black" , PALETTERGB ( 0, 0, 0)},
1221 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1222 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1223 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1224 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1225 {"dim gray" , PALETTERGB (105,105,105)},
1226 {"DimGray" , PALETTERGB (105,105,105)},
1227 {"dim grey" , PALETTERGB (105,105,105)},
1228 {"DimGrey" , PALETTERGB (105,105,105)},
1229 {"slate gray" , PALETTERGB (112,128,144)},
1230 {"SlateGray" , PALETTERGB (112,128,144)},
1231 {"slate grey" , PALETTERGB (112,128,144)},
1232 {"SlateGrey" , PALETTERGB (112,128,144)},
1233 {"light slate gray" , PALETTERGB (119,136,153)},
1234 {"LightSlateGray" , PALETTERGB (119,136,153)},
1235 {"light slate grey" , PALETTERGB (119,136,153)},
1236 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1237 {"gray" , PALETTERGB (190,190,190)},
1238 {"grey" , PALETTERGB (190,190,190)},
1239 {"light grey" , PALETTERGB (211,211,211)},
1240 {"LightGrey" , PALETTERGB (211,211,211)},
1241 {"light gray" , PALETTERGB (211,211,211)},
1242 {"LightGray" , PALETTERGB (211,211,211)},
1243 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1244 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1245 {"navy" , PALETTERGB ( 0, 0,128)},
1246 {"navy blue" , PALETTERGB ( 0, 0,128)},
1247 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1248 {"cornflower blue" , PALETTERGB (100,149,237)},
1249 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1250 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1251 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1252 {"slate blue" , PALETTERGB (106, 90,205)},
1253 {"SlateBlue" , PALETTERGB (106, 90,205)},
1254 {"medium slate blue" , PALETTERGB (123,104,238)},
1255 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1256 {"light slate blue" , PALETTERGB (132,112,255)},
1257 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1258 {"medium blue" , PALETTERGB ( 0, 0,205)},
1259 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1260 {"royal blue" , PALETTERGB ( 65,105,225)},
1261 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1262 {"blue" , PALETTERGB ( 0, 0,255)},
1263 {"dodger blue" , PALETTERGB ( 30,144,255)},
1264 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1265 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1266 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1267 {"sky blue" , PALETTERGB (135,206,235)},
1268 {"SkyBlue" , PALETTERGB (135,206,235)},
1269 {"light sky blue" , PALETTERGB (135,206,250)},
1270 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1271 {"steel blue" , PALETTERGB ( 70,130,180)},
1272 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1273 {"light steel blue" , PALETTERGB (176,196,222)},
1274 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1275 {"light blue" , PALETTERGB (173,216,230)},
1276 {"LightBlue" , PALETTERGB (173,216,230)},
1277 {"powder blue" , PALETTERGB (176,224,230)},
1278 {"PowderBlue" , PALETTERGB (176,224,230)},
1279 {"pale turquoise" , PALETTERGB (175,238,238)},
1280 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1281 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1282 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1283 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1284 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1285 {"turquoise" , PALETTERGB ( 64,224,208)},
1286 {"cyan" , PALETTERGB ( 0,255,255)},
1287 {"light cyan" , PALETTERGB (224,255,255)},
1288 {"LightCyan" , PALETTERGB (224,255,255)},
1289 {"cadet blue" , PALETTERGB ( 95,158,160)},
1290 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1291 {"medium aquamarine" , PALETTERGB (102,205,170)},
1292 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1293 {"aquamarine" , PALETTERGB (127,255,212)},
1294 {"dark green" , PALETTERGB ( 0,100, 0)},
1295 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1296 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1297 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1298 {"dark sea green" , PALETTERGB (143,188,143)},
1299 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1300 {"sea green" , PALETTERGB ( 46,139, 87)},
1301 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1302 {"medium sea green" , PALETTERGB ( 60,179,113)},
1303 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1304 {"light sea green" , PALETTERGB ( 32,178,170)},
1305 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1306 {"pale green" , PALETTERGB (152,251,152)},
1307 {"PaleGreen" , PALETTERGB (152,251,152)},
1308 {"spring green" , PALETTERGB ( 0,255,127)},
1309 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1310 {"lawn green" , PALETTERGB (124,252, 0)},
1311 {"LawnGreen" , PALETTERGB (124,252, 0)},
1312 {"green" , PALETTERGB ( 0,255, 0)},
1313 {"chartreuse" , PALETTERGB (127,255, 0)},
1314 {"medium spring green" , PALETTERGB ( 0,250,154)},
1315 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1316 {"green yellow" , PALETTERGB (173,255, 47)},
1317 {"GreenYellow" , PALETTERGB (173,255, 47)},
1318 {"lime green" , PALETTERGB ( 50,205, 50)},
1319 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1320 {"yellow green" , PALETTERGB (154,205, 50)},
1321 {"YellowGreen" , PALETTERGB (154,205, 50)},
1322 {"forest green" , PALETTERGB ( 34,139, 34)},
1323 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1324 {"olive drab" , PALETTERGB (107,142, 35)},
1325 {"OliveDrab" , PALETTERGB (107,142, 35)},
1326 {"dark khaki" , PALETTERGB (189,183,107)},
1327 {"DarkKhaki" , PALETTERGB (189,183,107)},
1328 {"khaki" , PALETTERGB (240,230,140)},
1329 {"pale goldenrod" , PALETTERGB (238,232,170)},
1330 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1331 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1332 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1333 {"light yellow" , PALETTERGB (255,255,224)},
1334 {"LightYellow" , PALETTERGB (255,255,224)},
1335 {"yellow" , PALETTERGB (255,255, 0)},
1336 {"gold" , PALETTERGB (255,215, 0)},
1337 {"light goldenrod" , PALETTERGB (238,221,130)},
1338 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1339 {"goldenrod" , PALETTERGB (218,165, 32)},
1340 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1341 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1342 {"rosy brown" , PALETTERGB (188,143,143)},
1343 {"RosyBrown" , PALETTERGB (188,143,143)},
1344 {"indian red" , PALETTERGB (205, 92, 92)},
1345 {"IndianRed" , PALETTERGB (205, 92, 92)},
1346 {"saddle brown" , PALETTERGB (139, 69, 19)},
1347 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1348 {"sienna" , PALETTERGB (160, 82, 45)},
1349 {"peru" , PALETTERGB (205,133, 63)},
1350 {"burlywood" , PALETTERGB (222,184,135)},
1351 {"beige" , PALETTERGB (245,245,220)},
1352 {"wheat" , PALETTERGB (245,222,179)},
1353 {"sandy brown" , PALETTERGB (244,164, 96)},
1354 {"SandyBrown" , PALETTERGB (244,164, 96)},
1355 {"tan" , PALETTERGB (210,180,140)},
1356 {"chocolate" , PALETTERGB (210,105, 30)},
1357 {"firebrick" , PALETTERGB (178,34, 34)},
1358 {"brown" , PALETTERGB (165,42, 42)},
1359 {"dark salmon" , PALETTERGB (233,150,122)},
1360 {"DarkSalmon" , PALETTERGB (233,150,122)},
1361 {"salmon" , PALETTERGB (250,128,114)},
1362 {"light salmon" , PALETTERGB (255,160,122)},
1363 {"LightSalmon" , PALETTERGB (255,160,122)},
1364 {"orange" , PALETTERGB (255,165, 0)},
1365 {"dark orange" , PALETTERGB (255,140, 0)},
1366 {"DarkOrange" , PALETTERGB (255,140, 0)},
1367 {"coral" , PALETTERGB (255,127, 80)},
1368 {"light coral" , PALETTERGB (240,128,128)},
1369 {"LightCoral" , PALETTERGB (240,128,128)},
1370 {"tomato" , PALETTERGB (255, 99, 71)},
1371 {"orange red" , PALETTERGB (255, 69, 0)},
1372 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1373 {"red" , PALETTERGB (255, 0, 0)},
1374 {"hot pink" , PALETTERGB (255,105,180)},
1375 {"HotPink" , PALETTERGB (255,105,180)},
1376 {"deep pink" , PALETTERGB (255, 20,147)},
1377 {"DeepPink" , PALETTERGB (255, 20,147)},
1378 {"pink" , PALETTERGB (255,192,203)},
1379 {"light pink" , PALETTERGB (255,182,193)},
1380 {"LightPink" , PALETTERGB (255,182,193)},
1381 {"pale violet red" , PALETTERGB (219,112,147)},
1382 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1383 {"maroon" , PALETTERGB (176, 48, 96)},
1384 {"medium violet red" , PALETTERGB (199, 21,133)},
1385 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1386 {"violet red" , PALETTERGB (208, 32,144)},
1387 {"VioletRed" , PALETTERGB (208, 32,144)},
1388 {"magenta" , PALETTERGB (255, 0,255)},
1389 {"violet" , PALETTERGB (238,130,238)},
1390 {"plum" , PALETTERGB (221,160,221)},
1391 {"orchid" , PALETTERGB (218,112,214)},
1392 {"medium orchid" , PALETTERGB (186, 85,211)},
1393 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1394 {"dark orchid" , PALETTERGB (153, 50,204)},
1395 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1396 {"dark violet" , PALETTERGB (148, 0,211)},
1397 {"DarkViolet" , PALETTERGB (148, 0,211)},
1398 {"blue violet" , PALETTERGB (138, 43,226)},
1399 {"BlueViolet" , PALETTERGB (138, 43,226)},
1400 {"purple" , PALETTERGB (160, 32,240)},
1401 {"medium purple" , PALETTERGB (147,112,219)},
1402 {"MediumPurple" , PALETTERGB (147,112,219)},
1403 {"thistle" , PALETTERGB (216,191,216)},
1404 {"gray0" , PALETTERGB ( 0, 0, 0)},
1405 {"grey0" , PALETTERGB ( 0, 0, 0)},
1406 {"dark grey" , PALETTERGB (169,169,169)},
1407 {"DarkGrey" , PALETTERGB (169,169,169)},
1408 {"dark gray" , PALETTERGB (169,169,169)},
1409 {"DarkGray" , PALETTERGB (169,169,169)},
1410 {"dark blue" , PALETTERGB ( 0, 0,139)},
1411 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1412 {"dark cyan" , PALETTERGB ( 0,139,139)},
1413 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1414 {"dark magenta" , PALETTERGB (139, 0,139)},
1415 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1416 {"dark red" , PALETTERGB (139, 0, 0)},
1417 {"DarkRed" , PALETTERGB (139, 0, 0)},
1418 {"light green" , PALETTERGB (144,238,144)},
1419 {"LightGreen" , PALETTERGB (144,238,144)},
1422 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1423 0, 0, 0, "Return the default color map.")
1426 int i;
1427 colormap_t *pc = w32_color_map;
1428 Lisp_Object cmap;
1430 BLOCK_INPUT;
1432 cmap = Qnil;
1434 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1435 pc++, i++)
1436 cmap = Fcons (Fcons (build_string (pc->name),
1437 make_number (pc->colorref)),
1438 cmap);
1440 UNBLOCK_INPUT;
1442 return (cmap);
1445 Lisp_Object
1446 w32_to_x_color (rgb)
1447 Lisp_Object rgb;
1449 Lisp_Object color;
1451 CHECK_NUMBER (rgb, 0);
1453 BLOCK_INPUT;
1455 color = Frassq (rgb, Vw32_color_map);
1457 UNBLOCK_INPUT;
1459 if (!NILP (color))
1460 return (Fcar (color));
1461 else
1462 return Qnil;
1465 COLORREF
1466 w32_color_map_lookup (colorname)
1467 char *colorname;
1469 Lisp_Object tail, ret = Qnil;
1471 BLOCK_INPUT;
1473 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1475 register Lisp_Object elt, tem;
1477 elt = Fcar (tail);
1478 if (!CONSP (elt)) continue;
1480 tem = Fcar (elt);
1482 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1484 ret = XUINT (Fcdr (elt));
1485 break;
1488 QUIT;
1492 UNBLOCK_INPUT;
1494 return ret;
1497 COLORREF
1498 x_to_w32_color (colorname)
1499 char * colorname;
1501 register Lisp_Object tail, ret = Qnil;
1503 BLOCK_INPUT;
1505 if (colorname[0] == '#')
1507 /* Could be an old-style RGB Device specification. */
1508 char *color;
1509 int size;
1510 color = colorname + 1;
1512 size = strlen(color);
1513 if (size == 3 || size == 6 || size == 9 || size == 12)
1515 UINT colorval;
1516 int i, pos;
1517 pos = 0;
1518 size /= 3;
1519 colorval = 0;
1521 for (i = 0; i < 3; i++)
1523 char *end;
1524 char t;
1525 unsigned long value;
1527 /* The check for 'x' in the following conditional takes into
1528 account the fact that strtol allows a "0x" in front of
1529 our numbers, and we don't. */
1530 if (!isxdigit(color[0]) || color[1] == 'x')
1531 break;
1532 t = color[size];
1533 color[size] = '\0';
1534 value = strtoul(color, &end, 16);
1535 color[size] = t;
1536 if (errno == ERANGE || end - color != size)
1537 break;
1538 switch (size)
1540 case 1:
1541 value = value * 0x10;
1542 break;
1543 case 2:
1544 break;
1545 case 3:
1546 value /= 0x10;
1547 break;
1548 case 4:
1549 value /= 0x100;
1550 break;
1552 colorval |= (value << pos);
1553 pos += 0x8;
1554 if (i == 2)
1556 UNBLOCK_INPUT;
1557 return (colorval);
1559 color = end;
1563 else if (strnicmp(colorname, "rgb:", 4) == 0)
1565 char *color;
1566 UINT colorval;
1567 int i, pos;
1568 pos = 0;
1570 colorval = 0;
1571 color = colorname + 4;
1572 for (i = 0; i < 3; i++)
1574 char *end;
1575 unsigned long value;
1577 /* The check for 'x' in the following conditional takes into
1578 account the fact that strtol allows a "0x" in front of
1579 our numbers, and we don't. */
1580 if (!isxdigit(color[0]) || color[1] == 'x')
1581 break;
1582 value = strtoul(color, &end, 16);
1583 if (errno == ERANGE)
1584 break;
1585 switch (end - color)
1587 case 1:
1588 value = value * 0x10 + value;
1589 break;
1590 case 2:
1591 break;
1592 case 3:
1593 value /= 0x10;
1594 break;
1595 case 4:
1596 value /= 0x100;
1597 break;
1598 default:
1599 value = ULONG_MAX;
1601 if (value == ULONG_MAX)
1602 break;
1603 colorval |= (value << pos);
1604 pos += 0x8;
1605 if (i == 2)
1607 if (*end != '\0')
1608 break;
1609 UNBLOCK_INPUT;
1610 return (colorval);
1612 if (*end != '/')
1613 break;
1614 color = end + 1;
1617 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1619 /* This is an RGB Intensity specification. */
1620 char *color;
1621 UINT colorval;
1622 int i, pos;
1623 pos = 0;
1625 colorval = 0;
1626 color = colorname + 5;
1627 for (i = 0; i < 3; i++)
1629 char *end;
1630 double value;
1631 UINT val;
1633 value = strtod(color, &end);
1634 if (errno == ERANGE)
1635 break;
1636 if (value < 0.0 || value > 1.0)
1637 break;
1638 val = (UINT)(0x100 * value);
1639 /* We used 0x100 instead of 0xFF to give an continuous
1640 range between 0.0 and 1.0 inclusive. The next statement
1641 fixes the 1.0 case. */
1642 if (val == 0x100)
1643 val = 0xFF;
1644 colorval |= (val << pos);
1645 pos += 0x8;
1646 if (i == 2)
1648 if (*end != '\0')
1649 break;
1650 UNBLOCK_INPUT;
1651 return (colorval);
1653 if (*end != '/')
1654 break;
1655 color = end + 1;
1658 /* I am not going to attempt to handle any of the CIE color schemes
1659 or TekHVC, since I don't know the algorithms for conversion to
1660 RGB. */
1662 /* If we fail to lookup the color name in w32_color_map, then check the
1663 colorname to see if it can be crudely approximated: If the X color
1664 ends in a number (e.g., "darkseagreen2"), strip the number and
1665 return the result of looking up the base color name. */
1666 ret = w32_color_map_lookup (colorname);
1667 if (NILP (ret))
1669 int len = strlen (colorname);
1671 if (isdigit (colorname[len - 1]))
1673 char *ptr, *approx = alloca (len);
1675 strcpy (approx, colorname);
1676 ptr = &approx[len - 1];
1677 while (ptr > approx && isdigit (*ptr))
1678 *ptr-- = '\0';
1680 ret = w32_color_map_lookup (approx);
1684 UNBLOCK_INPUT;
1685 return ret;
1689 void
1690 w32_regenerate_palette (FRAME_PTR f)
1692 struct w32_palette_entry * list;
1693 LOGPALETTE * log_palette;
1694 HPALETTE new_palette;
1695 int i;
1697 /* don't bother trying to create palette if not supported */
1698 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1699 return;
1701 log_palette = (LOGPALETTE *)
1702 alloca (sizeof (LOGPALETTE) +
1703 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1704 log_palette->palVersion = 0x300;
1705 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1707 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1708 for (i = 0;
1709 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1710 i++, list = list->next)
1711 log_palette->palPalEntry[i] = list->entry;
1713 new_palette = CreatePalette (log_palette);
1715 enter_crit ();
1717 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1718 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1719 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1721 /* Realize display palette and garbage all frames. */
1722 release_frame_dc (f, get_frame_dc (f));
1724 leave_crit ();
1727 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1728 #define SET_W32_COLOR(pe, color) \
1729 do \
1731 pe.peRed = GetRValue (color); \
1732 pe.peGreen = GetGValue (color); \
1733 pe.peBlue = GetBValue (color); \
1734 pe.peFlags = 0; \
1735 } while (0)
1737 #if 0
1738 /* Keep these around in case we ever want to track color usage. */
1739 void
1740 w32_map_color (FRAME_PTR f, COLORREF color)
1742 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1744 if (NILP (Vw32_enable_palette))
1745 return;
1747 /* check if color is already mapped */
1748 while (list)
1750 if (W32_COLOR (list->entry) == color)
1752 ++list->refcount;
1753 return;
1755 list = list->next;
1758 /* not already mapped, so add to list and recreate Windows palette */
1759 list = (struct w32_palette_entry *)
1760 xmalloc (sizeof (struct w32_palette_entry));
1761 SET_W32_COLOR (list->entry, color);
1762 list->refcount = 1;
1763 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1764 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1765 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1767 /* set flag that palette must be regenerated */
1768 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1771 void
1772 w32_unmap_color (FRAME_PTR f, COLORREF color)
1774 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1775 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1777 if (NILP (Vw32_enable_palette))
1778 return;
1780 /* check if color is already mapped */
1781 while (list)
1783 if (W32_COLOR (list->entry) == color)
1785 if (--list->refcount == 0)
1787 *prev = list->next;
1788 xfree (list);
1789 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1790 break;
1792 else
1793 return;
1795 prev = &list->next;
1796 list = list->next;
1799 /* set flag that palette must be regenerated */
1800 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1802 #endif
1805 /* Gamma-correct COLOR on frame F. */
1807 void
1808 gamma_correct (f, color)
1809 struct frame *f;
1810 COLORREF *color;
1812 if (f->gamma)
1814 *color = PALETTERGB (
1815 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1816 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1817 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1822 /* Decide if color named COLOR is valid for the display associated with
1823 the selected frame; if so, return the rgb values in COLOR_DEF.
1824 If ALLOC is nonzero, allocate a new colormap cell. */
1827 w32_defined_color (f, color, color_def, alloc)
1828 FRAME_PTR f;
1829 char *color;
1830 XColor *color_def;
1831 int alloc;
1833 register Lisp_Object tem;
1834 COLORREF w32_color_ref;
1836 tem = x_to_w32_color (color);
1838 if (!NILP (tem))
1840 if (f)
1842 /* Apply gamma correction. */
1843 w32_color_ref = XUINT (tem);
1844 gamma_correct (f, &w32_color_ref);
1845 XSETINT (tem, w32_color_ref);
1848 /* Map this color to the palette if it is enabled. */
1849 if (!NILP (Vw32_enable_palette))
1851 struct w32_palette_entry * entry =
1852 one_w32_display_info.color_list;
1853 struct w32_palette_entry ** prev =
1854 &one_w32_display_info.color_list;
1856 /* check if color is already mapped */
1857 while (entry)
1859 if (W32_COLOR (entry->entry) == XUINT (tem))
1860 break;
1861 prev = &entry->next;
1862 entry = entry->next;
1865 if (entry == NULL && alloc)
1867 /* not already mapped, so add to list */
1868 entry = (struct w32_palette_entry *)
1869 xmalloc (sizeof (struct w32_palette_entry));
1870 SET_W32_COLOR (entry->entry, XUINT (tem));
1871 entry->next = NULL;
1872 *prev = entry;
1873 one_w32_display_info.num_colors++;
1875 /* set flag that palette must be regenerated */
1876 one_w32_display_info.regen_palette = TRUE;
1879 /* Ensure COLORREF value is snapped to nearest color in (default)
1880 palette by simulating the PALETTERGB macro. This works whether
1881 or not the display device has a palette. */
1882 w32_color_ref = XUINT (tem) | 0x2000000;
1884 color_def->pixel = w32_color_ref;
1885 color_def->red = GetRValue (w32_color_ref);
1886 color_def->green = GetGValue (w32_color_ref);
1887 color_def->blue = GetBValue (w32_color_ref);
1889 return 1;
1891 else
1893 return 0;
1897 /* Given a string ARG naming a color, compute a pixel value from it
1898 suitable for screen F.
1899 If F is not a color screen, return DEF (default) regardless of what
1900 ARG says. */
1903 x_decode_color (f, arg, def)
1904 FRAME_PTR f;
1905 Lisp_Object arg;
1906 int def;
1908 XColor cdef;
1910 CHECK_STRING (arg, 0);
1912 if (strcmp (XSTRING (arg)->data, "black") == 0)
1913 return BLACK_PIX_DEFAULT (f);
1914 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1915 return WHITE_PIX_DEFAULT (f);
1917 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1918 return def;
1920 /* w32_defined_color is responsible for coping with failures
1921 by looking for a near-miss. */
1922 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1923 return cdef.pixel;
1925 /* defined_color failed; return an ultimate default. */
1926 return def;
1929 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1930 the previous value of that parameter, NEW_VALUE is the new value. */
1932 static void
1933 x_set_line_spacing (f, new_value, old_value)
1934 struct frame *f;
1935 Lisp_Object new_value, old_value;
1937 if (NILP (new_value))
1938 f->extra_line_spacing = 0;
1939 else if (NATNUMP (new_value))
1940 f->extra_line_spacing = XFASTINT (new_value);
1941 else
1942 Fsignal (Qerror, Fcons (build_string ("Illegal line-spacing"),
1943 Fcons (new_value, Qnil)));
1944 if (FRAME_VISIBLE_P (f))
1945 redraw_frame (f);
1949 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1950 the previous value of that parameter, NEW_VALUE is the new value. */
1952 static void
1953 x_set_screen_gamma (f, new_value, old_value)
1954 struct frame *f;
1955 Lisp_Object new_value, old_value;
1957 if (NILP (new_value))
1958 f->gamma = 0;
1959 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1960 /* The value 0.4545 is the normal viewing gamma. */
1961 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1962 else
1963 Fsignal (Qerror, Fcons (build_string ("Illegal screen-gamma"),
1964 Fcons (new_value, Qnil)));
1966 clear_face_cache (0);
1970 /* Functions called only from `x_set_frame_param'
1971 to set individual parameters.
1973 If FRAME_W32_WINDOW (f) is 0,
1974 the frame is being created and its window does not exist yet.
1975 In that case, just record the parameter's new value
1976 in the standard place; do not attempt to change the window. */
1978 void
1979 x_set_foreground_color (f, arg, oldval)
1980 struct frame *f;
1981 Lisp_Object arg, oldval;
1983 FRAME_FOREGROUND_PIXEL (f)
1984 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1986 if (FRAME_W32_WINDOW (f) != 0)
1988 update_face_from_frame_parameter (f, Qforeground_color, arg);
1989 if (FRAME_VISIBLE_P (f))
1990 redraw_frame (f);
1994 void
1995 x_set_background_color (f, arg, oldval)
1996 struct frame *f;
1997 Lisp_Object arg, oldval;
1999 FRAME_BACKGROUND_PIXEL (f)
2000 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2002 if (FRAME_W32_WINDOW (f) != 0)
2004 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2005 FRAME_BACKGROUND_PIXEL (f));
2007 update_face_from_frame_parameter (f, Qbackground_color, arg);
2009 if (FRAME_VISIBLE_P (f))
2010 redraw_frame (f);
2014 void
2015 x_set_mouse_color (f, arg, oldval)
2016 struct frame *f;
2017 Lisp_Object arg, oldval;
2020 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2021 int count;
2022 int mask_color;
2024 if (!EQ (Qnil, arg))
2025 f->output_data.w32->mouse_pixel
2026 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2027 mask_color = FRAME_BACKGROUND_PIXEL (f);
2029 /* Don't let pointers be invisible. */
2030 if (mask_color == f->output_data.w32->mouse_pixel
2031 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2032 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2034 #if 0 /* NTEMACS_TODO : cursor changes */
2035 BLOCK_INPUT;
2037 /* It's not okay to crash if the user selects a screwy cursor. */
2038 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2040 if (!EQ (Qnil, Vx_pointer_shape))
2042 CHECK_NUMBER (Vx_pointer_shape, 0);
2043 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2045 else
2046 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2047 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2049 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2051 CHECK_NUMBER (Vx_nontext_pointer_shape, 0);
2052 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2053 XINT (Vx_nontext_pointer_shape));
2055 else
2056 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2057 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2059 if (!EQ (Qnil, Vx_busy_pointer_shape))
2061 CHECK_NUMBER (Vx_busy_pointer_shape, 0);
2062 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2063 XINT (Vx_busy_pointer_shape));
2065 else
2066 busy_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2067 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2070 if (!EQ (Qnil, Vx_mode_pointer_shape))
2072 CHECK_NUMBER (Vx_mode_pointer_shape, 0);
2073 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2074 XINT (Vx_mode_pointer_shape));
2076 else
2077 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2078 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2080 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2082 CHECK_NUMBER (Vx_sensitive_text_pointer_shape, 0);
2083 cross_cursor
2084 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2085 XINT (Vx_sensitive_text_pointer_shape));
2087 else
2088 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2090 /* Check and report errors with the above calls. */
2091 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2092 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2095 XColor fore_color, back_color;
2097 fore_color.pixel = f->output_data.w32->mouse_pixel;
2098 back_color.pixel = mask_color;
2099 XQueryColor (FRAME_W32_DISPLAY (f),
2100 DefaultColormap (FRAME_W32_DISPLAY (f),
2101 DefaultScreen (FRAME_W32_DISPLAY (f))),
2102 &fore_color);
2103 XQueryColor (FRAME_W32_DISPLAY (f),
2104 DefaultColormap (FRAME_W32_DISPLAY (f),
2105 DefaultScreen (FRAME_W32_DISPLAY (f))),
2106 &back_color);
2107 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2108 &fore_color, &back_color);
2109 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2110 &fore_color, &back_color);
2111 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2112 &fore_color, &back_color);
2113 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2114 &fore_color, &back_color);
2115 XRecolorCursor (FRAME_W32_DISPLAY (f), busy_cursor,
2116 &fore_color, &back_color);
2119 if (FRAME_W32_WINDOW (f) != 0)
2120 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2122 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2123 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2124 f->output_data.w32->text_cursor = cursor;
2126 if (nontext_cursor != f->output_data.w32->nontext_cursor
2127 && f->output_data.w32->nontext_cursor != 0)
2128 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2129 f->output_data.w32->nontext_cursor = nontext_cursor;
2131 if (busy_cursor != f->output_data.w32->busy_cursor
2132 && f->output_data.w32->busy_cursor != 0)
2133 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->busy_cursor);
2134 f->output_data.w32->busy_cursor = busy_cursor;
2136 if (mode_cursor != f->output_data.w32->modeline_cursor
2137 && f->output_data.w32->modeline_cursor != 0)
2138 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2139 f->output_data.w32->modeline_cursor = mode_cursor;
2141 if (cross_cursor != f->output_data.w32->cross_cursor
2142 && f->output_data.w32->cross_cursor != 0)
2143 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2144 f->output_data.w32->cross_cursor = cross_cursor;
2146 XFlush (FRAME_W32_DISPLAY (f));
2147 UNBLOCK_INPUT;
2149 update_face_from_frame_parameter (f, Qmouse_color, arg);
2150 #endif /* NTEMACS_TODO */
2153 void
2154 x_set_cursor_color (f, arg, oldval)
2155 struct frame *f;
2156 Lisp_Object arg, oldval;
2158 unsigned long fore_pixel;
2160 if (!NILP (Vx_cursor_fore_pixel))
2161 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2162 WHITE_PIX_DEFAULT (f));
2163 else
2164 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2165 f->output_data.w32->cursor_pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2167 /* Make sure that the cursor color differs from the background color. */
2168 if (f->output_data.w32->cursor_pixel == FRAME_BACKGROUND_PIXEL (f))
2170 f->output_data.w32->cursor_pixel = f->output_data.w32->mouse_pixel;
2171 if (f->output_data.w32->cursor_pixel == fore_pixel)
2172 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2174 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2176 if (FRAME_W32_WINDOW (f) != 0)
2178 if (FRAME_VISIBLE_P (f))
2180 x_display_cursor (f, 0);
2181 x_display_cursor (f, 1);
2185 update_face_from_frame_parameter (f, Qcursor_color, arg);
2188 /* Set the border-color of frame F to pixel value PIX.
2189 Note that this does not fully take effect if done before
2190 F has an window. */
2191 void
2192 x_set_border_pixel (f, pix)
2193 struct frame *f;
2194 int pix;
2196 f->output_data.w32->border_pixel = pix;
2198 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2200 if (FRAME_VISIBLE_P (f))
2201 redraw_frame (f);
2205 /* Set the border-color of frame F to value described by ARG.
2206 ARG can be a string naming a color.
2207 The border-color is used for the border that is drawn by the server.
2208 Note that this does not fully take effect if done before
2209 F has a window; it must be redone when the window is created. */
2211 void
2212 x_set_border_color (f, arg, oldval)
2213 struct frame *f;
2214 Lisp_Object arg, oldval;
2216 int pix;
2218 CHECK_STRING (arg, 0);
2219 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2220 x_set_border_pixel (f, pix);
2221 update_face_from_frame_parameter (f, Qborder_color, arg);
2224 /* Value is the internal representation of the specified cursor type
2225 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2226 of the bar cursor. */
2228 enum text_cursor_kinds
2229 x_specified_cursor_type (arg, width)
2230 Lisp_Object arg;
2231 int *width;
2233 enum text_cursor_kinds type;
2235 if (EQ (arg, Qbar))
2237 type = BAR_CURSOR;
2238 *width = 2;
2240 else if (CONSP (arg)
2241 && EQ (XCAR (arg), Qbar)
2242 && INTEGERP (XCDR (arg))
2243 && XINT (XCDR (arg)) >= 0)
2245 type = BAR_CURSOR;
2246 *width = XINT (XCDR (arg));
2248 else if (NILP (arg))
2249 type = NO_CURSOR;
2250 else
2251 /* Treat anything unknown as "box cursor".
2252 It was bad to signal an error; people have trouble fixing
2253 .Xdefaults with Emacs, when it has something bad in it. */
2254 type = FILLED_BOX_CURSOR;
2256 return type;
2259 void
2260 x_set_cursor_type (f, arg, oldval)
2261 FRAME_PTR f;
2262 Lisp_Object arg, oldval;
2264 int width;
2266 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2267 f->output_data.w32->cursor_width = width;
2269 /* Make sure the cursor gets redrawn. This is overkill, but how
2270 often do people change cursor types? */
2271 update_mode_lines++;
2274 void
2275 x_set_icon_type (f, arg, oldval)
2276 struct frame *f;
2277 Lisp_Object arg, oldval;
2279 int result;
2281 if (NILP (arg) && NILP (oldval))
2282 return;
2284 if (STRINGP (arg) && STRINGP (oldval)
2285 && EQ (Fstring_equal (oldval, arg), Qt))
2286 return;
2288 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2289 return;
2291 BLOCK_INPUT;
2293 result = x_bitmap_icon (f, arg);
2294 if (result)
2296 UNBLOCK_INPUT;
2297 error ("No icon window available");
2300 UNBLOCK_INPUT;
2303 /* Return non-nil if frame F wants a bitmap icon. */
2305 Lisp_Object
2306 x_icon_type (f)
2307 FRAME_PTR f;
2309 Lisp_Object tem;
2311 tem = assq_no_quit (Qicon_type, f->param_alist);
2312 if (CONSP (tem))
2313 return XCDR (tem);
2314 else
2315 return Qnil;
2318 void
2319 x_set_icon_name (f, arg, oldval)
2320 struct frame *f;
2321 Lisp_Object arg, oldval;
2323 int result;
2325 if (STRINGP (arg))
2327 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2328 return;
2330 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2331 return;
2333 f->icon_name = arg;
2335 #if 0
2336 if (f->output_data.w32->icon_bitmap != 0)
2337 return;
2339 BLOCK_INPUT;
2341 result = x_text_icon (f,
2342 (char *) XSTRING ((!NILP (f->icon_name)
2343 ? f->icon_name
2344 : !NILP (f->title)
2345 ? f->title
2346 : f->name))->data);
2348 if (result)
2350 UNBLOCK_INPUT;
2351 error ("No icon window available");
2354 /* If the window was unmapped (and its icon was mapped),
2355 the new icon is not mapped, so map the window in its stead. */
2356 if (FRAME_VISIBLE_P (f))
2358 #ifdef USE_X_TOOLKIT
2359 XtPopup (f->output_data.w32->widget, XtGrabNone);
2360 #endif
2361 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2364 XFlush (FRAME_W32_DISPLAY (f));
2365 UNBLOCK_INPUT;
2366 #endif
2369 extern Lisp_Object x_new_font ();
2370 extern Lisp_Object x_new_fontset();
2372 void
2373 x_set_font (f, arg, oldval)
2374 struct frame *f;
2375 Lisp_Object arg, oldval;
2377 Lisp_Object result;
2378 Lisp_Object fontset_name;
2379 Lisp_Object frame;
2381 CHECK_STRING (arg, 1);
2383 fontset_name = Fquery_fontset (arg, Qnil);
2385 BLOCK_INPUT;
2386 result = (STRINGP (fontset_name)
2387 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2388 : x_new_font (f, XSTRING (arg)->data));
2389 UNBLOCK_INPUT;
2391 if (EQ (result, Qnil))
2392 error ("Font `%s' is not defined", XSTRING (arg)->data);
2393 else if (EQ (result, Qt))
2394 error ("The characters of the given font have varying widths");
2395 else if (STRINGP (result))
2397 store_frame_param (f, Qfont, result);
2398 recompute_basic_faces (f);
2400 else
2401 abort ();
2403 do_pending_window_change (0);
2405 /* Don't call `face-set-after-frame-default' when faces haven't been
2406 initialized yet. This is the case when called from
2407 Fx_create_frame. In that case, the X widget or window doesn't
2408 exist either, and we can end up in x_report_frame_params with a
2409 null widget which gives a segfault. */
2410 if (FRAME_FACE_CACHE (f))
2412 XSETFRAME (frame, f);
2413 call1 (Qface_set_after_frame_default, frame);
2417 void
2418 x_set_border_width (f, arg, oldval)
2419 struct frame *f;
2420 Lisp_Object arg, oldval;
2422 CHECK_NUMBER (arg, 0);
2424 if (XINT (arg) == f->output_data.w32->border_width)
2425 return;
2427 if (FRAME_W32_WINDOW (f) != 0)
2428 error ("Cannot change the border width of a window");
2430 f->output_data.w32->border_width = XINT (arg);
2433 void
2434 x_set_internal_border_width (f, arg, oldval)
2435 struct frame *f;
2436 Lisp_Object arg, oldval;
2438 int old = f->output_data.w32->internal_border_width;
2440 CHECK_NUMBER (arg, 0);
2441 f->output_data.w32->internal_border_width = XINT (arg);
2442 if (f->output_data.w32->internal_border_width < 0)
2443 f->output_data.w32->internal_border_width = 0;
2445 if (f->output_data.w32->internal_border_width == old)
2446 return;
2448 if (FRAME_W32_WINDOW (f) != 0)
2450 x_set_window_size (f, 0, f->width, f->height);
2451 SET_FRAME_GARBAGED (f);
2452 do_pending_window_change (0);
2456 void
2457 x_set_visibility (f, value, oldval)
2458 struct frame *f;
2459 Lisp_Object value, oldval;
2461 Lisp_Object frame;
2462 XSETFRAME (frame, f);
2464 if (NILP (value))
2465 Fmake_frame_invisible (frame, Qt);
2466 else if (EQ (value, Qicon))
2467 Ficonify_frame (frame);
2468 else
2469 Fmake_frame_visible (frame);
2472 void
2473 x_set_menu_bar_lines (f, value, oldval)
2474 struct frame *f;
2475 Lisp_Object value, oldval;
2477 int nlines;
2478 int olines = FRAME_MENU_BAR_LINES (f);
2480 /* Right now, menu bars don't work properly in minibuf-only frames;
2481 most of the commands try to apply themselves to the minibuffer
2482 frame itself, and get an error because you can't switch buffers
2483 in or split the minibuffer window. */
2484 if (FRAME_MINIBUF_ONLY_P (f))
2485 return;
2487 if (INTEGERP (value))
2488 nlines = XINT (value);
2489 else
2490 nlines = 0;
2492 FRAME_MENU_BAR_LINES (f) = 0;
2493 if (nlines)
2494 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2495 else
2497 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2498 free_frame_menubar (f);
2499 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2501 /* Adjust the frame size so that the client (text) dimensions
2502 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2503 set correctly. */
2504 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2505 do_pending_window_change (0);
2507 adjust_glyphs (f);
2511 /* Set the number of lines used for the tool bar of frame F to VALUE.
2512 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2513 is the old number of tool bar lines. This function changes the
2514 height of all windows on frame F to match the new tool bar height.
2515 The frame's height doesn't change. */
2517 void
2518 x_set_tool_bar_lines (f, value, oldval)
2519 struct frame *f;
2520 Lisp_Object value, oldval;
2522 int delta, nlines;
2524 /* Use VALUE only if an integer >= 0. */
2525 if (INTEGERP (value) && XINT (value) >= 0)
2526 nlines = XFASTINT (value);
2527 else
2528 nlines = 0;
2530 /* Make sure we redisplay all windows in this frame. */
2531 ++windows_or_buffers_changed;
2533 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2534 FRAME_TOOL_BAR_LINES (f) = nlines;
2535 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2536 do_pending_window_change (0);
2537 adjust_glyphs (f);
2541 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2542 w32_id_name.
2544 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2545 name; if NAME is a string, set F's name to NAME and set
2546 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2548 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2549 suggesting a new name, which lisp code should override; if
2550 F->explicit_name is set, ignore the new name; otherwise, set it. */
2552 void
2553 x_set_name (f, name, explicit)
2554 struct frame *f;
2555 Lisp_Object name;
2556 int explicit;
2558 /* Make sure that requests from lisp code override requests from
2559 Emacs redisplay code. */
2560 if (explicit)
2562 /* If we're switching from explicit to implicit, we had better
2563 update the mode lines and thereby update the title. */
2564 if (f->explicit_name && NILP (name))
2565 update_mode_lines = 1;
2567 f->explicit_name = ! NILP (name);
2569 else if (f->explicit_name)
2570 return;
2572 /* If NAME is nil, set the name to the w32_id_name. */
2573 if (NILP (name))
2575 /* Check for no change needed in this very common case
2576 before we do any consing. */
2577 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2578 XSTRING (f->name)->data))
2579 return;
2580 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2582 else
2583 CHECK_STRING (name, 0);
2585 /* Don't change the name if it's already NAME. */
2586 if (! NILP (Fstring_equal (name, f->name)))
2587 return;
2589 f->name = name;
2591 /* For setting the frame title, the title parameter should override
2592 the name parameter. */
2593 if (! NILP (f->title))
2594 name = f->title;
2596 if (FRAME_W32_WINDOW (f))
2598 if (STRING_MULTIBYTE (name))
2599 name = ENCODE_SYSTEM (name);
2601 BLOCK_INPUT;
2602 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2603 UNBLOCK_INPUT;
2607 /* This function should be called when the user's lisp code has
2608 specified a name for the frame; the name will override any set by the
2609 redisplay code. */
2610 void
2611 x_explicitly_set_name (f, arg, oldval)
2612 FRAME_PTR f;
2613 Lisp_Object arg, oldval;
2615 x_set_name (f, arg, 1);
2618 /* This function should be called by Emacs redisplay code to set the
2619 name; names set this way will never override names set by the user's
2620 lisp code. */
2621 void
2622 x_implicitly_set_name (f, arg, oldval)
2623 FRAME_PTR f;
2624 Lisp_Object arg, oldval;
2626 x_set_name (f, arg, 0);
2629 /* Change the title of frame F to NAME.
2630 If NAME is nil, use the frame name as the title.
2632 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2633 name; if NAME is a string, set F's name to NAME and set
2634 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2636 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2637 suggesting a new name, which lisp code should override; if
2638 F->explicit_name is set, ignore the new name; otherwise, set it. */
2640 void
2641 x_set_title (f, name, old_name)
2642 struct frame *f;
2643 Lisp_Object name, old_name;
2645 /* Don't change the title if it's already NAME. */
2646 if (EQ (name, f->title))
2647 return;
2649 update_mode_lines = 1;
2651 f->title = name;
2653 if (NILP (name))
2654 name = f->name;
2656 if (FRAME_W32_WINDOW (f))
2658 if (STRING_MULTIBYTE (name))
2659 name = ENCODE_SYSTEM (name);
2661 BLOCK_INPUT;
2662 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2663 UNBLOCK_INPUT;
2667 void
2668 x_set_autoraise (f, arg, oldval)
2669 struct frame *f;
2670 Lisp_Object arg, oldval;
2672 f->auto_raise = !EQ (Qnil, arg);
2675 void
2676 x_set_autolower (f, arg, oldval)
2677 struct frame *f;
2678 Lisp_Object arg, oldval;
2680 f->auto_lower = !EQ (Qnil, arg);
2683 void
2684 x_set_unsplittable (f, arg, oldval)
2685 struct frame *f;
2686 Lisp_Object arg, oldval;
2688 f->no_split = !NILP (arg);
2691 void
2692 x_set_vertical_scroll_bars (f, arg, oldval)
2693 struct frame *f;
2694 Lisp_Object arg, oldval;
2696 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2697 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2698 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2699 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2701 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2702 vertical_scroll_bar_none :
2703 /* Put scroll bars on the right by default, as is conventional
2704 on MS-Windows. */
2705 EQ (Qleft, arg)
2706 ? vertical_scroll_bar_left
2707 : vertical_scroll_bar_right;
2709 /* We set this parameter before creating the window for the
2710 frame, so we can get the geometry right from the start.
2711 However, if the window hasn't been created yet, we shouldn't
2712 call x_set_window_size. */
2713 if (FRAME_W32_WINDOW (f))
2714 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2715 do_pending_window_change (0);
2719 void
2720 x_set_scroll_bar_width (f, arg, oldval)
2721 struct frame *f;
2722 Lisp_Object arg, oldval;
2724 int wid = FONT_WIDTH (f->output_data.w32->font);
2726 if (NILP (arg))
2728 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2729 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2730 wid - 1) / wid;
2731 if (FRAME_W32_WINDOW (f))
2732 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2733 do_pending_window_change (0);
2735 else if (INTEGERP (arg) && XINT (arg) > 0
2736 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2738 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2739 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2740 + wid-1) / wid;
2741 if (FRAME_W32_WINDOW (f))
2742 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2743 do_pending_window_change (0);
2745 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2746 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2747 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2750 /* Subroutines of creating an frame. */
2752 /* Make sure that Vx_resource_name is set to a reasonable value.
2753 Fix it up, or set it to `emacs' if it is too hopeless. */
2755 static void
2756 validate_x_resource_name ()
2758 int len = 0;
2759 /* Number of valid characters in the resource name. */
2760 int good_count = 0;
2761 /* Number of invalid characters in the resource name. */
2762 int bad_count = 0;
2763 Lisp_Object new;
2764 int i;
2766 if (STRINGP (Vx_resource_name))
2768 unsigned char *p = XSTRING (Vx_resource_name)->data;
2769 int i;
2771 len = STRING_BYTES (XSTRING (Vx_resource_name));
2773 /* Only letters, digits, - and _ are valid in resource names.
2774 Count the valid characters and count the invalid ones. */
2775 for (i = 0; i < len; i++)
2777 int c = p[i];
2778 if (! ((c >= 'a' && c <= 'z')
2779 || (c >= 'A' && c <= 'Z')
2780 || (c >= '0' && c <= '9')
2781 || c == '-' || c == '_'))
2782 bad_count++;
2783 else
2784 good_count++;
2787 else
2788 /* Not a string => completely invalid. */
2789 bad_count = 5, good_count = 0;
2791 /* If name is valid already, return. */
2792 if (bad_count == 0)
2793 return;
2795 /* If name is entirely invalid, or nearly so, use `emacs'. */
2796 if (good_count == 0
2797 || (good_count == 1 && bad_count > 0))
2799 Vx_resource_name = build_string ("emacs");
2800 return;
2803 /* Name is partly valid. Copy it and replace the invalid characters
2804 with underscores. */
2806 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2808 for (i = 0; i < len; i++)
2810 int c = XSTRING (new)->data[i];
2811 if (! ((c >= 'a' && c <= 'z')
2812 || (c >= 'A' && c <= 'Z')
2813 || (c >= '0' && c <= '9')
2814 || c == '-' || c == '_'))
2815 XSTRING (new)->data[i] = '_';
2820 extern char *x_get_string_resource ();
2822 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2823 "Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.\n\
2824 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the\n\
2825 class, where INSTANCE is the name under which Emacs was invoked, or\n\
2826 the name specified by the `-name' or `-rn' command-line arguments.\n\
2828 The optional arguments COMPONENT and SUBCLASS add to the key and the\n\
2829 class, respectively. You must specify both of them or neither.\n\
2830 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'\n\
2831 and the class is `Emacs.CLASS.SUBCLASS'.")
2832 (attribute, class, component, subclass)
2833 Lisp_Object attribute, class, component, subclass;
2835 register char *value;
2836 char *name_key;
2837 char *class_key;
2839 CHECK_STRING (attribute, 0);
2840 CHECK_STRING (class, 0);
2842 if (!NILP (component))
2843 CHECK_STRING (component, 1);
2844 if (!NILP (subclass))
2845 CHECK_STRING (subclass, 2);
2846 if (NILP (component) != NILP (subclass))
2847 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2849 validate_x_resource_name ();
2851 /* Allocate space for the components, the dots which separate them,
2852 and the final '\0'. Make them big enough for the worst case. */
2853 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
2854 + (STRINGP (component)
2855 ? STRING_BYTES (XSTRING (component)) : 0)
2856 + STRING_BYTES (XSTRING (attribute))
2857 + 3);
2859 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2860 + STRING_BYTES (XSTRING (class))
2861 + (STRINGP (subclass)
2862 ? STRING_BYTES (XSTRING (subclass)) : 0)
2863 + 3);
2865 /* Start with emacs.FRAMENAME for the name (the specific one)
2866 and with `Emacs' for the class key (the general one). */
2867 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2868 strcpy (class_key, EMACS_CLASS);
2870 strcat (class_key, ".");
2871 strcat (class_key, XSTRING (class)->data);
2873 if (!NILP (component))
2875 strcat (class_key, ".");
2876 strcat (class_key, XSTRING (subclass)->data);
2878 strcat (name_key, ".");
2879 strcat (name_key, XSTRING (component)->data);
2882 strcat (name_key, ".");
2883 strcat (name_key, XSTRING (attribute)->data);
2885 value = x_get_string_resource (Qnil,
2886 name_key, class_key);
2888 if (value != (char *) 0)
2889 return build_string (value);
2890 else
2891 return Qnil;
2894 /* Used when C code wants a resource value. */
2896 char *
2897 x_get_resource_string (attribute, class)
2898 char *attribute, *class;
2900 char *name_key;
2901 char *class_key;
2902 struct frame *sf = SELECTED_FRAME ();
2904 /* Allocate space for the components, the dots which separate them,
2905 and the final '\0'. */
2906 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
2907 + strlen (attribute) + 2);
2908 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2909 + strlen (class) + 2);
2911 sprintf (name_key, "%s.%s",
2912 XSTRING (Vinvocation_name)->data,
2913 attribute);
2914 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
2916 return x_get_string_resource (sf, name_key, class_key);
2919 /* Types we might convert a resource string into. */
2920 enum resource_types
2922 RES_TYPE_NUMBER,
2923 RES_TYPE_FLOAT,
2924 RES_TYPE_BOOLEAN,
2925 RES_TYPE_STRING,
2926 RES_TYPE_SYMBOL
2929 /* Return the value of parameter PARAM.
2931 First search ALIST, then Vdefault_frame_alist, then the X defaults
2932 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2934 Convert the resource to the type specified by desired_type.
2936 If no default is specified, return Qunbound. If you call
2937 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
2938 and don't let it get stored in any Lisp-visible variables! */
2940 static Lisp_Object
2941 w32_get_arg (alist, param, attribute, class, type)
2942 Lisp_Object alist, param;
2943 char *attribute;
2944 char *class;
2945 enum resource_types type;
2947 register Lisp_Object tem;
2949 tem = Fassq (param, alist);
2950 if (EQ (tem, Qnil))
2951 tem = Fassq (param, Vdefault_frame_alist);
2952 if (EQ (tem, Qnil))
2955 if (attribute)
2957 tem = Fx_get_resource (build_string (attribute),
2958 build_string (class),
2959 Qnil, Qnil);
2961 if (NILP (tem))
2962 return Qunbound;
2964 switch (type)
2966 case RES_TYPE_NUMBER:
2967 return make_number (atoi (XSTRING (tem)->data));
2969 case RES_TYPE_FLOAT:
2970 return make_float (atof (XSTRING (tem)->data));
2972 case RES_TYPE_BOOLEAN:
2973 tem = Fdowncase (tem);
2974 if (!strcmp (XSTRING (tem)->data, "on")
2975 || !strcmp (XSTRING (tem)->data, "true"))
2976 return Qt;
2977 else
2978 return Qnil;
2980 case RES_TYPE_STRING:
2981 return tem;
2983 case RES_TYPE_SYMBOL:
2984 /* As a special case, we map the values `true' and `on'
2985 to Qt, and `false' and `off' to Qnil. */
2987 Lisp_Object lower;
2988 lower = Fdowncase (tem);
2989 if (!strcmp (XSTRING (lower)->data, "on")
2990 || !strcmp (XSTRING (lower)->data, "true"))
2991 return Qt;
2992 else if (!strcmp (XSTRING (lower)->data, "off")
2993 || !strcmp (XSTRING (lower)->data, "false"))
2994 return Qnil;
2995 else
2996 return Fintern (tem, Qnil);
2999 default:
3000 abort ();
3003 else
3004 return Qunbound;
3006 return Fcdr (tem);
3009 /* Record in frame F the specified or default value according to ALIST
3010 of the parameter named PROP (a Lisp symbol).
3011 If no value is specified for PROP, look for an X default for XPROP
3012 on the frame named NAME.
3013 If that is not found either, use the value DEFLT. */
3015 static Lisp_Object
3016 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3017 struct frame *f;
3018 Lisp_Object alist;
3019 Lisp_Object prop;
3020 Lisp_Object deflt;
3021 char *xprop;
3022 char *xclass;
3023 enum resource_types type;
3025 Lisp_Object tem;
3027 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3028 if (EQ (tem, Qunbound))
3029 tem = deflt;
3030 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3031 return tem;
3034 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3035 "Parse an X-style geometry string STRING.\n\
3036 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).\n\
3037 The properties returned may include `top', `left', `height', and `width'.\n\
3038 The value of `left' or `top' may be an integer,\n\
3039 or a list (+ N) meaning N pixels relative to top/left corner,\n\
3040 or a list (- N) meaning -N pixels relative to bottom/right corner.")
3041 (string)
3042 Lisp_Object string;
3044 int geometry, x, y;
3045 unsigned int width, height;
3046 Lisp_Object result;
3048 CHECK_STRING (string, 0);
3050 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3051 &x, &y, &width, &height);
3053 result = Qnil;
3054 if (geometry & XValue)
3056 Lisp_Object element;
3058 if (x >= 0 && (geometry & XNegative))
3059 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3060 else if (x < 0 && ! (geometry & XNegative))
3061 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3062 else
3063 element = Fcons (Qleft, make_number (x));
3064 result = Fcons (element, result);
3067 if (geometry & YValue)
3069 Lisp_Object element;
3071 if (y >= 0 && (geometry & YNegative))
3072 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3073 else if (y < 0 && ! (geometry & YNegative))
3074 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3075 else
3076 element = Fcons (Qtop, make_number (y));
3077 result = Fcons (element, result);
3080 if (geometry & WidthValue)
3081 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3082 if (geometry & HeightValue)
3083 result = Fcons (Fcons (Qheight, make_number (height)), result);
3085 return result;
3088 /* Calculate the desired size and position of this window,
3089 and return the flags saying which aspects were specified.
3091 This function does not make the coordinates positive. */
3093 #define DEFAULT_ROWS 40
3094 #define DEFAULT_COLS 80
3096 static int
3097 x_figure_window_size (f, parms)
3098 struct frame *f;
3099 Lisp_Object parms;
3101 register Lisp_Object tem0, tem1, tem2;
3102 long window_prompting = 0;
3104 /* Default values if we fall through.
3105 Actually, if that happens we should get
3106 window manager prompting. */
3107 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3108 f->height = DEFAULT_ROWS;
3109 /* Window managers expect that if program-specified
3110 positions are not (0,0), they're intentional, not defaults. */
3111 f->output_data.w32->top_pos = 0;
3112 f->output_data.w32->left_pos = 0;
3114 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3115 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3116 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3117 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3119 if (!EQ (tem0, Qunbound))
3121 CHECK_NUMBER (tem0, 0);
3122 f->height = XINT (tem0);
3124 if (!EQ (tem1, Qunbound))
3126 CHECK_NUMBER (tem1, 0);
3127 SET_FRAME_WIDTH (f, XINT (tem1));
3129 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3130 window_prompting |= USSize;
3131 else
3132 window_prompting |= PSize;
3135 f->output_data.w32->vertical_scroll_bar_extra
3136 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3138 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3139 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3140 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3141 f->output_data.w32->flags_areas_extra
3142 = FRAME_FLAGS_AREA_WIDTH (f);
3143 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3144 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3146 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3147 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3148 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3149 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3151 if (EQ (tem0, Qminus))
3153 f->output_data.w32->top_pos = 0;
3154 window_prompting |= YNegative;
3156 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3157 && CONSP (XCDR (tem0))
3158 && INTEGERP (XCAR (XCDR (tem0))))
3160 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3161 window_prompting |= YNegative;
3163 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3164 && CONSP (XCDR (tem0))
3165 && INTEGERP (XCAR (XCDR (tem0))))
3167 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3169 else if (EQ (tem0, Qunbound))
3170 f->output_data.w32->top_pos = 0;
3171 else
3173 CHECK_NUMBER (tem0, 0);
3174 f->output_data.w32->top_pos = XINT (tem0);
3175 if (f->output_data.w32->top_pos < 0)
3176 window_prompting |= YNegative;
3179 if (EQ (tem1, Qminus))
3181 f->output_data.w32->left_pos = 0;
3182 window_prompting |= XNegative;
3184 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3185 && CONSP (XCDR (tem1))
3186 && INTEGERP (XCAR (XCDR (tem1))))
3188 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3189 window_prompting |= XNegative;
3191 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3192 && CONSP (XCDR (tem1))
3193 && INTEGERP (XCAR (XCDR (tem1))))
3195 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3197 else if (EQ (tem1, Qunbound))
3198 f->output_data.w32->left_pos = 0;
3199 else
3201 CHECK_NUMBER (tem1, 0);
3202 f->output_data.w32->left_pos = XINT (tem1);
3203 if (f->output_data.w32->left_pos < 0)
3204 window_prompting |= XNegative;
3207 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3208 window_prompting |= USPosition;
3209 else
3210 window_prompting |= PPosition;
3213 return window_prompting;
3218 extern LRESULT CALLBACK w32_wnd_proc ();
3220 BOOL
3221 w32_init_class (hinst)
3222 HINSTANCE hinst;
3224 WNDCLASS wc;
3226 wc.style = CS_HREDRAW | CS_VREDRAW;
3227 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3228 wc.cbClsExtra = 0;
3229 wc.cbWndExtra = WND_EXTRA_BYTES;
3230 wc.hInstance = hinst;
3231 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3232 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3233 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3234 wc.lpszMenuName = NULL;
3235 wc.lpszClassName = EMACS_CLASS;
3237 return (RegisterClass (&wc));
3240 HWND
3241 w32_createscrollbar (f, bar)
3242 struct frame *f;
3243 struct scroll_bar * bar;
3245 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3246 /* Position and size of scroll bar. */
3247 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3248 XINT(bar->top),
3249 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3250 XINT(bar->height),
3251 FRAME_W32_WINDOW (f),
3252 NULL,
3253 hinst,
3254 NULL));
3257 void
3258 w32_createwindow (f)
3259 struct frame *f;
3261 HWND hwnd;
3262 RECT rect;
3264 rect.left = rect.top = 0;
3265 rect.right = PIXEL_WIDTH (f);
3266 rect.bottom = PIXEL_HEIGHT (f);
3268 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3269 FRAME_EXTERNAL_MENU_BAR (f));
3271 /* Do first time app init */
3273 if (!hprevinst)
3275 w32_init_class (hinst);
3278 FRAME_W32_WINDOW (f) = hwnd
3279 = CreateWindow (EMACS_CLASS,
3280 f->namebuf,
3281 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3282 f->output_data.w32->left_pos,
3283 f->output_data.w32->top_pos,
3284 rect.right - rect.left,
3285 rect.bottom - rect.top,
3286 NULL,
3287 NULL,
3288 hinst,
3289 NULL);
3291 if (hwnd)
3293 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3294 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3295 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3296 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3297 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3299 /* Enable drag-n-drop. */
3300 DragAcceptFiles (hwnd, TRUE);
3302 /* Do this to discard the default setting specified by our parent. */
3303 ShowWindow (hwnd, SW_HIDE);
3307 void
3308 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3309 W32Msg * wmsg;
3310 HWND hwnd;
3311 UINT msg;
3312 WPARAM wParam;
3313 LPARAM lParam;
3315 wmsg->msg.hwnd = hwnd;
3316 wmsg->msg.message = msg;
3317 wmsg->msg.wParam = wParam;
3318 wmsg->msg.lParam = lParam;
3319 wmsg->msg.time = GetMessageTime ();
3321 post_msg (wmsg);
3324 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3325 between left and right keys as advertised. We test for this
3326 support dynamically, and set a flag when the support is absent. If
3327 absent, we keep track of the left and right control and alt keys
3328 ourselves. This is particularly necessary on keyboards that rely
3329 upon the AltGr key, which is represented as having the left control
3330 and right alt keys pressed. For these keyboards, we need to know
3331 when the left alt key has been pressed in addition to the AltGr key
3332 so that we can properly support M-AltGr-key sequences (such as M-@
3333 on Swedish keyboards). */
3335 #define EMACS_LCONTROL 0
3336 #define EMACS_RCONTROL 1
3337 #define EMACS_LMENU 2
3338 #define EMACS_RMENU 3
3340 static int modifiers[4];
3341 static int modifiers_recorded;
3342 static int modifier_key_support_tested;
3344 static void
3345 test_modifier_support (unsigned int wparam)
3347 unsigned int l, r;
3349 if (wparam != VK_CONTROL && wparam != VK_MENU)
3350 return;
3351 if (wparam == VK_CONTROL)
3353 l = VK_LCONTROL;
3354 r = VK_RCONTROL;
3356 else
3358 l = VK_LMENU;
3359 r = VK_RMENU;
3361 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3362 modifiers_recorded = 1;
3363 else
3364 modifiers_recorded = 0;
3365 modifier_key_support_tested = 1;
3368 static void
3369 record_keydown (unsigned int wparam, unsigned int lparam)
3371 int i;
3373 if (!modifier_key_support_tested)
3374 test_modifier_support (wparam);
3376 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3377 return;
3379 if (wparam == VK_CONTROL)
3380 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3381 else
3382 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3384 modifiers[i] = 1;
3387 static void
3388 record_keyup (unsigned int wparam, unsigned int lparam)
3390 int i;
3392 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3393 return;
3395 if (wparam == VK_CONTROL)
3396 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3397 else
3398 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3400 modifiers[i] = 0;
3403 /* Emacs can lose focus while a modifier key has been pressed. When
3404 it regains focus, be conservative and clear all modifiers since
3405 we cannot reconstruct the left and right modifier state. */
3406 static void
3407 reset_modifiers ()
3409 SHORT ctrl, alt;
3411 if (GetFocus () == NULL)
3412 /* Emacs doesn't have keyboard focus. Do nothing. */
3413 return;
3415 ctrl = GetAsyncKeyState (VK_CONTROL);
3416 alt = GetAsyncKeyState (VK_MENU);
3418 if (!(ctrl & 0x08000))
3419 /* Clear any recorded control modifier state. */
3420 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3422 if (!(alt & 0x08000))
3423 /* Clear any recorded alt modifier state. */
3424 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3426 /* Update the state of all modifier keys, because modifiers used in
3427 hot-key combinations can get stuck on if Emacs loses focus as a
3428 result of a hot-key being pressed. */
3430 BYTE keystate[256];
3432 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3434 GetKeyboardState (keystate);
3435 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3436 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3437 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3438 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3439 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3440 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3441 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3442 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3443 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3444 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3445 SetKeyboardState (keystate);
3449 /* Synchronize modifier state with what is reported with the current
3450 keystroke. Even if we cannot distinguish between left and right
3451 modifier keys, we know that, if no modifiers are set, then neither
3452 the left or right modifier should be set. */
3453 static void
3454 sync_modifiers ()
3456 if (!modifiers_recorded)
3457 return;
3459 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3460 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3462 if (!(GetKeyState (VK_MENU) & 0x8000))
3463 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3466 static int
3467 modifier_set (int vkey)
3469 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3470 return (GetKeyState (vkey) & 0x1);
3471 if (!modifiers_recorded)
3472 return (GetKeyState (vkey) & 0x8000);
3474 switch (vkey)
3476 case VK_LCONTROL:
3477 return modifiers[EMACS_LCONTROL];
3478 case VK_RCONTROL:
3479 return modifiers[EMACS_RCONTROL];
3480 case VK_LMENU:
3481 return modifiers[EMACS_LMENU];
3482 case VK_RMENU:
3483 return modifiers[EMACS_RMENU];
3485 return (GetKeyState (vkey) & 0x8000);
3488 /* Convert between the modifier bits W32 uses and the modifier bits
3489 Emacs uses. */
3491 unsigned int
3492 w32_key_to_modifier (int key)
3494 Lisp_Object key_mapping;
3496 switch (key)
3498 case VK_LWIN:
3499 key_mapping = Vw32_lwindow_modifier;
3500 break;
3501 case VK_RWIN:
3502 key_mapping = Vw32_rwindow_modifier;
3503 break;
3504 case VK_APPS:
3505 key_mapping = Vw32_apps_modifier;
3506 break;
3507 case VK_SCROLL:
3508 key_mapping = Vw32_scroll_lock_modifier;
3509 break;
3510 default:
3511 key_mapping = Qnil;
3514 /* NB. This code runs in the input thread, asychronously to the lisp
3515 thread, so we must be careful to ensure access to lisp data is
3516 thread-safe. The following code is safe because the modifier
3517 variable values are updated atomically from lisp and symbols are
3518 not relocated by GC. Also, we don't have to worry about seeing GC
3519 markbits here. */
3520 if (EQ (key_mapping, Qhyper))
3521 return hyper_modifier;
3522 if (EQ (key_mapping, Qsuper))
3523 return super_modifier;
3524 if (EQ (key_mapping, Qmeta))
3525 return meta_modifier;
3526 if (EQ (key_mapping, Qalt))
3527 return alt_modifier;
3528 if (EQ (key_mapping, Qctrl))
3529 return ctrl_modifier;
3530 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3531 return ctrl_modifier;
3532 if (EQ (key_mapping, Qshift))
3533 return shift_modifier;
3535 /* Don't generate any modifier if not explicitly requested. */
3536 return 0;
3539 unsigned int
3540 w32_get_modifiers ()
3542 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3543 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3544 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3545 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3546 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3547 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3548 (modifier_set (VK_MENU) ?
3549 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3552 /* We map the VK_* modifiers into console modifier constants
3553 so that we can use the same routines to handle both console
3554 and window input. */
3556 static int
3557 construct_console_modifiers ()
3559 int mods;
3561 mods = 0;
3562 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3563 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3564 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3565 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3566 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3567 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3568 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3569 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3570 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3571 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3572 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3574 return mods;
3577 static int
3578 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3580 int mods;
3582 /* Convert to emacs modifiers. */
3583 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3585 return mods;
3588 unsigned int
3589 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3591 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3592 return virt_key;
3594 if (virt_key == VK_RETURN)
3595 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3597 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3598 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3600 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3601 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3603 if (virt_key == VK_CLEAR)
3604 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3606 return virt_key;
3609 /* List of special key combinations which w32 would normally capture,
3610 but emacs should grab instead. Not directly visible to lisp, to
3611 simplify synchronization. Each item is an integer encoding a virtual
3612 key code and modifier combination to capture. */
3613 Lisp_Object w32_grabbed_keys;
3615 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3616 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3617 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3618 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3620 /* Register hot-keys for reserved key combinations when Emacs has
3621 keyboard focus, since this is the only way Emacs can receive key
3622 combinations like Alt-Tab which are used by the system. */
3624 static void
3625 register_hot_keys (hwnd)
3626 HWND hwnd;
3628 Lisp_Object keylist;
3630 /* Use GC_CONSP, since we are called asynchronously. */
3631 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3633 Lisp_Object key = XCAR (keylist);
3635 /* Deleted entries get set to nil. */
3636 if (!INTEGERP (key))
3637 continue;
3639 RegisterHotKey (hwnd, HOTKEY_ID (key),
3640 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3644 static void
3645 unregister_hot_keys (hwnd)
3646 HWND hwnd;
3648 Lisp_Object keylist;
3650 /* Use GC_CONSP, since we are called asynchronously. */
3651 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3653 Lisp_Object key = XCAR (keylist);
3655 if (!INTEGERP (key))
3656 continue;
3658 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3662 /* Main message dispatch loop. */
3664 static void
3665 w32_msg_pump (deferred_msg * msg_buf)
3667 MSG msg;
3668 int result;
3669 HWND focus_window;
3671 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3673 while (GetMessage (&msg, NULL, 0, 0))
3675 if (msg.hwnd == NULL)
3677 switch (msg.message)
3679 case WM_NULL:
3680 /* Produced by complete_deferred_msg; just ignore. */
3681 break;
3682 case WM_EMACS_CREATEWINDOW:
3683 w32_createwindow ((struct frame *) msg.wParam);
3684 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3685 abort ();
3686 break;
3687 case WM_EMACS_SETLOCALE:
3688 SetThreadLocale (msg.wParam);
3689 /* Reply is not expected. */
3690 break;
3691 case WM_EMACS_SETKEYBOARDLAYOUT:
3692 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3693 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3694 result, 0))
3695 abort ();
3696 break;
3697 case WM_EMACS_REGISTER_HOT_KEY:
3698 focus_window = GetFocus ();
3699 if (focus_window != NULL)
3700 RegisterHotKey (focus_window,
3701 HOTKEY_ID (msg.wParam),
3702 HOTKEY_MODIFIERS (msg.wParam),
3703 HOTKEY_VK_CODE (msg.wParam));
3704 /* Reply is not expected. */
3705 break;
3706 case WM_EMACS_UNREGISTER_HOT_KEY:
3707 focus_window = GetFocus ();
3708 if (focus_window != NULL)
3709 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3710 /* Mark item as erased. NB: this code must be
3711 thread-safe. The next line is okay because the cons
3712 cell is never made into garbage and is not relocated by
3713 GC. */
3714 XCAR ((Lisp_Object) msg.lParam) = Qnil;
3715 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3716 abort ();
3717 break;
3718 case WM_EMACS_TOGGLE_LOCK_KEY:
3720 int vk_code = (int) msg.wParam;
3721 int cur_state = (GetKeyState (vk_code) & 1);
3722 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3724 /* NB: This code must be thread-safe. It is safe to
3725 call NILP because symbols are not relocated by GC,
3726 and pointer here is not touched by GC (so the markbit
3727 can't be set). Numbers are safe because they are
3728 immediate values. */
3729 if (NILP (new_state)
3730 || (NUMBERP (new_state)
3731 && (XUINT (new_state)) & 1 != cur_state))
3733 one_w32_display_info.faked_key = vk_code;
3735 keybd_event ((BYTE) vk_code,
3736 (BYTE) MapVirtualKey (vk_code, 0),
3737 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3738 keybd_event ((BYTE) vk_code,
3739 (BYTE) MapVirtualKey (vk_code, 0),
3740 KEYEVENTF_EXTENDEDKEY | 0, 0);
3741 keybd_event ((BYTE) vk_code,
3742 (BYTE) MapVirtualKey (vk_code, 0),
3743 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3744 cur_state = !cur_state;
3746 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3747 cur_state, 0))
3748 abort ();
3750 break;
3751 default:
3752 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3755 else
3757 DispatchMessage (&msg);
3760 /* Exit nested loop when our deferred message has completed. */
3761 if (msg_buf->completed)
3762 break;
3766 deferred_msg * deferred_msg_head;
3768 static deferred_msg *
3769 find_deferred_msg (HWND hwnd, UINT msg)
3771 deferred_msg * item;
3773 /* Don't actually need synchronization for read access, since
3774 modification of single pointer is always atomic. */
3775 /* enter_crit (); */
3777 for (item = deferred_msg_head; item != NULL; item = item->next)
3778 if (item->w32msg.msg.hwnd == hwnd
3779 && item->w32msg.msg.message == msg)
3780 break;
3782 /* leave_crit (); */
3784 return item;
3787 static LRESULT
3788 send_deferred_msg (deferred_msg * msg_buf,
3789 HWND hwnd,
3790 UINT msg,
3791 WPARAM wParam,
3792 LPARAM lParam)
3794 /* Only input thread can send deferred messages. */
3795 if (GetCurrentThreadId () != dwWindowsThreadId)
3796 abort ();
3798 /* It is an error to send a message that is already deferred. */
3799 if (find_deferred_msg (hwnd, msg) != NULL)
3800 abort ();
3802 /* Enforced synchronization is not needed because this is the only
3803 function that alters deferred_msg_head, and the following critical
3804 section is guaranteed to only be serially reentered (since only the
3805 input thread can call us). */
3807 /* enter_crit (); */
3809 msg_buf->completed = 0;
3810 msg_buf->next = deferred_msg_head;
3811 deferred_msg_head = msg_buf;
3812 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3814 /* leave_crit (); */
3816 /* Start a new nested message loop to process other messages until
3817 this one is completed. */
3818 w32_msg_pump (msg_buf);
3820 deferred_msg_head = msg_buf->next;
3822 return msg_buf->result;
3825 void
3826 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3828 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3830 if (msg_buf == NULL)
3831 /* Message may have been cancelled, so don't abort(). */
3832 return;
3834 msg_buf->result = result;
3835 msg_buf->completed = 1;
3837 /* Ensure input thread is woken so it notices the completion. */
3838 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3841 void
3842 cancel_all_deferred_msgs ()
3844 deferred_msg * item;
3846 /* Don't actually need synchronization for read access, since
3847 modification of single pointer is always atomic. */
3848 /* enter_crit (); */
3850 for (item = deferred_msg_head; item != NULL; item = item->next)
3852 item->result = 0;
3853 item->completed = 1;
3856 /* leave_crit (); */
3858 /* Ensure input thread is woken so it notices the completion. */
3859 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3862 DWORD
3863 w32_msg_worker (dw)
3864 DWORD dw;
3866 MSG msg;
3867 deferred_msg dummy_buf;
3869 /* Ensure our message queue is created */
3871 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3873 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3874 abort ();
3876 memset (&dummy_buf, 0, sizeof (dummy_buf));
3877 dummy_buf.w32msg.msg.hwnd = NULL;
3878 dummy_buf.w32msg.msg.message = WM_NULL;
3880 /* This is the inital message loop which should only exit when the
3881 application quits. */
3882 w32_msg_pump (&dummy_buf);
3884 return 0;
3887 static void
3888 post_character_message (hwnd, msg, wParam, lParam, modifiers)
3889 HWND hwnd;
3890 UINT msg;
3891 WPARAM wParam;
3892 LPARAM lParam;
3893 DWORD modifiers;
3896 W32Msg wmsg;
3898 wmsg.dwModifiers = modifiers;
3900 /* Detect quit_char and set quit-flag directly. Note that we
3901 still need to post a message to ensure the main thread will be
3902 woken up if blocked in sys_select(), but we do NOT want to post
3903 the quit_char message itself (because it will usually be as if
3904 the user had typed quit_char twice). Instead, we post a dummy
3905 message that has no particular effect. */
3907 int c = wParam;
3908 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
3909 c = make_ctrl_char (c) & 0377;
3910 if (c == quit_char
3911 || (wmsg.dwModifiers == 0 &&
3912 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
3914 Vquit_flag = Qt;
3916 /* The choice of message is somewhat arbitrary, as long as
3917 the main thread handler just ignores it. */
3918 msg = WM_NULL;
3920 /* Interrupt any blocking system calls. */
3921 signal_quit ();
3923 /* As a safety precaution, forcibly complete any deferred
3924 messages. This is a kludge, but I don't see any particularly
3925 clean way to handle the situation where a deferred message is
3926 "dropped" in the lisp thread, and will thus never be
3927 completed, eg. by the user trying to activate the menubar
3928 when the lisp thread is busy, and then typing C-g when the
3929 menubar doesn't open promptly (with the result that the
3930 menubar never responds at all because the deferred
3931 WM_INITMENU message is never completed). Another problem
3932 situation is when the lisp thread calls SendMessage (to send
3933 a window manager command) when a message has been deferred;
3934 the lisp thread gets blocked indefinitely waiting for the
3935 deferred message to be completed, which itself is waiting for
3936 the lisp thread to respond.
3938 Note that we don't want to block the input thread waiting for
3939 a reponse from the lisp thread (although that would at least
3940 solve the deadlock problem above), because we want to be able
3941 to receive C-g to interrupt the lisp thread. */
3942 cancel_all_deferred_msgs ();
3946 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3949 /* Main window procedure */
3951 LRESULT CALLBACK
3952 w32_wnd_proc (hwnd, msg, wParam, lParam)
3953 HWND hwnd;
3954 UINT msg;
3955 WPARAM wParam;
3956 LPARAM lParam;
3958 struct frame *f;
3959 struct w32_display_info *dpyinfo = &one_w32_display_info;
3960 W32Msg wmsg;
3961 int windows_translate;
3962 int key;
3964 /* Note that it is okay to call x_window_to_frame, even though we are
3965 not running in the main lisp thread, because frame deletion
3966 requires the lisp thread to synchronize with this thread. Thus, if
3967 a frame struct is returned, it can be used without concern that the
3968 lisp thread might make it disappear while we are using it.
3970 NB. Walking the frame list in this thread is safe (as long as
3971 writes of Lisp_Object slots are atomic, which they are on Windows).
3972 Although delete-frame can destructively modify the frame list while
3973 we are walking it, a garbage collection cannot occur until after
3974 delete-frame has synchronized with this thread.
3976 It is also safe to use functions that make GDI calls, such as
3977 w32_clear_rect, because these functions must obtain a DC handle
3978 from the frame struct using get_frame_dc which is thread-aware. */
3980 switch (msg)
3982 case WM_ERASEBKGND:
3983 f = x_window_to_frame (dpyinfo, hwnd);
3984 if (f)
3986 HDC hdc = get_frame_dc (f);
3987 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
3988 w32_clear_rect (f, hdc, &wmsg.rect);
3989 release_frame_dc (f, hdc);
3991 #if defined (W32_DEBUG_DISPLAY)
3992 DebPrint (("WM_ERASEBKGND: erasing %d,%d-%d,%d\n",
3993 wmsg.rect.left, wmsg.rect.top, wmsg.rect.right,
3994 wmsg.rect.bottom));
3995 #endif /* W32_DEBUG_DISPLAY */
3997 return 1;
3998 case WM_PALETTECHANGED:
3999 /* ignore our own changes */
4000 if ((HWND)wParam != hwnd)
4002 f = x_window_to_frame (dpyinfo, hwnd);
4003 if (f)
4004 /* get_frame_dc will realize our palette and force all
4005 frames to be redrawn if needed. */
4006 release_frame_dc (f, get_frame_dc (f));
4008 return 0;
4009 case WM_PAINT:
4011 PAINTSTRUCT paintStruct;
4012 RECT update_rect;
4014 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4015 fails. Apparently this can happen under some
4016 circumstances. */
4017 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
4019 enter_crit ();
4020 BeginPaint (hwnd, &paintStruct);
4022 if (w32_strict_painting)
4023 /* The rectangles returned by GetUpdateRect and BeginPaint
4024 do not always match. GetUpdateRect seems to be the
4025 more reliable of the two. */
4026 wmsg.rect = update_rect;
4027 else
4028 wmsg.rect = paintStruct.rcPaint;
4030 #if defined (W32_DEBUG_DISPLAY)
4031 DebPrint (("WM_PAINT: painting %d,%d-%d,%d\n", wmsg.rect.left,
4032 wmsg.rect.top, wmsg.rect.right, wmsg.rect.bottom));
4033 DebPrint (("WM_PAINT: update region is %d,%d-%d,%d\n",
4034 update_rect.left, update_rect.top,
4035 update_rect.right, update_rect.bottom));
4036 #endif
4037 EndPaint (hwnd, &paintStruct);
4038 leave_crit ();
4040 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4042 return 0;
4045 /* If GetUpdateRect returns 0 (meaning there is no update
4046 region), assume the whole window needs to be repainted. */
4047 GetClientRect(hwnd, &wmsg.rect);
4048 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4049 return 0;
4052 case WM_INPUTLANGCHANGE:
4053 /* Inform lisp thread of keyboard layout changes. */
4054 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4056 /* Clear dead keys in the keyboard state; for simplicity only
4057 preserve modifier key states. */
4059 int i;
4060 BYTE keystate[256];
4062 GetKeyboardState (keystate);
4063 for (i = 0; i < 256; i++)
4064 if (1
4065 && i != VK_SHIFT
4066 && i != VK_LSHIFT
4067 && i != VK_RSHIFT
4068 && i != VK_CAPITAL
4069 && i != VK_NUMLOCK
4070 && i != VK_SCROLL
4071 && i != VK_CONTROL
4072 && i != VK_LCONTROL
4073 && i != VK_RCONTROL
4074 && i != VK_MENU
4075 && i != VK_LMENU
4076 && i != VK_RMENU
4077 && i != VK_LWIN
4078 && i != VK_RWIN)
4079 keystate[i] = 0;
4080 SetKeyboardState (keystate);
4082 goto dflt;
4084 case WM_HOTKEY:
4085 /* Synchronize hot keys with normal input. */
4086 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4087 return (0);
4089 case WM_KEYUP:
4090 case WM_SYSKEYUP:
4091 record_keyup (wParam, lParam);
4092 goto dflt;
4094 case WM_KEYDOWN:
4095 case WM_SYSKEYDOWN:
4096 /* Ignore keystrokes we fake ourself; see below. */
4097 if (dpyinfo->faked_key == wParam)
4099 dpyinfo->faked_key = 0;
4100 /* Make sure TranslateMessage sees them though (as long as
4101 they don't produce WM_CHAR messages). This ensures that
4102 indicator lights are toggled promptly on Windows 9x, for
4103 example. */
4104 if (lispy_function_keys[wParam] != 0)
4106 windows_translate = 1;
4107 goto translate;
4109 return 0;
4112 /* Synchronize modifiers with current keystroke. */
4113 sync_modifiers ();
4114 record_keydown (wParam, lParam);
4115 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4117 windows_translate = 0;
4119 switch (wParam)
4121 case VK_LWIN:
4122 if (NILP (Vw32_pass_lwindow_to_system))
4124 /* Prevent system from acting on keyup (which opens the
4125 Start menu if no other key was pressed) by simulating a
4126 press of Space which we will ignore. */
4127 if (GetAsyncKeyState (wParam) & 1)
4129 if (NUMBERP (Vw32_phantom_key_code))
4130 key = XUINT (Vw32_phantom_key_code) & 255;
4131 else
4132 key = VK_SPACE;
4133 dpyinfo->faked_key = key;
4134 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4137 if (!NILP (Vw32_lwindow_modifier))
4138 return 0;
4139 break;
4140 case VK_RWIN:
4141 if (NILP (Vw32_pass_rwindow_to_system))
4143 if (GetAsyncKeyState (wParam) & 1)
4145 if (NUMBERP (Vw32_phantom_key_code))
4146 key = XUINT (Vw32_phantom_key_code) & 255;
4147 else
4148 key = VK_SPACE;
4149 dpyinfo->faked_key = key;
4150 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4153 if (!NILP (Vw32_rwindow_modifier))
4154 return 0;
4155 break;
4156 case VK_APPS:
4157 if (!NILP (Vw32_apps_modifier))
4158 return 0;
4159 break;
4160 case VK_MENU:
4161 if (NILP (Vw32_pass_alt_to_system))
4162 /* Prevent DefWindowProc from activating the menu bar if an
4163 Alt key is pressed and released by itself. */
4164 return 0;
4165 windows_translate = 1;
4166 break;
4167 case VK_CAPITAL:
4168 /* Decide whether to treat as modifier or function key. */
4169 if (NILP (Vw32_enable_caps_lock))
4170 goto disable_lock_key;
4171 windows_translate = 1;
4172 break;
4173 case VK_NUMLOCK:
4174 /* Decide whether to treat as modifier or function key. */
4175 if (NILP (Vw32_enable_num_lock))
4176 goto disable_lock_key;
4177 windows_translate = 1;
4178 break;
4179 case VK_SCROLL:
4180 /* Decide whether to treat as modifier or function key. */
4181 if (NILP (Vw32_scroll_lock_modifier))
4182 goto disable_lock_key;
4183 windows_translate = 1;
4184 break;
4185 disable_lock_key:
4186 /* Ensure the appropriate lock key state (and indicator light)
4187 remains in the same state. We do this by faking another
4188 press of the relevant key. Apparently, this really is the
4189 only way to toggle the state of the indicator lights. */
4190 dpyinfo->faked_key = wParam;
4191 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4192 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4193 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4194 KEYEVENTF_EXTENDEDKEY | 0, 0);
4195 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4196 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4197 /* Ensure indicator lights are updated promptly on Windows 9x
4198 (TranslateMessage apparently does this), after forwarding
4199 input event. */
4200 post_character_message (hwnd, msg, wParam, lParam,
4201 w32_get_key_modifiers (wParam, lParam));
4202 windows_translate = 1;
4203 break;
4204 case VK_CONTROL:
4205 case VK_SHIFT:
4206 case VK_PROCESSKEY: /* Generated by IME. */
4207 windows_translate = 1;
4208 break;
4209 case VK_CANCEL:
4210 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4211 which is confusing for purposes of key binding; convert
4212 VK_CANCEL events into VK_PAUSE events. */
4213 wParam = VK_PAUSE;
4214 break;
4215 case VK_PAUSE:
4216 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4217 for purposes of key binding; convert these back into
4218 VK_NUMLOCK events, at least when we want to see NumLock key
4219 presses. (Note that there is never any possibility that
4220 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4221 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4222 wParam = VK_NUMLOCK;
4223 break;
4224 default:
4225 /* If not defined as a function key, change it to a WM_CHAR message. */
4226 if (lispy_function_keys[wParam] == 0)
4228 DWORD modifiers = construct_console_modifiers ();
4230 if (!NILP (Vw32_recognize_altgr)
4231 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4233 /* Always let TranslateMessage handle AltGr key chords;
4234 for some reason, ToAscii doesn't always process AltGr
4235 chords correctly. */
4236 windows_translate = 1;
4238 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4240 /* Handle key chords including any modifiers other
4241 than shift directly, in order to preserve as much
4242 modifier information as possible. */
4243 if ('A' <= wParam && wParam <= 'Z')
4245 /* Don't translate modified alphabetic keystrokes,
4246 so the user doesn't need to constantly switch
4247 layout to type control or meta keystrokes when
4248 the normal layout translates alphabetic
4249 characters to non-ascii characters. */
4250 if (!modifier_set (VK_SHIFT))
4251 wParam += ('a' - 'A');
4252 msg = WM_CHAR;
4254 else
4256 /* Try to handle other keystrokes by determining the
4257 base character (ie. translating the base key plus
4258 shift modifier). */
4259 int add;
4260 int isdead = 0;
4261 KEY_EVENT_RECORD key;
4263 key.bKeyDown = TRUE;
4264 key.wRepeatCount = 1;
4265 key.wVirtualKeyCode = wParam;
4266 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4267 key.uChar.AsciiChar = 0;
4268 key.dwControlKeyState = modifiers;
4270 add = w32_kbd_patch_key (&key);
4271 /* 0 means an unrecognised keycode, negative means
4272 dead key. Ignore both. */
4273 while (--add >= 0)
4275 /* Forward asciified character sequence. */
4276 post_character_message
4277 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4278 w32_get_key_modifiers (wParam, lParam));
4279 w32_kbd_patch_key (&key);
4281 return 0;
4284 else
4286 /* Let TranslateMessage handle everything else. */
4287 windows_translate = 1;
4292 translate:
4293 if (windows_translate)
4295 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4297 windows_msg.time = GetMessageTime ();
4298 TranslateMessage (&windows_msg);
4299 goto dflt;
4302 /* Fall through */
4304 case WM_SYSCHAR:
4305 case WM_CHAR:
4306 post_character_message (hwnd, msg, wParam, lParam,
4307 w32_get_key_modifiers (wParam, lParam));
4308 break;
4310 /* Simulate middle mouse button events when left and right buttons
4311 are used together, but only if user has two button mouse. */
4312 case WM_LBUTTONDOWN:
4313 case WM_RBUTTONDOWN:
4314 if (XINT (Vw32_num_mouse_buttons) > 2)
4315 goto handle_plain_button;
4318 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4319 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4321 if (button_state & this)
4322 return 0;
4324 if (button_state == 0)
4325 SetCapture (hwnd);
4327 button_state |= this;
4329 if (button_state & other)
4331 if (mouse_button_timer)
4333 KillTimer (hwnd, mouse_button_timer);
4334 mouse_button_timer = 0;
4336 /* Generate middle mouse event instead. */
4337 msg = WM_MBUTTONDOWN;
4338 button_state |= MMOUSE;
4340 else if (button_state & MMOUSE)
4342 /* Ignore button event if we've already generated a
4343 middle mouse down event. This happens if the
4344 user releases and press one of the two buttons
4345 after we've faked a middle mouse event. */
4346 return 0;
4348 else
4350 /* Flush out saved message. */
4351 post_msg (&saved_mouse_button_msg);
4353 wmsg.dwModifiers = w32_get_modifiers ();
4354 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4356 /* Clear message buffer. */
4357 saved_mouse_button_msg.msg.hwnd = 0;
4359 else
4361 /* Hold onto message for now. */
4362 mouse_button_timer =
4363 SetTimer (hwnd, MOUSE_BUTTON_ID,
4364 XINT (Vw32_mouse_button_tolerance), NULL);
4365 saved_mouse_button_msg.msg.hwnd = hwnd;
4366 saved_mouse_button_msg.msg.message = msg;
4367 saved_mouse_button_msg.msg.wParam = wParam;
4368 saved_mouse_button_msg.msg.lParam = lParam;
4369 saved_mouse_button_msg.msg.time = GetMessageTime ();
4370 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4373 return 0;
4375 case WM_LBUTTONUP:
4376 case WM_RBUTTONUP:
4377 if (XINT (Vw32_num_mouse_buttons) > 2)
4378 goto handle_plain_button;
4381 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4382 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4384 if ((button_state & this) == 0)
4385 return 0;
4387 button_state &= ~this;
4389 if (button_state & MMOUSE)
4391 /* Only generate event when second button is released. */
4392 if ((button_state & other) == 0)
4394 msg = WM_MBUTTONUP;
4395 button_state &= ~MMOUSE;
4397 if (button_state) abort ();
4399 else
4400 return 0;
4402 else
4404 /* Flush out saved message if necessary. */
4405 if (saved_mouse_button_msg.msg.hwnd)
4407 post_msg (&saved_mouse_button_msg);
4410 wmsg.dwModifiers = w32_get_modifiers ();
4411 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4413 /* Always clear message buffer and cancel timer. */
4414 saved_mouse_button_msg.msg.hwnd = 0;
4415 KillTimer (hwnd, mouse_button_timer);
4416 mouse_button_timer = 0;
4418 if (button_state == 0)
4419 ReleaseCapture ();
4421 return 0;
4423 case WM_MBUTTONDOWN:
4424 case WM_MBUTTONUP:
4425 handle_plain_button:
4427 BOOL up;
4428 int button;
4430 if (parse_button (msg, &button, &up))
4432 if (up) ReleaseCapture ();
4433 else SetCapture (hwnd);
4434 button = (button == 0) ? LMOUSE :
4435 ((button == 1) ? MMOUSE : RMOUSE);
4436 if (up)
4437 button_state &= ~button;
4438 else
4439 button_state |= button;
4443 wmsg.dwModifiers = w32_get_modifiers ();
4444 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4445 return 0;
4447 case WM_VSCROLL:
4448 case WM_MOUSEMOVE:
4449 if (XINT (Vw32_mouse_move_interval) <= 0
4450 || (msg == WM_MOUSEMOVE && button_state == 0))
4452 wmsg.dwModifiers = w32_get_modifiers ();
4453 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4454 return 0;
4457 /* Hang onto mouse move and scroll messages for a bit, to avoid
4458 sending such events to Emacs faster than it can process them.
4459 If we get more events before the timer from the first message
4460 expires, we just replace the first message. */
4462 if (saved_mouse_move_msg.msg.hwnd == 0)
4463 mouse_move_timer =
4464 SetTimer (hwnd, MOUSE_MOVE_ID,
4465 XINT (Vw32_mouse_move_interval), NULL);
4467 /* Hold onto message for now. */
4468 saved_mouse_move_msg.msg.hwnd = hwnd;
4469 saved_mouse_move_msg.msg.message = msg;
4470 saved_mouse_move_msg.msg.wParam = wParam;
4471 saved_mouse_move_msg.msg.lParam = lParam;
4472 saved_mouse_move_msg.msg.time = GetMessageTime ();
4473 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4475 return 0;
4477 case WM_MOUSEWHEEL:
4478 wmsg.dwModifiers = w32_get_modifiers ();
4479 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4480 return 0;
4482 case WM_DROPFILES:
4483 wmsg.dwModifiers = w32_get_modifiers ();
4484 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4485 return 0;
4487 case WM_TIMER:
4488 /* Flush out saved messages if necessary. */
4489 if (wParam == mouse_button_timer)
4491 if (saved_mouse_button_msg.msg.hwnd)
4493 post_msg (&saved_mouse_button_msg);
4494 saved_mouse_button_msg.msg.hwnd = 0;
4496 KillTimer (hwnd, mouse_button_timer);
4497 mouse_button_timer = 0;
4499 else if (wParam == mouse_move_timer)
4501 if (saved_mouse_move_msg.msg.hwnd)
4503 post_msg (&saved_mouse_move_msg);
4504 saved_mouse_move_msg.msg.hwnd = 0;
4506 KillTimer (hwnd, mouse_move_timer);
4507 mouse_move_timer = 0;
4509 return 0;
4511 case WM_NCACTIVATE:
4512 /* Windows doesn't send us focus messages when putting up and
4513 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4514 The only indication we get that something happened is receiving
4515 this message afterwards. So this is a good time to reset our
4516 keyboard modifiers' state. */
4517 reset_modifiers ();
4518 goto dflt;
4520 case WM_INITMENU:
4521 button_state = 0;
4522 ReleaseCapture ();
4523 /* We must ensure menu bar is fully constructed and up to date
4524 before allowing user interaction with it. To achieve this
4525 we send this message to the lisp thread and wait for a
4526 reply (whose value is not actually needed) to indicate that
4527 the menu bar is now ready for use, so we can now return.
4529 To remain responsive in the meantime, we enter a nested message
4530 loop that can process all other messages.
4532 However, we skip all this if the message results from calling
4533 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4534 thread a message because it is blocked on us at this point. We
4535 set menubar_active before calling TrackPopupMenu to indicate
4536 this (there is no possibility of confusion with real menubar
4537 being active). */
4539 f = x_window_to_frame (dpyinfo, hwnd);
4540 if (f
4541 && (f->output_data.w32->menubar_active
4542 /* We can receive this message even in the absence of a
4543 menubar (ie. when the system menu is activated) - in this
4544 case we do NOT want to forward the message, otherwise it
4545 will cause the menubar to suddenly appear when the user
4546 had requested it to be turned off! */
4547 || f->output_data.w32->menubar_widget == NULL))
4548 return 0;
4551 deferred_msg msg_buf;
4553 /* Detect if message has already been deferred; in this case
4554 we cannot return any sensible value to ignore this. */
4555 if (find_deferred_msg (hwnd, msg) != NULL)
4556 abort ();
4558 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4561 case WM_EXITMENULOOP:
4562 f = x_window_to_frame (dpyinfo, hwnd);
4564 /* Indicate that menubar can be modified again. */
4565 if (f)
4566 f->output_data.w32->menubar_active = 0;
4567 goto dflt;
4569 case WM_MENUSELECT:
4570 wmsg.dwModifiers = w32_get_modifiers ();
4571 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4572 return 0;
4574 case WM_MEASUREITEM:
4575 f = x_window_to_frame (dpyinfo, hwnd);
4576 if (f)
4578 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4580 if (pMis->CtlType == ODT_MENU)
4582 /* Work out dimensions for popup menu titles. */
4583 char * title = (char *) pMis->itemData;
4584 HDC hdc = GetDC (hwnd);
4585 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4586 LOGFONT menu_logfont;
4587 HFONT old_font;
4588 SIZE size;
4590 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4591 menu_logfont.lfWeight = FW_BOLD;
4592 menu_font = CreateFontIndirect (&menu_logfont);
4593 old_font = SelectObject (hdc, menu_font);
4595 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4596 if (title)
4598 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4599 pMis->itemWidth = size.cx;
4600 if (pMis->itemHeight < size.cy)
4601 pMis->itemHeight = size.cy;
4603 else
4604 pMis->itemWidth = 0;
4606 SelectObject (hdc, old_font);
4607 DeleteObject (menu_font);
4608 ReleaseDC (hwnd, hdc);
4609 return TRUE;
4612 return 0;
4614 case WM_DRAWITEM:
4615 f = x_window_to_frame (dpyinfo, hwnd);
4616 if (f)
4618 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4620 if (pDis->CtlType == ODT_MENU)
4622 /* Draw popup menu title. */
4623 char * title = (char *) pDis->itemData;
4624 HDC hdc = pDis->hDC;
4625 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4626 LOGFONT menu_logfont;
4627 HFONT old_font;
4629 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4630 menu_logfont.lfWeight = FW_BOLD;
4631 menu_font = CreateFontIndirect (&menu_logfont);
4632 old_font = SelectObject (hdc, menu_font);
4634 /* Always draw title as if not selected. */
4635 ExtTextOut (hdc,
4636 pDis->rcItem.left + GetSystemMetrics (SM_CXMENUCHECK),
4637 pDis->rcItem.top,
4638 ETO_OPAQUE, &pDis->rcItem,
4639 title, strlen (title), NULL);
4641 SelectObject (hdc, old_font);
4642 DeleteObject (menu_font);
4643 return TRUE;
4646 return 0;
4648 #if 0
4649 /* Still not right - can't distinguish between clicks in the
4650 client area of the frame from clicks forwarded from the scroll
4651 bars - may have to hook WM_NCHITTEST to remember the mouse
4652 position and then check if it is in the client area ourselves. */
4653 case WM_MOUSEACTIVATE:
4654 /* Discard the mouse click that activates a frame, allowing the
4655 user to click anywhere without changing point (or worse!).
4656 Don't eat mouse clicks on scrollbars though!! */
4657 if (LOWORD (lParam) == HTCLIENT )
4658 return MA_ACTIVATEANDEAT;
4659 goto dflt;
4660 #endif
4662 case WM_ACTIVATEAPP:
4663 case WM_ACTIVATE:
4664 case WM_WINDOWPOSCHANGED:
4665 case WM_SHOWWINDOW:
4666 /* Inform lisp thread that a frame might have just been obscured
4667 or exposed, so should recheck visibility of all frames. */
4668 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4669 goto dflt;
4671 case WM_SETFOCUS:
4672 dpyinfo->faked_key = 0;
4673 reset_modifiers ();
4674 register_hot_keys (hwnd);
4675 goto command;
4676 case WM_KILLFOCUS:
4677 unregister_hot_keys (hwnd);
4678 button_state = 0;
4679 ReleaseCapture ();
4680 case WM_MOVE:
4681 case WM_SIZE:
4682 case WM_COMMAND:
4683 command:
4684 wmsg.dwModifiers = w32_get_modifiers ();
4685 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4686 goto dflt;
4688 case WM_CLOSE:
4689 wmsg.dwModifiers = w32_get_modifiers ();
4690 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4691 return 0;
4693 case WM_WINDOWPOSCHANGING:
4695 WINDOWPLACEMENT wp;
4696 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4698 wp.length = sizeof (WINDOWPLACEMENT);
4699 GetWindowPlacement (hwnd, &wp);
4701 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4703 RECT rect;
4704 int wdiff;
4705 int hdiff;
4706 DWORD font_width;
4707 DWORD line_height;
4708 DWORD internal_border;
4709 DWORD scrollbar_extra;
4710 RECT wr;
4712 wp.length = sizeof(wp);
4713 GetWindowRect (hwnd, &wr);
4715 enter_crit ();
4717 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4718 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4719 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4720 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4722 leave_crit ();
4724 memset (&rect, 0, sizeof (rect));
4725 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4726 GetMenu (hwnd) != NULL);
4728 /* Force width and height of client area to be exact
4729 multiples of the character cell dimensions. */
4730 wdiff = (lppos->cx - (rect.right - rect.left)
4731 - 2 * internal_border - scrollbar_extra)
4732 % font_width;
4733 hdiff = (lppos->cy - (rect.bottom - rect.top)
4734 - 2 * internal_border)
4735 % line_height;
4737 if (wdiff || hdiff)
4739 /* For right/bottom sizing we can just fix the sizes.
4740 However for top/left sizing we will need to fix the X
4741 and Y positions as well. */
4743 lppos->cx -= wdiff;
4744 lppos->cy -= hdiff;
4746 if (wp.showCmd != SW_SHOWMAXIMIZED
4747 && (lppos->flags & SWP_NOMOVE) == 0)
4749 if (lppos->x != wr.left || lppos->y != wr.top)
4751 lppos->x += wdiff;
4752 lppos->y += hdiff;
4754 else
4756 lppos->flags |= SWP_NOMOVE;
4760 return 0;
4765 goto dflt;
4767 case WM_GETMINMAXINFO:
4768 /* Hack to correct bug that allows Emacs frames to be resized
4769 below the Minimum Tracking Size. */
4770 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4771 return 0;
4773 case WM_EMACS_CREATESCROLLBAR:
4774 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4775 (struct scroll_bar *) lParam);
4777 case WM_EMACS_SHOWWINDOW:
4778 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4780 case WM_EMACS_SETFOREGROUND:
4782 HWND foreground_window;
4783 DWORD foreground_thread, retval;
4785 /* On NT 5.0, and apparently Windows 98, it is necessary to
4786 attach to the thread that currently has focus in order to
4787 pull the focus away from it. */
4788 foreground_window = GetForegroundWindow ();
4789 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4790 if (!foreground_window
4791 || foreground_thread == GetCurrentThreadId ()
4792 || !AttachThreadInput (GetCurrentThreadId (),
4793 foreground_thread, TRUE))
4794 foreground_thread = 0;
4796 retval = SetForegroundWindow ((HWND) wParam);
4798 /* Detach from the previous foreground thread. */
4799 if (foreground_thread)
4800 AttachThreadInput (GetCurrentThreadId (),
4801 foreground_thread, FALSE);
4803 return retval;
4806 case WM_EMACS_SETWINDOWPOS:
4808 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4809 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4810 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4813 case WM_EMACS_DESTROYWINDOW:
4814 DragAcceptFiles ((HWND) wParam, FALSE);
4815 return DestroyWindow ((HWND) wParam);
4817 case WM_EMACS_TRACKPOPUPMENU:
4819 UINT flags;
4820 POINT *pos;
4821 int retval;
4822 pos = (POINT *)lParam;
4823 flags = TPM_CENTERALIGN;
4824 if (button_state & LMOUSE)
4825 flags |= TPM_LEFTBUTTON;
4826 else if (button_state & RMOUSE)
4827 flags |= TPM_RIGHTBUTTON;
4829 /* Remember we did a SetCapture on the initial mouse down event,
4830 so for safety, we make sure the capture is cancelled now. */
4831 ReleaseCapture ();
4832 button_state = 0;
4834 /* Use menubar_active to indicate that WM_INITMENU is from
4835 TrackPopupMenu below, and should be ignored. */
4836 f = x_window_to_frame (dpyinfo, hwnd);
4837 if (f)
4838 f->output_data.w32->menubar_active = 1;
4840 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4841 0, hwnd, NULL))
4843 MSG amsg;
4844 /* Eat any mouse messages during popupmenu */
4845 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4846 PM_REMOVE));
4847 /* Get the menu selection, if any */
4848 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4850 retval = LOWORD (amsg.wParam);
4852 else
4854 retval = 0;
4857 else
4859 retval = -1;
4862 return retval;
4865 default:
4866 /* Check for messages registered at runtime. */
4867 if (msg == msh_mousewheel)
4869 wmsg.dwModifiers = w32_get_modifiers ();
4870 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4871 return 0;
4874 dflt:
4875 return DefWindowProc (hwnd, msg, wParam, lParam);
4879 /* The most common default return code for handled messages is 0. */
4880 return 0;
4883 void
4884 my_create_window (f)
4885 struct frame * f;
4887 MSG msg;
4889 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4890 abort ();
4891 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4894 /* Create and set up the w32 window for frame F. */
4896 static void
4897 w32_window (f, window_prompting, minibuffer_only)
4898 struct frame *f;
4899 long window_prompting;
4900 int minibuffer_only;
4902 BLOCK_INPUT;
4904 /* Use the resource name as the top-level window name
4905 for looking up resources. Make a non-Lisp copy
4906 for the window manager, so GC relocation won't bother it.
4908 Elsewhere we specify the window name for the window manager. */
4911 char *str = (char *) XSTRING (Vx_resource_name)->data;
4912 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4913 strcpy (f->namebuf, str);
4916 my_create_window (f);
4918 validate_x_resource_name ();
4920 /* x_set_name normally ignores requests to set the name if the
4921 requested name is the same as the current name. This is the one
4922 place where that assumption isn't correct; f->name is set, but
4923 the server hasn't been told. */
4925 Lisp_Object name;
4926 int explicit = f->explicit_name;
4928 f->explicit_name = 0;
4929 name = f->name;
4930 f->name = Qnil;
4931 x_set_name (f, name, explicit);
4934 UNBLOCK_INPUT;
4936 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4937 initialize_frame_menubar (f);
4939 if (FRAME_W32_WINDOW (f) == 0)
4940 error ("Unable to create window");
4943 /* Handle the icon stuff for this window. Perhaps later we might
4944 want an x_set_icon_position which can be called interactively as
4945 well. */
4947 static void
4948 x_icon (f, parms)
4949 struct frame *f;
4950 Lisp_Object parms;
4952 Lisp_Object icon_x, icon_y;
4954 /* Set the position of the icon. Note that Windows 95 groups all
4955 icons in the tray. */
4956 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4957 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4958 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4960 CHECK_NUMBER (icon_x, 0);
4961 CHECK_NUMBER (icon_y, 0);
4963 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4964 error ("Both left and top icon corners of icon must be specified");
4966 BLOCK_INPUT;
4968 if (! EQ (icon_x, Qunbound))
4969 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4971 #if 0 /* TODO */
4972 /* Start up iconic or window? */
4973 x_wm_set_window_state
4974 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4975 ? IconicState
4976 : NormalState));
4978 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4979 ? f->icon_name
4980 : f->name))->data);
4981 #endif
4983 UNBLOCK_INPUT;
4987 static void
4988 x_make_gc (f)
4989 struct frame *f;
4991 XGCValues gc_values;
4993 BLOCK_INPUT;
4995 /* Create the GC's of this frame.
4996 Note that many default values are used. */
4998 /* Normal video */
4999 gc_values.font = f->output_data.w32->font;
5001 /* Cursor has cursor-color background, background-color foreground. */
5002 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5003 gc_values.background = f->output_data.w32->cursor_pixel;
5004 f->output_data.w32->cursor_gc
5005 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5006 (GCFont | GCForeground | GCBackground),
5007 &gc_values);
5009 /* Reliefs. */
5010 f->output_data.w32->white_relief.gc = 0;
5011 f->output_data.w32->black_relief.gc = 0;
5013 UNBLOCK_INPUT;
5017 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5018 1, 1, 0,
5019 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5020 Returns an Emacs frame object.\n\
5021 ALIST is an alist of frame parameters.\n\
5022 If the parameters specify that the frame should not have a minibuffer,\n\
5023 and do not specify a specific minibuffer window to use,\n\
5024 then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5025 be shared by the new frame.\n\
5027 This function is an internal primitive--use `make-frame' instead.")
5028 (parms)
5029 Lisp_Object parms;
5031 struct frame *f;
5032 Lisp_Object frame, tem;
5033 Lisp_Object name;
5034 int minibuffer_only = 0;
5035 long window_prompting = 0;
5036 int width, height;
5037 int count = specpdl_ptr - specpdl;
5038 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5039 Lisp_Object display;
5040 struct w32_display_info *dpyinfo = NULL;
5041 Lisp_Object parent;
5042 struct kboard *kb;
5044 check_w32 ();
5046 /* Use this general default value to start with
5047 until we know if this frame has a specified name. */
5048 Vx_resource_name = Vinvocation_name;
5050 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5051 if (EQ (display, Qunbound))
5052 display = Qnil;
5053 dpyinfo = check_x_display_info (display);
5054 #ifdef MULTI_KBOARD
5055 kb = dpyinfo->kboard;
5056 #else
5057 kb = &the_only_kboard;
5058 #endif
5060 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5061 if (!STRINGP (name)
5062 && ! EQ (name, Qunbound)
5063 && ! NILP (name))
5064 error ("Invalid frame name--not a string or nil");
5066 if (STRINGP (name))
5067 Vx_resource_name = name;
5069 /* See if parent window is specified. */
5070 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5071 if (EQ (parent, Qunbound))
5072 parent = Qnil;
5073 if (! NILP (parent))
5074 CHECK_NUMBER (parent, 0);
5076 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5077 /* No need to protect DISPLAY because that's not used after passing
5078 it to make_frame_without_minibuffer. */
5079 frame = Qnil;
5080 GCPRO4 (parms, parent, name, frame);
5081 tem = w32_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
5082 if (EQ (tem, Qnone) || NILP (tem))
5083 f = make_frame_without_minibuffer (Qnil, kb, display);
5084 else if (EQ (tem, Qonly))
5086 f = make_minibuffer_frame ();
5087 minibuffer_only = 1;
5089 else if (WINDOWP (tem))
5090 f = make_frame_without_minibuffer (tem, kb, display);
5091 else
5092 f = make_frame (1);
5094 XSETFRAME (frame, f);
5096 /* Note that Windows does support scroll bars. */
5097 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5098 /* By default, make scrollbars the system standard width. */
5099 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5101 f->output_method = output_w32;
5102 f->output_data.w32 =
5103 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5104 bzero (f->output_data.w32, sizeof (struct w32_output));
5106 FRAME_FONTSET (f) = -1;
5108 f->icon_name
5109 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5110 if (! STRINGP (f->icon_name))
5111 f->icon_name = Qnil;
5113 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5114 #ifdef MULTI_KBOARD
5115 FRAME_KBOARD (f) = kb;
5116 #endif
5118 /* Specify the parent under which to make this window. */
5120 if (!NILP (parent))
5122 f->output_data.w32->parent_desc = (Window) parent;
5123 f->output_data.w32->explicit_parent = 1;
5125 else
5127 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5128 f->output_data.w32->explicit_parent = 0;
5131 /* Set the name; the functions to which we pass f expect the name to
5132 be set. */
5133 if (EQ (name, Qunbound) || NILP (name))
5135 f->name = build_string (dpyinfo->w32_id_name);
5136 f->explicit_name = 0;
5138 else
5140 f->name = name;
5141 f->explicit_name = 1;
5142 /* use the frame's title when getting resources for this frame. */
5143 specbind (Qx_resource_name, name);
5146 /* Extract the window parameters from the supplied values
5147 that are needed to determine window geometry. */
5149 Lisp_Object font;
5151 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5153 BLOCK_INPUT;
5154 /* First, try whatever font the caller has specified. */
5155 if (STRINGP (font))
5157 tem = Fquery_fontset (font, Qnil);
5158 if (STRINGP (tem))
5159 font = x_new_fontset (f, XSTRING (tem)->data);
5160 else
5161 font = x_new_font (f, XSTRING (font)->data);
5163 /* Try out a font which we hope has bold and italic variations. */
5164 if (!STRINGP (font))
5165 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5166 if (! STRINGP (font))
5167 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5168 /* If those didn't work, look for something which will at least work. */
5169 if (! STRINGP (font))
5170 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5171 UNBLOCK_INPUT;
5172 if (! STRINGP (font))
5173 font = build_string ("Fixedsys");
5175 x_default_parameter (f, parms, Qfont, font,
5176 "font", "Font", RES_TYPE_STRING);
5179 x_default_parameter (f, parms, Qborder_width, make_number (2),
5180 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
5181 /* This defaults to 2 in order to match xterm. We recognize either
5182 internalBorderWidth or internalBorder (which is what xterm calls
5183 it). */
5184 if (NILP (Fassq (Qinternal_border_width, parms)))
5186 Lisp_Object value;
5188 value = w32_get_arg (parms, Qinternal_border_width,
5189 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
5190 if (! EQ (value, Qunbound))
5191 parms = Fcons (Fcons (Qinternal_border_width, value),
5192 parms);
5194 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5195 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5196 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
5197 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
5198 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
5200 /* Also do the stuff which must be set before the window exists. */
5201 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5202 "foreground", "Foreground", RES_TYPE_STRING);
5203 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5204 "background", "Background", RES_TYPE_STRING);
5205 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5206 "pointerColor", "Foreground", RES_TYPE_STRING);
5207 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5208 "cursorColor", "Foreground", RES_TYPE_STRING);
5209 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5210 "borderColor", "BorderColor", RES_TYPE_STRING);
5211 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5212 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5213 x_default_parameter (f, parms, Qline_spacing, Qnil,
5214 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5217 /* Init faces before x_default_parameter is called for scroll-bar
5218 parameters because that function calls x_set_scroll_bar_width,
5219 which calls change_frame_size, which calls Fset_window_buffer,
5220 which runs hooks, which call Fvertical_motion. At the end, we
5221 end up in init_iterator with a null face cache, which should not
5222 happen. */
5223 init_frame_faces (f);
5225 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5226 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5227 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5228 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5229 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5230 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5231 x_default_parameter (f, parms, Qtitle, Qnil,
5232 "title", "Title", RES_TYPE_STRING);
5234 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5235 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5236 window_prompting = x_figure_window_size (f, parms);
5238 if (window_prompting & XNegative)
5240 if (window_prompting & YNegative)
5241 f->output_data.w32->win_gravity = SouthEastGravity;
5242 else
5243 f->output_data.w32->win_gravity = NorthEastGravity;
5245 else
5247 if (window_prompting & YNegative)
5248 f->output_data.w32->win_gravity = SouthWestGravity;
5249 else
5250 f->output_data.w32->win_gravity = NorthWestGravity;
5253 f->output_data.w32->size_hint_flags = window_prompting;
5255 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5256 f->no_split = minibuffer_only || EQ (tem, Qt);
5258 /* Create the window. Add the tool-bar height to the initial frame
5259 height so that the user gets a text display area of the size he
5260 specified with -g or via the registry. Later changes of the
5261 tool-bar height don't change the frame size. This is done so that
5262 users can create tall Emacs frames without having to guess how
5263 tall the tool-bar will get. */
5264 f->height += FRAME_TOOL_BAR_LINES (f);
5265 w32_window (f, window_prompting, minibuffer_only);
5266 x_icon (f, parms);
5268 x_make_gc (f);
5270 /* Now consider the frame official. */
5271 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5272 Vframe_list = Fcons (frame, Vframe_list);
5274 /* We need to do this after creating the window, so that the
5275 icon-creation functions can say whose icon they're describing. */
5276 x_default_parameter (f, parms, Qicon_type, Qnil,
5277 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5279 x_default_parameter (f, parms, Qauto_raise, Qnil,
5280 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5281 x_default_parameter (f, parms, Qauto_lower, Qnil,
5282 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5283 x_default_parameter (f, parms, Qcursor_type, Qbox,
5284 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5285 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5286 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5288 /* Dimensions, especially f->height, must be done via change_frame_size.
5289 Change will not be effected unless different from the current
5290 f->height. */
5291 width = f->width;
5292 height = f->height;
5293 f->height = 0;
5294 SET_FRAME_WIDTH (f, 0);
5295 change_frame_size (f, height, width, 1, 0, 0);
5297 /* Set up faces after all frame parameters are known. */
5298 call1 (Qface_set_after_frame_default, frame);
5300 /* Tell the server what size and position, etc, we want, and how
5301 badly we want them. This should be done after we have the menu
5302 bar so that its size can be taken into account. */
5303 BLOCK_INPUT;
5304 x_wm_set_size_hint (f, window_prompting, 0);
5305 UNBLOCK_INPUT;
5307 /* Make the window appear on the frame and enable display, unless
5308 the caller says not to. However, with explicit parent, Emacs
5309 cannot control visibility, so don't try. */
5310 if (! f->output_data.w32->explicit_parent)
5312 Lisp_Object visibility;
5314 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5315 if (EQ (visibility, Qunbound))
5316 visibility = Qt;
5318 if (EQ (visibility, Qicon))
5319 x_iconify_frame (f);
5320 else if (! NILP (visibility))
5321 x_make_frame_visible (f);
5322 else
5323 /* Must have been Qnil. */
5326 UNGCPRO;
5327 return unbind_to (count, frame);
5330 /* FRAME is used only to get a handle on the X display. We don't pass the
5331 display info directly because we're called from frame.c, which doesn't
5332 know about that structure. */
5333 Lisp_Object
5334 x_get_focus_frame (frame)
5335 struct frame *frame;
5337 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5338 Lisp_Object xfocus;
5339 if (! dpyinfo->w32_focus_frame)
5340 return Qnil;
5342 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5343 return xfocus;
5346 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5347 "Give FRAME input focus, raising to foreground if necessary.")
5348 (frame)
5349 Lisp_Object frame;
5351 x_focus_on_frame (check_x_frame (frame));
5352 return Qnil;
5356 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5357 int size, char* filename);
5359 struct font_info *
5360 w32_load_system_font (f,fontname,size)
5361 struct frame *f;
5362 char * fontname;
5363 int size;
5365 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5366 Lisp_Object font_names;
5368 /* Get a list of all the fonts that match this name. Once we
5369 have a list of matching fonts, we compare them against the fonts
5370 we already have loaded by comparing names. */
5371 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5373 if (!NILP (font_names))
5375 Lisp_Object tail;
5376 int i;
5378 /* First check if any are already loaded, as that is cheaper
5379 than loading another one. */
5380 for (i = 0; i < dpyinfo->n_fonts; i++)
5381 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5382 if (dpyinfo->font_table[i].name
5383 && (!strcmp (dpyinfo->font_table[i].name,
5384 XSTRING (XCAR (tail))->data)
5385 || !strcmp (dpyinfo->font_table[i].full_name,
5386 XSTRING (XCAR (tail))->data)))
5387 return (dpyinfo->font_table + i);
5389 fontname = (char *) XSTRING (XCAR (font_names))->data;
5391 else if (w32_strict_fontnames)
5393 /* If EnumFontFamiliesEx was available, we got a full list of
5394 fonts back so stop now to avoid the possibility of loading a
5395 random font. If we had to fall back to EnumFontFamilies, the
5396 list is incomplete, so continue whether the font we want was
5397 listed or not. */
5398 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5399 FARPROC enum_font_families_ex
5400 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5401 if (enum_font_families_ex)
5402 return NULL;
5405 /* Load the font and add it to the table. */
5407 char *full_name, *encoding;
5408 XFontStruct *font;
5409 struct font_info *fontp;
5410 LOGFONT lf;
5411 BOOL ok;
5412 int i;
5414 if (!fontname || !x_to_w32_font (fontname, &lf))
5415 return (NULL);
5417 if (!*lf.lfFaceName)
5418 /* If no name was specified for the font, we get a random font
5419 from CreateFontIndirect - this is not particularly
5420 desirable, especially since CreateFontIndirect does not
5421 fill out the missing name in lf, so we never know what we
5422 ended up with. */
5423 return NULL;
5425 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5427 /* Set bdf to NULL to indicate that this is a Windows font. */
5428 font->bdf = NULL;
5430 BLOCK_INPUT;
5432 font->hfont = CreateFontIndirect (&lf);
5434 if (font->hfont == NULL)
5436 ok = FALSE;
5438 else
5440 HDC hdc;
5441 HANDLE oldobj;
5443 hdc = GetDC (dpyinfo->root_window);
5444 oldobj = SelectObject (hdc, font->hfont);
5445 ok = GetTextMetrics (hdc, &font->tm);
5446 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5447 SelectObject (hdc, oldobj);
5448 ReleaseDC (dpyinfo->root_window, hdc);
5449 /* Fill out details in lf according to the font that was
5450 actually loaded. */
5451 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5452 lf.lfWidth = font->tm.tmAveCharWidth;
5453 lf.lfWeight = font->tm.tmWeight;
5454 lf.lfItalic = font->tm.tmItalic;
5455 lf.lfCharSet = font->tm.tmCharSet;
5456 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5457 ? VARIABLE_PITCH : FIXED_PITCH);
5458 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5459 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5462 UNBLOCK_INPUT;
5464 if (!ok)
5466 w32_unload_font (dpyinfo, font);
5467 return (NULL);
5470 /* Find a free slot in the font table. */
5471 for (i = 0; i < dpyinfo->n_fonts; ++i)
5472 if (dpyinfo->font_table[i].name == NULL)
5473 break;
5475 /* If no free slot found, maybe enlarge the font table. */
5476 if (i == dpyinfo->n_fonts
5477 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5479 int sz;
5480 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5481 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5482 dpyinfo->font_table
5483 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5486 fontp = dpyinfo->font_table + i;
5487 if (i == dpyinfo->n_fonts)
5488 ++dpyinfo->n_fonts;
5490 /* Now fill in the slots of *FONTP. */
5491 BLOCK_INPUT;
5492 fontp->font = font;
5493 fontp->font_idx = i;
5494 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5495 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5497 /* Work out the font's full name. */
5498 full_name = (char *)xmalloc (100);
5499 if (full_name && w32_to_x_font (&lf, full_name, 100))
5500 fontp->full_name = full_name;
5501 else
5503 /* If all else fails - just use the name we used to load it. */
5504 xfree (full_name);
5505 fontp->full_name = fontp->name;
5508 fontp->size = FONT_WIDTH (font);
5509 fontp->height = FONT_HEIGHT (font);
5511 /* The slot `encoding' specifies how to map a character
5512 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5513 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5514 (0:0x20..0x7F, 1:0xA0..0xFF,
5515 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5516 2:0xA020..0xFF7F). For the moment, we don't know which charset
5517 uses this font. So, we set information in fontp->encoding[1]
5518 which is never used by any charset. If mapping can't be
5519 decided, set FONT_ENCODING_NOT_DECIDED. */
5521 /* SJIS fonts need to be set to type 4, all others seem to work as
5522 type FONT_ENCODING_NOT_DECIDED. */
5523 encoding = strrchr (fontp->name, '-');
5524 if (encoding && stricmp (encoding+1, "sjis") == 0)
5525 fontp->encoding[1] = 4;
5526 else
5527 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5529 /* The following three values are set to 0 under W32, which is
5530 what they get set to if XGetFontProperty fails under X. */
5531 fontp->baseline_offset = 0;
5532 fontp->relative_compose = 0;
5533 fontp->default_ascent = 0;
5535 /* Set global flag fonts_changed_p to non-zero if the font loaded
5536 has a character with a smaller width than any other character
5537 before, or if the font loaded has a smalle>r height than any
5538 other font loaded before. If this happens, it will make a
5539 glyph matrix reallocation necessary. */
5540 fonts_changed_p = x_compute_min_glyph_bounds (f);
5541 UNBLOCK_INPUT;
5542 return fontp;
5546 /* Load font named FONTNAME of size SIZE for frame F, and return a
5547 pointer to the structure font_info while allocating it dynamically.
5548 If loading fails, return NULL. */
5549 struct font_info *
5550 w32_load_font (f,fontname,size)
5551 struct frame *f;
5552 char * fontname;
5553 int size;
5555 Lisp_Object bdf_fonts;
5556 struct font_info *retval = NULL;
5558 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5560 while (!retval && CONSP (bdf_fonts))
5562 char *bdf_name, *bdf_file;
5563 Lisp_Object bdf_pair;
5565 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5566 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5567 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5569 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5571 bdf_fonts = XCDR (bdf_fonts);
5574 if (retval)
5575 return retval;
5577 return w32_load_system_font(f, fontname, size);
5581 void
5582 w32_unload_font (dpyinfo, font)
5583 struct w32_display_info *dpyinfo;
5584 XFontStruct * font;
5586 if (font)
5588 if (font->bdf) w32_free_bdf_font (font->bdf);
5590 if (font->hfont) DeleteObject(font->hfont);
5591 xfree (font);
5595 /* The font conversion stuff between x and w32 */
5597 /* X font string is as follows (from faces.el)
5598 * (let ((- "[-?]")
5599 * (foundry "[^-]+")
5600 * (family "[^-]+")
5601 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5602 * (weight\? "\\([^-]*\\)") ; 1
5603 * (slant "\\([ior]\\)") ; 2
5604 * (slant\? "\\([^-]?\\)") ; 2
5605 * (swidth "\\([^-]*\\)") ; 3
5606 * (adstyle "[^-]*") ; 4
5607 * (pixelsize "[0-9]+")
5608 * (pointsize "[0-9][0-9]+")
5609 * (resx "[0-9][0-9]+")
5610 * (resy "[0-9][0-9]+")
5611 * (spacing "[cmp?*]")
5612 * (avgwidth "[0-9]+")
5613 * (registry "[^-]+")
5614 * (encoding "[^-]+")
5616 * (setq x-font-regexp
5617 * (concat "\\`\\*?[-?*]"
5618 * foundry - family - weight\? - slant\? - swidth - adstyle -
5619 * pixelsize - pointsize - resx - resy - spacing - registry -
5620 * encoding "[-?*]\\*?\\'"
5621 * ))
5622 * (setq x-font-regexp-head
5623 * (concat "\\`[-?*]" foundry - family - weight\? - slant\?
5624 * "\\([-*?]\\|\\'\\)"))
5625 * (setq x-font-regexp-slant (concat - slant -))
5626 * (setq x-font-regexp-weight (concat - weight -))
5627 * nil)
5630 #define FONT_START "[-?]"
5631 #define FONT_FOUNDRY "[^-]+"
5632 #define FONT_FAMILY "\\([^-]+\\)" /* 1 */
5633 #define FONT_WEIGHT "\\(bold\\|demibold\\|medium\\)" /* 2 */
5634 #define FONT_WEIGHT_Q "\\([^-]*\\)" /* 2 */
5635 #define FONT_SLANT "\\([ior]\\)" /* 3 */
5636 #define FONT_SLANT_Q "\\([^-]?\\)" /* 3 */
5637 #define FONT_SWIDTH "\\([^-]*\\)" /* 4 */
5638 #define FONT_ADSTYLE "[^-]*"
5639 #define FONT_PIXELSIZE "[^-]*"
5640 #define FONT_POINTSIZE "\\([0-9][0-9]+\\|\\*\\)" /* 5 */
5641 #define FONT_RESX "[0-9][0-9]+"
5642 #define FONT_RESY "[0-9][0-9]+"
5643 #define FONT_SPACING "[cmp?*]"
5644 #define FONT_AVGWIDTH "[0-9]+"
5645 #define FONT_REGISTRY "[^-]+"
5646 #define FONT_ENCODING "[^-]+"
5648 #define FONT_REGEXP ("\\`\\*?[-?*]" \
5649 FONT_FOUNDRY "-" \
5650 FONT_FAMILY "-" \
5651 FONT_WEIGHT_Q "-" \
5652 FONT_SLANT_Q "-" \
5653 FONT_SWIDTH "-" \
5654 FONT_ADSTYLE "-" \
5655 FONT_PIXELSIZE "-" \
5656 FONT_POINTSIZE "-" \
5657 "[-?*]\\|\\'")
5659 #define FONT_REGEXP_HEAD ("\\`[-?*]" \
5660 FONT_FOUNDRY "-" \
5661 FONT_FAMILY "-" \
5662 FONT_WEIGHT_Q "-" \
5663 FONT_SLANT_Q \
5664 "\\([-*?]\\|\\'\\)")
5666 #define FONT_REGEXP_SLANT "-" FONT_SLANT "-"
5667 #define FONT_REGEXP_WEIGHT "-" FONT_WEIGHT "-"
5669 LONG
5670 x_to_w32_weight (lpw)
5671 char * lpw;
5673 if (!lpw) return (FW_DONTCARE);
5675 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5676 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5677 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5678 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5679 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5680 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5681 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5682 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5683 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5684 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5685 else
5686 return FW_DONTCARE;
5690 char *
5691 w32_to_x_weight (fnweight)
5692 int fnweight;
5694 if (fnweight >= FW_HEAVY) return "heavy";
5695 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5696 if (fnweight >= FW_BOLD) return "bold";
5697 if (fnweight >= FW_SEMIBOLD) return "demibold";
5698 if (fnweight >= FW_MEDIUM) return "medium";
5699 if (fnweight >= FW_NORMAL) return "normal";
5700 if (fnweight >= FW_LIGHT) return "light";
5701 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5702 if (fnweight >= FW_THIN) return "thin";
5703 else
5704 return "*";
5707 LONG
5708 x_to_w32_charset (lpcs)
5709 char * lpcs;
5711 Lisp_Object rest;
5713 /* Look through w32-charset-info-alist for the character set.
5714 Format of each entry is
5715 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5717 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5719 Lisp_Object this_entry = XCAR (rest);
5720 char * x_charset = XSTRING (XCAR (this_entry))->data;
5722 if (strnicmp (lpcs, x_charset, strlen(x_charset)) == 0)
5724 Lisp_Object w32_charset = XCAR (XCDR (this_entry));
5725 // Translate Lisp symbol to number.
5726 if (w32_charset == Qw32_charset_ansi)
5727 return ANSI_CHARSET;
5728 if (w32_charset == Qw32_charset_symbol)
5729 return SYMBOL_CHARSET;
5730 if (w32_charset == Qw32_charset_shiftjis)
5731 return SHIFTJIS_CHARSET;
5732 if (w32_charset == Qw32_charset_hangul)
5733 return HANGEUL_CHARSET;
5734 if (w32_charset == Qw32_charset_chinesebig5)
5735 return CHINESEBIG5_CHARSET;
5736 if (w32_charset == Qw32_charset_gb2312)
5737 return GB2312_CHARSET;
5738 if (w32_charset == Qw32_charset_oem)
5739 return OEM_CHARSET;
5740 #ifdef JOHAB_CHARSET
5741 if (w32_charset == Qw32_charset_johab)
5742 return JOHAB_CHARSET;
5743 if (w32_charset == Qw32_charset_easteurope)
5744 return EASTEUROPE_CHARSET;
5745 if (w32_charset == Qw32_charset_turkish)
5746 return TURKISH_CHARSET;
5747 if (w32_charset == Qw32_charset_baltic)
5748 return BALTIC_CHARSET;
5749 if (w32_charset == Qw32_charset_russian)
5750 return RUSSIAN_CHARSET;
5751 if (w32_charset == Qw32_charset_arabic)
5752 return ARABIC_CHARSET;
5753 if (w32_charset == Qw32_charset_greek)
5754 return GREEK_CHARSET;
5755 if (w32_charset == Qw32_charset_hebrew)
5756 return HEBREW_CHARSET;
5757 if (w32_charset == Qw32_charset_thai)
5758 return THAI_CHARSET;
5759 if (w32_charset == Qw32_charset_mac)
5760 return MAC_CHARSET;
5761 #endif /* JOHAB_CHARSET */
5762 #ifdef UNICODE_CHARSET
5763 if (w32_charset == Qw32_charset_unicode)
5764 return UNICODE_CHARSET;
5765 #endif
5769 return DEFAULT_CHARSET;
5773 char *
5774 w32_to_x_charset (fncharset)
5775 int fncharset;
5777 static char buf[16];
5779 /* NTEMACS_TODO: use w32-charset-info-alist. Multiple matches
5780 are possible, so this will require more than just a rewrite of
5781 this function. w32_to_x_font is the only user of this function,
5782 and that will require rewriting too, and its users. */
5783 switch (fncharset)
5785 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5786 case ANSI_CHARSET: return "iso8859-1";
5787 case DEFAULT_CHARSET: return "ascii-*";
5788 case SYMBOL_CHARSET: return "ms-symbol";
5789 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
5790 case HANGEUL_CHARSET: return "ksc5601.1987-*";
5791 case GB2312_CHARSET: return "gb2312-*";
5792 case CHINESEBIG5_CHARSET: return "big5-*";
5793 case OEM_CHARSET: return "ms-oem";
5795 /* More recent versions of Windows (95 and NT4.0) define more
5796 character sets. */
5797 #ifdef EASTEUROPE_CHARSET
5798 case EASTEUROPE_CHARSET: return "iso8859-2";
5799 case TURKISH_CHARSET: return "iso8859-9";
5800 case BALTIC_CHARSET: return "iso8859-4";
5802 /* W95 with international support but not IE4 often has the
5803 KOI8-R codepage but not ISO8859-5. */
5804 case RUSSIAN_CHARSET:
5805 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5806 return "koi8-r";
5807 else
5808 return "iso8859-5";
5809 case ARABIC_CHARSET: return "iso8859-6";
5810 case GREEK_CHARSET: return "iso8859-7";
5811 case HEBREW_CHARSET: return "iso8859-8";
5812 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5813 case THAI_CHARSET: return "tis620-*";
5814 case MAC_CHARSET: return "mac-*";
5815 case JOHAB_CHARSET: return "ksc5601.1992-*";
5817 #endif
5819 #ifdef UNICODE_CHARSET
5820 case UNICODE_CHARSET: return "iso10646-unicode";
5821 #endif
5823 /* Encode numerical value of unknown charset. */
5824 sprintf (buf, "*-#%u", fncharset);
5825 return buf;
5829 /* Get the Windows codepage corresponding to the specified font. The
5830 charset info in the font name is used to look up
5831 w32-charset-to-codepage-alist. */
5832 int
5833 w32_codepage_for_font (char *fontname)
5835 Lisp_Object codepage;
5836 char charset_str[20], *charset, *end;
5838 /* Extract charset part of font string. */
5839 if (sscanf (fontname,
5840 "-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%19s",
5841 charset_str) == EOF)
5842 return CP_DEFAULT;
5844 /* Remove leading "*-". */
5845 if (strncmp ("*-", charset_str, 2) == 0)
5846 charset = charset_str + 2;
5847 else
5848 charset = charset_str;
5850 /* Stop match at wildcard (including preceding '-'). */
5851 if (end = strchr (charset, '*'))
5853 if (end > charset && *(end-1) == '-')
5854 end--;
5855 *end = '\0';
5858 codepage = Fcdr (Fcdr (Fassoc (build_string(charset),
5859 Vw32_charset_info_alist)));
5860 if (INTEGERP (codepage))
5861 return XINT (codepage);
5862 else
5863 return CP_DEFAULT;
5867 BOOL
5868 w32_to_x_font (lplogfont, lpxstr, len)
5869 LOGFONT * lplogfont;
5870 char * lpxstr;
5871 int len;
5873 char* fonttype;
5874 char *fontname;
5875 char height_pixels[8];
5876 char height_dpi[8];
5877 char width_pixels[8];
5878 char *fontname_dash;
5879 int display_resy = one_w32_display_info.resy;
5880 int display_resx = one_w32_display_info.resx;
5881 int bufsz;
5882 struct coding_system coding;
5884 if (!lpxstr) abort ();
5886 if (!lplogfont)
5887 return FALSE;
5889 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5890 fonttype = "raster";
5891 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5892 fonttype = "outline";
5893 else
5894 fonttype = "unknown";
5896 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5897 &coding);
5898 coding.src_multibyte = 0;
5899 coding.dst_multibyte = 1;
5900 coding.mode |= CODING_MODE_LAST_BLOCK;
5901 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5903 fontname = alloca(sizeof(*fontname) * bufsz);
5904 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5905 strlen(lplogfont->lfFaceName), bufsz - 1);
5906 *(fontname + coding.produced) = '\0';
5908 /* Replace dashes with underscores so the dashes are not
5909 misinterpreted. */
5910 fontname_dash = fontname;
5911 while (fontname_dash = strchr (fontname_dash, '-'))
5912 *fontname_dash = '_';
5914 if (lplogfont->lfHeight)
5916 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5917 sprintf (height_dpi, "%u",
5918 abs (lplogfont->lfHeight) * 720 / display_resy);
5920 else
5922 strcpy (height_pixels, "*");
5923 strcpy (height_dpi, "*");
5925 if (lplogfont->lfWidth)
5926 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5927 else
5928 strcpy (width_pixels, "*");
5930 _snprintf (lpxstr, len - 1,
5931 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5932 fonttype, /* foundry */
5933 fontname, /* family */
5934 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5935 lplogfont->lfItalic?'i':'r', /* slant */
5936 /* setwidth name */
5937 /* add style name */
5938 height_pixels, /* pixel size */
5939 height_dpi, /* point size */
5940 display_resx, /* resx */
5941 display_resy, /* resy */
5942 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5943 ? 'p' : 'c', /* spacing */
5944 width_pixels, /* avg width */
5945 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5946 and encoding*/
5949 lpxstr[len - 1] = 0; /* just to be sure */
5950 return (TRUE);
5953 BOOL
5954 x_to_w32_font (lpxstr, lplogfont)
5955 char * lpxstr;
5956 LOGFONT * lplogfont;
5958 struct coding_system coding;
5960 if (!lplogfont) return (FALSE);
5962 memset (lplogfont, 0, sizeof (*lplogfont));
5964 /* Set default value for each field. */
5965 #if 1
5966 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5967 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5968 lplogfont->lfQuality = DEFAULT_QUALITY;
5969 #else
5970 /* go for maximum quality */
5971 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5972 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5973 lplogfont->lfQuality = PROOF_QUALITY;
5974 #endif
5976 lplogfont->lfCharSet = DEFAULT_CHARSET;
5977 lplogfont->lfWeight = FW_DONTCARE;
5978 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5980 if (!lpxstr)
5981 return FALSE;
5983 /* Provide a simple escape mechanism for specifying Windows font names
5984 * directly -- if font spec does not beginning with '-', assume this
5985 * format:
5986 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5989 if (*lpxstr == '-')
5991 int fields, tem;
5992 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5993 width[10], resy[10], remainder[20];
5994 char * encoding;
5995 int dpi = one_w32_display_info.height_in;
5997 fields = sscanf (lpxstr,
5998 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5999 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6000 if (fields == EOF) return (FALSE);
6002 /* If wildcards cover more than one field, we don't know which
6003 field is which, so don't fill any in. */
6005 if (fields < 9)
6006 fields = 0;
6008 if (fields > 0 && name[0] != '*')
6010 int bufsize;
6011 unsigned char *buf;
6013 setup_coding_system
6014 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
6015 coding.src_multibyte = 1;
6016 coding.dst_multibyte = 1;
6017 bufsize = encoding_buffer_size (&coding, strlen (name));
6018 buf = (unsigned char *) alloca (bufsize);
6019 coding.mode |= CODING_MODE_LAST_BLOCK;
6020 encode_coding (&coding, name, buf, strlen (name), bufsize);
6021 if (coding.produced >= LF_FACESIZE)
6022 coding.produced = LF_FACESIZE - 1;
6023 buf[coding.produced] = 0;
6024 strcpy (lplogfont->lfFaceName, buf);
6026 else
6028 lplogfont->lfFaceName[0] = '\0';
6031 fields--;
6033 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6035 fields--;
6037 if (!NILP (Vw32_enable_synthesized_fonts))
6038 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6040 fields--;
6042 if (fields > 0 && pixels[0] != '*')
6043 lplogfont->lfHeight = atoi (pixels);
6045 fields--;
6046 fields--;
6047 if (fields > 0 && resy[0] != '*')
6049 tem = atoi (resy);
6050 if (tem > 0) dpi = tem;
6053 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6054 lplogfont->lfHeight = atoi (height) * dpi / 720;
6056 if (fields > 0)
6057 lplogfont->lfPitchAndFamily =
6058 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6060 fields--;
6062 if (fields > 0 && width[0] != '*')
6063 lplogfont->lfWidth = atoi (width) / 10;
6065 fields--;
6067 /* Strip the trailing '-' if present. (it shouldn't be, as it
6068 fails the test against xlfd-tight-regexp in fontset.el). */
6070 int len = strlen (remainder);
6071 if (len > 0 && remainder[len-1] == '-')
6072 remainder[len-1] = 0;
6074 encoding = remainder;
6075 if (strncmp (encoding, "*-", 2) == 0)
6076 encoding += 2;
6077 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
6079 else
6081 int fields;
6082 char name[100], height[10], width[10], weight[20];
6084 fields = sscanf (lpxstr,
6085 "%99[^:]:%9[^:]:%9[^:]:%19s",
6086 name, height, width, weight);
6088 if (fields == EOF) return (FALSE);
6090 if (fields > 0)
6092 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6093 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6095 else
6097 lplogfont->lfFaceName[0] = 0;
6100 fields--;
6102 if (fields > 0)
6103 lplogfont->lfHeight = atoi (height);
6105 fields--;
6107 if (fields > 0)
6108 lplogfont->lfWidth = atoi (width);
6110 fields--;
6112 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6115 /* This makes TrueType fonts work better. */
6116 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6118 return (TRUE);
6121 /* Strip the pixel height and point height from the given xlfd, and
6122 return the pixel height. If no pixel height is specified, calculate
6123 one from the point height, or if that isn't defined either, return
6124 0 (which usually signifies a scalable font).
6126 int xlfd_strip_height (char *fontname)
6128 int pixel_height, point_height, dpi, field_number;
6129 char *read_from, *write_to;
6131 xassert (fontname);
6133 pixel_height = field_number = 0;
6134 write_to = NULL;
6136 /* Look for height fields. */
6137 for (read_from = fontname; *read_from; read_from++)
6139 if (*read_from == '-')
6141 field_number++;
6142 if (field_number == 7) /* Pixel height. */
6144 read_from++;
6145 write_to = read_from;
6147 /* Find end of field. */
6148 for (;*read_from && *read_from != '-'; read_from++)
6151 /* Split the fontname at end of field. */
6152 if (*read_from)
6154 *read_from = '\0';
6155 read_from++;
6157 pixel_height = atoi (write_to);
6158 /* Blank out field. */
6159 if (read_from > write_to)
6161 *write_to = '-';
6162 write_to++;
6164 /* If the pixel height field is at the end (partial xfld),
6165 return now. */
6166 else
6167 return pixel_height;
6169 /* If we got a pixel height, the point height can be
6170 ignored. Just blank it out and break now. */
6171 if (pixel_height)
6173 /* Find end of point size field. */
6174 for (; *read_from && *read_from != '-'; read_from++)
6177 if (*read_from)
6178 read_from++;
6180 /* Blank out the point size field. */
6181 if (read_from > write_to)
6183 *write_to = '-';
6184 write_to++;
6186 else
6187 return pixel_height;
6189 break;
6191 /* If the point height is already blank, break now. */
6192 if (*read_from == '-')
6194 read_from++;
6195 break;
6198 else if (field_number == 8)
6200 /* If we didn't get a pixel height, try to get the point
6201 height and convert that. */
6202 int point_size;
6203 char *point_size_start = read_from++;
6205 /* Find end of field. */
6206 for (; *read_from && *read_from != '-'; read_from++)
6209 if (*read_from)
6211 *read_from = '\0';
6212 read_from++;
6215 point_size = atoi (point_size_start);
6217 /* Convert to pixel height. */
6218 pixel_height = point_size
6219 * one_w32_display_info.height_in / 720;
6221 /* Blank out this field and break. */
6222 *write_to = '-';
6223 write_to++;
6224 break;
6229 /* Shift the rest of the font spec into place. */
6230 if (write_to && read_from > write_to)
6232 for (; *read_from; read_from++, write_to++)
6233 *write_to = *read_from;
6234 *write_to = '\0';
6237 return pixel_height;
6240 /* Assume parameter 1 is fully qualified, no wildcards. */
6241 BOOL
6242 w32_font_match (fontname, pattern)
6243 char * fontname;
6244 char * pattern;
6246 char *regex = alloca (strlen (pattern) * 2);
6247 char *font_name_copy = alloca (strlen (fontname) + 1);
6248 char *ptr;
6250 /* Copy fontname so we can modify it during comparison. */
6251 strcpy (font_name_copy, fontname);
6253 ptr = regex;
6254 *ptr++ = '^';
6256 /* Turn pattern into a regexp and do a regexp match. */
6257 for (; *pattern; pattern++)
6259 if (*pattern == '?')
6260 *ptr++ = '.';
6261 else if (*pattern == '*')
6263 *ptr++ = '.';
6264 *ptr++ = '*';
6266 else
6267 *ptr++ = *pattern;
6269 *ptr = '$';
6270 *(ptr + 1) = '\0';
6272 /* Strip out font heights and compare them seperately, since
6273 rounding error can cause mismatches. This also allows a
6274 comparison between a font that declares only a pixel height and a
6275 pattern that declares the point height.
6278 int font_height, pattern_height;
6280 font_height = xlfd_strip_height (font_name_copy);
6281 pattern_height = xlfd_strip_height (regex);
6283 /* Compare now, and don't bother doing expensive regexp matching
6284 if the heights differ. */
6285 if (font_height && pattern_height && (font_height != pattern_height))
6286 return FALSE;
6289 return (fast_c_string_match_ignore_case (build_string (regex),
6290 font_name_copy) >= 0);
6293 /* Callback functions, and a structure holding info they need, for
6294 listing system fonts on W32. We need one set of functions to do the
6295 job properly, but these don't work on NT 3.51 and earlier, so we
6296 have a second set which don't handle character sets properly to
6297 fall back on.
6299 In both cases, there are two passes made. The first pass gets one
6300 font from each family, the second pass lists all the fonts from
6301 each family. */
6303 typedef struct enumfont_t
6305 HDC hdc;
6306 int numFonts;
6307 LOGFONT logfont;
6308 XFontStruct *size_ref;
6309 Lisp_Object *pattern;
6310 Lisp_Object *tail;
6311 } enumfont_t;
6313 int CALLBACK
6314 enum_font_cb2 (lplf, lptm, FontType, lpef)
6315 ENUMLOGFONT * lplf;
6316 NEWTEXTMETRIC * lptm;
6317 int FontType;
6318 enumfont_t * lpef;
6320 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6321 return (1);
6323 /* Check that the character set matches if it was specified */
6324 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6325 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6326 return (1);
6329 char buf[100];
6330 Lisp_Object width = Qnil;
6332 /* Truetype fonts do not report their true metrics until loaded */
6333 if (FontType != RASTER_FONTTYPE)
6335 if (!NILP (*(lpef->pattern)))
6337 /* Scalable fonts are as big as you want them to be. */
6338 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6339 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6340 width = make_number (lpef->logfont.lfWidth);
6342 else
6344 lplf->elfLogFont.lfHeight = 0;
6345 lplf->elfLogFont.lfWidth = 0;
6349 /* Make sure the height used here is the same as everywhere
6350 else (ie character height, not cell height). */
6351 if (lplf->elfLogFont.lfHeight > 0)
6353 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6354 if (FontType == RASTER_FONTTYPE)
6355 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6356 else
6357 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6360 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
6361 return (0);
6363 if (NILP (*(lpef->pattern))
6364 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6366 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6367 lpef->tail = &(XCDR (*lpef->tail));
6368 lpef->numFonts++;
6372 return (1);
6375 int CALLBACK
6376 enum_font_cb1 (lplf, lptm, FontType, lpef)
6377 ENUMLOGFONT * lplf;
6378 NEWTEXTMETRIC * lptm;
6379 int FontType;
6380 enumfont_t * lpef;
6382 return EnumFontFamilies (lpef->hdc,
6383 lplf->elfLogFont.lfFaceName,
6384 (FONTENUMPROC) enum_font_cb2,
6385 (LPARAM) lpef);
6389 int CALLBACK
6390 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6391 ENUMLOGFONTEX * lplf;
6392 NEWTEXTMETRICEX * lptm;
6393 int font_type;
6394 enumfont_t * lpef;
6396 /* We are not interested in the extra info we get back from the 'Ex
6397 version - only the fact that we get character set variations
6398 enumerated seperately. */
6399 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6400 font_type, lpef);
6403 int CALLBACK
6404 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6405 ENUMLOGFONTEX * lplf;
6406 NEWTEXTMETRICEX * lptm;
6407 int font_type;
6408 enumfont_t * lpef;
6410 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6411 FARPROC enum_font_families_ex
6412 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6413 /* We don't really expect EnumFontFamiliesEx to disappear once we
6414 get here, so don't bother handling it gracefully. */
6415 if (enum_font_families_ex == NULL)
6416 error ("gdi32.dll has disappeared!");
6417 return enum_font_families_ex (lpef->hdc,
6418 &lplf->elfLogFont,
6419 (FONTENUMPROC) enum_fontex_cb2,
6420 (LPARAM) lpef, 0);
6423 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6424 and xterm.c in Emacs 20.3) */
6426 Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6428 char *fontname, *ptnstr;
6429 Lisp_Object list, tem, newlist = Qnil;
6430 int n_fonts = 0;
6432 list = Vw32_bdf_filename_alist;
6433 ptnstr = XSTRING (pattern)->data;
6435 for ( ; CONSP (list); list = XCDR (list))
6437 tem = XCAR (list);
6438 if (CONSP (tem))
6439 fontname = XSTRING (XCAR (tem))->data;
6440 else if (STRINGP (tem))
6441 fontname = XSTRING (tem)->data;
6442 else
6443 continue;
6445 if (w32_font_match (fontname, ptnstr))
6447 newlist = Fcons (XCAR (tem), newlist);
6448 n_fonts++;
6449 if (n_fonts >= max_names)
6450 break;
6454 return newlist;
6457 Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6458 int size, int max_names);
6460 /* Return a list of names of available fonts matching PATTERN on frame
6461 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6462 to be listed. Frame F NULL means we have not yet created any
6463 frame, which means we can't get proper size info, as we don't have
6464 a device context to use for GetTextMetrics.
6465 MAXNAMES sets a limit on how many fonts to match. */
6467 Lisp_Object
6468 w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6470 Lisp_Object patterns, key = Qnil, tem, tpat;
6471 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6472 struct w32_display_info *dpyinfo = &one_w32_display_info;
6473 int n_fonts = 0;
6475 patterns = Fassoc (pattern, Valternate_fontname_alist);
6476 if (NILP (patterns))
6477 patterns = Fcons (pattern, Qnil);
6479 for (; CONSP (patterns); patterns = XCDR (patterns))
6481 enumfont_t ef;
6483 tpat = XCAR (patterns);
6485 /* See if we cached the result for this particular query.
6486 The cache is an alist of the form:
6487 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6489 if (tem = XCDR (dpyinfo->name_list_element),
6490 !NILP (list = Fassoc (tpat, tem)))
6492 list = Fcdr_safe (list);
6493 /* We have a cached list. Don't have to get the list again. */
6494 goto label_cached;
6497 BLOCK_INPUT;
6498 /* At first, put PATTERN in the cache. */
6499 list = Qnil;
6500 ef.pattern = &tpat;
6501 ef.tail = &list;
6502 ef.numFonts = 0;
6504 /* Use EnumFontFamiliesEx where it is available, as it knows
6505 about character sets. Fall back to EnumFontFamilies for
6506 older versions of NT that don't support the 'Ex function. */
6507 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
6508 NULL, &ef.logfont);
6510 LOGFONT font_match_pattern;
6511 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6512 FARPROC enum_font_families_ex
6513 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6515 /* We do our own pattern matching so we can handle wildcards. */
6516 font_match_pattern.lfFaceName[0] = 0;
6517 font_match_pattern.lfPitchAndFamily = 0;
6518 /* We can use the charset, because if it is a wildcard it will
6519 be DEFAULT_CHARSET anyway. */
6520 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6522 ef.hdc = GetDC (dpyinfo->root_window);
6524 if (enum_font_families_ex)
6525 enum_font_families_ex (ef.hdc,
6526 &font_match_pattern,
6527 (FONTENUMPROC) enum_fontex_cb1,
6528 (LPARAM) &ef, 0);
6529 else
6530 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6531 (LPARAM)&ef);
6533 ReleaseDC (dpyinfo->root_window, ef.hdc);
6536 UNBLOCK_INPUT;
6538 /* Make a list of the fonts we got back.
6539 Store that in the font cache for the display. */
6540 XCDR (dpyinfo->name_list_element)
6541 = Fcons (Fcons (tpat, list),
6542 XCDR (dpyinfo->name_list_element));
6544 label_cached:
6545 if (NILP (list)) continue; /* Try the remaining alternatives. */
6547 newlist = second_best = Qnil;
6549 /* Make a list of the fonts that have the right width. */
6550 for (; CONSP (list); list = XCDR (list))
6552 int found_size;
6553 tem = XCAR (list);
6555 if (!CONSP (tem))
6556 continue;
6557 if (NILP (XCAR (tem)))
6558 continue;
6559 if (!size)
6561 newlist = Fcons (XCAR (tem), newlist);
6562 n_fonts++;
6563 if (n_fonts >= maxnames)
6564 break;
6565 else
6566 continue;
6568 if (!INTEGERP (XCDR (tem)))
6570 /* Since we don't yet know the size of the font, we must
6571 load it and try GetTextMetrics. */
6572 W32FontStruct thisinfo;
6573 LOGFONT lf;
6574 HDC hdc;
6575 HANDLE oldobj;
6577 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6578 continue;
6580 BLOCK_INPUT;
6581 thisinfo.bdf = NULL;
6582 thisinfo.hfont = CreateFontIndirect (&lf);
6583 if (thisinfo.hfont == NULL)
6584 continue;
6586 hdc = GetDC (dpyinfo->root_window);
6587 oldobj = SelectObject (hdc, thisinfo.hfont);
6588 if (GetTextMetrics (hdc, &thisinfo.tm))
6589 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
6590 else
6591 XCDR (tem) = make_number (0);
6592 SelectObject (hdc, oldobj);
6593 ReleaseDC (dpyinfo->root_window, hdc);
6594 DeleteObject(thisinfo.hfont);
6595 UNBLOCK_INPUT;
6597 found_size = XINT (XCDR (tem));
6598 if (found_size == size)
6600 newlist = Fcons (XCAR (tem), newlist);
6601 n_fonts++;
6602 if (n_fonts >= maxnames)
6603 break;
6605 /* keep track of the closest matching size in case
6606 no exact match is found. */
6607 else if (found_size > 0)
6609 if (NILP (second_best))
6610 second_best = tem;
6612 else if (found_size < size)
6614 if (XINT (XCDR (second_best)) > size
6615 || XINT (XCDR (second_best)) < found_size)
6616 second_best = tem;
6618 else
6620 if (XINT (XCDR (second_best)) > size
6621 && XINT (XCDR (second_best)) >
6622 found_size)
6623 second_best = tem;
6628 if (!NILP (newlist))
6629 break;
6630 else if (!NILP (second_best))
6632 newlist = Fcons (XCAR (second_best), Qnil);
6633 break;
6637 /* Include any bdf fonts. */
6638 if (n_fonts < maxnames)
6640 Lisp_Object combined[2];
6641 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6642 combined[1] = newlist;
6643 newlist = Fnconc(2, combined);
6646 /* If we can't find a font that matches, check if Windows would be
6647 able to synthesize it from a different style. */
6648 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
6649 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6651 return newlist;
6654 Lisp_Object
6655 w32_list_synthesized_fonts (f, pattern, size, max_names)
6656 FRAME_PTR f;
6657 Lisp_Object pattern;
6658 int size;
6659 int max_names;
6661 int fields;
6662 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6663 char style[20], slant;
6664 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6666 full_pattn = XSTRING (pattern)->data;
6668 pattn_part2 = alloca (XSTRING (pattern)->size);
6669 /* Allow some space for wildcard expansion. */
6670 new_pattn = alloca (XSTRING (pattern)->size + 100);
6672 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6673 foundary, family, style, &slant, pattn_part2);
6674 if (fields == EOF || fields < 5)
6675 return Qnil;
6677 /* If the style and slant are wildcards already there is no point
6678 checking again (and we don't want to keep recursing). */
6679 if (*style == '*' && slant == '*')
6680 return Qnil;
6682 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6684 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6686 for ( ; CONSP (matches); matches = XCDR (matches))
6688 tem = XCAR (matches);
6689 if (!STRINGP (tem))
6690 continue;
6692 full_pattn = XSTRING (tem)->data;
6693 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6694 foundary, family, pattn_part2);
6695 if (fields == EOF || fields < 3)
6696 continue;
6698 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6699 slant, pattn_part2);
6701 synthed_matches = Fcons (build_string (new_pattn),
6702 synthed_matches);
6705 return synthed_matches;
6709 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6710 struct font_info *
6711 w32_get_font_info (f, font_idx)
6712 FRAME_PTR f;
6713 int font_idx;
6715 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6719 struct font_info*
6720 w32_query_font (struct frame *f, char *fontname)
6722 int i;
6723 struct font_info *pfi;
6725 pfi = FRAME_W32_FONT_TABLE (f);
6727 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6729 if (strcmp(pfi->name, fontname) == 0) return pfi;
6732 return NULL;
6735 /* Find a CCL program for a font specified by FONTP, and set the member
6736 `encoder' of the structure. */
6738 void
6739 w32_find_ccl_program (fontp)
6740 struct font_info *fontp;
6742 Lisp_Object list, elt;
6744 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
6746 elt = XCAR (list);
6747 if (CONSP (elt)
6748 && STRINGP (XCAR (elt))
6749 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
6750 >= 0))
6751 break;
6753 if (! NILP (list))
6755 struct ccl_program *ccl
6756 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6758 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
6759 xfree (ccl);
6760 else
6761 fontp->font_encoder = ccl;
6766 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6767 1, 1, 0,
6768 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6769 w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6770 will not be included in the list. DIR may be a list of directories.")
6771 (directory)
6772 Lisp_Object directory;
6774 Lisp_Object list = Qnil;
6775 struct gcpro gcpro1, gcpro2;
6777 if (!CONSP (directory))
6778 return w32_find_bdf_fonts_in_dir (directory);
6780 for ( ; CONSP (directory); directory = XCDR (directory))
6782 Lisp_Object pair[2];
6783 pair[0] = list;
6784 pair[1] = Qnil;
6785 GCPRO2 (directory, list);
6786 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6787 list = Fnconc( 2, pair );
6788 UNGCPRO;
6790 return list;
6793 /* Find BDF files in a specified directory. (use GCPRO when calling,
6794 as this calls lisp to get a directory listing). */
6795 Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6797 Lisp_Object filelist, list = Qnil;
6798 char fontname[100];
6800 if (!STRINGP(directory))
6801 return Qnil;
6803 filelist = Fdirectory_files (directory, Qt,
6804 build_string (".*\\.[bB][dD][fF]"), Qt);
6806 for ( ; CONSP(filelist); filelist = XCDR (filelist))
6808 Lisp_Object filename = XCAR (filelist);
6809 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6810 store_in_alist (&list, build_string (fontname), filename);
6812 return list;
6816 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
6817 "Internal function called by `color-defined-p', which see.")
6818 (color, frame)
6819 Lisp_Object color, frame;
6821 XColor foo;
6822 FRAME_PTR f = check_x_frame (frame);
6824 CHECK_STRING (color, 1);
6826 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6827 return Qt;
6828 else
6829 return Qnil;
6832 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
6833 "Internal function called by `color-values', which see.")
6834 (color, frame)
6835 Lisp_Object color, frame;
6837 XColor foo;
6838 FRAME_PTR f = check_x_frame (frame);
6840 CHECK_STRING (color, 1);
6842 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6844 Lisp_Object rgb[3];
6846 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6847 | GetRValue (foo.pixel));
6848 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6849 | GetGValue (foo.pixel));
6850 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6851 | GetBValue (foo.pixel));
6852 return Flist (3, rgb);
6854 else
6855 return Qnil;
6858 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
6859 "Internal function called by `display-color-p', which see.")
6860 (display)
6861 Lisp_Object display;
6863 struct w32_display_info *dpyinfo = check_x_display_info (display);
6865 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6866 return Qnil;
6868 return Qt;
6871 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6872 0, 1, 0,
6873 "Return t if the X display supports shades of gray.\n\
6874 Note that color displays do support shades of gray.\n\
6875 The optional argument DISPLAY specifies which display to ask about.\n\
6876 DISPLAY should be either a frame or a display name (a string).\n\
6877 If omitted or nil, that stands for the selected frame's display.")
6878 (display)
6879 Lisp_Object display;
6881 struct w32_display_info *dpyinfo = check_x_display_info (display);
6883 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6884 return Qnil;
6886 return Qt;
6889 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6890 0, 1, 0,
6891 "Returns the width in pixels of the X display DISPLAY.\n\
6892 The optional argument DISPLAY specifies which display to ask about.\n\
6893 DISPLAY should be either a frame or a display name (a string).\n\
6894 If omitted or nil, that stands for the selected frame's display.")
6895 (display)
6896 Lisp_Object display;
6898 struct w32_display_info *dpyinfo = check_x_display_info (display);
6900 return make_number (dpyinfo->width);
6903 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6904 Sx_display_pixel_height, 0, 1, 0,
6905 "Returns the height in pixels of the X display DISPLAY.\n\
6906 The optional argument DISPLAY specifies which display to ask about.\n\
6907 DISPLAY should be either a frame or a display name (a string).\n\
6908 If omitted or nil, that stands for the selected frame's display.")
6909 (display)
6910 Lisp_Object display;
6912 struct w32_display_info *dpyinfo = check_x_display_info (display);
6914 return make_number (dpyinfo->height);
6917 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6918 0, 1, 0,
6919 "Returns the number of bitplanes of the display DISPLAY.\n\
6920 The optional argument DISPLAY specifies which display to ask about.\n\
6921 DISPLAY should be either a frame or a display name (a string).\n\
6922 If omitted or nil, that stands for the selected frame's display.")
6923 (display)
6924 Lisp_Object display;
6926 struct w32_display_info *dpyinfo = check_x_display_info (display);
6928 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6931 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6932 0, 1, 0,
6933 "Returns the number of color cells of the display DISPLAY.\n\
6934 The optional argument DISPLAY specifies which display to ask about.\n\
6935 DISPLAY should be either a frame or a display name (a string).\n\
6936 If omitted or nil, that stands for the selected frame's display.")
6937 (display)
6938 Lisp_Object display;
6940 struct w32_display_info *dpyinfo = check_x_display_info (display);
6941 HDC hdc;
6942 int cap;
6944 hdc = GetDC (dpyinfo->root_window);
6945 if (dpyinfo->has_palette)
6946 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6947 else
6948 cap = GetDeviceCaps (hdc,NUMCOLORS);
6950 ReleaseDC (dpyinfo->root_window, hdc);
6952 return make_number (cap);
6955 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6956 Sx_server_max_request_size,
6957 0, 1, 0,
6958 "Returns the maximum request size of the server of display DISPLAY.\n\
6959 The optional argument DISPLAY specifies which display to ask about.\n\
6960 DISPLAY should be either a frame or a display name (a string).\n\
6961 If omitted or nil, that stands for the selected frame's display.")
6962 (display)
6963 Lisp_Object display;
6965 struct w32_display_info *dpyinfo = check_x_display_info (display);
6967 return make_number (1);
6970 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
6971 "Returns the vendor ID string of the W32 system (Microsoft).\n\
6972 The optional argument DISPLAY specifies which display to ask about.\n\
6973 DISPLAY should be either a frame or a display name (a string).\n\
6974 If omitted or nil, that stands for the selected frame's display.")
6975 (display)
6976 Lisp_Object display;
6978 return build_string ("Microsoft Corp.");
6981 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6982 "Returns the version numbers of the server of display DISPLAY.\n\
6983 The value is a list of three integers: the major and minor\n\
6984 version numbers, and the vendor-specific release\n\
6985 number. See also the function `x-server-vendor'.\n\n\
6986 The optional argument DISPLAY specifies which display to ask about.\n\
6987 DISPLAY should be either a frame or a display name (a string).\n\
6988 If omitted or nil, that stands for the selected frame's display.")
6989 (display)
6990 Lisp_Object display;
6992 return Fcons (make_number (w32_major_version),
6993 Fcons (make_number (w32_minor_version), Qnil));
6996 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6997 "Returns the number of screens on the server of display DISPLAY.\n\
6998 The optional argument DISPLAY specifies which display to ask about.\n\
6999 DISPLAY should be either a frame or a display name (a string).\n\
7000 If omitted or nil, that stands for the selected frame's display.")
7001 (display)
7002 Lisp_Object display;
7004 return make_number (1);
7007 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
7008 "Returns the height in millimeters of the X display DISPLAY.\n\
7009 The optional argument DISPLAY specifies which display to ask about.\n\
7010 DISPLAY should be either a frame or a display name (a string).\n\
7011 If omitted or nil, that stands for the selected frame's display.")
7012 (display)
7013 Lisp_Object display;
7015 struct w32_display_info *dpyinfo = check_x_display_info (display);
7016 HDC hdc;
7017 int cap;
7019 hdc = GetDC (dpyinfo->root_window);
7021 cap = GetDeviceCaps (hdc, VERTSIZE);
7023 ReleaseDC (dpyinfo->root_window, hdc);
7025 return make_number (cap);
7028 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7029 "Returns the width in millimeters of the X display DISPLAY.\n\
7030 The optional argument DISPLAY specifies which display to ask about.\n\
7031 DISPLAY should be either a frame or a display name (a string).\n\
7032 If omitted or nil, that stands for the selected frame's display.")
7033 (display)
7034 Lisp_Object display;
7036 struct w32_display_info *dpyinfo = check_x_display_info (display);
7038 HDC hdc;
7039 int cap;
7041 hdc = GetDC (dpyinfo->root_window);
7043 cap = GetDeviceCaps (hdc, HORZSIZE);
7045 ReleaseDC (dpyinfo->root_window, hdc);
7047 return make_number (cap);
7050 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7051 Sx_display_backing_store, 0, 1, 0,
7052 "Returns an indication of whether display DISPLAY does backing store.\n\
7053 The value may be `always', `when-mapped', or `not-useful'.\n\
7054 The optional argument DISPLAY specifies which display to ask about.\n\
7055 DISPLAY should be either a frame or a display name (a string).\n\
7056 If omitted or nil, that stands for the selected frame's display.")
7057 (display)
7058 Lisp_Object display;
7060 return intern ("not-useful");
7063 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7064 Sx_display_visual_class, 0, 1, 0,
7065 "Returns the visual class of the display DISPLAY.\n\
7066 The value is one of the symbols `static-gray', `gray-scale',\n\
7067 `static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7068 The optional argument DISPLAY specifies which display to ask about.\n\
7069 DISPLAY should be either a frame or a display name (a string).\n\
7070 If omitted or nil, that stands for the selected frame's display.")
7071 (display)
7072 Lisp_Object display;
7074 struct w32_display_info *dpyinfo = check_x_display_info (display);
7076 #if 0
7077 switch (dpyinfo->visual->class)
7079 case StaticGray: return (intern ("static-gray"));
7080 case GrayScale: return (intern ("gray-scale"));
7081 case StaticColor: return (intern ("static-color"));
7082 case PseudoColor: return (intern ("pseudo-color"));
7083 case TrueColor: return (intern ("true-color"));
7084 case DirectColor: return (intern ("direct-color"));
7085 default:
7086 error ("Display has an unknown visual class");
7088 #endif
7090 error ("Display has an unknown visual class");
7093 DEFUN ("x-display-save-under", Fx_display_save_under,
7094 Sx_display_save_under, 0, 1, 0,
7095 "Returns t if the display DISPLAY supports the save-under feature.\n\
7096 The optional argument DISPLAY specifies which display to ask about.\n\
7097 DISPLAY should be either a frame or a display name (a string).\n\
7098 If omitted or nil, that stands for the selected frame's display.")
7099 (display)
7100 Lisp_Object display;
7102 return Qnil;
7106 x_pixel_width (f)
7107 register struct frame *f;
7109 return PIXEL_WIDTH (f);
7113 x_pixel_height (f)
7114 register struct frame *f;
7116 return PIXEL_HEIGHT (f);
7120 x_char_width (f)
7121 register struct frame *f;
7123 return FONT_WIDTH (f->output_data.w32->font);
7127 x_char_height (f)
7128 register struct frame *f;
7130 return f->output_data.w32->line_height;
7134 x_screen_planes (f)
7135 register struct frame *f;
7137 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7140 /* Return the display structure for the display named NAME.
7141 Open a new connection if necessary. */
7143 struct w32_display_info *
7144 x_display_info_for_name (name)
7145 Lisp_Object name;
7147 Lisp_Object names;
7148 struct w32_display_info *dpyinfo;
7150 CHECK_STRING (name, 0);
7152 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7153 dpyinfo;
7154 dpyinfo = dpyinfo->next, names = XCDR (names))
7156 Lisp_Object tem;
7157 tem = Fstring_equal (XCAR (XCAR (names)), name);
7158 if (!NILP (tem))
7159 return dpyinfo;
7162 /* Use this general default value to start with. */
7163 Vx_resource_name = Vinvocation_name;
7165 validate_x_resource_name ();
7167 dpyinfo = w32_term_init (name, (unsigned char *)0,
7168 (char *) XSTRING (Vx_resource_name)->data);
7170 if (dpyinfo == 0)
7171 error ("Cannot connect to server %s", XSTRING (name)->data);
7173 w32_in_use = 1;
7174 XSETFASTINT (Vwindow_system_version, 3);
7176 return dpyinfo;
7179 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7180 1, 3, 0, "Open a connection to a server.\n\
7181 DISPLAY is the name of the display to connect to.\n\
7182 Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7183 If the optional third arg MUST-SUCCEED is non-nil,\n\
7184 terminate Emacs if we can't open the connection.")
7185 (display, xrm_string, must_succeed)
7186 Lisp_Object display, xrm_string, must_succeed;
7188 unsigned char *xrm_option;
7189 struct w32_display_info *dpyinfo;
7191 CHECK_STRING (display, 0);
7192 if (! NILP (xrm_string))
7193 CHECK_STRING (xrm_string, 1);
7195 if (! EQ (Vwindow_system, intern ("w32")))
7196 error ("Not using Microsoft Windows");
7198 /* Allow color mapping to be defined externally; first look in user's
7199 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7201 Lisp_Object color_file;
7202 struct gcpro gcpro1;
7204 color_file = build_string("~/rgb.txt");
7206 GCPRO1 (color_file);
7208 if (NILP (Ffile_readable_p (color_file)))
7209 color_file =
7210 Fexpand_file_name (build_string ("rgb.txt"),
7211 Fsymbol_value (intern ("data-directory")));
7213 Vw32_color_map = Fw32_load_color_file (color_file);
7215 UNGCPRO;
7217 if (NILP (Vw32_color_map))
7218 Vw32_color_map = Fw32_default_color_map ();
7220 if (! NILP (xrm_string))
7221 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7222 else
7223 xrm_option = (unsigned char *) 0;
7225 /* Use this general default value to start with. */
7226 /* First remove .exe suffix from invocation-name - it looks ugly. */
7228 char basename[ MAX_PATH ], *str;
7230 strcpy (basename, XSTRING (Vinvocation_name)->data);
7231 str = strrchr (basename, '.');
7232 if (str) *str = 0;
7233 Vinvocation_name = build_string (basename);
7235 Vx_resource_name = Vinvocation_name;
7237 validate_x_resource_name ();
7239 /* This is what opens the connection and sets x_current_display.
7240 This also initializes many symbols, such as those used for input. */
7241 dpyinfo = w32_term_init (display, xrm_option,
7242 (char *) XSTRING (Vx_resource_name)->data);
7244 if (dpyinfo == 0)
7246 if (!NILP (must_succeed))
7247 fatal ("Cannot connect to server %s.\n",
7248 XSTRING (display)->data);
7249 else
7250 error ("Cannot connect to server %s", XSTRING (display)->data);
7253 w32_in_use = 1;
7255 XSETFASTINT (Vwindow_system_version, 3);
7256 return Qnil;
7259 DEFUN ("x-close-connection", Fx_close_connection,
7260 Sx_close_connection, 1, 1, 0,
7261 "Close the connection to DISPLAY's server.\n\
7262 For DISPLAY, specify either a frame or a display name (a string).\n\
7263 If DISPLAY is nil, that stands for the selected frame's display.")
7264 (display)
7265 Lisp_Object display;
7267 struct w32_display_info *dpyinfo = check_x_display_info (display);
7268 int i;
7270 if (dpyinfo->reference_count > 0)
7271 error ("Display still has frames on it");
7273 BLOCK_INPUT;
7274 /* Free the fonts in the font table. */
7275 for (i = 0; i < dpyinfo->n_fonts; i++)
7276 if (dpyinfo->font_table[i].name)
7278 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7279 xfree (dpyinfo->font_table[i].full_name);
7280 xfree (dpyinfo->font_table[i].name);
7281 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7283 x_destroy_all_bitmaps (dpyinfo);
7285 x_delete_display (dpyinfo);
7286 UNBLOCK_INPUT;
7288 return Qnil;
7291 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7292 "Return the list of display names that Emacs has connections to.")
7295 Lisp_Object tail, result;
7297 result = Qnil;
7298 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7299 result = Fcons (XCAR (XCAR (tail)), result);
7301 return result;
7304 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7305 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7306 If ON is nil, allow buffering of requests.\n\
7307 This is a noop on W32 systems.\n\
7308 The optional second argument DISPLAY specifies which display to act on.\n\
7309 DISPLAY should be either a frame or a display name (a string).\n\
7310 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7311 (on, display)
7312 Lisp_Object display, on;
7314 return Qnil;
7319 /***********************************************************************
7320 Image types
7321 ***********************************************************************/
7323 /* Value is the number of elements of vector VECTOR. */
7325 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7327 /* List of supported image types. Use define_image_type to add new
7328 types. Use lookup_image_type to find a type for a given symbol. */
7330 static struct image_type *image_types;
7332 /* The symbol `image' which is the car of the lists used to represent
7333 images in Lisp. */
7335 extern Lisp_Object Qimage;
7337 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7339 Lisp_Object Qxbm;
7341 /* Keywords. */
7343 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7344 extern Lisp_Object QCdata;
7345 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7346 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
7347 Lisp_Object QCindex;
7349 /* Other symbols. */
7351 Lisp_Object Qlaplace;
7353 /* Time in seconds after which images should be removed from the cache
7354 if not displayed. */
7356 Lisp_Object Vimage_cache_eviction_delay;
7358 /* Function prototypes. */
7360 static void define_image_type P_ ((struct image_type *type));
7361 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7362 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7363 static void x_laplace P_ ((struct frame *, struct image *));
7364 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7365 Lisp_Object));
7368 /* Define a new image type from TYPE. This adds a copy of TYPE to
7369 image_types and adds the symbol *TYPE->type to Vimage_types. */
7371 static void
7372 define_image_type (type)
7373 struct image_type *type;
7375 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7376 The initialized data segment is read-only. */
7377 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7378 bcopy (type, p, sizeof *p);
7379 p->next = image_types;
7380 image_types = p;
7381 Vimage_types = Fcons (*p->type, Vimage_types);
7385 /* Look up image type SYMBOL, and return a pointer to its image_type
7386 structure. Value is null if SYMBOL is not a known image type. */
7388 static INLINE struct image_type *
7389 lookup_image_type (symbol)
7390 Lisp_Object symbol;
7392 struct image_type *type;
7394 for (type = image_types; type; type = type->next)
7395 if (EQ (symbol, *type->type))
7396 break;
7398 return type;
7402 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7403 valid image specification is a list whose car is the symbol
7404 `image', and whose rest is a property list. The property list must
7405 contain a value for key `:type'. That value must be the name of a
7406 supported image type. The rest of the property list depends on the
7407 image type. */
7410 valid_image_p (object)
7411 Lisp_Object object;
7413 int valid_p = 0;
7415 if (CONSP (object) && EQ (XCAR (object), Qimage))
7417 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7418 struct image_type *type = lookup_image_type (symbol);
7420 if (type)
7421 valid_p = type->valid_p (object);
7424 return valid_p;
7428 /* Log error message with format string FORMAT and argument ARG.
7429 Signaling an error, e.g. when an image cannot be loaded, is not a
7430 good idea because this would interrupt redisplay, and the error
7431 message display would lead to another redisplay. This function
7432 therefore simply displays a message. */
7434 static void
7435 image_error (format, arg1, arg2)
7436 char *format;
7437 Lisp_Object arg1, arg2;
7439 add_to_log (format, arg1, arg2);
7444 /***********************************************************************
7445 Image specifications
7446 ***********************************************************************/
7448 enum image_value_type
7450 IMAGE_DONT_CHECK_VALUE_TYPE,
7451 IMAGE_STRING_VALUE,
7452 IMAGE_SYMBOL_VALUE,
7453 IMAGE_POSITIVE_INTEGER_VALUE,
7454 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7455 IMAGE_ASCENT_VALUE,
7456 IMAGE_INTEGER_VALUE,
7457 IMAGE_FUNCTION_VALUE,
7458 IMAGE_NUMBER_VALUE,
7459 IMAGE_BOOL_VALUE
7462 /* Structure used when parsing image specifications. */
7464 struct image_keyword
7466 /* Name of keyword. */
7467 char *name;
7469 /* The type of value allowed. */
7470 enum image_value_type type;
7472 /* Non-zero means key must be present. */
7473 int mandatory_p;
7475 /* Used to recognize duplicate keywords in a property list. */
7476 int count;
7478 /* The value that was found. */
7479 Lisp_Object value;
7483 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7484 int, Lisp_Object));
7485 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7488 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7489 has the format (image KEYWORD VALUE ...). One of the keyword/
7490 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7491 image_keywords structures of size NKEYWORDS describing other
7492 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7494 static int
7495 parse_image_spec (spec, keywords, nkeywords, type)
7496 Lisp_Object spec;
7497 struct image_keyword *keywords;
7498 int nkeywords;
7499 Lisp_Object type;
7501 int i;
7502 Lisp_Object plist;
7504 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7505 return 0;
7507 plist = XCDR (spec);
7508 while (CONSP (plist))
7510 Lisp_Object key, value;
7512 /* First element of a pair must be a symbol. */
7513 key = XCAR (plist);
7514 plist = XCDR (plist);
7515 if (!SYMBOLP (key))
7516 return 0;
7518 /* There must follow a value. */
7519 if (!CONSP (plist))
7520 return 0;
7521 value = XCAR (plist);
7522 plist = XCDR (plist);
7524 /* Find key in KEYWORDS. Error if not found. */
7525 for (i = 0; i < nkeywords; ++i)
7526 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7527 break;
7529 if (i == nkeywords)
7530 continue;
7532 /* Record that we recognized the keyword. If a keywords
7533 was found more than once, it's an error. */
7534 keywords[i].value = value;
7535 ++keywords[i].count;
7537 if (keywords[i].count > 1)
7538 return 0;
7540 /* Check type of value against allowed type. */
7541 switch (keywords[i].type)
7543 case IMAGE_STRING_VALUE:
7544 if (!STRINGP (value))
7545 return 0;
7546 break;
7548 case IMAGE_SYMBOL_VALUE:
7549 if (!SYMBOLP (value))
7550 return 0;
7551 break;
7553 case IMAGE_POSITIVE_INTEGER_VALUE:
7554 if (!INTEGERP (value) || XINT (value) <= 0)
7555 return 0;
7556 break;
7558 case IMAGE_ASCENT_VALUE:
7559 if (SYMBOLP (value) && EQ (value, Qcenter))
7560 break;
7561 else if (INTEGERP (value)
7562 && XINT (value) >= 0
7563 && XINT (value) <= 100)
7564 break;
7565 return 0;
7567 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7568 if (!INTEGERP (value) || XINT (value) < 0)
7569 return 0;
7570 break;
7572 case IMAGE_DONT_CHECK_VALUE_TYPE:
7573 break;
7575 case IMAGE_FUNCTION_VALUE:
7576 value = indirect_function (value);
7577 if (SUBRP (value)
7578 || COMPILEDP (value)
7579 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7580 break;
7581 return 0;
7583 case IMAGE_NUMBER_VALUE:
7584 if (!INTEGERP (value) && !FLOATP (value))
7585 return 0;
7586 break;
7588 case IMAGE_INTEGER_VALUE:
7589 if (!INTEGERP (value))
7590 return 0;
7591 break;
7593 case IMAGE_BOOL_VALUE:
7594 if (!NILP (value) && !EQ (value, Qt))
7595 return 0;
7596 break;
7598 default:
7599 abort ();
7600 break;
7603 if (EQ (key, QCtype) && !EQ (type, value))
7604 return 0;
7607 /* Check that all mandatory fields are present. */
7608 for (i = 0; i < nkeywords; ++i)
7609 if (keywords[i].mandatory_p && keywords[i].count == 0)
7610 return 0;
7612 return NILP (plist);
7616 /* Return the value of KEY in image specification SPEC. Value is nil
7617 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7618 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7620 static Lisp_Object
7621 image_spec_value (spec, key, found)
7622 Lisp_Object spec, key;
7623 int *found;
7625 Lisp_Object tail;
7627 xassert (valid_image_p (spec));
7629 for (tail = XCDR (spec);
7630 CONSP (tail) && CONSP (XCDR (tail));
7631 tail = XCDR (XCDR (tail)))
7633 if (EQ (XCAR (tail), key))
7635 if (found)
7636 *found = 1;
7637 return XCAR (XCDR (tail));
7641 if (found)
7642 *found = 0;
7643 return Qnil;
7649 /***********************************************************************
7650 Image type independent image structures
7651 ***********************************************************************/
7653 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7654 static void free_image P_ ((struct frame *f, struct image *img));
7657 /* Allocate and return a new image structure for image specification
7658 SPEC. SPEC has a hash value of HASH. */
7660 static struct image *
7661 make_image (spec, hash)
7662 Lisp_Object spec;
7663 unsigned hash;
7665 struct image *img = (struct image *) xmalloc (sizeof *img);
7667 xassert (valid_image_p (spec));
7668 bzero (img, sizeof *img);
7669 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7670 xassert (img->type != NULL);
7671 img->spec = spec;
7672 img->data.lisp_val = Qnil;
7673 img->ascent = DEFAULT_IMAGE_ASCENT;
7674 img->hash = hash;
7675 return img;
7679 /* Free image IMG which was used on frame F, including its resources. */
7681 static void
7682 free_image (f, img)
7683 struct frame *f;
7684 struct image *img;
7686 if (img)
7688 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7690 /* Remove IMG from the hash table of its cache. */
7691 if (img->prev)
7692 img->prev->next = img->next;
7693 else
7694 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7696 if (img->next)
7697 img->next->prev = img->prev;
7699 c->images[img->id] = NULL;
7701 /* Free resources, then free IMG. */
7702 img->type->free (f, img);
7703 xfree (img);
7708 /* Prepare image IMG for display on frame F. Must be called before
7709 drawing an image. */
7711 void
7712 prepare_image_for_display (f, img)
7713 struct frame *f;
7714 struct image *img;
7716 EMACS_TIME t;
7718 /* We're about to display IMG, so set its timestamp to `now'. */
7719 EMACS_GET_TIME (t);
7720 img->timestamp = EMACS_SECS (t);
7722 /* If IMG doesn't have a pixmap yet, load it now, using the image
7723 type dependent loader function. */
7724 if (img->pixmap == 0 && !img->load_failed_p)
7725 img->load_failed_p = img->type->load (f, img) == 0;
7729 /* Value is the number of pixels for the ascent of image IMG when
7730 drawn in face FACE. */
7733 image_ascent (img, face)
7734 struct image *img;
7735 struct face *face;
7737 int height = img->height + img->margin;
7738 int ascent;
7740 if (img->ascent == CENTERED_IMAGE_ASCENT)
7742 if (face->font)
7743 ascent = height / 2 - (FONT_DESCENT(face->font)
7744 - FONT_BASE(face->font)) / 2;
7745 else
7746 ascent = height / 2;
7748 else
7749 ascent = height * img->ascent / 100.0;
7751 return ascent;
7756 /***********************************************************************
7757 Helper functions for X image types
7758 ***********************************************************************/
7760 static void x_clear_image P_ ((struct frame *f, struct image *img));
7761 static unsigned long x_alloc_image_color P_ ((struct frame *f,
7762 struct image *img,
7763 Lisp_Object color_name,
7764 unsigned long dflt));
7766 /* Free X resources of image IMG which is used on frame F. */
7768 static void
7769 x_clear_image (f, img)
7770 struct frame *f;
7771 struct image *img;
7773 #if 0 /* NTEMACS_TODO: W32 image support */
7775 if (img->pixmap)
7777 BLOCK_INPUT;
7778 XFreePixmap (NULL, img->pixmap);
7779 img->pixmap = 0;
7780 UNBLOCK_INPUT;
7783 if (img->ncolors)
7785 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7787 /* If display has an immutable color map, freeing colors is not
7788 necessary and some servers don't allow it. So don't do it. */
7789 if (class != StaticColor
7790 && class != StaticGray
7791 && class != TrueColor)
7793 Colormap cmap;
7794 BLOCK_INPUT;
7795 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7796 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7797 img->ncolors, 0);
7798 UNBLOCK_INPUT;
7801 xfree (img->colors);
7802 img->colors = NULL;
7803 img->ncolors = 0;
7805 #endif
7809 /* Allocate color COLOR_NAME for image IMG on frame F. If color
7810 cannot be allocated, use DFLT. Add a newly allocated color to
7811 IMG->colors, so that it can be freed again. Value is the pixel
7812 color. */
7814 static unsigned long
7815 x_alloc_image_color (f, img, color_name, dflt)
7816 struct frame *f;
7817 struct image *img;
7818 Lisp_Object color_name;
7819 unsigned long dflt;
7821 #if 0 /* NTEMACS_TODO: allocing colors. */
7822 XColor color;
7823 unsigned long result;
7825 xassert (STRINGP (color_name));
7827 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
7829 /* This isn't called frequently so we get away with simply
7830 reallocating the color vector to the needed size, here. */
7831 ++img->ncolors;
7832 img->colors =
7833 (unsigned long *) xrealloc (img->colors,
7834 img->ncolors * sizeof *img->colors);
7835 img->colors[img->ncolors - 1] = color.pixel;
7836 result = color.pixel;
7838 else
7839 result = dflt;
7840 return result;
7841 #endif
7842 return 0;
7847 /***********************************************************************
7848 Image Cache
7849 ***********************************************************************/
7851 static void cache_image P_ ((struct frame *f, struct image *img));
7854 /* Return a new, initialized image cache that is allocated from the
7855 heap. Call free_image_cache to free an image cache. */
7857 struct image_cache *
7858 make_image_cache ()
7860 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7861 int size;
7863 bzero (c, sizeof *c);
7864 c->size = 50;
7865 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7866 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7867 c->buckets = (struct image **) xmalloc (size);
7868 bzero (c->buckets, size);
7869 return c;
7873 /* Free image cache of frame F. Be aware that X frames share images
7874 caches. */
7876 void
7877 free_image_cache (f)
7878 struct frame *f;
7880 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7881 if (c)
7883 int i;
7885 /* Cache should not be referenced by any frame when freed. */
7886 xassert (c->refcount == 0);
7888 for (i = 0; i < c->used; ++i)
7889 free_image (f, c->images[i]);
7890 xfree (c->images);
7891 xfree (c);
7892 xfree (c->buckets);
7893 FRAME_X_IMAGE_CACHE (f) = NULL;
7898 /* Clear image cache of frame F. FORCE_P non-zero means free all
7899 images. FORCE_P zero means clear only images that haven't been
7900 displayed for some time. Should be called from time to time to
7901 reduce the number of loaded images. If image-eviction-seconds is
7902 non-nil, this frees images in the cache which weren't displayed for
7903 at least that many seconds. */
7905 void
7906 clear_image_cache (f, force_p)
7907 struct frame *f;
7908 int force_p;
7910 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7912 if (c && INTEGERP (Vimage_cache_eviction_delay))
7914 EMACS_TIME t;
7915 unsigned long old;
7916 int i, any_freed_p = 0;
7918 EMACS_GET_TIME (t);
7919 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7921 for (i = 0; i < c->used; ++i)
7923 struct image *img = c->images[i];
7924 if (img != NULL
7925 && (force_p
7926 || (img->timestamp > old)))
7928 free_image (f, img);
7929 any_freed_p = 1;
7933 /* We may be clearing the image cache because, for example,
7934 Emacs was iconified for a longer period of time. In that
7935 case, current matrices may still contain references to
7936 images freed above. So, clear these matrices. */
7937 if (any_freed_p)
7939 clear_current_matrices (f);
7940 ++windows_or_buffers_changed;
7946 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7947 0, 1, 0,
7948 "Clear the image cache of FRAME.\n\
7949 FRAME nil or omitted means use the selected frame.\n\
7950 FRAME t means clear the image caches of all frames.")
7951 (frame)
7952 Lisp_Object frame;
7954 if (EQ (frame, Qt))
7956 Lisp_Object tail;
7958 FOR_EACH_FRAME (tail, frame)
7959 if (FRAME_W32_P (XFRAME (frame)))
7960 clear_image_cache (XFRAME (frame), 1);
7962 else
7963 clear_image_cache (check_x_frame (frame), 1);
7965 return Qnil;
7969 /* Return the id of image with Lisp specification SPEC on frame F.
7970 SPEC must be a valid Lisp image specification (see valid_image_p). */
7973 lookup_image (f, spec)
7974 struct frame *f;
7975 Lisp_Object spec;
7977 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7978 struct image *img;
7979 int i;
7980 unsigned hash;
7981 struct gcpro gcpro1;
7982 EMACS_TIME now;
7984 /* F must be a window-system frame, and SPEC must be a valid image
7985 specification. */
7986 xassert (FRAME_WINDOW_P (f));
7987 xassert (valid_image_p (spec));
7989 GCPRO1 (spec);
7991 /* Look up SPEC in the hash table of the image cache. */
7992 hash = sxhash (spec, 0);
7993 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7995 for (img = c->buckets[i]; img; img = img->next)
7996 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7997 break;
7999 /* If not found, create a new image and cache it. */
8000 if (img == NULL)
8002 img = make_image (spec, hash);
8003 cache_image (f, img);
8004 img->load_failed_p = img->type->load (f, img) == 0;
8005 xassert (!interrupt_input_blocked);
8007 /* If we can't load the image, and we don't have a width and
8008 height, use some arbitrary width and height so that we can
8009 draw a rectangle for it. */
8010 if (img->load_failed_p)
8012 Lisp_Object value;
8014 value = image_spec_value (spec, QCwidth, NULL);
8015 img->width = (INTEGERP (value)
8016 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8017 value = image_spec_value (spec, QCheight, NULL);
8018 img->height = (INTEGERP (value)
8019 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8021 else
8023 /* Handle image type independent image attributes
8024 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8025 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
8026 Lisp_Object file;
8028 ascent = image_spec_value (spec, QCascent, NULL);
8029 if (INTEGERP (ascent))
8030 img->ascent = XFASTINT (ascent);
8031 else if (EQ (ascent, Qcenter))
8032 img->ascent = CENTERED_IMAGE_ASCENT;
8034 margin = image_spec_value (spec, QCmargin, NULL);
8035 if (INTEGERP (margin) && XINT (margin) >= 0)
8036 img->margin = XFASTINT (margin);
8038 relief = image_spec_value (spec, QCrelief, NULL);
8039 if (INTEGERP (relief))
8041 img->relief = XINT (relief);
8042 img->margin += abs (img->relief);
8045 /* Should we apply a Laplace edge-detection algorithm? */
8046 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8047 if (img->pixmap && EQ (algorithm, Qlaplace))
8048 x_laplace (f, img);
8050 /* Should we built a mask heuristically? */
8051 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8052 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8053 x_build_heuristic_mask (f, img, heuristic_mask);
8057 /* We're using IMG, so set its timestamp to `now'. */
8058 EMACS_GET_TIME (now);
8059 img->timestamp = EMACS_SECS (now);
8061 UNGCPRO;
8063 /* Value is the image id. */
8064 return img->id;
8068 /* Cache image IMG in the image cache of frame F. */
8070 static void
8071 cache_image (f, img)
8072 struct frame *f;
8073 struct image *img;
8075 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8076 int i;
8078 /* Find a free slot in c->images. */
8079 for (i = 0; i < c->used; ++i)
8080 if (c->images[i] == NULL)
8081 break;
8083 /* If no free slot found, maybe enlarge c->images. */
8084 if (i == c->used && c->used == c->size)
8086 c->size *= 2;
8087 c->images = (struct image **) xrealloc (c->images,
8088 c->size * sizeof *c->images);
8091 /* Add IMG to c->images, and assign IMG an id. */
8092 c->images[i] = img;
8093 img->id = i;
8094 if (i == c->used)
8095 ++c->used;
8097 /* Add IMG to the cache's hash table. */
8098 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8099 img->next = c->buckets[i];
8100 if (img->next)
8101 img->next->prev = img;
8102 img->prev = NULL;
8103 c->buckets[i] = img;
8107 /* Call FN on every image in the image cache of frame F. Used to mark
8108 Lisp Objects in the image cache. */
8110 void
8111 forall_images_in_image_cache (f, fn)
8112 struct frame *f;
8113 void (*fn) P_ ((struct image *img));
8115 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8117 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8118 if (c)
8120 int i;
8121 for (i = 0; i < c->used; ++i)
8122 if (c->images[i])
8123 fn (c->images[i]);
8130 /***********************************************************************
8131 W32 support code
8132 ***********************************************************************/
8134 #if 0 /* NTEMACS_TODO: W32 specific image code. */
8136 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8137 XImage **, Pixmap *));
8138 static void x_destroy_x_image P_ ((XImage *));
8139 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8142 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8143 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8144 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8145 via xmalloc. Print error messages via image_error if an error
8146 occurs. Value is non-zero if successful. */
8148 static int
8149 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8150 struct frame *f;
8151 int width, height, depth;
8152 XImage **ximg;
8153 Pixmap *pixmap;
8155 #if 0 /* NTEMACS_TODO: Image support for W32 */
8156 Display *display = FRAME_W32_DISPLAY (f);
8157 Screen *screen = FRAME_X_SCREEN (f);
8158 Window window = FRAME_W32_WINDOW (f);
8160 xassert (interrupt_input_blocked);
8162 if (depth <= 0)
8163 depth = DefaultDepthOfScreen (screen);
8164 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8165 depth, ZPixmap, 0, NULL, width, height,
8166 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8167 if (*ximg == NULL)
8169 image_error ("Unable to allocate X image", Qnil, Qnil);
8170 return 0;
8173 /* Allocate image raster. */
8174 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8176 /* Allocate a pixmap of the same size. */
8177 *pixmap = XCreatePixmap (display, window, width, height, depth);
8178 if (*pixmap == 0)
8180 x_destroy_x_image (*ximg);
8181 *ximg = NULL;
8182 image_error ("Unable to create X pixmap", Qnil, Qnil);
8183 return 0;
8185 #endif
8186 return 1;
8190 /* Destroy XImage XIMG. Free XIMG->data. */
8192 static void
8193 x_destroy_x_image (ximg)
8194 XImage *ximg;
8196 xassert (interrupt_input_blocked);
8197 if (ximg)
8199 xfree (ximg->data);
8200 ximg->data = NULL;
8201 XDestroyImage (ximg);
8206 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8207 are width and height of both the image and pixmap. */
8209 static void
8210 x_put_x_image (f, ximg, pixmap, width, height)
8211 struct frame *f;
8212 XImage *ximg;
8213 Pixmap pixmap;
8215 GC gc;
8217 xassert (interrupt_input_blocked);
8218 gc = XCreateGC (NULL, pixmap, 0, NULL);
8219 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8220 XFreeGC (NULL, gc);
8223 #endif
8226 /***********************************************************************
8227 Searching files
8228 ***********************************************************************/
8230 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8232 /* Find image file FILE. Look in data-directory, then
8233 x-bitmap-file-path. Value is the full name of the file found, or
8234 nil if not found. */
8236 static Lisp_Object
8237 x_find_image_file (file)
8238 Lisp_Object file;
8240 Lisp_Object file_found, search_path;
8241 struct gcpro gcpro1, gcpro2;
8242 int fd;
8244 file_found = Qnil;
8245 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8246 GCPRO2 (file_found, search_path);
8248 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8249 fd = openp (search_path, file, "", &file_found, 0);
8251 if (fd < 0)
8252 file_found = Qnil;
8253 else
8254 close (fd);
8256 UNGCPRO;
8257 return file_found;
8262 /***********************************************************************
8263 XBM images
8264 ***********************************************************************/
8266 static int xbm_load P_ ((struct frame *f, struct image *img));
8267 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8268 Lisp_Object file));
8269 static int xbm_image_p P_ ((Lisp_Object object));
8270 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8271 unsigned char **));
8274 /* Indices of image specification fields in xbm_format, below. */
8276 enum xbm_keyword_index
8278 XBM_TYPE,
8279 XBM_FILE,
8280 XBM_WIDTH,
8281 XBM_HEIGHT,
8282 XBM_DATA,
8283 XBM_FOREGROUND,
8284 XBM_BACKGROUND,
8285 XBM_ASCENT,
8286 XBM_MARGIN,
8287 XBM_RELIEF,
8288 XBM_ALGORITHM,
8289 XBM_HEURISTIC_MASK,
8290 XBM_LAST
8293 /* Vector of image_keyword structures describing the format
8294 of valid XBM image specifications. */
8296 static struct image_keyword xbm_format[XBM_LAST] =
8298 {":type", IMAGE_SYMBOL_VALUE, 1},
8299 {":file", IMAGE_STRING_VALUE, 0},
8300 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8301 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8302 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8303 {":foreground", IMAGE_STRING_VALUE, 0},
8304 {":background", IMAGE_STRING_VALUE, 0},
8305 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8306 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8307 {":relief", IMAGE_INTEGER_VALUE, 0},
8308 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8309 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8312 /* Structure describing the image type XBM. */
8314 static struct image_type xbm_type =
8316 &Qxbm,
8317 xbm_image_p,
8318 xbm_load,
8319 x_clear_image,
8320 NULL
8323 /* Tokens returned from xbm_scan. */
8325 enum xbm_token
8327 XBM_TK_IDENT = 256,
8328 XBM_TK_NUMBER
8332 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8333 A valid specification is a list starting with the symbol `image'
8334 The rest of the list is a property list which must contain an
8335 entry `:type xbm..
8337 If the specification specifies a file to load, it must contain
8338 an entry `:file FILENAME' where FILENAME is a string.
8340 If the specification is for a bitmap loaded from memory it must
8341 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8342 WIDTH and HEIGHT are integers > 0. DATA may be:
8344 1. a string large enough to hold the bitmap data, i.e. it must
8345 have a size >= (WIDTH + 7) / 8 * HEIGHT
8347 2. a bool-vector of size >= WIDTH * HEIGHT
8349 3. a vector of strings or bool-vectors, one for each line of the
8350 bitmap.
8352 Both the file and data forms may contain the additional entries
8353 `:background COLOR' and `:foreground COLOR'. If not present,
8354 foreground and background of the frame on which the image is
8355 displayed, is used. */
8357 static int
8358 xbm_image_p (object)
8359 Lisp_Object object;
8361 struct image_keyword kw[XBM_LAST];
8363 bcopy (xbm_format, kw, sizeof kw);
8364 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8365 return 0;
8367 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8369 if (kw[XBM_FILE].count)
8371 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8372 return 0;
8374 else
8376 Lisp_Object data;
8377 int width, height;
8379 /* Entries for `:width', `:height' and `:data' must be present. */
8380 if (!kw[XBM_WIDTH].count
8381 || !kw[XBM_HEIGHT].count
8382 || !kw[XBM_DATA].count)
8383 return 0;
8385 data = kw[XBM_DATA].value;
8386 width = XFASTINT (kw[XBM_WIDTH].value);
8387 height = XFASTINT (kw[XBM_HEIGHT].value);
8389 /* Check type of data, and width and height against contents of
8390 data. */
8391 if (VECTORP (data))
8393 int i;
8395 /* Number of elements of the vector must be >= height. */
8396 if (XVECTOR (data)->size < height)
8397 return 0;
8399 /* Each string or bool-vector in data must be large enough
8400 for one line of the image. */
8401 for (i = 0; i < height; ++i)
8403 Lisp_Object elt = XVECTOR (data)->contents[i];
8405 if (STRINGP (elt))
8407 if (XSTRING (elt)->size
8408 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8409 return 0;
8411 else if (BOOL_VECTOR_P (elt))
8413 if (XBOOL_VECTOR (elt)->size < width)
8414 return 0;
8416 else
8417 return 0;
8420 else if (STRINGP (data))
8422 if (XSTRING (data)->size
8423 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8424 return 0;
8426 else if (BOOL_VECTOR_P (data))
8428 if (XBOOL_VECTOR (data)->size < width * height)
8429 return 0;
8431 else
8432 return 0;
8435 /* Baseline must be a value between 0 and 100 (a percentage). */
8436 if (kw[XBM_ASCENT].count
8437 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8438 return 0;
8440 return 1;
8444 /* Scan a bitmap file. FP is the stream to read from. Value is
8445 either an enumerator from enum xbm_token, or a character for a
8446 single-character token, or 0 at end of file. If scanning an
8447 identifier, store the lexeme of the identifier in SVAL. If
8448 scanning a number, store its value in *IVAL. */
8450 static int
8451 xbm_scan (fp, sval, ival)
8452 FILE *fp;
8453 char *sval;
8454 int *ival;
8456 int c;
8458 /* Skip white space. */
8459 while ((c = fgetc (fp)) != EOF && isspace (c))
8462 if (c == EOF)
8463 c = 0;
8464 else if (isdigit (c))
8466 int value = 0, digit;
8468 if (c == '0')
8470 c = fgetc (fp);
8471 if (c == 'x' || c == 'X')
8473 while ((c = fgetc (fp)) != EOF)
8475 if (isdigit (c))
8476 digit = c - '0';
8477 else if (c >= 'a' && c <= 'f')
8478 digit = c - 'a' + 10;
8479 else if (c >= 'A' && c <= 'F')
8480 digit = c - 'A' + 10;
8481 else
8482 break;
8483 value = 16 * value + digit;
8486 else if (isdigit (c))
8488 value = c - '0';
8489 while ((c = fgetc (fp)) != EOF
8490 && isdigit (c))
8491 value = 8 * value + c - '0';
8494 else
8496 value = c - '0';
8497 while ((c = fgetc (fp)) != EOF
8498 && isdigit (c))
8499 value = 10 * value + c - '0';
8502 if (c != EOF)
8503 ungetc (c, fp);
8504 *ival = value;
8505 c = XBM_TK_NUMBER;
8507 else if (isalpha (c) || c == '_')
8509 *sval++ = c;
8510 while ((c = fgetc (fp)) != EOF
8511 && (isalnum (c) || c == '_'))
8512 *sval++ = c;
8513 *sval = 0;
8514 if (c != EOF)
8515 ungetc (c, fp);
8516 c = XBM_TK_IDENT;
8519 return c;
8523 /* Replacement for XReadBitmapFileData which isn't available under old
8524 X versions. FILE is the name of the bitmap file to read. Set
8525 *WIDTH and *HEIGHT to the width and height of the image. Return in
8526 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8527 successful. */
8529 static int
8530 xbm_read_bitmap_file_data (file, width, height, data)
8531 char *file;
8532 int *width, *height;
8533 unsigned char **data;
8535 FILE *fp;
8536 char buffer[BUFSIZ];
8537 int padding_p = 0;
8538 int v10 = 0;
8539 int bytes_per_line, i, nbytes;
8540 unsigned char *p;
8541 int value;
8542 int LA1;
8544 #define match() \
8545 LA1 = xbm_scan (fp, buffer, &value)
8547 #define expect(TOKEN) \
8548 if (LA1 != (TOKEN)) \
8549 goto failure; \
8550 else \
8551 match ()
8553 #define expect_ident(IDENT) \
8554 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8555 match (); \
8556 else \
8557 goto failure
8559 fp = fopen (file, "r");
8560 if (fp == NULL)
8561 return 0;
8563 *width = *height = -1;
8564 *data = NULL;
8565 LA1 = xbm_scan (fp, buffer, &value);
8567 /* Parse defines for width, height and hot-spots. */
8568 while (LA1 == '#')
8570 match ();
8571 expect_ident ("define");
8572 expect (XBM_TK_IDENT);
8574 if (LA1 == XBM_TK_NUMBER);
8576 char *p = strrchr (buffer, '_');
8577 p = p ? p + 1 : buffer;
8578 if (strcmp (p, "width") == 0)
8579 *width = value;
8580 else if (strcmp (p, "height") == 0)
8581 *height = value;
8583 expect (XBM_TK_NUMBER);
8586 if (*width < 0 || *height < 0)
8587 goto failure;
8589 /* Parse bits. Must start with `static'. */
8590 expect_ident ("static");
8591 if (LA1 == XBM_TK_IDENT)
8593 if (strcmp (buffer, "unsigned") == 0)
8595 match ();
8596 expect_ident ("char");
8598 else if (strcmp (buffer, "short") == 0)
8600 match ();
8601 v10 = 1;
8602 if (*width % 16 && *width % 16 < 9)
8603 padding_p = 1;
8605 else if (strcmp (buffer, "char") == 0)
8606 match ();
8607 else
8608 goto failure;
8610 else
8611 goto failure;
8613 expect (XBM_TK_IDENT);
8614 expect ('[');
8615 expect (']');
8616 expect ('=');
8617 expect ('{');
8619 bytes_per_line = (*width + 7) / 8 + padding_p;
8620 nbytes = bytes_per_line * *height;
8621 p = *data = (char *) xmalloc (nbytes);
8623 if (v10)
8626 for (i = 0; i < nbytes; i += 2)
8628 int val = value;
8629 expect (XBM_TK_NUMBER);
8631 *p++ = val;
8632 if (!padding_p || ((i + 2) % bytes_per_line))
8633 *p++ = value >> 8;
8635 if (LA1 == ',' || LA1 == '}')
8636 match ();
8637 else
8638 goto failure;
8641 else
8643 for (i = 0; i < nbytes; ++i)
8645 int val = value;
8646 expect (XBM_TK_NUMBER);
8648 *p++ = val;
8650 if (LA1 == ',' || LA1 == '}')
8651 match ();
8652 else
8653 goto failure;
8657 fclose (fp);
8658 return 1;
8660 failure:
8662 fclose (fp);
8663 if (*data)
8665 xfree (*data);
8666 *data = NULL;
8668 return 0;
8670 #undef match
8671 #undef expect
8672 #undef expect_ident
8676 /* Load XBM image IMG which will be displayed on frame F from file
8677 SPECIFIED_FILE. Value is non-zero if successful. */
8679 static int
8680 xbm_load_image_from_file (f, img, specified_file)
8681 struct frame *f;
8682 struct image *img;
8683 Lisp_Object specified_file;
8685 int rc;
8686 unsigned char *data;
8687 int success_p = 0;
8688 Lisp_Object file;
8689 struct gcpro gcpro1;
8691 xassert (STRINGP (specified_file));
8692 file = Qnil;
8693 GCPRO1 (file);
8695 file = x_find_image_file (specified_file);
8696 if (!STRINGP (file))
8698 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8699 UNGCPRO;
8700 return 0;
8703 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8704 &img->height, &data);
8705 if (rc)
8707 int depth = one_w32_display_info.n_cbits;
8708 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8709 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8710 Lisp_Object value;
8712 xassert (img->width > 0 && img->height > 0);
8714 /* Get foreground and background colors, maybe allocate colors. */
8715 value = image_spec_value (img->spec, QCforeground, NULL);
8716 if (!NILP (value))
8717 foreground = x_alloc_image_color (f, img, value, foreground);
8719 value = image_spec_value (img->spec, QCbackground, NULL);
8720 if (!NILP (value))
8721 background = x_alloc_image_color (f, img, value, background);
8723 #if 0 /* NTEMACS_TODO : Port image display to W32 */
8724 BLOCK_INPUT;
8725 img->pixmap
8726 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8727 FRAME_W32_WINDOW (f),
8728 data,
8729 img->width, img->height,
8730 foreground, background,
8731 depth);
8732 xfree (data);
8734 if (img->pixmap == 0)
8736 x_clear_image (f, img);
8737 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8739 else
8740 success_p = 1;
8742 UNBLOCK_INPUT;
8743 #endif
8745 else
8746 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8748 UNGCPRO;
8749 return success_p;
8753 /* Fill image IMG which is used on frame F with pixmap data. Value is
8754 non-zero if successful. */
8756 static int
8757 xbm_load (f, img)
8758 struct frame *f;
8759 struct image *img;
8761 int success_p = 0;
8762 Lisp_Object file_name;
8764 xassert (xbm_image_p (img->spec));
8766 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8767 file_name = image_spec_value (img->spec, QCfile, NULL);
8768 if (STRINGP (file_name))
8769 success_p = xbm_load_image_from_file (f, img, file_name);
8770 else
8772 struct image_keyword fmt[XBM_LAST];
8773 Lisp_Object data;
8774 int depth;
8775 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8776 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8777 char *bits;
8778 int parsed_p;
8780 /* Parse the list specification. */
8781 bcopy (xbm_format, fmt, sizeof fmt);
8782 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8783 xassert (parsed_p);
8785 /* Get specified width, and height. */
8786 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8787 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8788 xassert (img->width > 0 && img->height > 0);
8790 BLOCK_INPUT;
8792 if (fmt[XBM_ASCENT].count)
8793 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
8795 /* Get foreground and background colors, maybe allocate colors. */
8796 if (fmt[XBM_FOREGROUND].count)
8797 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8798 foreground);
8799 if (fmt[XBM_BACKGROUND].count)
8800 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8801 background);
8803 /* Set bits to the bitmap image data. */
8804 data = fmt[XBM_DATA].value;
8805 if (VECTORP (data))
8807 int i;
8808 char *p;
8809 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
8811 p = bits = (char *) alloca (nbytes * img->height);
8812 for (i = 0; i < img->height; ++i, p += nbytes)
8814 Lisp_Object line = XVECTOR (data)->contents[i];
8815 if (STRINGP (line))
8816 bcopy (XSTRING (line)->data, p, nbytes);
8817 else
8818 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
8821 else if (STRINGP (data))
8822 bits = XSTRING (data)->data;
8823 else
8824 bits = XBOOL_VECTOR (data)->data;
8826 #if 0 /* NTEMACS_TODO : W32 XPM code */
8827 /* Create the pixmap. */
8828 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
8829 img->pixmap
8830 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8831 FRAME_W32_WINDOW (f),
8832 bits,
8833 img->width, img->height,
8834 foreground, background,
8835 depth);
8836 #endif /* NTEMACS_TODO */
8838 if (img->pixmap)
8839 success_p = 1;
8840 else
8842 image_error ("Unable to create pixmap for XBM image `%s'",
8843 img->spec, Qnil);
8844 x_clear_image (f, img);
8847 UNBLOCK_INPUT;
8850 return success_p;
8855 /***********************************************************************
8856 XPM images
8857 ***********************************************************************/
8859 #if HAVE_XPM
8861 static int xpm_image_p P_ ((Lisp_Object object));
8862 static int xpm_load P_ ((struct frame *f, struct image *img));
8863 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
8865 #include "X11/xpm.h"
8867 /* The symbol `xpm' identifying XPM-format images. */
8869 Lisp_Object Qxpm;
8871 /* Indices of image specification fields in xpm_format, below. */
8873 enum xpm_keyword_index
8875 XPM_TYPE,
8876 XPM_FILE,
8877 XPM_DATA,
8878 XPM_ASCENT,
8879 XPM_MARGIN,
8880 XPM_RELIEF,
8881 XPM_ALGORITHM,
8882 XPM_HEURISTIC_MASK,
8883 XPM_COLOR_SYMBOLS,
8884 XPM_LAST
8887 /* Vector of image_keyword structures describing the format
8888 of valid XPM image specifications. */
8890 static struct image_keyword xpm_format[XPM_LAST] =
8892 {":type", IMAGE_SYMBOL_VALUE, 1},
8893 {":file", IMAGE_STRING_VALUE, 0},
8894 {":data", IMAGE_STRING_VALUE, 0},
8895 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8896 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8897 {":relief", IMAGE_INTEGER_VALUE, 0},
8898 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8899 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8900 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8903 /* Structure describing the image type XBM. */
8905 static struct image_type xpm_type =
8907 &Qxpm,
8908 xpm_image_p,
8909 xpm_load,
8910 x_clear_image,
8911 NULL
8915 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
8916 for XPM images. Such a list must consist of conses whose car and
8917 cdr are strings. */
8919 static int
8920 xpm_valid_color_symbols_p (color_symbols)
8921 Lisp_Object color_symbols;
8923 while (CONSP (color_symbols))
8925 Lisp_Object sym = XCAR (color_symbols);
8926 if (!CONSP (sym)
8927 || !STRINGP (XCAR (sym))
8928 || !STRINGP (XCDR (sym)))
8929 break;
8930 color_symbols = XCDR (color_symbols);
8933 return NILP (color_symbols);
8937 /* Value is non-zero if OBJECT is a valid XPM image specification. */
8939 static int
8940 xpm_image_p (object)
8941 Lisp_Object object;
8943 struct image_keyword fmt[XPM_LAST];
8944 bcopy (xpm_format, fmt, sizeof fmt);
8945 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
8946 /* Either `:file' or `:data' must be present. */
8947 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
8948 /* Either no `:color-symbols' or it's a list of conses
8949 whose car and cdr are strings. */
8950 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8951 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
8952 && (fmt[XPM_ASCENT].count == 0
8953 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
8957 /* Load image IMG which will be displayed on frame F. Value is
8958 non-zero if successful. */
8960 static int
8961 xpm_load (f, img)
8962 struct frame *f;
8963 struct image *img;
8965 int rc, i;
8966 XpmAttributes attrs;
8967 Lisp_Object specified_file, color_symbols;
8969 /* Configure the XPM lib. Use the visual of frame F. Allocate
8970 close colors. Return colors allocated. */
8971 bzero (&attrs, sizeof attrs);
8972 attrs.visual = FRAME_X_VISUAL (f);
8973 attrs.colormap = FRAME_X_COLORMAP (f);
8974 attrs.valuemask |= XpmVisual;
8975 attrs.valuemask |= XpmColormap;
8976 attrs.valuemask |= XpmReturnAllocPixels;
8977 #ifdef XpmAllocCloseColors
8978 attrs.alloc_close_colors = 1;
8979 attrs.valuemask |= XpmAllocCloseColors;
8980 #else
8981 attrs.closeness = 600;
8982 attrs.valuemask |= XpmCloseness;
8983 #endif
8985 /* If image specification contains symbolic color definitions, add
8986 these to `attrs'. */
8987 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
8988 if (CONSP (color_symbols))
8990 Lisp_Object tail;
8991 XpmColorSymbol *xpm_syms;
8992 int i, size;
8994 attrs.valuemask |= XpmColorSymbols;
8996 /* Count number of symbols. */
8997 attrs.numsymbols = 0;
8998 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
8999 ++attrs.numsymbols;
9001 /* Allocate an XpmColorSymbol array. */
9002 size = attrs.numsymbols * sizeof *xpm_syms;
9003 xpm_syms = (XpmColorSymbol *) alloca (size);
9004 bzero (xpm_syms, size);
9005 attrs.colorsymbols = xpm_syms;
9007 /* Fill the color symbol array. */
9008 for (tail = color_symbols, i = 0;
9009 CONSP (tail);
9010 ++i, tail = XCDR (tail))
9012 Lisp_Object name = XCAR (XCAR (tail));
9013 Lisp_Object color = XCDR (XCAR (tail));
9014 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9015 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9016 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9017 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9021 /* Create a pixmap for the image, either from a file, or from a
9022 string buffer containing data in the same format as an XPM file. */
9023 BLOCK_INPUT;
9024 specified_file = image_spec_value (img->spec, QCfile, NULL);
9025 if (STRINGP (specified_file))
9027 Lisp_Object file = x_find_image_file (specified_file);
9028 if (!STRINGP (file))
9030 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9031 UNBLOCK_INPUT;
9032 return 0;
9035 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9036 XSTRING (file)->data, &img->pixmap, &img->mask,
9037 &attrs);
9039 else
9041 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9042 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9043 XSTRING (buffer)->data,
9044 &img->pixmap, &img->mask,
9045 &attrs);
9047 UNBLOCK_INPUT;
9049 if (rc == XpmSuccess)
9051 /* Remember allocated colors. */
9052 img->ncolors = attrs.nalloc_pixels;
9053 img->colors = (unsigned long *) xmalloc (img->ncolors
9054 * sizeof *img->colors);
9055 for (i = 0; i < attrs.nalloc_pixels; ++i)
9056 img->colors[i] = attrs.alloc_pixels[i];
9058 img->width = attrs.width;
9059 img->height = attrs.height;
9060 xassert (img->width > 0 && img->height > 0);
9062 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9063 BLOCK_INPUT;
9064 XpmFreeAttributes (&attrs);
9065 UNBLOCK_INPUT;
9067 else
9069 switch (rc)
9071 case XpmOpenFailed:
9072 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9073 break;
9075 case XpmFileInvalid:
9076 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9077 break;
9079 case XpmNoMemory:
9080 image_error ("Out of memory (%s)", img->spec, Qnil);
9081 break;
9083 case XpmColorFailed:
9084 image_error ("Color allocation error (%s)", img->spec, Qnil);
9085 break;
9087 default:
9088 image_error ("Unknown error (%s)", img->spec, Qnil);
9089 break;
9093 return rc == XpmSuccess;
9096 #endif /* HAVE_XPM != 0 */
9099 #if 0 /* NTEMACS_TODO : Color tables on W32. */
9100 /***********************************************************************
9101 Color table
9102 ***********************************************************************/
9104 /* An entry in the color table mapping an RGB color to a pixel color. */
9106 struct ct_color
9108 int r, g, b;
9109 unsigned long pixel;
9111 /* Next in color table collision list. */
9112 struct ct_color *next;
9115 /* The bucket vector size to use. Must be prime. */
9117 #define CT_SIZE 101
9119 /* Value is a hash of the RGB color given by R, G, and B. */
9121 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9123 /* The color hash table. */
9125 struct ct_color **ct_table;
9127 /* Number of entries in the color table. */
9129 int ct_colors_allocated;
9131 /* Function prototypes. */
9133 static void init_color_table P_ ((void));
9134 static void free_color_table P_ ((void));
9135 static unsigned long *colors_in_color_table P_ ((int *n));
9136 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9137 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9140 /* Initialize the color table. */
9142 static void
9143 init_color_table ()
9145 int size = CT_SIZE * sizeof (*ct_table);
9146 ct_table = (struct ct_color **) xmalloc (size);
9147 bzero (ct_table, size);
9148 ct_colors_allocated = 0;
9152 /* Free memory associated with the color table. */
9154 static void
9155 free_color_table ()
9157 int i;
9158 struct ct_color *p, *next;
9160 for (i = 0; i < CT_SIZE; ++i)
9161 for (p = ct_table[i]; p; p = next)
9163 next = p->next;
9164 xfree (p);
9167 xfree (ct_table);
9168 ct_table = NULL;
9172 /* Value is a pixel color for RGB color R, G, B on frame F. If an
9173 entry for that color already is in the color table, return the
9174 pixel color of that entry. Otherwise, allocate a new color for R,
9175 G, B, and make an entry in the color table. */
9177 static unsigned long
9178 lookup_rgb_color (f, r, g, b)
9179 struct frame *f;
9180 int r, g, b;
9182 unsigned hash = CT_HASH_RGB (r, g, b);
9183 int i = hash % CT_SIZE;
9184 struct ct_color *p;
9186 for (p = ct_table[i]; p; p = p->next)
9187 if (p->r == r && p->g == g && p->b == b)
9188 break;
9190 if (p == NULL)
9192 COLORREF color;
9193 Colormap cmap;
9194 int rc;
9196 color = PALETTERGB (r, g, b);
9198 ++ct_colors_allocated;
9200 p = (struct ct_color *) xmalloc (sizeof *p);
9201 p->r = r;
9202 p->g = g;
9203 p->b = b;
9204 p->pixel = color;
9205 p->next = ct_table[i];
9206 ct_table[i] = p;
9209 return p->pixel;
9213 /* Look up pixel color PIXEL which is used on frame F in the color
9214 table. If not already present, allocate it. Value is PIXEL. */
9216 static unsigned long
9217 lookup_pixel_color (f, pixel)
9218 struct frame *f;
9219 unsigned long pixel;
9221 int i = pixel % CT_SIZE;
9222 struct ct_color *p;
9224 for (p = ct_table[i]; p; p = p->next)
9225 if (p->pixel == pixel)
9226 break;
9228 if (p == NULL)
9230 XColor color;
9231 Colormap cmap;
9232 int rc;
9234 BLOCK_INPUT;
9236 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9237 color.pixel = pixel;
9238 XQueryColor (NULL, cmap, &color);
9239 rc = x_alloc_nearest_color (f, cmap, &color);
9240 UNBLOCK_INPUT;
9242 if (rc)
9244 ++ct_colors_allocated;
9246 p = (struct ct_color *) xmalloc (sizeof *p);
9247 p->r = color.red;
9248 p->g = color.green;
9249 p->b = color.blue;
9250 p->pixel = pixel;
9251 p->next = ct_table[i];
9252 ct_table[i] = p;
9254 else
9255 return FRAME_FOREGROUND_PIXEL (f);
9257 return p->pixel;
9261 /* Value is a vector of all pixel colors contained in the color table,
9262 allocated via xmalloc. Set *N to the number of colors. */
9264 static unsigned long *
9265 colors_in_color_table (n)
9266 int *n;
9268 int i, j;
9269 struct ct_color *p;
9270 unsigned long *colors;
9272 if (ct_colors_allocated == 0)
9274 *n = 0;
9275 colors = NULL;
9277 else
9279 colors = (unsigned long *) xmalloc (ct_colors_allocated
9280 * sizeof *colors);
9281 *n = ct_colors_allocated;
9283 for (i = j = 0; i < CT_SIZE; ++i)
9284 for (p = ct_table[i]; p; p = p->next)
9285 colors[j++] = p->pixel;
9288 return colors;
9291 #endif /* NTEMACS_TODO */
9294 /***********************************************************************
9295 Algorithms
9296 ***********************************************************************/
9298 #if 0 /* NTEMACS_TODO : W32 versions of low level algorithms */
9299 static void x_laplace_write_row P_ ((struct frame *, long *,
9300 int, XImage *, int));
9301 static void x_laplace_read_row P_ ((struct frame *, Colormap,
9302 XColor *, int, XImage *, int));
9305 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9306 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9307 the width of one row in the image. */
9309 static void
9310 x_laplace_read_row (f, cmap, colors, width, ximg, y)
9311 struct frame *f;
9312 Colormap cmap;
9313 XColor *colors;
9314 int width;
9315 XImage *ximg;
9316 int y;
9318 int x;
9320 for (x = 0; x < width; ++x)
9321 colors[x].pixel = XGetPixel (ximg, x, y);
9323 XQueryColors (NULL, cmap, colors, width);
9327 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9328 containing the pixel colors to write. F is the frame we are
9329 working on. */
9331 static void
9332 x_laplace_write_row (f, pixels, width, ximg, y)
9333 struct frame *f;
9334 long *pixels;
9335 int width;
9336 XImage *ximg;
9337 int y;
9339 int x;
9341 for (x = 0; x < width; ++x)
9342 XPutPixel (ximg, x, y, pixels[x]);
9344 #endif
9346 /* Transform image IMG which is used on frame F with a Laplace
9347 edge-detection algorithm. The result is an image that can be used
9348 to draw disabled buttons, for example. */
9350 static void
9351 x_laplace (f, img)
9352 struct frame *f;
9353 struct image *img;
9355 #if 0 /* NTEMACS_TODO : W32 version */
9356 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9357 XImage *ximg, *oimg;
9358 XColor *in[3];
9359 long *out;
9360 Pixmap pixmap;
9361 int x, y, i;
9362 long pixel;
9363 int in_y, out_y, rc;
9364 int mv2 = 45000;
9366 BLOCK_INPUT;
9368 /* Get the X image IMG->pixmap. */
9369 ximg = XGetImage (NULL, img->pixmap,
9370 0, 0, img->width, img->height, ~0, ZPixmap);
9372 /* Allocate 3 input rows, and one output row of colors. */
9373 for (i = 0; i < 3; ++i)
9374 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9375 out = (long *) alloca (img->width * sizeof (long));
9377 /* Create an X image for output. */
9378 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9379 &oimg, &pixmap);
9381 /* Fill first two rows. */
9382 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9383 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9384 in_y = 2;
9386 /* Write first row, all zeros. */
9387 init_color_table ();
9388 pixel = lookup_rgb_color (f, 0, 0, 0);
9389 for (x = 0; x < img->width; ++x)
9390 out[x] = pixel;
9391 x_laplace_write_row (f, out, img->width, oimg, 0);
9392 out_y = 1;
9394 for (y = 2; y < img->height; ++y)
9396 int rowa = y % 3;
9397 int rowb = (y + 2) % 3;
9399 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9401 for (x = 0; x < img->width - 2; ++x)
9403 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9404 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9405 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9407 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9408 b & 0xffff);
9411 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9414 /* Write last line, all zeros. */
9415 for (x = 0; x < img->width; ++x)
9416 out[x] = pixel;
9417 x_laplace_write_row (f, out, img->width, oimg, out_y);
9419 /* Free the input image, and free resources of IMG. */
9420 XDestroyImage (ximg);
9421 x_clear_image (f, img);
9423 /* Put the output image into pixmap, and destroy it. */
9424 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9425 x_destroy_x_image (oimg);
9427 /* Remember new pixmap and colors in IMG. */
9428 img->pixmap = pixmap;
9429 img->colors = colors_in_color_table (&img->ncolors);
9430 free_color_table ();
9432 UNBLOCK_INPUT;
9433 #endif /* NTEMACS_TODO */
9437 /* Build a mask for image IMG which is used on frame F. FILE is the
9438 name of an image file, for error messages. HOW determines how to
9439 determine the background color of IMG. If it is a list '(R G B)',
9440 with R, G, and B being integers >= 0, take that as the color of the
9441 background. Otherwise, determine the background color of IMG
9442 heuristically. Value is non-zero if successful. */
9444 static int
9445 x_build_heuristic_mask (f, img, how)
9446 struct frame *f;
9447 struct image *img;
9448 Lisp_Object how;
9450 #if 0 /* NTEMACS_TODO : W32 version */
9451 Display *dpy = FRAME_W32_DISPLAY (f);
9452 XImage *ximg, *mask_img;
9453 int x, y, rc, look_at_corners_p;
9454 unsigned long bg;
9456 BLOCK_INPUT;
9458 /* Create an image and pixmap serving as mask. */
9459 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9460 &mask_img, &img->mask);
9461 if (!rc)
9463 UNBLOCK_INPUT;
9464 return 0;
9467 /* Get the X image of IMG->pixmap. */
9468 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9469 ~0, ZPixmap);
9471 /* Determine the background color of ximg. If HOW is `(R G B)'
9472 take that as color. Otherwise, try to determine the color
9473 heuristically. */
9474 look_at_corners_p = 1;
9476 if (CONSP (how))
9478 int rgb[3], i = 0;
9480 while (i < 3
9481 && CONSP (how)
9482 && NATNUMP (XCAR (how)))
9484 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9485 how = XCDR (how);
9488 if (i == 3 && NILP (how))
9490 char color_name[30];
9491 XColor exact, color;
9492 Colormap cmap;
9494 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9496 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9497 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9499 bg = color.pixel;
9500 look_at_corners_p = 0;
9505 if (look_at_corners_p)
9507 unsigned long corners[4];
9508 int i, best_count;
9510 /* Get the colors at the corners of ximg. */
9511 corners[0] = XGetPixel (ximg, 0, 0);
9512 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9513 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9514 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9516 /* Choose the most frequently found color as background. */
9517 for (i = best_count = 0; i < 4; ++i)
9519 int j, n;
9521 for (j = n = 0; j < 4; ++j)
9522 if (corners[i] == corners[j])
9523 ++n;
9525 if (n > best_count)
9526 bg = corners[i], best_count = n;
9530 /* Set all bits in mask_img to 1 whose color in ximg is different
9531 from the background color bg. */
9532 for (y = 0; y < img->height; ++y)
9533 for (x = 0; x < img->width; ++x)
9534 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9536 /* Put mask_img into img->mask. */
9537 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9538 x_destroy_x_image (mask_img);
9539 XDestroyImage (ximg);
9541 UNBLOCK_INPUT;
9542 #endif /* NTEMACS_TODO */
9544 return 1;
9549 /***********************************************************************
9550 PBM (mono, gray, color)
9551 ***********************************************************************/
9552 #ifdef HAVE_PBM
9554 static int pbm_image_p P_ ((Lisp_Object object));
9555 static int pbm_load P_ ((struct frame *f, struct image *img));
9556 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9558 /* The symbol `pbm' identifying images of this type. */
9560 Lisp_Object Qpbm;
9562 /* Indices of image specification fields in gs_format, below. */
9564 enum pbm_keyword_index
9566 PBM_TYPE,
9567 PBM_FILE,
9568 PBM_DATA,
9569 PBM_ASCENT,
9570 PBM_MARGIN,
9571 PBM_RELIEF,
9572 PBM_ALGORITHM,
9573 PBM_HEURISTIC_MASK,
9574 PBM_LAST
9577 /* Vector of image_keyword structures describing the format
9578 of valid user-defined image specifications. */
9580 static struct image_keyword pbm_format[PBM_LAST] =
9582 {":type", IMAGE_SYMBOL_VALUE, 1},
9583 {":file", IMAGE_STRING_VALUE, 0},
9584 {":data", IMAGE_STRING_VALUE, 0},
9585 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9586 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9587 {":relief", IMAGE_INTEGER_VALUE, 0},
9588 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9589 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9592 /* Structure describing the image type `pbm'. */
9594 static struct image_type pbm_type =
9596 &Qpbm,
9597 pbm_image_p,
9598 pbm_load,
9599 x_clear_image,
9600 NULL
9604 /* Return non-zero if OBJECT is a valid PBM image specification. */
9606 static int
9607 pbm_image_p (object)
9608 Lisp_Object object;
9610 struct image_keyword fmt[PBM_LAST];
9612 bcopy (pbm_format, fmt, sizeof fmt);
9614 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9615 || (fmt[PBM_ASCENT].count
9616 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9617 return 0;
9619 /* Must specify either :data or :file. */
9620 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9624 /* Scan a decimal number from *S and return it. Advance *S while
9625 reading the number. END is the end of the string. Value is -1 at
9626 end of input. */
9628 static int
9629 pbm_scan_number (s, end)
9630 unsigned char **s, *end;
9632 int c, val = -1;
9634 while (*s < end)
9636 /* Skip white-space. */
9637 while (*s < end && (c = *(*s)++, isspace (c)))
9640 if (c == '#')
9642 /* Skip comment to end of line. */
9643 while (*s < end && (c = *(*s)++, c != '\n'))
9646 else if (isdigit (c))
9648 /* Read decimal number. */
9649 val = c - '0';
9650 while (*s < end && (c = *(*s)++, isdigit (c)))
9651 val = 10 * val + c - '0';
9652 break;
9654 else
9655 break;
9658 return val;
9662 /* Read FILE into memory. Value is a pointer to a buffer allocated
9663 with xmalloc holding FILE's contents. Value is null if an error
9664 occured. *SIZE is set to the size of the file. */
9666 static char *
9667 pbm_read_file (file, size)
9668 Lisp_Object file;
9669 int *size;
9671 FILE *fp = NULL;
9672 char *buf = NULL;
9673 struct stat st;
9675 if (stat (XSTRING (file)->data, &st) == 0
9676 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9677 && (buf = (char *) xmalloc (st.st_size),
9678 fread (buf, 1, st.st_size, fp) == st.st_size))
9680 *size = st.st_size;
9681 fclose (fp);
9683 else
9685 if (fp)
9686 fclose (fp);
9687 if (buf)
9689 xfree (buf);
9690 buf = NULL;
9694 return buf;
9698 /* Load PBM image IMG for use on frame F. */
9700 static int
9701 pbm_load (f, img)
9702 struct frame *f;
9703 struct image *img;
9705 int raw_p, x, y;
9706 int width, height, max_color_idx = 0;
9707 XImage *ximg;
9708 Lisp_Object file, specified_file;
9709 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9710 struct gcpro gcpro1;
9711 unsigned char *contents = NULL;
9712 unsigned char *end, *p;
9713 int size;
9715 specified_file = image_spec_value (img->spec, QCfile, NULL);
9716 file = Qnil;
9717 GCPRO1 (file);
9719 if (STRINGP (specified_file))
9721 file = x_find_image_file (specified_file);
9722 if (!STRINGP (file))
9724 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9725 UNGCPRO;
9726 return 0;
9729 contents = pbm_read_file (file, &size);
9730 if (contents == NULL)
9732 image_error ("Error reading `%s'", file, Qnil);
9733 UNGCPRO;
9734 return 0;
9737 p = contents;
9738 end = contents + size;
9740 else
9742 Lisp_Object data;
9743 data = image_spec_value (img->spec, QCdata, NULL);
9744 p = XSTRING (data)->data;
9745 end = p + STRING_BYTES (XSTRING (data));
9748 /* Check magic number. */
9749 if (end - p < 2 || *p++ != 'P')
9751 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9752 error:
9753 xfree (contents);
9754 UNGCPRO;
9755 return 0;
9758 switch (*p++)
9760 case '1':
9761 raw_p = 0, type = PBM_MONO;
9762 break;
9764 case '2':
9765 raw_p = 0, type = PBM_GRAY;
9766 break;
9768 case '3':
9769 raw_p = 0, type = PBM_COLOR;
9770 break;
9772 case '4':
9773 raw_p = 1, type = PBM_MONO;
9774 break;
9776 case '5':
9777 raw_p = 1, type = PBM_GRAY;
9778 break;
9780 case '6':
9781 raw_p = 1, type = PBM_COLOR;
9782 break;
9784 default:
9785 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9786 goto error;
9789 /* Read width, height, maximum color-component. Characters
9790 starting with `#' up to the end of a line are ignored. */
9791 width = pbm_scan_number (&p, end);
9792 height = pbm_scan_number (&p, end);
9794 if (type != PBM_MONO)
9796 max_color_idx = pbm_scan_number (&p, end);
9797 if (raw_p && max_color_idx > 255)
9798 max_color_idx = 255;
9801 if (width < 0
9802 || height < 0
9803 || (type != PBM_MONO && max_color_idx < 0))
9804 goto error;
9806 BLOCK_INPUT;
9807 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9808 &ximg, &img->pixmap))
9810 UNBLOCK_INPUT;
9811 goto error;
9814 /* Initialize the color hash table. */
9815 init_color_table ();
9817 if (type == PBM_MONO)
9819 int c = 0, g;
9821 for (y = 0; y < height; ++y)
9822 for (x = 0; x < width; ++x)
9824 if (raw_p)
9826 if ((x & 7) == 0)
9827 c = *p++;
9828 g = c & 0x80;
9829 c <<= 1;
9831 else
9832 g = pbm_scan_number (&p, end);
9834 XPutPixel (ximg, x, y, (g
9835 ? FRAME_FOREGROUND_PIXEL (f)
9836 : FRAME_BACKGROUND_PIXEL (f)));
9839 else
9841 for (y = 0; y < height; ++y)
9842 for (x = 0; x < width; ++x)
9844 int r, g, b;
9846 if (type == PBM_GRAY)
9847 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
9848 else if (raw_p)
9850 r = *p++;
9851 g = *p++;
9852 b = *p++;
9854 else
9856 r = pbm_scan_number (&p, end);
9857 g = pbm_scan_number (&p, end);
9858 b = pbm_scan_number (&p, end);
9861 if (r < 0 || g < 0 || b < 0)
9863 xfree (ximg->data);
9864 ximg->data = NULL;
9865 XDestroyImage (ximg);
9866 UNBLOCK_INPUT;
9867 image_error ("Invalid pixel value in image `%s'",
9868 img->spec, Qnil);
9869 goto error;
9872 /* RGB values are now in the range 0..max_color_idx.
9873 Scale this to the range 0..0xffff supported by X. */
9874 r = (double) r * 65535 / max_color_idx;
9875 g = (double) g * 65535 / max_color_idx;
9876 b = (double) b * 65535 / max_color_idx;
9877 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9881 /* Store in IMG->colors the colors allocated for the image, and
9882 free the color table. */
9883 img->colors = colors_in_color_table (&img->ncolors);
9884 free_color_table ();
9886 /* Put the image into a pixmap. */
9887 x_put_x_image (f, ximg, img->pixmap, width, height);
9888 x_destroy_x_image (ximg);
9889 UNBLOCK_INPUT;
9891 img->width = width;
9892 img->height = height;
9894 UNGCPRO;
9895 xfree (contents);
9896 return 1;
9898 #endif /* HAVE_PBM */
9901 /***********************************************************************
9903 ***********************************************************************/
9905 #if HAVE_PNG
9907 #include <png.h>
9909 /* Function prototypes. */
9911 static int png_image_p P_ ((Lisp_Object object));
9912 static int png_load P_ ((struct frame *f, struct image *img));
9914 /* The symbol `png' identifying images of this type. */
9916 Lisp_Object Qpng;
9918 /* Indices of image specification fields in png_format, below. */
9920 enum png_keyword_index
9922 PNG_TYPE,
9923 PNG_DATA,
9924 PNG_FILE,
9925 PNG_ASCENT,
9926 PNG_MARGIN,
9927 PNG_RELIEF,
9928 PNG_ALGORITHM,
9929 PNG_HEURISTIC_MASK,
9930 PNG_LAST
9933 /* Vector of image_keyword structures describing the format
9934 of valid user-defined image specifications. */
9936 static struct image_keyword png_format[PNG_LAST] =
9938 {":type", IMAGE_SYMBOL_VALUE, 1},
9939 {":data", IMAGE_STRING_VALUE, 0},
9940 {":file", IMAGE_STRING_VALUE, 0},
9941 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9942 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9943 {":relief", IMAGE_INTEGER_VALUE, 0},
9944 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9945 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9948 /* Structure describing the image type `png'. */
9950 static struct image_type png_type =
9952 &Qpng,
9953 png_image_p,
9954 png_load,
9955 x_clear_image,
9956 NULL
9960 /* Return non-zero if OBJECT is a valid PNG image specification. */
9962 static int
9963 png_image_p (object)
9964 Lisp_Object object;
9966 struct image_keyword fmt[PNG_LAST];
9967 bcopy (png_format, fmt, sizeof fmt);
9969 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
9970 || (fmt[PNG_ASCENT].count
9971 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
9972 return 0;
9974 /* Must specify either the :data or :file keyword. */
9975 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
9979 /* Error and warning handlers installed when the PNG library
9980 is initialized. */
9982 static void
9983 my_png_error (png_ptr, msg)
9984 png_struct *png_ptr;
9985 char *msg;
9987 xassert (png_ptr != NULL);
9988 image_error ("PNG error: %s", build_string (msg), Qnil);
9989 longjmp (png_ptr->jmpbuf, 1);
9993 static void
9994 my_png_warning (png_ptr, msg)
9995 png_struct *png_ptr;
9996 char *msg;
9998 xassert (png_ptr != NULL);
9999 image_error ("PNG warning: %s", build_string (msg), Qnil);
10002 /* Memory source for PNG decoding. */
10004 struct png_memory_storage
10006 unsigned char *bytes; /* The data */
10007 size_t len; /* How big is it? */
10008 int index; /* Where are we? */
10012 /* Function set as reader function when reading PNG image from memory.
10013 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10014 bytes from the input to DATA. */
10016 static void
10017 png_read_from_memory (png_ptr, data, length)
10018 png_structp png_ptr;
10019 png_bytep data;
10020 png_size_t length;
10022 struct png_memory_storage *tbr
10023 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10025 if (length > tbr->len - tbr->index)
10026 png_error (png_ptr, "Read error");
10028 bcopy (tbr->bytes + tbr->index, data, length);
10029 tbr->index = tbr->index + length;
10032 /* Load PNG image IMG for use on frame F. Value is non-zero if
10033 successful. */
10035 static int
10036 png_load (f, img)
10037 struct frame *f;
10038 struct image *img;
10040 Lisp_Object file, specified_file;
10041 Lisp_Object specified_data;
10042 int x, y, i;
10043 XImage *ximg, *mask_img = NULL;
10044 struct gcpro gcpro1;
10045 png_struct *png_ptr = NULL;
10046 png_info *info_ptr = NULL, *end_info = NULL;
10047 FILE *fp = NULL;
10048 png_byte sig[8];
10049 png_byte *pixels = NULL;
10050 png_byte **rows = NULL;
10051 png_uint_32 width, height;
10052 int bit_depth, color_type, interlace_type;
10053 png_byte channels;
10054 png_uint_32 row_bytes;
10055 int transparent_p;
10056 char *gamma_str;
10057 double screen_gamma, image_gamma;
10058 int intent;
10059 struct png_memory_storage tbr; /* Data to be read */
10061 /* Find out what file to load. */
10062 specified_file = image_spec_value (img->spec, QCfile, NULL);
10063 specified_data = image_spec_value (img->spec, QCdata, NULL);
10064 file = Qnil;
10065 GCPRO1 (file);
10067 if (NILP (specified_data))
10069 file = x_find_image_file (specified_file);
10070 if (!STRINGP (file))
10072 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10073 UNGCPRO;
10074 return 0;
10077 /* Open the image file. */
10078 fp = fopen (XSTRING (file)->data, "rb");
10079 if (!fp)
10081 image_error ("Cannot open image file `%s'", file, Qnil);
10082 UNGCPRO;
10083 fclose (fp);
10084 return 0;
10087 /* Check PNG signature. */
10088 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10089 || !png_check_sig (sig, sizeof sig))
10091 image_error ("Not a PNG file:` %s'", file, Qnil);
10092 UNGCPRO;
10093 fclose (fp);
10094 return 0;
10097 else
10099 /* Read from memory. */
10100 tbr.bytes = XSTRING (specified_data)->data;
10101 tbr.len = STRING_BYTES (XSTRING (specified_data));
10102 tbr.index = 0;
10104 /* Check PNG signature. */
10105 if (tbr.len < sizeof sig
10106 || !png_check_sig (tbr.bytes, sizeof sig))
10108 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10109 UNGCPRO;
10110 return 0;
10113 /* Need to skip past the signature. */
10114 tbr.bytes += sizeof (sig);
10117 /* Initialize read and info structs for PNG lib. */
10118 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10119 my_png_error, my_png_warning);
10120 if (!png_ptr)
10122 if (fp) fclose (fp);
10123 UNGCPRO;
10124 return 0;
10127 info_ptr = png_create_info_struct (png_ptr);
10128 if (!info_ptr)
10130 png_destroy_read_struct (&png_ptr, NULL, NULL);
10131 if (fp) fclose (fp);
10132 UNGCPRO;
10133 return 0;
10136 end_info = png_create_info_struct (png_ptr);
10137 if (!end_info)
10139 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10140 if (fp) fclose (fp);
10141 UNGCPRO;
10142 return 0;
10145 /* Set error jump-back. We come back here when the PNG library
10146 detects an error. */
10147 if (setjmp (png_ptr->jmpbuf))
10149 error:
10150 if (png_ptr)
10151 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10152 xfree (pixels);
10153 xfree (rows);
10154 if (fp) fclose (fp);
10155 UNGCPRO;
10156 return 0;
10159 /* Read image info. */
10160 if (!NILP (specified_data))
10161 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10162 else
10163 png_init_io (png_ptr, fp);
10165 png_set_sig_bytes (png_ptr, sizeof sig);
10166 png_read_info (png_ptr, info_ptr);
10167 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10168 &interlace_type, NULL, NULL);
10170 /* If image contains simply transparency data, we prefer to
10171 construct a clipping mask. */
10172 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10173 transparent_p = 1;
10174 else
10175 transparent_p = 0;
10177 /* This function is easier to write if we only have to handle
10178 one data format: RGB or RGBA with 8 bits per channel. Let's
10179 transform other formats into that format. */
10181 /* Strip more than 8 bits per channel. */
10182 if (bit_depth == 16)
10183 png_set_strip_16 (png_ptr);
10185 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10186 if available. */
10187 png_set_expand (png_ptr);
10189 /* Convert grayscale images to RGB. */
10190 if (color_type == PNG_COLOR_TYPE_GRAY
10191 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10192 png_set_gray_to_rgb (png_ptr);
10194 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10195 gamma_str = getenv ("SCREEN_GAMMA");
10196 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10198 /* Tell the PNG lib to handle gamma correction for us. */
10200 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10201 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10202 /* There is a special chunk in the image specifying the gamma. */
10203 png_set_sRGB (png_ptr, info_ptr, intent);
10204 else
10205 #endif
10206 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10207 /* Image contains gamma information. */
10208 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10209 else
10210 /* Use a default of 0.5 for the image gamma. */
10211 png_set_gamma (png_ptr, screen_gamma, 0.5);
10213 /* Handle alpha channel by combining the image with a background
10214 color. Do this only if a real alpha channel is supplied. For
10215 simple transparency, we prefer a clipping mask. */
10216 if (!transparent_p)
10218 png_color_16 *image_background;
10220 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10221 /* Image contains a background color with which to
10222 combine the image. */
10223 png_set_background (png_ptr, image_background,
10224 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10225 else
10227 /* Image does not contain a background color with which
10228 to combine the image data via an alpha channel. Use
10229 the frame's background instead. */
10230 XColor color;
10231 Colormap cmap;
10232 png_color_16 frame_background;
10234 BLOCK_INPUT;
10235 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10236 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10237 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10238 UNBLOCK_INPUT;
10240 bzero (&frame_background, sizeof frame_background);
10241 frame_background.red = color.red;
10242 frame_background.green = color.green;
10243 frame_background.blue = color.blue;
10245 png_set_background (png_ptr, &frame_background,
10246 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10250 /* Update info structure. */
10251 png_read_update_info (png_ptr, info_ptr);
10253 /* Get number of channels. Valid values are 1 for grayscale images
10254 and images with a palette, 2 for grayscale images with transparency
10255 information (alpha channel), 3 for RGB images, and 4 for RGB
10256 images with alpha channel, i.e. RGBA. If conversions above were
10257 sufficient we should only have 3 or 4 channels here. */
10258 channels = png_get_channels (png_ptr, info_ptr);
10259 xassert (channels == 3 || channels == 4);
10261 /* Number of bytes needed for one row of the image. */
10262 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10264 /* Allocate memory for the image. */
10265 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10266 rows = (png_byte **) xmalloc (height * sizeof *rows);
10267 for (i = 0; i < height; ++i)
10268 rows[i] = pixels + i * row_bytes;
10270 /* Read the entire image. */
10271 png_read_image (png_ptr, rows);
10272 png_read_end (png_ptr, info_ptr);
10273 if (fp)
10275 fclose (fp);
10276 fp = NULL;
10279 BLOCK_INPUT;
10281 /* Create the X image and pixmap. */
10282 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10283 &img->pixmap))
10285 UNBLOCK_INPUT;
10286 goto error;
10289 /* Create an image and pixmap serving as mask if the PNG image
10290 contains an alpha channel. */
10291 if (channels == 4
10292 && !transparent_p
10293 && !x_create_x_image_and_pixmap (f, width, height, 1,
10294 &mask_img, &img->mask))
10296 x_destroy_x_image (ximg);
10297 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10298 img->pixmap = 0;
10299 UNBLOCK_INPUT;
10300 goto error;
10303 /* Fill the X image and mask from PNG data. */
10304 init_color_table ();
10306 for (y = 0; y < height; ++y)
10308 png_byte *p = rows[y];
10310 for (x = 0; x < width; ++x)
10312 unsigned r, g, b;
10314 r = *p++ << 8;
10315 g = *p++ << 8;
10316 b = *p++ << 8;
10317 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10319 /* An alpha channel, aka mask channel, associates variable
10320 transparency with an image. Where other image formats
10321 support binary transparency---fully transparent or fully
10322 opaque---PNG allows up to 254 levels of partial transparency.
10323 The PNG library implements partial transparency by combining
10324 the image with a specified background color.
10326 I'm not sure how to handle this here nicely: because the
10327 background on which the image is displayed may change, for
10328 real alpha channel support, it would be necessary to create
10329 a new image for each possible background.
10331 What I'm doing now is that a mask is created if we have
10332 boolean transparency information. Otherwise I'm using
10333 the frame's background color to combine the image with. */
10335 if (channels == 4)
10337 if (mask_img)
10338 XPutPixel (mask_img, x, y, *p > 0);
10339 ++p;
10344 /* Remember colors allocated for this image. */
10345 img->colors = colors_in_color_table (&img->ncolors);
10346 free_color_table ();
10348 /* Clean up. */
10349 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10350 xfree (rows);
10351 xfree (pixels);
10353 img->width = width;
10354 img->height = height;
10356 /* Put the image into the pixmap, then free the X image and its buffer. */
10357 x_put_x_image (f, ximg, img->pixmap, width, height);
10358 x_destroy_x_image (ximg);
10360 /* Same for the mask. */
10361 if (mask_img)
10363 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10364 x_destroy_x_image (mask_img);
10367 UNBLOCK_INPUT;
10368 UNGCPRO;
10369 return 1;
10372 #endif /* HAVE_PNG != 0 */
10376 /***********************************************************************
10377 JPEG
10378 ***********************************************************************/
10380 #if HAVE_JPEG
10382 /* Work around a warning about HAVE_STDLIB_H being redefined in
10383 jconfig.h. */
10384 #ifdef HAVE_STDLIB_H
10385 #define HAVE_STDLIB_H_1
10386 #undef HAVE_STDLIB_H
10387 #endif /* HAVE_STLIB_H */
10389 #include <jpeglib.h>
10390 #include <jerror.h>
10391 #include <setjmp.h>
10393 #ifdef HAVE_STLIB_H_1
10394 #define HAVE_STDLIB_H 1
10395 #endif
10397 static int jpeg_image_p P_ ((Lisp_Object object));
10398 static int jpeg_load P_ ((struct frame *f, struct image *img));
10400 /* The symbol `jpeg' identifying images of this type. */
10402 Lisp_Object Qjpeg;
10404 /* Indices of image specification fields in gs_format, below. */
10406 enum jpeg_keyword_index
10408 JPEG_TYPE,
10409 JPEG_DATA,
10410 JPEG_FILE,
10411 JPEG_ASCENT,
10412 JPEG_MARGIN,
10413 JPEG_RELIEF,
10414 JPEG_ALGORITHM,
10415 JPEG_HEURISTIC_MASK,
10416 JPEG_LAST
10419 /* Vector of image_keyword structures describing the format
10420 of valid user-defined image specifications. */
10422 static struct image_keyword jpeg_format[JPEG_LAST] =
10424 {":type", IMAGE_SYMBOL_VALUE, 1},
10425 {":data", IMAGE_STRING_VALUE, 0},
10426 {":file", IMAGE_STRING_VALUE, 0},
10427 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10428 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10429 {":relief", IMAGE_INTEGER_VALUE, 0},
10430 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10431 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10434 /* Structure describing the image type `jpeg'. */
10436 static struct image_type jpeg_type =
10438 &Qjpeg,
10439 jpeg_image_p,
10440 jpeg_load,
10441 x_clear_image,
10442 NULL
10446 /* Return non-zero if OBJECT is a valid JPEG image specification. */
10448 static int
10449 jpeg_image_p (object)
10450 Lisp_Object object;
10452 struct image_keyword fmt[JPEG_LAST];
10454 bcopy (jpeg_format, fmt, sizeof fmt);
10456 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10457 || (fmt[JPEG_ASCENT].count
10458 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10459 return 0;
10461 /* Must specify either the :data or :file keyword. */
10462 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10466 struct my_jpeg_error_mgr
10468 struct jpeg_error_mgr pub;
10469 jmp_buf setjmp_buffer;
10472 static void
10473 my_error_exit (cinfo)
10474 j_common_ptr cinfo;
10476 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10477 longjmp (mgr->setjmp_buffer, 1);
10480 /* Init source method for JPEG data source manager. Called by
10481 jpeg_read_header() before any data is actually read. See
10482 libjpeg.doc from the JPEG lib distribution. */
10484 static void
10485 our_init_source (cinfo)
10486 j_decompress_ptr cinfo;
10491 /* Fill input buffer method for JPEG data source manager. Called
10492 whenever more data is needed. We read the whole image in one step,
10493 so this only adds a fake end of input marker at the end. */
10495 static boolean
10496 our_fill_input_buffer (cinfo)
10497 j_decompress_ptr cinfo;
10499 /* Insert a fake EOI marker. */
10500 struct jpeg_source_mgr *src = cinfo->src;
10501 static JOCTET buffer[2];
10503 buffer[0] = (JOCTET) 0xFF;
10504 buffer[1] = (JOCTET) JPEG_EOI;
10506 src->next_input_byte = buffer;
10507 src->bytes_in_buffer = 2;
10508 return TRUE;
10512 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10513 is the JPEG data source manager. */
10515 static void
10516 our_skip_input_data (cinfo, num_bytes)
10517 j_decompress_ptr cinfo;
10518 long num_bytes;
10520 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10522 if (src)
10524 if (num_bytes > src->bytes_in_buffer)
10525 ERREXIT (cinfo, JERR_INPUT_EOF);
10527 src->bytes_in_buffer -= num_bytes;
10528 src->next_input_byte += num_bytes;
10533 /* Method to terminate data source. Called by
10534 jpeg_finish_decompress() after all data has been processed. */
10536 static void
10537 our_term_source (cinfo)
10538 j_decompress_ptr cinfo;
10543 /* Set up the JPEG lib for reading an image from DATA which contains
10544 LEN bytes. CINFO is the decompression info structure created for
10545 reading the image. */
10547 static void
10548 jpeg_memory_src (cinfo, data, len)
10549 j_decompress_ptr cinfo;
10550 JOCTET *data;
10551 unsigned int len;
10553 struct jpeg_source_mgr *src;
10555 if (cinfo->src == NULL)
10557 /* First time for this JPEG object? */
10558 cinfo->src = (struct jpeg_source_mgr *)
10559 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10560 sizeof (struct jpeg_source_mgr));
10561 src = (struct jpeg_source_mgr *) cinfo->src;
10562 src->next_input_byte = data;
10565 src = (struct jpeg_source_mgr *) cinfo->src;
10566 src->init_source = our_init_source;
10567 src->fill_input_buffer = our_fill_input_buffer;
10568 src->skip_input_data = our_skip_input_data;
10569 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10570 src->term_source = our_term_source;
10571 src->bytes_in_buffer = len;
10572 src->next_input_byte = data;
10576 /* Load image IMG for use on frame F. Patterned after example.c
10577 from the JPEG lib. */
10579 static int
10580 jpeg_load (f, img)
10581 struct frame *f;
10582 struct image *img;
10584 struct jpeg_decompress_struct cinfo;
10585 struct my_jpeg_error_mgr mgr;
10586 Lisp_Object file, specified_file;
10587 Lisp_Object specified_data;
10588 FILE *fp = NULL;
10589 JSAMPARRAY buffer;
10590 int row_stride, x, y;
10591 XImage *ximg = NULL;
10592 int rc;
10593 unsigned long *colors;
10594 int width, height;
10595 struct gcpro gcpro1;
10597 /* Open the JPEG file. */
10598 specified_file = image_spec_value (img->spec, QCfile, NULL);
10599 specified_data = image_spec_value (img->spec, QCdata, NULL);
10600 file = Qnil;
10601 GCPRO1 (file);
10603 if (NILP (specified_data))
10605 file = x_find_image_file (specified_file);
10606 if (!STRINGP (file))
10608 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10609 UNGCPRO;
10610 return 0;
10613 fp = fopen (XSTRING (file)->data, "r");
10614 if (fp == NULL)
10616 image_error ("Cannot open `%s'", file, Qnil);
10617 UNGCPRO;
10618 return 0;
10622 /* Customize libjpeg's error handling to call my_error_exit when an
10623 error is detected. This function will perform a longjmp. */
10624 mgr.pub.error_exit = my_error_exit;
10625 cinfo.err = jpeg_std_error (&mgr.pub);
10627 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10629 if (rc == 1)
10631 /* Called from my_error_exit. Display a JPEG error. */
10632 char buffer[JMSG_LENGTH_MAX];
10633 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10634 image_error ("Error reading JPEG image `%s': %s", img->spec,
10635 build_string (buffer));
10638 /* Close the input file and destroy the JPEG object. */
10639 if (fp)
10640 fclose (fp);
10641 jpeg_destroy_decompress (&cinfo);
10643 BLOCK_INPUT;
10645 /* If we already have an XImage, free that. */
10646 x_destroy_x_image (ximg);
10648 /* Free pixmap and colors. */
10649 x_clear_image (f, img);
10651 UNBLOCK_INPUT;
10652 UNGCPRO;
10653 return 0;
10656 /* Create the JPEG decompression object. Let it read from fp.
10657 Read the JPEG image header. */
10658 jpeg_create_decompress (&cinfo);
10660 if (NILP (specified_data))
10661 jpeg_stdio_src (&cinfo, fp);
10662 else
10663 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10664 STRING_BYTES (XSTRING (specified_data)));
10666 jpeg_read_header (&cinfo, TRUE);
10668 /* Customize decompression so that color quantization will be used.
10669 Start decompression. */
10670 cinfo.quantize_colors = TRUE;
10671 jpeg_start_decompress (&cinfo);
10672 width = img->width = cinfo.output_width;
10673 height = img->height = cinfo.output_height;
10675 BLOCK_INPUT;
10677 /* Create X image and pixmap. */
10678 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10679 &img->pixmap))
10681 UNBLOCK_INPUT;
10682 longjmp (mgr.setjmp_buffer, 2);
10685 /* Allocate colors. When color quantization is used,
10686 cinfo.actual_number_of_colors has been set with the number of
10687 colors generated, and cinfo.colormap is a two-dimensional array
10688 of color indices in the range 0..cinfo.actual_number_of_colors.
10689 No more than 255 colors will be generated. */
10691 int i, ir, ig, ib;
10693 if (cinfo.out_color_components > 2)
10694 ir = 0, ig = 1, ib = 2;
10695 else if (cinfo.out_color_components > 1)
10696 ir = 0, ig = 1, ib = 0;
10697 else
10698 ir = 0, ig = 0, ib = 0;
10700 /* Use the color table mechanism because it handles colors that
10701 cannot be allocated nicely. Such colors will be replaced with
10702 a default color, and we don't have to care about which colors
10703 can be freed safely, and which can't. */
10704 init_color_table ();
10705 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10706 * sizeof *colors);
10708 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10710 /* Multiply RGB values with 255 because X expects RGB values
10711 in the range 0..0xffff. */
10712 int r = cinfo.colormap[ir][i] << 8;
10713 int g = cinfo.colormap[ig][i] << 8;
10714 int b = cinfo.colormap[ib][i] << 8;
10715 colors[i] = lookup_rgb_color (f, r, g, b);
10718 /* Remember those colors actually allocated. */
10719 img->colors = colors_in_color_table (&img->ncolors);
10720 free_color_table ();
10723 /* Read pixels. */
10724 row_stride = width * cinfo.output_components;
10725 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10726 row_stride, 1);
10727 for (y = 0; y < height; ++y)
10729 jpeg_read_scanlines (&cinfo, buffer, 1);
10730 for (x = 0; x < cinfo.output_width; ++x)
10731 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10734 /* Clean up. */
10735 jpeg_finish_decompress (&cinfo);
10736 jpeg_destroy_decompress (&cinfo);
10737 if (fp)
10738 fclose (fp);
10740 /* Put the image into the pixmap. */
10741 x_put_x_image (f, ximg, img->pixmap, width, height);
10742 x_destroy_x_image (ximg);
10743 UNBLOCK_INPUT;
10744 UNGCPRO;
10745 return 1;
10748 #endif /* HAVE_JPEG */
10752 /***********************************************************************
10753 TIFF
10754 ***********************************************************************/
10756 #if HAVE_TIFF
10758 #include <tiffio.h>
10760 static int tiff_image_p P_ ((Lisp_Object object));
10761 static int tiff_load P_ ((struct frame *f, struct image *img));
10763 /* The symbol `tiff' identifying images of this type. */
10765 Lisp_Object Qtiff;
10767 /* Indices of image specification fields in tiff_format, below. */
10769 enum tiff_keyword_index
10771 TIFF_TYPE,
10772 TIFF_DATA,
10773 TIFF_FILE,
10774 TIFF_ASCENT,
10775 TIFF_MARGIN,
10776 TIFF_RELIEF,
10777 TIFF_ALGORITHM,
10778 TIFF_HEURISTIC_MASK,
10779 TIFF_LAST
10782 /* Vector of image_keyword structures describing the format
10783 of valid user-defined image specifications. */
10785 static struct image_keyword tiff_format[TIFF_LAST] =
10787 {":type", IMAGE_SYMBOL_VALUE, 1},
10788 {":data", IMAGE_STRING_VALUE, 0},
10789 {":file", IMAGE_STRING_VALUE, 0},
10790 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10791 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10792 {":relief", IMAGE_INTEGER_VALUE, 0},
10793 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10794 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10797 /* Structure describing the image type `tiff'. */
10799 static struct image_type tiff_type =
10801 &Qtiff,
10802 tiff_image_p,
10803 tiff_load,
10804 x_clear_image,
10805 NULL
10809 /* Return non-zero if OBJECT is a valid TIFF image specification. */
10811 static int
10812 tiff_image_p (object)
10813 Lisp_Object object;
10815 struct image_keyword fmt[TIFF_LAST];
10816 bcopy (tiff_format, fmt, sizeof fmt);
10818 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
10819 || (fmt[TIFF_ASCENT].count
10820 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
10821 return 0;
10823 /* Must specify either the :data or :file keyword. */
10824 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
10828 /* Reading from a memory buffer for TIFF images Based on the PNG
10829 memory source, but we have to provide a lot of extra functions.
10830 Blah.
10832 We really only need to implement read and seek, but I am not
10833 convinced that the TIFF library is smart enough not to destroy
10834 itself if we only hand it the function pointers we need to
10835 override. */
10837 typedef struct
10839 unsigned char *bytes;
10840 size_t len;
10841 int index;
10843 tiff_memory_source;
10845 static size_t
10846 tiff_read_from_memory (data, buf, size)
10847 thandle_t data;
10848 tdata_t buf;
10849 tsize_t size;
10851 tiff_memory_source *src = (tiff_memory_source *) data;
10853 if (size > src->len - src->index)
10854 return (size_t) -1;
10855 bcopy (src->bytes + src->index, buf, size);
10856 src->index += size;
10857 return size;
10860 static size_t
10861 tiff_write_from_memory (data, buf, size)
10862 thandle_t data;
10863 tdata_t buf;
10864 tsize_t size;
10866 return (size_t) -1;
10869 static toff_t
10870 tiff_seek_in_memory (data, off, whence)
10871 thandle_t data;
10872 toff_t off;
10873 int whence;
10875 tiff_memory_source *src = (tiff_memory_source *) data;
10876 int idx;
10878 switch (whence)
10880 case SEEK_SET: /* Go from beginning of source. */
10881 idx = off;
10882 break;
10884 case SEEK_END: /* Go from end of source. */
10885 idx = src->len + off;
10886 break;
10888 case SEEK_CUR: /* Go from current position. */
10889 idx = src->index + off;
10890 break;
10892 default: /* Invalid `whence'. */
10893 return -1;
10896 if (idx > src->len || idx < 0)
10897 return -1;
10899 src->index = idx;
10900 return src->index;
10903 static int
10904 tiff_close_memory (data)
10905 thandle_t data;
10907 /* NOOP */
10908 return 0;
10911 static int
10912 tiff_mmap_memory (data, pbase, psize)
10913 thandle_t data;
10914 tdata_t *pbase;
10915 toff_t *psize;
10917 /* It is already _IN_ memory. */
10918 return 0;
10921 static void
10922 tiff_unmap_memory (data, base, size)
10923 thandle_t data;
10924 tdata_t base;
10925 toff_t size;
10927 /* We don't need to do this. */
10930 static toff_t
10931 tiff_size_of_memory (data)
10932 thandle_t data;
10934 return ((tiff_memory_source *) data)->len;
10937 /* Load TIFF image IMG for use on frame F. Value is non-zero if
10938 successful. */
10940 static int
10941 tiff_load (f, img)
10942 struct frame *f;
10943 struct image *img;
10945 Lisp_Object file, specified_file;
10946 Lisp_Object specified_data;
10947 TIFF *tiff;
10948 int width, height, x, y;
10949 uint32 *buf;
10950 int rc;
10951 XImage *ximg;
10952 struct gcpro gcpro1;
10953 tiff_memory_source memsrc;
10955 specified_file = image_spec_value (img->spec, QCfile, NULL);
10956 specified_data = image_spec_value (img->spec, QCdata, NULL);
10957 file = Qnil;
10958 GCPRO1 (file);
10960 if (NILP (specified_data))
10962 /* Read from a file */
10963 file = x_find_image_file (specified_file);
10964 if (!STRINGP (file))
10966 image_error ("Cannot find image file `%s'", file, Qnil);
10967 UNGCPRO;
10968 return 0;
10971 /* Try to open the image file. */
10972 tiff = TIFFOpen (XSTRING (file)->data, "r");
10973 if (tiff == NULL)
10975 image_error ("Cannot open `%s'", file, Qnil);
10976 UNGCPRO;
10977 return 0;
10980 else
10982 /* Memory source! */
10983 memsrc.bytes = XSTRING (specified_data)->data;
10984 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10985 memsrc.index = 0;
10987 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
10988 (TIFFReadWriteProc) tiff_read_from_memory,
10989 (TIFFReadWriteProc) tiff_write_from_memory,
10990 tiff_seek_in_memory,
10991 tiff_close_memory,
10992 tiff_size_of_memory,
10993 tiff_mmap_memory,
10994 tiff_unmap_memory);
10996 if (!tiff)
10998 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
10999 UNGCPRO;
11000 return 0;
11004 /* Get width and height of the image, and allocate a raster buffer
11005 of width x height 32-bit values. */
11006 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11007 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11008 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11010 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11011 TIFFClose (tiff);
11012 if (!rc)
11014 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11015 xfree (buf);
11016 UNGCPRO;
11017 return 0;
11020 BLOCK_INPUT;
11022 /* Create the X image and pixmap. */
11023 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11025 UNBLOCK_INPUT;
11026 xfree (buf);
11027 UNGCPRO;
11028 return 0;
11031 /* Initialize the color table. */
11032 init_color_table ();
11034 /* Process the pixel raster. Origin is in the lower-left corner. */
11035 for (y = 0; y < height; ++y)
11037 uint32 *row = buf + y * width;
11039 for (x = 0; x < width; ++x)
11041 uint32 abgr = row[x];
11042 int r = TIFFGetR (abgr) << 8;
11043 int g = TIFFGetG (abgr) << 8;
11044 int b = TIFFGetB (abgr) << 8;
11045 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11049 /* Remember the colors allocated for the image. Free the color table. */
11050 img->colors = colors_in_color_table (&img->ncolors);
11051 free_color_table ();
11053 /* Put the image into the pixmap, then free the X image and its buffer. */
11054 x_put_x_image (f, ximg, img->pixmap, width, height);
11055 x_destroy_x_image (ximg);
11056 xfree (buf);
11057 UNBLOCK_INPUT;
11059 img->width = width;
11060 img->height = height;
11062 UNGCPRO;
11063 return 1;
11066 #endif /* HAVE_TIFF != 0 */
11070 /***********************************************************************
11072 ***********************************************************************/
11074 #if HAVE_GIF
11076 #include <gif_lib.h>
11078 static int gif_image_p P_ ((Lisp_Object object));
11079 static int gif_load P_ ((struct frame *f, struct image *img));
11081 /* The symbol `gif' identifying images of this type. */
11083 Lisp_Object Qgif;
11085 /* Indices of image specification fields in gif_format, below. */
11087 enum gif_keyword_index
11089 GIF_TYPE,
11090 GIF_DATA,
11091 GIF_FILE,
11092 GIF_ASCENT,
11093 GIF_MARGIN,
11094 GIF_RELIEF,
11095 GIF_ALGORITHM,
11096 GIF_HEURISTIC_MASK,
11097 GIF_IMAGE,
11098 GIF_LAST
11101 /* Vector of image_keyword structures describing the format
11102 of valid user-defined image specifications. */
11104 static struct image_keyword gif_format[GIF_LAST] =
11106 {":type", IMAGE_SYMBOL_VALUE, 1},
11107 {":data", IMAGE_STRING_VALUE, 0},
11108 {":file", IMAGE_STRING_VALUE, 0},
11109 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11110 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11111 {":relief", IMAGE_INTEGER_VALUE, 0},
11112 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11113 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11114 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11117 /* Structure describing the image type `gif'. */
11119 static struct image_type gif_type =
11121 &Qgif,
11122 gif_image_p,
11123 gif_load,
11124 x_clear_image,
11125 NULL
11128 /* Return non-zero if OBJECT is a valid GIF image specification. */
11130 static int
11131 gif_image_p (object)
11132 Lisp_Object object;
11134 struct image_keyword fmt[GIF_LAST];
11135 bcopy (gif_format, fmt, sizeof fmt);
11137 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11138 || (fmt[GIF_ASCENT].count
11139 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11140 return 0;
11142 /* Must specify either the :data or :file keyword. */
11143 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11146 /* Reading a GIF image from memory
11147 Based on the PNG memory stuff to a certain extent. */
11149 typedef struct
11151 unsigned char *bytes;
11152 size_t len;
11153 int index;
11155 gif_memory_source;
11157 /* Make the current memory source available to gif_read_from_memory.
11158 It's done this way because not all versions of libungif support
11159 a UserData field in the GifFileType structure. */
11160 static gif_memory_source *current_gif_memory_src;
11162 static int
11163 gif_read_from_memory (file, buf, len)
11164 GifFileType *file;
11165 GifByteType *buf;
11166 int len;
11168 gif_memory_source *src = current_gif_memory_src;
11170 if (len > src->len - src->index)
11171 return -1;
11173 bcopy (src->bytes + src->index, buf, len);
11174 src->index += len;
11175 return len;
11179 /* Load GIF image IMG for use on frame F. Value is non-zero if
11180 successful. */
11182 static int
11183 gif_load (f, img)
11184 struct frame *f;
11185 struct image *img;
11187 Lisp_Object file, specified_file;
11188 Lisp_Object specified_data;
11189 int rc, width, height, x, y, i;
11190 XImage *ximg;
11191 ColorMapObject *gif_color_map;
11192 unsigned long pixel_colors[256];
11193 GifFileType *gif;
11194 struct gcpro gcpro1;
11195 Lisp_Object image;
11196 int ino, image_left, image_top, image_width, image_height;
11197 gif_memory_source memsrc;
11198 unsigned char *raster;
11200 specified_file = image_spec_value (img->spec, QCfile, NULL);
11201 specified_data = image_spec_value (img->spec, QCdata, NULL);
11202 file = Qnil;
11203 GCPRO1 (file);
11205 if (NILP (specified_data))
11207 file = x_find_image_file (specified_file);
11208 if (!STRINGP (file))
11210 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11211 UNGCPRO;
11212 return 0;
11215 /* Open the GIF file. */
11216 gif = DGifOpenFileName (XSTRING (file)->data);
11217 if (gif == NULL)
11219 image_error ("Cannot open `%s'", file, Qnil);
11220 UNGCPRO;
11221 return 0;
11224 else
11226 /* Read from memory! */
11227 current_gif_memory_src = &memsrc;
11228 memsrc.bytes = XSTRING (specified_data)->data;
11229 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11230 memsrc.index = 0;
11232 gif = DGifOpen(&memsrc, gif_read_from_memory);
11233 if (!gif)
11235 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11236 UNGCPRO;
11237 return 0;
11241 /* Read entire contents. */
11242 rc = DGifSlurp (gif);
11243 if (rc == GIF_ERROR)
11245 image_error ("Error reading `%s'", img->spec, Qnil);
11246 DGifCloseFile (gif);
11247 UNGCPRO;
11248 return 0;
11251 image = image_spec_value (img->spec, QCindex, NULL);
11252 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11253 if (ino >= gif->ImageCount)
11255 image_error ("Invalid image number `%s' in image `%s'",
11256 image, img->spec);
11257 DGifCloseFile (gif);
11258 UNGCPRO;
11259 return 0;
11262 width = img->width = gif->SWidth;
11263 height = img->height = gif->SHeight;
11265 BLOCK_INPUT;
11267 /* Create the X image and pixmap. */
11268 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11270 UNBLOCK_INPUT;
11271 DGifCloseFile (gif);
11272 UNGCPRO;
11273 return 0;
11276 /* Allocate colors. */
11277 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11278 if (!gif_color_map)
11279 gif_color_map = gif->SColorMap;
11280 init_color_table ();
11281 bzero (pixel_colors, sizeof pixel_colors);
11283 for (i = 0; i < gif_color_map->ColorCount; ++i)
11285 int r = gif_color_map->Colors[i].Red << 8;
11286 int g = gif_color_map->Colors[i].Green << 8;
11287 int b = gif_color_map->Colors[i].Blue << 8;
11288 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11291 img->colors = colors_in_color_table (&img->ncolors);
11292 free_color_table ();
11294 /* Clear the part of the screen image that are not covered by
11295 the image from the GIF file. Full animated GIF support
11296 requires more than can be done here (see the gif89 spec,
11297 disposal methods). Let's simply assume that the part
11298 not covered by a sub-image is in the frame's background color. */
11299 image_top = gif->SavedImages[ino].ImageDesc.Top;
11300 image_left = gif->SavedImages[ino].ImageDesc.Left;
11301 image_width = gif->SavedImages[ino].ImageDesc.Width;
11302 image_height = gif->SavedImages[ino].ImageDesc.Height;
11304 for (y = 0; y < image_top; ++y)
11305 for (x = 0; x < width; ++x)
11306 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11308 for (y = image_top + image_height; y < height; ++y)
11309 for (x = 0; x < width; ++x)
11310 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11312 for (y = image_top; y < image_top + image_height; ++y)
11314 for (x = 0; x < image_left; ++x)
11315 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11316 for (x = image_left + image_width; x < width; ++x)
11317 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11320 /* Read the GIF image into the X image. We use a local variable
11321 `raster' here because RasterBits below is a char *, and invites
11322 problems with bytes >= 0x80. */
11323 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11325 if (gif->SavedImages[ino].ImageDesc.Interlace)
11327 static int interlace_start[] = {0, 4, 2, 1};
11328 static int interlace_increment[] = {8, 8, 4, 2};
11329 int pass, inc;
11330 int row = interlace_start[0];
11332 pass = 0;
11334 for (y = 0; y < image_height; y++)
11336 if (row >= image_height)
11338 row = interlace_start[++pass];
11339 while (row >= image_height)
11340 row = interlace_start[++pass];
11343 for (x = 0; x < image_width; x++)
11345 int i = raster[(y * image_width) + x];
11346 XPutPixel (ximg, x + image_left, row + image_top,
11347 pixel_colors[i]);
11350 row += interlace_increment[pass];
11353 else
11355 for (y = 0; y < image_height; ++y)
11356 for (x = 0; x < image_width; ++x)
11358 int i = raster[y* image_width + x];
11359 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11363 DGifCloseFile (gif);
11365 /* Put the image into the pixmap, then free the X image and its buffer. */
11366 x_put_x_image (f, ximg, img->pixmap, width, height);
11367 x_destroy_x_image (ximg);
11368 UNBLOCK_INPUT;
11370 UNGCPRO;
11371 return 1;
11374 #endif /* HAVE_GIF != 0 */
11378 /***********************************************************************
11379 Ghostscript
11380 ***********************************************************************/
11382 #ifdef HAVE_GHOSTSCRIPT
11383 static int gs_image_p P_ ((Lisp_Object object));
11384 static int gs_load P_ ((struct frame *f, struct image *img));
11385 static void gs_clear_image P_ ((struct frame *f, struct image *img));
11387 /* The symbol `postscript' identifying images of this type. */
11389 Lisp_Object Qpostscript;
11391 /* Keyword symbols. */
11393 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11395 /* Indices of image specification fields in gs_format, below. */
11397 enum gs_keyword_index
11399 GS_TYPE,
11400 GS_PT_WIDTH,
11401 GS_PT_HEIGHT,
11402 GS_FILE,
11403 GS_LOADER,
11404 GS_BOUNDING_BOX,
11405 GS_ASCENT,
11406 GS_MARGIN,
11407 GS_RELIEF,
11408 GS_ALGORITHM,
11409 GS_HEURISTIC_MASK,
11410 GS_LAST
11413 /* Vector of image_keyword structures describing the format
11414 of valid user-defined image specifications. */
11416 static struct image_keyword gs_format[GS_LAST] =
11418 {":type", IMAGE_SYMBOL_VALUE, 1},
11419 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11420 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11421 {":file", IMAGE_STRING_VALUE, 1},
11422 {":loader", IMAGE_FUNCTION_VALUE, 0},
11423 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11424 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11425 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11426 {":relief", IMAGE_INTEGER_VALUE, 0},
11427 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11428 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11431 /* Structure describing the image type `ghostscript'. */
11433 static struct image_type gs_type =
11435 &Qpostscript,
11436 gs_image_p,
11437 gs_load,
11438 gs_clear_image,
11439 NULL
11443 /* Free X resources of Ghostscript image IMG which is used on frame F. */
11445 static void
11446 gs_clear_image (f, img)
11447 struct frame *f;
11448 struct image *img;
11450 /* IMG->data.ptr_val may contain a recorded colormap. */
11451 xfree (img->data.ptr_val);
11452 x_clear_image (f, img);
11456 /* Return non-zero if OBJECT is a valid Ghostscript image
11457 specification. */
11459 static int
11460 gs_image_p (object)
11461 Lisp_Object object;
11463 struct image_keyword fmt[GS_LAST];
11464 Lisp_Object tem;
11465 int i;
11467 bcopy (gs_format, fmt, sizeof fmt);
11469 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11470 || (fmt[GS_ASCENT].count
11471 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11472 return 0;
11474 /* Bounding box must be a list or vector containing 4 integers. */
11475 tem = fmt[GS_BOUNDING_BOX].value;
11476 if (CONSP (tem))
11478 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11479 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11480 return 0;
11481 if (!NILP (tem))
11482 return 0;
11484 else if (VECTORP (tem))
11486 if (XVECTOR (tem)->size != 4)
11487 return 0;
11488 for (i = 0; i < 4; ++i)
11489 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11490 return 0;
11492 else
11493 return 0;
11495 return 1;
11499 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
11500 if successful. */
11502 static int
11503 gs_load (f, img)
11504 struct frame *f;
11505 struct image *img;
11507 char buffer[100];
11508 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11509 struct gcpro gcpro1, gcpro2;
11510 Lisp_Object frame;
11511 double in_width, in_height;
11512 Lisp_Object pixel_colors = Qnil;
11514 /* Compute pixel size of pixmap needed from the given size in the
11515 image specification. Sizes in the specification are in pt. 1 pt
11516 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11517 info. */
11518 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11519 in_width = XFASTINT (pt_width) / 72.0;
11520 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11521 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11522 in_height = XFASTINT (pt_height) / 72.0;
11523 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11525 /* Create the pixmap. */
11526 BLOCK_INPUT;
11527 xassert (img->pixmap == 0);
11528 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11529 img->width, img->height,
11530 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11531 UNBLOCK_INPUT;
11533 if (!img->pixmap)
11535 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11536 return 0;
11539 /* Call the loader to fill the pixmap. It returns a process object
11540 if successful. We do not record_unwind_protect here because
11541 other places in redisplay like calling window scroll functions
11542 don't either. Let the Lisp loader use `unwind-protect' instead. */
11543 GCPRO2 (window_and_pixmap_id, pixel_colors);
11545 sprintf (buffer, "%lu %lu",
11546 (unsigned long) FRAME_W32_WINDOW (f),
11547 (unsigned long) img->pixmap);
11548 window_and_pixmap_id = build_string (buffer);
11550 sprintf (buffer, "%lu %lu",
11551 FRAME_FOREGROUND_PIXEL (f),
11552 FRAME_BACKGROUND_PIXEL (f));
11553 pixel_colors = build_string (buffer);
11555 XSETFRAME (frame, f);
11556 loader = image_spec_value (img->spec, QCloader, NULL);
11557 if (NILP (loader))
11558 loader = intern ("gs-load-image");
11560 img->data.lisp_val = call6 (loader, frame, img->spec,
11561 make_number (img->width),
11562 make_number (img->height),
11563 window_and_pixmap_id,
11564 pixel_colors);
11565 UNGCPRO;
11566 return PROCESSP (img->data.lisp_val);
11570 /* Kill the Ghostscript process that was started to fill PIXMAP on
11571 frame F. Called from XTread_socket when receiving an event
11572 telling Emacs that Ghostscript has finished drawing. */
11574 void
11575 x_kill_gs_process (pixmap, f)
11576 Pixmap pixmap;
11577 struct frame *f;
11579 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11580 int class, i;
11581 struct image *img;
11583 /* Find the image containing PIXMAP. */
11584 for (i = 0; i < c->used; ++i)
11585 if (c->images[i]->pixmap == pixmap)
11586 break;
11588 /* Kill the GS process. We should have found PIXMAP in the image
11589 cache and its image should contain a process object. */
11590 xassert (i < c->used);
11591 img = c->images[i];
11592 xassert (PROCESSP (img->data.lisp_val));
11593 Fkill_process (img->data.lisp_val, Qnil);
11594 img->data.lisp_val = Qnil;
11596 /* On displays with a mutable colormap, figure out the colors
11597 allocated for the image by looking at the pixels of an XImage for
11598 img->pixmap. */
11599 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11600 if (class != StaticColor && class != StaticGray && class != TrueColor)
11602 XImage *ximg;
11604 BLOCK_INPUT;
11606 /* Try to get an XImage for img->pixmep. */
11607 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11608 0, 0, img->width, img->height, ~0, ZPixmap);
11609 if (ximg)
11611 int x, y;
11613 /* Initialize the color table. */
11614 init_color_table ();
11616 /* For each pixel of the image, look its color up in the
11617 color table. After having done so, the color table will
11618 contain an entry for each color used by the image. */
11619 for (y = 0; y < img->height; ++y)
11620 for (x = 0; x < img->width; ++x)
11622 unsigned long pixel = XGetPixel (ximg, x, y);
11623 lookup_pixel_color (f, pixel);
11626 /* Record colors in the image. Free color table and XImage. */
11627 img->colors = colors_in_color_table (&img->ncolors);
11628 free_color_table ();
11629 XDestroyImage (ximg);
11631 #if 0 /* This doesn't seem to be the case. If we free the colors
11632 here, we get a BadAccess later in x_clear_image when
11633 freeing the colors. */
11634 /* We have allocated colors once, but Ghostscript has also
11635 allocated colors on behalf of us. So, to get the
11636 reference counts right, free them once. */
11637 if (img->ncolors)
11639 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11640 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11641 img->colors, img->ncolors, 0);
11643 #endif
11645 else
11646 image_error ("Cannot get X image of `%s'; colors will not be freed",
11647 img->spec, Qnil);
11649 UNBLOCK_INPUT;
11653 #endif /* HAVE_GHOSTSCRIPT */
11656 /***********************************************************************
11657 Window properties
11658 ***********************************************************************/
11660 DEFUN ("x-change-window-property", Fx_change_window_property,
11661 Sx_change_window_property, 2, 3, 0,
11662 "Change window property PROP to VALUE on the X window of FRAME.\n\
11663 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11664 selected frame. Value is VALUE.")
11665 (prop, value, frame)
11666 Lisp_Object frame, prop, value;
11668 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11669 struct frame *f = check_x_frame (frame);
11670 Atom prop_atom;
11672 CHECK_STRING (prop, 1);
11673 CHECK_STRING (value, 2);
11675 BLOCK_INPUT;
11676 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11677 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11678 prop_atom, XA_STRING, 8, PropModeReplace,
11679 XSTRING (value)->data, XSTRING (value)->size);
11681 /* Make sure the property is set when we return. */
11682 XFlush (FRAME_W32_DISPLAY (f));
11683 UNBLOCK_INPUT;
11685 #endif /* NTEMACS_TODO */
11687 return value;
11691 DEFUN ("x-delete-window-property", Fx_delete_window_property,
11692 Sx_delete_window_property, 1, 2, 0,
11693 "Remove window property PROP from X window of FRAME.\n\
11694 FRAME nil or omitted means use the selected frame. Value is PROP.")
11695 (prop, frame)
11696 Lisp_Object prop, frame;
11698 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11700 struct frame *f = check_x_frame (frame);
11701 Atom prop_atom;
11703 CHECK_STRING (prop, 1);
11704 BLOCK_INPUT;
11705 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11706 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11708 /* Make sure the property is removed when we return. */
11709 XFlush (FRAME_W32_DISPLAY (f));
11710 UNBLOCK_INPUT;
11711 #endif /* NTEMACS_TODO */
11713 return prop;
11717 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11718 1, 2, 0,
11719 "Value is the value of window property PROP on FRAME.\n\
11720 If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11721 if FRAME hasn't a property with name PROP or if PROP has no string\n\
11722 value.")
11723 (prop, frame)
11724 Lisp_Object prop, frame;
11726 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11728 struct frame *f = check_x_frame (frame);
11729 Atom prop_atom;
11730 int rc;
11731 Lisp_Object prop_value = Qnil;
11732 char *tmp_data = NULL;
11733 Atom actual_type;
11734 int actual_format;
11735 unsigned long actual_size, bytes_remaining;
11737 CHECK_STRING (prop, 1);
11738 BLOCK_INPUT;
11739 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11740 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11741 prop_atom, 0, 0, False, XA_STRING,
11742 &actual_type, &actual_format, &actual_size,
11743 &bytes_remaining, (unsigned char **) &tmp_data);
11744 if (rc == Success)
11746 int size = bytes_remaining;
11748 XFree (tmp_data);
11749 tmp_data = NULL;
11751 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11752 prop_atom, 0, bytes_remaining,
11753 False, XA_STRING,
11754 &actual_type, &actual_format,
11755 &actual_size, &bytes_remaining,
11756 (unsigned char **) &tmp_data);
11757 if (rc == Success)
11758 prop_value = make_string (tmp_data, size);
11760 XFree (tmp_data);
11763 UNBLOCK_INPUT;
11765 return prop_value;
11767 #endif /* NTEMACS_TODO */
11768 return Qnil;
11773 /***********************************************************************
11774 Busy cursor
11775 ***********************************************************************/
11777 /* If non-null, an asynchronous timer that, when it expires, displays
11778 a busy cursor on all frames. */
11780 static struct atimer *busy_cursor_atimer;
11782 /* Non-zero means a busy cursor is currently shown. */
11784 static int busy_cursor_shown_p;
11786 /* Number of seconds to wait before displaying a busy cursor. */
11788 static Lisp_Object Vbusy_cursor_delay;
11790 /* Default number of seconds to wait before displaying a busy
11791 cursor. */
11793 #define DEFAULT_BUSY_CURSOR_DELAY 1
11795 /* Function prototypes. */
11797 static void show_busy_cursor P_ ((struct atimer *));
11798 static void hide_busy_cursor P_ ((void));
11801 /* Cancel a currently active busy-cursor timer, and start a new one. */
11803 void
11804 start_busy_cursor ()
11806 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11807 EMACS_TIME delay;
11808 int secs, usecs = 0;
11810 cancel_busy_cursor ();
11812 if (INTEGERP (Vbusy_cursor_delay)
11813 && XINT (Vbusy_cursor_delay) > 0)
11814 secs = XFASTINT (Vbusy_cursor_delay);
11815 else if (FLOATP (Vbusy_cursor_delay)
11816 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
11818 Lisp_Object tem;
11819 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
11820 secs = XFASTINT (tem);
11821 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
11823 else
11824 secs = DEFAULT_BUSY_CURSOR_DELAY;
11826 EMACS_SET_SECS_USECS (delay, secs, usecs);
11827 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
11828 show_busy_cursor, NULL);
11829 #endif
11833 /* Cancel the busy cursor timer if active, hide a busy cursor if
11834 shown. */
11836 void
11837 cancel_busy_cursor ()
11839 if (busy_cursor_atimer)
11841 cancel_atimer (busy_cursor_atimer);
11842 busy_cursor_atimer = NULL;
11845 if (busy_cursor_shown_p)
11846 hide_busy_cursor ();
11850 /* Timer function of busy_cursor_atimer. TIMER is equal to
11851 busy_cursor_atimer.
11853 Display a busy cursor on all frames by mapping the frames'
11854 busy_window. Set the busy_p flag in the frames' output_data.x
11855 structure to indicate that a busy cursor is shown on the
11856 frames. */
11858 static void
11859 show_busy_cursor (timer)
11860 struct atimer *timer;
11862 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11863 /* The timer implementation will cancel this timer automatically
11864 after this function has run. Set busy_cursor_atimer to null
11865 so that we know the timer doesn't have to be canceled. */
11866 busy_cursor_atimer = NULL;
11868 if (!busy_cursor_shown_p)
11870 Lisp_Object rest, frame;
11872 BLOCK_INPUT;
11874 FOR_EACH_FRAME (rest, frame)
11875 if (FRAME_X_P (XFRAME (frame)))
11877 struct frame *f = XFRAME (frame);
11879 f->output_data.w32->busy_p = 1;
11881 if (!f->output_data.w32->busy_window)
11883 unsigned long mask = CWCursor;
11884 XSetWindowAttributes attrs;
11886 attrs.cursor = f->output_data.w32->busy_cursor;
11888 f->output_data.w32->busy_window
11889 = XCreateWindow (FRAME_X_DISPLAY (f),
11890 FRAME_OUTER_WINDOW (f),
11891 0, 0, 32000, 32000, 0, 0,
11892 InputOnly,
11893 CopyFromParent,
11894 mask, &attrs);
11897 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
11898 XFlush (FRAME_X_DISPLAY (f));
11901 busy_cursor_shown_p = 1;
11902 UNBLOCK_INPUT;
11904 #endif
11908 /* Hide the busy cursor on all frames, if it is currently shown. */
11910 static void
11911 hide_busy_cursor ()
11913 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11914 if (busy_cursor_shown_p)
11916 Lisp_Object rest, frame;
11918 BLOCK_INPUT;
11919 FOR_EACH_FRAME (rest, frame)
11921 struct frame *f = XFRAME (frame);
11923 if (FRAME_X_P (f)
11924 /* Watch out for newly created frames. */
11925 && f->output_data.x->busy_window)
11927 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
11928 /* Sync here because XTread_socket looks at the busy_p flag
11929 that is reset to zero below. */
11930 XSync (FRAME_X_DISPLAY (f), False);
11931 f->output_data.x->busy_p = 0;
11935 busy_cursor_shown_p = 0;
11936 UNBLOCK_INPUT;
11938 #endif
11943 /***********************************************************************
11944 Tool tips
11945 ***********************************************************************/
11947 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
11948 Lisp_Object));
11950 /* The frame of a currently visible tooltip, or null. */
11952 struct frame *tip_frame;
11954 /* If non-nil, a timer started that hides the last tooltip when it
11955 fires. */
11957 Lisp_Object tip_timer;
11958 Window tip_window;
11960 /* Create a frame for a tooltip on the display described by DPYINFO.
11961 PARMS is a list of frame parameters. Value is the frame. */
11963 static Lisp_Object
11964 x_create_tip_frame (dpyinfo, parms)
11965 struct w32_display_info *dpyinfo;
11966 Lisp_Object parms;
11968 #if 0 /* NTEMACS_TODO : w32 version */
11969 struct frame *f;
11970 Lisp_Object frame, tem;
11971 Lisp_Object name;
11972 long window_prompting = 0;
11973 int width, height;
11974 int count = specpdl_ptr - specpdl;
11975 struct gcpro gcpro1, gcpro2, gcpro3;
11976 struct kboard *kb;
11978 check_x ();
11980 /* Use this general default value to start with until we know if
11981 this frame has a specified name. */
11982 Vx_resource_name = Vinvocation_name;
11984 #ifdef MULTI_KBOARD
11985 kb = dpyinfo->kboard;
11986 #else
11987 kb = &the_only_kboard;
11988 #endif
11990 /* Get the name of the frame to use for resource lookup. */
11991 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
11992 if (!STRINGP (name)
11993 && !EQ (name, Qunbound)
11994 && !NILP (name))
11995 error ("Invalid frame name--not a string or nil");
11996 Vx_resource_name = name;
11998 frame = Qnil;
11999 GCPRO3 (parms, name, frame);
12000 tip_frame = f = make_frame (1);
12001 XSETFRAME (frame, f);
12002 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
12004 f->output_method = output_w32;
12005 f->output_data.w32 =
12006 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12007 bzero (f->output_data.w32, sizeof (struct w32_output));
12008 #if 0
12009 f->output_data.w32->icon_bitmap = -1;
12010 #endif
12011 f->output_data.w32->fontset = -1;
12012 f->icon_name = Qnil;
12014 #ifdef MULTI_KBOARD
12015 FRAME_KBOARD (f) = kb;
12016 #endif
12017 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12018 f->output_data.w32->explicit_parent = 0;
12020 /* Set the name; the functions to which we pass f expect the name to
12021 be set. */
12022 if (EQ (name, Qunbound) || NILP (name))
12024 f->name = build_string (dpyinfo->x_id_name);
12025 f->explicit_name = 0;
12027 else
12029 f->name = name;
12030 f->explicit_name = 1;
12031 /* use the frame's title when getting resources for this frame. */
12032 specbind (Qx_resource_name, name);
12035 /* Extract the window parameters from the supplied values
12036 that are needed to determine window geometry. */
12038 Lisp_Object font;
12040 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12042 BLOCK_INPUT;
12043 /* First, try whatever font the caller has specified. */
12044 if (STRINGP (font))
12046 tem = Fquery_fontset (font, Qnil);
12047 if (STRINGP (tem))
12048 font = x_new_fontset (f, XSTRING (tem)->data);
12049 else
12050 font = x_new_font (f, XSTRING (font)->data);
12053 /* Try out a font which we hope has bold and italic variations. */
12054 if (!STRINGP (font))
12055 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
12056 if (!STRINGP (font))
12057 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12058 if (! STRINGP (font))
12059 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12060 if (! STRINGP (font))
12061 /* This was formerly the first thing tried, but it finds too many fonts
12062 and takes too long. */
12063 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12064 /* If those didn't work, look for something which will at least work. */
12065 if (! STRINGP (font))
12066 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12067 UNBLOCK_INPUT;
12068 if (! STRINGP (font))
12069 font = build_string ("fixed");
12071 x_default_parameter (f, parms, Qfont, font,
12072 "font", "Font", RES_TYPE_STRING);
12075 x_default_parameter (f, parms, Qborder_width, make_number (2),
12076 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12078 /* This defaults to 2 in order to match xterm. We recognize either
12079 internalBorderWidth or internalBorder (which is what xterm calls
12080 it). */
12081 if (NILP (Fassq (Qinternal_border_width, parms)))
12083 Lisp_Object value;
12085 value = w32_get_arg (parms, Qinternal_border_width,
12086 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12087 if (! EQ (value, Qunbound))
12088 parms = Fcons (Fcons (Qinternal_border_width, value),
12089 parms);
12092 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12093 "internalBorderWidth", "internalBorderWidth",
12094 RES_TYPE_NUMBER);
12096 /* Also do the stuff which must be set before the window exists. */
12097 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12098 "foreground", "Foreground", RES_TYPE_STRING);
12099 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12100 "background", "Background", RES_TYPE_STRING);
12101 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12102 "pointerColor", "Foreground", RES_TYPE_STRING);
12103 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12104 "cursorColor", "Foreground", RES_TYPE_STRING);
12105 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12106 "borderColor", "BorderColor", RES_TYPE_STRING);
12108 /* Init faces before x_default_parameter is called for scroll-bar
12109 parameters because that function calls x_set_scroll_bar_width,
12110 which calls change_frame_size, which calls Fset_window_buffer,
12111 which runs hooks, which call Fvertical_motion. At the end, we
12112 end up in init_iterator with a null face cache, which should not
12113 happen. */
12114 init_frame_faces (f);
12116 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12117 window_prompting = x_figure_window_size (f, parms);
12119 if (window_prompting & XNegative)
12121 if (window_prompting & YNegative)
12122 f->output_data.w32->win_gravity = SouthEastGravity;
12123 else
12124 f->output_data.w32->win_gravity = NorthEastGravity;
12126 else
12128 if (window_prompting & YNegative)
12129 f->output_data.w32->win_gravity = SouthWestGravity;
12130 else
12131 f->output_data.w32->win_gravity = NorthWestGravity;
12134 f->output_data.w32->size_hint_flags = window_prompting;
12136 XSetWindowAttributes attrs;
12137 unsigned long mask;
12139 BLOCK_INPUT;
12140 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12141 /* Window managers looks at the override-redirect flag to
12142 determine whether or net to give windows a decoration (Xlib
12143 3.2.8). */
12144 attrs.override_redirect = True;
12145 attrs.save_under = True;
12146 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12147 /* Arrange for getting MapNotify and UnmapNotify events. */
12148 attrs.event_mask = StructureNotifyMask;
12149 tip_window
12150 = FRAME_W32_WINDOW (f)
12151 = XCreateWindow (FRAME_W32_DISPLAY (f),
12152 FRAME_W32_DISPLAY_INFO (f)->root_window,
12153 /* x, y, width, height */
12154 0, 0, 1, 1,
12155 /* Border. */
12157 CopyFromParent, InputOutput, CopyFromParent,
12158 mask, &attrs);
12159 UNBLOCK_INPUT;
12162 x_make_gc (f);
12164 x_default_parameter (f, parms, Qauto_raise, Qnil,
12165 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12166 x_default_parameter (f, parms, Qauto_lower, Qnil,
12167 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12168 x_default_parameter (f, parms, Qcursor_type, Qbox,
12169 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12171 /* Dimensions, especially f->height, must be done via change_frame_size.
12172 Change will not be effected unless different from the current
12173 f->height. */
12174 width = f->width;
12175 height = f->height;
12176 f->height = 0;
12177 SET_FRAME_WIDTH (f, 0);
12178 change_frame_size (f, height, width, 1, 0, 0);
12180 f->no_split = 1;
12182 UNGCPRO;
12184 /* It is now ok to make the frame official even if we get an error
12185 below. And the frame needs to be on Vframe_list or making it
12186 visible won't work. */
12187 Vframe_list = Fcons (frame, Vframe_list);
12189 /* Now that the frame is official, it counts as a reference to
12190 its display. */
12191 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
12193 return unbind_to (count, frame);
12194 #endif /* NTEMACS_TODO */
12195 return Qnil;
12199 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
12200 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
12201 A tooltip window is a small X window displaying STRING at\n\
12202 the current mouse position.\n\
12203 FRAME nil or omitted means use the selected frame.\n\
12204 PARMS is an optional list of frame parameters which can be\n\
12205 used to change the tooltip's appearance.\n\
12206 Automatically hide the tooltip after TIMEOUT seconds.\n\
12207 TIMEOUT nil means use the default timeout of 5 seconds.")
12208 (string, frame, parms, timeout)
12209 Lisp_Object string, frame, parms, timeout;
12211 struct frame *f;
12212 struct window *w;
12213 Window root, child;
12214 Lisp_Object buffer;
12215 struct buffer *old_buffer;
12216 struct text_pos pos;
12217 int i, width, height;
12218 int root_x, root_y, win_x, win_y;
12219 unsigned pmask;
12220 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12221 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12222 int count = specpdl_ptr - specpdl;
12224 specbind (Qinhibit_redisplay, Qt);
12226 GCPRO4 (string, parms, frame, timeout);
12228 CHECK_STRING (string, 0);
12229 f = check_x_frame (frame);
12230 if (NILP (timeout))
12231 timeout = make_number (5);
12232 else
12233 CHECK_NATNUM (timeout, 2);
12235 /* Hide a previous tip, if any. */
12236 Fx_hide_tip ();
12238 /* Add default values to frame parameters. */
12239 if (NILP (Fassq (Qname, parms)))
12240 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12241 if (NILP (Fassq (Qinternal_border_width, parms)))
12242 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12243 if (NILP (Fassq (Qborder_width, parms)))
12244 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12245 if (NILP (Fassq (Qborder_color, parms)))
12246 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12247 if (NILP (Fassq (Qbackground_color, parms)))
12248 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12249 parms);
12251 /* Create a frame for the tooltip, and record it in the global
12252 variable tip_frame. */
12253 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12254 tip_frame = f = XFRAME (frame);
12256 /* Set up the frame's root window. Currently we use a size of 80
12257 columns x 40 lines. If someone wants to show a larger tip, he
12258 will loose. I don't think this is a realistic case. */
12259 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12260 w->left = w->top = make_number (0);
12261 w->width = 80;
12262 w->height = 40;
12263 adjust_glyphs (f);
12264 w->pseudo_window_p = 1;
12266 /* Display the tooltip text in a temporary buffer. */
12267 buffer = Fget_buffer_create (build_string (" *tip*"));
12268 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12269 old_buffer = current_buffer;
12270 set_buffer_internal_1 (XBUFFER (buffer));
12271 Ferase_buffer ();
12272 Finsert (make_number (1), &string);
12273 clear_glyph_matrix (w->desired_matrix);
12274 clear_glyph_matrix (w->current_matrix);
12275 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12276 try_window (FRAME_ROOT_WINDOW (f), pos);
12278 /* Compute width and height of the tooltip. */
12279 width = height = 0;
12280 for (i = 0; i < w->desired_matrix->nrows; ++i)
12282 struct glyph_row *row = &w->desired_matrix->rows[i];
12283 struct glyph *last;
12284 int row_width;
12286 /* Stop at the first empty row at the end. */
12287 if (!row->enabled_p || !row->displays_text_p)
12288 break;
12290 /* Let the row go over the full width of the frame. */
12291 row->full_width_p = 1;
12293 /* There's a glyph at the end of rows that is use to place
12294 the cursor there. Don't include the width of this glyph. */
12295 if (row->used[TEXT_AREA])
12297 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12298 row_width = row->pixel_width - last->pixel_width;
12300 else
12301 row_width = row->pixel_width;
12303 height += row->height;
12304 width = max (width, row_width);
12307 /* Add the frame's internal border to the width and height the X
12308 window should have. */
12309 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12310 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12312 /* Move the tooltip window where the mouse pointer is. Resize and
12313 show it. */
12314 #if 0 /* NTEMACS_TODO : W32 specifics */
12315 BLOCK_INPUT;
12316 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
12317 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
12318 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12319 root_x + 5, root_y - height - 5, width, height);
12320 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
12321 UNBLOCK_INPUT;
12322 #endif /* NTEMACS_TODO */
12324 /* Draw into the window. */
12325 w->must_be_updated_p = 1;
12326 update_single_window (w, 1);
12328 /* Restore original current buffer. */
12329 set_buffer_internal_1 (old_buffer);
12330 windows_or_buffers_changed = old_windows_or_buffers_changed;
12332 /* Let the tip disappear after timeout seconds. */
12333 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12334 intern ("x-hide-tip"));
12336 UNGCPRO;
12337 return unbind_to (count, Qnil);
12341 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12342 "Hide the current tooltip window, if there is any.\n\
12343 Value is t is tooltip was open, nil otherwise.")
12346 int count = specpdl_ptr - specpdl;
12347 int deleted_p = 0;
12349 specbind (Qinhibit_redisplay, Qt);
12351 if (!NILP (tip_timer))
12353 call1 (intern ("cancel-timer"), tip_timer);
12354 tip_timer = Qnil;
12357 if (tip_frame)
12359 Lisp_Object frame;
12361 XSETFRAME (frame, tip_frame);
12362 Fdelete_frame (frame, Qt);
12363 tip_frame = NULL;
12364 deleted_p = 1;
12367 return unbind_to (count, deleted_p ? Qt : Qnil);
12372 /***********************************************************************
12373 File selection dialog
12374 ***********************************************************************/
12376 extern Lisp_Object Qfile_name_history;
12378 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12379 "Read file name, prompting with PROMPT in directory DIR.\n\
12380 Use a file selection dialog.\n\
12381 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12382 specified. Don't let the user enter a file name in the file\n\
12383 selection dialog's entry field, if MUSTMATCH is non-nil.")
12384 (prompt, dir, default_filename, mustmatch)
12385 Lisp_Object prompt, dir, default_filename, mustmatch;
12387 struct frame *f = SELECTED_FRAME ();
12388 Lisp_Object file = Qnil;
12389 int count = specpdl_ptr - specpdl;
12390 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12391 char filename[MAX_PATH + 1];
12392 char init_dir[MAX_PATH + 1];
12393 int use_dialog_p = 1;
12395 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12396 CHECK_STRING (prompt, 0);
12397 CHECK_STRING (dir, 1);
12399 /* Create the dialog with PROMPT as title, using DIR as initial
12400 directory and using "*" as pattern. */
12401 dir = Fexpand_file_name (dir, Qnil);
12402 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12403 init_dir[MAX_PATH] = '\0';
12404 unixtodos_filename (init_dir);
12406 if (STRINGP (default_filename))
12408 char *file_name_only;
12409 char *full_path_name = XSTRING (default_filename)->data;
12411 unixtodos_filename (full_path_name);
12413 file_name_only = strrchr (full_path_name, '\\');
12414 if (!file_name_only)
12415 file_name_only = full_path_name;
12416 else
12418 file_name_only++;
12420 /* If default_file_name is a directory, don't use the open
12421 file dialog, as it does not support selecting
12422 directories. */
12423 if (!(*file_name_only))
12424 use_dialog_p = 0;
12427 strncpy (filename, file_name_only, MAX_PATH);
12428 filename[MAX_PATH] = '\0';
12430 else
12431 filename[0] = '\0';
12433 if (use_dialog_p)
12435 OPENFILENAME file_details;
12436 char *filename_file;
12438 /* Prevent redisplay. */
12439 specbind (Qinhibit_redisplay, Qt);
12440 BLOCK_INPUT;
12442 bzero (&file_details, sizeof (file_details));
12443 file_details.lStructSize = sizeof (file_details);
12444 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12445 file_details.lpstrFile = filename;
12446 file_details.nMaxFile = sizeof (filename);
12447 file_details.lpstrInitialDir = init_dir;
12448 file_details.lpstrTitle = XSTRING (prompt)->data;
12449 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
12451 if (!NILP (mustmatch))
12452 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
12454 if (GetOpenFileName (&file_details))
12456 dostounix_filename (filename);
12457 file = build_string (filename);
12459 else
12460 file = Qnil;
12462 UNBLOCK_INPUT;
12463 file = unbind_to (count, file);
12465 /* Open File dialog will not allow folders to be selected, so resort
12466 to minibuffer completing reads for directories. */
12467 else
12468 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12469 dir, mustmatch, dir, Qfile_name_history,
12470 default_filename, Qnil);
12472 UNGCPRO;
12474 /* Make "Cancel" equivalent to C-g. */
12475 if (NILP (file))
12476 Fsignal (Qquit, Qnil);
12478 return unbind_to (count, file);
12483 /***********************************************************************
12484 Tests
12485 ***********************************************************************/
12487 #if GLYPH_DEBUG
12489 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12490 "Value is non-nil if SPEC is a valid image specification.")
12491 (spec)
12492 Lisp_Object spec;
12494 return valid_image_p (spec) ? Qt : Qnil;
12498 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12499 (spec)
12500 Lisp_Object spec;
12502 int id = -1;
12504 if (valid_image_p (spec))
12505 id = lookup_image (SELECTED_FRAME (), spec);
12507 debug_print (spec);
12508 return make_number (id);
12511 #endif /* GLYPH_DEBUG != 0 */
12515 /***********************************************************************
12516 w32 specialized functions
12517 ***********************************************************************/
12519 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12520 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
12521 (frame)
12522 Lisp_Object frame;
12524 FRAME_PTR f = check_x_frame (frame);
12525 CHOOSEFONT cf;
12526 LOGFONT lf;
12527 TEXTMETRIC tm;
12528 HDC hdc;
12529 HANDLE oldobj;
12530 char buf[100];
12532 bzero (&cf, sizeof (cf));
12533 bzero (&lf, sizeof (lf));
12535 cf.lStructSize = sizeof (cf);
12536 cf.hwndOwner = FRAME_W32_WINDOW (f);
12537 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
12538 cf.lpLogFont = &lf;
12540 /* Initialize as much of the font details as we can from the current
12541 default font. */
12542 hdc = GetDC (FRAME_W32_WINDOW (f));
12543 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12544 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12545 if (GetTextMetrics (hdc, &tm))
12547 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12548 lf.lfWeight = tm.tmWeight;
12549 lf.lfItalic = tm.tmItalic;
12550 lf.lfUnderline = tm.tmUnderlined;
12551 lf.lfStrikeOut = tm.tmStruckOut;
12552 lf.lfCharSet = tm.tmCharSet;
12553 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12555 SelectObject (hdc, oldobj);
12556 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
12558 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
12559 return Qnil;
12561 return build_string (buf);
12564 DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12565 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12566 Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12567 to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12568 to activate the menubar for keyboard access. 0xf140 activates the\n\
12569 screen saver if defined.\n\
12571 If optional parameter FRAME is not specified, use selected frame.")
12572 (command, frame)
12573 Lisp_Object command, frame;
12575 WPARAM code;
12576 FRAME_PTR f = check_x_frame (frame);
12578 CHECK_NUMBER (command, 0);
12580 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
12582 return Qnil;
12585 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12586 "Get Windows to perform OPERATION on DOCUMENT.\n\
12587 This is a wrapper around the ShellExecute system function, which\n\
12588 invokes the application registered to handle OPERATION for DOCUMENT.\n\
12589 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12590 nil for the default action), and DOCUMENT is typically the name of a\n\
12591 document file or URL, but can also be a program executable to run or\n\
12592 a directory to open in the Windows Explorer.\n\
12594 If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12595 containing command line parameters, but otherwise should be nil.\n\
12597 SHOW-FLAG can be used to control whether the invoked application is hidden\n\
12598 or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
12599 otherwise it is an integer representing a ShowWindow flag:\n\
12601 0 - start hidden\n\
12602 1 - start normally\n\
12603 3 - start maximized\n\
12604 6 - start minimized")
12605 (operation, document, parameters, show_flag)
12606 Lisp_Object operation, document, parameters, show_flag;
12608 Lisp_Object current_dir;
12610 CHECK_STRING (document, 0);
12612 /* Encode filename and current directory. */
12613 current_dir = ENCODE_FILE (current_buffer->directory);
12614 document = ENCODE_FILE (document);
12615 if ((int) ShellExecute (NULL,
12616 (STRINGP (operation) ?
12617 XSTRING (operation)->data : NULL),
12618 XSTRING (document)->data,
12619 (STRINGP (parameters) ?
12620 XSTRING (parameters)->data : NULL),
12621 XSTRING (current_dir)->data,
12622 (INTEGERP (show_flag) ?
12623 XINT (show_flag) : SW_SHOWDEFAULT))
12624 > 32)
12625 return Qt;
12626 error ("ShellExecute failed");
12629 /* Lookup virtual keycode from string representing the name of a
12630 non-ascii keystroke into the corresponding virtual key, using
12631 lispy_function_keys. */
12632 static int
12633 lookup_vk_code (char *key)
12635 int i;
12637 for (i = 0; i < 256; i++)
12638 if (lispy_function_keys[i] != 0
12639 && strcmp (lispy_function_keys[i], key) == 0)
12640 return i;
12642 return -1;
12645 /* Convert a one-element vector style key sequence to a hot key
12646 definition. */
12647 static int
12648 w32_parse_hot_key (key)
12649 Lisp_Object key;
12651 /* Copied from Fdefine_key and store_in_keymap. */
12652 register Lisp_Object c;
12653 int vk_code;
12654 int lisp_modifiers;
12655 int w32_modifiers;
12656 struct gcpro gcpro1;
12658 CHECK_VECTOR (key, 0);
12660 if (XFASTINT (Flength (key)) != 1)
12661 return Qnil;
12663 GCPRO1 (key);
12665 c = Faref (key, make_number (0));
12667 if (CONSP (c) && lucid_event_type_list_p (c))
12668 c = Fevent_convert_list (c);
12670 UNGCPRO;
12672 if (! INTEGERP (c) && ! SYMBOLP (c))
12673 error ("Key definition is invalid");
12675 /* Work out the base key and the modifiers. */
12676 if (SYMBOLP (c))
12678 c = parse_modifiers (c);
12679 lisp_modifiers = Fcar (Fcdr (c));
12680 c = Fcar (c);
12681 if (!SYMBOLP (c))
12682 abort ();
12683 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12685 else if (INTEGERP (c))
12687 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12688 /* Many ascii characters are their own virtual key code. */
12689 vk_code = XINT (c) & CHARACTERBITS;
12692 if (vk_code < 0 || vk_code > 255)
12693 return Qnil;
12695 if ((lisp_modifiers & meta_modifier) != 0
12696 && !NILP (Vw32_alt_is_meta))
12697 lisp_modifiers |= alt_modifier;
12699 /* Convert lisp modifiers to Windows hot-key form. */
12700 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12701 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12702 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12703 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12705 return HOTKEY (vk_code, w32_modifiers);
12708 DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12709 "Register KEY as a hot-key combination.\n\
12710 Certain key combinations like Alt-Tab are reserved for system use on\n\
12711 Windows, and therefore are normally intercepted by the system. However,\n\
12712 most of these key combinations can be received by registering them as\n\
12713 hot-keys, overriding their special meaning.\n\
12715 KEY must be a one element key definition in vector form that would be\n\
12716 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12717 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12718 is always interpreted as the Windows modifier keys.\n\
12720 The return value is the hotkey-id if registered, otherwise nil.")
12721 (key)
12722 Lisp_Object key;
12724 key = w32_parse_hot_key (key);
12726 if (NILP (Fmemq (key, w32_grabbed_keys)))
12728 /* Reuse an empty slot if possible. */
12729 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12731 /* Safe to add new key to list, even if we have focus. */
12732 if (NILP (item))
12733 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
12734 else
12735 XCAR (item) = key;
12737 /* Notify input thread about new hot-key definition, so that it
12738 takes effect without needing to switch focus. */
12739 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
12740 (WPARAM) key, 0);
12743 return key;
12746 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
12747 "Unregister HOTKEY as a hot-key combination.")
12748 (key)
12749 Lisp_Object key;
12751 Lisp_Object item;
12753 if (!INTEGERP (key))
12754 key = w32_parse_hot_key (key);
12756 item = Fmemq (key, w32_grabbed_keys);
12758 if (!NILP (item))
12760 /* Notify input thread about hot-key definition being removed, so
12761 that it takes effect without needing focus switch. */
12762 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
12763 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
12765 MSG msg;
12766 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12768 return Qt;
12770 return Qnil;
12773 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
12774 "Return list of registered hot-key IDs.")
12777 return Fcopy_sequence (w32_grabbed_keys);
12780 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
12781 "Convert hot-key ID to a lisp key combination.")
12782 (hotkeyid)
12783 Lisp_Object hotkeyid;
12785 int vk_code, w32_modifiers;
12786 Lisp_Object key;
12788 CHECK_NUMBER (hotkeyid, 0);
12790 vk_code = HOTKEY_VK_CODE (hotkeyid);
12791 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
12793 if (lispy_function_keys[vk_code])
12794 key = intern (lispy_function_keys[vk_code]);
12795 else
12796 key = make_number (vk_code);
12798 key = Fcons (key, Qnil);
12799 if (w32_modifiers & MOD_SHIFT)
12800 key = Fcons (Qshift, key);
12801 if (w32_modifiers & MOD_CONTROL)
12802 key = Fcons (Qctrl, key);
12803 if (w32_modifiers & MOD_ALT)
12804 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
12805 if (w32_modifiers & MOD_WIN)
12806 key = Fcons (Qhyper, key);
12808 return key;
12811 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
12812 "Toggle the state of the lock key KEY.\n\
12813 KEY can be `capslock', `kp-numlock', or `scroll'.\n\
12814 If the optional parameter NEW-STATE is a number, then the state of KEY\n\
12815 is set to off if the low bit of NEW-STATE is zero, otherwise on.")
12816 (key, new_state)
12817 Lisp_Object key, new_state;
12819 int vk_code;
12820 int cur_state;
12822 if (EQ (key, intern ("capslock")))
12823 vk_code = VK_CAPITAL;
12824 else if (EQ (key, intern ("kp-numlock")))
12825 vk_code = VK_NUMLOCK;
12826 else if (EQ (key, intern ("scroll")))
12827 vk_code = VK_SCROLL;
12828 else
12829 return Qnil;
12831 if (!dwWindowsThreadId)
12832 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
12834 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
12835 (WPARAM) vk_code, (LPARAM) new_state))
12837 MSG msg;
12838 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12839 return make_number (msg.wParam);
12841 return Qnil;
12844 syms_of_w32fns ()
12846 /* This is zero if not using MS-Windows. */
12847 w32_in_use = 0;
12849 /* The section below is built by the lisp expression at the top of the file,
12850 just above where these variables are declared. */
12851 /*&&& init symbols here &&&*/
12852 Qauto_raise = intern ("auto-raise");
12853 staticpro (&Qauto_raise);
12854 Qauto_lower = intern ("auto-lower");
12855 staticpro (&Qauto_lower);
12856 Qbar = intern ("bar");
12857 staticpro (&Qbar);
12858 Qborder_color = intern ("border-color");
12859 staticpro (&Qborder_color);
12860 Qborder_width = intern ("border-width");
12861 staticpro (&Qborder_width);
12862 Qbox = intern ("box");
12863 staticpro (&Qbox);
12864 Qcursor_color = intern ("cursor-color");
12865 staticpro (&Qcursor_color);
12866 Qcursor_type = intern ("cursor-type");
12867 staticpro (&Qcursor_type);
12868 Qgeometry = intern ("geometry");
12869 staticpro (&Qgeometry);
12870 Qicon_left = intern ("icon-left");
12871 staticpro (&Qicon_left);
12872 Qicon_top = intern ("icon-top");
12873 staticpro (&Qicon_top);
12874 Qicon_type = intern ("icon-type");
12875 staticpro (&Qicon_type);
12876 Qicon_name = intern ("icon-name");
12877 staticpro (&Qicon_name);
12878 Qinternal_border_width = intern ("internal-border-width");
12879 staticpro (&Qinternal_border_width);
12880 Qleft = intern ("left");
12881 staticpro (&Qleft);
12882 Qright = intern ("right");
12883 staticpro (&Qright);
12884 Qmouse_color = intern ("mouse-color");
12885 staticpro (&Qmouse_color);
12886 Qnone = intern ("none");
12887 staticpro (&Qnone);
12888 Qparent_id = intern ("parent-id");
12889 staticpro (&Qparent_id);
12890 Qscroll_bar_width = intern ("scroll-bar-width");
12891 staticpro (&Qscroll_bar_width);
12892 Qsuppress_icon = intern ("suppress-icon");
12893 staticpro (&Qsuppress_icon);
12894 Qundefined_color = intern ("undefined-color");
12895 staticpro (&Qundefined_color);
12896 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
12897 staticpro (&Qvertical_scroll_bars);
12898 Qvisibility = intern ("visibility");
12899 staticpro (&Qvisibility);
12900 Qwindow_id = intern ("window-id");
12901 staticpro (&Qwindow_id);
12902 Qx_frame_parameter = intern ("x-frame-parameter");
12903 staticpro (&Qx_frame_parameter);
12904 Qx_resource_name = intern ("x-resource-name");
12905 staticpro (&Qx_resource_name);
12906 Quser_position = intern ("user-position");
12907 staticpro (&Quser_position);
12908 Quser_size = intern ("user-size");
12909 staticpro (&Quser_size);
12910 Qscreen_gamma = intern ("screen-gamma");
12911 staticpro (&Qscreen_gamma);
12912 Qline_spacing = intern ("line-spacing");
12913 staticpro (&Qline_spacing);
12914 Qcenter = intern ("center");
12915 staticpro (&Qcenter);
12916 /* This is the end of symbol initialization. */
12918 Qhyper = intern ("hyper");
12919 staticpro (&Qhyper);
12920 Qsuper = intern ("super");
12921 staticpro (&Qsuper);
12922 Qmeta = intern ("meta");
12923 staticpro (&Qmeta);
12924 Qalt = intern ("alt");
12925 staticpro (&Qalt);
12926 Qctrl = intern ("ctrl");
12927 staticpro (&Qctrl);
12928 Qcontrol = intern ("control");
12929 staticpro (&Qcontrol);
12930 Qshift = intern ("shift");
12931 staticpro (&Qshift);
12933 /* Text property `display' should be nonsticky by default. */
12934 Vtext_property_default_nonsticky
12935 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
12938 Qlaplace = intern ("laplace");
12939 staticpro (&Qlaplace);
12941 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
12942 staticpro (&Qface_set_after_frame_default);
12944 Fput (Qundefined_color, Qerror_conditions,
12945 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
12946 Fput (Qundefined_color, Qerror_message,
12947 build_string ("Undefined color"));
12949 staticpro (&w32_grabbed_keys);
12950 w32_grabbed_keys = Qnil;
12952 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
12953 "An array of color name mappings for windows.");
12954 Vw32_color_map = Qnil;
12956 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
12957 "Non-nil if alt key presses are passed on to Windows.\n\
12958 When non-nil, for example, alt pressed and released and then space will\n\
12959 open the System menu. When nil, Emacs silently swallows alt key events.");
12960 Vw32_pass_alt_to_system = Qnil;
12962 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
12963 "Non-nil if the alt key is to be considered the same as the meta key.\n\
12964 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
12965 Vw32_alt_is_meta = Qt;
12967 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
12968 "If non-zero, the virtual key code for an alternative quit key.");
12969 XSETINT (Vw32_quit_key, 0);
12971 DEFVAR_LISP ("w32-pass-lwindow-to-system",
12972 &Vw32_pass_lwindow_to_system,
12973 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
12974 When non-nil, the Start menu is opened by tapping the key.");
12975 Vw32_pass_lwindow_to_system = Qt;
12977 DEFVAR_LISP ("w32-pass-rwindow-to-system",
12978 &Vw32_pass_rwindow_to_system,
12979 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
12980 When non-nil, the Start menu is opened by tapping the key.");
12981 Vw32_pass_rwindow_to_system = Qt;
12983 DEFVAR_INT ("w32-phantom-key-code",
12984 &Vw32_phantom_key_code,
12985 "Virtual key code used to generate \"phantom\" key presses.\n\
12986 Value is a number between 0 and 255.\n\
12988 Phantom key presses are generated in order to stop the system from\n\
12989 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
12990 `w32-pass-rwindow-to-system' is nil.");
12991 /* Although 255 is technically not a valid key code, it works and
12992 means that this hack won't interfere with any real key code. */
12993 Vw32_phantom_key_code = 255;
12995 DEFVAR_LISP ("w32-enable-num-lock",
12996 &Vw32_enable_num_lock,
12997 "Non-nil if Num Lock should act normally.\n\
12998 Set to nil to see Num Lock as the key `kp-numlock'.");
12999 Vw32_enable_num_lock = Qt;
13001 DEFVAR_LISP ("w32-enable-caps-lock",
13002 &Vw32_enable_caps_lock,
13003 "Non-nil if Caps Lock should act normally.\n\
13004 Set to nil to see Caps Lock as the key `capslock'.");
13005 Vw32_enable_caps_lock = Qt;
13007 DEFVAR_LISP ("w32-scroll-lock-modifier",
13008 &Vw32_scroll_lock_modifier,
13009 "Modifier to use for the Scroll Lock on state.\n\
13010 The value can be hyper, super, meta, alt, control or shift for the\n\
13011 respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
13012 Any other value will cause the key to be ignored.");
13013 Vw32_scroll_lock_modifier = Qt;
13015 DEFVAR_LISP ("w32-lwindow-modifier",
13016 &Vw32_lwindow_modifier,
13017 "Modifier to use for the left \"Windows\" key.\n\
13018 The value can be hyper, super, meta, alt, control or shift for the\n\
13019 respective modifier, or nil to appear as the key `lwindow'.\n\
13020 Any other value will cause the key to be ignored.");
13021 Vw32_lwindow_modifier = Qnil;
13023 DEFVAR_LISP ("w32-rwindow-modifier",
13024 &Vw32_rwindow_modifier,
13025 "Modifier to use for the right \"Windows\" key.\n\
13026 The value can be hyper, super, meta, alt, control or shift for the\n\
13027 respective modifier, or nil to appear as the key `rwindow'.\n\
13028 Any other value will cause the key to be ignored.");
13029 Vw32_rwindow_modifier = Qnil;
13031 DEFVAR_LISP ("w32-apps-modifier",
13032 &Vw32_apps_modifier,
13033 "Modifier to use for the \"Apps\" key.\n\
13034 The value can be hyper, super, meta, alt, control or shift for the\n\
13035 respective modifier, or nil to appear as the key `apps'.\n\
13036 Any other value will cause the key to be ignored.");
13037 Vw32_apps_modifier = Qnil;
13039 DEFVAR_LISP ("w32-enable-synthesized_fonts", &Vw32_enable_synthesized_fonts,
13040 "Non-nil enables selection of artificially italicized and bold fonts.");
13041 Vw32_enable_synthesized_fonts = Qnil;
13043 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
13044 "Non-nil enables Windows palette management to map colors exactly.");
13045 Vw32_enable_palette = Qt;
13047 DEFVAR_INT ("w32-mouse-button-tolerance",
13048 &Vw32_mouse_button_tolerance,
13049 "Analogue of double click interval for faking middle mouse events.\n\
13050 The value is the minimum time in milliseconds that must elapse between\n\
13051 left/right button down events before they are considered distinct events.\n\
13052 If both mouse buttons are depressed within this interval, a middle mouse\n\
13053 button down event is generated instead.");
13054 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
13056 DEFVAR_INT ("w32-mouse-move-interval",
13057 &Vw32_mouse_move_interval,
13058 "Minimum interval between mouse move events.\n\
13059 The value is the minimum time in milliseconds that must elapse between\n\
13060 successive mouse move (or scroll bar drag) events before they are\n\
13061 reported as lisp events.");
13062 XSETINT (Vw32_mouse_move_interval, 0);
13064 init_x_parm_symbols ();
13066 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
13067 "List of directories to search for bitmap files for w32.");
13068 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13070 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13071 "The shape of the pointer when over text.\n\
13072 Changing the value does not affect existing frames\n\
13073 unless you set the mouse color.");
13074 Vx_pointer_shape = Qnil;
13076 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13077 "The name Emacs uses to look up resources; for internal use only.\n\
13078 `x-get-resource' uses this as the first component of the instance name\n\
13079 when requesting resource values.\n\
13080 Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13081 was invoked, or to the value specified with the `-name' or `-rn'\n\
13082 switches, if present.");
13083 Vx_resource_name = Qnil;
13085 Vx_nontext_pointer_shape = Qnil;
13087 Vx_mode_pointer_shape = Qnil;
13089 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13090 "The shape of the pointer when Emacs is busy.\n\
13091 This variable takes effect when you create a new frame\n\
13092 or when you set the mouse color.");
13093 Vx_busy_pointer_shape = Qnil;
13095 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13096 "Non-zero means Emacs displays a busy cursor on window systems.");
13097 display_busy_cursor_p = 1;
13099 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13100 "*Seconds to wait before displaying a busy-cursor.\n\
13101 Value must be an integer or float.");
13102 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13104 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
13105 &Vx_sensitive_text_pointer_shape,
13106 "The shape of the pointer when over mouse-sensitive text.\n\
13107 This variable takes effect when you create a new frame\n\
13108 or when you set the mouse color.");
13109 Vx_sensitive_text_pointer_shape = Qnil;
13111 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13112 "A string indicating the foreground color of the cursor box.");
13113 Vx_cursor_fore_pixel = Qnil;
13115 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13116 "Non-nil if no window manager is in use.\n\
13117 Emacs doesn't try to figure this out; this is always nil\n\
13118 unless you set it to something else.");
13119 /* We don't have any way to find this out, so set it to nil
13120 and maybe the user would like to set it to t. */
13121 Vx_no_window_manager = Qnil;
13123 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13124 &Vx_pixel_size_width_font_regexp,
13125 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13127 Since Emacs gets width of a font matching with this regexp from\n\
13128 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13129 such a font. This is especially effective for such large fonts as\n\
13130 Chinese, Japanese, and Korean.");
13131 Vx_pixel_size_width_font_regexp = Qnil;
13133 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13134 "Time after which cached images are removed from the cache.\n\
13135 When an image has not been displayed this many seconds, remove it\n\
13136 from the image cache. Value must be an integer or nil with nil\n\
13137 meaning don't clear the cache.");
13138 Vimage_cache_eviction_delay = make_number (30 * 60);
13140 DEFVAR_LISP ("w32-bdf-filename-alist",
13141 &Vw32_bdf_filename_alist,
13142 "List of bdf fonts and their corresponding filenames.");
13143 Vw32_bdf_filename_alist = Qnil;
13145 DEFVAR_BOOL ("w32-strict-fontnames",
13146 &w32_strict_fontnames,
13147 "Non-nil means only use fonts that are exact matches for those requested.\n\
13148 Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13149 and allows third-party CJK display to work by specifying false charset\n\
13150 fields to trick Emacs into translating to Big5, SJIS etc.\n\
13151 Setting this to t will prevent wrong fonts being selected when\n\
13152 fontsets are automatically created.");
13153 w32_strict_fontnames = 0;
13155 DEFVAR_BOOL ("w32-strict-painting",
13156 &w32_strict_painting,
13157 "Non-nil means use strict rules for repainting frames.\n\
13158 Set this to nil to get the old behaviour for repainting; this should\n\
13159 only be necessary if the default setting causes problems.");
13160 w32_strict_painting = 1;
13162 DEFVAR_LISP ("w32-system-coding-system",
13163 &Vw32_system_coding_system,
13164 "Coding system used by Windows system functions, such as for font names.");
13165 Vw32_system_coding_system = Qnil;
13167 DEFVAR_LISP ("w32-charset-info-alist",
13168 &Vw32_charset_info_alist,
13169 "Alist linking Emacs character sets to Windows fonts\n\
13170 and codepages. Each entry should be of the form:\n\
13172 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13174 where CHARSET_NAME is a string used in font names to identify the charset,\n\
13175 WINDOWS_CHARSET is a symbol that can be one of:\n\
13176 w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
13177 w32-charset-shiftjis, w32-charset-hangul, w32-charset-gb2312,\n\
13178 w32-charset-chinesebig5, "
13179 #ifdef JOHAB_CHARSET
13180 "w32-charset-johab, w32-charset-hebrew,\n\
13181 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13182 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13183 w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13184 #endif
13185 #ifdef UNICODE_CHARSET
13186 "w32-charset-unicode, "
13187 #endif
13188 "or w32-charset-oem.\n\
13189 CODEPAGE should be an integer specifying the codepage that should be used\n\
13190 to display the character set, t to do no translation and output as Unicode,\n\
13191 or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13192 versions of Windows) characters.");
13193 Vw32_charset_info_alist = Qnil;
13195 staticpro (&Qw32_charset_ansi);
13196 Qw32_charset_ansi = intern ("w32-charset-ansi");
13197 staticpro (&Qw32_charset_symbol);
13198 Qw32_charset_symbol = intern ("w32-charset-symbol");
13199 staticpro (&Qw32_charset_shiftjis);
13200 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
13201 staticpro (&Qw32_charset_hangul);
13202 Qw32_charset_hangul = intern ("w32-charset-hangul");
13203 staticpro (&Qw32_charset_chinesebig5);
13204 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13205 staticpro (&Qw32_charset_gb2312);
13206 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13207 staticpro (&Qw32_charset_oem);
13208 Qw32_charset_oem = intern ("w32-charset-oem");
13210 #ifdef JOHAB_CHARSET
13212 static int w32_extra_charsets_defined = 1;
13213 DEFVAR_BOOL ("w32-extra-charsets-defined", w32_extra_charsets_defined, "");
13215 staticpro (&Qw32_charset_johab);
13216 Qw32_charset_johab = intern ("w32-charset-johab");
13217 staticpro (&Qw32_charset_easteurope);
13218 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13219 staticpro (&Qw32_charset_turkish);
13220 Qw32_charset_turkish = intern ("w32-charset-turkish");
13221 staticpro (&Qw32_charset_baltic);
13222 Qw32_charset_baltic = intern ("w32-charset-baltic");
13223 staticpro (&Qw32_charset_russian);
13224 Qw32_charset_russian = intern ("w32-charset-russian");
13225 staticpro (&Qw32_charset_arabic);
13226 Qw32_charset_arabic = intern ("w32-charset-arabic");
13227 staticpro (&Qw32_charset_greek);
13228 Qw32_charset_greek = intern ("w32-charset-greek");
13229 staticpro (&Qw32_charset_hebrew);
13230 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
13231 staticpro (&Qw32_charset_thai);
13232 Qw32_charset_thai = intern ("w32-charset-thai");
13233 staticpro (&Qw32_charset_mac);
13234 Qw32_charset_mac = intern ("w32-charset-mac");
13236 #endif
13238 #ifdef UNICODE_CHARSET
13240 static int w32_unicode_charset_defined = 1;
13241 DEFVAR_BOOL ("w32-unicode-charset-defined",
13242 w32_unicode_charset_defined, "");
13244 staticpro (&Qw32_charset_unicode);
13245 Qw32_charset_unicode = intern ("w32-charset-unicode");
13246 #endif
13248 defsubr (&Sx_get_resource);
13249 #if 0 /* NTEMACS_TODO: Port to W32 */
13250 defsubr (&Sx_change_window_property);
13251 defsubr (&Sx_delete_window_property);
13252 defsubr (&Sx_window_property);
13253 #endif
13254 defsubr (&Sxw_display_color_p);
13255 defsubr (&Sx_display_grayscale_p);
13256 defsubr (&Sxw_color_defined_p);
13257 defsubr (&Sxw_color_values);
13258 defsubr (&Sx_server_max_request_size);
13259 defsubr (&Sx_server_vendor);
13260 defsubr (&Sx_server_version);
13261 defsubr (&Sx_display_pixel_width);
13262 defsubr (&Sx_display_pixel_height);
13263 defsubr (&Sx_display_mm_width);
13264 defsubr (&Sx_display_mm_height);
13265 defsubr (&Sx_display_screens);
13266 defsubr (&Sx_display_planes);
13267 defsubr (&Sx_display_color_cells);
13268 defsubr (&Sx_display_visual_class);
13269 defsubr (&Sx_display_backing_store);
13270 defsubr (&Sx_display_save_under);
13271 defsubr (&Sx_parse_geometry);
13272 defsubr (&Sx_create_frame);
13273 defsubr (&Sx_open_connection);
13274 defsubr (&Sx_close_connection);
13275 defsubr (&Sx_display_list);
13276 defsubr (&Sx_synchronize);
13278 /* W32 specific functions */
13280 defsubr (&Sw32_focus_frame);
13281 defsubr (&Sw32_select_font);
13282 defsubr (&Sw32_define_rgb_color);
13283 defsubr (&Sw32_default_color_map);
13284 defsubr (&Sw32_load_color_file);
13285 defsubr (&Sw32_send_sys_command);
13286 defsubr (&Sw32_shell_execute);
13287 defsubr (&Sw32_register_hot_key);
13288 defsubr (&Sw32_unregister_hot_key);
13289 defsubr (&Sw32_registered_hot_keys);
13290 defsubr (&Sw32_reconstruct_hot_key);
13291 defsubr (&Sw32_toggle_lock_key);
13292 defsubr (&Sw32_find_bdf_fonts);
13294 /* Setting callback functions for fontset handler. */
13295 get_font_info_func = w32_get_font_info;
13297 #if 0 /* This function pointer doesn't seem to be used anywhere.
13298 And the pointer assigned has the wrong type, anyway. */
13299 list_fonts_func = w32_list_fonts;
13300 #endif
13302 load_font_func = w32_load_font;
13303 find_ccl_program_func = w32_find_ccl_program;
13304 query_font_func = w32_query_font;
13305 set_frame_fontset_func = x_set_font;
13306 check_window_system_func = check_w32;
13308 #if 0 /* NTEMACS_TODO Image support for W32 */
13309 /* Images. */
13310 Qxbm = intern ("xbm");
13311 staticpro (&Qxbm);
13312 QCtype = intern (":type");
13313 staticpro (&QCtype);
13314 QCalgorithm = intern (":algorithm");
13315 staticpro (&QCalgorithm);
13316 QCheuristic_mask = intern (":heuristic-mask");
13317 staticpro (&QCheuristic_mask);
13318 QCcolor_symbols = intern (":color-symbols");
13319 staticpro (&QCcolor_symbols);
13320 QCascent = intern (":ascent");
13321 staticpro (&QCascent);
13322 QCmargin = intern (":margin");
13323 staticpro (&QCmargin);
13324 QCrelief = intern (":relief");
13325 staticpro (&QCrelief);
13326 Qpostscript = intern ("postscript");
13327 staticpro (&Qpostscript);
13328 QCloader = intern (":loader");
13329 staticpro (&QCloader);
13330 QCbounding_box = intern (":bounding-box");
13331 staticpro (&QCbounding_box);
13332 QCpt_width = intern (":pt-width");
13333 staticpro (&QCpt_width);
13334 QCpt_height = intern (":pt-height");
13335 staticpro (&QCpt_height);
13336 QCindex = intern (":index");
13337 staticpro (&QCindex);
13338 Qpbm = intern ("pbm");
13339 staticpro (&Qpbm);
13341 #if HAVE_XPM
13342 Qxpm = intern ("xpm");
13343 staticpro (&Qxpm);
13344 #endif
13346 #if HAVE_JPEG
13347 Qjpeg = intern ("jpeg");
13348 staticpro (&Qjpeg);
13349 #endif
13351 #if HAVE_TIFF
13352 Qtiff = intern ("tiff");
13353 staticpro (&Qtiff);
13354 #endif
13356 #if HAVE_GIF
13357 Qgif = intern ("gif");
13358 staticpro (&Qgif);
13359 #endif
13361 #if HAVE_PNG
13362 Qpng = intern ("png");
13363 staticpro (&Qpng);
13364 #endif
13366 defsubr (&Sclear_image_cache);
13368 #if GLYPH_DEBUG
13369 defsubr (&Simagep);
13370 defsubr (&Slookup_image);
13371 #endif
13372 #endif /* NTEMACS_TODO */
13374 busy_cursor_atimer = NULL;
13375 busy_cursor_shown_p = 0;
13377 defsubr (&Sx_show_tip);
13378 defsubr (&Sx_hide_tip);
13379 staticpro (&tip_timer);
13380 tip_timer = Qnil;
13382 defsubr (&Sx_file_dialog);
13386 void
13387 init_xfns ()
13389 image_types = NULL;
13390 Vimage_types = Qnil;
13392 #if 0 /* NTEMACS_TODO : Image support for W32 */
13393 define_image_type (&xbm_type);
13394 define_image_type (&gs_type);
13395 define_image_type (&pbm_type);
13397 #if HAVE_XPM
13398 define_image_type (&xpm_type);
13399 #endif
13401 #if HAVE_JPEG
13402 define_image_type (&jpeg_type);
13403 #endif
13405 #if HAVE_TIFF
13406 define_image_type (&tiff_type);
13407 #endif
13409 #if HAVE_GIF
13410 define_image_type (&gif_type);
13411 #endif
13413 #if HAVE_PNG
13414 define_image_type (&png_type);
13415 #endif
13416 #endif /* NTEMACS_TODO */
13419 #undef abort
13421 void
13422 w32_abort()
13424 int button;
13425 button = MessageBox (NULL,
13426 "A fatal error has occurred!\n\n"
13427 "Select Abort to exit, Retry to debug, Ignore to continue",
13428 "Emacs Abort Dialog",
13429 MB_ICONEXCLAMATION | MB_TASKMODAL
13430 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13431 switch (button)
13433 case IDRETRY:
13434 DebugBreak ();
13435 break;
13436 case IDIGNORE:
13437 break;
13438 case IDABORT:
13439 default:
13440 abort ();
13441 break;
13445 /* For convenience when debugging. */
13447 w32_last_error()
13449 return GetLastError ();