[HAVE_TERMCAP_H]: Include <termcap.h>.
[emacs.git] / src / w32fns.c
blob7e44f78efda1b6c6624c1afc250ed2a42a55cb23
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 ("Invalid 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 ("Invalid 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 if (title)
4626 HDC hdc = pDis->hDC;
4627 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4628 LOGFONT menu_logfont;
4629 HFONT old_font;
4631 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4632 menu_logfont.lfWeight = FW_BOLD;
4633 menu_font = CreateFontIndirect (&menu_logfont);
4634 old_font = SelectObject (hdc, menu_font);
4636 /* Always draw title as if not selected. */
4637 ExtTextOut (hdc,
4638 pDis->rcItem.left
4639 + GetSystemMetrics (SM_CXMENUCHECK),
4640 pDis->rcItem.top,
4641 ETO_OPAQUE, &pDis->rcItem,
4642 title, strlen (title), NULL);
4644 SelectObject (hdc, old_font);
4645 DeleteObject (menu_font);
4647 return TRUE;
4650 return 0;
4652 #if 0
4653 /* Still not right - can't distinguish between clicks in the
4654 client area of the frame from clicks forwarded from the scroll
4655 bars - may have to hook WM_NCHITTEST to remember the mouse
4656 position and then check if it is in the client area ourselves. */
4657 case WM_MOUSEACTIVATE:
4658 /* Discard the mouse click that activates a frame, allowing the
4659 user to click anywhere without changing point (or worse!).
4660 Don't eat mouse clicks on scrollbars though!! */
4661 if (LOWORD (lParam) == HTCLIENT )
4662 return MA_ACTIVATEANDEAT;
4663 goto dflt;
4664 #endif
4666 case WM_ACTIVATEAPP:
4667 case WM_ACTIVATE:
4668 case WM_WINDOWPOSCHANGED:
4669 case WM_SHOWWINDOW:
4670 /* Inform lisp thread that a frame might have just been obscured
4671 or exposed, so should recheck visibility of all frames. */
4672 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4673 goto dflt;
4675 case WM_SETFOCUS:
4676 dpyinfo->faked_key = 0;
4677 reset_modifiers ();
4678 register_hot_keys (hwnd);
4679 goto command;
4680 case WM_KILLFOCUS:
4681 unregister_hot_keys (hwnd);
4682 button_state = 0;
4683 ReleaseCapture ();
4684 case WM_MOVE:
4685 case WM_SIZE:
4686 case WM_COMMAND:
4687 command:
4688 wmsg.dwModifiers = w32_get_modifiers ();
4689 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4690 goto dflt;
4692 case WM_CLOSE:
4693 wmsg.dwModifiers = w32_get_modifiers ();
4694 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4695 return 0;
4697 case WM_WINDOWPOSCHANGING:
4699 WINDOWPLACEMENT wp;
4700 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4702 wp.length = sizeof (WINDOWPLACEMENT);
4703 GetWindowPlacement (hwnd, &wp);
4705 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4707 RECT rect;
4708 int wdiff;
4709 int hdiff;
4710 DWORD font_width;
4711 DWORD line_height;
4712 DWORD internal_border;
4713 DWORD scrollbar_extra;
4714 RECT wr;
4716 wp.length = sizeof(wp);
4717 GetWindowRect (hwnd, &wr);
4719 enter_crit ();
4721 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4722 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4723 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4724 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4726 leave_crit ();
4728 memset (&rect, 0, sizeof (rect));
4729 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4730 GetMenu (hwnd) != NULL);
4732 /* Force width and height of client area to be exact
4733 multiples of the character cell dimensions. */
4734 wdiff = (lppos->cx - (rect.right - rect.left)
4735 - 2 * internal_border - scrollbar_extra)
4736 % font_width;
4737 hdiff = (lppos->cy - (rect.bottom - rect.top)
4738 - 2 * internal_border)
4739 % line_height;
4741 if (wdiff || hdiff)
4743 /* For right/bottom sizing we can just fix the sizes.
4744 However for top/left sizing we will need to fix the X
4745 and Y positions as well. */
4747 lppos->cx -= wdiff;
4748 lppos->cy -= hdiff;
4750 if (wp.showCmd != SW_SHOWMAXIMIZED
4751 && (lppos->flags & SWP_NOMOVE) == 0)
4753 if (lppos->x != wr.left || lppos->y != wr.top)
4755 lppos->x += wdiff;
4756 lppos->y += hdiff;
4758 else
4760 lppos->flags |= SWP_NOMOVE;
4764 return 0;
4769 goto dflt;
4771 case WM_GETMINMAXINFO:
4772 /* Hack to correct bug that allows Emacs frames to be resized
4773 below the Minimum Tracking Size. */
4774 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4775 return 0;
4777 case WM_EMACS_CREATESCROLLBAR:
4778 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4779 (struct scroll_bar *) lParam);
4781 case WM_EMACS_SHOWWINDOW:
4782 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4784 case WM_EMACS_SETFOREGROUND:
4786 HWND foreground_window;
4787 DWORD foreground_thread, retval;
4789 /* On NT 5.0, and apparently Windows 98, it is necessary to
4790 attach to the thread that currently has focus in order to
4791 pull the focus away from it. */
4792 foreground_window = GetForegroundWindow ();
4793 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4794 if (!foreground_window
4795 || foreground_thread == GetCurrentThreadId ()
4796 || !AttachThreadInput (GetCurrentThreadId (),
4797 foreground_thread, TRUE))
4798 foreground_thread = 0;
4800 retval = SetForegroundWindow ((HWND) wParam);
4802 /* Detach from the previous foreground thread. */
4803 if (foreground_thread)
4804 AttachThreadInput (GetCurrentThreadId (),
4805 foreground_thread, FALSE);
4807 return retval;
4810 case WM_EMACS_SETWINDOWPOS:
4812 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4813 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4814 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4817 case WM_EMACS_DESTROYWINDOW:
4818 DragAcceptFiles ((HWND) wParam, FALSE);
4819 return DestroyWindow ((HWND) wParam);
4821 case WM_EMACS_TRACKPOPUPMENU:
4823 UINT flags;
4824 POINT *pos;
4825 int retval;
4826 pos = (POINT *)lParam;
4827 flags = TPM_CENTERALIGN;
4828 if (button_state & LMOUSE)
4829 flags |= TPM_LEFTBUTTON;
4830 else if (button_state & RMOUSE)
4831 flags |= TPM_RIGHTBUTTON;
4833 /* Remember we did a SetCapture on the initial mouse down event,
4834 so for safety, we make sure the capture is cancelled now. */
4835 ReleaseCapture ();
4836 button_state = 0;
4838 /* Use menubar_active to indicate that WM_INITMENU is from
4839 TrackPopupMenu below, and should be ignored. */
4840 f = x_window_to_frame (dpyinfo, hwnd);
4841 if (f)
4842 f->output_data.w32->menubar_active = 1;
4844 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4845 0, hwnd, NULL))
4847 MSG amsg;
4848 /* Eat any mouse messages during popupmenu */
4849 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4850 PM_REMOVE));
4851 /* Get the menu selection, if any */
4852 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4854 retval = LOWORD (amsg.wParam);
4856 else
4858 retval = 0;
4861 else
4863 retval = -1;
4866 return retval;
4869 default:
4870 /* Check for messages registered at runtime. */
4871 if (msg == msh_mousewheel)
4873 wmsg.dwModifiers = w32_get_modifiers ();
4874 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4875 return 0;
4878 dflt:
4879 return DefWindowProc (hwnd, msg, wParam, lParam);
4883 /* The most common default return code for handled messages is 0. */
4884 return 0;
4887 void
4888 my_create_window (f)
4889 struct frame * f;
4891 MSG msg;
4893 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4894 abort ();
4895 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4898 /* Create and set up the w32 window for frame F. */
4900 static void
4901 w32_window (f, window_prompting, minibuffer_only)
4902 struct frame *f;
4903 long window_prompting;
4904 int minibuffer_only;
4906 BLOCK_INPUT;
4908 /* Use the resource name as the top-level window name
4909 for looking up resources. Make a non-Lisp copy
4910 for the window manager, so GC relocation won't bother it.
4912 Elsewhere we specify the window name for the window manager. */
4915 char *str = (char *) XSTRING (Vx_resource_name)->data;
4916 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4917 strcpy (f->namebuf, str);
4920 my_create_window (f);
4922 validate_x_resource_name ();
4924 /* x_set_name normally ignores requests to set the name if the
4925 requested name is the same as the current name. This is the one
4926 place where that assumption isn't correct; f->name is set, but
4927 the server hasn't been told. */
4929 Lisp_Object name;
4930 int explicit = f->explicit_name;
4932 f->explicit_name = 0;
4933 name = f->name;
4934 f->name = Qnil;
4935 x_set_name (f, name, explicit);
4938 UNBLOCK_INPUT;
4940 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4941 initialize_frame_menubar (f);
4943 if (FRAME_W32_WINDOW (f) == 0)
4944 error ("Unable to create window");
4947 /* Handle the icon stuff for this window. Perhaps later we might
4948 want an x_set_icon_position which can be called interactively as
4949 well. */
4951 static void
4952 x_icon (f, parms)
4953 struct frame *f;
4954 Lisp_Object parms;
4956 Lisp_Object icon_x, icon_y;
4958 /* Set the position of the icon. Note that Windows 95 groups all
4959 icons in the tray. */
4960 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4961 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4962 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4964 CHECK_NUMBER (icon_x, 0);
4965 CHECK_NUMBER (icon_y, 0);
4967 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4968 error ("Both left and top icon corners of icon must be specified");
4970 BLOCK_INPUT;
4972 if (! EQ (icon_x, Qunbound))
4973 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4975 #if 0 /* TODO */
4976 /* Start up iconic or window? */
4977 x_wm_set_window_state
4978 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4979 ? IconicState
4980 : NormalState));
4982 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
4983 ? f->icon_name
4984 : f->name))->data);
4985 #endif
4987 UNBLOCK_INPUT;
4991 static void
4992 x_make_gc (f)
4993 struct frame *f;
4995 XGCValues gc_values;
4997 BLOCK_INPUT;
4999 /* Create the GC's of this frame.
5000 Note that many default values are used. */
5002 /* Normal video */
5003 gc_values.font = f->output_data.w32->font;
5005 /* Cursor has cursor-color background, background-color foreground. */
5006 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5007 gc_values.background = f->output_data.w32->cursor_pixel;
5008 f->output_data.w32->cursor_gc
5009 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5010 (GCFont | GCForeground | GCBackground),
5011 &gc_values);
5013 /* Reliefs. */
5014 f->output_data.w32->white_relief.gc = 0;
5015 f->output_data.w32->black_relief.gc = 0;
5017 UNBLOCK_INPUT;
5021 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5022 1, 1, 0,
5023 "Make a new window, which is called a \"frame\" in Emacs terms.\n\
5024 Returns an Emacs frame object.\n\
5025 ALIST is an alist of frame parameters.\n\
5026 If the parameters specify that the frame should not have a minibuffer,\n\
5027 and do not specify a specific minibuffer window to use,\n\
5028 then `default-minibuffer-frame' must be a frame whose minibuffer can\n\
5029 be shared by the new frame.\n\
5031 This function is an internal primitive--use `make-frame' instead.")
5032 (parms)
5033 Lisp_Object parms;
5035 struct frame *f;
5036 Lisp_Object frame, tem;
5037 Lisp_Object name;
5038 int minibuffer_only = 0;
5039 long window_prompting = 0;
5040 int width, height;
5041 int count = specpdl_ptr - specpdl;
5042 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5043 Lisp_Object display;
5044 struct w32_display_info *dpyinfo = NULL;
5045 Lisp_Object parent;
5046 struct kboard *kb;
5048 check_w32 ();
5050 /* Use this general default value to start with
5051 until we know if this frame has a specified name. */
5052 Vx_resource_name = Vinvocation_name;
5054 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5055 if (EQ (display, Qunbound))
5056 display = Qnil;
5057 dpyinfo = check_x_display_info (display);
5058 #ifdef MULTI_KBOARD
5059 kb = dpyinfo->kboard;
5060 #else
5061 kb = &the_only_kboard;
5062 #endif
5064 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5065 if (!STRINGP (name)
5066 && ! EQ (name, Qunbound)
5067 && ! NILP (name))
5068 error ("Invalid frame name--not a string or nil");
5070 if (STRINGP (name))
5071 Vx_resource_name = name;
5073 /* See if parent window is specified. */
5074 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5075 if (EQ (parent, Qunbound))
5076 parent = Qnil;
5077 if (! NILP (parent))
5078 CHECK_NUMBER (parent, 0);
5080 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5081 /* No need to protect DISPLAY because that's not used after passing
5082 it to make_frame_without_minibuffer. */
5083 frame = Qnil;
5084 GCPRO4 (parms, parent, name, frame);
5085 tem = w32_get_arg (parms, Qminibuffer, 0, 0, RES_TYPE_SYMBOL);
5086 if (EQ (tem, Qnone) || NILP (tem))
5087 f = make_frame_without_minibuffer (Qnil, kb, display);
5088 else if (EQ (tem, Qonly))
5090 f = make_minibuffer_frame ();
5091 minibuffer_only = 1;
5093 else if (WINDOWP (tem))
5094 f = make_frame_without_minibuffer (tem, kb, display);
5095 else
5096 f = make_frame (1);
5098 XSETFRAME (frame, f);
5100 /* Note that Windows does support scroll bars. */
5101 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5102 /* By default, make scrollbars the system standard width. */
5103 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5105 f->output_method = output_w32;
5106 f->output_data.w32 =
5107 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5108 bzero (f->output_data.w32, sizeof (struct w32_output));
5110 FRAME_FONTSET (f) = -1;
5112 f->icon_name
5113 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5114 if (! STRINGP (f->icon_name))
5115 f->icon_name = Qnil;
5117 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5118 #ifdef MULTI_KBOARD
5119 FRAME_KBOARD (f) = kb;
5120 #endif
5122 /* Specify the parent under which to make this window. */
5124 if (!NILP (parent))
5126 f->output_data.w32->parent_desc = (Window) parent;
5127 f->output_data.w32->explicit_parent = 1;
5129 else
5131 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5132 f->output_data.w32->explicit_parent = 0;
5135 /* Set the name; the functions to which we pass f expect the name to
5136 be set. */
5137 if (EQ (name, Qunbound) || NILP (name))
5139 f->name = build_string (dpyinfo->w32_id_name);
5140 f->explicit_name = 0;
5142 else
5144 f->name = name;
5145 f->explicit_name = 1;
5146 /* use the frame's title when getting resources for this frame. */
5147 specbind (Qx_resource_name, name);
5150 /* Extract the window parameters from the supplied values
5151 that are needed to determine window geometry. */
5153 Lisp_Object font;
5155 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5157 BLOCK_INPUT;
5158 /* First, try whatever font the caller has specified. */
5159 if (STRINGP (font))
5161 tem = Fquery_fontset (font, Qnil);
5162 if (STRINGP (tem))
5163 font = x_new_fontset (f, XSTRING (tem)->data);
5164 else
5165 font = x_new_font (f, XSTRING (font)->data);
5167 /* Try out a font which we hope has bold and italic variations. */
5168 if (!STRINGP (font))
5169 font = x_new_font (f, "-*-Courier New-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5170 if (! STRINGP (font))
5171 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5172 /* If those didn't work, look for something which will at least work. */
5173 if (! STRINGP (font))
5174 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5175 UNBLOCK_INPUT;
5176 if (! STRINGP (font))
5177 font = build_string ("Fixedsys");
5179 x_default_parameter (f, parms, Qfont, font,
5180 "font", "Font", RES_TYPE_STRING);
5183 x_default_parameter (f, parms, Qborder_width, make_number (2),
5184 "borderwidth", "BorderWidth", RES_TYPE_NUMBER);
5185 /* This defaults to 2 in order to match xterm. We recognize either
5186 internalBorderWidth or internalBorder (which is what xterm calls
5187 it). */
5188 if (NILP (Fassq (Qinternal_border_width, parms)))
5190 Lisp_Object value;
5192 value = w32_get_arg (parms, Qinternal_border_width,
5193 "internalBorder", "BorderWidth", RES_TYPE_NUMBER);
5194 if (! EQ (value, Qunbound))
5195 parms = Fcons (Fcons (Qinternal_border_width, value),
5196 parms);
5198 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5199 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5200 "internalBorderWidth", "BorderWidth", RES_TYPE_NUMBER);
5201 x_default_parameter (f, parms, Qvertical_scroll_bars, Qt,
5202 "verticalScrollBars", "ScrollBars", RES_TYPE_BOOLEAN);
5204 /* Also do the stuff which must be set before the window exists. */
5205 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5206 "foreground", "Foreground", RES_TYPE_STRING);
5207 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5208 "background", "Background", RES_TYPE_STRING);
5209 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5210 "pointerColor", "Foreground", RES_TYPE_STRING);
5211 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5212 "cursorColor", "Foreground", RES_TYPE_STRING);
5213 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5214 "borderColor", "BorderColor", RES_TYPE_STRING);
5215 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5216 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5217 x_default_parameter (f, parms, Qline_spacing, Qnil,
5218 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5221 /* Init faces before x_default_parameter is called for scroll-bar
5222 parameters because that function calls x_set_scroll_bar_width,
5223 which calls change_frame_size, which calls Fset_window_buffer,
5224 which runs hooks, which call Fvertical_motion. At the end, we
5225 end up in init_iterator with a null face cache, which should not
5226 happen. */
5227 init_frame_faces (f);
5229 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5230 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5231 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5232 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5233 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5234 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5235 x_default_parameter (f, parms, Qtitle, Qnil,
5236 "title", "Title", RES_TYPE_STRING);
5238 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5239 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5240 window_prompting = x_figure_window_size (f, parms);
5242 if (window_prompting & XNegative)
5244 if (window_prompting & YNegative)
5245 f->output_data.w32->win_gravity = SouthEastGravity;
5246 else
5247 f->output_data.w32->win_gravity = NorthEastGravity;
5249 else
5251 if (window_prompting & YNegative)
5252 f->output_data.w32->win_gravity = SouthWestGravity;
5253 else
5254 f->output_data.w32->win_gravity = NorthWestGravity;
5257 f->output_data.w32->size_hint_flags = window_prompting;
5259 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5260 f->no_split = minibuffer_only || EQ (tem, Qt);
5262 /* Create the window. Add the tool-bar height to the initial frame
5263 height so that the user gets a text display area of the size he
5264 specified with -g or via the registry. Later changes of the
5265 tool-bar height don't change the frame size. This is done so that
5266 users can create tall Emacs frames without having to guess how
5267 tall the tool-bar will get. */
5268 f->height += FRAME_TOOL_BAR_LINES (f);
5269 w32_window (f, window_prompting, minibuffer_only);
5270 x_icon (f, parms);
5272 x_make_gc (f);
5274 /* Now consider the frame official. */
5275 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5276 Vframe_list = Fcons (frame, Vframe_list);
5278 /* We need to do this after creating the window, so that the
5279 icon-creation functions can say whose icon they're describing. */
5280 x_default_parameter (f, parms, Qicon_type, Qnil,
5281 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5283 x_default_parameter (f, parms, Qauto_raise, Qnil,
5284 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5285 x_default_parameter (f, parms, Qauto_lower, Qnil,
5286 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5287 x_default_parameter (f, parms, Qcursor_type, Qbox,
5288 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5289 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5290 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5292 /* Dimensions, especially f->height, must be done via change_frame_size.
5293 Change will not be effected unless different from the current
5294 f->height. */
5295 width = f->width;
5296 height = f->height;
5297 f->height = 0;
5298 SET_FRAME_WIDTH (f, 0);
5299 change_frame_size (f, height, width, 1, 0, 0);
5301 /* Set up faces after all frame parameters are known. */
5302 call1 (Qface_set_after_frame_default, frame);
5304 /* Tell the server what size and position, etc, we want, and how
5305 badly we want them. This should be done after we have the menu
5306 bar so that its size can be taken into account. */
5307 BLOCK_INPUT;
5308 x_wm_set_size_hint (f, window_prompting, 0);
5309 UNBLOCK_INPUT;
5311 /* Make the window appear on the frame and enable display, unless
5312 the caller says not to. However, with explicit parent, Emacs
5313 cannot control visibility, so don't try. */
5314 if (! f->output_data.w32->explicit_parent)
5316 Lisp_Object visibility;
5318 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5319 if (EQ (visibility, Qunbound))
5320 visibility = Qt;
5322 if (EQ (visibility, Qicon))
5323 x_iconify_frame (f);
5324 else if (! NILP (visibility))
5325 x_make_frame_visible (f);
5326 else
5327 /* Must have been Qnil. */
5330 UNGCPRO;
5331 return unbind_to (count, frame);
5334 /* FRAME is used only to get a handle on the X display. We don't pass the
5335 display info directly because we're called from frame.c, which doesn't
5336 know about that structure. */
5337 Lisp_Object
5338 x_get_focus_frame (frame)
5339 struct frame *frame;
5341 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5342 Lisp_Object xfocus;
5343 if (! dpyinfo->w32_focus_frame)
5344 return Qnil;
5346 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5347 return xfocus;
5350 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5351 "Give FRAME input focus, raising to foreground if necessary.")
5352 (frame)
5353 Lisp_Object frame;
5355 x_focus_on_frame (check_x_frame (frame));
5356 return Qnil;
5360 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5361 int size, char* filename);
5363 struct font_info *
5364 w32_load_system_font (f,fontname,size)
5365 struct frame *f;
5366 char * fontname;
5367 int size;
5369 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5370 Lisp_Object font_names;
5372 /* Get a list of all the fonts that match this name. Once we
5373 have a list of matching fonts, we compare them against the fonts
5374 we already have loaded by comparing names. */
5375 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5377 if (!NILP (font_names))
5379 Lisp_Object tail;
5380 int i;
5382 /* First check if any are already loaded, as that is cheaper
5383 than loading another one. */
5384 for (i = 0; i < dpyinfo->n_fonts; i++)
5385 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5386 if (dpyinfo->font_table[i].name
5387 && (!strcmp (dpyinfo->font_table[i].name,
5388 XSTRING (XCAR (tail))->data)
5389 || !strcmp (dpyinfo->font_table[i].full_name,
5390 XSTRING (XCAR (tail))->data)))
5391 return (dpyinfo->font_table + i);
5393 fontname = (char *) XSTRING (XCAR (font_names))->data;
5395 else if (w32_strict_fontnames)
5397 /* If EnumFontFamiliesEx was available, we got a full list of
5398 fonts back so stop now to avoid the possibility of loading a
5399 random font. If we had to fall back to EnumFontFamilies, the
5400 list is incomplete, so continue whether the font we want was
5401 listed or not. */
5402 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5403 FARPROC enum_font_families_ex
5404 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5405 if (enum_font_families_ex)
5406 return NULL;
5409 /* Load the font and add it to the table. */
5411 char *full_name, *encoding;
5412 XFontStruct *font;
5413 struct font_info *fontp;
5414 LOGFONT lf;
5415 BOOL ok;
5416 int i;
5418 if (!fontname || !x_to_w32_font (fontname, &lf))
5419 return (NULL);
5421 if (!*lf.lfFaceName)
5422 /* If no name was specified for the font, we get a random font
5423 from CreateFontIndirect - this is not particularly
5424 desirable, especially since CreateFontIndirect does not
5425 fill out the missing name in lf, so we never know what we
5426 ended up with. */
5427 return NULL;
5429 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5431 /* Set bdf to NULL to indicate that this is a Windows font. */
5432 font->bdf = NULL;
5434 BLOCK_INPUT;
5436 font->hfont = CreateFontIndirect (&lf);
5438 if (font->hfont == NULL)
5440 ok = FALSE;
5442 else
5444 HDC hdc;
5445 HANDLE oldobj;
5447 hdc = GetDC (dpyinfo->root_window);
5448 oldobj = SelectObject (hdc, font->hfont);
5449 ok = GetTextMetrics (hdc, &font->tm);
5450 font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS;
5451 SelectObject (hdc, oldobj);
5452 ReleaseDC (dpyinfo->root_window, hdc);
5453 /* Fill out details in lf according to the font that was
5454 actually loaded. */
5455 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5456 lf.lfWidth = font->tm.tmAveCharWidth;
5457 lf.lfWeight = font->tm.tmWeight;
5458 lf.lfItalic = font->tm.tmItalic;
5459 lf.lfCharSet = font->tm.tmCharSet;
5460 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5461 ? VARIABLE_PITCH : FIXED_PITCH);
5462 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5463 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5466 UNBLOCK_INPUT;
5468 if (!ok)
5470 w32_unload_font (dpyinfo, font);
5471 return (NULL);
5474 /* Find a free slot in the font table. */
5475 for (i = 0; i < dpyinfo->n_fonts; ++i)
5476 if (dpyinfo->font_table[i].name == NULL)
5477 break;
5479 /* If no free slot found, maybe enlarge the font table. */
5480 if (i == dpyinfo->n_fonts
5481 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5483 int sz;
5484 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5485 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5486 dpyinfo->font_table
5487 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5490 fontp = dpyinfo->font_table + i;
5491 if (i == dpyinfo->n_fonts)
5492 ++dpyinfo->n_fonts;
5494 /* Now fill in the slots of *FONTP. */
5495 BLOCK_INPUT;
5496 fontp->font = font;
5497 fontp->font_idx = i;
5498 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5499 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5501 /* Work out the font's full name. */
5502 full_name = (char *)xmalloc (100);
5503 if (full_name && w32_to_x_font (&lf, full_name, 100))
5504 fontp->full_name = full_name;
5505 else
5507 /* If all else fails - just use the name we used to load it. */
5508 xfree (full_name);
5509 fontp->full_name = fontp->name;
5512 fontp->size = FONT_WIDTH (font);
5513 fontp->height = FONT_HEIGHT (font);
5515 /* The slot `encoding' specifies how to map a character
5516 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5517 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5518 (0:0x20..0x7F, 1:0xA0..0xFF,
5519 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5520 2:0xA020..0xFF7F). For the moment, we don't know which charset
5521 uses this font. So, we set information in fontp->encoding[1]
5522 which is never used by any charset. If mapping can't be
5523 decided, set FONT_ENCODING_NOT_DECIDED. */
5525 /* SJIS fonts need to be set to type 4, all others seem to work as
5526 type FONT_ENCODING_NOT_DECIDED. */
5527 encoding = strrchr (fontp->name, '-');
5528 if (encoding && stricmp (encoding+1, "sjis") == 0)
5529 fontp->encoding[1] = 4;
5530 else
5531 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5533 /* The following three values are set to 0 under W32, which is
5534 what they get set to if XGetFontProperty fails under X. */
5535 fontp->baseline_offset = 0;
5536 fontp->relative_compose = 0;
5537 fontp->default_ascent = 0;
5539 /* Set global flag fonts_changed_p to non-zero if the font loaded
5540 has a character with a smaller width than any other character
5541 before, or if the font loaded has a smalle>r height than any
5542 other font loaded before. If this happens, it will make a
5543 glyph matrix reallocation necessary. */
5544 fonts_changed_p = x_compute_min_glyph_bounds (f);
5545 UNBLOCK_INPUT;
5546 return fontp;
5550 /* Load font named FONTNAME of size SIZE for frame F, and return a
5551 pointer to the structure font_info while allocating it dynamically.
5552 If loading fails, return NULL. */
5553 struct font_info *
5554 w32_load_font (f,fontname,size)
5555 struct frame *f;
5556 char * fontname;
5557 int size;
5559 Lisp_Object bdf_fonts;
5560 struct font_info *retval = NULL;
5562 bdf_fonts = w32_list_bdf_fonts (build_string (fontname));
5564 while (!retval && CONSP (bdf_fonts))
5566 char *bdf_name, *bdf_file;
5567 Lisp_Object bdf_pair;
5569 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5570 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5571 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5573 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5575 bdf_fonts = XCDR (bdf_fonts);
5578 if (retval)
5579 return retval;
5581 return w32_load_system_font(f, fontname, size);
5585 void
5586 w32_unload_font (dpyinfo, font)
5587 struct w32_display_info *dpyinfo;
5588 XFontStruct * font;
5590 if (font)
5592 if (font->bdf) w32_free_bdf_font (font->bdf);
5594 if (font->hfont) DeleteObject(font->hfont);
5595 xfree (font);
5599 /* The font conversion stuff between x and w32 */
5601 /* X font string is as follows (from faces.el)
5602 * (let ((- "[-?]")
5603 * (foundry "[^-]+")
5604 * (family "[^-]+")
5605 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5606 * (weight\? "\\([^-]*\\)") ; 1
5607 * (slant "\\([ior]\\)") ; 2
5608 * (slant\? "\\([^-]?\\)") ; 2
5609 * (swidth "\\([^-]*\\)") ; 3
5610 * (adstyle "[^-]*") ; 4
5611 * (pixelsize "[0-9]+")
5612 * (pointsize "[0-9][0-9]+")
5613 * (resx "[0-9][0-9]+")
5614 * (resy "[0-9][0-9]+")
5615 * (spacing "[cmp?*]")
5616 * (avgwidth "[0-9]+")
5617 * (registry "[^-]+")
5618 * (encoding "[^-]+")
5622 LONG
5623 x_to_w32_weight (lpw)
5624 char * lpw;
5626 if (!lpw) return (FW_DONTCARE);
5628 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5629 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5630 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5631 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5632 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5633 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5634 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5635 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5636 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5637 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5638 else
5639 return FW_DONTCARE;
5643 char *
5644 w32_to_x_weight (fnweight)
5645 int fnweight;
5647 if (fnweight >= FW_HEAVY) return "heavy";
5648 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5649 if (fnweight >= FW_BOLD) return "bold";
5650 if (fnweight >= FW_SEMIBOLD) return "demibold";
5651 if (fnweight >= FW_MEDIUM) return "medium";
5652 if (fnweight >= FW_NORMAL) return "normal";
5653 if (fnweight >= FW_LIGHT) return "light";
5654 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5655 if (fnweight >= FW_THIN) return "thin";
5656 else
5657 return "*";
5660 LONG
5661 x_to_w32_charset (lpcs)
5662 char * lpcs;
5664 Lisp_Object rest;
5666 /* Look through w32-charset-info-alist for the character set.
5667 Format of each entry is
5668 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5670 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5672 Lisp_Object this_entry = XCAR (rest);
5673 char * x_charset = XSTRING (XCAR (this_entry))->data;
5675 if (strnicmp (lpcs, x_charset, strlen(x_charset)) == 0)
5677 Lisp_Object w32_charset = XCAR (XCDR (this_entry));
5678 // Translate Lisp symbol to number.
5679 if (w32_charset == Qw32_charset_ansi)
5680 return ANSI_CHARSET;
5681 if (w32_charset == Qw32_charset_symbol)
5682 return SYMBOL_CHARSET;
5683 if (w32_charset == Qw32_charset_shiftjis)
5684 return SHIFTJIS_CHARSET;
5685 if (w32_charset == Qw32_charset_hangul)
5686 return HANGEUL_CHARSET;
5687 if (w32_charset == Qw32_charset_chinesebig5)
5688 return CHINESEBIG5_CHARSET;
5689 if (w32_charset == Qw32_charset_gb2312)
5690 return GB2312_CHARSET;
5691 if (w32_charset == Qw32_charset_oem)
5692 return OEM_CHARSET;
5693 #ifdef JOHAB_CHARSET
5694 if (w32_charset == Qw32_charset_johab)
5695 return JOHAB_CHARSET;
5696 if (w32_charset == Qw32_charset_easteurope)
5697 return EASTEUROPE_CHARSET;
5698 if (w32_charset == Qw32_charset_turkish)
5699 return TURKISH_CHARSET;
5700 if (w32_charset == Qw32_charset_baltic)
5701 return BALTIC_CHARSET;
5702 if (w32_charset == Qw32_charset_russian)
5703 return RUSSIAN_CHARSET;
5704 if (w32_charset == Qw32_charset_arabic)
5705 return ARABIC_CHARSET;
5706 if (w32_charset == Qw32_charset_greek)
5707 return GREEK_CHARSET;
5708 if (w32_charset == Qw32_charset_hebrew)
5709 return HEBREW_CHARSET;
5710 if (w32_charset == Qw32_charset_thai)
5711 return THAI_CHARSET;
5712 if (w32_charset == Qw32_charset_mac)
5713 return MAC_CHARSET;
5714 #endif /* JOHAB_CHARSET */
5715 #ifdef UNICODE_CHARSET
5716 if (w32_charset == Qw32_charset_unicode)
5717 return UNICODE_CHARSET;
5718 #endif
5722 return DEFAULT_CHARSET;
5726 char *
5727 w32_to_x_charset (fncharset)
5728 int fncharset;
5730 static char buf[16];
5732 /* NTEMACS_TODO: use w32-charset-info-alist. Multiple matches
5733 are possible, so this will require more than just a rewrite of
5734 this function. w32_to_x_font is the only user of this function,
5735 and that will require rewriting too, and its users. */
5736 switch (fncharset)
5738 /* ansi is considered iso8859-1, as most modern ansi fonts are. */
5739 case ANSI_CHARSET: return "iso8859-1";
5740 case DEFAULT_CHARSET: return "ascii-*";
5741 case SYMBOL_CHARSET: return "ms-symbol";
5742 case SHIFTJIS_CHARSET: return "jisx0208-sjis";
5743 case HANGEUL_CHARSET: return "ksc5601.1987-*";
5744 case GB2312_CHARSET: return "gb2312-*";
5745 case CHINESEBIG5_CHARSET: return "big5-*";
5746 case OEM_CHARSET: return "ms-oem";
5748 /* More recent versions of Windows (95 and NT4.0) define more
5749 character sets. */
5750 #ifdef EASTEUROPE_CHARSET
5751 case EASTEUROPE_CHARSET: return "iso8859-2";
5752 case TURKISH_CHARSET: return "iso8859-9";
5753 case BALTIC_CHARSET: return "iso8859-4";
5755 /* W95 with international support but not IE4 often has the
5756 KOI8-R codepage but not ISO8859-5. */
5757 case RUSSIAN_CHARSET:
5758 if (!IsValidCodePage(28595) && IsValidCodePage(20886))
5759 return "koi8-r";
5760 else
5761 return "iso8859-5";
5762 case ARABIC_CHARSET: return "iso8859-6";
5763 case GREEK_CHARSET: return "iso8859-7";
5764 case HEBREW_CHARSET: return "iso8859-8";
5765 case VIETNAMESE_CHARSET: return "viscii1.1-*";
5766 case THAI_CHARSET: return "tis620-*";
5767 case MAC_CHARSET: return "mac-*";
5768 case JOHAB_CHARSET: return "ksc5601.1992-*";
5770 #endif
5772 #ifdef UNICODE_CHARSET
5773 case UNICODE_CHARSET: return "iso10646-unicode";
5774 #endif
5776 /* Encode numerical value of unknown charset. */
5777 sprintf (buf, "*-#%u", fncharset);
5778 return buf;
5782 /* Get the Windows codepage corresponding to the specified font. The
5783 charset info in the font name is used to look up
5784 w32-charset-to-codepage-alist. */
5785 int
5786 w32_codepage_for_font (char *fontname)
5788 Lisp_Object codepage;
5789 char charset_str[20], *charset, *end;
5791 /* Extract charset part of font string. */
5792 if (sscanf (fontname,
5793 "-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%*[^-]-%19s",
5794 charset_str) == EOF)
5795 return CP_DEFAULT;
5797 /* Remove leading "*-". */
5798 if (strncmp ("*-", charset_str, 2) == 0)
5799 charset = charset_str + 2;
5800 else
5801 charset = charset_str;
5803 /* Stop match at wildcard (including preceding '-'). */
5804 if (end = strchr (charset, '*'))
5806 if (end > charset && *(end-1) == '-')
5807 end--;
5808 *end = '\0';
5811 codepage = Fcdr (Fcdr (Fassoc (build_string(charset),
5812 Vw32_charset_info_alist)));
5813 if (INTEGERP (codepage))
5814 return XINT (codepage);
5815 else
5816 return CP_DEFAULT;
5820 BOOL
5821 w32_to_x_font (lplogfont, lpxstr, len)
5822 LOGFONT * lplogfont;
5823 char * lpxstr;
5824 int len;
5826 char* fonttype;
5827 char *fontname;
5828 char height_pixels[8];
5829 char height_dpi[8];
5830 char width_pixels[8];
5831 char *fontname_dash;
5832 int display_resy = one_w32_display_info.resy;
5833 int display_resx = one_w32_display_info.resx;
5834 int bufsz;
5835 struct coding_system coding;
5837 if (!lpxstr) abort ();
5839 if (!lplogfont)
5840 return FALSE;
5842 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5843 fonttype = "raster";
5844 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5845 fonttype = "outline";
5846 else
5847 fonttype = "unknown";
5849 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
5850 &coding);
5851 coding.src_multibyte = 0;
5852 coding.dst_multibyte = 1;
5853 coding.mode |= CODING_MODE_LAST_BLOCK;
5854 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
5856 fontname = alloca(sizeof(*fontname) * bufsz);
5857 decode_coding (&coding, lplogfont->lfFaceName, fontname,
5858 strlen(lplogfont->lfFaceName), bufsz - 1);
5859 *(fontname + coding.produced) = '\0';
5861 /* Replace dashes with underscores so the dashes are not
5862 misinterpreted. */
5863 fontname_dash = fontname;
5864 while (fontname_dash = strchr (fontname_dash, '-'))
5865 *fontname_dash = '_';
5867 if (lplogfont->lfHeight)
5869 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
5870 sprintf (height_dpi, "%u",
5871 abs (lplogfont->lfHeight) * 720 / display_resy);
5873 else
5875 strcpy (height_pixels, "*");
5876 strcpy (height_dpi, "*");
5878 if (lplogfont->lfWidth)
5879 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5880 else
5881 strcpy (width_pixels, "*");
5883 _snprintf (lpxstr, len - 1,
5884 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5885 fonttype, /* foundry */
5886 fontname, /* family */
5887 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5888 lplogfont->lfItalic?'i':'r', /* slant */
5889 /* setwidth name */
5890 /* add style name */
5891 height_pixels, /* pixel size */
5892 height_dpi, /* point size */
5893 display_resx, /* resx */
5894 display_resy, /* resy */
5895 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5896 ? 'p' : 'c', /* spacing */
5897 width_pixels, /* avg width */
5898 w32_to_x_charset (lplogfont->lfCharSet) /* charset registry
5899 and encoding*/
5902 lpxstr[len - 1] = 0; /* just to be sure */
5903 return (TRUE);
5906 BOOL
5907 x_to_w32_font (lpxstr, lplogfont)
5908 char * lpxstr;
5909 LOGFONT * lplogfont;
5911 struct coding_system coding;
5913 if (!lplogfont) return (FALSE);
5915 memset (lplogfont, 0, sizeof (*lplogfont));
5917 /* Set default value for each field. */
5918 #if 1
5919 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5920 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5921 lplogfont->lfQuality = DEFAULT_QUALITY;
5922 #else
5923 /* go for maximum quality */
5924 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5925 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5926 lplogfont->lfQuality = PROOF_QUALITY;
5927 #endif
5929 lplogfont->lfCharSet = DEFAULT_CHARSET;
5930 lplogfont->lfWeight = FW_DONTCARE;
5931 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5933 if (!lpxstr)
5934 return FALSE;
5936 /* Provide a simple escape mechanism for specifying Windows font names
5937 * directly -- if font spec does not beginning with '-', assume this
5938 * format:
5939 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5942 if (*lpxstr == '-')
5944 int fields, tem;
5945 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5946 width[10], resy[10], remainder[20];
5947 char * encoding;
5948 int dpi = one_w32_display_info.height_in;
5950 fields = sscanf (lpxstr,
5951 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%19s",
5952 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5953 if (fields == EOF) return (FALSE);
5955 /* If wildcards cover more than one field, we don't know which
5956 field is which, so don't fill any in. */
5958 if (fields < 9)
5959 fields = 0;
5961 if (fields > 0 && name[0] != '*')
5963 int bufsize;
5964 unsigned char *buf;
5966 setup_coding_system
5967 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
5968 coding.src_multibyte = 1;
5969 coding.dst_multibyte = 1;
5970 bufsize = encoding_buffer_size (&coding, strlen (name));
5971 buf = (unsigned char *) alloca (bufsize);
5972 coding.mode |= CODING_MODE_LAST_BLOCK;
5973 encode_coding (&coding, name, buf, strlen (name), bufsize);
5974 if (coding.produced >= LF_FACESIZE)
5975 coding.produced = LF_FACESIZE - 1;
5976 buf[coding.produced] = 0;
5977 strcpy (lplogfont->lfFaceName, buf);
5979 else
5981 lplogfont->lfFaceName[0] = '\0';
5984 fields--;
5986 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5988 fields--;
5990 if (!NILP (Vw32_enable_synthesized_fonts))
5991 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5993 fields--;
5995 if (fields > 0 && pixels[0] != '*')
5996 lplogfont->lfHeight = atoi (pixels);
5998 fields--;
5999 fields--;
6000 if (fields > 0 && resy[0] != '*')
6002 tem = atoi (resy);
6003 if (tem > 0) dpi = tem;
6006 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6007 lplogfont->lfHeight = atoi (height) * dpi / 720;
6009 if (fields > 0)
6010 lplogfont->lfPitchAndFamily =
6011 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6013 fields--;
6015 if (fields > 0 && width[0] != '*')
6016 lplogfont->lfWidth = atoi (width) / 10;
6018 fields--;
6020 /* Strip the trailing '-' if present. (it shouldn't be, as it
6021 fails the test against xlfd-tight-regexp in fontset.el). */
6023 int len = strlen (remainder);
6024 if (len > 0 && remainder[len-1] == '-')
6025 remainder[len-1] = 0;
6027 encoding = remainder;
6028 if (strncmp (encoding, "*-", 2) == 0)
6029 encoding += 2;
6030 lplogfont->lfCharSet = x_to_w32_charset (fields > 0 ? encoding : "");
6032 else
6034 int fields;
6035 char name[100], height[10], width[10], weight[20];
6037 fields = sscanf (lpxstr,
6038 "%99[^:]:%9[^:]:%9[^:]:%19s",
6039 name, height, width, weight);
6041 if (fields == EOF) return (FALSE);
6043 if (fields > 0)
6045 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6046 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6048 else
6050 lplogfont->lfFaceName[0] = 0;
6053 fields--;
6055 if (fields > 0)
6056 lplogfont->lfHeight = atoi (height);
6058 fields--;
6060 if (fields > 0)
6061 lplogfont->lfWidth = atoi (width);
6063 fields--;
6065 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6068 /* This makes TrueType fonts work better. */
6069 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6071 return (TRUE);
6074 /* Strip the pixel height and point height from the given xlfd, and
6075 return the pixel height. If no pixel height is specified, calculate
6076 one from the point height, or if that isn't defined either, return
6077 0 (which usually signifies a scalable font).
6079 int xlfd_strip_height (char *fontname)
6081 int pixel_height, point_height, dpi, field_number;
6082 char *read_from, *write_to;
6084 xassert (fontname);
6086 pixel_height = field_number = 0;
6087 write_to = NULL;
6089 /* Look for height fields. */
6090 for (read_from = fontname; *read_from; read_from++)
6092 if (*read_from == '-')
6094 field_number++;
6095 if (field_number == 7) /* Pixel height. */
6097 read_from++;
6098 write_to = read_from;
6100 /* Find end of field. */
6101 for (;*read_from && *read_from != '-'; read_from++)
6104 /* Split the fontname at end of field. */
6105 if (*read_from)
6107 *read_from = '\0';
6108 read_from++;
6110 pixel_height = atoi (write_to);
6111 /* Blank out field. */
6112 if (read_from > write_to)
6114 *write_to = '-';
6115 write_to++;
6117 /* If the pixel height field is at the end (partial xfld),
6118 return now. */
6119 else
6120 return pixel_height;
6122 /* If we got a pixel height, the point height can be
6123 ignored. Just blank it out and break now. */
6124 if (pixel_height)
6126 /* Find end of point size field. */
6127 for (; *read_from && *read_from != '-'; read_from++)
6130 if (*read_from)
6131 read_from++;
6133 /* Blank out the point size field. */
6134 if (read_from > write_to)
6136 *write_to = '-';
6137 write_to++;
6139 else
6140 return pixel_height;
6142 break;
6144 /* If the point height is already blank, break now. */
6145 if (*read_from == '-')
6147 read_from++;
6148 break;
6151 else if (field_number == 8)
6153 /* If we didn't get a pixel height, try to get the point
6154 height and convert that. */
6155 int point_size;
6156 char *point_size_start = read_from++;
6158 /* Find end of field. */
6159 for (; *read_from && *read_from != '-'; read_from++)
6162 if (*read_from)
6164 *read_from = '\0';
6165 read_from++;
6168 point_size = atoi (point_size_start);
6170 /* Convert to pixel height. */
6171 pixel_height = point_size
6172 * one_w32_display_info.height_in / 720;
6174 /* Blank out this field and break. */
6175 *write_to = '-';
6176 write_to++;
6177 break;
6182 /* Shift the rest of the font spec into place. */
6183 if (write_to && read_from > write_to)
6185 for (; *read_from; read_from++, write_to++)
6186 *write_to = *read_from;
6187 *write_to = '\0';
6190 return pixel_height;
6193 /* Assume parameter 1 is fully qualified, no wildcards. */
6194 BOOL
6195 w32_font_match (fontname, pattern)
6196 char * fontname;
6197 char * pattern;
6199 char *regex = alloca (strlen (pattern) * 2);
6200 char *font_name_copy = alloca (strlen (fontname) + 1);
6201 char *ptr;
6203 /* Copy fontname so we can modify it during comparison. */
6204 strcpy (font_name_copy, fontname);
6206 ptr = regex;
6207 *ptr++ = '^';
6209 /* Turn pattern into a regexp and do a regexp match. */
6210 for (; *pattern; pattern++)
6212 if (*pattern == '?')
6213 *ptr++ = '.';
6214 else if (*pattern == '*')
6216 *ptr++ = '.';
6217 *ptr++ = '*';
6219 else
6220 *ptr++ = *pattern;
6222 *ptr = '$';
6223 *(ptr + 1) = '\0';
6225 /* Strip out font heights and compare them seperately, since
6226 rounding error can cause mismatches. This also allows a
6227 comparison between a font that declares only a pixel height and a
6228 pattern that declares the point height.
6231 int font_height, pattern_height;
6233 font_height = xlfd_strip_height (font_name_copy);
6234 pattern_height = xlfd_strip_height (regex);
6236 /* Compare now, and don't bother doing expensive regexp matching
6237 if the heights differ. */
6238 if (font_height && pattern_height && (font_height != pattern_height))
6239 return FALSE;
6242 return (fast_c_string_match_ignore_case (build_string (regex),
6243 font_name_copy) >= 0);
6246 /* Callback functions, and a structure holding info they need, for
6247 listing system fonts on W32. We need one set of functions to do the
6248 job properly, but these don't work on NT 3.51 and earlier, so we
6249 have a second set which don't handle character sets properly to
6250 fall back on.
6252 In both cases, there are two passes made. The first pass gets one
6253 font from each family, the second pass lists all the fonts from
6254 each family. */
6256 typedef struct enumfont_t
6258 HDC hdc;
6259 int numFonts;
6260 LOGFONT logfont;
6261 XFontStruct *size_ref;
6262 Lisp_Object *pattern;
6263 Lisp_Object *tail;
6264 } enumfont_t;
6266 int CALLBACK
6267 enum_font_cb2 (lplf, lptm, FontType, lpef)
6268 ENUMLOGFONT * lplf;
6269 NEWTEXTMETRIC * lptm;
6270 int FontType;
6271 enumfont_t * lpef;
6273 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6274 return (1);
6276 /* Check that the character set matches if it was specified */
6277 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6278 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6279 return (1);
6282 char buf[100];
6283 Lisp_Object width = Qnil;
6285 /* Truetype fonts do not report their true metrics until loaded */
6286 if (FontType != RASTER_FONTTYPE)
6288 if (!NILP (*(lpef->pattern)))
6290 /* Scalable fonts are as big as you want them to be. */
6291 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6292 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6293 width = make_number (lpef->logfont.lfWidth);
6295 else
6297 lplf->elfLogFont.lfHeight = 0;
6298 lplf->elfLogFont.lfWidth = 0;
6302 /* Make sure the height used here is the same as everywhere
6303 else (ie character height, not cell height). */
6304 if (lplf->elfLogFont.lfHeight > 0)
6306 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6307 if (FontType == RASTER_FONTTYPE)
6308 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6309 else
6310 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6313 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100))
6314 return (0);
6316 if (NILP (*(lpef->pattern))
6317 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6319 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6320 lpef->tail = &(XCDR (*lpef->tail));
6321 lpef->numFonts++;
6325 return (1);
6328 int CALLBACK
6329 enum_font_cb1 (lplf, lptm, FontType, lpef)
6330 ENUMLOGFONT * lplf;
6331 NEWTEXTMETRIC * lptm;
6332 int FontType;
6333 enumfont_t * lpef;
6335 return EnumFontFamilies (lpef->hdc,
6336 lplf->elfLogFont.lfFaceName,
6337 (FONTENUMPROC) enum_font_cb2,
6338 (LPARAM) lpef);
6342 int CALLBACK
6343 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6344 ENUMLOGFONTEX * lplf;
6345 NEWTEXTMETRICEX * lptm;
6346 int font_type;
6347 enumfont_t * lpef;
6349 /* We are not interested in the extra info we get back from the 'Ex
6350 version - only the fact that we get character set variations
6351 enumerated seperately. */
6352 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6353 font_type, lpef);
6356 int CALLBACK
6357 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6358 ENUMLOGFONTEX * lplf;
6359 NEWTEXTMETRICEX * lptm;
6360 int font_type;
6361 enumfont_t * lpef;
6363 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6364 FARPROC enum_font_families_ex
6365 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6366 /* We don't really expect EnumFontFamiliesEx to disappear once we
6367 get here, so don't bother handling it gracefully. */
6368 if (enum_font_families_ex == NULL)
6369 error ("gdi32.dll has disappeared!");
6370 return enum_font_families_ex (lpef->hdc,
6371 &lplf->elfLogFont,
6372 (FONTENUMPROC) enum_fontex_cb2,
6373 (LPARAM) lpef, 0);
6376 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6377 and xterm.c in Emacs 20.3) */
6379 Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6381 char *fontname, *ptnstr;
6382 Lisp_Object list, tem, newlist = Qnil;
6383 int n_fonts = 0;
6385 list = Vw32_bdf_filename_alist;
6386 ptnstr = XSTRING (pattern)->data;
6388 for ( ; CONSP (list); list = XCDR (list))
6390 tem = XCAR (list);
6391 if (CONSP (tem))
6392 fontname = XSTRING (XCAR (tem))->data;
6393 else if (STRINGP (tem))
6394 fontname = XSTRING (tem)->data;
6395 else
6396 continue;
6398 if (w32_font_match (fontname, ptnstr))
6400 newlist = Fcons (XCAR (tem), newlist);
6401 n_fonts++;
6402 if (n_fonts >= max_names)
6403 break;
6407 return newlist;
6410 Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f, Lisp_Object pattern,
6411 int size, int max_names);
6413 /* Return a list of names of available fonts matching PATTERN on frame
6414 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6415 to be listed. Frame F NULL means we have not yet created any
6416 frame, which means we can't get proper size info, as we don't have
6417 a device context to use for GetTextMetrics.
6418 MAXNAMES sets a limit on how many fonts to match. */
6420 Lisp_Object
6421 w32_list_fonts (FRAME_PTR f, Lisp_Object pattern, int size, int maxnames )
6423 Lisp_Object patterns, key = Qnil, tem, tpat;
6424 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6425 struct w32_display_info *dpyinfo = &one_w32_display_info;
6426 int n_fonts = 0;
6428 patterns = Fassoc (pattern, Valternate_fontname_alist);
6429 if (NILP (patterns))
6430 patterns = Fcons (pattern, Qnil);
6432 for (; CONSP (patterns); patterns = XCDR (patterns))
6434 enumfont_t ef;
6436 tpat = XCAR (patterns);
6438 /* See if we cached the result for this particular query.
6439 The cache is an alist of the form:
6440 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6442 if (tem = XCDR (dpyinfo->name_list_element),
6443 !NILP (list = Fassoc (tpat, tem)))
6445 list = Fcdr_safe (list);
6446 /* We have a cached list. Don't have to get the list again. */
6447 goto label_cached;
6450 BLOCK_INPUT;
6451 /* At first, put PATTERN in the cache. */
6452 list = Qnil;
6453 ef.pattern = &tpat;
6454 ef.tail = &list;
6455 ef.numFonts = 0;
6457 /* Use EnumFontFamiliesEx where it is available, as it knows
6458 about character sets. Fall back to EnumFontFamilies for
6459 older versions of NT that don't support the 'Ex function. */
6460 x_to_w32_font (STRINGP (tpat) ? XSTRING (tpat)->data :
6461 NULL, &ef.logfont);
6463 LOGFONT font_match_pattern;
6464 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6465 FARPROC enum_font_families_ex
6466 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6468 /* We do our own pattern matching so we can handle wildcards. */
6469 font_match_pattern.lfFaceName[0] = 0;
6470 font_match_pattern.lfPitchAndFamily = 0;
6471 /* We can use the charset, because if it is a wildcard it will
6472 be DEFAULT_CHARSET anyway. */
6473 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6475 ef.hdc = GetDC (dpyinfo->root_window);
6477 if (enum_font_families_ex)
6478 enum_font_families_ex (ef.hdc,
6479 &font_match_pattern,
6480 (FONTENUMPROC) enum_fontex_cb1,
6481 (LPARAM) &ef, 0);
6482 else
6483 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6484 (LPARAM)&ef);
6486 ReleaseDC (dpyinfo->root_window, ef.hdc);
6489 UNBLOCK_INPUT;
6491 /* Make a list of the fonts we got back.
6492 Store that in the font cache for the display. */
6493 XCDR (dpyinfo->name_list_element)
6494 = Fcons (Fcons (tpat, list),
6495 XCDR (dpyinfo->name_list_element));
6497 label_cached:
6498 if (NILP (list)) continue; /* Try the remaining alternatives. */
6500 newlist = second_best = Qnil;
6502 /* Make a list of the fonts that have the right width. */
6503 for (; CONSP (list); list = XCDR (list))
6505 int found_size;
6506 tem = XCAR (list);
6508 if (!CONSP (tem))
6509 continue;
6510 if (NILP (XCAR (tem)))
6511 continue;
6512 if (!size)
6514 newlist = Fcons (XCAR (tem), newlist);
6515 n_fonts++;
6516 if (n_fonts >= maxnames)
6517 break;
6518 else
6519 continue;
6521 if (!INTEGERP (XCDR (tem)))
6523 /* Since we don't yet know the size of the font, we must
6524 load it and try GetTextMetrics. */
6525 W32FontStruct thisinfo;
6526 LOGFONT lf;
6527 HDC hdc;
6528 HANDLE oldobj;
6530 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6531 continue;
6533 BLOCK_INPUT;
6534 thisinfo.bdf = NULL;
6535 thisinfo.hfont = CreateFontIndirect (&lf);
6536 if (thisinfo.hfont == NULL)
6537 continue;
6539 hdc = GetDC (dpyinfo->root_window);
6540 oldobj = SelectObject (hdc, thisinfo.hfont);
6541 if (GetTextMetrics (hdc, &thisinfo.tm))
6542 XCDR (tem) = make_number (FONT_WIDTH (&thisinfo));
6543 else
6544 XCDR (tem) = make_number (0);
6545 SelectObject (hdc, oldobj);
6546 ReleaseDC (dpyinfo->root_window, hdc);
6547 DeleteObject(thisinfo.hfont);
6548 UNBLOCK_INPUT;
6550 found_size = XINT (XCDR (tem));
6551 if (found_size == size)
6553 newlist = Fcons (XCAR (tem), newlist);
6554 n_fonts++;
6555 if (n_fonts >= maxnames)
6556 break;
6558 /* keep track of the closest matching size in case
6559 no exact match is found. */
6560 else if (found_size > 0)
6562 if (NILP (second_best))
6563 second_best = tem;
6565 else if (found_size < size)
6567 if (XINT (XCDR (second_best)) > size
6568 || XINT (XCDR (second_best)) < found_size)
6569 second_best = tem;
6571 else
6573 if (XINT (XCDR (second_best)) > size
6574 && XINT (XCDR (second_best)) >
6575 found_size)
6576 second_best = tem;
6581 if (!NILP (newlist))
6582 break;
6583 else if (!NILP (second_best))
6585 newlist = Fcons (XCAR (second_best), Qnil);
6586 break;
6590 /* Include any bdf fonts. */
6591 if (n_fonts < maxnames)
6593 Lisp_Object combined[2];
6594 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6595 combined[1] = newlist;
6596 newlist = Fnconc(2, combined);
6599 /* If we can't find a font that matches, check if Windows would be
6600 able to synthesize it from a different style. */
6601 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
6602 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
6604 return newlist;
6607 Lisp_Object
6608 w32_list_synthesized_fonts (f, pattern, size, max_names)
6609 FRAME_PTR f;
6610 Lisp_Object pattern;
6611 int size;
6612 int max_names;
6614 int fields;
6615 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
6616 char style[20], slant;
6617 Lisp_Object matches, match, tem, synthed_matches = Qnil;
6619 full_pattn = XSTRING (pattern)->data;
6621 pattn_part2 = alloca (XSTRING (pattern)->size);
6622 /* Allow some space for wildcard expansion. */
6623 new_pattn = alloca (XSTRING (pattern)->size + 100);
6625 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
6626 foundary, family, style, &slant, pattn_part2);
6627 if (fields == EOF || fields < 5)
6628 return Qnil;
6630 /* If the style and slant are wildcards already there is no point
6631 checking again (and we don't want to keep recursing). */
6632 if (*style == '*' && slant == '*')
6633 return Qnil;
6635 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
6637 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
6639 for ( ; CONSP (matches); matches = XCDR (matches))
6641 tem = XCAR (matches);
6642 if (!STRINGP (tem))
6643 continue;
6645 full_pattn = XSTRING (tem)->data;
6646 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
6647 foundary, family, pattn_part2);
6648 if (fields == EOF || fields < 3)
6649 continue;
6651 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
6652 slant, pattn_part2);
6654 synthed_matches = Fcons (build_string (new_pattn),
6655 synthed_matches);
6658 return synthed_matches;
6662 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6663 struct font_info *
6664 w32_get_font_info (f, font_idx)
6665 FRAME_PTR f;
6666 int font_idx;
6668 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6672 struct font_info*
6673 w32_query_font (struct frame *f, char *fontname)
6675 int i;
6676 struct font_info *pfi;
6678 pfi = FRAME_W32_FONT_TABLE (f);
6680 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6682 if (strcmp(pfi->name, fontname) == 0) return pfi;
6685 return NULL;
6688 /* Find a CCL program for a font specified by FONTP, and set the member
6689 `encoder' of the structure. */
6691 void
6692 w32_find_ccl_program (fontp)
6693 struct font_info *fontp;
6695 Lisp_Object list, elt;
6697 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
6699 elt = XCAR (list);
6700 if (CONSP (elt)
6701 && STRINGP (XCAR (elt))
6702 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
6703 >= 0))
6704 break;
6706 if (! NILP (list))
6708 struct ccl_program *ccl
6709 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6711 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
6712 xfree (ccl);
6713 else
6714 fontp->font_encoder = ccl;
6719 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6720 1, 1, 0,
6721 "Return a list of BDF fonts in DIR, suitable for appending to\n\
6722 w32-bdf-filename-alist. Fonts which do not contain an xfld description\n\
6723 will not be included in the list. DIR may be a list of directories.")
6724 (directory)
6725 Lisp_Object directory;
6727 Lisp_Object list = Qnil;
6728 struct gcpro gcpro1, gcpro2;
6730 if (!CONSP (directory))
6731 return w32_find_bdf_fonts_in_dir (directory);
6733 for ( ; CONSP (directory); directory = XCDR (directory))
6735 Lisp_Object pair[2];
6736 pair[0] = list;
6737 pair[1] = Qnil;
6738 GCPRO2 (directory, list);
6739 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
6740 list = Fnconc( 2, pair );
6741 UNGCPRO;
6743 return list;
6746 /* Find BDF files in a specified directory. (use GCPRO when calling,
6747 as this calls lisp to get a directory listing). */
6748 Lisp_Object w32_find_bdf_fonts_in_dir( Lisp_Object directory )
6750 Lisp_Object filelist, list = Qnil;
6751 char fontname[100];
6753 if (!STRINGP(directory))
6754 return Qnil;
6756 filelist = Fdirectory_files (directory, Qt,
6757 build_string (".*\\.[bB][dD][fF]"), Qt);
6759 for ( ; CONSP(filelist); filelist = XCDR (filelist))
6761 Lisp_Object filename = XCAR (filelist);
6762 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
6763 store_in_alist (&list, build_string (fontname), filename);
6765 return list;
6769 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
6770 "Internal function called by `color-defined-p', which see.")
6771 (color, frame)
6772 Lisp_Object color, frame;
6774 XColor foo;
6775 FRAME_PTR f = check_x_frame (frame);
6777 CHECK_STRING (color, 1);
6779 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6780 return Qt;
6781 else
6782 return Qnil;
6785 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
6786 "Internal function called by `color-values', which see.")
6787 (color, frame)
6788 Lisp_Object color, frame;
6790 XColor foo;
6791 FRAME_PTR f = check_x_frame (frame);
6793 CHECK_STRING (color, 1);
6795 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
6797 Lisp_Object rgb[3];
6799 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
6800 | GetRValue (foo.pixel));
6801 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
6802 | GetGValue (foo.pixel));
6803 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
6804 | GetBValue (foo.pixel));
6805 return Flist (3, rgb);
6807 else
6808 return Qnil;
6811 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
6812 "Internal function called by `display-color-p', which see.")
6813 (display)
6814 Lisp_Object display;
6816 struct w32_display_info *dpyinfo = check_x_display_info (display);
6818 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6819 return Qnil;
6821 return Qt;
6824 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p, Sx_display_grayscale_p,
6825 0, 1, 0,
6826 "Return t if the X display supports shades of gray.\n\
6827 Note that color displays do support shades of gray.\n\
6828 The optional argument DISPLAY specifies which display to ask about.\n\
6829 DISPLAY should be either a frame or a display name (a string).\n\
6830 If omitted or nil, that stands for the selected frame's display.")
6831 (display)
6832 Lisp_Object display;
6834 struct w32_display_info *dpyinfo = check_x_display_info (display);
6836 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6837 return Qnil;
6839 return Qt;
6842 DEFUN ("x-display-pixel-width", Fx_display_pixel_width, Sx_display_pixel_width,
6843 0, 1, 0,
6844 "Returns the width in pixels of the X display DISPLAY.\n\
6845 The optional argument DISPLAY specifies which display to ask about.\n\
6846 DISPLAY should be either a frame or a display name (a string).\n\
6847 If omitted or nil, that stands for the selected frame's display.")
6848 (display)
6849 Lisp_Object display;
6851 struct w32_display_info *dpyinfo = check_x_display_info (display);
6853 return make_number (dpyinfo->width);
6856 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6857 Sx_display_pixel_height, 0, 1, 0,
6858 "Returns the height in pixels of the X display DISPLAY.\n\
6859 The optional argument DISPLAY specifies which display to ask about.\n\
6860 DISPLAY should be either a frame or a display name (a string).\n\
6861 If omitted or nil, that stands for the selected frame's display.")
6862 (display)
6863 Lisp_Object display;
6865 struct w32_display_info *dpyinfo = check_x_display_info (display);
6867 return make_number (dpyinfo->height);
6870 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6871 0, 1, 0,
6872 "Returns the number of bitplanes of the display DISPLAY.\n\
6873 The optional argument DISPLAY specifies which display to ask about.\n\
6874 DISPLAY should be either a frame or a display name (a string).\n\
6875 If omitted or nil, that stands for the selected frame's display.")
6876 (display)
6877 Lisp_Object display;
6879 struct w32_display_info *dpyinfo = check_x_display_info (display);
6881 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6884 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6885 0, 1, 0,
6886 "Returns the number of color cells of the display DISPLAY.\n\
6887 The optional argument DISPLAY specifies which display to ask about.\n\
6888 DISPLAY should be either a frame or a display name (a string).\n\
6889 If omitted or nil, that stands for the selected frame's display.")
6890 (display)
6891 Lisp_Object display;
6893 struct w32_display_info *dpyinfo = check_x_display_info (display);
6894 HDC hdc;
6895 int cap;
6897 hdc = GetDC (dpyinfo->root_window);
6898 if (dpyinfo->has_palette)
6899 cap = GetDeviceCaps (hdc,SIZEPALETTE);
6900 else
6901 cap = GetDeviceCaps (hdc,NUMCOLORS);
6903 ReleaseDC (dpyinfo->root_window, hdc);
6905 return make_number (cap);
6908 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6909 Sx_server_max_request_size,
6910 0, 1, 0,
6911 "Returns the maximum request size of the server of display DISPLAY.\n\
6912 The optional argument DISPLAY specifies which display to ask about.\n\
6913 DISPLAY should be either a frame or a display name (a string).\n\
6914 If omitted or nil, that stands for the selected frame's display.")
6915 (display)
6916 Lisp_Object display;
6918 struct w32_display_info *dpyinfo = check_x_display_info (display);
6920 return make_number (1);
6923 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
6924 "Returns the vendor ID string of the W32 system (Microsoft).\n\
6925 The optional argument DISPLAY specifies which display to ask about.\n\
6926 DISPLAY should be either a frame or a display name (a string).\n\
6927 If omitted or nil, that stands for the selected frame's display.")
6928 (display)
6929 Lisp_Object display;
6931 return build_string ("Microsoft Corp.");
6934 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6935 "Returns the version numbers of the server of display DISPLAY.\n\
6936 The value is a list of three integers: the major and minor\n\
6937 version numbers, and the vendor-specific release\n\
6938 number. See also the function `x-server-vendor'.\n\n\
6939 The optional argument DISPLAY specifies which display to ask about.\n\
6940 DISPLAY should be either a frame or a display name (a string).\n\
6941 If omitted or nil, that stands for the selected frame's display.")
6942 (display)
6943 Lisp_Object display;
6945 return Fcons (make_number (w32_major_version),
6946 Fcons (make_number (w32_minor_version), Qnil));
6949 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6950 "Returns the number of screens on the server of display DISPLAY.\n\
6951 The optional argument DISPLAY specifies which display to ask about.\n\
6952 DISPLAY should be either a frame or a display name (a string).\n\
6953 If omitted or nil, that stands for the selected frame's display.")
6954 (display)
6955 Lisp_Object display;
6957 return make_number (1);
6960 DEFUN ("x-display-mm-height", Fx_display_mm_height, Sx_display_mm_height, 0, 1, 0,
6961 "Returns the height in millimeters of the X display DISPLAY.\n\
6962 The optional argument DISPLAY specifies which display to ask about.\n\
6963 DISPLAY should be either a frame or a display name (a string).\n\
6964 If omitted or nil, that stands for the selected frame's display.")
6965 (display)
6966 Lisp_Object display;
6968 struct w32_display_info *dpyinfo = check_x_display_info (display);
6969 HDC hdc;
6970 int cap;
6972 hdc = GetDC (dpyinfo->root_window);
6974 cap = GetDeviceCaps (hdc, VERTSIZE);
6976 ReleaseDC (dpyinfo->root_window, hdc);
6978 return make_number (cap);
6981 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
6982 "Returns the width in millimeters of the X display DISPLAY.\n\
6983 The optional argument DISPLAY specifies which display to ask about.\n\
6984 DISPLAY should be either a frame or a display name (a string).\n\
6985 If omitted or nil, that stands for the selected frame's display.")
6986 (display)
6987 Lisp_Object display;
6989 struct w32_display_info *dpyinfo = check_x_display_info (display);
6991 HDC hdc;
6992 int cap;
6994 hdc = GetDC (dpyinfo->root_window);
6996 cap = GetDeviceCaps (hdc, HORZSIZE);
6998 ReleaseDC (dpyinfo->root_window, hdc);
7000 return make_number (cap);
7003 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7004 Sx_display_backing_store, 0, 1, 0,
7005 "Returns an indication of whether display DISPLAY does backing store.\n\
7006 The value may be `always', `when-mapped', or `not-useful'.\n\
7007 The optional argument DISPLAY specifies which display to ask about.\n\
7008 DISPLAY should be either a frame or a display name (a string).\n\
7009 If omitted or nil, that stands for the selected frame's display.")
7010 (display)
7011 Lisp_Object display;
7013 return intern ("not-useful");
7016 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7017 Sx_display_visual_class, 0, 1, 0,
7018 "Returns the visual class of the display DISPLAY.\n\
7019 The value is one of the symbols `static-gray', `gray-scale',\n\
7020 `static-color', `pseudo-color', `true-color', or `direct-color'.\n\n\
7021 The optional argument DISPLAY specifies which display to ask about.\n\
7022 DISPLAY should be either a frame or a display name (a string).\n\
7023 If omitted or nil, that stands for the selected frame's display.")
7024 (display)
7025 Lisp_Object display;
7027 struct w32_display_info *dpyinfo = check_x_display_info (display);
7029 #if 0
7030 switch (dpyinfo->visual->class)
7032 case StaticGray: return (intern ("static-gray"));
7033 case GrayScale: return (intern ("gray-scale"));
7034 case StaticColor: return (intern ("static-color"));
7035 case PseudoColor: return (intern ("pseudo-color"));
7036 case TrueColor: return (intern ("true-color"));
7037 case DirectColor: return (intern ("direct-color"));
7038 default:
7039 error ("Display has an unknown visual class");
7041 #endif
7043 error ("Display has an unknown visual class");
7046 DEFUN ("x-display-save-under", Fx_display_save_under,
7047 Sx_display_save_under, 0, 1, 0,
7048 "Returns t if the display DISPLAY supports the save-under feature.\n\
7049 The optional argument DISPLAY specifies which display to ask about.\n\
7050 DISPLAY should be either a frame or a display name (a string).\n\
7051 If omitted or nil, that stands for the selected frame's display.")
7052 (display)
7053 Lisp_Object display;
7055 return Qnil;
7059 x_pixel_width (f)
7060 register struct frame *f;
7062 return PIXEL_WIDTH (f);
7066 x_pixel_height (f)
7067 register struct frame *f;
7069 return PIXEL_HEIGHT (f);
7073 x_char_width (f)
7074 register struct frame *f;
7076 return FONT_WIDTH (f->output_data.w32->font);
7080 x_char_height (f)
7081 register struct frame *f;
7083 return f->output_data.w32->line_height;
7087 x_screen_planes (f)
7088 register struct frame *f;
7090 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7093 /* Return the display structure for the display named NAME.
7094 Open a new connection if necessary. */
7096 struct w32_display_info *
7097 x_display_info_for_name (name)
7098 Lisp_Object name;
7100 Lisp_Object names;
7101 struct w32_display_info *dpyinfo;
7103 CHECK_STRING (name, 0);
7105 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7106 dpyinfo;
7107 dpyinfo = dpyinfo->next, names = XCDR (names))
7109 Lisp_Object tem;
7110 tem = Fstring_equal (XCAR (XCAR (names)), name);
7111 if (!NILP (tem))
7112 return dpyinfo;
7115 /* Use this general default value to start with. */
7116 Vx_resource_name = Vinvocation_name;
7118 validate_x_resource_name ();
7120 dpyinfo = w32_term_init (name, (unsigned char *)0,
7121 (char *) XSTRING (Vx_resource_name)->data);
7123 if (dpyinfo == 0)
7124 error ("Cannot connect to server %s", XSTRING (name)->data);
7126 w32_in_use = 1;
7127 XSETFASTINT (Vwindow_system_version, 3);
7129 return dpyinfo;
7132 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7133 1, 3, 0, "Open a connection to a server.\n\
7134 DISPLAY is the name of the display to connect to.\n\
7135 Optional second arg XRM-STRING is a string of resources in xrdb format.\n\
7136 If the optional third arg MUST-SUCCEED is non-nil,\n\
7137 terminate Emacs if we can't open the connection.")
7138 (display, xrm_string, must_succeed)
7139 Lisp_Object display, xrm_string, must_succeed;
7141 unsigned char *xrm_option;
7142 struct w32_display_info *dpyinfo;
7144 CHECK_STRING (display, 0);
7145 if (! NILP (xrm_string))
7146 CHECK_STRING (xrm_string, 1);
7148 if (! EQ (Vwindow_system, intern ("w32")))
7149 error ("Not using Microsoft Windows");
7151 /* Allow color mapping to be defined externally; first look in user's
7152 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7154 Lisp_Object color_file;
7155 struct gcpro gcpro1;
7157 color_file = build_string("~/rgb.txt");
7159 GCPRO1 (color_file);
7161 if (NILP (Ffile_readable_p (color_file)))
7162 color_file =
7163 Fexpand_file_name (build_string ("rgb.txt"),
7164 Fsymbol_value (intern ("data-directory")));
7166 Vw32_color_map = Fw32_load_color_file (color_file);
7168 UNGCPRO;
7170 if (NILP (Vw32_color_map))
7171 Vw32_color_map = Fw32_default_color_map ();
7173 if (! NILP (xrm_string))
7174 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7175 else
7176 xrm_option = (unsigned char *) 0;
7178 /* Use this general default value to start with. */
7179 /* First remove .exe suffix from invocation-name - it looks ugly. */
7181 char basename[ MAX_PATH ], *str;
7183 strcpy (basename, XSTRING (Vinvocation_name)->data);
7184 str = strrchr (basename, '.');
7185 if (str) *str = 0;
7186 Vinvocation_name = build_string (basename);
7188 Vx_resource_name = Vinvocation_name;
7190 validate_x_resource_name ();
7192 /* This is what opens the connection and sets x_current_display.
7193 This also initializes many symbols, such as those used for input. */
7194 dpyinfo = w32_term_init (display, xrm_option,
7195 (char *) XSTRING (Vx_resource_name)->data);
7197 if (dpyinfo == 0)
7199 if (!NILP (must_succeed))
7200 fatal ("Cannot connect to server %s.\n",
7201 XSTRING (display)->data);
7202 else
7203 error ("Cannot connect to server %s", XSTRING (display)->data);
7206 w32_in_use = 1;
7208 XSETFASTINT (Vwindow_system_version, 3);
7209 return Qnil;
7212 DEFUN ("x-close-connection", Fx_close_connection,
7213 Sx_close_connection, 1, 1, 0,
7214 "Close the connection to DISPLAY's server.\n\
7215 For DISPLAY, specify either a frame or a display name (a string).\n\
7216 If DISPLAY is nil, that stands for the selected frame's display.")
7217 (display)
7218 Lisp_Object display;
7220 struct w32_display_info *dpyinfo = check_x_display_info (display);
7221 int i;
7223 if (dpyinfo->reference_count > 0)
7224 error ("Display still has frames on it");
7226 BLOCK_INPUT;
7227 /* Free the fonts in the font table. */
7228 for (i = 0; i < dpyinfo->n_fonts; i++)
7229 if (dpyinfo->font_table[i].name)
7231 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7232 xfree (dpyinfo->font_table[i].full_name);
7233 xfree (dpyinfo->font_table[i].name);
7234 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7236 x_destroy_all_bitmaps (dpyinfo);
7238 x_delete_display (dpyinfo);
7239 UNBLOCK_INPUT;
7241 return Qnil;
7244 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7245 "Return the list of display names that Emacs has connections to.")
7248 Lisp_Object tail, result;
7250 result = Qnil;
7251 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7252 result = Fcons (XCAR (XCAR (tail)), result);
7254 return result;
7257 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7258 "If ON is non-nil, report errors as soon as the erring request is made.\n\
7259 If ON is nil, allow buffering of requests.\n\
7260 This is a noop on W32 systems.\n\
7261 The optional second argument DISPLAY specifies which display to act on.\n\
7262 DISPLAY should be either a frame or a display name (a string).\n\
7263 If DISPLAY is omitted or nil, that stands for the selected frame's display.")
7264 (on, display)
7265 Lisp_Object display, on;
7267 return Qnil;
7272 /***********************************************************************
7273 Image types
7274 ***********************************************************************/
7276 /* Value is the number of elements of vector VECTOR. */
7278 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7280 /* List of supported image types. Use define_image_type to add new
7281 types. Use lookup_image_type to find a type for a given symbol. */
7283 static struct image_type *image_types;
7285 /* The symbol `image' which is the car of the lists used to represent
7286 images in Lisp. */
7288 extern Lisp_Object Qimage;
7290 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7292 Lisp_Object Qxbm;
7294 /* Keywords. */
7296 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7297 extern Lisp_Object QCdata;
7298 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7299 Lisp_Object QCalgorithm, QCcolor_symbols, QCheuristic_mask;
7300 Lisp_Object QCindex;
7302 /* Other symbols. */
7304 Lisp_Object Qlaplace;
7306 /* Time in seconds after which images should be removed from the cache
7307 if not displayed. */
7309 Lisp_Object Vimage_cache_eviction_delay;
7311 /* Function prototypes. */
7313 static void define_image_type P_ ((struct image_type *type));
7314 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7315 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7316 static void x_laplace P_ ((struct frame *, struct image *));
7317 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7318 Lisp_Object));
7321 /* Define a new image type from TYPE. This adds a copy of TYPE to
7322 image_types and adds the symbol *TYPE->type to Vimage_types. */
7324 static void
7325 define_image_type (type)
7326 struct image_type *type;
7328 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7329 The initialized data segment is read-only. */
7330 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7331 bcopy (type, p, sizeof *p);
7332 p->next = image_types;
7333 image_types = p;
7334 Vimage_types = Fcons (*p->type, Vimage_types);
7338 /* Look up image type SYMBOL, and return a pointer to its image_type
7339 structure. Value is null if SYMBOL is not a known image type. */
7341 static INLINE struct image_type *
7342 lookup_image_type (symbol)
7343 Lisp_Object symbol;
7345 struct image_type *type;
7347 for (type = image_types; type; type = type->next)
7348 if (EQ (symbol, *type->type))
7349 break;
7351 return type;
7355 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7356 valid image specification is a list whose car is the symbol
7357 `image', and whose rest is a property list. The property list must
7358 contain a value for key `:type'. That value must be the name of a
7359 supported image type. The rest of the property list depends on the
7360 image type. */
7363 valid_image_p (object)
7364 Lisp_Object object;
7366 int valid_p = 0;
7368 if (CONSP (object) && EQ (XCAR (object), Qimage))
7370 Lisp_Object symbol = Fplist_get (XCDR (object), QCtype);
7371 struct image_type *type = lookup_image_type (symbol);
7373 if (type)
7374 valid_p = type->valid_p (object);
7377 return valid_p;
7381 /* Log error message with format string FORMAT and argument ARG.
7382 Signaling an error, e.g. when an image cannot be loaded, is not a
7383 good idea because this would interrupt redisplay, and the error
7384 message display would lead to another redisplay. This function
7385 therefore simply displays a message. */
7387 static void
7388 image_error (format, arg1, arg2)
7389 char *format;
7390 Lisp_Object arg1, arg2;
7392 add_to_log (format, arg1, arg2);
7397 /***********************************************************************
7398 Image specifications
7399 ***********************************************************************/
7401 enum image_value_type
7403 IMAGE_DONT_CHECK_VALUE_TYPE,
7404 IMAGE_STRING_VALUE,
7405 IMAGE_SYMBOL_VALUE,
7406 IMAGE_POSITIVE_INTEGER_VALUE,
7407 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7408 IMAGE_ASCENT_VALUE,
7409 IMAGE_INTEGER_VALUE,
7410 IMAGE_FUNCTION_VALUE,
7411 IMAGE_NUMBER_VALUE,
7412 IMAGE_BOOL_VALUE
7415 /* Structure used when parsing image specifications. */
7417 struct image_keyword
7419 /* Name of keyword. */
7420 char *name;
7422 /* The type of value allowed. */
7423 enum image_value_type type;
7425 /* Non-zero means key must be present. */
7426 int mandatory_p;
7428 /* Used to recognize duplicate keywords in a property list. */
7429 int count;
7431 /* The value that was found. */
7432 Lisp_Object value;
7436 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7437 int, Lisp_Object));
7438 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7441 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7442 has the format (image KEYWORD VALUE ...). One of the keyword/
7443 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7444 image_keywords structures of size NKEYWORDS describing other
7445 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7447 static int
7448 parse_image_spec (spec, keywords, nkeywords, type)
7449 Lisp_Object spec;
7450 struct image_keyword *keywords;
7451 int nkeywords;
7452 Lisp_Object type;
7454 int i;
7455 Lisp_Object plist;
7457 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7458 return 0;
7460 plist = XCDR (spec);
7461 while (CONSP (plist))
7463 Lisp_Object key, value;
7465 /* First element of a pair must be a symbol. */
7466 key = XCAR (plist);
7467 plist = XCDR (plist);
7468 if (!SYMBOLP (key))
7469 return 0;
7471 /* There must follow a value. */
7472 if (!CONSP (plist))
7473 return 0;
7474 value = XCAR (plist);
7475 plist = XCDR (plist);
7477 /* Find key in KEYWORDS. Error if not found. */
7478 for (i = 0; i < nkeywords; ++i)
7479 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7480 break;
7482 if (i == nkeywords)
7483 continue;
7485 /* Record that we recognized the keyword. If a keywords
7486 was found more than once, it's an error. */
7487 keywords[i].value = value;
7488 ++keywords[i].count;
7490 if (keywords[i].count > 1)
7491 return 0;
7493 /* Check type of value against allowed type. */
7494 switch (keywords[i].type)
7496 case IMAGE_STRING_VALUE:
7497 if (!STRINGP (value))
7498 return 0;
7499 break;
7501 case IMAGE_SYMBOL_VALUE:
7502 if (!SYMBOLP (value))
7503 return 0;
7504 break;
7506 case IMAGE_POSITIVE_INTEGER_VALUE:
7507 if (!INTEGERP (value) || XINT (value) <= 0)
7508 return 0;
7509 break;
7511 case IMAGE_ASCENT_VALUE:
7512 if (SYMBOLP (value) && EQ (value, Qcenter))
7513 break;
7514 else if (INTEGERP (value)
7515 && XINT (value) >= 0
7516 && XINT (value) <= 100)
7517 break;
7518 return 0;
7520 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7521 if (!INTEGERP (value) || XINT (value) < 0)
7522 return 0;
7523 break;
7525 case IMAGE_DONT_CHECK_VALUE_TYPE:
7526 break;
7528 case IMAGE_FUNCTION_VALUE:
7529 value = indirect_function (value);
7530 if (SUBRP (value)
7531 || COMPILEDP (value)
7532 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
7533 break;
7534 return 0;
7536 case IMAGE_NUMBER_VALUE:
7537 if (!INTEGERP (value) && !FLOATP (value))
7538 return 0;
7539 break;
7541 case IMAGE_INTEGER_VALUE:
7542 if (!INTEGERP (value))
7543 return 0;
7544 break;
7546 case IMAGE_BOOL_VALUE:
7547 if (!NILP (value) && !EQ (value, Qt))
7548 return 0;
7549 break;
7551 default:
7552 abort ();
7553 break;
7556 if (EQ (key, QCtype) && !EQ (type, value))
7557 return 0;
7560 /* Check that all mandatory fields are present. */
7561 for (i = 0; i < nkeywords; ++i)
7562 if (keywords[i].mandatory_p && keywords[i].count == 0)
7563 return 0;
7565 return NILP (plist);
7569 /* Return the value of KEY in image specification SPEC. Value is nil
7570 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
7571 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
7573 static Lisp_Object
7574 image_spec_value (spec, key, found)
7575 Lisp_Object spec, key;
7576 int *found;
7578 Lisp_Object tail;
7580 xassert (valid_image_p (spec));
7582 for (tail = XCDR (spec);
7583 CONSP (tail) && CONSP (XCDR (tail));
7584 tail = XCDR (XCDR (tail)))
7586 if (EQ (XCAR (tail), key))
7588 if (found)
7589 *found = 1;
7590 return XCAR (XCDR (tail));
7594 if (found)
7595 *found = 0;
7596 return Qnil;
7602 /***********************************************************************
7603 Image type independent image structures
7604 ***********************************************************************/
7606 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
7607 static void free_image P_ ((struct frame *f, struct image *img));
7610 /* Allocate and return a new image structure for image specification
7611 SPEC. SPEC has a hash value of HASH. */
7613 static struct image *
7614 make_image (spec, hash)
7615 Lisp_Object spec;
7616 unsigned hash;
7618 struct image *img = (struct image *) xmalloc (sizeof *img);
7620 xassert (valid_image_p (spec));
7621 bzero (img, sizeof *img);
7622 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
7623 xassert (img->type != NULL);
7624 img->spec = spec;
7625 img->data.lisp_val = Qnil;
7626 img->ascent = DEFAULT_IMAGE_ASCENT;
7627 img->hash = hash;
7628 return img;
7632 /* Free image IMG which was used on frame F, including its resources. */
7634 static void
7635 free_image (f, img)
7636 struct frame *f;
7637 struct image *img;
7639 if (img)
7641 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7643 /* Remove IMG from the hash table of its cache. */
7644 if (img->prev)
7645 img->prev->next = img->next;
7646 else
7647 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
7649 if (img->next)
7650 img->next->prev = img->prev;
7652 c->images[img->id] = NULL;
7654 /* Free resources, then free IMG. */
7655 img->type->free (f, img);
7656 xfree (img);
7661 /* Prepare image IMG for display on frame F. Must be called before
7662 drawing an image. */
7664 void
7665 prepare_image_for_display (f, img)
7666 struct frame *f;
7667 struct image *img;
7669 EMACS_TIME t;
7671 /* We're about to display IMG, so set its timestamp to `now'. */
7672 EMACS_GET_TIME (t);
7673 img->timestamp = EMACS_SECS (t);
7675 /* If IMG doesn't have a pixmap yet, load it now, using the image
7676 type dependent loader function. */
7677 if (img->pixmap == 0 && !img->load_failed_p)
7678 img->load_failed_p = img->type->load (f, img) == 0;
7682 /* Value is the number of pixels for the ascent of image IMG when
7683 drawn in face FACE. */
7686 image_ascent (img, face)
7687 struct image *img;
7688 struct face *face;
7690 int height = img->height + img->margin;
7691 int ascent;
7693 if (img->ascent == CENTERED_IMAGE_ASCENT)
7695 if (face->font)
7696 ascent = height / 2 - (FONT_DESCENT(face->font)
7697 - FONT_BASE(face->font)) / 2;
7698 else
7699 ascent = height / 2;
7701 else
7702 ascent = height * img->ascent / 100.0;
7704 return ascent;
7709 /***********************************************************************
7710 Helper functions for X image types
7711 ***********************************************************************/
7713 static void x_clear_image P_ ((struct frame *f, struct image *img));
7714 static unsigned long x_alloc_image_color P_ ((struct frame *f,
7715 struct image *img,
7716 Lisp_Object color_name,
7717 unsigned long dflt));
7719 /* Free X resources of image IMG which is used on frame F. */
7721 static void
7722 x_clear_image (f, img)
7723 struct frame *f;
7724 struct image *img;
7726 #if 0 /* NTEMACS_TODO: W32 image support */
7728 if (img->pixmap)
7730 BLOCK_INPUT;
7731 XFreePixmap (NULL, img->pixmap);
7732 img->pixmap = 0;
7733 UNBLOCK_INPUT;
7736 if (img->ncolors)
7738 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
7740 /* If display has an immutable color map, freeing colors is not
7741 necessary and some servers don't allow it. So don't do it. */
7742 if (class != StaticColor
7743 && class != StaticGray
7744 && class != TrueColor)
7746 Colormap cmap;
7747 BLOCK_INPUT;
7748 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
7749 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
7750 img->ncolors, 0);
7751 UNBLOCK_INPUT;
7754 xfree (img->colors);
7755 img->colors = NULL;
7756 img->ncolors = 0;
7758 #endif
7762 /* Allocate color COLOR_NAME for image IMG on frame F. If color
7763 cannot be allocated, use DFLT. Add a newly allocated color to
7764 IMG->colors, so that it can be freed again. Value is the pixel
7765 color. */
7767 static unsigned long
7768 x_alloc_image_color (f, img, color_name, dflt)
7769 struct frame *f;
7770 struct image *img;
7771 Lisp_Object color_name;
7772 unsigned long dflt;
7774 #if 0 /* NTEMACS_TODO: allocing colors. */
7775 XColor color;
7776 unsigned long result;
7778 xassert (STRINGP (color_name));
7780 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
7782 /* This isn't called frequently so we get away with simply
7783 reallocating the color vector to the needed size, here. */
7784 ++img->ncolors;
7785 img->colors =
7786 (unsigned long *) xrealloc (img->colors,
7787 img->ncolors * sizeof *img->colors);
7788 img->colors[img->ncolors - 1] = color.pixel;
7789 result = color.pixel;
7791 else
7792 result = dflt;
7793 return result;
7794 #endif
7795 return 0;
7800 /***********************************************************************
7801 Image Cache
7802 ***********************************************************************/
7804 static void cache_image P_ ((struct frame *f, struct image *img));
7807 /* Return a new, initialized image cache that is allocated from the
7808 heap. Call free_image_cache to free an image cache. */
7810 struct image_cache *
7811 make_image_cache ()
7813 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
7814 int size;
7816 bzero (c, sizeof *c);
7817 c->size = 50;
7818 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
7819 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
7820 c->buckets = (struct image **) xmalloc (size);
7821 bzero (c->buckets, size);
7822 return c;
7826 /* Free image cache of frame F. Be aware that X frames share images
7827 caches. */
7829 void
7830 free_image_cache (f)
7831 struct frame *f;
7833 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7834 if (c)
7836 int i;
7838 /* Cache should not be referenced by any frame when freed. */
7839 xassert (c->refcount == 0);
7841 for (i = 0; i < c->used; ++i)
7842 free_image (f, c->images[i]);
7843 xfree (c->images);
7844 xfree (c);
7845 xfree (c->buckets);
7846 FRAME_X_IMAGE_CACHE (f) = NULL;
7851 /* Clear image cache of frame F. FORCE_P non-zero means free all
7852 images. FORCE_P zero means clear only images that haven't been
7853 displayed for some time. Should be called from time to time to
7854 reduce the number of loaded images. If image-eviction-seconds is
7855 non-nil, this frees images in the cache which weren't displayed for
7856 at least that many seconds. */
7858 void
7859 clear_image_cache (f, force_p)
7860 struct frame *f;
7861 int force_p;
7863 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7865 if (c && INTEGERP (Vimage_cache_eviction_delay))
7867 EMACS_TIME t;
7868 unsigned long old;
7869 int i, any_freed_p = 0;
7871 EMACS_GET_TIME (t);
7872 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
7874 for (i = 0; i < c->used; ++i)
7876 struct image *img = c->images[i];
7877 if (img != NULL
7878 && (force_p
7879 || (img->timestamp > old)))
7881 free_image (f, img);
7882 any_freed_p = 1;
7886 /* We may be clearing the image cache because, for example,
7887 Emacs was iconified for a longer period of time. In that
7888 case, current matrices may still contain references to
7889 images freed above. So, clear these matrices. */
7890 if (any_freed_p)
7892 clear_current_matrices (f);
7893 ++windows_or_buffers_changed;
7899 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
7900 0, 1, 0,
7901 "Clear the image cache of FRAME.\n\
7902 FRAME nil or omitted means use the selected frame.\n\
7903 FRAME t means clear the image caches of all frames.")
7904 (frame)
7905 Lisp_Object frame;
7907 if (EQ (frame, Qt))
7909 Lisp_Object tail;
7911 FOR_EACH_FRAME (tail, frame)
7912 if (FRAME_W32_P (XFRAME (frame)))
7913 clear_image_cache (XFRAME (frame), 1);
7915 else
7916 clear_image_cache (check_x_frame (frame), 1);
7918 return Qnil;
7922 /* Return the id of image with Lisp specification SPEC on frame F.
7923 SPEC must be a valid Lisp image specification (see valid_image_p). */
7926 lookup_image (f, spec)
7927 struct frame *f;
7928 Lisp_Object spec;
7930 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
7931 struct image *img;
7932 int i;
7933 unsigned hash;
7934 struct gcpro gcpro1;
7935 EMACS_TIME now;
7937 /* F must be a window-system frame, and SPEC must be a valid image
7938 specification. */
7939 xassert (FRAME_WINDOW_P (f));
7940 xassert (valid_image_p (spec));
7942 GCPRO1 (spec);
7944 /* Look up SPEC in the hash table of the image cache. */
7945 hash = sxhash (spec, 0);
7946 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
7948 for (img = c->buckets[i]; img; img = img->next)
7949 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
7950 break;
7952 /* If not found, create a new image and cache it. */
7953 if (img == NULL)
7955 img = make_image (spec, hash);
7956 cache_image (f, img);
7957 img->load_failed_p = img->type->load (f, img) == 0;
7958 xassert (!interrupt_input_blocked);
7960 /* If we can't load the image, and we don't have a width and
7961 height, use some arbitrary width and height so that we can
7962 draw a rectangle for it. */
7963 if (img->load_failed_p)
7965 Lisp_Object value;
7967 value = image_spec_value (spec, QCwidth, NULL);
7968 img->width = (INTEGERP (value)
7969 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
7970 value = image_spec_value (spec, QCheight, NULL);
7971 img->height = (INTEGERP (value)
7972 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
7974 else
7976 /* Handle image type independent image attributes
7977 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
7978 Lisp_Object ascent, margin, relief, algorithm, heuristic_mask;
7979 Lisp_Object file;
7981 ascent = image_spec_value (spec, QCascent, NULL);
7982 if (INTEGERP (ascent))
7983 img->ascent = XFASTINT (ascent);
7984 else if (EQ (ascent, Qcenter))
7985 img->ascent = CENTERED_IMAGE_ASCENT;
7987 margin = image_spec_value (spec, QCmargin, NULL);
7988 if (INTEGERP (margin) && XINT (margin) >= 0)
7989 img->margin = XFASTINT (margin);
7991 relief = image_spec_value (spec, QCrelief, NULL);
7992 if (INTEGERP (relief))
7994 img->relief = XINT (relief);
7995 img->margin += abs (img->relief);
7998 /* Should we apply a Laplace edge-detection algorithm? */
7999 algorithm = image_spec_value (spec, QCalgorithm, NULL);
8000 if (img->pixmap && EQ (algorithm, Qlaplace))
8001 x_laplace (f, img);
8003 /* Should we built a mask heuristically? */
8004 heuristic_mask = image_spec_value (spec, QCheuristic_mask, NULL);
8005 if (img->pixmap && !img->mask && !NILP (heuristic_mask))
8006 x_build_heuristic_mask (f, img, heuristic_mask);
8010 /* We're using IMG, so set its timestamp to `now'. */
8011 EMACS_GET_TIME (now);
8012 img->timestamp = EMACS_SECS (now);
8014 UNGCPRO;
8016 /* Value is the image id. */
8017 return img->id;
8021 /* Cache image IMG in the image cache of frame F. */
8023 static void
8024 cache_image (f, img)
8025 struct frame *f;
8026 struct image *img;
8028 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8029 int i;
8031 /* Find a free slot in c->images. */
8032 for (i = 0; i < c->used; ++i)
8033 if (c->images[i] == NULL)
8034 break;
8036 /* If no free slot found, maybe enlarge c->images. */
8037 if (i == c->used && c->used == c->size)
8039 c->size *= 2;
8040 c->images = (struct image **) xrealloc (c->images,
8041 c->size * sizeof *c->images);
8044 /* Add IMG to c->images, and assign IMG an id. */
8045 c->images[i] = img;
8046 img->id = i;
8047 if (i == c->used)
8048 ++c->used;
8050 /* Add IMG to the cache's hash table. */
8051 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8052 img->next = c->buckets[i];
8053 if (img->next)
8054 img->next->prev = img;
8055 img->prev = NULL;
8056 c->buckets[i] = img;
8060 /* Call FN on every image in the image cache of frame F. Used to mark
8061 Lisp Objects in the image cache. */
8063 void
8064 forall_images_in_image_cache (f, fn)
8065 struct frame *f;
8066 void (*fn) P_ ((struct image *img));
8068 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8070 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8071 if (c)
8073 int i;
8074 for (i = 0; i < c->used; ++i)
8075 if (c->images[i])
8076 fn (c->images[i]);
8083 /***********************************************************************
8084 W32 support code
8085 ***********************************************************************/
8087 #if 0 /* NTEMACS_TODO: W32 specific image code. */
8089 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8090 XImage **, Pixmap *));
8091 static void x_destroy_x_image P_ ((XImage *));
8092 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8095 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8096 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8097 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8098 via xmalloc. Print error messages via image_error if an error
8099 occurs. Value is non-zero if successful. */
8101 static int
8102 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8103 struct frame *f;
8104 int width, height, depth;
8105 XImage **ximg;
8106 Pixmap *pixmap;
8108 #if 0 /* NTEMACS_TODO: Image support for W32 */
8109 Display *display = FRAME_W32_DISPLAY (f);
8110 Screen *screen = FRAME_X_SCREEN (f);
8111 Window window = FRAME_W32_WINDOW (f);
8113 xassert (interrupt_input_blocked);
8115 if (depth <= 0)
8116 depth = DefaultDepthOfScreen (screen);
8117 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8118 depth, ZPixmap, 0, NULL, width, height,
8119 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8120 if (*ximg == NULL)
8122 image_error ("Unable to allocate X image", Qnil, Qnil);
8123 return 0;
8126 /* Allocate image raster. */
8127 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8129 /* Allocate a pixmap of the same size. */
8130 *pixmap = XCreatePixmap (display, window, width, height, depth);
8131 if (*pixmap == 0)
8133 x_destroy_x_image (*ximg);
8134 *ximg = NULL;
8135 image_error ("Unable to create X pixmap", Qnil, Qnil);
8136 return 0;
8138 #endif
8139 return 1;
8143 /* Destroy XImage XIMG. Free XIMG->data. */
8145 static void
8146 x_destroy_x_image (ximg)
8147 XImage *ximg;
8149 xassert (interrupt_input_blocked);
8150 if (ximg)
8152 xfree (ximg->data);
8153 ximg->data = NULL;
8154 XDestroyImage (ximg);
8159 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8160 are width and height of both the image and pixmap. */
8162 static void
8163 x_put_x_image (f, ximg, pixmap, width, height)
8164 struct frame *f;
8165 XImage *ximg;
8166 Pixmap pixmap;
8168 GC gc;
8170 xassert (interrupt_input_blocked);
8171 gc = XCreateGC (NULL, pixmap, 0, NULL);
8172 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8173 XFreeGC (NULL, gc);
8176 #endif
8179 /***********************************************************************
8180 Searching files
8181 ***********************************************************************/
8183 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8185 /* Find image file FILE. Look in data-directory, then
8186 x-bitmap-file-path. Value is the full name of the file found, or
8187 nil if not found. */
8189 static Lisp_Object
8190 x_find_image_file (file)
8191 Lisp_Object file;
8193 Lisp_Object file_found, search_path;
8194 struct gcpro gcpro1, gcpro2;
8195 int fd;
8197 file_found = Qnil;
8198 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8199 GCPRO2 (file_found, search_path);
8201 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8202 fd = openp (search_path, file, "", &file_found, 0);
8204 if (fd < 0)
8205 file_found = Qnil;
8206 else
8207 close (fd);
8209 UNGCPRO;
8210 return file_found;
8215 /***********************************************************************
8216 XBM images
8217 ***********************************************************************/
8219 static int xbm_load P_ ((struct frame *f, struct image *img));
8220 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8221 Lisp_Object file));
8222 static int xbm_image_p P_ ((Lisp_Object object));
8223 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8224 unsigned char **));
8227 /* Indices of image specification fields in xbm_format, below. */
8229 enum xbm_keyword_index
8231 XBM_TYPE,
8232 XBM_FILE,
8233 XBM_WIDTH,
8234 XBM_HEIGHT,
8235 XBM_DATA,
8236 XBM_FOREGROUND,
8237 XBM_BACKGROUND,
8238 XBM_ASCENT,
8239 XBM_MARGIN,
8240 XBM_RELIEF,
8241 XBM_ALGORITHM,
8242 XBM_HEURISTIC_MASK,
8243 XBM_LAST
8246 /* Vector of image_keyword structures describing the format
8247 of valid XBM image specifications. */
8249 static struct image_keyword xbm_format[XBM_LAST] =
8251 {":type", IMAGE_SYMBOL_VALUE, 1},
8252 {":file", IMAGE_STRING_VALUE, 0},
8253 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8254 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8255 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8256 {":foreground", IMAGE_STRING_VALUE, 0},
8257 {":background", IMAGE_STRING_VALUE, 0},
8258 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8259 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8260 {":relief", IMAGE_INTEGER_VALUE, 0},
8261 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8262 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8265 /* Structure describing the image type XBM. */
8267 static struct image_type xbm_type =
8269 &Qxbm,
8270 xbm_image_p,
8271 xbm_load,
8272 x_clear_image,
8273 NULL
8276 /* Tokens returned from xbm_scan. */
8278 enum xbm_token
8280 XBM_TK_IDENT = 256,
8281 XBM_TK_NUMBER
8285 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8286 A valid specification is a list starting with the symbol `image'
8287 The rest of the list is a property list which must contain an
8288 entry `:type xbm..
8290 If the specification specifies a file to load, it must contain
8291 an entry `:file FILENAME' where FILENAME is a string.
8293 If the specification is for a bitmap loaded from memory it must
8294 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8295 WIDTH and HEIGHT are integers > 0. DATA may be:
8297 1. a string large enough to hold the bitmap data, i.e. it must
8298 have a size >= (WIDTH + 7) / 8 * HEIGHT
8300 2. a bool-vector of size >= WIDTH * HEIGHT
8302 3. a vector of strings or bool-vectors, one for each line of the
8303 bitmap.
8305 Both the file and data forms may contain the additional entries
8306 `:background COLOR' and `:foreground COLOR'. If not present,
8307 foreground and background of the frame on which the image is
8308 displayed, is used. */
8310 static int
8311 xbm_image_p (object)
8312 Lisp_Object object;
8314 struct image_keyword kw[XBM_LAST];
8316 bcopy (xbm_format, kw, sizeof kw);
8317 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8318 return 0;
8320 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8322 if (kw[XBM_FILE].count)
8324 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8325 return 0;
8327 else
8329 Lisp_Object data;
8330 int width, height;
8332 /* Entries for `:width', `:height' and `:data' must be present. */
8333 if (!kw[XBM_WIDTH].count
8334 || !kw[XBM_HEIGHT].count
8335 || !kw[XBM_DATA].count)
8336 return 0;
8338 data = kw[XBM_DATA].value;
8339 width = XFASTINT (kw[XBM_WIDTH].value);
8340 height = XFASTINT (kw[XBM_HEIGHT].value);
8342 /* Check type of data, and width and height against contents of
8343 data. */
8344 if (VECTORP (data))
8346 int i;
8348 /* Number of elements of the vector must be >= height. */
8349 if (XVECTOR (data)->size < height)
8350 return 0;
8352 /* Each string or bool-vector in data must be large enough
8353 for one line of the image. */
8354 for (i = 0; i < height; ++i)
8356 Lisp_Object elt = XVECTOR (data)->contents[i];
8358 if (STRINGP (elt))
8360 if (XSTRING (elt)->size
8361 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8362 return 0;
8364 else if (BOOL_VECTOR_P (elt))
8366 if (XBOOL_VECTOR (elt)->size < width)
8367 return 0;
8369 else
8370 return 0;
8373 else if (STRINGP (data))
8375 if (XSTRING (data)->size
8376 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8377 return 0;
8379 else if (BOOL_VECTOR_P (data))
8381 if (XBOOL_VECTOR (data)->size < width * height)
8382 return 0;
8384 else
8385 return 0;
8388 /* Baseline must be a value between 0 and 100 (a percentage). */
8389 if (kw[XBM_ASCENT].count
8390 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8391 return 0;
8393 return 1;
8397 /* Scan a bitmap file. FP is the stream to read from. Value is
8398 either an enumerator from enum xbm_token, or a character for a
8399 single-character token, or 0 at end of file. If scanning an
8400 identifier, store the lexeme of the identifier in SVAL. If
8401 scanning a number, store its value in *IVAL. */
8403 static int
8404 xbm_scan (fp, sval, ival)
8405 FILE *fp;
8406 char *sval;
8407 int *ival;
8409 int c;
8411 /* Skip white space. */
8412 while ((c = fgetc (fp)) != EOF && isspace (c))
8415 if (c == EOF)
8416 c = 0;
8417 else if (isdigit (c))
8419 int value = 0, digit;
8421 if (c == '0')
8423 c = fgetc (fp);
8424 if (c == 'x' || c == 'X')
8426 while ((c = fgetc (fp)) != EOF)
8428 if (isdigit (c))
8429 digit = c - '0';
8430 else if (c >= 'a' && c <= 'f')
8431 digit = c - 'a' + 10;
8432 else if (c >= 'A' && c <= 'F')
8433 digit = c - 'A' + 10;
8434 else
8435 break;
8436 value = 16 * value + digit;
8439 else if (isdigit (c))
8441 value = c - '0';
8442 while ((c = fgetc (fp)) != EOF
8443 && isdigit (c))
8444 value = 8 * value + c - '0';
8447 else
8449 value = c - '0';
8450 while ((c = fgetc (fp)) != EOF
8451 && isdigit (c))
8452 value = 10 * value + c - '0';
8455 if (c != EOF)
8456 ungetc (c, fp);
8457 *ival = value;
8458 c = XBM_TK_NUMBER;
8460 else if (isalpha (c) || c == '_')
8462 *sval++ = c;
8463 while ((c = fgetc (fp)) != EOF
8464 && (isalnum (c) || c == '_'))
8465 *sval++ = c;
8466 *sval = 0;
8467 if (c != EOF)
8468 ungetc (c, fp);
8469 c = XBM_TK_IDENT;
8472 return c;
8476 /* Replacement for XReadBitmapFileData which isn't available under old
8477 X versions. FILE is the name of the bitmap file to read. Set
8478 *WIDTH and *HEIGHT to the width and height of the image. Return in
8479 *DATA the bitmap data allocated with xmalloc. Value is non-zero if
8480 successful. */
8482 static int
8483 xbm_read_bitmap_file_data (file, width, height, data)
8484 char *file;
8485 int *width, *height;
8486 unsigned char **data;
8488 FILE *fp;
8489 char buffer[BUFSIZ];
8490 int padding_p = 0;
8491 int v10 = 0;
8492 int bytes_per_line, i, nbytes;
8493 unsigned char *p;
8494 int value;
8495 int LA1;
8497 #define match() \
8498 LA1 = xbm_scan (fp, buffer, &value)
8500 #define expect(TOKEN) \
8501 if (LA1 != (TOKEN)) \
8502 goto failure; \
8503 else \
8504 match ()
8506 #define expect_ident(IDENT) \
8507 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
8508 match (); \
8509 else \
8510 goto failure
8512 fp = fopen (file, "r");
8513 if (fp == NULL)
8514 return 0;
8516 *width = *height = -1;
8517 *data = NULL;
8518 LA1 = xbm_scan (fp, buffer, &value);
8520 /* Parse defines for width, height and hot-spots. */
8521 while (LA1 == '#')
8523 match ();
8524 expect_ident ("define");
8525 expect (XBM_TK_IDENT);
8527 if (LA1 == XBM_TK_NUMBER);
8529 char *p = strrchr (buffer, '_');
8530 p = p ? p + 1 : buffer;
8531 if (strcmp (p, "width") == 0)
8532 *width = value;
8533 else if (strcmp (p, "height") == 0)
8534 *height = value;
8536 expect (XBM_TK_NUMBER);
8539 if (*width < 0 || *height < 0)
8540 goto failure;
8542 /* Parse bits. Must start with `static'. */
8543 expect_ident ("static");
8544 if (LA1 == XBM_TK_IDENT)
8546 if (strcmp (buffer, "unsigned") == 0)
8548 match ();
8549 expect_ident ("char");
8551 else if (strcmp (buffer, "short") == 0)
8553 match ();
8554 v10 = 1;
8555 if (*width % 16 && *width % 16 < 9)
8556 padding_p = 1;
8558 else if (strcmp (buffer, "char") == 0)
8559 match ();
8560 else
8561 goto failure;
8563 else
8564 goto failure;
8566 expect (XBM_TK_IDENT);
8567 expect ('[');
8568 expect (']');
8569 expect ('=');
8570 expect ('{');
8572 bytes_per_line = (*width + 7) / 8 + padding_p;
8573 nbytes = bytes_per_line * *height;
8574 p = *data = (char *) xmalloc (nbytes);
8576 if (v10)
8579 for (i = 0; i < nbytes; i += 2)
8581 int val = value;
8582 expect (XBM_TK_NUMBER);
8584 *p++ = val;
8585 if (!padding_p || ((i + 2) % bytes_per_line))
8586 *p++ = value >> 8;
8588 if (LA1 == ',' || LA1 == '}')
8589 match ();
8590 else
8591 goto failure;
8594 else
8596 for (i = 0; i < nbytes; ++i)
8598 int val = value;
8599 expect (XBM_TK_NUMBER);
8601 *p++ = val;
8603 if (LA1 == ',' || LA1 == '}')
8604 match ();
8605 else
8606 goto failure;
8610 fclose (fp);
8611 return 1;
8613 failure:
8615 fclose (fp);
8616 if (*data)
8618 xfree (*data);
8619 *data = NULL;
8621 return 0;
8623 #undef match
8624 #undef expect
8625 #undef expect_ident
8629 /* Load XBM image IMG which will be displayed on frame F from file
8630 SPECIFIED_FILE. Value is non-zero if successful. */
8632 static int
8633 xbm_load_image_from_file (f, img, specified_file)
8634 struct frame *f;
8635 struct image *img;
8636 Lisp_Object specified_file;
8638 int rc;
8639 unsigned char *data;
8640 int success_p = 0;
8641 Lisp_Object file;
8642 struct gcpro gcpro1;
8644 xassert (STRINGP (specified_file));
8645 file = Qnil;
8646 GCPRO1 (file);
8648 file = x_find_image_file (specified_file);
8649 if (!STRINGP (file))
8651 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8652 UNGCPRO;
8653 return 0;
8656 rc = xbm_read_bitmap_file_data (XSTRING (file)->data, &img->width,
8657 &img->height, &data);
8658 if (rc)
8660 int depth = one_w32_display_info.n_cbits;
8661 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8662 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8663 Lisp_Object value;
8665 xassert (img->width > 0 && img->height > 0);
8667 /* Get foreground and background colors, maybe allocate colors. */
8668 value = image_spec_value (img->spec, QCforeground, NULL);
8669 if (!NILP (value))
8670 foreground = x_alloc_image_color (f, img, value, foreground);
8672 value = image_spec_value (img->spec, QCbackground, NULL);
8673 if (!NILP (value))
8674 background = x_alloc_image_color (f, img, value, background);
8676 #if 0 /* NTEMACS_TODO : Port image display to W32 */
8677 BLOCK_INPUT;
8678 img->pixmap
8679 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8680 FRAME_W32_WINDOW (f),
8681 data,
8682 img->width, img->height,
8683 foreground, background,
8684 depth);
8685 xfree (data);
8687 if (img->pixmap == 0)
8689 x_clear_image (f, img);
8690 image_error ("Unable to create X pixmap for `%s'", file, Qnil);
8692 else
8693 success_p = 1;
8695 UNBLOCK_INPUT;
8696 #endif
8698 else
8699 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
8701 UNGCPRO;
8702 return success_p;
8706 /* Fill image IMG which is used on frame F with pixmap data. Value is
8707 non-zero if successful. */
8709 static int
8710 xbm_load (f, img)
8711 struct frame *f;
8712 struct image *img;
8714 int success_p = 0;
8715 Lisp_Object file_name;
8717 xassert (xbm_image_p (img->spec));
8719 /* If IMG->spec specifies a file name, create a non-file spec from it. */
8720 file_name = image_spec_value (img->spec, QCfile, NULL);
8721 if (STRINGP (file_name))
8722 success_p = xbm_load_image_from_file (f, img, file_name);
8723 else
8725 struct image_keyword fmt[XBM_LAST];
8726 Lisp_Object data;
8727 int depth;
8728 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
8729 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
8730 char *bits;
8731 int parsed_p;
8733 /* Parse the list specification. */
8734 bcopy (xbm_format, fmt, sizeof fmt);
8735 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
8736 xassert (parsed_p);
8738 /* Get specified width, and height. */
8739 img->width = XFASTINT (fmt[XBM_WIDTH].value);
8740 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
8741 xassert (img->width > 0 && img->height > 0);
8743 BLOCK_INPUT;
8745 if (fmt[XBM_ASCENT].count)
8746 img->ascent = XFASTINT (fmt[XBM_ASCENT].value);
8748 /* Get foreground and background colors, maybe allocate colors. */
8749 if (fmt[XBM_FOREGROUND].count)
8750 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
8751 foreground);
8752 if (fmt[XBM_BACKGROUND].count)
8753 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
8754 background);
8756 /* Set bits to the bitmap image data. */
8757 data = fmt[XBM_DATA].value;
8758 if (VECTORP (data))
8760 int i;
8761 char *p;
8762 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
8764 p = bits = (char *) alloca (nbytes * img->height);
8765 for (i = 0; i < img->height; ++i, p += nbytes)
8767 Lisp_Object line = XVECTOR (data)->contents[i];
8768 if (STRINGP (line))
8769 bcopy (XSTRING (line)->data, p, nbytes);
8770 else
8771 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
8774 else if (STRINGP (data))
8775 bits = XSTRING (data)->data;
8776 else
8777 bits = XBOOL_VECTOR (data)->data;
8779 #if 0 /* NTEMACS_TODO : W32 XPM code */
8780 /* Create the pixmap. */
8781 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
8782 img->pixmap
8783 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
8784 FRAME_W32_WINDOW (f),
8785 bits,
8786 img->width, img->height,
8787 foreground, background,
8788 depth);
8789 #endif /* NTEMACS_TODO */
8791 if (img->pixmap)
8792 success_p = 1;
8793 else
8795 image_error ("Unable to create pixmap for XBM image `%s'",
8796 img->spec, Qnil);
8797 x_clear_image (f, img);
8800 UNBLOCK_INPUT;
8803 return success_p;
8808 /***********************************************************************
8809 XPM images
8810 ***********************************************************************/
8812 #if HAVE_XPM
8814 static int xpm_image_p P_ ((Lisp_Object object));
8815 static int xpm_load P_ ((struct frame *f, struct image *img));
8816 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
8818 #include "X11/xpm.h"
8820 /* The symbol `xpm' identifying XPM-format images. */
8822 Lisp_Object Qxpm;
8824 /* Indices of image specification fields in xpm_format, below. */
8826 enum xpm_keyword_index
8828 XPM_TYPE,
8829 XPM_FILE,
8830 XPM_DATA,
8831 XPM_ASCENT,
8832 XPM_MARGIN,
8833 XPM_RELIEF,
8834 XPM_ALGORITHM,
8835 XPM_HEURISTIC_MASK,
8836 XPM_COLOR_SYMBOLS,
8837 XPM_LAST
8840 /* Vector of image_keyword structures describing the format
8841 of valid XPM image specifications. */
8843 static struct image_keyword xpm_format[XPM_LAST] =
8845 {":type", IMAGE_SYMBOL_VALUE, 1},
8846 {":file", IMAGE_STRING_VALUE, 0},
8847 {":data", IMAGE_STRING_VALUE, 0},
8848 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8849 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8850 {":relief", IMAGE_INTEGER_VALUE, 0},
8851 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8852 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8853 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8856 /* Structure describing the image type XBM. */
8858 static struct image_type xpm_type =
8860 &Qxpm,
8861 xpm_image_p,
8862 xpm_load,
8863 x_clear_image,
8864 NULL
8868 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
8869 for XPM images. Such a list must consist of conses whose car and
8870 cdr are strings. */
8872 static int
8873 xpm_valid_color_symbols_p (color_symbols)
8874 Lisp_Object color_symbols;
8876 while (CONSP (color_symbols))
8878 Lisp_Object sym = XCAR (color_symbols);
8879 if (!CONSP (sym)
8880 || !STRINGP (XCAR (sym))
8881 || !STRINGP (XCDR (sym)))
8882 break;
8883 color_symbols = XCDR (color_symbols);
8886 return NILP (color_symbols);
8890 /* Value is non-zero if OBJECT is a valid XPM image specification. */
8892 static int
8893 xpm_image_p (object)
8894 Lisp_Object object;
8896 struct image_keyword fmt[XPM_LAST];
8897 bcopy (xpm_format, fmt, sizeof fmt);
8898 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
8899 /* Either `:file' or `:data' must be present. */
8900 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
8901 /* Either no `:color-symbols' or it's a list of conses
8902 whose car and cdr are strings. */
8903 && (fmt[XPM_COLOR_SYMBOLS].count == 0
8904 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
8905 && (fmt[XPM_ASCENT].count == 0
8906 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
8910 /* Load image IMG which will be displayed on frame F. Value is
8911 non-zero if successful. */
8913 static int
8914 xpm_load (f, img)
8915 struct frame *f;
8916 struct image *img;
8918 int rc, i;
8919 XpmAttributes attrs;
8920 Lisp_Object specified_file, color_symbols;
8922 /* Configure the XPM lib. Use the visual of frame F. Allocate
8923 close colors. Return colors allocated. */
8924 bzero (&attrs, sizeof attrs);
8925 attrs.visual = FRAME_X_VISUAL (f);
8926 attrs.colormap = FRAME_X_COLORMAP (f);
8927 attrs.valuemask |= XpmVisual;
8928 attrs.valuemask |= XpmColormap;
8929 attrs.valuemask |= XpmReturnAllocPixels;
8930 #ifdef XpmAllocCloseColors
8931 attrs.alloc_close_colors = 1;
8932 attrs.valuemask |= XpmAllocCloseColors;
8933 #else
8934 attrs.closeness = 600;
8935 attrs.valuemask |= XpmCloseness;
8936 #endif
8938 /* If image specification contains symbolic color definitions, add
8939 these to `attrs'. */
8940 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
8941 if (CONSP (color_symbols))
8943 Lisp_Object tail;
8944 XpmColorSymbol *xpm_syms;
8945 int i, size;
8947 attrs.valuemask |= XpmColorSymbols;
8949 /* Count number of symbols. */
8950 attrs.numsymbols = 0;
8951 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
8952 ++attrs.numsymbols;
8954 /* Allocate an XpmColorSymbol array. */
8955 size = attrs.numsymbols * sizeof *xpm_syms;
8956 xpm_syms = (XpmColorSymbol *) alloca (size);
8957 bzero (xpm_syms, size);
8958 attrs.colorsymbols = xpm_syms;
8960 /* Fill the color symbol array. */
8961 for (tail = color_symbols, i = 0;
8962 CONSP (tail);
8963 ++i, tail = XCDR (tail))
8965 Lisp_Object name = XCAR (XCAR (tail));
8966 Lisp_Object color = XCDR (XCAR (tail));
8967 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
8968 strcpy (xpm_syms[i].name, XSTRING (name)->data);
8969 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
8970 strcpy (xpm_syms[i].value, XSTRING (color)->data);
8974 /* Create a pixmap for the image, either from a file, or from a
8975 string buffer containing data in the same format as an XPM file. */
8976 BLOCK_INPUT;
8977 specified_file = image_spec_value (img->spec, QCfile, NULL);
8978 if (STRINGP (specified_file))
8980 Lisp_Object file = x_find_image_file (specified_file);
8981 if (!STRINGP (file))
8983 image_error ("Cannot find image file `%s'", specified_file, Qnil);
8984 UNBLOCK_INPUT;
8985 return 0;
8988 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
8989 XSTRING (file)->data, &img->pixmap, &img->mask,
8990 &attrs);
8992 else
8994 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
8995 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
8996 XSTRING (buffer)->data,
8997 &img->pixmap, &img->mask,
8998 &attrs);
9000 UNBLOCK_INPUT;
9002 if (rc == XpmSuccess)
9004 /* Remember allocated colors. */
9005 img->ncolors = attrs.nalloc_pixels;
9006 img->colors = (unsigned long *) xmalloc (img->ncolors
9007 * sizeof *img->colors);
9008 for (i = 0; i < attrs.nalloc_pixels; ++i)
9009 img->colors[i] = attrs.alloc_pixels[i];
9011 img->width = attrs.width;
9012 img->height = attrs.height;
9013 xassert (img->width > 0 && img->height > 0);
9015 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9016 BLOCK_INPUT;
9017 XpmFreeAttributes (&attrs);
9018 UNBLOCK_INPUT;
9020 else
9022 switch (rc)
9024 case XpmOpenFailed:
9025 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9026 break;
9028 case XpmFileInvalid:
9029 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9030 break;
9032 case XpmNoMemory:
9033 image_error ("Out of memory (%s)", img->spec, Qnil);
9034 break;
9036 case XpmColorFailed:
9037 image_error ("Color allocation error (%s)", img->spec, Qnil);
9038 break;
9040 default:
9041 image_error ("Unknown error (%s)", img->spec, Qnil);
9042 break;
9046 return rc == XpmSuccess;
9049 #endif /* HAVE_XPM != 0 */
9052 #if 0 /* NTEMACS_TODO : Color tables on W32. */
9053 /***********************************************************************
9054 Color table
9055 ***********************************************************************/
9057 /* An entry in the color table mapping an RGB color to a pixel color. */
9059 struct ct_color
9061 int r, g, b;
9062 unsigned long pixel;
9064 /* Next in color table collision list. */
9065 struct ct_color *next;
9068 /* The bucket vector size to use. Must be prime. */
9070 #define CT_SIZE 101
9072 /* Value is a hash of the RGB color given by R, G, and B. */
9074 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9076 /* The color hash table. */
9078 struct ct_color **ct_table;
9080 /* Number of entries in the color table. */
9082 int ct_colors_allocated;
9084 /* Function prototypes. */
9086 static void init_color_table P_ ((void));
9087 static void free_color_table P_ ((void));
9088 static unsigned long *colors_in_color_table P_ ((int *n));
9089 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9090 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9093 /* Initialize the color table. */
9095 static void
9096 init_color_table ()
9098 int size = CT_SIZE * sizeof (*ct_table);
9099 ct_table = (struct ct_color **) xmalloc (size);
9100 bzero (ct_table, size);
9101 ct_colors_allocated = 0;
9105 /* Free memory associated with the color table. */
9107 static void
9108 free_color_table ()
9110 int i;
9111 struct ct_color *p, *next;
9113 for (i = 0; i < CT_SIZE; ++i)
9114 for (p = ct_table[i]; p; p = next)
9116 next = p->next;
9117 xfree (p);
9120 xfree (ct_table);
9121 ct_table = NULL;
9125 /* Value is a pixel color for RGB color R, G, B on frame F. If an
9126 entry for that color already is in the color table, return the
9127 pixel color of that entry. Otherwise, allocate a new color for R,
9128 G, B, and make an entry in the color table. */
9130 static unsigned long
9131 lookup_rgb_color (f, r, g, b)
9132 struct frame *f;
9133 int r, g, b;
9135 unsigned hash = CT_HASH_RGB (r, g, b);
9136 int i = hash % CT_SIZE;
9137 struct ct_color *p;
9139 for (p = ct_table[i]; p; p = p->next)
9140 if (p->r == r && p->g == g && p->b == b)
9141 break;
9143 if (p == NULL)
9145 COLORREF color;
9146 Colormap cmap;
9147 int rc;
9149 color = PALETTERGB (r, g, b);
9151 ++ct_colors_allocated;
9153 p = (struct ct_color *) xmalloc (sizeof *p);
9154 p->r = r;
9155 p->g = g;
9156 p->b = b;
9157 p->pixel = color;
9158 p->next = ct_table[i];
9159 ct_table[i] = p;
9162 return p->pixel;
9166 /* Look up pixel color PIXEL which is used on frame F in the color
9167 table. If not already present, allocate it. Value is PIXEL. */
9169 static unsigned long
9170 lookup_pixel_color (f, pixel)
9171 struct frame *f;
9172 unsigned long pixel;
9174 int i = pixel % CT_SIZE;
9175 struct ct_color *p;
9177 for (p = ct_table[i]; p; p = p->next)
9178 if (p->pixel == pixel)
9179 break;
9181 if (p == NULL)
9183 XColor color;
9184 Colormap cmap;
9185 int rc;
9187 BLOCK_INPUT;
9189 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9190 color.pixel = pixel;
9191 XQueryColor (NULL, cmap, &color);
9192 rc = x_alloc_nearest_color (f, cmap, &color);
9193 UNBLOCK_INPUT;
9195 if (rc)
9197 ++ct_colors_allocated;
9199 p = (struct ct_color *) xmalloc (sizeof *p);
9200 p->r = color.red;
9201 p->g = color.green;
9202 p->b = color.blue;
9203 p->pixel = pixel;
9204 p->next = ct_table[i];
9205 ct_table[i] = p;
9207 else
9208 return FRAME_FOREGROUND_PIXEL (f);
9210 return p->pixel;
9214 /* Value is a vector of all pixel colors contained in the color table,
9215 allocated via xmalloc. Set *N to the number of colors. */
9217 static unsigned long *
9218 colors_in_color_table (n)
9219 int *n;
9221 int i, j;
9222 struct ct_color *p;
9223 unsigned long *colors;
9225 if (ct_colors_allocated == 0)
9227 *n = 0;
9228 colors = NULL;
9230 else
9232 colors = (unsigned long *) xmalloc (ct_colors_allocated
9233 * sizeof *colors);
9234 *n = ct_colors_allocated;
9236 for (i = j = 0; i < CT_SIZE; ++i)
9237 for (p = ct_table[i]; p; p = p->next)
9238 colors[j++] = p->pixel;
9241 return colors;
9244 #endif /* NTEMACS_TODO */
9247 /***********************************************************************
9248 Algorithms
9249 ***********************************************************************/
9251 #if 0 /* NTEMACS_TODO : W32 versions of low level algorithms */
9252 static void x_laplace_write_row P_ ((struct frame *, long *,
9253 int, XImage *, int));
9254 static void x_laplace_read_row P_ ((struct frame *, Colormap,
9255 XColor *, int, XImage *, int));
9258 /* Fill COLORS with RGB colors from row Y of image XIMG. F is the
9259 frame we operate on, CMAP is the color-map in effect, and WIDTH is
9260 the width of one row in the image. */
9262 static void
9263 x_laplace_read_row (f, cmap, colors, width, ximg, y)
9264 struct frame *f;
9265 Colormap cmap;
9266 XColor *colors;
9267 int width;
9268 XImage *ximg;
9269 int y;
9271 int x;
9273 for (x = 0; x < width; ++x)
9274 colors[x].pixel = XGetPixel (ximg, x, y);
9276 XQueryColors (NULL, cmap, colors, width);
9280 /* Write row Y of image XIMG. PIXELS is an array of WIDTH longs
9281 containing the pixel colors to write. F is the frame we are
9282 working on. */
9284 static void
9285 x_laplace_write_row (f, pixels, width, ximg, y)
9286 struct frame *f;
9287 long *pixels;
9288 int width;
9289 XImage *ximg;
9290 int y;
9292 int x;
9294 for (x = 0; x < width; ++x)
9295 XPutPixel (ximg, x, y, pixels[x]);
9297 #endif
9299 /* Transform image IMG which is used on frame F with a Laplace
9300 edge-detection algorithm. The result is an image that can be used
9301 to draw disabled buttons, for example. */
9303 static void
9304 x_laplace (f, img)
9305 struct frame *f;
9306 struct image *img;
9308 #if 0 /* NTEMACS_TODO : W32 version */
9309 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9310 XImage *ximg, *oimg;
9311 XColor *in[3];
9312 long *out;
9313 Pixmap pixmap;
9314 int x, y, i;
9315 long pixel;
9316 int in_y, out_y, rc;
9317 int mv2 = 45000;
9319 BLOCK_INPUT;
9321 /* Get the X image IMG->pixmap. */
9322 ximg = XGetImage (NULL, img->pixmap,
9323 0, 0, img->width, img->height, ~0, ZPixmap);
9325 /* Allocate 3 input rows, and one output row of colors. */
9326 for (i = 0; i < 3; ++i)
9327 in[i] = (XColor *) alloca (img->width * sizeof (XColor));
9328 out = (long *) alloca (img->width * sizeof (long));
9330 /* Create an X image for output. */
9331 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9332 &oimg, &pixmap);
9334 /* Fill first two rows. */
9335 x_laplace_read_row (f, cmap, in[0], img->width, ximg, 0);
9336 x_laplace_read_row (f, cmap, in[1], img->width, ximg, 1);
9337 in_y = 2;
9339 /* Write first row, all zeros. */
9340 init_color_table ();
9341 pixel = lookup_rgb_color (f, 0, 0, 0);
9342 for (x = 0; x < img->width; ++x)
9343 out[x] = pixel;
9344 x_laplace_write_row (f, out, img->width, oimg, 0);
9345 out_y = 1;
9347 for (y = 2; y < img->height; ++y)
9349 int rowa = y % 3;
9350 int rowb = (y + 2) % 3;
9352 x_laplace_read_row (f, cmap, in[rowa], img->width, ximg, in_y++);
9354 for (x = 0; x < img->width - 2; ++x)
9356 int r = in[rowa][x].red + mv2 - in[rowb][x + 2].red;
9357 int g = in[rowa][x].green + mv2 - in[rowb][x + 2].green;
9358 int b = in[rowa][x].blue + mv2 - in[rowb][x + 2].blue;
9360 out[x + 1] = lookup_rgb_color (f, r & 0xffff, g & 0xffff,
9361 b & 0xffff);
9364 x_laplace_write_row (f, out, img->width, oimg, out_y++);
9367 /* Write last line, all zeros. */
9368 for (x = 0; x < img->width; ++x)
9369 out[x] = pixel;
9370 x_laplace_write_row (f, out, img->width, oimg, out_y);
9372 /* Free the input image, and free resources of IMG. */
9373 XDestroyImage (ximg);
9374 x_clear_image (f, img);
9376 /* Put the output image into pixmap, and destroy it. */
9377 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9378 x_destroy_x_image (oimg);
9380 /* Remember new pixmap and colors in IMG. */
9381 img->pixmap = pixmap;
9382 img->colors = colors_in_color_table (&img->ncolors);
9383 free_color_table ();
9385 UNBLOCK_INPUT;
9386 #endif /* NTEMACS_TODO */
9390 /* Build a mask for image IMG which is used on frame F. FILE is the
9391 name of an image file, for error messages. HOW determines how to
9392 determine the background color of IMG. If it is a list '(R G B)',
9393 with R, G, and B being integers >= 0, take that as the color of the
9394 background. Otherwise, determine the background color of IMG
9395 heuristically. Value is non-zero if successful. */
9397 static int
9398 x_build_heuristic_mask (f, img, how)
9399 struct frame *f;
9400 struct image *img;
9401 Lisp_Object how;
9403 #if 0 /* NTEMACS_TODO : W32 version */
9404 Display *dpy = FRAME_W32_DISPLAY (f);
9405 XImage *ximg, *mask_img;
9406 int x, y, rc, look_at_corners_p;
9407 unsigned long bg;
9409 BLOCK_INPUT;
9411 /* Create an image and pixmap serving as mask. */
9412 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
9413 &mask_img, &img->mask);
9414 if (!rc)
9416 UNBLOCK_INPUT;
9417 return 0;
9420 /* Get the X image of IMG->pixmap. */
9421 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
9422 ~0, ZPixmap);
9424 /* Determine the background color of ximg. If HOW is `(R G B)'
9425 take that as color. Otherwise, try to determine the color
9426 heuristically. */
9427 look_at_corners_p = 1;
9429 if (CONSP (how))
9431 int rgb[3], i = 0;
9433 while (i < 3
9434 && CONSP (how)
9435 && NATNUMP (XCAR (how)))
9437 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
9438 how = XCDR (how);
9441 if (i == 3 && NILP (how))
9443 char color_name[30];
9444 XColor exact, color;
9445 Colormap cmap;
9447 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
9449 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9450 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
9452 bg = color.pixel;
9453 look_at_corners_p = 0;
9458 if (look_at_corners_p)
9460 unsigned long corners[4];
9461 int i, best_count;
9463 /* Get the colors at the corners of ximg. */
9464 corners[0] = XGetPixel (ximg, 0, 0);
9465 corners[1] = XGetPixel (ximg, img->width - 1, 0);
9466 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
9467 corners[3] = XGetPixel (ximg, 0, img->height - 1);
9469 /* Choose the most frequently found color as background. */
9470 for (i = best_count = 0; i < 4; ++i)
9472 int j, n;
9474 for (j = n = 0; j < 4; ++j)
9475 if (corners[i] == corners[j])
9476 ++n;
9478 if (n > best_count)
9479 bg = corners[i], best_count = n;
9483 /* Set all bits in mask_img to 1 whose color in ximg is different
9484 from the background color bg. */
9485 for (y = 0; y < img->height; ++y)
9486 for (x = 0; x < img->width; ++x)
9487 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
9489 /* Put mask_img into img->mask. */
9490 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
9491 x_destroy_x_image (mask_img);
9492 XDestroyImage (ximg);
9494 UNBLOCK_INPUT;
9495 #endif /* NTEMACS_TODO */
9497 return 1;
9502 /***********************************************************************
9503 PBM (mono, gray, color)
9504 ***********************************************************************/
9505 #ifdef HAVE_PBM
9507 static int pbm_image_p P_ ((Lisp_Object object));
9508 static int pbm_load P_ ((struct frame *f, struct image *img));
9509 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
9511 /* The symbol `pbm' identifying images of this type. */
9513 Lisp_Object Qpbm;
9515 /* Indices of image specification fields in gs_format, below. */
9517 enum pbm_keyword_index
9519 PBM_TYPE,
9520 PBM_FILE,
9521 PBM_DATA,
9522 PBM_ASCENT,
9523 PBM_MARGIN,
9524 PBM_RELIEF,
9525 PBM_ALGORITHM,
9526 PBM_HEURISTIC_MASK,
9527 PBM_LAST
9530 /* Vector of image_keyword structures describing the format
9531 of valid user-defined image specifications. */
9533 static struct image_keyword pbm_format[PBM_LAST] =
9535 {":type", IMAGE_SYMBOL_VALUE, 1},
9536 {":file", IMAGE_STRING_VALUE, 0},
9537 {":data", IMAGE_STRING_VALUE, 0},
9538 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9539 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9540 {":relief", IMAGE_INTEGER_VALUE, 0},
9541 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9542 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9545 /* Structure describing the image type `pbm'. */
9547 static struct image_type pbm_type =
9549 &Qpbm,
9550 pbm_image_p,
9551 pbm_load,
9552 x_clear_image,
9553 NULL
9557 /* Return non-zero if OBJECT is a valid PBM image specification. */
9559 static int
9560 pbm_image_p (object)
9561 Lisp_Object object;
9563 struct image_keyword fmt[PBM_LAST];
9565 bcopy (pbm_format, fmt, sizeof fmt);
9567 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
9568 || (fmt[PBM_ASCENT].count
9569 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
9570 return 0;
9572 /* Must specify either :data or :file. */
9573 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
9577 /* Scan a decimal number from *S and return it. Advance *S while
9578 reading the number. END is the end of the string. Value is -1 at
9579 end of input. */
9581 static int
9582 pbm_scan_number (s, end)
9583 unsigned char **s, *end;
9585 int c, val = -1;
9587 while (*s < end)
9589 /* Skip white-space. */
9590 while (*s < end && (c = *(*s)++, isspace (c)))
9593 if (c == '#')
9595 /* Skip comment to end of line. */
9596 while (*s < end && (c = *(*s)++, c != '\n'))
9599 else if (isdigit (c))
9601 /* Read decimal number. */
9602 val = c - '0';
9603 while (*s < end && (c = *(*s)++, isdigit (c)))
9604 val = 10 * val + c - '0';
9605 break;
9607 else
9608 break;
9611 return val;
9615 /* Read FILE into memory. Value is a pointer to a buffer allocated
9616 with xmalloc holding FILE's contents. Value is null if an error
9617 occured. *SIZE is set to the size of the file. */
9619 static char *
9620 pbm_read_file (file, size)
9621 Lisp_Object file;
9622 int *size;
9624 FILE *fp = NULL;
9625 char *buf = NULL;
9626 struct stat st;
9628 if (stat (XSTRING (file)->data, &st) == 0
9629 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
9630 && (buf = (char *) xmalloc (st.st_size),
9631 fread (buf, 1, st.st_size, fp) == st.st_size))
9633 *size = st.st_size;
9634 fclose (fp);
9636 else
9638 if (fp)
9639 fclose (fp);
9640 if (buf)
9642 xfree (buf);
9643 buf = NULL;
9647 return buf;
9651 /* Load PBM image IMG for use on frame F. */
9653 static int
9654 pbm_load (f, img)
9655 struct frame *f;
9656 struct image *img;
9658 int raw_p, x, y;
9659 int width, height, max_color_idx = 0;
9660 XImage *ximg;
9661 Lisp_Object file, specified_file;
9662 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
9663 struct gcpro gcpro1;
9664 unsigned char *contents = NULL;
9665 unsigned char *end, *p;
9666 int size;
9668 specified_file = image_spec_value (img->spec, QCfile, NULL);
9669 file = Qnil;
9670 GCPRO1 (file);
9672 if (STRINGP (specified_file))
9674 file = x_find_image_file (specified_file);
9675 if (!STRINGP (file))
9677 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9678 UNGCPRO;
9679 return 0;
9682 contents = pbm_read_file (file, &size);
9683 if (contents == NULL)
9685 image_error ("Error reading `%s'", file, Qnil);
9686 UNGCPRO;
9687 return 0;
9690 p = contents;
9691 end = contents + size;
9693 else
9695 Lisp_Object data;
9696 data = image_spec_value (img->spec, QCdata, NULL);
9697 p = XSTRING (data)->data;
9698 end = p + STRING_BYTES (XSTRING (data));
9701 /* Check magic number. */
9702 if (end - p < 2 || *p++ != 'P')
9704 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9705 error:
9706 xfree (contents);
9707 UNGCPRO;
9708 return 0;
9711 switch (*p++)
9713 case '1':
9714 raw_p = 0, type = PBM_MONO;
9715 break;
9717 case '2':
9718 raw_p = 0, type = PBM_GRAY;
9719 break;
9721 case '3':
9722 raw_p = 0, type = PBM_COLOR;
9723 break;
9725 case '4':
9726 raw_p = 1, type = PBM_MONO;
9727 break;
9729 case '5':
9730 raw_p = 1, type = PBM_GRAY;
9731 break;
9733 case '6':
9734 raw_p = 1, type = PBM_COLOR;
9735 break;
9737 default:
9738 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
9739 goto error;
9742 /* Read width, height, maximum color-component. Characters
9743 starting with `#' up to the end of a line are ignored. */
9744 width = pbm_scan_number (&p, end);
9745 height = pbm_scan_number (&p, end);
9747 if (type != PBM_MONO)
9749 max_color_idx = pbm_scan_number (&p, end);
9750 if (raw_p && max_color_idx > 255)
9751 max_color_idx = 255;
9754 if (width < 0
9755 || height < 0
9756 || (type != PBM_MONO && max_color_idx < 0))
9757 goto error;
9759 BLOCK_INPUT;
9760 if (!x_create_x_image_and_pixmap (f, width, height, 0,
9761 &ximg, &img->pixmap))
9763 UNBLOCK_INPUT;
9764 goto error;
9767 /* Initialize the color hash table. */
9768 init_color_table ();
9770 if (type == PBM_MONO)
9772 int c = 0, g;
9774 for (y = 0; y < height; ++y)
9775 for (x = 0; x < width; ++x)
9777 if (raw_p)
9779 if ((x & 7) == 0)
9780 c = *p++;
9781 g = c & 0x80;
9782 c <<= 1;
9784 else
9785 g = pbm_scan_number (&p, end);
9787 XPutPixel (ximg, x, y, (g
9788 ? FRAME_FOREGROUND_PIXEL (f)
9789 : FRAME_BACKGROUND_PIXEL (f)));
9792 else
9794 for (y = 0; y < height; ++y)
9795 for (x = 0; x < width; ++x)
9797 int r, g, b;
9799 if (type == PBM_GRAY)
9800 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
9801 else if (raw_p)
9803 r = *p++;
9804 g = *p++;
9805 b = *p++;
9807 else
9809 r = pbm_scan_number (&p, end);
9810 g = pbm_scan_number (&p, end);
9811 b = pbm_scan_number (&p, end);
9814 if (r < 0 || g < 0 || b < 0)
9816 xfree (ximg->data);
9817 ximg->data = NULL;
9818 XDestroyImage (ximg);
9819 UNBLOCK_INPUT;
9820 image_error ("Invalid pixel value in image `%s'",
9821 img->spec, Qnil);
9822 goto error;
9825 /* RGB values are now in the range 0..max_color_idx.
9826 Scale this to the range 0..0xffff supported by X. */
9827 r = (double) r * 65535 / max_color_idx;
9828 g = (double) g * 65535 / max_color_idx;
9829 b = (double) b * 65535 / max_color_idx;
9830 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
9834 /* Store in IMG->colors the colors allocated for the image, and
9835 free the color table. */
9836 img->colors = colors_in_color_table (&img->ncolors);
9837 free_color_table ();
9839 /* Put the image into a pixmap. */
9840 x_put_x_image (f, ximg, img->pixmap, width, height);
9841 x_destroy_x_image (ximg);
9842 UNBLOCK_INPUT;
9844 img->width = width;
9845 img->height = height;
9847 UNGCPRO;
9848 xfree (contents);
9849 return 1;
9851 #endif /* HAVE_PBM */
9854 /***********************************************************************
9856 ***********************************************************************/
9858 #if HAVE_PNG
9860 #include <png.h>
9862 /* Function prototypes. */
9864 static int png_image_p P_ ((Lisp_Object object));
9865 static int png_load P_ ((struct frame *f, struct image *img));
9867 /* The symbol `png' identifying images of this type. */
9869 Lisp_Object Qpng;
9871 /* Indices of image specification fields in png_format, below. */
9873 enum png_keyword_index
9875 PNG_TYPE,
9876 PNG_DATA,
9877 PNG_FILE,
9878 PNG_ASCENT,
9879 PNG_MARGIN,
9880 PNG_RELIEF,
9881 PNG_ALGORITHM,
9882 PNG_HEURISTIC_MASK,
9883 PNG_LAST
9886 /* Vector of image_keyword structures describing the format
9887 of valid user-defined image specifications. */
9889 static struct image_keyword png_format[PNG_LAST] =
9891 {":type", IMAGE_SYMBOL_VALUE, 1},
9892 {":data", IMAGE_STRING_VALUE, 0},
9893 {":file", IMAGE_STRING_VALUE, 0},
9894 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9895 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9896 {":relief", IMAGE_INTEGER_VALUE, 0},
9897 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9898 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9901 /* Structure describing the image type `png'. */
9903 static struct image_type png_type =
9905 &Qpng,
9906 png_image_p,
9907 png_load,
9908 x_clear_image,
9909 NULL
9913 /* Return non-zero if OBJECT is a valid PNG image specification. */
9915 static int
9916 png_image_p (object)
9917 Lisp_Object object;
9919 struct image_keyword fmt[PNG_LAST];
9920 bcopy (png_format, fmt, sizeof fmt);
9922 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
9923 || (fmt[PNG_ASCENT].count
9924 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
9925 return 0;
9927 /* Must specify either the :data or :file keyword. */
9928 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
9932 /* Error and warning handlers installed when the PNG library
9933 is initialized. */
9935 static void
9936 my_png_error (png_ptr, msg)
9937 png_struct *png_ptr;
9938 char *msg;
9940 xassert (png_ptr != NULL);
9941 image_error ("PNG error: %s", build_string (msg), Qnil);
9942 longjmp (png_ptr->jmpbuf, 1);
9946 static void
9947 my_png_warning (png_ptr, msg)
9948 png_struct *png_ptr;
9949 char *msg;
9951 xassert (png_ptr != NULL);
9952 image_error ("PNG warning: %s", build_string (msg), Qnil);
9955 /* Memory source for PNG decoding. */
9957 struct png_memory_storage
9959 unsigned char *bytes; /* The data */
9960 size_t len; /* How big is it? */
9961 int index; /* Where are we? */
9965 /* Function set as reader function when reading PNG image from memory.
9966 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
9967 bytes from the input to DATA. */
9969 static void
9970 png_read_from_memory (png_ptr, data, length)
9971 png_structp png_ptr;
9972 png_bytep data;
9973 png_size_t length;
9975 struct png_memory_storage *tbr
9976 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
9978 if (length > tbr->len - tbr->index)
9979 png_error (png_ptr, "Read error");
9981 bcopy (tbr->bytes + tbr->index, data, length);
9982 tbr->index = tbr->index + length;
9985 /* Load PNG image IMG for use on frame F. Value is non-zero if
9986 successful. */
9988 static int
9989 png_load (f, img)
9990 struct frame *f;
9991 struct image *img;
9993 Lisp_Object file, specified_file;
9994 Lisp_Object specified_data;
9995 int x, y, i;
9996 XImage *ximg, *mask_img = NULL;
9997 struct gcpro gcpro1;
9998 png_struct *png_ptr = NULL;
9999 png_info *info_ptr = NULL, *end_info = NULL;
10000 FILE *fp = NULL;
10001 png_byte sig[8];
10002 png_byte *pixels = NULL;
10003 png_byte **rows = NULL;
10004 png_uint_32 width, height;
10005 int bit_depth, color_type, interlace_type;
10006 png_byte channels;
10007 png_uint_32 row_bytes;
10008 int transparent_p;
10009 char *gamma_str;
10010 double screen_gamma, image_gamma;
10011 int intent;
10012 struct png_memory_storage tbr; /* Data to be read */
10014 /* Find out what file to load. */
10015 specified_file = image_spec_value (img->spec, QCfile, NULL);
10016 specified_data = image_spec_value (img->spec, QCdata, NULL);
10017 file = Qnil;
10018 GCPRO1 (file);
10020 if (NILP (specified_data))
10022 file = x_find_image_file (specified_file);
10023 if (!STRINGP (file))
10025 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10026 UNGCPRO;
10027 return 0;
10030 /* Open the image file. */
10031 fp = fopen (XSTRING (file)->data, "rb");
10032 if (!fp)
10034 image_error ("Cannot open image file `%s'", file, Qnil);
10035 UNGCPRO;
10036 fclose (fp);
10037 return 0;
10040 /* Check PNG signature. */
10041 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10042 || !png_check_sig (sig, sizeof sig))
10044 image_error ("Not a PNG file:` %s'", file, Qnil);
10045 UNGCPRO;
10046 fclose (fp);
10047 return 0;
10050 else
10052 /* Read from memory. */
10053 tbr.bytes = XSTRING (specified_data)->data;
10054 tbr.len = STRING_BYTES (XSTRING (specified_data));
10055 tbr.index = 0;
10057 /* Check PNG signature. */
10058 if (tbr.len < sizeof sig
10059 || !png_check_sig (tbr.bytes, sizeof sig))
10061 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10062 UNGCPRO;
10063 return 0;
10066 /* Need to skip past the signature. */
10067 tbr.bytes += sizeof (sig);
10070 /* Initialize read and info structs for PNG lib. */
10071 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10072 my_png_error, my_png_warning);
10073 if (!png_ptr)
10075 if (fp) fclose (fp);
10076 UNGCPRO;
10077 return 0;
10080 info_ptr = png_create_info_struct (png_ptr);
10081 if (!info_ptr)
10083 png_destroy_read_struct (&png_ptr, NULL, NULL);
10084 if (fp) fclose (fp);
10085 UNGCPRO;
10086 return 0;
10089 end_info = png_create_info_struct (png_ptr);
10090 if (!end_info)
10092 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10093 if (fp) fclose (fp);
10094 UNGCPRO;
10095 return 0;
10098 /* Set error jump-back. We come back here when the PNG library
10099 detects an error. */
10100 if (setjmp (png_ptr->jmpbuf))
10102 error:
10103 if (png_ptr)
10104 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10105 xfree (pixels);
10106 xfree (rows);
10107 if (fp) fclose (fp);
10108 UNGCPRO;
10109 return 0;
10112 /* Read image info. */
10113 if (!NILP (specified_data))
10114 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10115 else
10116 png_init_io (png_ptr, fp);
10118 png_set_sig_bytes (png_ptr, sizeof sig);
10119 png_read_info (png_ptr, info_ptr);
10120 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10121 &interlace_type, NULL, NULL);
10123 /* If image contains simply transparency data, we prefer to
10124 construct a clipping mask. */
10125 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10126 transparent_p = 1;
10127 else
10128 transparent_p = 0;
10130 /* This function is easier to write if we only have to handle
10131 one data format: RGB or RGBA with 8 bits per channel. Let's
10132 transform other formats into that format. */
10134 /* Strip more than 8 bits per channel. */
10135 if (bit_depth == 16)
10136 png_set_strip_16 (png_ptr);
10138 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10139 if available. */
10140 png_set_expand (png_ptr);
10142 /* Convert grayscale images to RGB. */
10143 if (color_type == PNG_COLOR_TYPE_GRAY
10144 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10145 png_set_gray_to_rgb (png_ptr);
10147 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10148 gamma_str = getenv ("SCREEN_GAMMA");
10149 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10151 /* Tell the PNG lib to handle gamma correction for us. */
10153 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10154 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10155 /* There is a special chunk in the image specifying the gamma. */
10156 png_set_sRGB (png_ptr, info_ptr, intent);
10157 else
10158 #endif
10159 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10160 /* Image contains gamma information. */
10161 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10162 else
10163 /* Use a default of 0.5 for the image gamma. */
10164 png_set_gamma (png_ptr, screen_gamma, 0.5);
10166 /* Handle alpha channel by combining the image with a background
10167 color. Do this only if a real alpha channel is supplied. For
10168 simple transparency, we prefer a clipping mask. */
10169 if (!transparent_p)
10171 png_color_16 *image_background;
10173 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10174 /* Image contains a background color with which to
10175 combine the image. */
10176 png_set_background (png_ptr, image_background,
10177 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10178 else
10180 /* Image does not contain a background color with which
10181 to combine the image data via an alpha channel. Use
10182 the frame's background instead. */
10183 XColor color;
10184 Colormap cmap;
10185 png_color_16 frame_background;
10187 BLOCK_INPUT;
10188 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10189 color.pixel = FRAME_BACKGROUND_PIXEL (f);
10190 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
10191 UNBLOCK_INPUT;
10193 bzero (&frame_background, sizeof frame_background);
10194 frame_background.red = color.red;
10195 frame_background.green = color.green;
10196 frame_background.blue = color.blue;
10198 png_set_background (png_ptr, &frame_background,
10199 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
10203 /* Update info structure. */
10204 png_read_update_info (png_ptr, info_ptr);
10206 /* Get number of channels. Valid values are 1 for grayscale images
10207 and images with a palette, 2 for grayscale images with transparency
10208 information (alpha channel), 3 for RGB images, and 4 for RGB
10209 images with alpha channel, i.e. RGBA. If conversions above were
10210 sufficient we should only have 3 or 4 channels here. */
10211 channels = png_get_channels (png_ptr, info_ptr);
10212 xassert (channels == 3 || channels == 4);
10214 /* Number of bytes needed for one row of the image. */
10215 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
10217 /* Allocate memory for the image. */
10218 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
10219 rows = (png_byte **) xmalloc (height * sizeof *rows);
10220 for (i = 0; i < height; ++i)
10221 rows[i] = pixels + i * row_bytes;
10223 /* Read the entire image. */
10224 png_read_image (png_ptr, rows);
10225 png_read_end (png_ptr, info_ptr);
10226 if (fp)
10228 fclose (fp);
10229 fp = NULL;
10232 BLOCK_INPUT;
10234 /* Create the X image and pixmap. */
10235 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10236 &img->pixmap))
10238 UNBLOCK_INPUT;
10239 goto error;
10242 /* Create an image and pixmap serving as mask if the PNG image
10243 contains an alpha channel. */
10244 if (channels == 4
10245 && !transparent_p
10246 && !x_create_x_image_and_pixmap (f, width, height, 1,
10247 &mask_img, &img->mask))
10249 x_destroy_x_image (ximg);
10250 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
10251 img->pixmap = 0;
10252 UNBLOCK_INPUT;
10253 goto error;
10256 /* Fill the X image and mask from PNG data. */
10257 init_color_table ();
10259 for (y = 0; y < height; ++y)
10261 png_byte *p = rows[y];
10263 for (x = 0; x < width; ++x)
10265 unsigned r, g, b;
10267 r = *p++ << 8;
10268 g = *p++ << 8;
10269 b = *p++ << 8;
10270 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10272 /* An alpha channel, aka mask channel, associates variable
10273 transparency with an image. Where other image formats
10274 support binary transparency---fully transparent or fully
10275 opaque---PNG allows up to 254 levels of partial transparency.
10276 The PNG library implements partial transparency by combining
10277 the image with a specified background color.
10279 I'm not sure how to handle this here nicely: because the
10280 background on which the image is displayed may change, for
10281 real alpha channel support, it would be necessary to create
10282 a new image for each possible background.
10284 What I'm doing now is that a mask is created if we have
10285 boolean transparency information. Otherwise I'm using
10286 the frame's background color to combine the image with. */
10288 if (channels == 4)
10290 if (mask_img)
10291 XPutPixel (mask_img, x, y, *p > 0);
10292 ++p;
10297 /* Remember colors allocated for this image. */
10298 img->colors = colors_in_color_table (&img->ncolors);
10299 free_color_table ();
10301 /* Clean up. */
10302 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10303 xfree (rows);
10304 xfree (pixels);
10306 img->width = width;
10307 img->height = height;
10309 /* Put the image into the pixmap, then free the X image and its buffer. */
10310 x_put_x_image (f, ximg, img->pixmap, width, height);
10311 x_destroy_x_image (ximg);
10313 /* Same for the mask. */
10314 if (mask_img)
10316 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10317 x_destroy_x_image (mask_img);
10320 UNBLOCK_INPUT;
10321 UNGCPRO;
10322 return 1;
10325 #endif /* HAVE_PNG != 0 */
10329 /***********************************************************************
10330 JPEG
10331 ***********************************************************************/
10333 #if HAVE_JPEG
10335 /* Work around a warning about HAVE_STDLIB_H being redefined in
10336 jconfig.h. */
10337 #ifdef HAVE_STDLIB_H
10338 #define HAVE_STDLIB_H_1
10339 #undef HAVE_STDLIB_H
10340 #endif /* HAVE_STLIB_H */
10342 #include <jpeglib.h>
10343 #include <jerror.h>
10344 #include <setjmp.h>
10346 #ifdef HAVE_STLIB_H_1
10347 #define HAVE_STDLIB_H 1
10348 #endif
10350 static int jpeg_image_p P_ ((Lisp_Object object));
10351 static int jpeg_load P_ ((struct frame *f, struct image *img));
10353 /* The symbol `jpeg' identifying images of this type. */
10355 Lisp_Object Qjpeg;
10357 /* Indices of image specification fields in gs_format, below. */
10359 enum jpeg_keyword_index
10361 JPEG_TYPE,
10362 JPEG_DATA,
10363 JPEG_FILE,
10364 JPEG_ASCENT,
10365 JPEG_MARGIN,
10366 JPEG_RELIEF,
10367 JPEG_ALGORITHM,
10368 JPEG_HEURISTIC_MASK,
10369 JPEG_LAST
10372 /* Vector of image_keyword structures describing the format
10373 of valid user-defined image specifications. */
10375 static struct image_keyword jpeg_format[JPEG_LAST] =
10377 {":type", IMAGE_SYMBOL_VALUE, 1},
10378 {":data", IMAGE_STRING_VALUE, 0},
10379 {":file", IMAGE_STRING_VALUE, 0},
10380 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10381 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10382 {":relief", IMAGE_INTEGER_VALUE, 0},
10383 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10384 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10387 /* Structure describing the image type `jpeg'. */
10389 static struct image_type jpeg_type =
10391 &Qjpeg,
10392 jpeg_image_p,
10393 jpeg_load,
10394 x_clear_image,
10395 NULL
10399 /* Return non-zero if OBJECT is a valid JPEG image specification. */
10401 static int
10402 jpeg_image_p (object)
10403 Lisp_Object object;
10405 struct image_keyword fmt[JPEG_LAST];
10407 bcopy (jpeg_format, fmt, sizeof fmt);
10409 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
10410 || (fmt[JPEG_ASCENT].count
10411 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
10412 return 0;
10414 /* Must specify either the :data or :file keyword. */
10415 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
10419 struct my_jpeg_error_mgr
10421 struct jpeg_error_mgr pub;
10422 jmp_buf setjmp_buffer;
10425 static void
10426 my_error_exit (cinfo)
10427 j_common_ptr cinfo;
10429 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
10430 longjmp (mgr->setjmp_buffer, 1);
10433 /* Init source method for JPEG data source manager. Called by
10434 jpeg_read_header() before any data is actually read. See
10435 libjpeg.doc from the JPEG lib distribution. */
10437 static void
10438 our_init_source (cinfo)
10439 j_decompress_ptr cinfo;
10444 /* Fill input buffer method for JPEG data source manager. Called
10445 whenever more data is needed. We read the whole image in one step,
10446 so this only adds a fake end of input marker at the end. */
10448 static boolean
10449 our_fill_input_buffer (cinfo)
10450 j_decompress_ptr cinfo;
10452 /* Insert a fake EOI marker. */
10453 struct jpeg_source_mgr *src = cinfo->src;
10454 static JOCTET buffer[2];
10456 buffer[0] = (JOCTET) 0xFF;
10457 buffer[1] = (JOCTET) JPEG_EOI;
10459 src->next_input_byte = buffer;
10460 src->bytes_in_buffer = 2;
10461 return TRUE;
10465 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
10466 is the JPEG data source manager. */
10468 static void
10469 our_skip_input_data (cinfo, num_bytes)
10470 j_decompress_ptr cinfo;
10471 long num_bytes;
10473 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
10475 if (src)
10477 if (num_bytes > src->bytes_in_buffer)
10478 ERREXIT (cinfo, JERR_INPUT_EOF);
10480 src->bytes_in_buffer -= num_bytes;
10481 src->next_input_byte += num_bytes;
10486 /* Method to terminate data source. Called by
10487 jpeg_finish_decompress() after all data has been processed. */
10489 static void
10490 our_term_source (cinfo)
10491 j_decompress_ptr cinfo;
10496 /* Set up the JPEG lib for reading an image from DATA which contains
10497 LEN bytes. CINFO is the decompression info structure created for
10498 reading the image. */
10500 static void
10501 jpeg_memory_src (cinfo, data, len)
10502 j_decompress_ptr cinfo;
10503 JOCTET *data;
10504 unsigned int len;
10506 struct jpeg_source_mgr *src;
10508 if (cinfo->src == NULL)
10510 /* First time for this JPEG object? */
10511 cinfo->src = (struct jpeg_source_mgr *)
10512 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
10513 sizeof (struct jpeg_source_mgr));
10514 src = (struct jpeg_source_mgr *) cinfo->src;
10515 src->next_input_byte = data;
10518 src = (struct jpeg_source_mgr *) cinfo->src;
10519 src->init_source = our_init_source;
10520 src->fill_input_buffer = our_fill_input_buffer;
10521 src->skip_input_data = our_skip_input_data;
10522 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
10523 src->term_source = our_term_source;
10524 src->bytes_in_buffer = len;
10525 src->next_input_byte = data;
10529 /* Load image IMG for use on frame F. Patterned after example.c
10530 from the JPEG lib. */
10532 static int
10533 jpeg_load (f, img)
10534 struct frame *f;
10535 struct image *img;
10537 struct jpeg_decompress_struct cinfo;
10538 struct my_jpeg_error_mgr mgr;
10539 Lisp_Object file, specified_file;
10540 Lisp_Object specified_data;
10541 FILE *fp = NULL;
10542 JSAMPARRAY buffer;
10543 int row_stride, x, y;
10544 XImage *ximg = NULL;
10545 int rc;
10546 unsigned long *colors;
10547 int width, height;
10548 struct gcpro gcpro1;
10550 /* Open the JPEG file. */
10551 specified_file = image_spec_value (img->spec, QCfile, NULL);
10552 specified_data = image_spec_value (img->spec, QCdata, NULL);
10553 file = Qnil;
10554 GCPRO1 (file);
10556 if (NILP (specified_data))
10558 file = x_find_image_file (specified_file);
10559 if (!STRINGP (file))
10561 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10562 UNGCPRO;
10563 return 0;
10566 fp = fopen (XSTRING (file)->data, "r");
10567 if (fp == NULL)
10569 image_error ("Cannot open `%s'", file, Qnil);
10570 UNGCPRO;
10571 return 0;
10575 /* Customize libjpeg's error handling to call my_error_exit when an
10576 error is detected. This function will perform a longjmp. */
10577 mgr.pub.error_exit = my_error_exit;
10578 cinfo.err = jpeg_std_error (&mgr.pub);
10580 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
10582 if (rc == 1)
10584 /* Called from my_error_exit. Display a JPEG error. */
10585 char buffer[JMSG_LENGTH_MAX];
10586 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
10587 image_error ("Error reading JPEG image `%s': %s", img->spec,
10588 build_string (buffer));
10591 /* Close the input file and destroy the JPEG object. */
10592 if (fp)
10593 fclose (fp);
10594 jpeg_destroy_decompress (&cinfo);
10596 BLOCK_INPUT;
10598 /* If we already have an XImage, free that. */
10599 x_destroy_x_image (ximg);
10601 /* Free pixmap and colors. */
10602 x_clear_image (f, img);
10604 UNBLOCK_INPUT;
10605 UNGCPRO;
10606 return 0;
10609 /* Create the JPEG decompression object. Let it read from fp.
10610 Read the JPEG image header. */
10611 jpeg_create_decompress (&cinfo);
10613 if (NILP (specified_data))
10614 jpeg_stdio_src (&cinfo, fp);
10615 else
10616 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
10617 STRING_BYTES (XSTRING (specified_data)));
10619 jpeg_read_header (&cinfo, TRUE);
10621 /* Customize decompression so that color quantization will be used.
10622 Start decompression. */
10623 cinfo.quantize_colors = TRUE;
10624 jpeg_start_decompress (&cinfo);
10625 width = img->width = cinfo.output_width;
10626 height = img->height = cinfo.output_height;
10628 BLOCK_INPUT;
10630 /* Create X image and pixmap. */
10631 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
10632 &img->pixmap))
10634 UNBLOCK_INPUT;
10635 longjmp (mgr.setjmp_buffer, 2);
10638 /* Allocate colors. When color quantization is used,
10639 cinfo.actual_number_of_colors has been set with the number of
10640 colors generated, and cinfo.colormap is a two-dimensional array
10641 of color indices in the range 0..cinfo.actual_number_of_colors.
10642 No more than 255 colors will be generated. */
10644 int i, ir, ig, ib;
10646 if (cinfo.out_color_components > 2)
10647 ir = 0, ig = 1, ib = 2;
10648 else if (cinfo.out_color_components > 1)
10649 ir = 0, ig = 1, ib = 0;
10650 else
10651 ir = 0, ig = 0, ib = 0;
10653 /* Use the color table mechanism because it handles colors that
10654 cannot be allocated nicely. Such colors will be replaced with
10655 a default color, and we don't have to care about which colors
10656 can be freed safely, and which can't. */
10657 init_color_table ();
10658 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
10659 * sizeof *colors);
10661 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
10663 /* Multiply RGB values with 255 because X expects RGB values
10664 in the range 0..0xffff. */
10665 int r = cinfo.colormap[ir][i] << 8;
10666 int g = cinfo.colormap[ig][i] << 8;
10667 int b = cinfo.colormap[ib][i] << 8;
10668 colors[i] = lookup_rgb_color (f, r, g, b);
10671 /* Remember those colors actually allocated. */
10672 img->colors = colors_in_color_table (&img->ncolors);
10673 free_color_table ();
10676 /* Read pixels. */
10677 row_stride = width * cinfo.output_components;
10678 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
10679 row_stride, 1);
10680 for (y = 0; y < height; ++y)
10682 jpeg_read_scanlines (&cinfo, buffer, 1);
10683 for (x = 0; x < cinfo.output_width; ++x)
10684 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
10687 /* Clean up. */
10688 jpeg_finish_decompress (&cinfo);
10689 jpeg_destroy_decompress (&cinfo);
10690 if (fp)
10691 fclose (fp);
10693 /* Put the image into the pixmap. */
10694 x_put_x_image (f, ximg, img->pixmap, width, height);
10695 x_destroy_x_image (ximg);
10696 UNBLOCK_INPUT;
10697 UNGCPRO;
10698 return 1;
10701 #endif /* HAVE_JPEG */
10705 /***********************************************************************
10706 TIFF
10707 ***********************************************************************/
10709 #if HAVE_TIFF
10711 #include <tiffio.h>
10713 static int tiff_image_p P_ ((Lisp_Object object));
10714 static int tiff_load P_ ((struct frame *f, struct image *img));
10716 /* The symbol `tiff' identifying images of this type. */
10718 Lisp_Object Qtiff;
10720 /* Indices of image specification fields in tiff_format, below. */
10722 enum tiff_keyword_index
10724 TIFF_TYPE,
10725 TIFF_DATA,
10726 TIFF_FILE,
10727 TIFF_ASCENT,
10728 TIFF_MARGIN,
10729 TIFF_RELIEF,
10730 TIFF_ALGORITHM,
10731 TIFF_HEURISTIC_MASK,
10732 TIFF_LAST
10735 /* Vector of image_keyword structures describing the format
10736 of valid user-defined image specifications. */
10738 static struct image_keyword tiff_format[TIFF_LAST] =
10740 {":type", IMAGE_SYMBOL_VALUE, 1},
10741 {":data", IMAGE_STRING_VALUE, 0},
10742 {":file", IMAGE_STRING_VALUE, 0},
10743 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10744 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
10745 {":relief", IMAGE_INTEGER_VALUE, 0},
10746 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10747 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10750 /* Structure describing the image type `tiff'. */
10752 static struct image_type tiff_type =
10754 &Qtiff,
10755 tiff_image_p,
10756 tiff_load,
10757 x_clear_image,
10758 NULL
10762 /* Return non-zero if OBJECT is a valid TIFF image specification. */
10764 static int
10765 tiff_image_p (object)
10766 Lisp_Object object;
10768 struct image_keyword fmt[TIFF_LAST];
10769 bcopy (tiff_format, fmt, sizeof fmt);
10771 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
10772 || (fmt[TIFF_ASCENT].count
10773 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
10774 return 0;
10776 /* Must specify either the :data or :file keyword. */
10777 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
10781 /* Reading from a memory buffer for TIFF images Based on the PNG
10782 memory source, but we have to provide a lot of extra functions.
10783 Blah.
10785 We really only need to implement read and seek, but I am not
10786 convinced that the TIFF library is smart enough not to destroy
10787 itself if we only hand it the function pointers we need to
10788 override. */
10790 typedef struct
10792 unsigned char *bytes;
10793 size_t len;
10794 int index;
10796 tiff_memory_source;
10798 static size_t
10799 tiff_read_from_memory (data, buf, size)
10800 thandle_t data;
10801 tdata_t buf;
10802 tsize_t size;
10804 tiff_memory_source *src = (tiff_memory_source *) data;
10806 if (size > src->len - src->index)
10807 return (size_t) -1;
10808 bcopy (src->bytes + src->index, buf, size);
10809 src->index += size;
10810 return size;
10813 static size_t
10814 tiff_write_from_memory (data, buf, size)
10815 thandle_t data;
10816 tdata_t buf;
10817 tsize_t size;
10819 return (size_t) -1;
10822 static toff_t
10823 tiff_seek_in_memory (data, off, whence)
10824 thandle_t data;
10825 toff_t off;
10826 int whence;
10828 tiff_memory_source *src = (tiff_memory_source *) data;
10829 int idx;
10831 switch (whence)
10833 case SEEK_SET: /* Go from beginning of source. */
10834 idx = off;
10835 break;
10837 case SEEK_END: /* Go from end of source. */
10838 idx = src->len + off;
10839 break;
10841 case SEEK_CUR: /* Go from current position. */
10842 idx = src->index + off;
10843 break;
10845 default: /* Invalid `whence'. */
10846 return -1;
10849 if (idx > src->len || idx < 0)
10850 return -1;
10852 src->index = idx;
10853 return src->index;
10856 static int
10857 tiff_close_memory (data)
10858 thandle_t data;
10860 /* NOOP */
10861 return 0;
10864 static int
10865 tiff_mmap_memory (data, pbase, psize)
10866 thandle_t data;
10867 tdata_t *pbase;
10868 toff_t *psize;
10870 /* It is already _IN_ memory. */
10871 return 0;
10874 static void
10875 tiff_unmap_memory (data, base, size)
10876 thandle_t data;
10877 tdata_t base;
10878 toff_t size;
10880 /* We don't need to do this. */
10883 static toff_t
10884 tiff_size_of_memory (data)
10885 thandle_t data;
10887 return ((tiff_memory_source *) data)->len;
10890 /* Load TIFF image IMG for use on frame F. Value is non-zero if
10891 successful. */
10893 static int
10894 tiff_load (f, img)
10895 struct frame *f;
10896 struct image *img;
10898 Lisp_Object file, specified_file;
10899 Lisp_Object specified_data;
10900 TIFF *tiff;
10901 int width, height, x, y;
10902 uint32 *buf;
10903 int rc;
10904 XImage *ximg;
10905 struct gcpro gcpro1;
10906 tiff_memory_source memsrc;
10908 specified_file = image_spec_value (img->spec, QCfile, NULL);
10909 specified_data = image_spec_value (img->spec, QCdata, NULL);
10910 file = Qnil;
10911 GCPRO1 (file);
10913 if (NILP (specified_data))
10915 /* Read from a file */
10916 file = x_find_image_file (specified_file);
10917 if (!STRINGP (file))
10919 image_error ("Cannot find image file `%s'", file, Qnil);
10920 UNGCPRO;
10921 return 0;
10924 /* Try to open the image file. */
10925 tiff = TIFFOpen (XSTRING (file)->data, "r");
10926 if (tiff == NULL)
10928 image_error ("Cannot open `%s'", file, Qnil);
10929 UNGCPRO;
10930 return 0;
10933 else
10935 /* Memory source! */
10936 memsrc.bytes = XSTRING (specified_data)->data;
10937 memsrc.len = STRING_BYTES (XSTRING (specified_data));
10938 memsrc.index = 0;
10940 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
10941 (TIFFReadWriteProc) tiff_read_from_memory,
10942 (TIFFReadWriteProc) tiff_write_from_memory,
10943 tiff_seek_in_memory,
10944 tiff_close_memory,
10945 tiff_size_of_memory,
10946 tiff_mmap_memory,
10947 tiff_unmap_memory);
10949 if (!tiff)
10951 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
10952 UNGCPRO;
10953 return 0;
10957 /* Get width and height of the image, and allocate a raster buffer
10958 of width x height 32-bit values. */
10959 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
10960 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
10961 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
10963 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
10964 TIFFClose (tiff);
10965 if (!rc)
10967 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
10968 xfree (buf);
10969 UNGCPRO;
10970 return 0;
10973 BLOCK_INPUT;
10975 /* Create the X image and pixmap. */
10976 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
10978 UNBLOCK_INPUT;
10979 xfree (buf);
10980 UNGCPRO;
10981 return 0;
10984 /* Initialize the color table. */
10985 init_color_table ();
10987 /* Process the pixel raster. Origin is in the lower-left corner. */
10988 for (y = 0; y < height; ++y)
10990 uint32 *row = buf + y * width;
10992 for (x = 0; x < width; ++x)
10994 uint32 abgr = row[x];
10995 int r = TIFFGetR (abgr) << 8;
10996 int g = TIFFGetG (abgr) << 8;
10997 int b = TIFFGetB (abgr) << 8;
10998 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11002 /* Remember the colors allocated for the image. Free the color table. */
11003 img->colors = colors_in_color_table (&img->ncolors);
11004 free_color_table ();
11006 /* Put the image into the pixmap, then free the X image and its buffer. */
11007 x_put_x_image (f, ximg, img->pixmap, width, height);
11008 x_destroy_x_image (ximg);
11009 xfree (buf);
11010 UNBLOCK_INPUT;
11012 img->width = width;
11013 img->height = height;
11015 UNGCPRO;
11016 return 1;
11019 #endif /* HAVE_TIFF != 0 */
11023 /***********************************************************************
11025 ***********************************************************************/
11027 #if HAVE_GIF
11029 #include <gif_lib.h>
11031 static int gif_image_p P_ ((Lisp_Object object));
11032 static int gif_load P_ ((struct frame *f, struct image *img));
11034 /* The symbol `gif' identifying images of this type. */
11036 Lisp_Object Qgif;
11038 /* Indices of image specification fields in gif_format, below. */
11040 enum gif_keyword_index
11042 GIF_TYPE,
11043 GIF_DATA,
11044 GIF_FILE,
11045 GIF_ASCENT,
11046 GIF_MARGIN,
11047 GIF_RELIEF,
11048 GIF_ALGORITHM,
11049 GIF_HEURISTIC_MASK,
11050 GIF_IMAGE,
11051 GIF_LAST
11054 /* Vector of image_keyword structures describing the format
11055 of valid user-defined image specifications. */
11057 static struct image_keyword gif_format[GIF_LAST] =
11059 {":type", IMAGE_SYMBOL_VALUE, 1},
11060 {":data", IMAGE_STRING_VALUE, 0},
11061 {":file", IMAGE_STRING_VALUE, 0},
11062 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11063 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11064 {":relief", IMAGE_INTEGER_VALUE, 0},
11065 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11066 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11067 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11070 /* Structure describing the image type `gif'. */
11072 static struct image_type gif_type =
11074 &Qgif,
11075 gif_image_p,
11076 gif_load,
11077 x_clear_image,
11078 NULL
11081 /* Return non-zero if OBJECT is a valid GIF image specification. */
11083 static int
11084 gif_image_p (object)
11085 Lisp_Object object;
11087 struct image_keyword fmt[GIF_LAST];
11088 bcopy (gif_format, fmt, sizeof fmt);
11090 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11091 || (fmt[GIF_ASCENT].count
11092 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11093 return 0;
11095 /* Must specify either the :data or :file keyword. */
11096 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11099 /* Reading a GIF image from memory
11100 Based on the PNG memory stuff to a certain extent. */
11102 typedef struct
11104 unsigned char *bytes;
11105 size_t len;
11106 int index;
11108 gif_memory_source;
11110 /* Make the current memory source available to gif_read_from_memory.
11111 It's done this way because not all versions of libungif support
11112 a UserData field in the GifFileType structure. */
11113 static gif_memory_source *current_gif_memory_src;
11115 static int
11116 gif_read_from_memory (file, buf, len)
11117 GifFileType *file;
11118 GifByteType *buf;
11119 int len;
11121 gif_memory_source *src = current_gif_memory_src;
11123 if (len > src->len - src->index)
11124 return -1;
11126 bcopy (src->bytes + src->index, buf, len);
11127 src->index += len;
11128 return len;
11132 /* Load GIF image IMG for use on frame F. Value is non-zero if
11133 successful. */
11135 static int
11136 gif_load (f, img)
11137 struct frame *f;
11138 struct image *img;
11140 Lisp_Object file, specified_file;
11141 Lisp_Object specified_data;
11142 int rc, width, height, x, y, i;
11143 XImage *ximg;
11144 ColorMapObject *gif_color_map;
11145 unsigned long pixel_colors[256];
11146 GifFileType *gif;
11147 struct gcpro gcpro1;
11148 Lisp_Object image;
11149 int ino, image_left, image_top, image_width, image_height;
11150 gif_memory_source memsrc;
11151 unsigned char *raster;
11153 specified_file = image_spec_value (img->spec, QCfile, NULL);
11154 specified_data = image_spec_value (img->spec, QCdata, NULL);
11155 file = Qnil;
11156 GCPRO1 (file);
11158 if (NILP (specified_data))
11160 file = x_find_image_file (specified_file);
11161 if (!STRINGP (file))
11163 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11164 UNGCPRO;
11165 return 0;
11168 /* Open the GIF file. */
11169 gif = DGifOpenFileName (XSTRING (file)->data);
11170 if (gif == NULL)
11172 image_error ("Cannot open `%s'", file, Qnil);
11173 UNGCPRO;
11174 return 0;
11177 else
11179 /* Read from memory! */
11180 current_gif_memory_src = &memsrc;
11181 memsrc.bytes = XSTRING (specified_data)->data;
11182 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11183 memsrc.index = 0;
11185 gif = DGifOpen(&memsrc, gif_read_from_memory);
11186 if (!gif)
11188 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
11189 UNGCPRO;
11190 return 0;
11194 /* Read entire contents. */
11195 rc = DGifSlurp (gif);
11196 if (rc == GIF_ERROR)
11198 image_error ("Error reading `%s'", img->spec, Qnil);
11199 DGifCloseFile (gif);
11200 UNGCPRO;
11201 return 0;
11204 image = image_spec_value (img->spec, QCindex, NULL);
11205 ino = INTEGERP (image) ? XFASTINT (image) : 0;
11206 if (ino >= gif->ImageCount)
11208 image_error ("Invalid image number `%s' in image `%s'",
11209 image, img->spec);
11210 DGifCloseFile (gif);
11211 UNGCPRO;
11212 return 0;
11215 width = img->width = gif->SWidth;
11216 height = img->height = gif->SHeight;
11218 BLOCK_INPUT;
11220 /* Create the X image and pixmap. */
11221 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11223 UNBLOCK_INPUT;
11224 DGifCloseFile (gif);
11225 UNGCPRO;
11226 return 0;
11229 /* Allocate colors. */
11230 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
11231 if (!gif_color_map)
11232 gif_color_map = gif->SColorMap;
11233 init_color_table ();
11234 bzero (pixel_colors, sizeof pixel_colors);
11236 for (i = 0; i < gif_color_map->ColorCount; ++i)
11238 int r = gif_color_map->Colors[i].Red << 8;
11239 int g = gif_color_map->Colors[i].Green << 8;
11240 int b = gif_color_map->Colors[i].Blue << 8;
11241 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
11244 img->colors = colors_in_color_table (&img->ncolors);
11245 free_color_table ();
11247 /* Clear the part of the screen image that are not covered by
11248 the image from the GIF file. Full animated GIF support
11249 requires more than can be done here (see the gif89 spec,
11250 disposal methods). Let's simply assume that the part
11251 not covered by a sub-image is in the frame's background color. */
11252 image_top = gif->SavedImages[ino].ImageDesc.Top;
11253 image_left = gif->SavedImages[ino].ImageDesc.Left;
11254 image_width = gif->SavedImages[ino].ImageDesc.Width;
11255 image_height = gif->SavedImages[ino].ImageDesc.Height;
11257 for (y = 0; y < image_top; ++y)
11258 for (x = 0; x < width; ++x)
11259 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11261 for (y = image_top + image_height; y < height; ++y)
11262 for (x = 0; x < width; ++x)
11263 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11265 for (y = image_top; y < image_top + image_height; ++y)
11267 for (x = 0; x < image_left; ++x)
11268 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11269 for (x = image_left + image_width; x < width; ++x)
11270 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
11273 /* Read the GIF image into the X image. We use a local variable
11274 `raster' here because RasterBits below is a char *, and invites
11275 problems with bytes >= 0x80. */
11276 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
11278 if (gif->SavedImages[ino].ImageDesc.Interlace)
11280 static int interlace_start[] = {0, 4, 2, 1};
11281 static int interlace_increment[] = {8, 8, 4, 2};
11282 int pass, inc;
11283 int row = interlace_start[0];
11285 pass = 0;
11287 for (y = 0; y < image_height; y++)
11289 if (row >= image_height)
11291 row = interlace_start[++pass];
11292 while (row >= image_height)
11293 row = interlace_start[++pass];
11296 for (x = 0; x < image_width; x++)
11298 int i = raster[(y * image_width) + x];
11299 XPutPixel (ximg, x + image_left, row + image_top,
11300 pixel_colors[i]);
11303 row += interlace_increment[pass];
11306 else
11308 for (y = 0; y < image_height; ++y)
11309 for (x = 0; x < image_width; ++x)
11311 int i = raster[y* image_width + x];
11312 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
11316 DGifCloseFile (gif);
11318 /* Put the image into the pixmap, then free the X image and its buffer. */
11319 x_put_x_image (f, ximg, img->pixmap, width, height);
11320 x_destroy_x_image (ximg);
11321 UNBLOCK_INPUT;
11323 UNGCPRO;
11324 return 1;
11327 #endif /* HAVE_GIF != 0 */
11331 /***********************************************************************
11332 Ghostscript
11333 ***********************************************************************/
11335 #ifdef HAVE_GHOSTSCRIPT
11336 static int gs_image_p P_ ((Lisp_Object object));
11337 static int gs_load P_ ((struct frame *f, struct image *img));
11338 static void gs_clear_image P_ ((struct frame *f, struct image *img));
11340 /* The symbol `postscript' identifying images of this type. */
11342 Lisp_Object Qpostscript;
11344 /* Keyword symbols. */
11346 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
11348 /* Indices of image specification fields in gs_format, below. */
11350 enum gs_keyword_index
11352 GS_TYPE,
11353 GS_PT_WIDTH,
11354 GS_PT_HEIGHT,
11355 GS_FILE,
11356 GS_LOADER,
11357 GS_BOUNDING_BOX,
11358 GS_ASCENT,
11359 GS_MARGIN,
11360 GS_RELIEF,
11361 GS_ALGORITHM,
11362 GS_HEURISTIC_MASK,
11363 GS_LAST
11366 /* Vector of image_keyword structures describing the format
11367 of valid user-defined image specifications. */
11369 static struct image_keyword gs_format[GS_LAST] =
11371 {":type", IMAGE_SYMBOL_VALUE, 1},
11372 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11373 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
11374 {":file", IMAGE_STRING_VALUE, 1},
11375 {":loader", IMAGE_FUNCTION_VALUE, 0},
11376 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
11377 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11378 {":margin", IMAGE_POSITIVE_INTEGER_VALUE, 0},
11379 {":relief", IMAGE_INTEGER_VALUE, 0},
11380 {":algorithm", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11381 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11384 /* Structure describing the image type `ghostscript'. */
11386 static struct image_type gs_type =
11388 &Qpostscript,
11389 gs_image_p,
11390 gs_load,
11391 gs_clear_image,
11392 NULL
11396 /* Free X resources of Ghostscript image IMG which is used on frame F. */
11398 static void
11399 gs_clear_image (f, img)
11400 struct frame *f;
11401 struct image *img;
11403 /* IMG->data.ptr_val may contain a recorded colormap. */
11404 xfree (img->data.ptr_val);
11405 x_clear_image (f, img);
11409 /* Return non-zero if OBJECT is a valid Ghostscript image
11410 specification. */
11412 static int
11413 gs_image_p (object)
11414 Lisp_Object object;
11416 struct image_keyword fmt[GS_LAST];
11417 Lisp_Object tem;
11418 int i;
11420 bcopy (gs_format, fmt, sizeof fmt);
11422 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
11423 || (fmt[GS_ASCENT].count
11424 && XFASTINT (fmt[GS_ASCENT].value) > 100))
11425 return 0;
11427 /* Bounding box must be a list or vector containing 4 integers. */
11428 tem = fmt[GS_BOUNDING_BOX].value;
11429 if (CONSP (tem))
11431 for (i = 0; i < 4; ++i, tem = XCDR (tem))
11432 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
11433 return 0;
11434 if (!NILP (tem))
11435 return 0;
11437 else if (VECTORP (tem))
11439 if (XVECTOR (tem)->size != 4)
11440 return 0;
11441 for (i = 0; i < 4; ++i)
11442 if (!INTEGERP (XVECTOR (tem)->contents[i]))
11443 return 0;
11445 else
11446 return 0;
11448 return 1;
11452 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
11453 if successful. */
11455 static int
11456 gs_load (f, img)
11457 struct frame *f;
11458 struct image *img;
11460 char buffer[100];
11461 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
11462 struct gcpro gcpro1, gcpro2;
11463 Lisp_Object frame;
11464 double in_width, in_height;
11465 Lisp_Object pixel_colors = Qnil;
11467 /* Compute pixel size of pixmap needed from the given size in the
11468 image specification. Sizes in the specification are in pt. 1 pt
11469 = 1/72 in, xdpi and ydpi are stored in the frame's X display
11470 info. */
11471 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
11472 in_width = XFASTINT (pt_width) / 72.0;
11473 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
11474 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
11475 in_height = XFASTINT (pt_height) / 72.0;
11476 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
11478 /* Create the pixmap. */
11479 BLOCK_INPUT;
11480 xassert (img->pixmap == 0);
11481 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11482 img->width, img->height,
11483 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
11484 UNBLOCK_INPUT;
11486 if (!img->pixmap)
11488 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
11489 return 0;
11492 /* Call the loader to fill the pixmap. It returns a process object
11493 if successful. We do not record_unwind_protect here because
11494 other places in redisplay like calling window scroll functions
11495 don't either. Let the Lisp loader use `unwind-protect' instead. */
11496 GCPRO2 (window_and_pixmap_id, pixel_colors);
11498 sprintf (buffer, "%lu %lu",
11499 (unsigned long) FRAME_W32_WINDOW (f),
11500 (unsigned long) img->pixmap);
11501 window_and_pixmap_id = build_string (buffer);
11503 sprintf (buffer, "%lu %lu",
11504 FRAME_FOREGROUND_PIXEL (f),
11505 FRAME_BACKGROUND_PIXEL (f));
11506 pixel_colors = build_string (buffer);
11508 XSETFRAME (frame, f);
11509 loader = image_spec_value (img->spec, QCloader, NULL);
11510 if (NILP (loader))
11511 loader = intern ("gs-load-image");
11513 img->data.lisp_val = call6 (loader, frame, img->spec,
11514 make_number (img->width),
11515 make_number (img->height),
11516 window_and_pixmap_id,
11517 pixel_colors);
11518 UNGCPRO;
11519 return PROCESSP (img->data.lisp_val);
11523 /* Kill the Ghostscript process that was started to fill PIXMAP on
11524 frame F. Called from XTread_socket when receiving an event
11525 telling Emacs that Ghostscript has finished drawing. */
11527 void
11528 x_kill_gs_process (pixmap, f)
11529 Pixmap pixmap;
11530 struct frame *f;
11532 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
11533 int class, i;
11534 struct image *img;
11536 /* Find the image containing PIXMAP. */
11537 for (i = 0; i < c->used; ++i)
11538 if (c->images[i]->pixmap == pixmap)
11539 break;
11541 /* Kill the GS process. We should have found PIXMAP in the image
11542 cache and its image should contain a process object. */
11543 xassert (i < c->used);
11544 img = c->images[i];
11545 xassert (PROCESSP (img->data.lisp_val));
11546 Fkill_process (img->data.lisp_val, Qnil);
11547 img->data.lisp_val = Qnil;
11549 /* On displays with a mutable colormap, figure out the colors
11550 allocated for the image by looking at the pixels of an XImage for
11551 img->pixmap. */
11552 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
11553 if (class != StaticColor && class != StaticGray && class != TrueColor)
11555 XImage *ximg;
11557 BLOCK_INPUT;
11559 /* Try to get an XImage for img->pixmep. */
11560 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
11561 0, 0, img->width, img->height, ~0, ZPixmap);
11562 if (ximg)
11564 int x, y;
11566 /* Initialize the color table. */
11567 init_color_table ();
11569 /* For each pixel of the image, look its color up in the
11570 color table. After having done so, the color table will
11571 contain an entry for each color used by the image. */
11572 for (y = 0; y < img->height; ++y)
11573 for (x = 0; x < img->width; ++x)
11575 unsigned long pixel = XGetPixel (ximg, x, y);
11576 lookup_pixel_color (f, pixel);
11579 /* Record colors in the image. Free color table and XImage. */
11580 img->colors = colors_in_color_table (&img->ncolors);
11581 free_color_table ();
11582 XDestroyImage (ximg);
11584 #if 0 /* This doesn't seem to be the case. If we free the colors
11585 here, we get a BadAccess later in x_clear_image when
11586 freeing the colors. */
11587 /* We have allocated colors once, but Ghostscript has also
11588 allocated colors on behalf of us. So, to get the
11589 reference counts right, free them once. */
11590 if (img->ncolors)
11592 Colormap cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11593 XFreeColors (FRAME_W32_DISPLAY (f), cmap,
11594 img->colors, img->ncolors, 0);
11596 #endif
11598 else
11599 image_error ("Cannot get X image of `%s'; colors will not be freed",
11600 img->spec, Qnil);
11602 UNBLOCK_INPUT;
11606 #endif /* HAVE_GHOSTSCRIPT */
11609 /***********************************************************************
11610 Window properties
11611 ***********************************************************************/
11613 DEFUN ("x-change-window-property", Fx_change_window_property,
11614 Sx_change_window_property, 2, 3, 0,
11615 "Change window property PROP to VALUE on the X window of FRAME.\n\
11616 PROP and VALUE must be strings. FRAME nil or omitted means use the\n\
11617 selected frame. Value is VALUE.")
11618 (prop, value, frame)
11619 Lisp_Object frame, prop, value;
11621 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11622 struct frame *f = check_x_frame (frame);
11623 Atom prop_atom;
11625 CHECK_STRING (prop, 1);
11626 CHECK_STRING (value, 2);
11628 BLOCK_INPUT;
11629 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11630 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11631 prop_atom, XA_STRING, 8, PropModeReplace,
11632 XSTRING (value)->data, XSTRING (value)->size);
11634 /* Make sure the property is set when we return. */
11635 XFlush (FRAME_W32_DISPLAY (f));
11636 UNBLOCK_INPUT;
11638 #endif /* NTEMACS_TODO */
11640 return value;
11644 DEFUN ("x-delete-window-property", Fx_delete_window_property,
11645 Sx_delete_window_property, 1, 2, 0,
11646 "Remove window property PROP from X window of FRAME.\n\
11647 FRAME nil or omitted means use the selected frame. Value is PROP.")
11648 (prop, frame)
11649 Lisp_Object prop, frame;
11651 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11653 struct frame *f = check_x_frame (frame);
11654 Atom prop_atom;
11656 CHECK_STRING (prop, 1);
11657 BLOCK_INPUT;
11658 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11659 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
11661 /* Make sure the property is removed when we return. */
11662 XFlush (FRAME_W32_DISPLAY (f));
11663 UNBLOCK_INPUT;
11664 #endif /* NTEMACS_TODO */
11666 return prop;
11670 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
11671 1, 2, 0,
11672 "Value is the value of window property PROP on FRAME.\n\
11673 If FRAME is nil or omitted, use the selected frame. Value is nil\n\
11674 if FRAME hasn't a property with name PROP or if PROP has no string\n\
11675 value.")
11676 (prop, frame)
11677 Lisp_Object prop, frame;
11679 #if 0 /* NTEMACS_TODO : port window properties to W32 */
11681 struct frame *f = check_x_frame (frame);
11682 Atom prop_atom;
11683 int rc;
11684 Lisp_Object prop_value = Qnil;
11685 char *tmp_data = NULL;
11686 Atom actual_type;
11687 int actual_format;
11688 unsigned long actual_size, bytes_remaining;
11690 CHECK_STRING (prop, 1);
11691 BLOCK_INPUT;
11692 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
11693 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11694 prop_atom, 0, 0, False, XA_STRING,
11695 &actual_type, &actual_format, &actual_size,
11696 &bytes_remaining, (unsigned char **) &tmp_data);
11697 if (rc == Success)
11699 int size = bytes_remaining;
11701 XFree (tmp_data);
11702 tmp_data = NULL;
11704 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
11705 prop_atom, 0, bytes_remaining,
11706 False, XA_STRING,
11707 &actual_type, &actual_format,
11708 &actual_size, &bytes_remaining,
11709 (unsigned char **) &tmp_data);
11710 if (rc == Success)
11711 prop_value = make_string (tmp_data, size);
11713 XFree (tmp_data);
11716 UNBLOCK_INPUT;
11718 return prop_value;
11720 #endif /* NTEMACS_TODO */
11721 return Qnil;
11726 /***********************************************************************
11727 Busy cursor
11728 ***********************************************************************/
11730 /* If non-null, an asynchronous timer that, when it expires, displays
11731 a busy cursor on all frames. */
11733 static struct atimer *busy_cursor_atimer;
11735 /* Non-zero means a busy cursor is currently shown. */
11737 static int busy_cursor_shown_p;
11739 /* Number of seconds to wait before displaying a busy cursor. */
11741 static Lisp_Object Vbusy_cursor_delay;
11743 /* Default number of seconds to wait before displaying a busy
11744 cursor. */
11746 #define DEFAULT_BUSY_CURSOR_DELAY 1
11748 /* Function prototypes. */
11750 static void show_busy_cursor P_ ((struct atimer *));
11751 static void hide_busy_cursor P_ ((void));
11754 /* Cancel a currently active busy-cursor timer, and start a new one. */
11756 void
11757 start_busy_cursor ()
11759 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11760 EMACS_TIME delay;
11761 int secs, usecs = 0;
11763 cancel_busy_cursor ();
11765 if (INTEGERP (Vbusy_cursor_delay)
11766 && XINT (Vbusy_cursor_delay) > 0)
11767 secs = XFASTINT (Vbusy_cursor_delay);
11768 else if (FLOATP (Vbusy_cursor_delay)
11769 && XFLOAT_DATA (Vbusy_cursor_delay) > 0)
11771 Lisp_Object tem;
11772 tem = Ftruncate (Vbusy_cursor_delay, Qnil);
11773 secs = XFASTINT (tem);
11774 usecs = (XFLOAT_DATA (Vbusy_cursor_delay) - secs) * 1000000;
11776 else
11777 secs = DEFAULT_BUSY_CURSOR_DELAY;
11779 EMACS_SET_SECS_USECS (delay, secs, usecs);
11780 busy_cursor_atimer = start_atimer (ATIMER_RELATIVE, delay,
11781 show_busy_cursor, NULL);
11782 #endif
11786 /* Cancel the busy cursor timer if active, hide a busy cursor if
11787 shown. */
11789 void
11790 cancel_busy_cursor ()
11792 if (busy_cursor_atimer)
11794 cancel_atimer (busy_cursor_atimer);
11795 busy_cursor_atimer = NULL;
11798 if (busy_cursor_shown_p)
11799 hide_busy_cursor ();
11803 /* Timer function of busy_cursor_atimer. TIMER is equal to
11804 busy_cursor_atimer.
11806 Display a busy cursor on all frames by mapping the frames'
11807 busy_window. Set the busy_p flag in the frames' output_data.x
11808 structure to indicate that a busy cursor is shown on the
11809 frames. */
11811 static void
11812 show_busy_cursor (timer)
11813 struct atimer *timer;
11815 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11816 /* The timer implementation will cancel this timer automatically
11817 after this function has run. Set busy_cursor_atimer to null
11818 so that we know the timer doesn't have to be canceled. */
11819 busy_cursor_atimer = NULL;
11821 if (!busy_cursor_shown_p)
11823 Lisp_Object rest, frame;
11825 BLOCK_INPUT;
11827 FOR_EACH_FRAME (rest, frame)
11828 if (FRAME_X_P (XFRAME (frame)))
11830 struct frame *f = XFRAME (frame);
11832 f->output_data.w32->busy_p = 1;
11834 if (!f->output_data.w32->busy_window)
11836 unsigned long mask = CWCursor;
11837 XSetWindowAttributes attrs;
11839 attrs.cursor = f->output_data.w32->busy_cursor;
11841 f->output_data.w32->busy_window
11842 = XCreateWindow (FRAME_X_DISPLAY (f),
11843 FRAME_OUTER_WINDOW (f),
11844 0, 0, 32000, 32000, 0, 0,
11845 InputOnly,
11846 CopyFromParent,
11847 mask, &attrs);
11850 XMapRaised (FRAME_X_DISPLAY (f), f->output_data.w32->busy_window);
11851 XFlush (FRAME_X_DISPLAY (f));
11854 busy_cursor_shown_p = 1;
11855 UNBLOCK_INPUT;
11857 #endif
11861 /* Hide the busy cursor on all frames, if it is currently shown. */
11863 static void
11864 hide_busy_cursor ()
11866 #if 0 /* NTEMACS_TODO: cursor shape changes. */
11867 if (busy_cursor_shown_p)
11869 Lisp_Object rest, frame;
11871 BLOCK_INPUT;
11872 FOR_EACH_FRAME (rest, frame)
11874 struct frame *f = XFRAME (frame);
11876 if (FRAME_X_P (f)
11877 /* Watch out for newly created frames. */
11878 && f->output_data.x->busy_window)
11880 XUnmapWindow (FRAME_X_DISPLAY (f), f->output_data.x->busy_window);
11881 /* Sync here because XTread_socket looks at the busy_p flag
11882 that is reset to zero below. */
11883 XSync (FRAME_X_DISPLAY (f), False);
11884 f->output_data.x->busy_p = 0;
11888 busy_cursor_shown_p = 0;
11889 UNBLOCK_INPUT;
11891 #endif
11896 /***********************************************************************
11897 Tool tips
11898 ***********************************************************************/
11900 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
11901 Lisp_Object));
11903 /* The frame of a currently visible tooltip, or null. */
11905 struct frame *tip_frame;
11907 /* If non-nil, a timer started that hides the last tooltip when it
11908 fires. */
11910 Lisp_Object tip_timer;
11911 Window tip_window;
11913 /* Create a frame for a tooltip on the display described by DPYINFO.
11914 PARMS is a list of frame parameters. Value is the frame. */
11916 static Lisp_Object
11917 x_create_tip_frame (dpyinfo, parms)
11918 struct w32_display_info *dpyinfo;
11919 Lisp_Object parms;
11921 #if 0 /* NTEMACS_TODO : w32 version */
11922 struct frame *f;
11923 Lisp_Object frame, tem;
11924 Lisp_Object name;
11925 long window_prompting = 0;
11926 int width, height;
11927 int count = specpdl_ptr - specpdl;
11928 struct gcpro gcpro1, gcpro2, gcpro3;
11929 struct kboard *kb;
11931 check_x ();
11933 /* Use this general default value to start with until we know if
11934 this frame has a specified name. */
11935 Vx_resource_name = Vinvocation_name;
11937 #ifdef MULTI_KBOARD
11938 kb = dpyinfo->kboard;
11939 #else
11940 kb = &the_only_kboard;
11941 #endif
11943 /* Get the name of the frame to use for resource lookup. */
11944 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
11945 if (!STRINGP (name)
11946 && !EQ (name, Qunbound)
11947 && !NILP (name))
11948 error ("Invalid frame name--not a string or nil");
11949 Vx_resource_name = name;
11951 frame = Qnil;
11952 GCPRO3 (parms, name, frame);
11953 tip_frame = f = make_frame (1);
11954 XSETFRAME (frame, f);
11955 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
11957 f->output_method = output_w32;
11958 f->output_data.w32 =
11959 (struct w32_output *) xmalloc (sizeof (struct w32_output));
11960 bzero (f->output_data.w32, sizeof (struct w32_output));
11961 #if 0
11962 f->output_data.w32->icon_bitmap = -1;
11963 #endif
11964 f->output_data.w32->fontset = -1;
11965 f->icon_name = Qnil;
11967 #ifdef MULTI_KBOARD
11968 FRAME_KBOARD (f) = kb;
11969 #endif
11970 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
11971 f->output_data.w32->explicit_parent = 0;
11973 /* Set the name; the functions to which we pass f expect the name to
11974 be set. */
11975 if (EQ (name, Qunbound) || NILP (name))
11977 f->name = build_string (dpyinfo->x_id_name);
11978 f->explicit_name = 0;
11980 else
11982 f->name = name;
11983 f->explicit_name = 1;
11984 /* use the frame's title when getting resources for this frame. */
11985 specbind (Qx_resource_name, name);
11988 /* Extract the window parameters from the supplied values
11989 that are needed to determine window geometry. */
11991 Lisp_Object font;
11993 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
11995 BLOCK_INPUT;
11996 /* First, try whatever font the caller has specified. */
11997 if (STRINGP (font))
11999 tem = Fquery_fontset (font, Qnil);
12000 if (STRINGP (tem))
12001 font = x_new_fontset (f, XSTRING (tem)->data);
12002 else
12003 font = x_new_font (f, XSTRING (font)->data);
12006 /* Try out a font which we hope has bold and italic variations. */
12007 if (!STRINGP (font))
12008 font = x_new_font (f, "-adobe-courier-medium-r-*-*-*-120-*-*-*-*-iso8859-1");
12009 if (!STRINGP (font))
12010 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12011 if (! STRINGP (font))
12012 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12013 if (! STRINGP (font))
12014 /* This was formerly the first thing tried, but it finds too many fonts
12015 and takes too long. */
12016 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12017 /* If those didn't work, look for something which will at least work. */
12018 if (! STRINGP (font))
12019 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12020 UNBLOCK_INPUT;
12021 if (! STRINGP (font))
12022 font = build_string ("fixed");
12024 x_default_parameter (f, parms, Qfont, font,
12025 "font", "Font", RES_TYPE_STRING);
12028 x_default_parameter (f, parms, Qborder_width, make_number (2),
12029 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12031 /* This defaults to 2 in order to match xterm. We recognize either
12032 internalBorderWidth or internalBorder (which is what xterm calls
12033 it). */
12034 if (NILP (Fassq (Qinternal_border_width, parms)))
12036 Lisp_Object value;
12038 value = w32_get_arg (parms, Qinternal_border_width,
12039 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12040 if (! EQ (value, Qunbound))
12041 parms = Fcons (Fcons (Qinternal_border_width, value),
12042 parms);
12045 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12046 "internalBorderWidth", "internalBorderWidth",
12047 RES_TYPE_NUMBER);
12049 /* Also do the stuff which must be set before the window exists. */
12050 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12051 "foreground", "Foreground", RES_TYPE_STRING);
12052 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12053 "background", "Background", RES_TYPE_STRING);
12054 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12055 "pointerColor", "Foreground", RES_TYPE_STRING);
12056 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12057 "cursorColor", "Foreground", RES_TYPE_STRING);
12058 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12059 "borderColor", "BorderColor", RES_TYPE_STRING);
12061 /* Init faces before x_default_parameter is called for scroll-bar
12062 parameters because that function calls x_set_scroll_bar_width,
12063 which calls change_frame_size, which calls Fset_window_buffer,
12064 which runs hooks, which call Fvertical_motion. At the end, we
12065 end up in init_iterator with a null face cache, which should not
12066 happen. */
12067 init_frame_faces (f);
12069 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12070 window_prompting = x_figure_window_size (f, parms);
12072 if (window_prompting & XNegative)
12074 if (window_prompting & YNegative)
12075 f->output_data.w32->win_gravity = SouthEastGravity;
12076 else
12077 f->output_data.w32->win_gravity = NorthEastGravity;
12079 else
12081 if (window_prompting & YNegative)
12082 f->output_data.w32->win_gravity = SouthWestGravity;
12083 else
12084 f->output_data.w32->win_gravity = NorthWestGravity;
12087 f->output_data.w32->size_hint_flags = window_prompting;
12089 XSetWindowAttributes attrs;
12090 unsigned long mask;
12092 BLOCK_INPUT;
12093 mask = CWBackPixel | CWOverrideRedirect | CWSaveUnder | CWEventMask;
12094 /* Window managers looks at the override-redirect flag to
12095 determine whether or net to give windows a decoration (Xlib
12096 3.2.8). */
12097 attrs.override_redirect = True;
12098 attrs.save_under = True;
12099 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
12100 /* Arrange for getting MapNotify and UnmapNotify events. */
12101 attrs.event_mask = StructureNotifyMask;
12102 tip_window
12103 = FRAME_W32_WINDOW (f)
12104 = XCreateWindow (FRAME_W32_DISPLAY (f),
12105 FRAME_W32_DISPLAY_INFO (f)->root_window,
12106 /* x, y, width, height */
12107 0, 0, 1, 1,
12108 /* Border. */
12110 CopyFromParent, InputOutput, CopyFromParent,
12111 mask, &attrs);
12112 UNBLOCK_INPUT;
12115 x_make_gc (f);
12117 x_default_parameter (f, parms, Qauto_raise, Qnil,
12118 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12119 x_default_parameter (f, parms, Qauto_lower, Qnil,
12120 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
12121 x_default_parameter (f, parms, Qcursor_type, Qbox,
12122 "cursorType", "CursorType", RES_TYPE_SYMBOL);
12124 /* Dimensions, especially f->height, must be done via change_frame_size.
12125 Change will not be effected unless different from the current
12126 f->height. */
12127 width = f->width;
12128 height = f->height;
12129 f->height = 0;
12130 SET_FRAME_WIDTH (f, 0);
12131 change_frame_size (f, height, width, 1, 0, 0);
12133 f->no_split = 1;
12135 UNGCPRO;
12137 /* It is now ok to make the frame official even if we get an error
12138 below. And the frame needs to be on Vframe_list or making it
12139 visible won't work. */
12140 Vframe_list = Fcons (frame, Vframe_list);
12142 /* Now that the frame is official, it counts as a reference to
12143 its display. */
12144 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
12146 return unbind_to (count, frame);
12147 #endif /* NTEMACS_TODO */
12148 return Qnil;
12152 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 4, 0,
12153 "Show STRING in a \"tooltip\" window on frame FRAME.\n\
12154 A tooltip window is a small X window displaying STRING at\n\
12155 the current mouse position.\n\
12156 FRAME nil or omitted means use the selected frame.\n\
12157 PARMS is an optional list of frame parameters which can be\n\
12158 used to change the tooltip's appearance.\n\
12159 Automatically hide the tooltip after TIMEOUT seconds.\n\
12160 TIMEOUT nil means use the default timeout of 5 seconds.")
12161 (string, frame, parms, timeout)
12162 Lisp_Object string, frame, parms, timeout;
12164 struct frame *f;
12165 struct window *w;
12166 Window root, child;
12167 Lisp_Object buffer;
12168 struct buffer *old_buffer;
12169 struct text_pos pos;
12170 int i, width, height;
12171 int root_x, root_y, win_x, win_y;
12172 unsigned pmask;
12173 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
12174 int old_windows_or_buffers_changed = windows_or_buffers_changed;
12175 int count = specpdl_ptr - specpdl;
12177 specbind (Qinhibit_redisplay, Qt);
12179 GCPRO4 (string, parms, frame, timeout);
12181 CHECK_STRING (string, 0);
12182 f = check_x_frame (frame);
12183 if (NILP (timeout))
12184 timeout = make_number (5);
12185 else
12186 CHECK_NATNUM (timeout, 2);
12188 /* Hide a previous tip, if any. */
12189 Fx_hide_tip ();
12191 /* Add default values to frame parameters. */
12192 if (NILP (Fassq (Qname, parms)))
12193 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
12194 if (NILP (Fassq (Qinternal_border_width, parms)))
12195 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
12196 if (NILP (Fassq (Qborder_width, parms)))
12197 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
12198 if (NILP (Fassq (Qborder_color, parms)))
12199 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
12200 if (NILP (Fassq (Qbackground_color, parms)))
12201 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
12202 parms);
12204 /* Create a frame for the tooltip, and record it in the global
12205 variable tip_frame. */
12206 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
12207 tip_frame = f = XFRAME (frame);
12209 /* Set up the frame's root window. Currently we use a size of 80
12210 columns x 40 lines. If someone wants to show a larger tip, he
12211 will loose. I don't think this is a realistic case. */
12212 w = XWINDOW (FRAME_ROOT_WINDOW (f));
12213 w->left = w->top = make_number (0);
12214 w->width = 80;
12215 w->height = 40;
12216 adjust_glyphs (f);
12217 w->pseudo_window_p = 1;
12219 /* Display the tooltip text in a temporary buffer. */
12220 buffer = Fget_buffer_create (build_string (" *tip*"));
12221 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12222 old_buffer = current_buffer;
12223 set_buffer_internal_1 (XBUFFER (buffer));
12224 Ferase_buffer ();
12225 Finsert (make_number (1), &string);
12226 clear_glyph_matrix (w->desired_matrix);
12227 clear_glyph_matrix (w->current_matrix);
12228 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
12229 try_window (FRAME_ROOT_WINDOW (f), pos);
12231 /* Compute width and height of the tooltip. */
12232 width = height = 0;
12233 for (i = 0; i < w->desired_matrix->nrows; ++i)
12235 struct glyph_row *row = &w->desired_matrix->rows[i];
12236 struct glyph *last;
12237 int row_width;
12239 /* Stop at the first empty row at the end. */
12240 if (!row->enabled_p || !row->displays_text_p)
12241 break;
12243 /* Let the row go over the full width of the frame. */
12244 row->full_width_p = 1;
12246 /* There's a glyph at the end of rows that is use to place
12247 the cursor there. Don't include the width of this glyph. */
12248 if (row->used[TEXT_AREA])
12250 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
12251 row_width = row->pixel_width - last->pixel_width;
12253 else
12254 row_width = row->pixel_width;
12256 height += row->height;
12257 width = max (width, row_width);
12260 /* Add the frame's internal border to the width and height the X
12261 window should have. */
12262 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12263 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
12265 /* Move the tooltip window where the mouse pointer is. Resize and
12266 show it. */
12267 #if 0 /* NTEMACS_TODO : W32 specifics */
12268 BLOCK_INPUT;
12269 XQueryPointer (FRAME_W32_DISPLAY (f), FRAME_W32_DISPLAY_INFO (f)->root_window,
12270 &root, &child, &root_x, &root_y, &win_x, &win_y, &pmask);
12271 XMoveResizeWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12272 root_x + 5, root_y - height - 5, width, height);
12273 XMapRaised (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
12274 UNBLOCK_INPUT;
12275 #endif /* NTEMACS_TODO */
12277 /* Draw into the window. */
12278 w->must_be_updated_p = 1;
12279 update_single_window (w, 1);
12281 /* Restore original current buffer. */
12282 set_buffer_internal_1 (old_buffer);
12283 windows_or_buffers_changed = old_windows_or_buffers_changed;
12285 /* Let the tip disappear after timeout seconds. */
12286 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
12287 intern ("x-hide-tip"));
12289 UNGCPRO;
12290 return unbind_to (count, Qnil);
12294 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
12295 "Hide the current tooltip window, if there is any.\n\
12296 Value is t is tooltip was open, nil otherwise.")
12299 int count = specpdl_ptr - specpdl;
12300 int deleted_p = 0;
12302 specbind (Qinhibit_redisplay, Qt);
12304 if (!NILP (tip_timer))
12306 call1 (intern ("cancel-timer"), tip_timer);
12307 tip_timer = Qnil;
12310 if (tip_frame)
12312 Lisp_Object frame;
12314 XSETFRAME (frame, tip_frame);
12315 Fdelete_frame (frame, Qt);
12316 tip_frame = NULL;
12317 deleted_p = 1;
12320 return unbind_to (count, deleted_p ? Qt : Qnil);
12325 /***********************************************************************
12326 File selection dialog
12327 ***********************************************************************/
12329 extern Lisp_Object Qfile_name_history;
12331 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
12332 "Read file name, prompting with PROMPT in directory DIR.\n\
12333 Use a file selection dialog.\n\
12334 Select DEFAULT-FILENAME in the dialog's file selection box, if\n\
12335 specified. Don't let the user enter a file name in the file\n\
12336 selection dialog's entry field, if MUSTMATCH is non-nil.")
12337 (prompt, dir, default_filename, mustmatch)
12338 Lisp_Object prompt, dir, default_filename, mustmatch;
12340 struct frame *f = SELECTED_FRAME ();
12341 Lisp_Object file = Qnil;
12342 int count = specpdl_ptr - specpdl;
12343 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
12344 char filename[MAX_PATH + 1];
12345 char init_dir[MAX_PATH + 1];
12346 int use_dialog_p = 1;
12348 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
12349 CHECK_STRING (prompt, 0);
12350 CHECK_STRING (dir, 1);
12352 /* Create the dialog with PROMPT as title, using DIR as initial
12353 directory and using "*" as pattern. */
12354 dir = Fexpand_file_name (dir, Qnil);
12355 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
12356 init_dir[MAX_PATH] = '\0';
12357 unixtodos_filename (init_dir);
12359 if (STRINGP (default_filename))
12361 char *file_name_only;
12362 char *full_path_name = XSTRING (default_filename)->data;
12364 unixtodos_filename (full_path_name);
12366 file_name_only = strrchr (full_path_name, '\\');
12367 if (!file_name_only)
12368 file_name_only = full_path_name;
12369 else
12371 file_name_only++;
12373 /* If default_file_name is a directory, don't use the open
12374 file dialog, as it does not support selecting
12375 directories. */
12376 if (!(*file_name_only))
12377 use_dialog_p = 0;
12380 strncpy (filename, file_name_only, MAX_PATH);
12381 filename[MAX_PATH] = '\0';
12383 else
12384 filename[0] = '\0';
12386 if (use_dialog_p)
12388 OPENFILENAME file_details;
12389 char *filename_file;
12391 /* Prevent redisplay. */
12392 specbind (Qinhibit_redisplay, Qt);
12393 BLOCK_INPUT;
12395 bzero (&file_details, sizeof (file_details));
12396 file_details.lStructSize = sizeof (file_details);
12397 file_details.hwndOwner = FRAME_W32_WINDOW (f);
12398 file_details.lpstrFile = filename;
12399 file_details.nMaxFile = sizeof (filename);
12400 file_details.lpstrInitialDir = init_dir;
12401 file_details.lpstrTitle = XSTRING (prompt)->data;
12402 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
12404 if (!NILP (mustmatch))
12405 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
12407 if (GetOpenFileName (&file_details))
12409 dostounix_filename (filename);
12410 file = build_string (filename);
12412 else
12413 file = Qnil;
12415 UNBLOCK_INPUT;
12416 file = unbind_to (count, file);
12418 /* Open File dialog will not allow folders to be selected, so resort
12419 to minibuffer completing reads for directories. */
12420 else
12421 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
12422 dir, mustmatch, dir, Qfile_name_history,
12423 default_filename, Qnil);
12425 UNGCPRO;
12427 /* Make "Cancel" equivalent to C-g. */
12428 if (NILP (file))
12429 Fsignal (Qquit, Qnil);
12431 return unbind_to (count, file);
12436 /***********************************************************************
12437 Tests
12438 ***********************************************************************/
12440 #if GLYPH_DEBUG
12442 DEFUN ("imagep", Fimagep, Simagep, 1, 1, 0,
12443 "Value is non-nil if SPEC is a valid image specification.")
12444 (spec)
12445 Lisp_Object spec;
12447 return valid_image_p (spec) ? Qt : Qnil;
12451 DEFUN ("lookup-image", Flookup_image, Slookup_image, 1, 1, 0, "")
12452 (spec)
12453 Lisp_Object spec;
12455 int id = -1;
12457 if (valid_image_p (spec))
12458 id = lookup_image (SELECTED_FRAME (), spec);
12460 debug_print (spec);
12461 return make_number (id);
12464 #endif /* GLYPH_DEBUG != 0 */
12468 /***********************************************************************
12469 w32 specialized functions
12470 ***********************************************************************/
12472 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
12473 "This will display the W32 font dialog and return an X font string corresponding to the selection.")
12474 (frame)
12475 Lisp_Object frame;
12477 FRAME_PTR f = check_x_frame (frame);
12478 CHOOSEFONT cf;
12479 LOGFONT lf;
12480 TEXTMETRIC tm;
12481 HDC hdc;
12482 HANDLE oldobj;
12483 char buf[100];
12485 bzero (&cf, sizeof (cf));
12486 bzero (&lf, sizeof (lf));
12488 cf.lStructSize = sizeof (cf);
12489 cf.hwndOwner = FRAME_W32_WINDOW (f);
12490 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
12491 cf.lpLogFont = &lf;
12493 /* Initialize as much of the font details as we can from the current
12494 default font. */
12495 hdc = GetDC (FRAME_W32_WINDOW (f));
12496 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
12497 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
12498 if (GetTextMetrics (hdc, &tm))
12500 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
12501 lf.lfWeight = tm.tmWeight;
12502 lf.lfItalic = tm.tmItalic;
12503 lf.lfUnderline = tm.tmUnderlined;
12504 lf.lfStrikeOut = tm.tmStruckOut;
12505 lf.lfCharSet = tm.tmCharSet;
12506 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
12508 SelectObject (hdc, oldobj);
12509 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
12511 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100))
12512 return Qnil;
12514 return build_string (buf);
12517 DEFUN ("w32-send-sys-command", Fw32_send_sys_command, Sw32_send_sys_command, 1, 2, 0,
12518 "Send frame a Windows WM_SYSCOMMAND message of type COMMAND.\n\
12519 Some useful values for command are 0xf030 to maximise frame (0xf020\n\
12520 to minimize), 0xf120 to restore frame to original size, and 0xf100\n\
12521 to activate the menubar for keyboard access. 0xf140 activates the\n\
12522 screen saver if defined.\n\
12524 If optional parameter FRAME is not specified, use selected frame.")
12525 (command, frame)
12526 Lisp_Object command, frame;
12528 WPARAM code;
12529 FRAME_PTR f = check_x_frame (frame);
12531 CHECK_NUMBER (command, 0);
12533 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
12535 return Qnil;
12538 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
12539 "Get Windows to perform OPERATION on DOCUMENT.\n\
12540 This is a wrapper around the ShellExecute system function, which\n\
12541 invokes the application registered to handle OPERATION for DOCUMENT.\n\
12542 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be\n\
12543 nil for the default action), and DOCUMENT is typically the name of a\n\
12544 document file or URL, but can also be a program executable to run or\n\
12545 a directory to open in the Windows Explorer.\n\
12547 If DOCUMENT is a program executable, PARAMETERS can be a string\n\
12548 containing command line parameters, but otherwise should be nil.\n\
12550 SHOW-FLAG can be used to control whether the invoked application is hidden\n\
12551 or minimized. If SHOW-FLAG is nil, the application is displayed normally,\n\
12552 otherwise it is an integer representing a ShowWindow flag:\n\
12554 0 - start hidden\n\
12555 1 - start normally\n\
12556 3 - start maximized\n\
12557 6 - start minimized")
12558 (operation, document, parameters, show_flag)
12559 Lisp_Object operation, document, parameters, show_flag;
12561 Lisp_Object current_dir;
12563 CHECK_STRING (document, 0);
12565 /* Encode filename and current directory. */
12566 current_dir = ENCODE_FILE (current_buffer->directory);
12567 document = ENCODE_FILE (document);
12568 if ((int) ShellExecute (NULL,
12569 (STRINGP (operation) ?
12570 XSTRING (operation)->data : NULL),
12571 XSTRING (document)->data,
12572 (STRINGP (parameters) ?
12573 XSTRING (parameters)->data : NULL),
12574 XSTRING (current_dir)->data,
12575 (INTEGERP (show_flag) ?
12576 XINT (show_flag) : SW_SHOWDEFAULT))
12577 > 32)
12578 return Qt;
12579 error ("ShellExecute failed");
12582 /* Lookup virtual keycode from string representing the name of a
12583 non-ascii keystroke into the corresponding virtual key, using
12584 lispy_function_keys. */
12585 static int
12586 lookup_vk_code (char *key)
12588 int i;
12590 for (i = 0; i < 256; i++)
12591 if (lispy_function_keys[i] != 0
12592 && strcmp (lispy_function_keys[i], key) == 0)
12593 return i;
12595 return -1;
12598 /* Convert a one-element vector style key sequence to a hot key
12599 definition. */
12600 static int
12601 w32_parse_hot_key (key)
12602 Lisp_Object key;
12604 /* Copied from Fdefine_key and store_in_keymap. */
12605 register Lisp_Object c;
12606 int vk_code;
12607 int lisp_modifiers;
12608 int w32_modifiers;
12609 struct gcpro gcpro1;
12611 CHECK_VECTOR (key, 0);
12613 if (XFASTINT (Flength (key)) != 1)
12614 return Qnil;
12616 GCPRO1 (key);
12618 c = Faref (key, make_number (0));
12620 if (CONSP (c) && lucid_event_type_list_p (c))
12621 c = Fevent_convert_list (c);
12623 UNGCPRO;
12625 if (! INTEGERP (c) && ! SYMBOLP (c))
12626 error ("Key definition is invalid");
12628 /* Work out the base key and the modifiers. */
12629 if (SYMBOLP (c))
12631 c = parse_modifiers (c);
12632 lisp_modifiers = Fcar (Fcdr (c));
12633 c = Fcar (c);
12634 if (!SYMBOLP (c))
12635 abort ();
12636 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
12638 else if (INTEGERP (c))
12640 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
12641 /* Many ascii characters are their own virtual key code. */
12642 vk_code = XINT (c) & CHARACTERBITS;
12645 if (vk_code < 0 || vk_code > 255)
12646 return Qnil;
12648 if ((lisp_modifiers & meta_modifier) != 0
12649 && !NILP (Vw32_alt_is_meta))
12650 lisp_modifiers |= alt_modifier;
12652 /* Convert lisp modifiers to Windows hot-key form. */
12653 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
12654 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
12655 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
12656 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
12658 return HOTKEY (vk_code, w32_modifiers);
12661 DEFUN ("w32-register-hot-key", Fw32_register_hot_key, Sw32_register_hot_key, 1, 1, 0,
12662 "Register KEY as a hot-key combination.\n\
12663 Certain key combinations like Alt-Tab are reserved for system use on\n\
12664 Windows, and therefore are normally intercepted by the system. However,\n\
12665 most of these key combinations can be received by registering them as\n\
12666 hot-keys, overriding their special meaning.\n\
12668 KEY must be a one element key definition in vector form that would be\n\
12669 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta\n\
12670 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper\n\
12671 is always interpreted as the Windows modifier keys.\n\
12673 The return value is the hotkey-id if registered, otherwise nil.")
12674 (key)
12675 Lisp_Object key;
12677 key = w32_parse_hot_key (key);
12679 if (NILP (Fmemq (key, w32_grabbed_keys)))
12681 /* Reuse an empty slot if possible. */
12682 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
12684 /* Safe to add new key to list, even if we have focus. */
12685 if (NILP (item))
12686 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
12687 else
12688 XCAR (item) = key;
12690 /* Notify input thread about new hot-key definition, so that it
12691 takes effect without needing to switch focus. */
12692 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
12693 (WPARAM) key, 0);
12696 return key;
12699 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key, Sw32_unregister_hot_key, 1, 1, 0,
12700 "Unregister HOTKEY as a hot-key combination.")
12701 (key)
12702 Lisp_Object key;
12704 Lisp_Object item;
12706 if (!INTEGERP (key))
12707 key = w32_parse_hot_key (key);
12709 item = Fmemq (key, w32_grabbed_keys);
12711 if (!NILP (item))
12713 /* Notify input thread about hot-key definition being removed, so
12714 that it takes effect without needing focus switch. */
12715 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
12716 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
12718 MSG msg;
12719 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12721 return Qt;
12723 return Qnil;
12726 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys, Sw32_registered_hot_keys, 0, 0, 0,
12727 "Return list of registered hot-key IDs.")
12730 return Fcopy_sequence (w32_grabbed_keys);
12733 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key, Sw32_reconstruct_hot_key, 1, 1, 0,
12734 "Convert hot-key ID to a lisp key combination.")
12735 (hotkeyid)
12736 Lisp_Object hotkeyid;
12738 int vk_code, w32_modifiers;
12739 Lisp_Object key;
12741 CHECK_NUMBER (hotkeyid, 0);
12743 vk_code = HOTKEY_VK_CODE (hotkeyid);
12744 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
12746 if (lispy_function_keys[vk_code])
12747 key = intern (lispy_function_keys[vk_code]);
12748 else
12749 key = make_number (vk_code);
12751 key = Fcons (key, Qnil);
12752 if (w32_modifiers & MOD_SHIFT)
12753 key = Fcons (Qshift, key);
12754 if (w32_modifiers & MOD_CONTROL)
12755 key = Fcons (Qctrl, key);
12756 if (w32_modifiers & MOD_ALT)
12757 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
12758 if (w32_modifiers & MOD_WIN)
12759 key = Fcons (Qhyper, key);
12761 return key;
12764 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key, Sw32_toggle_lock_key, 1, 2, 0,
12765 "Toggle the state of the lock key KEY.\n\
12766 KEY can be `capslock', `kp-numlock', or `scroll'.\n\
12767 If the optional parameter NEW-STATE is a number, then the state of KEY\n\
12768 is set to off if the low bit of NEW-STATE is zero, otherwise on.")
12769 (key, new_state)
12770 Lisp_Object key, new_state;
12772 int vk_code;
12773 int cur_state;
12775 if (EQ (key, intern ("capslock")))
12776 vk_code = VK_CAPITAL;
12777 else if (EQ (key, intern ("kp-numlock")))
12778 vk_code = VK_NUMLOCK;
12779 else if (EQ (key, intern ("scroll")))
12780 vk_code = VK_SCROLL;
12781 else
12782 return Qnil;
12784 if (!dwWindowsThreadId)
12785 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
12787 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
12788 (WPARAM) vk_code, (LPARAM) new_state))
12790 MSG msg;
12791 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
12792 return make_number (msg.wParam);
12794 return Qnil;
12797 syms_of_w32fns ()
12799 /* This is zero if not using MS-Windows. */
12800 w32_in_use = 0;
12802 /* The section below is built by the lisp expression at the top of the file,
12803 just above where these variables are declared. */
12804 /*&&& init symbols here &&&*/
12805 Qauto_raise = intern ("auto-raise");
12806 staticpro (&Qauto_raise);
12807 Qauto_lower = intern ("auto-lower");
12808 staticpro (&Qauto_lower);
12809 Qbar = intern ("bar");
12810 staticpro (&Qbar);
12811 Qborder_color = intern ("border-color");
12812 staticpro (&Qborder_color);
12813 Qborder_width = intern ("border-width");
12814 staticpro (&Qborder_width);
12815 Qbox = intern ("box");
12816 staticpro (&Qbox);
12817 Qcursor_color = intern ("cursor-color");
12818 staticpro (&Qcursor_color);
12819 Qcursor_type = intern ("cursor-type");
12820 staticpro (&Qcursor_type);
12821 Qgeometry = intern ("geometry");
12822 staticpro (&Qgeometry);
12823 Qicon_left = intern ("icon-left");
12824 staticpro (&Qicon_left);
12825 Qicon_top = intern ("icon-top");
12826 staticpro (&Qicon_top);
12827 Qicon_type = intern ("icon-type");
12828 staticpro (&Qicon_type);
12829 Qicon_name = intern ("icon-name");
12830 staticpro (&Qicon_name);
12831 Qinternal_border_width = intern ("internal-border-width");
12832 staticpro (&Qinternal_border_width);
12833 Qleft = intern ("left");
12834 staticpro (&Qleft);
12835 Qright = intern ("right");
12836 staticpro (&Qright);
12837 Qmouse_color = intern ("mouse-color");
12838 staticpro (&Qmouse_color);
12839 Qnone = intern ("none");
12840 staticpro (&Qnone);
12841 Qparent_id = intern ("parent-id");
12842 staticpro (&Qparent_id);
12843 Qscroll_bar_width = intern ("scroll-bar-width");
12844 staticpro (&Qscroll_bar_width);
12845 Qsuppress_icon = intern ("suppress-icon");
12846 staticpro (&Qsuppress_icon);
12847 Qundefined_color = intern ("undefined-color");
12848 staticpro (&Qundefined_color);
12849 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
12850 staticpro (&Qvertical_scroll_bars);
12851 Qvisibility = intern ("visibility");
12852 staticpro (&Qvisibility);
12853 Qwindow_id = intern ("window-id");
12854 staticpro (&Qwindow_id);
12855 Qx_frame_parameter = intern ("x-frame-parameter");
12856 staticpro (&Qx_frame_parameter);
12857 Qx_resource_name = intern ("x-resource-name");
12858 staticpro (&Qx_resource_name);
12859 Quser_position = intern ("user-position");
12860 staticpro (&Quser_position);
12861 Quser_size = intern ("user-size");
12862 staticpro (&Quser_size);
12863 Qscreen_gamma = intern ("screen-gamma");
12864 staticpro (&Qscreen_gamma);
12865 Qline_spacing = intern ("line-spacing");
12866 staticpro (&Qline_spacing);
12867 Qcenter = intern ("center");
12868 staticpro (&Qcenter);
12869 /* This is the end of symbol initialization. */
12871 Qhyper = intern ("hyper");
12872 staticpro (&Qhyper);
12873 Qsuper = intern ("super");
12874 staticpro (&Qsuper);
12875 Qmeta = intern ("meta");
12876 staticpro (&Qmeta);
12877 Qalt = intern ("alt");
12878 staticpro (&Qalt);
12879 Qctrl = intern ("ctrl");
12880 staticpro (&Qctrl);
12881 Qcontrol = intern ("control");
12882 staticpro (&Qcontrol);
12883 Qshift = intern ("shift");
12884 staticpro (&Qshift);
12886 /* Text property `display' should be nonsticky by default. */
12887 Vtext_property_default_nonsticky
12888 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
12891 Qlaplace = intern ("laplace");
12892 staticpro (&Qlaplace);
12894 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
12895 staticpro (&Qface_set_after_frame_default);
12897 Fput (Qundefined_color, Qerror_conditions,
12898 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
12899 Fput (Qundefined_color, Qerror_message,
12900 build_string ("Undefined color"));
12902 staticpro (&w32_grabbed_keys);
12903 w32_grabbed_keys = Qnil;
12905 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
12906 "An array of color name mappings for windows.");
12907 Vw32_color_map = Qnil;
12909 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
12910 "Non-nil if alt key presses are passed on to Windows.\n\
12911 When non-nil, for example, alt pressed and released and then space will\n\
12912 open the System menu. When nil, Emacs silently swallows alt key events.");
12913 Vw32_pass_alt_to_system = Qnil;
12915 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
12916 "Non-nil if the alt key is to be considered the same as the meta key.\n\
12917 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta.");
12918 Vw32_alt_is_meta = Qt;
12920 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
12921 "If non-zero, the virtual key code for an alternative quit key.");
12922 XSETINT (Vw32_quit_key, 0);
12924 DEFVAR_LISP ("w32-pass-lwindow-to-system",
12925 &Vw32_pass_lwindow_to_system,
12926 "Non-nil if the left \"Windows\" key is passed on to Windows.\n\
12927 When non-nil, the Start menu is opened by tapping the key.");
12928 Vw32_pass_lwindow_to_system = Qt;
12930 DEFVAR_LISP ("w32-pass-rwindow-to-system",
12931 &Vw32_pass_rwindow_to_system,
12932 "Non-nil if the right \"Windows\" key is passed on to Windows.\n\
12933 When non-nil, the Start menu is opened by tapping the key.");
12934 Vw32_pass_rwindow_to_system = Qt;
12936 DEFVAR_INT ("w32-phantom-key-code",
12937 &Vw32_phantom_key_code,
12938 "Virtual key code used to generate \"phantom\" key presses.\n\
12939 Value is a number between 0 and 255.\n\
12941 Phantom key presses are generated in order to stop the system from\n\
12942 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or\n\
12943 `w32-pass-rwindow-to-system' is nil.");
12944 /* Although 255 is technically not a valid key code, it works and
12945 means that this hack won't interfere with any real key code. */
12946 Vw32_phantom_key_code = 255;
12948 DEFVAR_LISP ("w32-enable-num-lock",
12949 &Vw32_enable_num_lock,
12950 "Non-nil if Num Lock should act normally.\n\
12951 Set to nil to see Num Lock as the key `kp-numlock'.");
12952 Vw32_enable_num_lock = Qt;
12954 DEFVAR_LISP ("w32-enable-caps-lock",
12955 &Vw32_enable_caps_lock,
12956 "Non-nil if Caps Lock should act normally.\n\
12957 Set to nil to see Caps Lock as the key `capslock'.");
12958 Vw32_enable_caps_lock = Qt;
12960 DEFVAR_LISP ("w32-scroll-lock-modifier",
12961 &Vw32_scroll_lock_modifier,
12962 "Modifier to use for the Scroll Lock on state.\n\
12963 The value can be hyper, super, meta, alt, control or shift for the\n\
12964 respective modifier, or nil to see Scroll Lock as the key `scroll'.\n\
12965 Any other value will cause the key to be ignored.");
12966 Vw32_scroll_lock_modifier = Qt;
12968 DEFVAR_LISP ("w32-lwindow-modifier",
12969 &Vw32_lwindow_modifier,
12970 "Modifier to use for the left \"Windows\" key.\n\
12971 The value can be hyper, super, meta, alt, control or shift for the\n\
12972 respective modifier, or nil to appear as the key `lwindow'.\n\
12973 Any other value will cause the key to be ignored.");
12974 Vw32_lwindow_modifier = Qnil;
12976 DEFVAR_LISP ("w32-rwindow-modifier",
12977 &Vw32_rwindow_modifier,
12978 "Modifier to use for the right \"Windows\" key.\n\
12979 The value can be hyper, super, meta, alt, control or shift for the\n\
12980 respective modifier, or nil to appear as the key `rwindow'.\n\
12981 Any other value will cause the key to be ignored.");
12982 Vw32_rwindow_modifier = Qnil;
12984 DEFVAR_LISP ("w32-apps-modifier",
12985 &Vw32_apps_modifier,
12986 "Modifier to use for the \"Apps\" key.\n\
12987 The value can be hyper, super, meta, alt, control or shift for the\n\
12988 respective modifier, or nil to appear as the key `apps'.\n\
12989 Any other value will cause the key to be ignored.");
12990 Vw32_apps_modifier = Qnil;
12992 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
12993 "Non-nil enables selection of artificially italicized and bold fonts.");
12994 Vw32_enable_synthesized_fonts = Qnil;
12996 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
12997 "Non-nil enables Windows palette management to map colors exactly.");
12998 Vw32_enable_palette = Qt;
13000 DEFVAR_INT ("w32-mouse-button-tolerance",
13001 &Vw32_mouse_button_tolerance,
13002 "Analogue of double click interval for faking middle mouse events.\n\
13003 The value is the minimum time in milliseconds that must elapse between\n\
13004 left/right button down events before they are considered distinct events.\n\
13005 If both mouse buttons are depressed within this interval, a middle mouse\n\
13006 button down event is generated instead.");
13007 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
13009 DEFVAR_INT ("w32-mouse-move-interval",
13010 &Vw32_mouse_move_interval,
13011 "Minimum interval between mouse move events.\n\
13012 The value is the minimum time in milliseconds that must elapse between\n\
13013 successive mouse move (or scroll bar drag) events before they are\n\
13014 reported as lisp events.");
13015 XSETINT (Vw32_mouse_move_interval, 0);
13017 init_x_parm_symbols ();
13019 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
13020 "List of directories to search for bitmap files for w32.");
13021 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
13023 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
13024 "The shape of the pointer when over text.\n\
13025 Changing the value does not affect existing frames\n\
13026 unless you set the mouse color.");
13027 Vx_pointer_shape = Qnil;
13029 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
13030 "The name Emacs uses to look up resources; for internal use only.\n\
13031 `x-get-resource' uses this as the first component of the instance name\n\
13032 when requesting resource values.\n\
13033 Emacs initially sets `x-resource-name' to the name under which Emacs\n\
13034 was invoked, or to the value specified with the `-name' or `-rn'\n\
13035 switches, if present.");
13036 Vx_resource_name = Qnil;
13038 Vx_nontext_pointer_shape = Qnil;
13040 Vx_mode_pointer_shape = Qnil;
13042 DEFVAR_LISP ("x-busy-pointer-shape", &Vx_busy_pointer_shape,
13043 "The shape of the pointer when Emacs is busy.\n\
13044 This variable takes effect when you create a new frame\n\
13045 or when you set the mouse color.");
13046 Vx_busy_pointer_shape = Qnil;
13048 DEFVAR_BOOL ("display-busy-cursor", &display_busy_cursor_p,
13049 "Non-zero means Emacs displays a busy cursor on window systems.");
13050 display_busy_cursor_p = 1;
13052 DEFVAR_LISP ("busy-cursor-delay", &Vbusy_cursor_delay,
13053 "*Seconds to wait before displaying a busy-cursor.\n\
13054 Value must be an integer or float.");
13055 Vbusy_cursor_delay = make_number (DEFAULT_BUSY_CURSOR_DELAY);
13057 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
13058 &Vx_sensitive_text_pointer_shape,
13059 "The shape of the pointer when over mouse-sensitive text.\n\
13060 This variable takes effect when you create a new frame\n\
13061 or when you set the mouse color.");
13062 Vx_sensitive_text_pointer_shape = Qnil;
13064 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
13065 "A string indicating the foreground color of the cursor box.");
13066 Vx_cursor_fore_pixel = Qnil;
13068 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
13069 "Non-nil if no window manager is in use.\n\
13070 Emacs doesn't try to figure this out; this is always nil\n\
13071 unless you set it to something else.");
13072 /* We don't have any way to find this out, so set it to nil
13073 and maybe the user would like to set it to t. */
13074 Vx_no_window_manager = Qnil;
13076 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
13077 &Vx_pixel_size_width_font_regexp,
13078 "Regexp matching a font name whose width is the same as `PIXEL_SIZE'.\n\
13080 Since Emacs gets width of a font matching with this regexp from\n\
13081 PIXEL_SIZE field of the name, font finding mechanism gets faster for\n\
13082 such a font. This is especially effective for such large fonts as\n\
13083 Chinese, Japanese, and Korean.");
13084 Vx_pixel_size_width_font_regexp = Qnil;
13086 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
13087 "Time after which cached images are removed from the cache.\n\
13088 When an image has not been displayed this many seconds, remove it\n\
13089 from the image cache. Value must be an integer or nil with nil\n\
13090 meaning don't clear the cache.");
13091 Vimage_cache_eviction_delay = make_number (30 * 60);
13093 DEFVAR_LISP ("w32-bdf-filename-alist",
13094 &Vw32_bdf_filename_alist,
13095 "List of bdf fonts and their corresponding filenames.");
13096 Vw32_bdf_filename_alist = Qnil;
13098 DEFVAR_BOOL ("w32-strict-fontnames",
13099 &w32_strict_fontnames,
13100 "Non-nil means only use fonts that are exact matches for those requested.\n\
13101 Default is nil, which allows old fontnames that are not XLFD compliant,\n\
13102 and allows third-party CJK display to work by specifying false charset\n\
13103 fields to trick Emacs into translating to Big5, SJIS etc.\n\
13104 Setting this to t will prevent wrong fonts being selected when\n\
13105 fontsets are automatically created.");
13106 w32_strict_fontnames = 0;
13108 DEFVAR_BOOL ("w32-strict-painting",
13109 &w32_strict_painting,
13110 "Non-nil means use strict rules for repainting frames.\n\
13111 Set this to nil to get the old behaviour for repainting; this should\n\
13112 only be necessary if the default setting causes problems.");
13113 w32_strict_painting = 1;
13115 DEFVAR_LISP ("w32-system-coding-system",
13116 &Vw32_system_coding_system,
13117 "Coding system used by Windows system functions, such as for font names.");
13118 Vw32_system_coding_system = Qnil;
13120 DEFVAR_LISP ("w32-charset-info-alist",
13121 &Vw32_charset_info_alist,
13122 "Alist linking Emacs character sets to Windows fonts\n\
13123 and codepages. Each entry should be of the form:\n\
13125 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))\n\
13127 where CHARSET_NAME is a string used in font names to identify the charset,\n\
13128 WINDOWS_CHARSET is a symbol that can be one of:\n\
13129 w32-charset-ansi, w32-charset-default, w32-charset-symbol,\n\
13130 w32-charset-shiftjis, w32-charset-hangul, w32-charset-gb2312,\n\
13131 w32-charset-chinesebig5, "
13132 #ifdef JOHAB_CHARSET
13133 "w32-charset-johab, w32-charset-hebrew,\n\
13134 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,\n\
13135 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,\n\
13136 w32-charset-russian, w32-charset-mac, w32-charset-baltic,\n"
13137 #endif
13138 #ifdef UNICODE_CHARSET
13139 "w32-charset-unicode, "
13140 #endif
13141 "or w32-charset-oem.\n\
13142 CODEPAGE should be an integer specifying the codepage that should be used\n\
13143 to display the character set, t to do no translation and output as Unicode,\n\
13144 or nil to do no translation and output as 8 bit (or multibyte on far-east\n\
13145 versions of Windows) characters.");
13146 Vw32_charset_info_alist = Qnil;
13148 staticpro (&Qw32_charset_ansi);
13149 Qw32_charset_ansi = intern ("w32-charset-ansi");
13150 staticpro (&Qw32_charset_symbol);
13151 Qw32_charset_symbol = intern ("w32-charset-symbol");
13152 staticpro (&Qw32_charset_shiftjis);
13153 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
13154 staticpro (&Qw32_charset_hangul);
13155 Qw32_charset_hangul = intern ("w32-charset-hangul");
13156 staticpro (&Qw32_charset_chinesebig5);
13157 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
13158 staticpro (&Qw32_charset_gb2312);
13159 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
13160 staticpro (&Qw32_charset_oem);
13161 Qw32_charset_oem = intern ("w32-charset-oem");
13163 #ifdef JOHAB_CHARSET
13165 static int w32_extra_charsets_defined = 1;
13166 DEFVAR_BOOL ("w32-extra-charsets-defined", w32_extra_charsets_defined, "");
13168 staticpro (&Qw32_charset_johab);
13169 Qw32_charset_johab = intern ("w32-charset-johab");
13170 staticpro (&Qw32_charset_easteurope);
13171 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
13172 staticpro (&Qw32_charset_turkish);
13173 Qw32_charset_turkish = intern ("w32-charset-turkish");
13174 staticpro (&Qw32_charset_baltic);
13175 Qw32_charset_baltic = intern ("w32-charset-baltic");
13176 staticpro (&Qw32_charset_russian);
13177 Qw32_charset_russian = intern ("w32-charset-russian");
13178 staticpro (&Qw32_charset_arabic);
13179 Qw32_charset_arabic = intern ("w32-charset-arabic");
13180 staticpro (&Qw32_charset_greek);
13181 Qw32_charset_greek = intern ("w32-charset-greek");
13182 staticpro (&Qw32_charset_hebrew);
13183 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
13184 staticpro (&Qw32_charset_thai);
13185 Qw32_charset_thai = intern ("w32-charset-thai");
13186 staticpro (&Qw32_charset_mac);
13187 Qw32_charset_mac = intern ("w32-charset-mac");
13189 #endif
13191 #ifdef UNICODE_CHARSET
13193 static int w32_unicode_charset_defined = 1;
13194 DEFVAR_BOOL ("w32-unicode-charset-defined",
13195 w32_unicode_charset_defined, "");
13197 staticpro (&Qw32_charset_unicode);
13198 Qw32_charset_unicode = intern ("w32-charset-unicode");
13199 #endif
13201 defsubr (&Sx_get_resource);
13202 #if 0 /* NTEMACS_TODO: Port to W32 */
13203 defsubr (&Sx_change_window_property);
13204 defsubr (&Sx_delete_window_property);
13205 defsubr (&Sx_window_property);
13206 #endif
13207 defsubr (&Sxw_display_color_p);
13208 defsubr (&Sx_display_grayscale_p);
13209 defsubr (&Sxw_color_defined_p);
13210 defsubr (&Sxw_color_values);
13211 defsubr (&Sx_server_max_request_size);
13212 defsubr (&Sx_server_vendor);
13213 defsubr (&Sx_server_version);
13214 defsubr (&Sx_display_pixel_width);
13215 defsubr (&Sx_display_pixel_height);
13216 defsubr (&Sx_display_mm_width);
13217 defsubr (&Sx_display_mm_height);
13218 defsubr (&Sx_display_screens);
13219 defsubr (&Sx_display_planes);
13220 defsubr (&Sx_display_color_cells);
13221 defsubr (&Sx_display_visual_class);
13222 defsubr (&Sx_display_backing_store);
13223 defsubr (&Sx_display_save_under);
13224 defsubr (&Sx_parse_geometry);
13225 defsubr (&Sx_create_frame);
13226 defsubr (&Sx_open_connection);
13227 defsubr (&Sx_close_connection);
13228 defsubr (&Sx_display_list);
13229 defsubr (&Sx_synchronize);
13231 /* W32 specific functions */
13233 defsubr (&Sw32_focus_frame);
13234 defsubr (&Sw32_select_font);
13235 defsubr (&Sw32_define_rgb_color);
13236 defsubr (&Sw32_default_color_map);
13237 defsubr (&Sw32_load_color_file);
13238 defsubr (&Sw32_send_sys_command);
13239 defsubr (&Sw32_shell_execute);
13240 defsubr (&Sw32_register_hot_key);
13241 defsubr (&Sw32_unregister_hot_key);
13242 defsubr (&Sw32_registered_hot_keys);
13243 defsubr (&Sw32_reconstruct_hot_key);
13244 defsubr (&Sw32_toggle_lock_key);
13245 defsubr (&Sw32_find_bdf_fonts);
13247 /* Setting callback functions for fontset handler. */
13248 get_font_info_func = w32_get_font_info;
13250 #if 0 /* This function pointer doesn't seem to be used anywhere.
13251 And the pointer assigned has the wrong type, anyway. */
13252 list_fonts_func = w32_list_fonts;
13253 #endif
13255 load_font_func = w32_load_font;
13256 find_ccl_program_func = w32_find_ccl_program;
13257 query_font_func = w32_query_font;
13258 set_frame_fontset_func = x_set_font;
13259 check_window_system_func = check_w32;
13261 #if 0 /* NTEMACS_TODO Image support for W32 */
13262 /* Images. */
13263 Qxbm = intern ("xbm");
13264 staticpro (&Qxbm);
13265 QCtype = intern (":type");
13266 staticpro (&QCtype);
13267 QCalgorithm = intern (":algorithm");
13268 staticpro (&QCalgorithm);
13269 QCheuristic_mask = intern (":heuristic-mask");
13270 staticpro (&QCheuristic_mask);
13271 QCcolor_symbols = intern (":color-symbols");
13272 staticpro (&QCcolor_symbols);
13273 QCascent = intern (":ascent");
13274 staticpro (&QCascent);
13275 QCmargin = intern (":margin");
13276 staticpro (&QCmargin);
13277 QCrelief = intern (":relief");
13278 staticpro (&QCrelief);
13279 Qpostscript = intern ("postscript");
13280 staticpro (&Qpostscript);
13281 QCloader = intern (":loader");
13282 staticpro (&QCloader);
13283 QCbounding_box = intern (":bounding-box");
13284 staticpro (&QCbounding_box);
13285 QCpt_width = intern (":pt-width");
13286 staticpro (&QCpt_width);
13287 QCpt_height = intern (":pt-height");
13288 staticpro (&QCpt_height);
13289 QCindex = intern (":index");
13290 staticpro (&QCindex);
13291 Qpbm = intern ("pbm");
13292 staticpro (&Qpbm);
13294 #if HAVE_XPM
13295 Qxpm = intern ("xpm");
13296 staticpro (&Qxpm);
13297 #endif
13299 #if HAVE_JPEG
13300 Qjpeg = intern ("jpeg");
13301 staticpro (&Qjpeg);
13302 #endif
13304 #if HAVE_TIFF
13305 Qtiff = intern ("tiff");
13306 staticpro (&Qtiff);
13307 #endif
13309 #if HAVE_GIF
13310 Qgif = intern ("gif");
13311 staticpro (&Qgif);
13312 #endif
13314 #if HAVE_PNG
13315 Qpng = intern ("png");
13316 staticpro (&Qpng);
13317 #endif
13319 defsubr (&Sclear_image_cache);
13321 #if GLYPH_DEBUG
13322 defsubr (&Simagep);
13323 defsubr (&Slookup_image);
13324 #endif
13325 #endif /* NTEMACS_TODO */
13327 busy_cursor_atimer = NULL;
13328 busy_cursor_shown_p = 0;
13330 defsubr (&Sx_show_tip);
13331 defsubr (&Sx_hide_tip);
13332 staticpro (&tip_timer);
13333 tip_timer = Qnil;
13335 defsubr (&Sx_file_dialog);
13339 void
13340 init_xfns ()
13342 image_types = NULL;
13343 Vimage_types = Qnil;
13345 #if 0 /* NTEMACS_TODO : Image support for W32 */
13346 define_image_type (&xbm_type);
13347 define_image_type (&gs_type);
13348 define_image_type (&pbm_type);
13350 #if HAVE_XPM
13351 define_image_type (&xpm_type);
13352 #endif
13354 #if HAVE_JPEG
13355 define_image_type (&jpeg_type);
13356 #endif
13358 #if HAVE_TIFF
13359 define_image_type (&tiff_type);
13360 #endif
13362 #if HAVE_GIF
13363 define_image_type (&gif_type);
13364 #endif
13366 #if HAVE_PNG
13367 define_image_type (&png_type);
13368 #endif
13369 #endif /* NTEMACS_TODO */
13372 #undef abort
13374 void
13375 w32_abort()
13377 int button;
13378 button = MessageBox (NULL,
13379 "A fatal error has occurred!\n\n"
13380 "Select Abort to exit, Retry to debug, Ignore to continue",
13381 "Emacs Abort Dialog",
13382 MB_ICONEXCLAMATION | MB_TASKMODAL
13383 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
13384 switch (button)
13386 case IDRETRY:
13387 DebugBreak ();
13388 break;
13389 case IDIGNORE:
13390 break;
13391 case IDABORT:
13392 default:
13393 abort ();
13394 break;
13398 /* For convenience when debugging. */
13400 w32_last_error()
13402 return GetLastError ();