]> code.delx.au - gnu-emacs/blob - src/w32fns.c
(command-line-processed): Doc fix.
[gnu-emacs] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
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.
11
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.
16
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. */
21
22 /* Added by Kevin Gallo */
23
24 #include <config.h>
25
26 #include <signal.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <errno.h>
30
31 #include "lisp.h"
32 #include "charset.h"
33 #include "dispextern.h"
34 #include "w32term.h"
35 #include "keyboard.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "buffer.h"
39 #include "fontset.h"
40 #include "intervals.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"
48
49 #include "bitmaps/gray.xbm"
50
51 #include <commdlg.h>
52 #include <shellapi.h>
53 #include <ctype.h>
54
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;
59
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
69
70 extern char *lispy_function_keys[];
71
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. */
75
76 int gray_bitmap_width = gray_width;
77 int gray_bitmap_height = gray_height;
78 unsigned char *gray_bitmap_bits = gray_bits;
79
80 /* The colormap for converting color names to RGB values */
81 Lisp_Object Vw32_color_map;
82
83 /* Non nil if alt key presses are passed on to Windows. */
84 Lisp_Object Vw32_pass_alt_to_system;
85
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;
89
90 /* If non-zero, the windows virtual key code for an alternative quit key. */
91 Lisp_Object Vw32_quit_key;
92
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;
96
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;
100
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;
104
105 /* Modifier associated with the left "Windows" key, or nil to act as a
106 normal key. */
107 Lisp_Object Vw32_lwindow_modifier;
108
109 /* Modifier associated with the right "Windows" key, or nil to act as a
110 normal key. */
111 Lisp_Object Vw32_rwindow_modifier;
112
113 /* Modifier associated with the "Apps" key, or nil to act as a normal
114 key. */
115 Lisp_Object Vw32_apps_modifier;
116
117 /* Value is nil if Num Lock acts as a function key. */
118 Lisp_Object Vw32_enable_num_lock;
119
120 /* Value is nil if Caps Lock acts as a function key. */
121 Lisp_Object Vw32_enable_caps_lock;
122
123 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
124 Lisp_Object Vw32_scroll_lock_modifier;
125
126 /* Switch to control whether we inhibit requests for synthesized bold
127 and italic versions of fonts. */
128 Lisp_Object Vw32_enable_synthesized_fonts;
129
130 /* Enable palette management. */
131 Lisp_Object Vw32_enable_palette;
132
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;
136
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;
140
141 /* The name we're using in resource queries. */
142 Lisp_Object Vx_resource_name;
143
144 /* Non nil if no window manager is in use. */
145 Lisp_Object Vx_no_window_manager;
146
147 /* Non-zero means we're allowed to display a hourglass pointer. */
148
149 int display_hourglass_p;
150
151 /* The background and shape of the mouse pointer, and shape when not
152 over text or in the modeline. */
153
154 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
155 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
156
157 /* The shape when over mouse-sensitive text. */
158
159 Lisp_Object Vx_sensitive_text_pointer_shape;
160
161 /* Color of chars displayed in cursor box. */
162
163 Lisp_Object Vx_cursor_fore_pixel;
164
165 /* Nonzero if using Windows. */
166
167 static int w32_in_use;
168
169 /* Search path for bitmap files. */
170
171 Lisp_Object Vx_bitmap_file_path;
172
173 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
174
175 Lisp_Object Vx_pixel_size_width_font_regexp;
176
177 /* Alist of bdf fonts and the files that define them. */
178 Lisp_Object Vw32_bdf_filename_alist;
179
180 Lisp_Object Vw32_system_coding_system;
181
182 /* A flag to control whether fonts are matched strictly or not. */
183 int w32_strict_fontnames;
184
185 /* A flag to control whether we should only repaint if GetUpdateRect
186 indicates there is an update region. */
187 int w32_strict_painting;
188
189 /* Associative list linking character set strings to Windows codepages. */
190 Lisp_Object Vw32_charset_info_alist;
191
192 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
193 #ifndef VIETNAMESE_CHARSET
194 #define VIETNAMESE_CHARSET 163
195 #endif
196
197 Lisp_Object Qauto_raise;
198 Lisp_Object Qauto_lower;
199 Lisp_Object Qbar;
200 Lisp_Object Qborder_color;
201 Lisp_Object Qborder_width;
202 Lisp_Object Qbox;
203 Lisp_Object Qcursor_color;
204 Lisp_Object Qcursor_type;
205 Lisp_Object Qgeometry;
206 Lisp_Object Qicon_left;
207 Lisp_Object Qicon_top;
208 Lisp_Object Qicon_type;
209 Lisp_Object Qicon_name;
210 Lisp_Object Qinternal_border_width;
211 Lisp_Object Qleft;
212 Lisp_Object Qright;
213 Lisp_Object Qmouse_color;
214 Lisp_Object Qnone;
215 Lisp_Object Qparent_id;
216 Lisp_Object Qscroll_bar_width;
217 Lisp_Object Qsuppress_icon;
218 Lisp_Object Qundefined_color;
219 Lisp_Object Qvertical_scroll_bars;
220 Lisp_Object Qvisibility;
221 Lisp_Object Qwindow_id;
222 Lisp_Object Qx_frame_parameter;
223 Lisp_Object Qx_resource_name;
224 Lisp_Object Quser_position;
225 Lisp_Object Quser_size;
226 Lisp_Object Qscreen_gamma;
227 Lisp_Object Qline_spacing;
228 Lisp_Object Qcenter;
229 Lisp_Object Qcancel_timer;
230 Lisp_Object Qhyper;
231 Lisp_Object Qsuper;
232 Lisp_Object Qmeta;
233 Lisp_Object Qalt;
234 Lisp_Object Qctrl;
235 Lisp_Object Qcontrol;
236 Lisp_Object Qshift;
237
238 Lisp_Object Qw32_charset_ansi;
239 Lisp_Object Qw32_charset_default;
240 Lisp_Object Qw32_charset_symbol;
241 Lisp_Object Qw32_charset_shiftjis;
242 Lisp_Object Qw32_charset_hangeul;
243 Lisp_Object Qw32_charset_gb2312;
244 Lisp_Object Qw32_charset_chinesebig5;
245 Lisp_Object Qw32_charset_oem;
246
247 #ifndef JOHAB_CHARSET
248 #define JOHAB_CHARSET 130
249 #endif
250 #ifdef JOHAB_CHARSET
251 Lisp_Object Qw32_charset_easteurope;
252 Lisp_Object Qw32_charset_turkish;
253 Lisp_Object Qw32_charset_baltic;
254 Lisp_Object Qw32_charset_russian;
255 Lisp_Object Qw32_charset_arabic;
256 Lisp_Object Qw32_charset_greek;
257 Lisp_Object Qw32_charset_hebrew;
258 Lisp_Object Qw32_charset_vietnamese;
259 Lisp_Object Qw32_charset_thai;
260 Lisp_Object Qw32_charset_johab;
261 Lisp_Object Qw32_charset_mac;
262 #endif
263
264 #ifdef UNICODE_CHARSET
265 Lisp_Object Qw32_charset_unicode;
266 #endif
267
268 extern Lisp_Object Qtop;
269 extern Lisp_Object Qdisplay;
270 extern Lisp_Object Qtool_bar_lines;
271
272 /* State variables for emulating a three button mouse. */
273 #define LMOUSE 1
274 #define MMOUSE 2
275 #define RMOUSE 4
276
277 static int button_state = 0;
278 static W32Msg saved_mouse_button_msg;
279 static unsigned mouse_button_timer; /* non-zero when timer is active */
280 static W32Msg saved_mouse_move_msg;
281 static unsigned mouse_move_timer;
282
283 /* W95 mousewheel handler */
284 unsigned int msh_mousewheel = 0;
285
286 #define MOUSE_BUTTON_ID 1
287 #define MOUSE_MOVE_ID 2
288
289 /* The below are defined in frame.c. */
290
291 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
292 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
293 extern Lisp_Object Qtool_bar_lines;
294
295 extern Lisp_Object Vwindow_system_version;
296
297 Lisp_Object Qface_set_after_frame_default;
298
299 #ifdef GLYPH_DEBUG
300 int image_cache_refcount, dpyinfo_refcount;
301 #endif
302
303
304 /* From w32term.c. */
305 extern Lisp_Object Vw32_num_mouse_buttons;
306 extern Lisp_Object Vw32_recognize_altgr;
307
308 extern HWND w32_system_caret_hwnd;
309 extern int w32_system_caret_width;
310 extern int w32_system_caret_height;
311 extern int w32_system_caret_x;
312 extern int w32_system_caret_y;
313
314 \f
315 /* Error if we are not connected to MS-Windows. */
316 void
317 check_w32 ()
318 {
319 if (! w32_in_use)
320 error ("MS-Windows not in use or not initialized");
321 }
322
323 /* Nonzero if we can use mouse menus.
324 You should not call this unless HAVE_MENUS is defined. */
325
326 int
327 have_menus_p ()
328 {
329 return w32_in_use;
330 }
331
332 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
333 and checking validity for W32. */
334
335 FRAME_PTR
336 check_x_frame (frame)
337 Lisp_Object frame;
338 {
339 FRAME_PTR f;
340
341 if (NILP (frame))
342 frame = selected_frame;
343 CHECK_LIVE_FRAME (frame);
344 f = XFRAME (frame);
345 if (! FRAME_W32_P (f))
346 error ("non-w32 frame used");
347 return f;
348 }
349
350 /* Let the user specify an display with a frame.
351 nil stands for the selected frame--or, if that is not a w32 frame,
352 the first display on the list. */
353
354 static struct w32_display_info *
355 check_x_display_info (frame)
356 Lisp_Object frame;
357 {
358 if (NILP (frame))
359 {
360 struct frame *sf = XFRAME (selected_frame);
361
362 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
363 return FRAME_W32_DISPLAY_INFO (sf);
364 else
365 return &one_w32_display_info;
366 }
367 else if (STRINGP (frame))
368 return x_display_info_for_name (frame);
369 else
370 {
371 FRAME_PTR f;
372
373 CHECK_LIVE_FRAME (frame);
374 f = XFRAME (frame);
375 if (! FRAME_W32_P (f))
376 error ("non-w32 frame used");
377 return FRAME_W32_DISPLAY_INFO (f);
378 }
379 }
380 \f
381 /* Return the Emacs frame-object corresponding to an w32 window.
382 It could be the frame's main window or an icon window. */
383
384 /* This function can be called during GC, so use GC_xxx type test macros. */
385
386 struct frame *
387 x_window_to_frame (dpyinfo, wdesc)
388 struct w32_display_info *dpyinfo;
389 HWND wdesc;
390 {
391 Lisp_Object tail, frame;
392 struct frame *f;
393
394 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
395 {
396 frame = XCAR (tail);
397 if (!GC_FRAMEP (frame))
398 continue;
399 f = XFRAME (frame);
400 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
401 continue;
402 if (f->output_data.w32->hourglass_window == wdesc)
403 return f;
404
405 /* TODO: Check tooltips when supported. */
406 if (FRAME_W32_WINDOW (f) == wdesc)
407 return f;
408 }
409 return 0;
410 }
411
412 \f
413
414 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
415 id, which is just an int that this section returns. Bitmaps are
416 reference counted so they can be shared among frames.
417
418 Bitmap indices are guaranteed to be > 0, so a negative number can
419 be used to indicate no bitmap.
420
421 If you use x_create_bitmap_from_data, then you must keep track of
422 the bitmaps yourself. That is, creating a bitmap from the same
423 data more than once will not be caught. */
424
425
426 /* Functions to access the contents of a bitmap, given an id. */
427
428 int
429 x_bitmap_height (f, id)
430 FRAME_PTR f;
431 int id;
432 {
433 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
434 }
435
436 int
437 x_bitmap_width (f, id)
438 FRAME_PTR f;
439 int id;
440 {
441 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
442 }
443
444 int
445 x_bitmap_pixmap (f, id)
446 FRAME_PTR f;
447 int id;
448 {
449 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
450 }
451
452
453 /* Allocate a new bitmap record. Returns index of new record. */
454
455 static int
456 x_allocate_bitmap_record (f)
457 FRAME_PTR f;
458 {
459 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
460 int i;
461
462 if (dpyinfo->bitmaps == NULL)
463 {
464 dpyinfo->bitmaps_size = 10;
465 dpyinfo->bitmaps
466 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
467 dpyinfo->bitmaps_last = 1;
468 return 1;
469 }
470
471 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
472 return ++dpyinfo->bitmaps_last;
473
474 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
475 if (dpyinfo->bitmaps[i].refcount == 0)
476 return i + 1;
477
478 dpyinfo->bitmaps_size *= 2;
479 dpyinfo->bitmaps
480 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
481 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
482 return ++dpyinfo->bitmaps_last;
483 }
484
485 /* Add one reference to the reference count of the bitmap with id ID. */
486
487 void
488 x_reference_bitmap (f, id)
489 FRAME_PTR f;
490 int id;
491 {
492 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
493 }
494
495 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
496
497 int
498 x_create_bitmap_from_data (f, bits, width, height)
499 struct frame *f;
500 char *bits;
501 unsigned int width, height;
502 {
503 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
504 Pixmap bitmap;
505 int id;
506
507 bitmap = CreateBitmap (width, height,
508 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
509 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
510 bits);
511
512 if (! bitmap)
513 return -1;
514
515 id = x_allocate_bitmap_record (f);
516 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
517 dpyinfo->bitmaps[id - 1].file = NULL;
518 dpyinfo->bitmaps[id - 1].hinst = NULL;
519 dpyinfo->bitmaps[id - 1].refcount = 1;
520 dpyinfo->bitmaps[id - 1].depth = 1;
521 dpyinfo->bitmaps[id - 1].height = height;
522 dpyinfo->bitmaps[id - 1].width = width;
523
524 return id;
525 }
526
527 /* Create bitmap from file FILE for frame F. */
528
529 int
530 x_create_bitmap_from_file (f, file)
531 struct frame *f;
532 Lisp_Object file;
533 {
534 return -1;
535 #if 0 /* TODO : bitmap support */
536 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
537 unsigned int width, height;
538 HBITMAP bitmap;
539 int xhot, yhot, result, id;
540 Lisp_Object found;
541 int fd;
542 char *filename;
543 HINSTANCE hinst;
544
545 /* Look for an existing bitmap with the same name. */
546 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
547 {
548 if (dpyinfo->bitmaps[id].refcount
549 && dpyinfo->bitmaps[id].file
550 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
551 {
552 ++dpyinfo->bitmaps[id].refcount;
553 return id + 1;
554 }
555 }
556
557 /* Search bitmap-file-path for the file, if appropriate. */
558 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
559 if (fd < 0)
560 return -1;
561 emacs_close (fd);
562
563 filename = (char *) XSTRING (found)->data;
564
565 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
566
567 if (hinst == NULL)
568 return -1;
569
570
571 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
572 filename, &width, &height, &bitmap, &xhot, &yhot);
573 if (result != BitmapSuccess)
574 return -1;
575
576 id = x_allocate_bitmap_record (f);
577 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
578 dpyinfo->bitmaps[id - 1].refcount = 1;
579 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
580 dpyinfo->bitmaps[id - 1].depth = 1;
581 dpyinfo->bitmaps[id - 1].height = height;
582 dpyinfo->bitmaps[id - 1].width = width;
583 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
584
585 return id;
586 #endif /* TODO */
587 }
588
589 /* Remove reference to bitmap with id number ID. */
590
591 void
592 x_destroy_bitmap (f, id)
593 FRAME_PTR f;
594 int id;
595 {
596 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
597
598 if (id > 0)
599 {
600 --dpyinfo->bitmaps[id - 1].refcount;
601 if (dpyinfo->bitmaps[id - 1].refcount == 0)
602 {
603 BLOCK_INPUT;
604 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
605 if (dpyinfo->bitmaps[id - 1].file)
606 {
607 xfree (dpyinfo->bitmaps[id - 1].file);
608 dpyinfo->bitmaps[id - 1].file = NULL;
609 }
610 UNBLOCK_INPUT;
611 }
612 }
613 }
614
615 /* Free all the bitmaps for the display specified by DPYINFO. */
616
617 static void
618 x_destroy_all_bitmaps (dpyinfo)
619 struct w32_display_info *dpyinfo;
620 {
621 int i;
622 for (i = 0; i < dpyinfo->bitmaps_last; i++)
623 if (dpyinfo->bitmaps[i].refcount > 0)
624 {
625 DeleteObject (dpyinfo->bitmaps[i].pixmap);
626 if (dpyinfo->bitmaps[i].file)
627 xfree (dpyinfo->bitmaps[i].file);
628 }
629 dpyinfo->bitmaps_last = 0;
630 }
631 \f
632 /* Connect the frame-parameter names for W32 frames
633 to the ways of passing the parameter values to the window system.
634
635 The name of a parameter, as a Lisp symbol,
636 has an `x-frame-parameter' property which is an integer in Lisp
637 but can be interpreted as an `enum x_frame_parm' in C. */
638
639 enum x_frame_parm
640 {
641 X_PARM_FOREGROUND_COLOR,
642 X_PARM_BACKGROUND_COLOR,
643 X_PARM_MOUSE_COLOR,
644 X_PARM_CURSOR_COLOR,
645 X_PARM_BORDER_COLOR,
646 X_PARM_ICON_TYPE,
647 X_PARM_FONT,
648 X_PARM_BORDER_WIDTH,
649 X_PARM_INTERNAL_BORDER_WIDTH,
650 X_PARM_NAME,
651 X_PARM_AUTORAISE,
652 X_PARM_AUTOLOWER,
653 X_PARM_VERT_SCROLL_BAR,
654 X_PARM_VISIBILITY,
655 X_PARM_MENU_BAR_LINES
656 };
657
658
659 struct x_frame_parm_table
660 {
661 char *name;
662 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
663 };
664
665 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
666 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
667 static void x_change_window_heights P_ ((Lisp_Object, int));
668 /* TODO: Native Input Method support; see x_create_im. */
669 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
670 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
671 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
672 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
673 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
674 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
675 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
676 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
677 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
678 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
679 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
680 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
681 Lisp_Object));
682 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
683 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
684 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
685 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
686 Lisp_Object));
687 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
688 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
689 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
690 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
691 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
692 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
693 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
694 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
695 Lisp_Object));
696
697 static struct x_frame_parm_table x_frame_parms[] =
698 {
699 "auto-raise", x_set_autoraise,
700 "auto-lower", x_set_autolower,
701 "background-color", x_set_background_color,
702 "border-color", x_set_border_color,
703 "border-width", x_set_border_width,
704 "cursor-color", x_set_cursor_color,
705 "cursor-type", x_set_cursor_type,
706 "font", x_set_font,
707 "foreground-color", x_set_foreground_color,
708 "icon-name", x_set_icon_name,
709 "icon-type", x_set_icon_type,
710 "internal-border-width", x_set_internal_border_width,
711 "menu-bar-lines", x_set_menu_bar_lines,
712 "mouse-color", x_set_mouse_color,
713 "name", x_explicitly_set_name,
714 "scroll-bar-width", x_set_scroll_bar_width,
715 "title", x_set_title,
716 "unsplittable", x_set_unsplittable,
717 "vertical-scroll-bars", x_set_vertical_scroll_bars,
718 "visibility", x_set_visibility,
719 "tool-bar-lines", x_set_tool_bar_lines,
720 "screen-gamma", x_set_screen_gamma,
721 "line-spacing", x_set_line_spacing
722 };
723
724 /* Attach the `x-frame-parameter' properties to
725 the Lisp symbol names of parameters relevant to W32. */
726
727 void
728 init_x_parm_symbols ()
729 {
730 int i;
731
732 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
733 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
734 make_number (i));
735 }
736 \f
737 /* Change the parameters of frame F as specified by ALIST.
738 If a parameter is not specially recognized, do nothing;
739 otherwise call the `x_set_...' function for that parameter. */
740
741 void
742 x_set_frame_parameters (f, alist)
743 FRAME_PTR f;
744 Lisp_Object alist;
745 {
746 Lisp_Object tail;
747
748 /* If both of these parameters are present, it's more efficient to
749 set them both at once. So we wait until we've looked at the
750 entire list before we set them. */
751 int width, height;
752
753 /* Same here. */
754 Lisp_Object left, top;
755
756 /* Same with these. */
757 Lisp_Object icon_left, icon_top;
758
759 /* Record in these vectors all the parms specified. */
760 Lisp_Object *parms;
761 Lisp_Object *values;
762 int i, p;
763 int left_no_change = 0, top_no_change = 0;
764 int icon_left_no_change = 0, icon_top_no_change = 0;
765
766 struct gcpro gcpro1, gcpro2;
767
768 i = 0;
769 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
770 i++;
771
772 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
773 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
774
775 /* Extract parm names and values into those vectors. */
776
777 i = 0;
778 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
779 {
780 Lisp_Object elt;
781
782 elt = Fcar (tail);
783 parms[i] = Fcar (elt);
784 values[i] = Fcdr (elt);
785 i++;
786 }
787 /* TAIL and ALIST are not used again below here. */
788 alist = tail = Qnil;
789
790 GCPRO2 (*parms, *values);
791 gcpro1.nvars = i;
792 gcpro2.nvars = i;
793
794 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
795 because their values appear in VALUES and strings are not valid. */
796 top = left = Qunbound;
797 icon_left = icon_top = Qunbound;
798
799 /* Provide default values for HEIGHT and WIDTH. */
800 if (FRAME_NEW_WIDTH (f))
801 width = FRAME_NEW_WIDTH (f);
802 else
803 width = FRAME_WIDTH (f);
804
805 if (FRAME_NEW_HEIGHT (f))
806 height = FRAME_NEW_HEIGHT (f);
807 else
808 height = FRAME_HEIGHT (f);
809
810 /* Process foreground_color and background_color before anything else.
811 They are independent of other properties, but other properties (e.g.,
812 cursor_color) are dependent upon them. */
813 for (p = 0; p < i; p++)
814 {
815 Lisp_Object prop, val;
816
817 prop = parms[p];
818 val = values[p];
819 if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
820 {
821 register Lisp_Object param_index, old_value;
822
823 param_index = Fget (prop, Qx_frame_parameter);
824 old_value = get_frame_param (f, prop);
825 store_frame_param (f, prop, val);
826 if (NATNUMP (param_index)
827 && (XFASTINT (param_index)
828 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
829 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
830 }
831 }
832
833 /* Now process them in reverse of specified order. */
834 for (i--; i >= 0; i--)
835 {
836 Lisp_Object prop, val;
837
838 prop = parms[i];
839 val = values[i];
840
841 if (EQ (prop, Qwidth) && NUMBERP (val))
842 width = XFASTINT (val);
843 else if (EQ (prop, Qheight) && NUMBERP (val))
844 height = XFASTINT (val);
845 else if (EQ (prop, Qtop))
846 top = val;
847 else if (EQ (prop, Qleft))
848 left = val;
849 else if (EQ (prop, Qicon_top))
850 icon_top = val;
851 else if (EQ (prop, Qicon_left))
852 icon_left = val;
853 else if (EQ (prop, Qforeground_color) || EQ (prop, Qbackground_color))
854 /* Processed above. */
855 continue;
856 else
857 {
858 register Lisp_Object param_index, old_value;
859
860 param_index = Fget (prop, Qx_frame_parameter);
861 old_value = get_frame_param (f, prop);
862 store_frame_param (f, prop, val);
863 if (NATNUMP (param_index)
864 && (XFASTINT (param_index)
865 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
866 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
867 }
868 }
869
870 /* Don't die if just one of these was set. */
871 if (EQ (left, Qunbound))
872 {
873 left_no_change = 1;
874 if (f->output_data.w32->left_pos < 0)
875 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
876 else
877 XSETINT (left, f->output_data.w32->left_pos);
878 }
879 if (EQ (top, Qunbound))
880 {
881 top_no_change = 1;
882 if (f->output_data.w32->top_pos < 0)
883 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
884 else
885 XSETINT (top, f->output_data.w32->top_pos);
886 }
887
888 /* If one of the icon positions was not set, preserve or default it. */
889 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
890 {
891 icon_left_no_change = 1;
892 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
893 if (NILP (icon_left))
894 XSETINT (icon_left, 0);
895 }
896 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
897 {
898 icon_top_no_change = 1;
899 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
900 if (NILP (icon_top))
901 XSETINT (icon_top, 0);
902 }
903
904 /* Don't set these parameters unless they've been explicitly
905 specified. The window might be mapped or resized while we're in
906 this function, and we don't want to override that unless the lisp
907 code has asked for it.
908
909 Don't set these parameters unless they actually differ from the
910 window's current parameters; the window may not actually exist
911 yet. */
912 {
913 Lisp_Object frame;
914
915 check_frame_size (f, &height, &width);
916
917 XSETFRAME (frame, f);
918
919 if (width != FRAME_WIDTH (f)
920 || height != FRAME_HEIGHT (f)
921 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
922 Fset_frame_size (frame, make_number (width), make_number (height));
923
924 if ((!NILP (left) || !NILP (top))
925 && ! (left_no_change && top_no_change)
926 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
927 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
928 {
929 int leftpos = 0;
930 int toppos = 0;
931
932 /* Record the signs. */
933 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
934 if (EQ (left, Qminus))
935 f->output_data.w32->size_hint_flags |= XNegative;
936 else if (INTEGERP (left))
937 {
938 leftpos = XINT (left);
939 if (leftpos < 0)
940 f->output_data.w32->size_hint_flags |= XNegative;
941 }
942 else if (CONSP (left) && EQ (XCAR (left), Qminus)
943 && CONSP (XCDR (left))
944 && INTEGERP (XCAR (XCDR (left))))
945 {
946 leftpos = - XINT (XCAR (XCDR (left)));
947 f->output_data.w32->size_hint_flags |= XNegative;
948 }
949 else if (CONSP (left) && EQ (XCAR (left), Qplus)
950 && CONSP (XCDR (left))
951 && INTEGERP (XCAR (XCDR (left))))
952 {
953 leftpos = XINT (XCAR (XCDR (left)));
954 }
955
956 if (EQ (top, Qminus))
957 f->output_data.w32->size_hint_flags |= YNegative;
958 else if (INTEGERP (top))
959 {
960 toppos = XINT (top);
961 if (toppos < 0)
962 f->output_data.w32->size_hint_flags |= YNegative;
963 }
964 else if (CONSP (top) && EQ (XCAR (top), Qminus)
965 && CONSP (XCDR (top))
966 && INTEGERP (XCAR (XCDR (top))))
967 {
968 toppos = - XINT (XCAR (XCDR (top)));
969 f->output_data.w32->size_hint_flags |= YNegative;
970 }
971 else if (CONSP (top) && EQ (XCAR (top), Qplus)
972 && CONSP (XCDR (top))
973 && INTEGERP (XCAR (XCDR (top))))
974 {
975 toppos = XINT (XCAR (XCDR (top)));
976 }
977
978
979 /* Store the numeric value of the position. */
980 f->output_data.w32->top_pos = toppos;
981 f->output_data.w32->left_pos = leftpos;
982
983 f->output_data.w32->win_gravity = NorthWestGravity;
984
985 /* Actually set that position, and convert to absolute. */
986 x_set_offset (f, leftpos, toppos, -1);
987 }
988
989 if ((!NILP (icon_left) || !NILP (icon_top))
990 && ! (icon_left_no_change && icon_top_no_change))
991 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
992 }
993
994 UNGCPRO;
995 }
996
997 /* Store the screen positions of frame F into XPTR and YPTR.
998 These are the positions of the containing window manager window,
999 not Emacs's own window. */
1000
1001 void
1002 x_real_positions (f, xptr, yptr)
1003 FRAME_PTR f;
1004 int *xptr, *yptr;
1005 {
1006 POINT pt;
1007
1008 {
1009 RECT rect;
1010
1011 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1012 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1013
1014 pt.x = rect.left;
1015 pt.y = rect.top;
1016 }
1017
1018 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1019
1020 *xptr = pt.x;
1021 *yptr = pt.y;
1022 }
1023
1024 /* Insert a description of internally-recorded parameters of frame X
1025 into the parameter alist *ALISTPTR that is to be given to the user.
1026 Only parameters that are specific to W32
1027 and whose values are not correctly recorded in the frame's
1028 param_alist need to be considered here. */
1029
1030 void
1031 x_report_frame_params (f, alistptr)
1032 struct frame *f;
1033 Lisp_Object *alistptr;
1034 {
1035 char buf[16];
1036 Lisp_Object tem;
1037
1038 /* Represent negative positions (off the top or left screen edge)
1039 in a way that Fmodify_frame_parameters will understand correctly. */
1040 XSETINT (tem, f->output_data.w32->left_pos);
1041 if (f->output_data.w32->left_pos >= 0)
1042 store_in_alist (alistptr, Qleft, tem);
1043 else
1044 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1045
1046 XSETINT (tem, f->output_data.w32->top_pos);
1047 if (f->output_data.w32->top_pos >= 0)
1048 store_in_alist (alistptr, Qtop, tem);
1049 else
1050 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1051
1052 store_in_alist (alistptr, Qborder_width,
1053 make_number (f->output_data.w32->border_width));
1054 store_in_alist (alistptr, Qinternal_border_width,
1055 make_number (f->output_data.w32->internal_border_width));
1056 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1057 store_in_alist (alistptr, Qwindow_id,
1058 build_string (buf));
1059 store_in_alist (alistptr, Qicon_name, f->icon_name);
1060 FRAME_SAMPLE_VISIBILITY (f);
1061 store_in_alist (alistptr, Qvisibility,
1062 (FRAME_VISIBLE_P (f) ? Qt
1063 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1064 store_in_alist (alistptr, Qdisplay,
1065 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1066 }
1067 \f
1068
1069 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1070 Sw32_define_rgb_color, 4, 4, 0,
1071 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1072 This adds or updates a named color to w32-color-map, making it
1073 available for use. The original entry's RGB ref is returned, or nil
1074 if the entry is new. */)
1075 (red, green, blue, name)
1076 Lisp_Object red, green, blue, name;
1077 {
1078 Lisp_Object rgb;
1079 Lisp_Object oldrgb = Qnil;
1080 Lisp_Object entry;
1081
1082 CHECK_NUMBER (red);
1083 CHECK_NUMBER (green);
1084 CHECK_NUMBER (blue);
1085 CHECK_STRING (name);
1086
1087 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1088
1089 BLOCK_INPUT;
1090
1091 /* replace existing entry in w32-color-map or add new entry. */
1092 entry = Fassoc (name, Vw32_color_map);
1093 if (NILP (entry))
1094 {
1095 entry = Fcons (name, rgb);
1096 Vw32_color_map = Fcons (entry, Vw32_color_map);
1097 }
1098 else
1099 {
1100 oldrgb = Fcdr (entry);
1101 Fsetcdr (entry, rgb);
1102 }
1103
1104 UNBLOCK_INPUT;
1105
1106 return (oldrgb);
1107 }
1108
1109 DEFUN ("w32-load-color-file", Fw32_load_color_file,
1110 Sw32_load_color_file, 1, 1, 0,
1111 doc: /* Create an alist of color entries from an external file.
1112 Assign this value to w32-color-map to replace the existing color map.
1113
1114 The file should define one named RGB color per line like so:
1115 R G B name
1116 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
1117 (filename)
1118 Lisp_Object filename;
1119 {
1120 FILE *fp;
1121 Lisp_Object cmap = Qnil;
1122 Lisp_Object abspath;
1123
1124 CHECK_STRING (filename);
1125 abspath = Fexpand_file_name (filename, Qnil);
1126
1127 fp = fopen (XSTRING (filename)->data, "rt");
1128 if (fp)
1129 {
1130 char buf[512];
1131 int red, green, blue;
1132 int num;
1133
1134 BLOCK_INPUT;
1135
1136 while (fgets (buf, sizeof (buf), fp) != NULL) {
1137 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1138 {
1139 char *name = buf + num;
1140 num = strlen (name) - 1;
1141 if (name[num] == '\n')
1142 name[num] = 0;
1143 cmap = Fcons (Fcons (build_string (name),
1144 make_number (RGB (red, green, blue))),
1145 cmap);
1146 }
1147 }
1148 fclose (fp);
1149
1150 UNBLOCK_INPUT;
1151 }
1152
1153 return cmap;
1154 }
1155
1156 /* The default colors for the w32 color map */
1157 typedef struct colormap_t
1158 {
1159 char *name;
1160 COLORREF colorref;
1161 } colormap_t;
1162
1163 colormap_t w32_color_map[] =
1164 {
1165 {"snow" , PALETTERGB (255,250,250)},
1166 {"ghost white" , PALETTERGB (248,248,255)},
1167 {"GhostWhite" , PALETTERGB (248,248,255)},
1168 {"white smoke" , PALETTERGB (245,245,245)},
1169 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1170 {"gainsboro" , PALETTERGB (220,220,220)},
1171 {"floral white" , PALETTERGB (255,250,240)},
1172 {"FloralWhite" , PALETTERGB (255,250,240)},
1173 {"old lace" , PALETTERGB (253,245,230)},
1174 {"OldLace" , PALETTERGB (253,245,230)},
1175 {"linen" , PALETTERGB (250,240,230)},
1176 {"antique white" , PALETTERGB (250,235,215)},
1177 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1178 {"papaya whip" , PALETTERGB (255,239,213)},
1179 {"PapayaWhip" , PALETTERGB (255,239,213)},
1180 {"blanched almond" , PALETTERGB (255,235,205)},
1181 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1182 {"bisque" , PALETTERGB (255,228,196)},
1183 {"peach puff" , PALETTERGB (255,218,185)},
1184 {"PeachPuff" , PALETTERGB (255,218,185)},
1185 {"navajo white" , PALETTERGB (255,222,173)},
1186 {"NavajoWhite" , PALETTERGB (255,222,173)},
1187 {"moccasin" , PALETTERGB (255,228,181)},
1188 {"cornsilk" , PALETTERGB (255,248,220)},
1189 {"ivory" , PALETTERGB (255,255,240)},
1190 {"lemon chiffon" , PALETTERGB (255,250,205)},
1191 {"LemonChiffon" , PALETTERGB (255,250,205)},
1192 {"seashell" , PALETTERGB (255,245,238)},
1193 {"honeydew" , PALETTERGB (240,255,240)},
1194 {"mint cream" , PALETTERGB (245,255,250)},
1195 {"MintCream" , PALETTERGB (245,255,250)},
1196 {"azure" , PALETTERGB (240,255,255)},
1197 {"alice blue" , PALETTERGB (240,248,255)},
1198 {"AliceBlue" , PALETTERGB (240,248,255)},
1199 {"lavender" , PALETTERGB (230,230,250)},
1200 {"lavender blush" , PALETTERGB (255,240,245)},
1201 {"LavenderBlush" , PALETTERGB (255,240,245)},
1202 {"misty rose" , PALETTERGB (255,228,225)},
1203 {"MistyRose" , PALETTERGB (255,228,225)},
1204 {"white" , PALETTERGB (255,255,255)},
1205 {"black" , PALETTERGB ( 0, 0, 0)},
1206 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1207 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1208 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1209 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1210 {"dim gray" , PALETTERGB (105,105,105)},
1211 {"DimGray" , PALETTERGB (105,105,105)},
1212 {"dim grey" , PALETTERGB (105,105,105)},
1213 {"DimGrey" , PALETTERGB (105,105,105)},
1214 {"slate gray" , PALETTERGB (112,128,144)},
1215 {"SlateGray" , PALETTERGB (112,128,144)},
1216 {"slate grey" , PALETTERGB (112,128,144)},
1217 {"SlateGrey" , PALETTERGB (112,128,144)},
1218 {"light slate gray" , PALETTERGB (119,136,153)},
1219 {"LightSlateGray" , PALETTERGB (119,136,153)},
1220 {"light slate grey" , PALETTERGB (119,136,153)},
1221 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1222 {"gray" , PALETTERGB (190,190,190)},
1223 {"grey" , PALETTERGB (190,190,190)},
1224 {"light grey" , PALETTERGB (211,211,211)},
1225 {"LightGrey" , PALETTERGB (211,211,211)},
1226 {"light gray" , PALETTERGB (211,211,211)},
1227 {"LightGray" , PALETTERGB (211,211,211)},
1228 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1229 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1230 {"navy" , PALETTERGB ( 0, 0,128)},
1231 {"navy blue" , PALETTERGB ( 0, 0,128)},
1232 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1233 {"cornflower blue" , PALETTERGB (100,149,237)},
1234 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1235 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1236 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1237 {"slate blue" , PALETTERGB (106, 90,205)},
1238 {"SlateBlue" , PALETTERGB (106, 90,205)},
1239 {"medium slate blue" , PALETTERGB (123,104,238)},
1240 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1241 {"light slate blue" , PALETTERGB (132,112,255)},
1242 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1243 {"medium blue" , PALETTERGB ( 0, 0,205)},
1244 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1245 {"royal blue" , PALETTERGB ( 65,105,225)},
1246 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1247 {"blue" , PALETTERGB ( 0, 0,255)},
1248 {"dodger blue" , PALETTERGB ( 30,144,255)},
1249 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1250 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1251 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1252 {"sky blue" , PALETTERGB (135,206,235)},
1253 {"SkyBlue" , PALETTERGB (135,206,235)},
1254 {"light sky blue" , PALETTERGB (135,206,250)},
1255 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1256 {"steel blue" , PALETTERGB ( 70,130,180)},
1257 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1258 {"light steel blue" , PALETTERGB (176,196,222)},
1259 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1260 {"light blue" , PALETTERGB (173,216,230)},
1261 {"LightBlue" , PALETTERGB (173,216,230)},
1262 {"powder blue" , PALETTERGB (176,224,230)},
1263 {"PowderBlue" , PALETTERGB (176,224,230)},
1264 {"pale turquoise" , PALETTERGB (175,238,238)},
1265 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1266 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1267 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1268 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1269 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1270 {"turquoise" , PALETTERGB ( 64,224,208)},
1271 {"cyan" , PALETTERGB ( 0,255,255)},
1272 {"light cyan" , PALETTERGB (224,255,255)},
1273 {"LightCyan" , PALETTERGB (224,255,255)},
1274 {"cadet blue" , PALETTERGB ( 95,158,160)},
1275 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1276 {"medium aquamarine" , PALETTERGB (102,205,170)},
1277 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1278 {"aquamarine" , PALETTERGB (127,255,212)},
1279 {"dark green" , PALETTERGB ( 0,100, 0)},
1280 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1281 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1282 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1283 {"dark sea green" , PALETTERGB (143,188,143)},
1284 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1285 {"sea green" , PALETTERGB ( 46,139, 87)},
1286 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1287 {"medium sea green" , PALETTERGB ( 60,179,113)},
1288 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1289 {"light sea green" , PALETTERGB ( 32,178,170)},
1290 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1291 {"pale green" , PALETTERGB (152,251,152)},
1292 {"PaleGreen" , PALETTERGB (152,251,152)},
1293 {"spring green" , PALETTERGB ( 0,255,127)},
1294 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1295 {"lawn green" , PALETTERGB (124,252, 0)},
1296 {"LawnGreen" , PALETTERGB (124,252, 0)},
1297 {"green" , PALETTERGB ( 0,255, 0)},
1298 {"chartreuse" , PALETTERGB (127,255, 0)},
1299 {"medium spring green" , PALETTERGB ( 0,250,154)},
1300 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1301 {"green yellow" , PALETTERGB (173,255, 47)},
1302 {"GreenYellow" , PALETTERGB (173,255, 47)},
1303 {"lime green" , PALETTERGB ( 50,205, 50)},
1304 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1305 {"yellow green" , PALETTERGB (154,205, 50)},
1306 {"YellowGreen" , PALETTERGB (154,205, 50)},
1307 {"forest green" , PALETTERGB ( 34,139, 34)},
1308 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1309 {"olive drab" , PALETTERGB (107,142, 35)},
1310 {"OliveDrab" , PALETTERGB (107,142, 35)},
1311 {"dark khaki" , PALETTERGB (189,183,107)},
1312 {"DarkKhaki" , PALETTERGB (189,183,107)},
1313 {"khaki" , PALETTERGB (240,230,140)},
1314 {"pale goldenrod" , PALETTERGB (238,232,170)},
1315 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1316 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1317 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1318 {"light yellow" , PALETTERGB (255,255,224)},
1319 {"LightYellow" , PALETTERGB (255,255,224)},
1320 {"yellow" , PALETTERGB (255,255, 0)},
1321 {"gold" , PALETTERGB (255,215, 0)},
1322 {"light goldenrod" , PALETTERGB (238,221,130)},
1323 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1324 {"goldenrod" , PALETTERGB (218,165, 32)},
1325 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1326 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1327 {"rosy brown" , PALETTERGB (188,143,143)},
1328 {"RosyBrown" , PALETTERGB (188,143,143)},
1329 {"indian red" , PALETTERGB (205, 92, 92)},
1330 {"IndianRed" , PALETTERGB (205, 92, 92)},
1331 {"saddle brown" , PALETTERGB (139, 69, 19)},
1332 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1333 {"sienna" , PALETTERGB (160, 82, 45)},
1334 {"peru" , PALETTERGB (205,133, 63)},
1335 {"burlywood" , PALETTERGB (222,184,135)},
1336 {"beige" , PALETTERGB (245,245,220)},
1337 {"wheat" , PALETTERGB (245,222,179)},
1338 {"sandy brown" , PALETTERGB (244,164, 96)},
1339 {"SandyBrown" , PALETTERGB (244,164, 96)},
1340 {"tan" , PALETTERGB (210,180,140)},
1341 {"chocolate" , PALETTERGB (210,105, 30)},
1342 {"firebrick" , PALETTERGB (178,34, 34)},
1343 {"brown" , PALETTERGB (165,42, 42)},
1344 {"dark salmon" , PALETTERGB (233,150,122)},
1345 {"DarkSalmon" , PALETTERGB (233,150,122)},
1346 {"salmon" , PALETTERGB (250,128,114)},
1347 {"light salmon" , PALETTERGB (255,160,122)},
1348 {"LightSalmon" , PALETTERGB (255,160,122)},
1349 {"orange" , PALETTERGB (255,165, 0)},
1350 {"dark orange" , PALETTERGB (255,140, 0)},
1351 {"DarkOrange" , PALETTERGB (255,140, 0)},
1352 {"coral" , PALETTERGB (255,127, 80)},
1353 {"light coral" , PALETTERGB (240,128,128)},
1354 {"LightCoral" , PALETTERGB (240,128,128)},
1355 {"tomato" , PALETTERGB (255, 99, 71)},
1356 {"orange red" , PALETTERGB (255, 69, 0)},
1357 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1358 {"red" , PALETTERGB (255, 0, 0)},
1359 {"hot pink" , PALETTERGB (255,105,180)},
1360 {"HotPink" , PALETTERGB (255,105,180)},
1361 {"deep pink" , PALETTERGB (255, 20,147)},
1362 {"DeepPink" , PALETTERGB (255, 20,147)},
1363 {"pink" , PALETTERGB (255,192,203)},
1364 {"light pink" , PALETTERGB (255,182,193)},
1365 {"LightPink" , PALETTERGB (255,182,193)},
1366 {"pale violet red" , PALETTERGB (219,112,147)},
1367 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1368 {"maroon" , PALETTERGB (176, 48, 96)},
1369 {"medium violet red" , PALETTERGB (199, 21,133)},
1370 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1371 {"violet red" , PALETTERGB (208, 32,144)},
1372 {"VioletRed" , PALETTERGB (208, 32,144)},
1373 {"magenta" , PALETTERGB (255, 0,255)},
1374 {"violet" , PALETTERGB (238,130,238)},
1375 {"plum" , PALETTERGB (221,160,221)},
1376 {"orchid" , PALETTERGB (218,112,214)},
1377 {"medium orchid" , PALETTERGB (186, 85,211)},
1378 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1379 {"dark orchid" , PALETTERGB (153, 50,204)},
1380 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1381 {"dark violet" , PALETTERGB (148, 0,211)},
1382 {"DarkViolet" , PALETTERGB (148, 0,211)},
1383 {"blue violet" , PALETTERGB (138, 43,226)},
1384 {"BlueViolet" , PALETTERGB (138, 43,226)},
1385 {"purple" , PALETTERGB (160, 32,240)},
1386 {"medium purple" , PALETTERGB (147,112,219)},
1387 {"MediumPurple" , PALETTERGB (147,112,219)},
1388 {"thistle" , PALETTERGB (216,191,216)},
1389 {"gray0" , PALETTERGB ( 0, 0, 0)},
1390 {"grey0" , PALETTERGB ( 0, 0, 0)},
1391 {"dark grey" , PALETTERGB (169,169,169)},
1392 {"DarkGrey" , PALETTERGB (169,169,169)},
1393 {"dark gray" , PALETTERGB (169,169,169)},
1394 {"DarkGray" , PALETTERGB (169,169,169)},
1395 {"dark blue" , PALETTERGB ( 0, 0,139)},
1396 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1397 {"dark cyan" , PALETTERGB ( 0,139,139)},
1398 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1399 {"dark magenta" , PALETTERGB (139, 0,139)},
1400 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1401 {"dark red" , PALETTERGB (139, 0, 0)},
1402 {"DarkRed" , PALETTERGB (139, 0, 0)},
1403 {"light green" , PALETTERGB (144,238,144)},
1404 {"LightGreen" , PALETTERGB (144,238,144)},
1405 };
1406
1407 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1408 0, 0, 0, doc: /* Return the default color map. */)
1409 ()
1410 {
1411 int i;
1412 colormap_t *pc = w32_color_map;
1413 Lisp_Object cmap;
1414
1415 BLOCK_INPUT;
1416
1417 cmap = Qnil;
1418
1419 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1420 pc++, i++)
1421 cmap = Fcons (Fcons (build_string (pc->name),
1422 make_number (pc->colorref)),
1423 cmap);
1424
1425 UNBLOCK_INPUT;
1426
1427 return (cmap);
1428 }
1429
1430 Lisp_Object
1431 w32_to_x_color (rgb)
1432 Lisp_Object rgb;
1433 {
1434 Lisp_Object color;
1435
1436 CHECK_NUMBER (rgb);
1437
1438 BLOCK_INPUT;
1439
1440 color = Frassq (rgb, Vw32_color_map);
1441
1442 UNBLOCK_INPUT;
1443
1444 if (!NILP (color))
1445 return (Fcar (color));
1446 else
1447 return Qnil;
1448 }
1449
1450 COLORREF
1451 w32_color_map_lookup (colorname)
1452 char *colorname;
1453 {
1454 Lisp_Object tail, ret = Qnil;
1455
1456 BLOCK_INPUT;
1457
1458 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1459 {
1460 register Lisp_Object elt, tem;
1461
1462 elt = Fcar (tail);
1463 if (!CONSP (elt)) continue;
1464
1465 tem = Fcar (elt);
1466
1467 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1468 {
1469 ret = XUINT (Fcdr (elt));
1470 break;
1471 }
1472
1473 QUIT;
1474 }
1475
1476
1477 UNBLOCK_INPUT;
1478
1479 return ret;
1480 }
1481
1482 COLORREF
1483 x_to_w32_color (colorname)
1484 char * colorname;
1485 {
1486 register Lisp_Object ret = Qnil;
1487
1488 BLOCK_INPUT;
1489
1490 if (colorname[0] == '#')
1491 {
1492 /* Could be an old-style RGB Device specification. */
1493 char *color;
1494 int size;
1495 color = colorname + 1;
1496
1497 size = strlen(color);
1498 if (size == 3 || size == 6 || size == 9 || size == 12)
1499 {
1500 UINT colorval;
1501 int i, pos;
1502 pos = 0;
1503 size /= 3;
1504 colorval = 0;
1505
1506 for (i = 0; i < 3; i++)
1507 {
1508 char *end;
1509 char t;
1510 unsigned long value;
1511
1512 /* The check for 'x' in the following conditional takes into
1513 account the fact that strtol allows a "0x" in front of
1514 our numbers, and we don't. */
1515 if (!isxdigit(color[0]) || color[1] == 'x')
1516 break;
1517 t = color[size];
1518 color[size] = '\0';
1519 value = strtoul(color, &end, 16);
1520 color[size] = t;
1521 if (errno == ERANGE || end - color != size)
1522 break;
1523 switch (size)
1524 {
1525 case 1:
1526 value = value * 0x10;
1527 break;
1528 case 2:
1529 break;
1530 case 3:
1531 value /= 0x10;
1532 break;
1533 case 4:
1534 value /= 0x100;
1535 break;
1536 }
1537 colorval |= (value << pos);
1538 pos += 0x8;
1539 if (i == 2)
1540 {
1541 UNBLOCK_INPUT;
1542 return (colorval);
1543 }
1544 color = end;
1545 }
1546 }
1547 }
1548 else if (strnicmp(colorname, "rgb:", 4) == 0)
1549 {
1550 char *color;
1551 UINT colorval;
1552 int i, pos;
1553 pos = 0;
1554
1555 colorval = 0;
1556 color = colorname + 4;
1557 for (i = 0; i < 3; i++)
1558 {
1559 char *end;
1560 unsigned long value;
1561
1562 /* The check for 'x' in the following conditional takes into
1563 account the fact that strtol allows a "0x" in front of
1564 our numbers, and we don't. */
1565 if (!isxdigit(color[0]) || color[1] == 'x')
1566 break;
1567 value = strtoul(color, &end, 16);
1568 if (errno == ERANGE)
1569 break;
1570 switch (end - color)
1571 {
1572 case 1:
1573 value = value * 0x10 + value;
1574 break;
1575 case 2:
1576 break;
1577 case 3:
1578 value /= 0x10;
1579 break;
1580 case 4:
1581 value /= 0x100;
1582 break;
1583 default:
1584 value = ULONG_MAX;
1585 }
1586 if (value == ULONG_MAX)
1587 break;
1588 colorval |= (value << pos);
1589 pos += 0x8;
1590 if (i == 2)
1591 {
1592 if (*end != '\0')
1593 break;
1594 UNBLOCK_INPUT;
1595 return (colorval);
1596 }
1597 if (*end != '/')
1598 break;
1599 color = end + 1;
1600 }
1601 }
1602 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1603 {
1604 /* This is an RGB Intensity specification. */
1605 char *color;
1606 UINT colorval;
1607 int i, pos;
1608 pos = 0;
1609
1610 colorval = 0;
1611 color = colorname + 5;
1612 for (i = 0; i < 3; i++)
1613 {
1614 char *end;
1615 double value;
1616 UINT val;
1617
1618 value = strtod(color, &end);
1619 if (errno == ERANGE)
1620 break;
1621 if (value < 0.0 || value > 1.0)
1622 break;
1623 val = (UINT)(0x100 * value);
1624 /* We used 0x100 instead of 0xFF to give an continuous
1625 range between 0.0 and 1.0 inclusive. The next statement
1626 fixes the 1.0 case. */
1627 if (val == 0x100)
1628 val = 0xFF;
1629 colorval |= (val << pos);
1630 pos += 0x8;
1631 if (i == 2)
1632 {
1633 if (*end != '\0')
1634 break;
1635 UNBLOCK_INPUT;
1636 return (colorval);
1637 }
1638 if (*end != '/')
1639 break;
1640 color = end + 1;
1641 }
1642 }
1643 /* I am not going to attempt to handle any of the CIE color schemes
1644 or TekHVC, since I don't know the algorithms for conversion to
1645 RGB. */
1646
1647 /* If we fail to lookup the color name in w32_color_map, then check the
1648 colorname to see if it can be crudely approximated: If the X color
1649 ends in a number (e.g., "darkseagreen2"), strip the number and
1650 return the result of looking up the base color name. */
1651 ret = w32_color_map_lookup (colorname);
1652 if (NILP (ret))
1653 {
1654 int len = strlen (colorname);
1655
1656 if (isdigit (colorname[len - 1]))
1657 {
1658 char *ptr, *approx = alloca (len + 1);
1659
1660 strcpy (approx, colorname);
1661 ptr = &approx[len - 1];
1662 while (ptr > approx && isdigit (*ptr))
1663 *ptr-- = '\0';
1664
1665 ret = w32_color_map_lookup (approx);
1666 }
1667 }
1668
1669 UNBLOCK_INPUT;
1670 return ret;
1671 }
1672
1673
1674 void
1675 w32_regenerate_palette (FRAME_PTR f)
1676 {
1677 struct w32_palette_entry * list;
1678 LOGPALETTE * log_palette;
1679 HPALETTE new_palette;
1680 int i;
1681
1682 /* don't bother trying to create palette if not supported */
1683 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1684 return;
1685
1686 log_palette = (LOGPALETTE *)
1687 alloca (sizeof (LOGPALETTE) +
1688 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1689 log_palette->palVersion = 0x300;
1690 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1691
1692 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1693 for (i = 0;
1694 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1695 i++, list = list->next)
1696 log_palette->palPalEntry[i] = list->entry;
1697
1698 new_palette = CreatePalette (log_palette);
1699
1700 enter_crit ();
1701
1702 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1703 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1704 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1705
1706 /* Realize display palette and garbage all frames. */
1707 release_frame_dc (f, get_frame_dc (f));
1708
1709 leave_crit ();
1710 }
1711
1712 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1713 #define SET_W32_COLOR(pe, color) \
1714 do \
1715 { \
1716 pe.peRed = GetRValue (color); \
1717 pe.peGreen = GetGValue (color); \
1718 pe.peBlue = GetBValue (color); \
1719 pe.peFlags = 0; \
1720 } while (0)
1721
1722 #if 0
1723 /* Keep these around in case we ever want to track color usage. */
1724 void
1725 w32_map_color (FRAME_PTR f, COLORREF color)
1726 {
1727 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1728
1729 if (NILP (Vw32_enable_palette))
1730 return;
1731
1732 /* check if color is already mapped */
1733 while (list)
1734 {
1735 if (W32_COLOR (list->entry) == color)
1736 {
1737 ++list->refcount;
1738 return;
1739 }
1740 list = list->next;
1741 }
1742
1743 /* not already mapped, so add to list and recreate Windows palette */
1744 list = (struct w32_palette_entry *)
1745 xmalloc (sizeof (struct w32_palette_entry));
1746 SET_W32_COLOR (list->entry, color);
1747 list->refcount = 1;
1748 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1749 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1750 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1751
1752 /* set flag that palette must be regenerated */
1753 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1754 }
1755
1756 void
1757 w32_unmap_color (FRAME_PTR f, COLORREF color)
1758 {
1759 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1760 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1761
1762 if (NILP (Vw32_enable_palette))
1763 return;
1764
1765 /* check if color is already mapped */
1766 while (list)
1767 {
1768 if (W32_COLOR (list->entry) == color)
1769 {
1770 if (--list->refcount == 0)
1771 {
1772 *prev = list->next;
1773 xfree (list);
1774 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1775 break;
1776 }
1777 else
1778 return;
1779 }
1780 prev = &list->next;
1781 list = list->next;
1782 }
1783
1784 /* set flag that palette must be regenerated */
1785 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1786 }
1787 #endif
1788
1789
1790 /* Gamma-correct COLOR on frame F. */
1791
1792 void
1793 gamma_correct (f, color)
1794 struct frame *f;
1795 COLORREF *color;
1796 {
1797 if (f->gamma)
1798 {
1799 *color = PALETTERGB (
1800 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1801 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1802 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1803 }
1804 }
1805
1806
1807 /* Decide if color named COLOR is valid for the display associated with
1808 the selected frame; if so, return the rgb values in COLOR_DEF.
1809 If ALLOC is nonzero, allocate a new colormap cell. */
1810
1811 int
1812 w32_defined_color (f, color, color_def, alloc)
1813 FRAME_PTR f;
1814 char *color;
1815 XColor *color_def;
1816 int alloc;
1817 {
1818 register Lisp_Object tem;
1819 COLORREF w32_color_ref;
1820
1821 tem = x_to_w32_color (color);
1822
1823 if (!NILP (tem))
1824 {
1825 if (f)
1826 {
1827 /* Apply gamma correction. */
1828 w32_color_ref = XUINT (tem);
1829 gamma_correct (f, &w32_color_ref);
1830 XSETINT (tem, w32_color_ref);
1831 }
1832
1833 /* Map this color to the palette if it is enabled. */
1834 if (!NILP (Vw32_enable_palette))
1835 {
1836 struct w32_palette_entry * entry =
1837 one_w32_display_info.color_list;
1838 struct w32_palette_entry ** prev =
1839 &one_w32_display_info.color_list;
1840
1841 /* check if color is already mapped */
1842 while (entry)
1843 {
1844 if (W32_COLOR (entry->entry) == XUINT (tem))
1845 break;
1846 prev = &entry->next;
1847 entry = entry->next;
1848 }
1849
1850 if (entry == NULL && alloc)
1851 {
1852 /* not already mapped, so add to list */
1853 entry = (struct w32_palette_entry *)
1854 xmalloc (sizeof (struct w32_palette_entry));
1855 SET_W32_COLOR (entry->entry, XUINT (tem));
1856 entry->next = NULL;
1857 *prev = entry;
1858 one_w32_display_info.num_colors++;
1859
1860 /* set flag that palette must be regenerated */
1861 one_w32_display_info.regen_palette = TRUE;
1862 }
1863 }
1864 /* Ensure COLORREF value is snapped to nearest color in (default)
1865 palette by simulating the PALETTERGB macro. This works whether
1866 or not the display device has a palette. */
1867 w32_color_ref = XUINT (tem) | 0x2000000;
1868
1869 color_def->pixel = w32_color_ref;
1870 color_def->red = GetRValue (w32_color_ref);
1871 color_def->green = GetGValue (w32_color_ref);
1872 color_def->blue = GetBValue (w32_color_ref);
1873
1874 return 1;
1875 }
1876 else
1877 {
1878 return 0;
1879 }
1880 }
1881
1882 /* Given a string ARG naming a color, compute a pixel value from it
1883 suitable for screen F.
1884 If F is not a color screen, return DEF (default) regardless of what
1885 ARG says. */
1886
1887 int
1888 x_decode_color (f, arg, def)
1889 FRAME_PTR f;
1890 Lisp_Object arg;
1891 int def;
1892 {
1893 XColor cdef;
1894
1895 CHECK_STRING (arg);
1896
1897 if (strcmp (XSTRING (arg)->data, "black") == 0)
1898 return BLACK_PIX_DEFAULT (f);
1899 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1900 return WHITE_PIX_DEFAULT (f);
1901
1902 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1903 return def;
1904
1905 /* w32_defined_color is responsible for coping with failures
1906 by looking for a near-miss. */
1907 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1908 return cdef.pixel;
1909
1910 /* defined_color failed; return an ultimate default. */
1911 return def;
1912 }
1913 \f
1914 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
1915 the previous value of that parameter, NEW_VALUE is the new value. */
1916
1917 static void
1918 x_set_line_spacing (f, new_value, old_value)
1919 struct frame *f;
1920 Lisp_Object new_value, old_value;
1921 {
1922 if (NILP (new_value))
1923 f->extra_line_spacing = 0;
1924 else if (NATNUMP (new_value))
1925 f->extra_line_spacing = XFASTINT (new_value);
1926 else
1927 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
1928 Fcons (new_value, Qnil)));
1929 if (FRAME_VISIBLE_P (f))
1930 redraw_frame (f);
1931 }
1932
1933
1934 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
1935 the previous value of that parameter, NEW_VALUE is the new value. */
1936
1937 static void
1938 x_set_screen_gamma (f, new_value, old_value)
1939 struct frame *f;
1940 Lisp_Object new_value, old_value;
1941 {
1942 if (NILP (new_value))
1943 f->gamma = 0;
1944 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
1945 /* The value 0.4545 is the normal viewing gamma. */
1946 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
1947 else
1948 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
1949 Fcons (new_value, Qnil)));
1950
1951 clear_face_cache (0);
1952 }
1953
1954
1955 /* Functions called only from `x_set_frame_param'
1956 to set individual parameters.
1957
1958 If FRAME_W32_WINDOW (f) is 0,
1959 the frame is being created and its window does not exist yet.
1960 In that case, just record the parameter's new value
1961 in the standard place; do not attempt to change the window. */
1962
1963 void
1964 x_set_foreground_color (f, arg, oldval)
1965 struct frame *f;
1966 Lisp_Object arg, oldval;
1967 {
1968 struct w32_output *x = f->output_data.w32;
1969 PIX_TYPE fg, old_fg;
1970
1971 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1972 old_fg = FRAME_FOREGROUND_PIXEL (f);
1973 FRAME_FOREGROUND_PIXEL (f) = fg;
1974
1975 if (FRAME_W32_WINDOW (f) != 0)
1976 {
1977 if (x->cursor_pixel == old_fg)
1978 x->cursor_pixel = fg;
1979
1980 update_face_from_frame_parameter (f, Qforeground_color, arg);
1981 if (FRAME_VISIBLE_P (f))
1982 redraw_frame (f);
1983 }
1984 }
1985
1986 void
1987 x_set_background_color (f, arg, oldval)
1988 struct frame *f;
1989 Lisp_Object arg, oldval;
1990 {
1991 FRAME_BACKGROUND_PIXEL (f)
1992 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1993
1994 if (FRAME_W32_WINDOW (f) != 0)
1995 {
1996 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1997 FRAME_BACKGROUND_PIXEL (f));
1998
1999 update_face_from_frame_parameter (f, Qbackground_color, arg);
2000
2001 if (FRAME_VISIBLE_P (f))
2002 redraw_frame (f);
2003 }
2004 }
2005
2006 void
2007 x_set_mouse_color (f, arg, oldval)
2008 struct frame *f;
2009 Lisp_Object arg, oldval;
2010 {
2011 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2012 int count;
2013 int mask_color;
2014
2015 if (!EQ (Qnil, arg))
2016 f->output_data.w32->mouse_pixel
2017 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2018 mask_color = FRAME_BACKGROUND_PIXEL (f);
2019
2020 /* Don't let pointers be invisible. */
2021 if (mask_color == f->output_data.w32->mouse_pixel
2022 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2023 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2024
2025 #if 0 /* TODO : cursor changes */
2026 BLOCK_INPUT;
2027
2028 /* It's not okay to crash if the user selects a screwy cursor. */
2029 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2030
2031 if (!EQ (Qnil, Vx_pointer_shape))
2032 {
2033 CHECK_NUMBER (Vx_pointer_shape);
2034 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2035 }
2036 else
2037 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2038 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2039
2040 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2041 {
2042 CHECK_NUMBER (Vx_nontext_pointer_shape);
2043 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2044 XINT (Vx_nontext_pointer_shape));
2045 }
2046 else
2047 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2048 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2049
2050 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2051 {
2052 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2053 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2054 XINT (Vx_hourglass_pointer_shape));
2055 }
2056 else
2057 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2058 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2059
2060 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2061 if (!EQ (Qnil, Vx_mode_pointer_shape))
2062 {
2063 CHECK_NUMBER (Vx_mode_pointer_shape);
2064 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2065 XINT (Vx_mode_pointer_shape));
2066 }
2067 else
2068 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2069 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2070
2071 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2072 {
2073 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2074 cross_cursor
2075 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2076 XINT (Vx_sensitive_text_pointer_shape));
2077 }
2078 else
2079 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2080
2081 if (!NILP (Vx_window_horizontal_drag_shape))
2082 {
2083 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2084 horizontal_drag_cursor
2085 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2086 XINT (Vx_window_horizontal_drag_shape));
2087 }
2088 else
2089 horizontal_drag_cursor
2090 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2091
2092 /* Check and report errors with the above calls. */
2093 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2094 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2095
2096 {
2097 XColor fore_color, back_color;
2098
2099 fore_color.pixel = f->output_data.w32->mouse_pixel;
2100 back_color.pixel = mask_color;
2101 XQueryColor (FRAME_W32_DISPLAY (f),
2102 DefaultColormap (FRAME_W32_DISPLAY (f),
2103 DefaultScreen (FRAME_W32_DISPLAY (f))),
2104 &fore_color);
2105 XQueryColor (FRAME_W32_DISPLAY (f),
2106 DefaultColormap (FRAME_W32_DISPLAY (f),
2107 DefaultScreen (FRAME_W32_DISPLAY (f))),
2108 &back_color);
2109 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2110 &fore_color, &back_color);
2111 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2112 &fore_color, &back_color);
2113 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2114 &fore_color, &back_color);
2115 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2116 &fore_color, &back_color);
2117 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2118 &fore_color, &back_color);
2119 }
2120
2121 if (FRAME_W32_WINDOW (f) != 0)
2122 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2123
2124 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2125 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2126 f->output_data.w32->text_cursor = cursor;
2127
2128 if (nontext_cursor != f->output_data.w32->nontext_cursor
2129 && f->output_data.w32->nontext_cursor != 0)
2130 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2131 f->output_data.w32->nontext_cursor = nontext_cursor;
2132
2133 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2134 && f->output_data.w32->hourglass_cursor != 0)
2135 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2136 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2137
2138 if (mode_cursor != f->output_data.w32->modeline_cursor
2139 && f->output_data.w32->modeline_cursor != 0)
2140 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2141 f->output_data.w32->modeline_cursor = mode_cursor;
2142
2143 if (cross_cursor != f->output_data.w32->cross_cursor
2144 && f->output_data.w32->cross_cursor != 0)
2145 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2146 f->output_data.w32->cross_cursor = cross_cursor;
2147
2148 XFlush (FRAME_W32_DISPLAY (f));
2149 UNBLOCK_INPUT;
2150
2151 update_face_from_frame_parameter (f, Qmouse_color, arg);
2152 #endif /* TODO */
2153 }
2154
2155 /* Defined in w32term.c. */
2156 void x_update_cursor (struct frame *f, int on_p);
2157
2158 void
2159 x_set_cursor_color (f, arg, oldval)
2160 struct frame *f;
2161 Lisp_Object arg, oldval;
2162 {
2163 unsigned long fore_pixel, pixel;
2164
2165 if (!NILP (Vx_cursor_fore_pixel))
2166 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2167 WHITE_PIX_DEFAULT (f));
2168 else
2169 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2170
2171 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2172
2173 /* Make sure that the cursor color differs from the background color. */
2174 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2175 {
2176 pixel = f->output_data.w32->mouse_pixel;
2177 if (pixel == fore_pixel)
2178 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2179 }
2180
2181 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2182 f->output_data.w32->cursor_pixel = pixel;
2183
2184 if (FRAME_W32_WINDOW (f) != 0)
2185 {
2186 if (FRAME_VISIBLE_P (f))
2187 {
2188 x_update_cursor (f, 0);
2189 x_update_cursor (f, 1);
2190 }
2191 }
2192
2193 update_face_from_frame_parameter (f, Qcursor_color, arg);
2194 }
2195
2196 /* Set the border-color of frame F to pixel value PIX.
2197 Note that this does not fully take effect if done before
2198 F has an window. */
2199 void
2200 x_set_border_pixel (f, pix)
2201 struct frame *f;
2202 int pix;
2203 {
2204 f->output_data.w32->border_pixel = pix;
2205
2206 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2207 {
2208 if (FRAME_VISIBLE_P (f))
2209 redraw_frame (f);
2210 }
2211 }
2212
2213 /* Set the border-color of frame F to value described by ARG.
2214 ARG can be a string naming a color.
2215 The border-color is used for the border that is drawn by the server.
2216 Note that this does not fully take effect if done before
2217 F has a window; it must be redone when the window is created. */
2218
2219 void
2220 x_set_border_color (f, arg, oldval)
2221 struct frame *f;
2222 Lisp_Object arg, oldval;
2223 {
2224 int pix;
2225
2226 CHECK_STRING (arg);
2227 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2228 x_set_border_pixel (f, pix);
2229 update_face_from_frame_parameter (f, Qborder_color, arg);
2230 }
2231
2232 /* Value is the internal representation of the specified cursor type
2233 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2234 of the bar cursor. */
2235
2236 enum text_cursor_kinds
2237 x_specified_cursor_type (arg, width)
2238 Lisp_Object arg;
2239 int *width;
2240 {
2241 enum text_cursor_kinds type;
2242
2243 if (EQ (arg, Qbar))
2244 {
2245 type = BAR_CURSOR;
2246 *width = 2;
2247 }
2248 else if (CONSP (arg)
2249 && EQ (XCAR (arg), Qbar)
2250 && INTEGERP (XCDR (arg))
2251 && XINT (XCDR (arg)) >= 0)
2252 {
2253 type = BAR_CURSOR;
2254 *width = XINT (XCDR (arg));
2255 }
2256 else if (NILP (arg))
2257 type = NO_CURSOR;
2258 else
2259 /* Treat anything unknown as "box cursor".
2260 It was bad to signal an error; people have trouble fixing
2261 .Xdefaults with Emacs, when it has something bad in it. */
2262 type = FILLED_BOX_CURSOR;
2263
2264 return type;
2265 }
2266
2267 void
2268 x_set_cursor_type (f, arg, oldval)
2269 FRAME_PTR f;
2270 Lisp_Object arg, oldval;
2271 {
2272 int width;
2273
2274 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2275 f->output_data.w32->cursor_width = width;
2276
2277 /* Make sure the cursor gets redrawn. This is overkill, but how
2278 often do people change cursor types? */
2279 update_mode_lines++;
2280 }
2281 \f
2282 void
2283 x_set_icon_type (f, arg, oldval)
2284 struct frame *f;
2285 Lisp_Object arg, oldval;
2286 {
2287 int result;
2288
2289 if (NILP (arg) && NILP (oldval))
2290 return;
2291
2292 if (STRINGP (arg) && STRINGP (oldval)
2293 && EQ (Fstring_equal (oldval, arg), Qt))
2294 return;
2295
2296 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2297 return;
2298
2299 BLOCK_INPUT;
2300
2301 result = x_bitmap_icon (f, arg);
2302 if (result)
2303 {
2304 UNBLOCK_INPUT;
2305 error ("No icon window available");
2306 }
2307
2308 UNBLOCK_INPUT;
2309 }
2310
2311 /* Return non-nil if frame F wants a bitmap icon. */
2312
2313 Lisp_Object
2314 x_icon_type (f)
2315 FRAME_PTR f;
2316 {
2317 Lisp_Object tem;
2318
2319 tem = assq_no_quit (Qicon_type, f->param_alist);
2320 if (CONSP (tem))
2321 return XCDR (tem);
2322 else
2323 return Qnil;
2324 }
2325
2326 void
2327 x_set_icon_name (f, arg, oldval)
2328 struct frame *f;
2329 Lisp_Object arg, oldval;
2330 {
2331 if (STRINGP (arg))
2332 {
2333 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2334 return;
2335 }
2336 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2337 return;
2338
2339 f->icon_name = arg;
2340
2341 #if 0
2342 if (f->output_data.w32->icon_bitmap != 0)
2343 return;
2344
2345 BLOCK_INPUT;
2346
2347 result = x_text_icon (f,
2348 (char *) XSTRING ((!NILP (f->icon_name)
2349 ? f->icon_name
2350 : !NILP (f->title)
2351 ? f->title
2352 : f->name))->data);
2353
2354 if (result)
2355 {
2356 UNBLOCK_INPUT;
2357 error ("No icon window available");
2358 }
2359
2360 /* If the window was unmapped (and its icon was mapped),
2361 the new icon is not mapped, so map the window in its stead. */
2362 if (FRAME_VISIBLE_P (f))
2363 {
2364 #ifdef USE_X_TOOLKIT
2365 XtPopup (f->output_data.w32->widget, XtGrabNone);
2366 #endif
2367 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2368 }
2369
2370 XFlush (FRAME_W32_DISPLAY (f));
2371 UNBLOCK_INPUT;
2372 #endif
2373 }
2374
2375 extern Lisp_Object x_new_font ();
2376 extern Lisp_Object x_new_fontset();
2377
2378 void
2379 x_set_font (f, arg, oldval)
2380 struct frame *f;
2381 Lisp_Object arg, oldval;
2382 {
2383 Lisp_Object result;
2384 Lisp_Object fontset_name;
2385 Lisp_Object frame;
2386 int old_fontset = FRAME_FONTSET(f);
2387
2388 CHECK_STRING (arg);
2389
2390 fontset_name = Fquery_fontset (arg, Qnil);
2391
2392 BLOCK_INPUT;
2393 result = (STRINGP (fontset_name)
2394 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2395 : x_new_font (f, XSTRING (arg)->data));
2396 UNBLOCK_INPUT;
2397
2398 if (EQ (result, Qnil))
2399 error ("Font `%s' is not defined", XSTRING (arg)->data);
2400 else if (EQ (result, Qt))
2401 error ("The characters of the given font have varying widths");
2402 else if (STRINGP (result))
2403 {
2404 if (STRINGP (fontset_name))
2405 {
2406 /* Fontset names are built from ASCII font names, so the
2407 names may be equal despite there was a change. */
2408 if (old_fontset == FRAME_FONTSET (f))
2409 return;
2410 }
2411 else if (!NILP (Fequal (result, oldval)))
2412 return;
2413
2414 store_frame_param (f, Qfont, result);
2415 recompute_basic_faces (f);
2416 }
2417 else
2418 abort ();
2419
2420 do_pending_window_change (0);
2421
2422 /* Don't call `face-set-after-frame-default' when faces haven't been
2423 initialized yet. This is the case when called from
2424 Fx_create_frame. In that case, the X widget or window doesn't
2425 exist either, and we can end up in x_report_frame_params with a
2426 null widget which gives a segfault. */
2427 if (FRAME_FACE_CACHE (f))
2428 {
2429 XSETFRAME (frame, f);
2430 call1 (Qface_set_after_frame_default, frame);
2431 }
2432 }
2433
2434 void
2435 x_set_border_width (f, arg, oldval)
2436 struct frame *f;
2437 Lisp_Object arg, oldval;
2438 {
2439 CHECK_NUMBER (arg);
2440
2441 if (XINT (arg) == f->output_data.w32->border_width)
2442 return;
2443
2444 if (FRAME_W32_WINDOW (f) != 0)
2445 error ("Cannot change the border width of a window");
2446
2447 f->output_data.w32->border_width = XINT (arg);
2448 }
2449
2450 void
2451 x_set_internal_border_width (f, arg, oldval)
2452 struct frame *f;
2453 Lisp_Object arg, oldval;
2454 {
2455 int old = f->output_data.w32->internal_border_width;
2456
2457 CHECK_NUMBER (arg);
2458 f->output_data.w32->internal_border_width = XINT (arg);
2459 if (f->output_data.w32->internal_border_width < 0)
2460 f->output_data.w32->internal_border_width = 0;
2461
2462 if (f->output_data.w32->internal_border_width == old)
2463 return;
2464
2465 if (FRAME_W32_WINDOW (f) != 0)
2466 {
2467 x_set_window_size (f, 0, f->width, f->height);
2468 SET_FRAME_GARBAGED (f);
2469 do_pending_window_change (0);
2470 }
2471 }
2472
2473 void
2474 x_set_visibility (f, value, oldval)
2475 struct frame *f;
2476 Lisp_Object value, oldval;
2477 {
2478 Lisp_Object frame;
2479 XSETFRAME (frame, f);
2480
2481 if (NILP (value))
2482 Fmake_frame_invisible (frame, Qt);
2483 else if (EQ (value, Qicon))
2484 Ficonify_frame (frame);
2485 else
2486 Fmake_frame_visible (frame);
2487 }
2488
2489 \f
2490 /* Change window heights in windows rooted in WINDOW by N lines. */
2491
2492 static void
2493 x_change_window_heights (window, n)
2494 Lisp_Object window;
2495 int n;
2496 {
2497 struct window *w = XWINDOW (window);
2498
2499 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2500 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2501
2502 if (INTEGERP (w->orig_top))
2503 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2504 if (INTEGERP (w->orig_height))
2505 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2506
2507 /* Handle just the top child in a vertical split. */
2508 if (!NILP (w->vchild))
2509 x_change_window_heights (w->vchild, n);
2510
2511 /* Adjust all children in a horizontal split. */
2512 for (window = w->hchild; !NILP (window); window = w->next)
2513 {
2514 w = XWINDOW (window);
2515 x_change_window_heights (window, n);
2516 }
2517 }
2518
2519 void
2520 x_set_menu_bar_lines (f, value, oldval)
2521 struct frame *f;
2522 Lisp_Object value, oldval;
2523 {
2524 int nlines;
2525 int olines = FRAME_MENU_BAR_LINES (f);
2526
2527 /* Right now, menu bars don't work properly in minibuf-only frames;
2528 most of the commands try to apply themselves to the minibuffer
2529 frame itself, and get an error because you can't switch buffers
2530 in or split the minibuffer window. */
2531 if (FRAME_MINIBUF_ONLY_P (f))
2532 return;
2533
2534 if (INTEGERP (value))
2535 nlines = XINT (value);
2536 else
2537 nlines = 0;
2538
2539 FRAME_MENU_BAR_LINES (f) = 0;
2540 if (nlines)
2541 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2542 else
2543 {
2544 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2545 free_frame_menubar (f);
2546 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2547
2548 /* Adjust the frame size so that the client (text) dimensions
2549 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2550 set correctly. */
2551 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2552 do_pending_window_change (0);
2553 }
2554 adjust_glyphs (f);
2555 }
2556
2557
2558 /* Set the number of lines used for the tool bar of frame F to VALUE.
2559 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2560 is the old number of tool bar lines. This function changes the
2561 height of all windows on frame F to match the new tool bar height.
2562 The frame's height doesn't change. */
2563
2564 void
2565 x_set_tool_bar_lines (f, value, oldval)
2566 struct frame *f;
2567 Lisp_Object value, oldval;
2568 {
2569 int delta, nlines, root_height;
2570 Lisp_Object root_window;
2571
2572 /* Treat tool bars like menu bars. */
2573 if (FRAME_MINIBUF_ONLY_P (f))
2574 return;
2575
2576 /* Use VALUE only if an integer >= 0. */
2577 if (INTEGERP (value) && XINT (value) >= 0)
2578 nlines = XFASTINT (value);
2579 else
2580 nlines = 0;
2581
2582 /* Make sure we redisplay all windows in this frame. */
2583 ++windows_or_buffers_changed;
2584
2585 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2586
2587 /* Don't resize the tool-bar to more than we have room for. */
2588 root_window = FRAME_ROOT_WINDOW (f);
2589 root_height = XINT (XWINDOW (root_window)->height);
2590 if (root_height - delta < 1)
2591 {
2592 delta = root_height - 1;
2593 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2594 }
2595
2596 FRAME_TOOL_BAR_LINES (f) = nlines;
2597 x_change_window_heights (root_window, delta);
2598 adjust_glyphs (f);
2599
2600 /* We also have to make sure that the internal border at the top of
2601 the frame, below the menu bar or tool bar, is redrawn when the
2602 tool bar disappears. This is so because the internal border is
2603 below the tool bar if one is displayed, but is below the menu bar
2604 if there isn't a tool bar. The tool bar draws into the area
2605 below the menu bar. */
2606 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2607 {
2608 updating_frame = f;
2609 clear_frame ();
2610 clear_current_matrices (f);
2611 updating_frame = NULL;
2612 }
2613
2614 /* If the tool bar gets smaller, the internal border below it
2615 has to be cleared. It was formerly part of the display
2616 of the larger tool bar, and updating windows won't clear it. */
2617 if (delta < 0)
2618 {
2619 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2620 int width = PIXEL_WIDTH (f);
2621 int y = nlines * CANON_Y_UNIT (f);
2622
2623 BLOCK_INPUT;
2624 {
2625 HDC hdc = get_frame_dc (f);
2626 w32_clear_area (f, hdc, 0, y, width, height);
2627 release_frame_dc (f, hdc);
2628 }
2629 UNBLOCK_INPUT;
2630
2631 if (WINDOWP (f->tool_bar_window))
2632 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2633 }
2634 }
2635
2636
2637 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2638 w32_id_name.
2639
2640 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2641 name; if NAME is a string, set F's name to NAME and set
2642 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2643
2644 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2645 suggesting a new name, which lisp code should override; if
2646 F->explicit_name is set, ignore the new name; otherwise, set it. */
2647
2648 void
2649 x_set_name (f, name, explicit)
2650 struct frame *f;
2651 Lisp_Object name;
2652 int explicit;
2653 {
2654 /* Make sure that requests from lisp code override requests from
2655 Emacs redisplay code. */
2656 if (explicit)
2657 {
2658 /* If we're switching from explicit to implicit, we had better
2659 update the mode lines and thereby update the title. */
2660 if (f->explicit_name && NILP (name))
2661 update_mode_lines = 1;
2662
2663 f->explicit_name = ! NILP (name);
2664 }
2665 else if (f->explicit_name)
2666 return;
2667
2668 /* If NAME is nil, set the name to the w32_id_name. */
2669 if (NILP (name))
2670 {
2671 /* Check for no change needed in this very common case
2672 before we do any consing. */
2673 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2674 XSTRING (f->name)->data))
2675 return;
2676 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2677 }
2678 else
2679 CHECK_STRING (name);
2680
2681 /* Don't change the name if it's already NAME. */
2682 if (! NILP (Fstring_equal (name, f->name)))
2683 return;
2684
2685 f->name = name;
2686
2687 /* For setting the frame title, the title parameter should override
2688 the name parameter. */
2689 if (! NILP (f->title))
2690 name = f->title;
2691
2692 if (FRAME_W32_WINDOW (f))
2693 {
2694 if (STRING_MULTIBYTE (name))
2695 name = ENCODE_SYSTEM (name);
2696
2697 BLOCK_INPUT;
2698 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2699 UNBLOCK_INPUT;
2700 }
2701 }
2702
2703 /* This function should be called when the user's lisp code has
2704 specified a name for the frame; the name will override any set by the
2705 redisplay code. */
2706 void
2707 x_explicitly_set_name (f, arg, oldval)
2708 FRAME_PTR f;
2709 Lisp_Object arg, oldval;
2710 {
2711 x_set_name (f, arg, 1);
2712 }
2713
2714 /* This function should be called by Emacs redisplay code to set the
2715 name; names set this way will never override names set by the user's
2716 lisp code. */
2717 void
2718 x_implicitly_set_name (f, arg, oldval)
2719 FRAME_PTR f;
2720 Lisp_Object arg, oldval;
2721 {
2722 x_set_name (f, arg, 0);
2723 }
2724 \f
2725 /* Change the title of frame F to NAME.
2726 If NAME is nil, use the frame name as the title.
2727
2728 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2729 name; if NAME is a string, set F's name to NAME and set
2730 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2731
2732 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2733 suggesting a new name, which lisp code should override; if
2734 F->explicit_name is set, ignore the new name; otherwise, set it. */
2735
2736 void
2737 x_set_title (f, name, old_name)
2738 struct frame *f;
2739 Lisp_Object name, old_name;
2740 {
2741 /* Don't change the title if it's already NAME. */
2742 if (EQ (name, f->title))
2743 return;
2744
2745 update_mode_lines = 1;
2746
2747 f->title = name;
2748
2749 if (NILP (name))
2750 name = f->name;
2751
2752 if (FRAME_W32_WINDOW (f))
2753 {
2754 if (STRING_MULTIBYTE (name))
2755 name = ENCODE_SYSTEM (name);
2756
2757 BLOCK_INPUT;
2758 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2759 UNBLOCK_INPUT;
2760 }
2761 }
2762 \f
2763 void
2764 x_set_autoraise (f, arg, oldval)
2765 struct frame *f;
2766 Lisp_Object arg, oldval;
2767 {
2768 f->auto_raise = !EQ (Qnil, arg);
2769 }
2770
2771 void
2772 x_set_autolower (f, arg, oldval)
2773 struct frame *f;
2774 Lisp_Object arg, oldval;
2775 {
2776 f->auto_lower = !EQ (Qnil, arg);
2777 }
2778
2779 void
2780 x_set_unsplittable (f, arg, oldval)
2781 struct frame *f;
2782 Lisp_Object arg, oldval;
2783 {
2784 f->no_split = !NILP (arg);
2785 }
2786
2787 void
2788 x_set_vertical_scroll_bars (f, arg, oldval)
2789 struct frame *f;
2790 Lisp_Object arg, oldval;
2791 {
2792 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2793 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2794 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2795 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2796 {
2797 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2798 vertical_scroll_bar_none :
2799 /* Put scroll bars on the right by default, as is conventional
2800 on MS-Windows. */
2801 EQ (Qleft, arg)
2802 ? vertical_scroll_bar_left
2803 : vertical_scroll_bar_right;
2804
2805 /* We set this parameter before creating the window for the
2806 frame, so we can get the geometry right from the start.
2807 However, if the window hasn't been created yet, we shouldn't
2808 call x_set_window_size. */
2809 if (FRAME_W32_WINDOW (f))
2810 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2811 do_pending_window_change (0);
2812 }
2813 }
2814
2815 void
2816 x_set_scroll_bar_width (f, arg, oldval)
2817 struct frame *f;
2818 Lisp_Object arg, oldval;
2819 {
2820 int wid = FONT_WIDTH (f->output_data.w32->font);
2821
2822 if (NILP (arg))
2823 {
2824 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2825 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2826 wid - 1) / wid;
2827 if (FRAME_W32_WINDOW (f))
2828 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2829 do_pending_window_change (0);
2830 }
2831 else if (INTEGERP (arg) && XINT (arg) > 0
2832 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2833 {
2834 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2835 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2836 + wid-1) / wid;
2837 if (FRAME_W32_WINDOW (f))
2838 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2839 do_pending_window_change (0);
2840 }
2841 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2842 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2843 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2844 }
2845 \f
2846 /* Subroutines of creating an frame. */
2847
2848 /* Make sure that Vx_resource_name is set to a reasonable value.
2849 Fix it up, or set it to `emacs' if it is too hopeless. */
2850
2851 static void
2852 validate_x_resource_name ()
2853 {
2854 int len = 0;
2855 /* Number of valid characters in the resource name. */
2856 int good_count = 0;
2857 /* Number of invalid characters in the resource name. */
2858 int bad_count = 0;
2859 Lisp_Object new;
2860 int i;
2861
2862 if (STRINGP (Vx_resource_name))
2863 {
2864 unsigned char *p = XSTRING (Vx_resource_name)->data;
2865 int i;
2866
2867 len = STRING_BYTES (XSTRING (Vx_resource_name));
2868
2869 /* Only letters, digits, - and _ are valid in resource names.
2870 Count the valid characters and count the invalid ones. */
2871 for (i = 0; i < len; i++)
2872 {
2873 int c = p[i];
2874 if (! ((c >= 'a' && c <= 'z')
2875 || (c >= 'A' && c <= 'Z')
2876 || (c >= '0' && c <= '9')
2877 || c == '-' || c == '_'))
2878 bad_count++;
2879 else
2880 good_count++;
2881 }
2882 }
2883 else
2884 /* Not a string => completely invalid. */
2885 bad_count = 5, good_count = 0;
2886
2887 /* If name is valid already, return. */
2888 if (bad_count == 0)
2889 return;
2890
2891 /* If name is entirely invalid, or nearly so, use `emacs'. */
2892 if (good_count == 0
2893 || (good_count == 1 && bad_count > 0))
2894 {
2895 Vx_resource_name = build_string ("emacs");
2896 return;
2897 }
2898
2899 /* Name is partly valid. Copy it and replace the invalid characters
2900 with underscores. */
2901
2902 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
2903
2904 for (i = 0; i < len; i++)
2905 {
2906 int c = XSTRING (new)->data[i];
2907 if (! ((c >= 'a' && c <= 'z')
2908 || (c >= 'A' && c <= 'Z')
2909 || (c >= '0' && c <= '9')
2910 || c == '-' || c == '_'))
2911 XSTRING (new)->data[i] = '_';
2912 }
2913 }
2914
2915
2916 extern char *x_get_string_resource ();
2917
2918 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
2919 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
2920 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
2921 class, where INSTANCE is the name under which Emacs was invoked, or
2922 the name specified by the `-name' or `-rn' command-line arguments.
2923
2924 The optional arguments COMPONENT and SUBCLASS add to the key and the
2925 class, respectively. You must specify both of them or neither.
2926 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
2927 and the class is `Emacs.CLASS.SUBCLASS'. */)
2928 (attribute, class, component, subclass)
2929 Lisp_Object attribute, class, component, subclass;
2930 {
2931 register char *value;
2932 char *name_key;
2933 char *class_key;
2934
2935 CHECK_STRING (attribute);
2936 CHECK_STRING (class);
2937
2938 if (!NILP (component))
2939 CHECK_STRING (component);
2940 if (!NILP (subclass))
2941 CHECK_STRING (subclass);
2942 if (NILP (component) != NILP (subclass))
2943 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
2944
2945 validate_x_resource_name ();
2946
2947 /* Allocate space for the components, the dots which separate them,
2948 and the final '\0'. Make them big enough for the worst case. */
2949 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
2950 + (STRINGP (component)
2951 ? STRING_BYTES (XSTRING (component)) : 0)
2952 + STRING_BYTES (XSTRING (attribute))
2953 + 3);
2954
2955 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
2956 + STRING_BYTES (XSTRING (class))
2957 + (STRINGP (subclass)
2958 ? STRING_BYTES (XSTRING (subclass)) : 0)
2959 + 3);
2960
2961 /* Start with emacs.FRAMENAME for the name (the specific one)
2962 and with `Emacs' for the class key (the general one). */
2963 strcpy (name_key, XSTRING (Vx_resource_name)->data);
2964 strcpy (class_key, EMACS_CLASS);
2965
2966 strcat (class_key, ".");
2967 strcat (class_key, XSTRING (class)->data);
2968
2969 if (!NILP (component))
2970 {
2971 strcat (class_key, ".");
2972 strcat (class_key, XSTRING (subclass)->data);
2973
2974 strcat (name_key, ".");
2975 strcat (name_key, XSTRING (component)->data);
2976 }
2977
2978 strcat (name_key, ".");
2979 strcat (name_key, XSTRING (attribute)->data);
2980
2981 value = x_get_string_resource (Qnil,
2982 name_key, class_key);
2983
2984 if (value != (char *) 0)
2985 return build_string (value);
2986 else
2987 return Qnil;
2988 }
2989
2990 /* Used when C code wants a resource value. */
2991
2992 char *
2993 x_get_resource_string (attribute, class)
2994 char *attribute, *class;
2995 {
2996 char *name_key;
2997 char *class_key;
2998 struct frame *sf = SELECTED_FRAME ();
2999
3000 /* Allocate space for the components, the dots which separate them,
3001 and the final '\0'. */
3002 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3003 + strlen (attribute) + 2);
3004 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3005 + strlen (class) + 2);
3006
3007 sprintf (name_key, "%s.%s",
3008 XSTRING (Vinvocation_name)->data,
3009 attribute);
3010 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3011
3012 return x_get_string_resource (sf, name_key, class_key);
3013 }
3014
3015 /* Types we might convert a resource string into. */
3016 enum resource_types
3017 {
3018 RES_TYPE_NUMBER,
3019 RES_TYPE_FLOAT,
3020 RES_TYPE_BOOLEAN,
3021 RES_TYPE_STRING,
3022 RES_TYPE_SYMBOL
3023 };
3024
3025 /* Return the value of parameter PARAM.
3026
3027 First search ALIST, then Vdefault_frame_alist, then the X defaults
3028 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3029
3030 Convert the resource to the type specified by desired_type.
3031
3032 If no default is specified, return Qunbound. If you call
3033 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3034 and don't let it get stored in any Lisp-visible variables! */
3035
3036 static Lisp_Object
3037 w32_get_arg (alist, param, attribute, class, type)
3038 Lisp_Object alist, param;
3039 char *attribute;
3040 char *class;
3041 enum resource_types type;
3042 {
3043 register Lisp_Object tem;
3044
3045 tem = Fassq (param, alist);
3046 if (EQ (tem, Qnil))
3047 tem = Fassq (param, Vdefault_frame_alist);
3048 if (EQ (tem, Qnil))
3049 {
3050
3051 if (attribute)
3052 {
3053 tem = Fx_get_resource (build_string (attribute),
3054 build_string (class),
3055 Qnil, Qnil);
3056
3057 if (NILP (tem))
3058 return Qunbound;
3059
3060 switch (type)
3061 {
3062 case RES_TYPE_NUMBER:
3063 return make_number (atoi (XSTRING (tem)->data));
3064
3065 case RES_TYPE_FLOAT:
3066 return make_float (atof (XSTRING (tem)->data));
3067
3068 case RES_TYPE_BOOLEAN:
3069 tem = Fdowncase (tem);
3070 if (!strcmp (XSTRING (tem)->data, "on")
3071 || !strcmp (XSTRING (tem)->data, "true"))
3072 return Qt;
3073 else
3074 return Qnil;
3075
3076 case RES_TYPE_STRING:
3077 return tem;
3078
3079 case RES_TYPE_SYMBOL:
3080 /* As a special case, we map the values `true' and `on'
3081 to Qt, and `false' and `off' to Qnil. */
3082 {
3083 Lisp_Object lower;
3084 lower = Fdowncase (tem);
3085 if (!strcmp (XSTRING (lower)->data, "on")
3086 || !strcmp (XSTRING (lower)->data, "true"))
3087 return Qt;
3088 else if (!strcmp (XSTRING (lower)->data, "off")
3089 || !strcmp (XSTRING (lower)->data, "false"))
3090 return Qnil;
3091 else
3092 return Fintern (tem, Qnil);
3093 }
3094
3095 default:
3096 abort ();
3097 }
3098 }
3099 else
3100 return Qunbound;
3101 }
3102 return Fcdr (tem);
3103 }
3104
3105 /* Record in frame F the specified or default value according to ALIST
3106 of the parameter named PROP (a Lisp symbol).
3107 If no value is specified for PROP, look for an X default for XPROP
3108 on the frame named NAME.
3109 If that is not found either, use the value DEFLT. */
3110
3111 static Lisp_Object
3112 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3113 struct frame *f;
3114 Lisp_Object alist;
3115 Lisp_Object prop;
3116 Lisp_Object deflt;
3117 char *xprop;
3118 char *xclass;
3119 enum resource_types type;
3120 {
3121 Lisp_Object tem;
3122
3123 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3124 if (EQ (tem, Qunbound))
3125 tem = deflt;
3126 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3127 return tem;
3128 }
3129 \f
3130 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3131 doc: /* Parse an X-style geometry string STRING.
3132 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3133 The properties returned may include `top', `left', `height', and `width'.
3134 The value of `left' or `top' may be an integer,
3135 or a list (+ N) meaning N pixels relative to top/left corner,
3136 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3137 (string)
3138 Lisp_Object string;
3139 {
3140 int geometry, x, y;
3141 unsigned int width, height;
3142 Lisp_Object result;
3143
3144 CHECK_STRING (string);
3145
3146 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3147 &x, &y, &width, &height);
3148
3149 result = Qnil;
3150 if (geometry & XValue)
3151 {
3152 Lisp_Object element;
3153
3154 if (x >= 0 && (geometry & XNegative))
3155 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3156 else if (x < 0 && ! (geometry & XNegative))
3157 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3158 else
3159 element = Fcons (Qleft, make_number (x));
3160 result = Fcons (element, result);
3161 }
3162
3163 if (geometry & YValue)
3164 {
3165 Lisp_Object element;
3166
3167 if (y >= 0 && (geometry & YNegative))
3168 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3169 else if (y < 0 && ! (geometry & YNegative))
3170 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3171 else
3172 element = Fcons (Qtop, make_number (y));
3173 result = Fcons (element, result);
3174 }
3175
3176 if (geometry & WidthValue)
3177 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3178 if (geometry & HeightValue)
3179 result = Fcons (Fcons (Qheight, make_number (height)), result);
3180
3181 return result;
3182 }
3183
3184 /* Calculate the desired size and position of this window,
3185 and return the flags saying which aspects were specified.
3186
3187 This function does not make the coordinates positive. */
3188
3189 #define DEFAULT_ROWS 40
3190 #define DEFAULT_COLS 80
3191
3192 static int
3193 x_figure_window_size (f, parms)
3194 struct frame *f;
3195 Lisp_Object parms;
3196 {
3197 register Lisp_Object tem0, tem1, tem2;
3198 long window_prompting = 0;
3199
3200 /* Default values if we fall through.
3201 Actually, if that happens we should get
3202 window manager prompting. */
3203 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3204 f->height = DEFAULT_ROWS;
3205 /* Window managers expect that if program-specified
3206 positions are not (0,0), they're intentional, not defaults. */
3207 f->output_data.w32->top_pos = 0;
3208 f->output_data.w32->left_pos = 0;
3209
3210 /* Ensure that old new_width and new_height will not override the
3211 values set here. */
3212 FRAME_NEW_WIDTH (f) = 0;
3213 FRAME_NEW_HEIGHT (f) = 0;
3214
3215 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3216 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3217 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3218 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3219 {
3220 if (!EQ (tem0, Qunbound))
3221 {
3222 CHECK_NUMBER (tem0);
3223 f->height = XINT (tem0);
3224 }
3225 if (!EQ (tem1, Qunbound))
3226 {
3227 CHECK_NUMBER (tem1);
3228 SET_FRAME_WIDTH (f, XINT (tem1));
3229 }
3230 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3231 window_prompting |= USSize;
3232 else
3233 window_prompting |= PSize;
3234 }
3235
3236 f->output_data.w32->vertical_scroll_bar_extra
3237 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3238 ? 0
3239 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3240 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3241 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3242 f->output_data.w32->fringes_extra
3243 = FRAME_FRINGE_WIDTH (f);
3244 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3245 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3246
3247 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3248 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3249 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3250 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3251 {
3252 if (EQ (tem0, Qminus))
3253 {
3254 f->output_data.w32->top_pos = 0;
3255 window_prompting |= YNegative;
3256 }
3257 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3258 && CONSP (XCDR (tem0))
3259 && INTEGERP (XCAR (XCDR (tem0))))
3260 {
3261 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3262 window_prompting |= YNegative;
3263 }
3264 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3265 && CONSP (XCDR (tem0))
3266 && INTEGERP (XCAR (XCDR (tem0))))
3267 {
3268 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3269 }
3270 else if (EQ (tem0, Qunbound))
3271 f->output_data.w32->top_pos = 0;
3272 else
3273 {
3274 CHECK_NUMBER (tem0);
3275 f->output_data.w32->top_pos = XINT (tem0);
3276 if (f->output_data.w32->top_pos < 0)
3277 window_prompting |= YNegative;
3278 }
3279
3280 if (EQ (tem1, Qminus))
3281 {
3282 f->output_data.w32->left_pos = 0;
3283 window_prompting |= XNegative;
3284 }
3285 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3286 && CONSP (XCDR (tem1))
3287 && INTEGERP (XCAR (XCDR (tem1))))
3288 {
3289 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3290 window_prompting |= XNegative;
3291 }
3292 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3293 && CONSP (XCDR (tem1))
3294 && INTEGERP (XCAR (XCDR (tem1))))
3295 {
3296 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3297 }
3298 else if (EQ (tem1, Qunbound))
3299 f->output_data.w32->left_pos = 0;
3300 else
3301 {
3302 CHECK_NUMBER (tem1);
3303 f->output_data.w32->left_pos = XINT (tem1);
3304 if (f->output_data.w32->left_pos < 0)
3305 window_prompting |= XNegative;
3306 }
3307
3308 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3309 window_prompting |= USPosition;
3310 else
3311 window_prompting |= PPosition;
3312 }
3313
3314 return window_prompting;
3315 }
3316
3317 \f
3318
3319 extern LRESULT CALLBACK w32_wnd_proc ();
3320
3321 BOOL
3322 w32_init_class (hinst)
3323 HINSTANCE hinst;
3324 {
3325 WNDCLASS wc;
3326
3327 wc.style = CS_HREDRAW | CS_VREDRAW;
3328 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3329 wc.cbClsExtra = 0;
3330 wc.cbWndExtra = WND_EXTRA_BYTES;
3331 wc.hInstance = hinst;
3332 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3333 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3334 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3335 wc.lpszMenuName = NULL;
3336 wc.lpszClassName = EMACS_CLASS;
3337
3338 return (RegisterClass (&wc));
3339 }
3340
3341 HWND
3342 w32_createscrollbar (f, bar)
3343 struct frame *f;
3344 struct scroll_bar * bar;
3345 {
3346 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3347 /* Position and size of scroll bar. */
3348 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3349 XINT(bar->top),
3350 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3351 XINT(bar->height),
3352 FRAME_W32_WINDOW (f),
3353 NULL,
3354 hinst,
3355 NULL));
3356 }
3357
3358 void
3359 w32_createwindow (f)
3360 struct frame *f;
3361 {
3362 HWND hwnd;
3363 RECT rect;
3364
3365 rect.left = rect.top = 0;
3366 rect.right = PIXEL_WIDTH (f);
3367 rect.bottom = PIXEL_HEIGHT (f);
3368
3369 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3370 FRAME_EXTERNAL_MENU_BAR (f));
3371
3372 /* Do first time app init */
3373
3374 if (!hprevinst)
3375 {
3376 w32_init_class (hinst);
3377 }
3378
3379 FRAME_W32_WINDOW (f) = hwnd
3380 = CreateWindow (EMACS_CLASS,
3381 f->namebuf,
3382 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3383 f->output_data.w32->left_pos,
3384 f->output_data.w32->top_pos,
3385 rect.right - rect.left,
3386 rect.bottom - rect.top,
3387 NULL,
3388 NULL,
3389 hinst,
3390 NULL);
3391
3392 if (hwnd)
3393 {
3394 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3395 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3396 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3397 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3398 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3399
3400 /* Enable drag-n-drop. */
3401 DragAcceptFiles (hwnd, TRUE);
3402
3403 /* Do this to discard the default setting specified by our parent. */
3404 ShowWindow (hwnd, SW_HIDE);
3405 }
3406 }
3407
3408 void
3409 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3410 W32Msg * wmsg;
3411 HWND hwnd;
3412 UINT msg;
3413 WPARAM wParam;
3414 LPARAM lParam;
3415 {
3416 wmsg->msg.hwnd = hwnd;
3417 wmsg->msg.message = msg;
3418 wmsg->msg.wParam = wParam;
3419 wmsg->msg.lParam = lParam;
3420 wmsg->msg.time = GetMessageTime ();
3421
3422 post_msg (wmsg);
3423 }
3424
3425 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3426 between left and right keys as advertised. We test for this
3427 support dynamically, and set a flag when the support is absent. If
3428 absent, we keep track of the left and right control and alt keys
3429 ourselves. This is particularly necessary on keyboards that rely
3430 upon the AltGr key, which is represented as having the left control
3431 and right alt keys pressed. For these keyboards, we need to know
3432 when the left alt key has been pressed in addition to the AltGr key
3433 so that we can properly support M-AltGr-key sequences (such as M-@
3434 on Swedish keyboards). */
3435
3436 #define EMACS_LCONTROL 0
3437 #define EMACS_RCONTROL 1
3438 #define EMACS_LMENU 2
3439 #define EMACS_RMENU 3
3440
3441 static int modifiers[4];
3442 static int modifiers_recorded;
3443 static int modifier_key_support_tested;
3444
3445 static void
3446 test_modifier_support (unsigned int wparam)
3447 {
3448 unsigned int l, r;
3449
3450 if (wparam != VK_CONTROL && wparam != VK_MENU)
3451 return;
3452 if (wparam == VK_CONTROL)
3453 {
3454 l = VK_LCONTROL;
3455 r = VK_RCONTROL;
3456 }
3457 else
3458 {
3459 l = VK_LMENU;
3460 r = VK_RMENU;
3461 }
3462 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3463 modifiers_recorded = 1;
3464 else
3465 modifiers_recorded = 0;
3466 modifier_key_support_tested = 1;
3467 }
3468
3469 static void
3470 record_keydown (unsigned int wparam, unsigned int lparam)
3471 {
3472 int i;
3473
3474 if (!modifier_key_support_tested)
3475 test_modifier_support (wparam);
3476
3477 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3478 return;
3479
3480 if (wparam == VK_CONTROL)
3481 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3482 else
3483 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3484
3485 modifiers[i] = 1;
3486 }
3487
3488 static void
3489 record_keyup (unsigned int wparam, unsigned int lparam)
3490 {
3491 int i;
3492
3493 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3494 return;
3495
3496 if (wparam == VK_CONTROL)
3497 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3498 else
3499 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3500
3501 modifiers[i] = 0;
3502 }
3503
3504 /* Emacs can lose focus while a modifier key has been pressed. When
3505 it regains focus, be conservative and clear all modifiers since
3506 we cannot reconstruct the left and right modifier state. */
3507 static void
3508 reset_modifiers ()
3509 {
3510 SHORT ctrl, alt;
3511
3512 if (GetFocus () == NULL)
3513 /* Emacs doesn't have keyboard focus. Do nothing. */
3514 return;
3515
3516 ctrl = GetAsyncKeyState (VK_CONTROL);
3517 alt = GetAsyncKeyState (VK_MENU);
3518
3519 if (!(ctrl & 0x08000))
3520 /* Clear any recorded control modifier state. */
3521 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3522
3523 if (!(alt & 0x08000))
3524 /* Clear any recorded alt modifier state. */
3525 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3526
3527 /* Update the state of all modifier keys, because modifiers used in
3528 hot-key combinations can get stuck on if Emacs loses focus as a
3529 result of a hot-key being pressed. */
3530 {
3531 BYTE keystate[256];
3532
3533 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3534
3535 GetKeyboardState (keystate);
3536 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3537 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3538 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3539 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3540 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3541 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3542 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3543 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3544 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3545 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3546 SetKeyboardState (keystate);
3547 }
3548 }
3549
3550 /* Synchronize modifier state with what is reported with the current
3551 keystroke. Even if we cannot distinguish between left and right
3552 modifier keys, we know that, if no modifiers are set, then neither
3553 the left or right modifier should be set. */
3554 static void
3555 sync_modifiers ()
3556 {
3557 if (!modifiers_recorded)
3558 return;
3559
3560 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3561 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3562
3563 if (!(GetKeyState (VK_MENU) & 0x8000))
3564 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3565 }
3566
3567 static int
3568 modifier_set (int vkey)
3569 {
3570 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3571 return (GetKeyState (vkey) & 0x1);
3572 if (!modifiers_recorded)
3573 return (GetKeyState (vkey) & 0x8000);
3574
3575 switch (vkey)
3576 {
3577 case VK_LCONTROL:
3578 return modifiers[EMACS_LCONTROL];
3579 case VK_RCONTROL:
3580 return modifiers[EMACS_RCONTROL];
3581 case VK_LMENU:
3582 return modifiers[EMACS_LMENU];
3583 case VK_RMENU:
3584 return modifiers[EMACS_RMENU];
3585 }
3586 return (GetKeyState (vkey) & 0x8000);
3587 }
3588
3589 /* Convert between the modifier bits W32 uses and the modifier bits
3590 Emacs uses. */
3591
3592 unsigned int
3593 w32_key_to_modifier (int key)
3594 {
3595 Lisp_Object key_mapping;
3596
3597 switch (key)
3598 {
3599 case VK_LWIN:
3600 key_mapping = Vw32_lwindow_modifier;
3601 break;
3602 case VK_RWIN:
3603 key_mapping = Vw32_rwindow_modifier;
3604 break;
3605 case VK_APPS:
3606 key_mapping = Vw32_apps_modifier;
3607 break;
3608 case VK_SCROLL:
3609 key_mapping = Vw32_scroll_lock_modifier;
3610 break;
3611 default:
3612 key_mapping = Qnil;
3613 }
3614
3615 /* NB. This code runs in the input thread, asychronously to the lisp
3616 thread, so we must be careful to ensure access to lisp data is
3617 thread-safe. The following code is safe because the modifier
3618 variable values are updated atomically from lisp and symbols are
3619 not relocated by GC. Also, we don't have to worry about seeing GC
3620 markbits here. */
3621 if (EQ (key_mapping, Qhyper))
3622 return hyper_modifier;
3623 if (EQ (key_mapping, Qsuper))
3624 return super_modifier;
3625 if (EQ (key_mapping, Qmeta))
3626 return meta_modifier;
3627 if (EQ (key_mapping, Qalt))
3628 return alt_modifier;
3629 if (EQ (key_mapping, Qctrl))
3630 return ctrl_modifier;
3631 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3632 return ctrl_modifier;
3633 if (EQ (key_mapping, Qshift))
3634 return shift_modifier;
3635
3636 /* Don't generate any modifier if not explicitly requested. */
3637 return 0;
3638 }
3639
3640 unsigned int
3641 w32_get_modifiers ()
3642 {
3643 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3644 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3645 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3646 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3647 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3648 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3649 (modifier_set (VK_MENU) ?
3650 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3651 }
3652
3653 /* We map the VK_* modifiers into console modifier constants
3654 so that we can use the same routines to handle both console
3655 and window input. */
3656
3657 static int
3658 construct_console_modifiers ()
3659 {
3660 int mods;
3661
3662 mods = 0;
3663 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3664 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3665 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3666 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3667 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3668 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3669 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3670 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3671 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3672 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3673 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3674
3675 return mods;
3676 }
3677
3678 static int
3679 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3680 {
3681 int mods;
3682
3683 /* Convert to emacs modifiers. */
3684 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3685
3686 return mods;
3687 }
3688
3689 unsigned int
3690 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3691 {
3692 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3693 return virt_key;
3694
3695 if (virt_key == VK_RETURN)
3696 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3697
3698 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3699 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3700
3701 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3702 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3703
3704 if (virt_key == VK_CLEAR)
3705 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3706
3707 return virt_key;
3708 }
3709
3710 /* List of special key combinations which w32 would normally capture,
3711 but emacs should grab instead. Not directly visible to lisp, to
3712 simplify synchronization. Each item is an integer encoding a virtual
3713 key code and modifier combination to capture. */
3714 Lisp_Object w32_grabbed_keys;
3715
3716 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3717 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3718 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3719 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3720
3721 /* Register hot-keys for reserved key combinations when Emacs has
3722 keyboard focus, since this is the only way Emacs can receive key
3723 combinations like Alt-Tab which are used by the system. */
3724
3725 static void
3726 register_hot_keys (hwnd)
3727 HWND hwnd;
3728 {
3729 Lisp_Object keylist;
3730
3731 /* Use GC_CONSP, since we are called asynchronously. */
3732 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3733 {
3734 Lisp_Object key = XCAR (keylist);
3735
3736 /* Deleted entries get set to nil. */
3737 if (!INTEGERP (key))
3738 continue;
3739
3740 RegisterHotKey (hwnd, HOTKEY_ID (key),
3741 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3742 }
3743 }
3744
3745 static void
3746 unregister_hot_keys (hwnd)
3747 HWND hwnd;
3748 {
3749 Lisp_Object keylist;
3750
3751 /* Use GC_CONSP, since we are called asynchronously. */
3752 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3753 {
3754 Lisp_Object key = XCAR (keylist);
3755
3756 if (!INTEGERP (key))
3757 continue;
3758
3759 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3760 }
3761 }
3762
3763 /* Main message dispatch loop. */
3764
3765 static void
3766 w32_msg_pump (deferred_msg * msg_buf)
3767 {
3768 MSG msg;
3769 int result;
3770 HWND focus_window;
3771
3772 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3773
3774 while (GetMessage (&msg, NULL, 0, 0))
3775 {
3776 if (msg.hwnd == NULL)
3777 {
3778 switch (msg.message)
3779 {
3780 case WM_NULL:
3781 /* Produced by complete_deferred_msg; just ignore. */
3782 break;
3783 case WM_EMACS_CREATEWINDOW:
3784 w32_createwindow ((struct frame *) msg.wParam);
3785 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3786 abort ();
3787 break;
3788 case WM_EMACS_SETLOCALE:
3789 SetThreadLocale (msg.wParam);
3790 /* Reply is not expected. */
3791 break;
3792 case WM_EMACS_SETKEYBOARDLAYOUT:
3793 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3794 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3795 result, 0))
3796 abort ();
3797 break;
3798 case WM_EMACS_REGISTER_HOT_KEY:
3799 focus_window = GetFocus ();
3800 if (focus_window != NULL)
3801 RegisterHotKey (focus_window,
3802 HOTKEY_ID (msg.wParam),
3803 HOTKEY_MODIFIERS (msg.wParam),
3804 HOTKEY_VK_CODE (msg.wParam));
3805 /* Reply is not expected. */
3806 break;
3807 case WM_EMACS_UNREGISTER_HOT_KEY:
3808 focus_window = GetFocus ();
3809 if (focus_window != NULL)
3810 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3811 /* Mark item as erased. NB: this code must be
3812 thread-safe. The next line is okay because the cons
3813 cell is never made into garbage and is not relocated by
3814 GC. */
3815 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
3816 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3817 abort ();
3818 break;
3819 case WM_EMACS_TOGGLE_LOCK_KEY:
3820 {
3821 int vk_code = (int) msg.wParam;
3822 int cur_state = (GetKeyState (vk_code) & 1);
3823 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3824
3825 /* NB: This code must be thread-safe. It is safe to
3826 call NILP because symbols are not relocated by GC,
3827 and pointer here is not touched by GC (so the markbit
3828 can't be set). Numbers are safe because they are
3829 immediate values. */
3830 if (NILP (new_state)
3831 || (NUMBERP (new_state)
3832 && ((XUINT (new_state)) & 1) != cur_state))
3833 {
3834 one_w32_display_info.faked_key = vk_code;
3835
3836 keybd_event ((BYTE) vk_code,
3837 (BYTE) MapVirtualKey (vk_code, 0),
3838 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3839 keybd_event ((BYTE) vk_code,
3840 (BYTE) MapVirtualKey (vk_code, 0),
3841 KEYEVENTF_EXTENDEDKEY | 0, 0);
3842 keybd_event ((BYTE) vk_code,
3843 (BYTE) MapVirtualKey (vk_code, 0),
3844 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3845 cur_state = !cur_state;
3846 }
3847 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3848 cur_state, 0))
3849 abort ();
3850 }
3851 break;
3852 default:
3853 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3854 }
3855 }
3856 else
3857 {
3858 DispatchMessage (&msg);
3859 }
3860
3861 /* Exit nested loop when our deferred message has completed. */
3862 if (msg_buf->completed)
3863 break;
3864 }
3865 }
3866
3867 deferred_msg * deferred_msg_head;
3868
3869 static deferred_msg *
3870 find_deferred_msg (HWND hwnd, UINT msg)
3871 {
3872 deferred_msg * item;
3873
3874 /* Don't actually need synchronization for read access, since
3875 modification of single pointer is always atomic. */
3876 /* enter_crit (); */
3877
3878 for (item = deferred_msg_head; item != NULL; item = item->next)
3879 if (item->w32msg.msg.hwnd == hwnd
3880 && item->w32msg.msg.message == msg)
3881 break;
3882
3883 /* leave_crit (); */
3884
3885 return item;
3886 }
3887
3888 static LRESULT
3889 send_deferred_msg (deferred_msg * msg_buf,
3890 HWND hwnd,
3891 UINT msg,
3892 WPARAM wParam,
3893 LPARAM lParam)
3894 {
3895 /* Only input thread can send deferred messages. */
3896 if (GetCurrentThreadId () != dwWindowsThreadId)
3897 abort ();
3898
3899 /* It is an error to send a message that is already deferred. */
3900 if (find_deferred_msg (hwnd, msg) != NULL)
3901 abort ();
3902
3903 /* Enforced synchronization is not needed because this is the only
3904 function that alters deferred_msg_head, and the following critical
3905 section is guaranteed to only be serially reentered (since only the
3906 input thread can call us). */
3907
3908 /* enter_crit (); */
3909
3910 msg_buf->completed = 0;
3911 msg_buf->next = deferred_msg_head;
3912 deferred_msg_head = msg_buf;
3913 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
3914
3915 /* leave_crit (); */
3916
3917 /* Start a new nested message loop to process other messages until
3918 this one is completed. */
3919 w32_msg_pump (msg_buf);
3920
3921 deferred_msg_head = msg_buf->next;
3922
3923 return msg_buf->result;
3924 }
3925
3926 void
3927 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
3928 {
3929 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
3930
3931 if (msg_buf == NULL)
3932 /* Message may have been cancelled, so don't abort(). */
3933 return;
3934
3935 msg_buf->result = result;
3936 msg_buf->completed = 1;
3937
3938 /* Ensure input thread is woken so it notices the completion. */
3939 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3940 }
3941
3942 void
3943 cancel_all_deferred_msgs ()
3944 {
3945 deferred_msg * item;
3946
3947 /* Don't actually need synchronization for read access, since
3948 modification of single pointer is always atomic. */
3949 /* enter_crit (); */
3950
3951 for (item = deferred_msg_head; item != NULL; item = item->next)
3952 {
3953 item->result = 0;
3954 item->completed = 1;
3955 }
3956
3957 /* leave_crit (); */
3958
3959 /* Ensure input thread is woken so it notices the completion. */
3960 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
3961 }
3962
3963 DWORD
3964 w32_msg_worker (dw)
3965 DWORD dw;
3966 {
3967 MSG msg;
3968 deferred_msg dummy_buf;
3969
3970 /* Ensure our message queue is created */
3971
3972 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
3973
3974 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3975 abort ();
3976
3977 memset (&dummy_buf, 0, sizeof (dummy_buf));
3978 dummy_buf.w32msg.msg.hwnd = NULL;
3979 dummy_buf.w32msg.msg.message = WM_NULL;
3980
3981 /* This is the inital message loop which should only exit when the
3982 application quits. */
3983 w32_msg_pump (&dummy_buf);
3984
3985 return 0;
3986 }
3987
3988 static void
3989 post_character_message (hwnd, msg, wParam, lParam, modifiers)
3990 HWND hwnd;
3991 UINT msg;
3992 WPARAM wParam;
3993 LPARAM lParam;
3994 DWORD modifiers;
3995
3996 {
3997 W32Msg wmsg;
3998
3999 wmsg.dwModifiers = modifiers;
4000
4001 /* Detect quit_char and set quit-flag directly. Note that we
4002 still need to post a message to ensure the main thread will be
4003 woken up if blocked in sys_select(), but we do NOT want to post
4004 the quit_char message itself (because it will usually be as if
4005 the user had typed quit_char twice). Instead, we post a dummy
4006 message that has no particular effect. */
4007 {
4008 int c = wParam;
4009 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4010 c = make_ctrl_char (c) & 0377;
4011 if (c == quit_char
4012 || (wmsg.dwModifiers == 0 &&
4013 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
4014 {
4015 Vquit_flag = Qt;
4016
4017 /* The choice of message is somewhat arbitrary, as long as
4018 the main thread handler just ignores it. */
4019 msg = WM_NULL;
4020
4021 /* Interrupt any blocking system calls. */
4022 signal_quit ();
4023
4024 /* As a safety precaution, forcibly complete any deferred
4025 messages. This is a kludge, but I don't see any particularly
4026 clean way to handle the situation where a deferred message is
4027 "dropped" in the lisp thread, and will thus never be
4028 completed, eg. by the user trying to activate the menubar
4029 when the lisp thread is busy, and then typing C-g when the
4030 menubar doesn't open promptly (with the result that the
4031 menubar never responds at all because the deferred
4032 WM_INITMENU message is never completed). Another problem
4033 situation is when the lisp thread calls SendMessage (to send
4034 a window manager command) when a message has been deferred;
4035 the lisp thread gets blocked indefinitely waiting for the
4036 deferred message to be completed, which itself is waiting for
4037 the lisp thread to respond.
4038
4039 Note that we don't want to block the input thread waiting for
4040 a reponse from the lisp thread (although that would at least
4041 solve the deadlock problem above), because we want to be able
4042 to receive C-g to interrupt the lisp thread. */
4043 cancel_all_deferred_msgs ();
4044 }
4045 }
4046
4047 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4048 }
4049
4050 /* Main window procedure */
4051
4052 LRESULT CALLBACK
4053 w32_wnd_proc (hwnd, msg, wParam, lParam)
4054 HWND hwnd;
4055 UINT msg;
4056 WPARAM wParam;
4057 LPARAM lParam;
4058 {
4059 struct frame *f;
4060 struct w32_display_info *dpyinfo = &one_w32_display_info;
4061 W32Msg wmsg;
4062 int windows_translate;
4063 int key;
4064
4065 /* Note that it is okay to call x_window_to_frame, even though we are
4066 not running in the main lisp thread, because frame deletion
4067 requires the lisp thread to synchronize with this thread. Thus, if
4068 a frame struct is returned, it can be used without concern that the
4069 lisp thread might make it disappear while we are using it.
4070
4071 NB. Walking the frame list in this thread is safe (as long as
4072 writes of Lisp_Object slots are atomic, which they are on Windows).
4073 Although delete-frame can destructively modify the frame list while
4074 we are walking it, a garbage collection cannot occur until after
4075 delete-frame has synchronized with this thread.
4076
4077 It is also safe to use functions that make GDI calls, such as
4078 w32_clear_rect, because these functions must obtain a DC handle
4079 from the frame struct using get_frame_dc which is thread-aware. */
4080
4081 switch (msg)
4082 {
4083 case WM_ERASEBKGND:
4084 f = x_window_to_frame (dpyinfo, hwnd);
4085 if (f)
4086 {
4087 HDC hdc = get_frame_dc (f);
4088 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4089 w32_clear_rect (f, hdc, &wmsg.rect);
4090 release_frame_dc (f, hdc);
4091
4092 #if defined (W32_DEBUG_DISPLAY)
4093 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4094 f,
4095 wmsg.rect.left, wmsg.rect.top,
4096 wmsg.rect.right, wmsg.rect.bottom));
4097 #endif /* W32_DEBUG_DISPLAY */
4098 }
4099 return 1;
4100 case WM_PALETTECHANGED:
4101 /* ignore our own changes */
4102 if ((HWND)wParam != hwnd)
4103 {
4104 f = x_window_to_frame (dpyinfo, hwnd);
4105 if (f)
4106 /* get_frame_dc will realize our palette and force all
4107 frames to be redrawn if needed. */
4108 release_frame_dc (f, get_frame_dc (f));
4109 }
4110 return 0;
4111 case WM_PAINT:
4112 {
4113 PAINTSTRUCT paintStruct;
4114 RECT update_rect;
4115
4116 f = x_window_to_frame (dpyinfo, hwnd);
4117 if (f == 0)
4118 {
4119 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4120 return 0;
4121 }
4122
4123 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4124 fails. Apparently this can happen under some
4125 circumstances. */
4126 if (!w32_strict_painting || GetUpdateRect (hwnd, &update_rect, FALSE))
4127 {
4128 enter_crit ();
4129 BeginPaint (hwnd, &paintStruct);
4130
4131 if (w32_strict_painting)
4132 /* The rectangles returned by GetUpdateRect and BeginPaint
4133 do not always match. GetUpdateRect seems to be the
4134 more reliable of the two. */
4135 wmsg.rect = update_rect;
4136 else
4137 wmsg.rect = paintStruct.rcPaint;
4138
4139 #if defined (W32_DEBUG_DISPLAY)
4140 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4141 f,
4142 wmsg.rect.left, wmsg.rect.top,
4143 wmsg.rect.right, wmsg.rect.bottom));
4144 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4145 update_rect.left, update_rect.top,
4146 update_rect.right, update_rect.bottom));
4147 #endif
4148 EndPaint (hwnd, &paintStruct);
4149 leave_crit ();
4150
4151 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4152
4153 return 0;
4154 }
4155
4156 /* If GetUpdateRect returns 0 (meaning there is no update
4157 region), assume the whole window needs to be repainted. */
4158 GetClientRect(hwnd, &wmsg.rect);
4159 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4160 return 0;
4161 }
4162
4163 case WM_INPUTLANGCHANGE:
4164 /* Inform lisp thread of keyboard layout changes. */
4165 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4166
4167 /* Clear dead keys in the keyboard state; for simplicity only
4168 preserve modifier key states. */
4169 {
4170 int i;
4171 BYTE keystate[256];
4172
4173 GetKeyboardState (keystate);
4174 for (i = 0; i < 256; i++)
4175 if (1
4176 && i != VK_SHIFT
4177 && i != VK_LSHIFT
4178 && i != VK_RSHIFT
4179 && i != VK_CAPITAL
4180 && i != VK_NUMLOCK
4181 && i != VK_SCROLL
4182 && i != VK_CONTROL
4183 && i != VK_LCONTROL
4184 && i != VK_RCONTROL
4185 && i != VK_MENU
4186 && i != VK_LMENU
4187 && i != VK_RMENU
4188 && i != VK_LWIN
4189 && i != VK_RWIN)
4190 keystate[i] = 0;
4191 SetKeyboardState (keystate);
4192 }
4193 goto dflt;
4194
4195 case WM_HOTKEY:
4196 /* Synchronize hot keys with normal input. */
4197 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4198 return (0);
4199
4200 case WM_KEYUP:
4201 case WM_SYSKEYUP:
4202 record_keyup (wParam, lParam);
4203 goto dflt;
4204
4205 case WM_KEYDOWN:
4206 case WM_SYSKEYDOWN:
4207 /* Ignore keystrokes we fake ourself; see below. */
4208 if (dpyinfo->faked_key == wParam)
4209 {
4210 dpyinfo->faked_key = 0;
4211 /* Make sure TranslateMessage sees them though (as long as
4212 they don't produce WM_CHAR messages). This ensures that
4213 indicator lights are toggled promptly on Windows 9x, for
4214 example. */
4215 if (lispy_function_keys[wParam] != 0)
4216 {
4217 windows_translate = 1;
4218 goto translate;
4219 }
4220 return 0;
4221 }
4222
4223 /* Synchronize modifiers with current keystroke. */
4224 sync_modifiers ();
4225 record_keydown (wParam, lParam);
4226 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4227
4228 windows_translate = 0;
4229
4230 switch (wParam)
4231 {
4232 case VK_LWIN:
4233 if (NILP (Vw32_pass_lwindow_to_system))
4234 {
4235 /* Prevent system from acting on keyup (which opens the
4236 Start menu if no other key was pressed) by simulating a
4237 press of Space which we will ignore. */
4238 if (GetAsyncKeyState (wParam) & 1)
4239 {
4240 if (NUMBERP (Vw32_phantom_key_code))
4241 key = XUINT (Vw32_phantom_key_code) & 255;
4242 else
4243 key = VK_SPACE;
4244 dpyinfo->faked_key = key;
4245 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4246 }
4247 }
4248 if (!NILP (Vw32_lwindow_modifier))
4249 return 0;
4250 break;
4251 case VK_RWIN:
4252 if (NILP (Vw32_pass_rwindow_to_system))
4253 {
4254 if (GetAsyncKeyState (wParam) & 1)
4255 {
4256 if (NUMBERP (Vw32_phantom_key_code))
4257 key = XUINT (Vw32_phantom_key_code) & 255;
4258 else
4259 key = VK_SPACE;
4260 dpyinfo->faked_key = key;
4261 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4262 }
4263 }
4264 if (!NILP (Vw32_rwindow_modifier))
4265 return 0;
4266 break;
4267 case VK_APPS:
4268 if (!NILP (Vw32_apps_modifier))
4269 return 0;
4270 break;
4271 case VK_MENU:
4272 if (NILP (Vw32_pass_alt_to_system))
4273 /* Prevent DefWindowProc from activating the menu bar if an
4274 Alt key is pressed and released by itself. */
4275 return 0;
4276 windows_translate = 1;
4277 break;
4278 case VK_CAPITAL:
4279 /* Decide whether to treat as modifier or function key. */
4280 if (NILP (Vw32_enable_caps_lock))
4281 goto disable_lock_key;
4282 windows_translate = 1;
4283 break;
4284 case VK_NUMLOCK:
4285 /* Decide whether to treat as modifier or function key. */
4286 if (NILP (Vw32_enable_num_lock))
4287 goto disable_lock_key;
4288 windows_translate = 1;
4289 break;
4290 case VK_SCROLL:
4291 /* Decide whether to treat as modifier or function key. */
4292 if (NILP (Vw32_scroll_lock_modifier))
4293 goto disable_lock_key;
4294 windows_translate = 1;
4295 break;
4296 disable_lock_key:
4297 /* Ensure the appropriate lock key state (and indicator light)
4298 remains in the same state. We do this by faking another
4299 press of the relevant key. Apparently, this really is the
4300 only way to toggle the state of the indicator lights. */
4301 dpyinfo->faked_key = wParam;
4302 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4303 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4304 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4305 KEYEVENTF_EXTENDEDKEY | 0, 0);
4306 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4307 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4308 /* Ensure indicator lights are updated promptly on Windows 9x
4309 (TranslateMessage apparently does this), after forwarding
4310 input event. */
4311 post_character_message (hwnd, msg, wParam, lParam,
4312 w32_get_key_modifiers (wParam, lParam));
4313 windows_translate = 1;
4314 break;
4315 case VK_CONTROL:
4316 case VK_SHIFT:
4317 case VK_PROCESSKEY: /* Generated by IME. */
4318 windows_translate = 1;
4319 break;
4320 case VK_CANCEL:
4321 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4322 which is confusing for purposes of key binding; convert
4323 VK_CANCEL events into VK_PAUSE events. */
4324 wParam = VK_PAUSE;
4325 break;
4326 case VK_PAUSE:
4327 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4328 for purposes of key binding; convert these back into
4329 VK_NUMLOCK events, at least when we want to see NumLock key
4330 presses. (Note that there is never any possibility that
4331 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4332 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4333 wParam = VK_NUMLOCK;
4334 break;
4335 default:
4336 /* If not defined as a function key, change it to a WM_CHAR message. */
4337 if (lispy_function_keys[wParam] == 0)
4338 {
4339 DWORD modifiers = construct_console_modifiers ();
4340
4341 if (!NILP (Vw32_recognize_altgr)
4342 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4343 {
4344 /* Always let TranslateMessage handle AltGr key chords;
4345 for some reason, ToAscii doesn't always process AltGr
4346 chords correctly. */
4347 windows_translate = 1;
4348 }
4349 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4350 {
4351 /* Handle key chords including any modifiers other
4352 than shift directly, in order to preserve as much
4353 modifier information as possible. */
4354 if ('A' <= wParam && wParam <= 'Z')
4355 {
4356 /* Don't translate modified alphabetic keystrokes,
4357 so the user doesn't need to constantly switch
4358 layout to type control or meta keystrokes when
4359 the normal layout translates alphabetic
4360 characters to non-ascii characters. */
4361 if (!modifier_set (VK_SHIFT))
4362 wParam += ('a' - 'A');
4363 msg = WM_CHAR;
4364 }
4365 else
4366 {
4367 /* Try to handle other keystrokes by determining the
4368 base character (ie. translating the base key plus
4369 shift modifier). */
4370 int add;
4371 int isdead = 0;
4372 KEY_EVENT_RECORD key;
4373
4374 key.bKeyDown = TRUE;
4375 key.wRepeatCount = 1;
4376 key.wVirtualKeyCode = wParam;
4377 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4378 key.uChar.AsciiChar = 0;
4379 key.dwControlKeyState = modifiers;
4380
4381 add = w32_kbd_patch_key (&key);
4382 /* 0 means an unrecognised keycode, negative means
4383 dead key. Ignore both. */
4384 while (--add >= 0)
4385 {
4386 /* Forward asciified character sequence. */
4387 post_character_message
4388 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4389 w32_get_key_modifiers (wParam, lParam));
4390 w32_kbd_patch_key (&key);
4391 }
4392 return 0;
4393 }
4394 }
4395 else
4396 {
4397 /* Let TranslateMessage handle everything else. */
4398 windows_translate = 1;
4399 }
4400 }
4401 }
4402
4403 translate:
4404 if (windows_translate)
4405 {
4406 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4407
4408 windows_msg.time = GetMessageTime ();
4409 TranslateMessage (&windows_msg);
4410 goto dflt;
4411 }
4412
4413 /* Fall through */
4414
4415 case WM_SYSCHAR:
4416 case WM_CHAR:
4417 post_character_message (hwnd, msg, wParam, lParam,
4418 w32_get_key_modifiers (wParam, lParam));
4419 break;
4420
4421 /* Simulate middle mouse button events when left and right buttons
4422 are used together, but only if user has two button mouse. */
4423 case WM_LBUTTONDOWN:
4424 case WM_RBUTTONDOWN:
4425 if (XINT (Vw32_num_mouse_buttons) > 2)
4426 goto handle_plain_button;
4427
4428 {
4429 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4430 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4431
4432 if (button_state & this)
4433 return 0;
4434
4435 if (button_state == 0)
4436 SetCapture (hwnd);
4437
4438 button_state |= this;
4439
4440 if (button_state & other)
4441 {
4442 if (mouse_button_timer)
4443 {
4444 KillTimer (hwnd, mouse_button_timer);
4445 mouse_button_timer = 0;
4446
4447 /* Generate middle mouse event instead. */
4448 msg = WM_MBUTTONDOWN;
4449 button_state |= MMOUSE;
4450 }
4451 else if (button_state & MMOUSE)
4452 {
4453 /* Ignore button event if we've already generated a
4454 middle mouse down event. This happens if the
4455 user releases and press one of the two buttons
4456 after we've faked a middle mouse event. */
4457 return 0;
4458 }
4459 else
4460 {
4461 /* Flush out saved message. */
4462 post_msg (&saved_mouse_button_msg);
4463 }
4464 wmsg.dwModifiers = w32_get_modifiers ();
4465 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4466
4467 /* Clear message buffer. */
4468 saved_mouse_button_msg.msg.hwnd = 0;
4469 }
4470 else
4471 {
4472 /* Hold onto message for now. */
4473 mouse_button_timer =
4474 SetTimer (hwnd, MOUSE_BUTTON_ID,
4475 XINT (Vw32_mouse_button_tolerance), NULL);
4476 saved_mouse_button_msg.msg.hwnd = hwnd;
4477 saved_mouse_button_msg.msg.message = msg;
4478 saved_mouse_button_msg.msg.wParam = wParam;
4479 saved_mouse_button_msg.msg.lParam = lParam;
4480 saved_mouse_button_msg.msg.time = GetMessageTime ();
4481 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4482 }
4483 }
4484 return 0;
4485
4486 case WM_LBUTTONUP:
4487 case WM_RBUTTONUP:
4488 if (XINT (Vw32_num_mouse_buttons) > 2)
4489 goto handle_plain_button;
4490
4491 {
4492 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4493 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4494
4495 if ((button_state & this) == 0)
4496 return 0;
4497
4498 button_state &= ~this;
4499
4500 if (button_state & MMOUSE)
4501 {
4502 /* Only generate event when second button is released. */
4503 if ((button_state & other) == 0)
4504 {
4505 msg = WM_MBUTTONUP;
4506 button_state &= ~MMOUSE;
4507
4508 if (button_state) abort ();
4509 }
4510 else
4511 return 0;
4512 }
4513 else
4514 {
4515 /* Flush out saved message if necessary. */
4516 if (saved_mouse_button_msg.msg.hwnd)
4517 {
4518 post_msg (&saved_mouse_button_msg);
4519 }
4520 }
4521 wmsg.dwModifiers = w32_get_modifiers ();
4522 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4523
4524 /* Always clear message buffer and cancel timer. */
4525 saved_mouse_button_msg.msg.hwnd = 0;
4526 KillTimer (hwnd, mouse_button_timer);
4527 mouse_button_timer = 0;
4528
4529 if (button_state == 0)
4530 ReleaseCapture ();
4531 }
4532 return 0;
4533
4534 case WM_MBUTTONDOWN:
4535 case WM_MBUTTONUP:
4536 handle_plain_button:
4537 {
4538 BOOL up;
4539 int button;
4540
4541 if (parse_button (msg, &button, &up))
4542 {
4543 if (up) ReleaseCapture ();
4544 else SetCapture (hwnd);
4545 button = (button == 0) ? LMOUSE :
4546 ((button == 1) ? MMOUSE : RMOUSE);
4547 if (up)
4548 button_state &= ~button;
4549 else
4550 button_state |= button;
4551 }
4552 }
4553
4554 wmsg.dwModifiers = w32_get_modifiers ();
4555 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4556 return 0;
4557
4558 case WM_VSCROLL:
4559 case WM_MOUSEMOVE:
4560 if (XINT (Vw32_mouse_move_interval) <= 0
4561 || (msg == WM_MOUSEMOVE && button_state == 0))
4562 {
4563 wmsg.dwModifiers = w32_get_modifiers ();
4564 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4565 return 0;
4566 }
4567
4568 /* Hang onto mouse move and scroll messages for a bit, to avoid
4569 sending such events to Emacs faster than it can process them.
4570 If we get more events before the timer from the first message
4571 expires, we just replace the first message. */
4572
4573 if (saved_mouse_move_msg.msg.hwnd == 0)
4574 mouse_move_timer =
4575 SetTimer (hwnd, MOUSE_MOVE_ID,
4576 XINT (Vw32_mouse_move_interval), NULL);
4577
4578 /* Hold onto message for now. */
4579 saved_mouse_move_msg.msg.hwnd = hwnd;
4580 saved_mouse_move_msg.msg.message = msg;
4581 saved_mouse_move_msg.msg.wParam = wParam;
4582 saved_mouse_move_msg.msg.lParam = lParam;
4583 saved_mouse_move_msg.msg.time = GetMessageTime ();
4584 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4585
4586 return 0;
4587
4588 case WM_MOUSEWHEEL:
4589 wmsg.dwModifiers = w32_get_modifiers ();
4590 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4591 return 0;
4592
4593 case WM_DROPFILES:
4594 wmsg.dwModifiers = w32_get_modifiers ();
4595 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4596 return 0;
4597
4598 case WM_TIMER:
4599 /* Flush out saved messages if necessary. */
4600 if (wParam == mouse_button_timer)
4601 {
4602 if (saved_mouse_button_msg.msg.hwnd)
4603 {
4604 post_msg (&saved_mouse_button_msg);
4605 saved_mouse_button_msg.msg.hwnd = 0;
4606 }
4607 KillTimer (hwnd, mouse_button_timer);
4608 mouse_button_timer = 0;
4609 }
4610 else if (wParam == mouse_move_timer)
4611 {
4612 if (saved_mouse_move_msg.msg.hwnd)
4613 {
4614 post_msg (&saved_mouse_move_msg);
4615 saved_mouse_move_msg.msg.hwnd = 0;
4616 }
4617 KillTimer (hwnd, mouse_move_timer);
4618 mouse_move_timer = 0;
4619 }
4620 return 0;
4621
4622 case WM_NCACTIVATE:
4623 /* Windows doesn't send us focus messages when putting up and
4624 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4625 The only indication we get that something happened is receiving
4626 this message afterwards. So this is a good time to reset our
4627 keyboard modifiers' state. */
4628 reset_modifiers ();
4629 goto dflt;
4630
4631 case WM_INITMENU:
4632 button_state = 0;
4633 ReleaseCapture ();
4634 /* We must ensure menu bar is fully constructed and up to date
4635 before allowing user interaction with it. To achieve this
4636 we send this message to the lisp thread and wait for a
4637 reply (whose value is not actually needed) to indicate that
4638 the menu bar is now ready for use, so we can now return.
4639
4640 To remain responsive in the meantime, we enter a nested message
4641 loop that can process all other messages.
4642
4643 However, we skip all this if the message results from calling
4644 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4645 thread a message because it is blocked on us at this point. We
4646 set menubar_active before calling TrackPopupMenu to indicate
4647 this (there is no possibility of confusion with real menubar
4648 being active). */
4649
4650 f = x_window_to_frame (dpyinfo, hwnd);
4651 if (f
4652 && (f->output_data.w32->menubar_active
4653 /* We can receive this message even in the absence of a
4654 menubar (ie. when the system menu is activated) - in this
4655 case we do NOT want to forward the message, otherwise it
4656 will cause the menubar to suddenly appear when the user
4657 had requested it to be turned off! */
4658 || f->output_data.w32->menubar_widget == NULL))
4659 return 0;
4660
4661 {
4662 deferred_msg msg_buf;
4663
4664 /* Detect if message has already been deferred; in this case
4665 we cannot return any sensible value to ignore this. */
4666 if (find_deferred_msg (hwnd, msg) != NULL)
4667 abort ();
4668
4669 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4670 }
4671
4672 case WM_EXITMENULOOP:
4673 f = x_window_to_frame (dpyinfo, hwnd);
4674
4675 /* Indicate that menubar can be modified again. */
4676 if (f)
4677 f->output_data.w32->menubar_active = 0;
4678 goto dflt;
4679
4680 case WM_MENUSELECT:
4681 wmsg.dwModifiers = w32_get_modifiers ();
4682 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4683 return 0;
4684
4685 case WM_MEASUREITEM:
4686 f = x_window_to_frame (dpyinfo, hwnd);
4687 if (f)
4688 {
4689 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4690
4691 if (pMis->CtlType == ODT_MENU)
4692 {
4693 /* Work out dimensions for popup menu titles. */
4694 char * title = (char *) pMis->itemData;
4695 HDC hdc = GetDC (hwnd);
4696 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4697 LOGFONT menu_logfont;
4698 HFONT old_font;
4699 SIZE size;
4700
4701 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4702 menu_logfont.lfWeight = FW_BOLD;
4703 menu_font = CreateFontIndirect (&menu_logfont);
4704 old_font = SelectObject (hdc, menu_font);
4705
4706 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4707 if (title)
4708 {
4709 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4710 pMis->itemWidth = size.cx;
4711 if (pMis->itemHeight < size.cy)
4712 pMis->itemHeight = size.cy;
4713 }
4714 else
4715 pMis->itemWidth = 0;
4716
4717 SelectObject (hdc, old_font);
4718 DeleteObject (menu_font);
4719 ReleaseDC (hwnd, hdc);
4720 return TRUE;
4721 }
4722 }
4723 return 0;
4724
4725 case WM_DRAWITEM:
4726 f = x_window_to_frame (dpyinfo, hwnd);
4727 if (f)
4728 {
4729 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4730
4731 if (pDis->CtlType == ODT_MENU)
4732 {
4733 /* Draw popup menu title. */
4734 char * title = (char *) pDis->itemData;
4735 if (title)
4736 {
4737 HDC hdc = pDis->hDC;
4738 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4739 LOGFONT menu_logfont;
4740 HFONT old_font;
4741
4742 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4743 menu_logfont.lfWeight = FW_BOLD;
4744 menu_font = CreateFontIndirect (&menu_logfont);
4745 old_font = SelectObject (hdc, menu_font);
4746
4747 /* Always draw title as if not selected. */
4748 ExtTextOut (hdc,
4749 pDis->rcItem.left
4750 + GetSystemMetrics (SM_CXMENUCHECK),
4751 pDis->rcItem.top,
4752 ETO_OPAQUE, &pDis->rcItem,
4753 title, strlen (title), NULL);
4754
4755 SelectObject (hdc, old_font);
4756 DeleteObject (menu_font);
4757 }
4758 return TRUE;
4759 }
4760 }
4761 return 0;
4762
4763 #if 0
4764 /* Still not right - can't distinguish between clicks in the
4765 client area of the frame from clicks forwarded from the scroll
4766 bars - may have to hook WM_NCHITTEST to remember the mouse
4767 position and then check if it is in the client area ourselves. */
4768 case WM_MOUSEACTIVATE:
4769 /* Discard the mouse click that activates a frame, allowing the
4770 user to click anywhere without changing point (or worse!).
4771 Don't eat mouse clicks on scrollbars though!! */
4772 if (LOWORD (lParam) == HTCLIENT )
4773 return MA_ACTIVATEANDEAT;
4774 goto dflt;
4775 #endif
4776
4777 case WM_ACTIVATEAPP:
4778 case WM_ACTIVATE:
4779 case WM_WINDOWPOSCHANGED:
4780 case WM_SHOWWINDOW:
4781 /* Inform lisp thread that a frame might have just been obscured
4782 or exposed, so should recheck visibility of all frames. */
4783 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4784 goto dflt;
4785
4786 case WM_SETFOCUS:
4787 dpyinfo->faked_key = 0;
4788 reset_modifiers ();
4789 register_hot_keys (hwnd);
4790 goto command;
4791 case WM_KILLFOCUS:
4792 unregister_hot_keys (hwnd);
4793 button_state = 0;
4794 ReleaseCapture ();
4795 /* Relinquish the system caret. */
4796 if (w32_system_caret_hwnd)
4797 {
4798 DestroyCaret ();
4799 w32_system_caret_hwnd = NULL;
4800 }
4801 case WM_MOVE:
4802 case WM_SIZE:
4803 case WM_COMMAND:
4804 command:
4805 wmsg.dwModifiers = w32_get_modifiers ();
4806 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4807 goto dflt;
4808
4809 case WM_CLOSE:
4810 wmsg.dwModifiers = w32_get_modifiers ();
4811 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4812 return 0;
4813
4814 case WM_WINDOWPOSCHANGING:
4815 {
4816 WINDOWPLACEMENT wp;
4817 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
4818
4819 wp.length = sizeof (WINDOWPLACEMENT);
4820 GetWindowPlacement (hwnd, &wp);
4821
4822 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
4823 {
4824 RECT rect;
4825 int wdiff;
4826 int hdiff;
4827 DWORD font_width;
4828 DWORD line_height;
4829 DWORD internal_border;
4830 DWORD scrollbar_extra;
4831 RECT wr;
4832
4833 wp.length = sizeof(wp);
4834 GetWindowRect (hwnd, &wr);
4835
4836 enter_crit ();
4837
4838 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
4839 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
4840 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
4841 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
4842
4843 leave_crit ();
4844
4845 memset (&rect, 0, sizeof (rect));
4846 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
4847 GetMenu (hwnd) != NULL);
4848
4849 /* Force width and height of client area to be exact
4850 multiples of the character cell dimensions. */
4851 wdiff = (lppos->cx - (rect.right - rect.left)
4852 - 2 * internal_border - scrollbar_extra)
4853 % font_width;
4854 hdiff = (lppos->cy - (rect.bottom - rect.top)
4855 - 2 * internal_border)
4856 % line_height;
4857
4858 if (wdiff || hdiff)
4859 {
4860 /* For right/bottom sizing we can just fix the sizes.
4861 However for top/left sizing we will need to fix the X
4862 and Y positions as well. */
4863
4864 lppos->cx -= wdiff;
4865 lppos->cy -= hdiff;
4866
4867 if (wp.showCmd != SW_SHOWMAXIMIZED
4868 && (lppos->flags & SWP_NOMOVE) == 0)
4869 {
4870 if (lppos->x != wr.left || lppos->y != wr.top)
4871 {
4872 lppos->x += wdiff;
4873 lppos->y += hdiff;
4874 }
4875 else
4876 {
4877 lppos->flags |= SWP_NOMOVE;
4878 }
4879 }
4880
4881 return 0;
4882 }
4883 }
4884 }
4885
4886 goto dflt;
4887
4888 case WM_GETMINMAXINFO:
4889 /* Hack to correct bug that allows Emacs frames to be resized
4890 below the Minimum Tracking Size. */
4891 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
4892 /* Hack to allow resizing the Emacs frame above the screen size.
4893 Note that Windows 9x limits coordinates to 16-bits. */
4894 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
4895 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
4896 return 0;
4897
4898 case WM_EMACS_CREATESCROLLBAR:
4899 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
4900 (struct scroll_bar *) lParam);
4901
4902 case WM_EMACS_SHOWWINDOW:
4903 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
4904
4905 case WM_EMACS_SETFOREGROUND:
4906 {
4907 HWND foreground_window;
4908 DWORD foreground_thread, retval;
4909
4910 /* On NT 5.0, and apparently Windows 98, it is necessary to
4911 attach to the thread that currently has focus in order to
4912 pull the focus away from it. */
4913 foreground_window = GetForegroundWindow ();
4914 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
4915 if (!foreground_window
4916 || foreground_thread == GetCurrentThreadId ()
4917 || !AttachThreadInput (GetCurrentThreadId (),
4918 foreground_thread, TRUE))
4919 foreground_thread = 0;
4920
4921 retval = SetForegroundWindow ((HWND) wParam);
4922
4923 /* Detach from the previous foreground thread. */
4924 if (foreground_thread)
4925 AttachThreadInput (GetCurrentThreadId (),
4926 foreground_thread, FALSE);
4927
4928 return retval;
4929 }
4930
4931 case WM_EMACS_SETWINDOWPOS:
4932 {
4933 WINDOWPOS * pos = (WINDOWPOS *) wParam;
4934 return SetWindowPos (hwnd, pos->hwndInsertAfter,
4935 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
4936 }
4937
4938 case WM_EMACS_DESTROYWINDOW:
4939 DragAcceptFiles ((HWND) wParam, FALSE);
4940 return DestroyWindow ((HWND) wParam);
4941
4942 case WM_EMACS_DESTROY_CARET:
4943 w32_system_caret_hwnd = NULL;
4944 return DestroyCaret ();
4945
4946 case WM_EMACS_TRACK_CARET:
4947 /* If there is currently no system caret, create one. */
4948 if (w32_system_caret_hwnd == NULL)
4949 {
4950 w32_system_caret_hwnd = hwnd;
4951 CreateCaret (hwnd, NULL, w32_system_caret_width,
4952 w32_system_caret_height);
4953 }
4954 return SetCaretPos (w32_system_caret_x, w32_system_caret_y);
4955
4956 case WM_EMACS_TRACKPOPUPMENU:
4957 {
4958 UINT flags;
4959 POINT *pos;
4960 int retval;
4961 pos = (POINT *)lParam;
4962 flags = TPM_CENTERALIGN;
4963 if (button_state & LMOUSE)
4964 flags |= TPM_LEFTBUTTON;
4965 else if (button_state & RMOUSE)
4966 flags |= TPM_RIGHTBUTTON;
4967
4968 /* Remember we did a SetCapture on the initial mouse down event,
4969 so for safety, we make sure the capture is cancelled now. */
4970 ReleaseCapture ();
4971 button_state = 0;
4972
4973 /* Use menubar_active to indicate that WM_INITMENU is from
4974 TrackPopupMenu below, and should be ignored. */
4975 f = x_window_to_frame (dpyinfo, hwnd);
4976 if (f)
4977 f->output_data.w32->menubar_active = 1;
4978
4979 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4980 0, hwnd, NULL))
4981 {
4982 MSG amsg;
4983 /* Eat any mouse messages during popupmenu */
4984 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4985 PM_REMOVE));
4986 /* Get the menu selection, if any */
4987 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4988 {
4989 retval = LOWORD (amsg.wParam);
4990 }
4991 else
4992 {
4993 retval = 0;
4994 }
4995 }
4996 else
4997 {
4998 retval = -1;
4999 }
5000
5001 return retval;
5002 }
5003
5004 default:
5005 /* Check for messages registered at runtime. */
5006 if (msg == msh_mousewheel)
5007 {
5008 wmsg.dwModifiers = w32_get_modifiers ();
5009 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5010 return 0;
5011 }
5012
5013 dflt:
5014 return DefWindowProc (hwnd, msg, wParam, lParam);
5015 }
5016
5017
5018 /* The most common default return code for handled messages is 0. */
5019 return 0;
5020 }
5021
5022 void
5023 my_create_window (f)
5024 struct frame * f;
5025 {
5026 MSG msg;
5027
5028 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5029 abort ();
5030 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5031 }
5032
5033 /* Create and set up the w32 window for frame F. */
5034
5035 static void
5036 w32_window (f, window_prompting, minibuffer_only)
5037 struct frame *f;
5038 long window_prompting;
5039 int minibuffer_only;
5040 {
5041 BLOCK_INPUT;
5042
5043 /* Use the resource name as the top-level window name
5044 for looking up resources. Make a non-Lisp copy
5045 for the window manager, so GC relocation won't bother it.
5046
5047 Elsewhere we specify the window name for the window manager. */
5048
5049 {
5050 char *str = (char *) XSTRING (Vx_resource_name)->data;
5051 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5052 strcpy (f->namebuf, str);
5053 }
5054
5055 my_create_window (f);
5056
5057 validate_x_resource_name ();
5058
5059 /* x_set_name normally ignores requests to set the name if the
5060 requested name is the same as the current name. This is the one
5061 place where that assumption isn't correct; f->name is set, but
5062 the server hasn't been told. */
5063 {
5064 Lisp_Object name;
5065 int explicit = f->explicit_name;
5066
5067 f->explicit_name = 0;
5068 name = f->name;
5069 f->name = Qnil;
5070 x_set_name (f, name, explicit);
5071 }
5072
5073 UNBLOCK_INPUT;
5074
5075 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5076 initialize_frame_menubar (f);
5077
5078 if (FRAME_W32_WINDOW (f) == 0)
5079 error ("Unable to create window");
5080 }
5081
5082 /* Handle the icon stuff for this window. Perhaps later we might
5083 want an x_set_icon_position which can be called interactively as
5084 well. */
5085
5086 static void
5087 x_icon (f, parms)
5088 struct frame *f;
5089 Lisp_Object parms;
5090 {
5091 Lisp_Object icon_x, icon_y;
5092
5093 /* Set the position of the icon. Note that Windows 95 groups all
5094 icons in the tray. */
5095 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5096 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5097 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5098 {
5099 CHECK_NUMBER (icon_x);
5100 CHECK_NUMBER (icon_y);
5101 }
5102 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5103 error ("Both left and top icon corners of icon must be specified");
5104
5105 BLOCK_INPUT;
5106
5107 if (! EQ (icon_x, Qunbound))
5108 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5109
5110 #if 0 /* TODO */
5111 /* Start up iconic or window? */
5112 x_wm_set_window_state
5113 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5114 ? IconicState
5115 : NormalState));
5116
5117 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5118 ? f->icon_name
5119 : f->name))->data);
5120 #endif
5121
5122 UNBLOCK_INPUT;
5123 }
5124
5125
5126 static void
5127 x_make_gc (f)
5128 struct frame *f;
5129 {
5130 XGCValues gc_values;
5131
5132 BLOCK_INPUT;
5133
5134 /* Create the GC's of this frame.
5135 Note that many default values are used. */
5136
5137 /* Normal video */
5138 gc_values.font = f->output_data.w32->font;
5139
5140 /* Cursor has cursor-color background, background-color foreground. */
5141 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5142 gc_values.background = f->output_data.w32->cursor_pixel;
5143 f->output_data.w32->cursor_gc
5144 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5145 (GCFont | GCForeground | GCBackground),
5146 &gc_values);
5147
5148 /* Reliefs. */
5149 f->output_data.w32->white_relief.gc = 0;
5150 f->output_data.w32->black_relief.gc = 0;
5151
5152 UNBLOCK_INPUT;
5153 }
5154
5155
5156 /* Handler for signals raised during x_create_frame and
5157 x_create_top_frame. FRAME is the frame which is partially
5158 constructed. */
5159
5160 static Lisp_Object
5161 unwind_create_frame (frame)
5162 Lisp_Object frame;
5163 {
5164 struct frame *f = XFRAME (frame);
5165
5166 /* If frame is ``official'', nothing to do. */
5167 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5168 {
5169 #ifdef GLYPH_DEBUG
5170 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5171 #endif
5172
5173 x_free_frame_resources (f);
5174
5175 /* Check that reference counts are indeed correct. */
5176 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5177 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5178
5179 return Qt;
5180 }
5181
5182 return Qnil;
5183 }
5184
5185
5186 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5187 1, 1, 0,
5188 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5189 Returns an Emacs frame object.
5190 ALIST is an alist of frame parameters.
5191 If the parameters specify that the frame should not have a minibuffer,
5192 and do not specify a specific minibuffer window to use,
5193 then `default-minibuffer-frame' must be a frame whose minibuffer can
5194 be shared by the new frame.
5195
5196 This function is an internal primitive--use `make-frame' instead. */)
5197 (parms)
5198 Lisp_Object parms;
5199 {
5200 struct frame *f;
5201 Lisp_Object frame, tem;
5202 Lisp_Object name;
5203 int minibuffer_only = 0;
5204 long window_prompting = 0;
5205 int width, height;
5206 int count = BINDING_STACK_SIZE ();
5207 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5208 Lisp_Object display;
5209 struct w32_display_info *dpyinfo = NULL;
5210 Lisp_Object parent;
5211 struct kboard *kb;
5212
5213 check_w32 ();
5214
5215 /* Use this general default value to start with
5216 until we know if this frame has a specified name. */
5217 Vx_resource_name = Vinvocation_name;
5218
5219 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5220 if (EQ (display, Qunbound))
5221 display = Qnil;
5222 dpyinfo = check_x_display_info (display);
5223 #ifdef MULTI_KBOARD
5224 kb = dpyinfo->kboard;
5225 #else
5226 kb = &the_only_kboard;
5227 #endif
5228
5229 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5230 if (!STRINGP (name)
5231 && ! EQ (name, Qunbound)
5232 && ! NILP (name))
5233 error ("Invalid frame name--not a string or nil");
5234
5235 if (STRINGP (name))
5236 Vx_resource_name = name;
5237
5238 /* See if parent window is specified. */
5239 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5240 if (EQ (parent, Qunbound))
5241 parent = Qnil;
5242 if (! NILP (parent))
5243 CHECK_NUMBER (parent);
5244
5245 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5246 /* No need to protect DISPLAY because that's not used after passing
5247 it to make_frame_without_minibuffer. */
5248 frame = Qnil;
5249 GCPRO4 (parms, parent, name, frame);
5250 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5251 RES_TYPE_SYMBOL);
5252 if (EQ (tem, Qnone) || NILP (tem))
5253 f = make_frame_without_minibuffer (Qnil, kb, display);
5254 else if (EQ (tem, Qonly))
5255 {
5256 f = make_minibuffer_frame ();
5257 minibuffer_only = 1;
5258 }
5259 else if (WINDOWP (tem))
5260 f = make_frame_without_minibuffer (tem, kb, display);
5261 else
5262 f = make_frame (1);
5263
5264 XSETFRAME (frame, f);
5265
5266 /* Note that Windows does support scroll bars. */
5267 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5268 /* By default, make scrollbars the system standard width. */
5269 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5270
5271 f->output_method = output_w32;
5272 f->output_data.w32 =
5273 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5274 bzero (f->output_data.w32, sizeof (struct w32_output));
5275 FRAME_FONTSET (f) = -1;
5276 record_unwind_protect (unwind_create_frame, frame);
5277
5278 f->icon_name
5279 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5280 if (! STRINGP (f->icon_name))
5281 f->icon_name = Qnil;
5282
5283 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5284 #ifdef MULTI_KBOARD
5285 FRAME_KBOARD (f) = kb;
5286 #endif
5287
5288 /* Specify the parent under which to make this window. */
5289
5290 if (!NILP (parent))
5291 {
5292 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5293 f->output_data.w32->explicit_parent = 1;
5294 }
5295 else
5296 {
5297 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5298 f->output_data.w32->explicit_parent = 0;
5299 }
5300
5301 /* Set the name; the functions to which we pass f expect the name to
5302 be set. */
5303 if (EQ (name, Qunbound) || NILP (name))
5304 {
5305 f->name = build_string (dpyinfo->w32_id_name);
5306 f->explicit_name = 0;
5307 }
5308 else
5309 {
5310 f->name = name;
5311 f->explicit_name = 1;
5312 /* use the frame's title when getting resources for this frame. */
5313 specbind (Qx_resource_name, name);
5314 }
5315
5316 /* Extract the window parameters from the supplied values
5317 that are needed to determine window geometry. */
5318 {
5319 Lisp_Object font;
5320
5321 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5322
5323 BLOCK_INPUT;
5324 /* First, try whatever font the caller has specified. */
5325 if (STRINGP (font))
5326 {
5327 tem = Fquery_fontset (font, Qnil);
5328 if (STRINGP (tem))
5329 font = x_new_fontset (f, XSTRING (tem)->data);
5330 else
5331 font = x_new_font (f, XSTRING (font)->data);
5332 }
5333 /* Try out a font which we hope has bold and italic variations. */
5334 if (!STRINGP (font))
5335 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5336 if (! STRINGP (font))
5337 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5338 /* If those didn't work, look for something which will at least work. */
5339 if (! STRINGP (font))
5340 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5341 UNBLOCK_INPUT;
5342 if (! STRINGP (font))
5343 font = build_string ("Fixedsys");
5344
5345 x_default_parameter (f, parms, Qfont, font,
5346 "font", "Font", RES_TYPE_STRING);
5347 }
5348
5349 x_default_parameter (f, parms, Qborder_width, make_number (2),
5350 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5351 /* This defaults to 2 in order to match xterm. We recognize either
5352 internalBorderWidth or internalBorder (which is what xterm calls
5353 it). */
5354 if (NILP (Fassq (Qinternal_border_width, parms)))
5355 {
5356 Lisp_Object value;
5357
5358 value = w32_get_arg (parms, Qinternal_border_width,
5359 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5360 if (! EQ (value, Qunbound))
5361 parms = Fcons (Fcons (Qinternal_border_width, value),
5362 parms);
5363 }
5364 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5365 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5366 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5367 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5368 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5369
5370 /* Also do the stuff which must be set before the window exists. */
5371 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5372 "foreground", "Foreground", RES_TYPE_STRING);
5373 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5374 "background", "Background", RES_TYPE_STRING);
5375 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5376 "pointerColor", "Foreground", RES_TYPE_STRING);
5377 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5378 "cursorColor", "Foreground", RES_TYPE_STRING);
5379 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5380 "borderColor", "BorderColor", RES_TYPE_STRING);
5381 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5382 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5383 x_default_parameter (f, parms, Qline_spacing, Qnil,
5384 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5385
5386
5387 /* Init faces before x_default_parameter is called for scroll-bar
5388 parameters because that function calls x_set_scroll_bar_width,
5389 which calls change_frame_size, which calls Fset_window_buffer,
5390 which runs hooks, which call Fvertical_motion. At the end, we
5391 end up in init_iterator with a null face cache, which should not
5392 happen. */
5393 init_frame_faces (f);
5394
5395 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5396 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5397 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5398 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5399 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5400 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5401 x_default_parameter (f, parms, Qtitle, Qnil,
5402 "title", "Title", RES_TYPE_STRING);
5403
5404 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5405 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5406
5407 /* Add the tool-bar height to the initial frame height so that the
5408 user gets a text display area of the size he specified with -g or
5409 via .Xdefaults. Later changes of the tool-bar height don't
5410 change the frame size. This is done so that users can create
5411 tall Emacs frames without having to guess how tall the tool-bar
5412 will get. */
5413 if (FRAME_TOOL_BAR_LINES (f))
5414 {
5415 int margin, relief, bar_height;
5416
5417 relief = (tool_bar_button_relief > 0
5418 ? tool_bar_button_relief
5419 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5420
5421 if (INTEGERP (Vtool_bar_button_margin)
5422 && XINT (Vtool_bar_button_margin) > 0)
5423 margin = XFASTINT (Vtool_bar_button_margin);
5424 else if (CONSP (Vtool_bar_button_margin)
5425 && INTEGERP (XCDR (Vtool_bar_button_margin))
5426 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5427 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5428 else
5429 margin = 0;
5430
5431 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5432 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5433 }
5434
5435 window_prompting = x_figure_window_size (f, parms);
5436
5437 if (window_prompting & XNegative)
5438 {
5439 if (window_prompting & YNegative)
5440 f->output_data.w32->win_gravity = SouthEastGravity;
5441 else
5442 f->output_data.w32->win_gravity = NorthEastGravity;
5443 }
5444 else
5445 {
5446 if (window_prompting & YNegative)
5447 f->output_data.w32->win_gravity = SouthWestGravity;
5448 else
5449 f->output_data.w32->win_gravity = NorthWestGravity;
5450 }
5451
5452 f->output_data.w32->size_hint_flags = window_prompting;
5453
5454 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5455 f->no_split = minibuffer_only || EQ (tem, Qt);
5456
5457 w32_window (f, window_prompting, minibuffer_only);
5458 x_icon (f, parms);
5459
5460 x_make_gc (f);
5461
5462 /* Now consider the frame official. */
5463 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5464 Vframe_list = Fcons (frame, Vframe_list);
5465
5466 /* We need to do this after creating the window, so that the
5467 icon-creation functions can say whose icon they're describing. */
5468 x_default_parameter (f, parms, Qicon_type, Qnil,
5469 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5470
5471 x_default_parameter (f, parms, Qauto_raise, Qnil,
5472 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5473 x_default_parameter (f, parms, Qauto_lower, Qnil,
5474 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5475 x_default_parameter (f, parms, Qcursor_type, Qbox,
5476 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5477 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5478 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5479
5480 /* Dimensions, especially f->height, must be done via change_frame_size.
5481 Change will not be effected unless different from the current
5482 f->height. */
5483 width = f->width;
5484 height = f->height;
5485
5486 f->height = 0;
5487 SET_FRAME_WIDTH (f, 0);
5488 change_frame_size (f, height, width, 1, 0, 0);
5489
5490 /* Tell the server what size and position, etc, we want, and how
5491 badly we want them. This should be done after we have the menu
5492 bar so that its size can be taken into account. */
5493 BLOCK_INPUT;
5494 x_wm_set_size_hint (f, window_prompting, 0);
5495 UNBLOCK_INPUT;
5496
5497 /* Set up faces after all frame parameters are known. This call
5498 also merges in face attributes specified for new frames. If we
5499 don't do this, the `menu' face for instance won't have the right
5500 colors, and the menu bar won't appear in the specified colors for
5501 new frames. */
5502 call1 (Qface_set_after_frame_default, frame);
5503
5504 /* Make the window appear on the frame and enable display, unless
5505 the caller says not to. However, with explicit parent, Emacs
5506 cannot control visibility, so don't try. */
5507 if (! f->output_data.w32->explicit_parent)
5508 {
5509 Lisp_Object visibility;
5510
5511 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5512 if (EQ (visibility, Qunbound))
5513 visibility = Qt;
5514
5515 if (EQ (visibility, Qicon))
5516 x_iconify_frame (f);
5517 else if (! NILP (visibility))
5518 x_make_frame_visible (f);
5519 else
5520 /* Must have been Qnil. */
5521 ;
5522 }
5523 UNGCPRO;
5524
5525 /* Make sure windows on this frame appear in calls to next-window
5526 and similar functions. */
5527 Vwindow_list = Qnil;
5528
5529 return unbind_to (count, frame);
5530 }
5531
5532 /* FRAME is used only to get a handle on the X display. We don't pass the
5533 display info directly because we're called from frame.c, which doesn't
5534 know about that structure. */
5535 Lisp_Object
5536 x_get_focus_frame (frame)
5537 struct frame *frame;
5538 {
5539 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5540 Lisp_Object xfocus;
5541 if (! dpyinfo->w32_focus_frame)
5542 return Qnil;
5543
5544 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5545 return xfocus;
5546 }
5547
5548 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5549 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
5550 (frame)
5551 Lisp_Object frame;
5552 {
5553 x_focus_on_frame (check_x_frame (frame));
5554 return Qnil;
5555 }
5556
5557 \f
5558 /* Return the charset portion of a font name. */
5559 char * xlfd_charset_of_font (char * fontname)
5560 {
5561 char *charset, *encoding;
5562
5563 encoding = strrchr(fontname, '-');
5564 if (!encoding || encoding == fontname)
5565 return NULL;
5566
5567 for (charset = encoding - 1; charset >= fontname; charset--)
5568 if (*charset == '-')
5569 break;
5570
5571 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5572 return NULL;
5573
5574 return charset + 1;
5575 }
5576
5577 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5578 int size, char* filename);
5579 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5580 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5581 char * charset);
5582 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5583
5584 static struct font_info *
5585 w32_load_system_font (f,fontname,size)
5586 struct frame *f;
5587 char * fontname;
5588 int size;
5589 {
5590 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5591 Lisp_Object font_names;
5592
5593 /* Get a list of all the fonts that match this name. Once we
5594 have a list of matching fonts, we compare them against the fonts
5595 we already have loaded by comparing names. */
5596 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5597
5598 if (!NILP (font_names))
5599 {
5600 Lisp_Object tail;
5601 int i;
5602
5603 /* First check if any are already loaded, as that is cheaper
5604 than loading another one. */
5605 for (i = 0; i < dpyinfo->n_fonts; i++)
5606 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5607 if (dpyinfo->font_table[i].name
5608 && (!strcmp (dpyinfo->font_table[i].name,
5609 XSTRING (XCAR (tail))->data)
5610 || !strcmp (dpyinfo->font_table[i].full_name,
5611 XSTRING (XCAR (tail))->data)))
5612 return (dpyinfo->font_table + i);
5613
5614 fontname = (char *) XSTRING (XCAR (font_names))->data;
5615 }
5616 else if (w32_strict_fontnames)
5617 {
5618 /* If EnumFontFamiliesEx was available, we got a full list of
5619 fonts back so stop now to avoid the possibility of loading a
5620 random font. If we had to fall back to EnumFontFamilies, the
5621 list is incomplete, so continue whether the font we want was
5622 listed or not. */
5623 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5624 FARPROC enum_font_families_ex
5625 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5626 if (enum_font_families_ex)
5627 return NULL;
5628 }
5629
5630 /* Load the font and add it to the table. */
5631 {
5632 char *full_name, *encoding, *charset;
5633 XFontStruct *font;
5634 struct font_info *fontp;
5635 LOGFONT lf;
5636 BOOL ok;
5637 int codepage;
5638 int i;
5639
5640 if (!fontname || !x_to_w32_font (fontname, &lf))
5641 return (NULL);
5642
5643 if (!*lf.lfFaceName)
5644 /* If no name was specified for the font, we get a random font
5645 from CreateFontIndirect - this is not particularly
5646 desirable, especially since CreateFontIndirect does not
5647 fill out the missing name in lf, so we never know what we
5648 ended up with. */
5649 return NULL;
5650
5651 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5652 bzero (font, sizeof (*font));
5653
5654 /* Set bdf to NULL to indicate that this is a Windows font. */
5655 font->bdf = NULL;
5656
5657 BLOCK_INPUT;
5658
5659 font->hfont = CreateFontIndirect (&lf);
5660
5661 if (font->hfont == NULL)
5662 {
5663 ok = FALSE;
5664 }
5665 else
5666 {
5667 HDC hdc;
5668 HANDLE oldobj;
5669
5670 codepage = w32_codepage_for_font (fontname);
5671
5672 hdc = GetDC (dpyinfo->root_window);
5673 oldobj = SelectObject (hdc, font->hfont);
5674
5675 ok = GetTextMetrics (hdc, &font->tm);
5676 if (codepage == CP_UNICODE)
5677 font->double_byte_p = 1;
5678 else
5679 {
5680 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5681 don't report themselves as double byte fonts, when
5682 patently they are. So instead of trusting
5683 GetFontLanguageInfo, we check the properties of the
5684 codepage directly, since that is ultimately what we are
5685 working from anyway. */
5686 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5687 CPINFO cpi = {0};
5688 GetCPInfo (codepage, &cpi);
5689 font->double_byte_p = cpi.MaxCharSize > 1;
5690 }
5691
5692 SelectObject (hdc, oldobj);
5693 ReleaseDC (dpyinfo->root_window, hdc);
5694 /* Fill out details in lf according to the font that was
5695 actually loaded. */
5696 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5697 lf.lfWidth = font->tm.tmAveCharWidth;
5698 lf.lfWeight = font->tm.tmWeight;
5699 lf.lfItalic = font->tm.tmItalic;
5700 lf.lfCharSet = font->tm.tmCharSet;
5701 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5702 ? VARIABLE_PITCH : FIXED_PITCH);
5703 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5704 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5705
5706 w32_cache_char_metrics (font);
5707 }
5708
5709 UNBLOCK_INPUT;
5710
5711 if (!ok)
5712 {
5713 w32_unload_font (dpyinfo, font);
5714 return (NULL);
5715 }
5716
5717 /* Find a free slot in the font table. */
5718 for (i = 0; i < dpyinfo->n_fonts; ++i)
5719 if (dpyinfo->font_table[i].name == NULL)
5720 break;
5721
5722 /* If no free slot found, maybe enlarge the font table. */
5723 if (i == dpyinfo->n_fonts
5724 && dpyinfo->n_fonts == dpyinfo->font_table_size)
5725 {
5726 int sz;
5727 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
5728 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
5729 dpyinfo->font_table
5730 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
5731 }
5732
5733 fontp = dpyinfo->font_table + i;
5734 if (i == dpyinfo->n_fonts)
5735 ++dpyinfo->n_fonts;
5736
5737 /* Now fill in the slots of *FONTP. */
5738 BLOCK_INPUT;
5739 fontp->font = font;
5740 fontp->font_idx = i;
5741 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
5742 bcopy (fontname, fontp->name, strlen (fontname) + 1);
5743
5744 charset = xlfd_charset_of_font (fontname);
5745
5746 /* Cache the W32 codepage for a font. This makes w32_encode_char
5747 (called for every glyph during redisplay) much faster. */
5748 fontp->codepage = codepage;
5749
5750 /* Work out the font's full name. */
5751 full_name = (char *)xmalloc (100);
5752 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
5753 fontp->full_name = full_name;
5754 else
5755 {
5756 /* If all else fails - just use the name we used to load it. */
5757 xfree (full_name);
5758 fontp->full_name = fontp->name;
5759 }
5760
5761 fontp->size = FONT_WIDTH (font);
5762 fontp->height = FONT_HEIGHT (font);
5763
5764 /* The slot `encoding' specifies how to map a character
5765 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
5766 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
5767 (0:0x20..0x7F, 1:0xA0..0xFF,
5768 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
5769 2:0xA020..0xFF7F). For the moment, we don't know which charset
5770 uses this font. So, we set information in fontp->encoding[1]
5771 which is never used by any charset. If mapping can't be
5772 decided, set FONT_ENCODING_NOT_DECIDED. */
5773
5774 /* SJIS fonts need to be set to type 4, all others seem to work as
5775 type FONT_ENCODING_NOT_DECIDED. */
5776 encoding = strrchr (fontp->name, '-');
5777 if (encoding && stricmp (encoding+1, "sjis") == 0)
5778 fontp->encoding[1] = 4;
5779 else
5780 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
5781
5782 /* The following three values are set to 0 under W32, which is
5783 what they get set to if XGetFontProperty fails under X. */
5784 fontp->baseline_offset = 0;
5785 fontp->relative_compose = 0;
5786 fontp->default_ascent = 0;
5787
5788 /* Set global flag fonts_changed_p to non-zero if the font loaded
5789 has a character with a smaller width than any other character
5790 before, or if the font loaded has a smalle>r height than any
5791 other font loaded before. If this happens, it will make a
5792 glyph matrix reallocation necessary. */
5793 fonts_changed_p = x_compute_min_glyph_bounds (f);
5794 UNBLOCK_INPUT;
5795 return fontp;
5796 }
5797 }
5798
5799 /* Load font named FONTNAME of size SIZE for frame F, and return a
5800 pointer to the structure font_info while allocating it dynamically.
5801 If loading fails, return NULL. */
5802 struct font_info *
5803 w32_load_font (f,fontname,size)
5804 struct frame *f;
5805 char * fontname;
5806 int size;
5807 {
5808 Lisp_Object bdf_fonts;
5809 struct font_info *retval = NULL;
5810
5811 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
5812
5813 while (!retval && CONSP (bdf_fonts))
5814 {
5815 char *bdf_name, *bdf_file;
5816 Lisp_Object bdf_pair;
5817
5818 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
5819 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
5820 bdf_file = XSTRING (XCDR (bdf_pair))->data;
5821
5822 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
5823
5824 bdf_fonts = XCDR (bdf_fonts);
5825 }
5826
5827 if (retval)
5828 return retval;
5829
5830 return w32_load_system_font(f, fontname, size);
5831 }
5832
5833
5834 void
5835 w32_unload_font (dpyinfo, font)
5836 struct w32_display_info *dpyinfo;
5837 XFontStruct * font;
5838 {
5839 if (font)
5840 {
5841 if (font->per_char) xfree (font->per_char);
5842 if (font->bdf) w32_free_bdf_font (font->bdf);
5843
5844 if (font->hfont) DeleteObject(font->hfont);
5845 xfree (font);
5846 }
5847 }
5848
5849 /* The font conversion stuff between x and w32 */
5850
5851 /* X font string is as follows (from faces.el)
5852 * (let ((- "[-?]")
5853 * (foundry "[^-]+")
5854 * (family "[^-]+")
5855 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
5856 * (weight\? "\\([^-]*\\)") ; 1
5857 * (slant "\\([ior]\\)") ; 2
5858 * (slant\? "\\([^-]?\\)") ; 2
5859 * (swidth "\\([^-]*\\)") ; 3
5860 * (adstyle "[^-]*") ; 4
5861 * (pixelsize "[0-9]+")
5862 * (pointsize "[0-9][0-9]+")
5863 * (resx "[0-9][0-9]+")
5864 * (resy "[0-9][0-9]+")
5865 * (spacing "[cmp?*]")
5866 * (avgwidth "[0-9]+")
5867 * (registry "[^-]+")
5868 * (encoding "[^-]+")
5869 * )
5870 */
5871
5872 static LONG
5873 x_to_w32_weight (lpw)
5874 char * lpw;
5875 {
5876 if (!lpw) return (FW_DONTCARE);
5877
5878 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
5879 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
5880 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
5881 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
5882 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
5883 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
5884 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
5885 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
5886 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
5887 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
5888 else
5889 return FW_DONTCARE;
5890 }
5891
5892
5893 static char *
5894 w32_to_x_weight (fnweight)
5895 int fnweight;
5896 {
5897 if (fnweight >= FW_HEAVY) return "heavy";
5898 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5899 if (fnweight >= FW_BOLD) return "bold";
5900 if (fnweight >= FW_SEMIBOLD) return "demibold";
5901 if (fnweight >= FW_MEDIUM) return "medium";
5902 if (fnweight >= FW_NORMAL) return "normal";
5903 if (fnweight >= FW_LIGHT) return "light";
5904 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5905 if (fnweight >= FW_THIN) return "thin";
5906 else
5907 return "*";
5908 }
5909
5910 static LONG
5911 x_to_w32_charset (lpcs)
5912 char * lpcs;
5913 {
5914 Lisp_Object this_entry, w32_charset;
5915 char *charset;
5916 int len = strlen (lpcs);
5917
5918 /* Support "*-#nnn" format for unknown charsets. */
5919 if (strncmp (lpcs, "*-#", 3) == 0)
5920 return atoi (lpcs + 3);
5921
5922 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
5923 charset = alloca (len + 1);
5924 strcpy (charset, lpcs);
5925 lpcs = strchr (charset, '*');
5926 if (lpcs)
5927 *lpcs = 0;
5928
5929 /* Look through w32-charset-info-alist for the character set.
5930 Format of each entry is
5931 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5932 */
5933 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
5934
5935 if (NILP(this_entry))
5936 {
5937 /* At startup, we want iso8859-1 fonts to come up properly. */
5938 if (stricmp(charset, "iso8859-1") == 0)
5939 return ANSI_CHARSET;
5940 else
5941 return DEFAULT_CHARSET;
5942 }
5943
5944 w32_charset = Fcar (Fcdr (this_entry));
5945
5946 // Translate Lisp symbol to number.
5947 if (w32_charset == Qw32_charset_ansi)
5948 return ANSI_CHARSET;
5949 if (w32_charset == Qw32_charset_symbol)
5950 return SYMBOL_CHARSET;
5951 if (w32_charset == Qw32_charset_shiftjis)
5952 return SHIFTJIS_CHARSET;
5953 if (w32_charset == Qw32_charset_hangeul)
5954 return HANGEUL_CHARSET;
5955 if (w32_charset == Qw32_charset_chinesebig5)
5956 return CHINESEBIG5_CHARSET;
5957 if (w32_charset == Qw32_charset_gb2312)
5958 return GB2312_CHARSET;
5959 if (w32_charset == Qw32_charset_oem)
5960 return OEM_CHARSET;
5961 #ifdef JOHAB_CHARSET
5962 if (w32_charset == Qw32_charset_johab)
5963 return JOHAB_CHARSET;
5964 if (w32_charset == Qw32_charset_easteurope)
5965 return EASTEUROPE_CHARSET;
5966 if (w32_charset == Qw32_charset_turkish)
5967 return TURKISH_CHARSET;
5968 if (w32_charset == Qw32_charset_baltic)
5969 return BALTIC_CHARSET;
5970 if (w32_charset == Qw32_charset_russian)
5971 return RUSSIAN_CHARSET;
5972 if (w32_charset == Qw32_charset_arabic)
5973 return ARABIC_CHARSET;
5974 if (w32_charset == Qw32_charset_greek)
5975 return GREEK_CHARSET;
5976 if (w32_charset == Qw32_charset_hebrew)
5977 return HEBREW_CHARSET;
5978 if (w32_charset == Qw32_charset_vietnamese)
5979 return VIETNAMESE_CHARSET;
5980 if (w32_charset == Qw32_charset_thai)
5981 return THAI_CHARSET;
5982 if (w32_charset == Qw32_charset_mac)
5983 return MAC_CHARSET;
5984 #endif /* JOHAB_CHARSET */
5985 #ifdef UNICODE_CHARSET
5986 if (w32_charset == Qw32_charset_unicode)
5987 return UNICODE_CHARSET;
5988 #endif
5989
5990 return DEFAULT_CHARSET;
5991 }
5992
5993
5994 static char *
5995 w32_to_x_charset (fncharset)
5996 int fncharset;
5997 {
5998 static char buf[32];
5999 Lisp_Object charset_type;
6000
6001 switch (fncharset)
6002 {
6003 case ANSI_CHARSET:
6004 /* Handle startup case of w32-charset-info-alist not
6005 being set up yet. */
6006 if (NILP(Vw32_charset_info_alist))
6007 return "iso8859-1";
6008 charset_type = Qw32_charset_ansi;
6009 break;
6010 case DEFAULT_CHARSET:
6011 charset_type = Qw32_charset_default;
6012 break;
6013 case SYMBOL_CHARSET:
6014 charset_type = Qw32_charset_symbol;
6015 break;
6016 case SHIFTJIS_CHARSET:
6017 charset_type = Qw32_charset_shiftjis;
6018 break;
6019 case HANGEUL_CHARSET:
6020 charset_type = Qw32_charset_hangeul;
6021 break;
6022 case GB2312_CHARSET:
6023 charset_type = Qw32_charset_gb2312;
6024 break;
6025 case CHINESEBIG5_CHARSET:
6026 charset_type = Qw32_charset_chinesebig5;
6027 break;
6028 case OEM_CHARSET:
6029 charset_type = Qw32_charset_oem;
6030 break;
6031
6032 /* More recent versions of Windows (95 and NT4.0) define more
6033 character sets. */
6034 #ifdef EASTEUROPE_CHARSET
6035 case EASTEUROPE_CHARSET:
6036 charset_type = Qw32_charset_easteurope;
6037 break;
6038 case TURKISH_CHARSET:
6039 charset_type = Qw32_charset_turkish;
6040 break;
6041 case BALTIC_CHARSET:
6042 charset_type = Qw32_charset_baltic;
6043 break;
6044 case RUSSIAN_CHARSET:
6045 charset_type = Qw32_charset_russian;
6046 break;
6047 case ARABIC_CHARSET:
6048 charset_type = Qw32_charset_arabic;
6049 break;
6050 case GREEK_CHARSET:
6051 charset_type = Qw32_charset_greek;
6052 break;
6053 case HEBREW_CHARSET:
6054 charset_type = Qw32_charset_hebrew;
6055 break;
6056 case VIETNAMESE_CHARSET:
6057 charset_type = Qw32_charset_vietnamese;
6058 break;
6059 case THAI_CHARSET:
6060 charset_type = Qw32_charset_thai;
6061 break;
6062 case MAC_CHARSET:
6063 charset_type = Qw32_charset_mac;
6064 break;
6065 case JOHAB_CHARSET:
6066 charset_type = Qw32_charset_johab;
6067 break;
6068 #endif
6069
6070 #ifdef UNICODE_CHARSET
6071 case UNICODE_CHARSET:
6072 charset_type = Qw32_charset_unicode;
6073 break;
6074 #endif
6075 default:
6076 /* Encode numerical value of unknown charset. */
6077 sprintf (buf, "*-#%u", fncharset);
6078 return buf;
6079 }
6080
6081 {
6082 Lisp_Object rest;
6083 char * best_match = NULL;
6084
6085 /* Look through w32-charset-info-alist for the character set.
6086 Prefer ISO codepages, and prefer lower numbers in the ISO
6087 range. Only return charsets for codepages which are installed.
6088
6089 Format of each entry is
6090 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6091 */
6092 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6093 {
6094 char * x_charset;
6095 Lisp_Object w32_charset;
6096 Lisp_Object codepage;
6097
6098 Lisp_Object this_entry = XCAR (rest);
6099
6100 /* Skip invalid entries in alist. */
6101 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6102 || !CONSP (XCDR (this_entry))
6103 || !SYMBOLP (XCAR (XCDR (this_entry))))
6104 continue;
6105
6106 x_charset = XSTRING (XCAR (this_entry))->data;
6107 w32_charset = XCAR (XCDR (this_entry));
6108 codepage = XCDR (XCDR (this_entry));
6109
6110 /* Look for Same charset and a valid codepage (or non-int
6111 which means ignore). */
6112 if (w32_charset == charset_type
6113 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6114 || IsValidCodePage (XINT (codepage))))
6115 {
6116 /* If we don't have a match already, then this is the
6117 best. */
6118 if (!best_match)
6119 best_match = x_charset;
6120 /* If this is an ISO codepage, and the best so far isn't,
6121 then this is better. */
6122 else if (stricmp (best_match, "iso") != 0
6123 && stricmp (x_charset, "iso") == 0)
6124 best_match = x_charset;
6125 /* If both are ISO8859 codepages, choose the one with the
6126 lowest number in the encoding field. */
6127 else if (stricmp (best_match, "iso8859-") == 0
6128 && stricmp (x_charset, "iso8859-") == 0)
6129 {
6130 int best_enc = atoi (best_match + 8);
6131 int this_enc = atoi (x_charset + 8);
6132 if (this_enc > 0 && this_enc < best_enc)
6133 best_match = x_charset;
6134 }
6135 }
6136 }
6137
6138 /* If no match, encode the numeric value. */
6139 if (!best_match)
6140 {
6141 sprintf (buf, "*-#%u", fncharset);
6142 return buf;
6143 }
6144
6145 strncpy(buf, best_match, 31);
6146 buf[31] = '\0';
6147 return buf;
6148 }
6149 }
6150
6151
6152 /* Get the Windows codepage corresponding to the specified font. The
6153 charset info in the font name is used to look up
6154 w32-charset-to-codepage-alist. */
6155 int
6156 w32_codepage_for_font (char *fontname)
6157 {
6158 Lisp_Object codepage, entry;
6159 char *charset_str, *charset, *end;
6160
6161 if (NILP (Vw32_charset_info_alist))
6162 return CP_DEFAULT;
6163
6164 /* Extract charset part of font string. */
6165 charset = xlfd_charset_of_font (fontname);
6166
6167 if (!charset)
6168 return CP_UNKNOWN;
6169
6170 charset_str = (char *) alloca (strlen (charset) + 1);
6171 strcpy (charset_str, charset);
6172
6173 #if 0
6174 /* Remove leading "*-". */
6175 if (strncmp ("*-", charset_str, 2) == 0)
6176 charset = charset_str + 2;
6177 else
6178 #endif
6179 charset = charset_str;
6180
6181 /* Stop match at wildcard (including preceding '-'). */
6182 if (end = strchr (charset, '*'))
6183 {
6184 if (end > charset && *(end-1) == '-')
6185 end--;
6186 *end = '\0';
6187 }
6188
6189 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6190 if (NILP (entry))
6191 return CP_UNKNOWN;
6192
6193 codepage = Fcdr (Fcdr (entry));
6194
6195 if (NILP (codepage))
6196 return CP_8BIT;
6197 else if (XFASTINT (codepage) == XFASTINT (Qt))
6198 return CP_UNICODE;
6199 else if (INTEGERP (codepage))
6200 return XINT (codepage);
6201 else
6202 return CP_UNKNOWN;
6203 }
6204
6205
6206 static BOOL
6207 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6208 LOGFONT * lplogfont;
6209 char * lpxstr;
6210 int len;
6211 char * specific_charset;
6212 {
6213 char* fonttype;
6214 char *fontname;
6215 char height_pixels[8];
6216 char height_dpi[8];
6217 char width_pixels[8];
6218 char *fontname_dash;
6219 int display_resy = one_w32_display_info.resy;
6220 int display_resx = one_w32_display_info.resx;
6221 int bufsz;
6222 struct coding_system coding;
6223
6224 if (!lpxstr) abort ();
6225
6226 if (!lplogfont)
6227 return FALSE;
6228
6229 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6230 fonttype = "raster";
6231 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6232 fonttype = "outline";
6233 else
6234 fonttype = "unknown";
6235
6236 setup_coding_system (Fcheck_coding_system (Vw32_system_coding_system),
6237 &coding);
6238 coding.src_multibyte = 0;
6239 coding.dst_multibyte = 1;
6240 coding.mode |= CODING_MODE_LAST_BLOCK;
6241 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6242
6243 fontname = alloca(sizeof(*fontname) * bufsz);
6244 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6245 strlen(lplogfont->lfFaceName), bufsz - 1);
6246 *(fontname + coding.produced) = '\0';
6247
6248 /* Replace dashes with underscores so the dashes are not
6249 misinterpreted. */
6250 fontname_dash = fontname;
6251 while (fontname_dash = strchr (fontname_dash, '-'))
6252 *fontname_dash = '_';
6253
6254 if (lplogfont->lfHeight)
6255 {
6256 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6257 sprintf (height_dpi, "%u",
6258 abs (lplogfont->lfHeight) * 720 / display_resy);
6259 }
6260 else
6261 {
6262 strcpy (height_pixels, "*");
6263 strcpy (height_dpi, "*");
6264 }
6265 if (lplogfont->lfWidth)
6266 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6267 else
6268 strcpy (width_pixels, "*");
6269
6270 _snprintf (lpxstr, len - 1,
6271 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6272 fonttype, /* foundry */
6273 fontname, /* family */
6274 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6275 lplogfont->lfItalic?'i':'r', /* slant */
6276 /* setwidth name */
6277 /* add style name */
6278 height_pixels, /* pixel size */
6279 height_dpi, /* point size */
6280 display_resx, /* resx */
6281 display_resy, /* resy */
6282 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6283 ? 'p' : 'c', /* spacing */
6284 width_pixels, /* avg width */
6285 specific_charset ? specific_charset
6286 : w32_to_x_charset (lplogfont->lfCharSet)
6287 /* charset registry and encoding */
6288 );
6289
6290 lpxstr[len - 1] = 0; /* just to be sure */
6291 return (TRUE);
6292 }
6293
6294 static BOOL
6295 x_to_w32_font (lpxstr, lplogfont)
6296 char * lpxstr;
6297 LOGFONT * lplogfont;
6298 {
6299 struct coding_system coding;
6300
6301 if (!lplogfont) return (FALSE);
6302
6303 memset (lplogfont, 0, sizeof (*lplogfont));
6304
6305 /* Set default value for each field. */
6306 #if 1
6307 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6308 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6309 lplogfont->lfQuality = DEFAULT_QUALITY;
6310 #else
6311 /* go for maximum quality */
6312 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6313 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6314 lplogfont->lfQuality = PROOF_QUALITY;
6315 #endif
6316
6317 lplogfont->lfCharSet = DEFAULT_CHARSET;
6318 lplogfont->lfWeight = FW_DONTCARE;
6319 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6320
6321 if (!lpxstr)
6322 return FALSE;
6323
6324 /* Provide a simple escape mechanism for specifying Windows font names
6325 * directly -- if font spec does not beginning with '-', assume this
6326 * format:
6327 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6328 */
6329
6330 if (*lpxstr == '-')
6331 {
6332 int fields, tem;
6333 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6334 width[10], resy[10], remainder[50];
6335 char * encoding;
6336 int dpi = one_w32_display_info.resy;
6337
6338 fields = sscanf (lpxstr,
6339 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6340 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6341 if (fields == EOF)
6342 return (FALSE);
6343
6344 /* In the general case when wildcards cover more than one field,
6345 we don't know which field is which, so don't fill any in.
6346 However, we need to cope with this particular form, which is
6347 generated by font_list_1 (invoked by try_font_list):
6348 "-raster-6x10-*-gb2312*-*"
6349 and make sure to correctly parse the charset field. */
6350 if (fields == 3)
6351 {
6352 fields = sscanf (lpxstr,
6353 "-%*[^-]-%49[^-]-*-%49s",
6354 name, remainder);
6355 }
6356 else if (fields < 9)
6357 {
6358 fields = 0;
6359 remainder[0] = 0;
6360 }
6361
6362 if (fields > 0 && name[0] != '*')
6363 {
6364 int bufsize;
6365 unsigned char *buf;
6366
6367 setup_coding_system
6368 (Fcheck_coding_system (Vw32_system_coding_system), &coding);
6369 coding.src_multibyte = 1;
6370 coding.dst_multibyte = 1;
6371 bufsize = encoding_buffer_size (&coding, strlen (name));
6372 buf = (unsigned char *) alloca (bufsize);
6373 coding.mode |= CODING_MODE_LAST_BLOCK;
6374 encode_coding (&coding, name, buf, strlen (name), bufsize);
6375 if (coding.produced >= LF_FACESIZE)
6376 coding.produced = LF_FACESIZE - 1;
6377 buf[coding.produced] = 0;
6378 strcpy (lplogfont->lfFaceName, buf);
6379 }
6380 else
6381 {
6382 lplogfont->lfFaceName[0] = '\0';
6383 }
6384
6385 fields--;
6386
6387 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6388
6389 fields--;
6390
6391 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6392
6393 fields--;
6394
6395 if (fields > 0 && pixels[0] != '*')
6396 lplogfont->lfHeight = atoi (pixels);
6397
6398 fields--;
6399 fields--;
6400 if (fields > 0 && resy[0] != '*')
6401 {
6402 tem = atoi (resy);
6403 if (tem > 0) dpi = tem;
6404 }
6405
6406 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6407 lplogfont->lfHeight = atoi (height) * dpi / 720;
6408
6409 if (fields > 0)
6410 lplogfont->lfPitchAndFamily =
6411 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6412
6413 fields--;
6414
6415 if (fields > 0 && width[0] != '*')
6416 lplogfont->lfWidth = atoi (width) / 10;
6417
6418 fields--;
6419
6420 /* Strip the trailing '-' if present. (it shouldn't be, as it
6421 fails the test against xlfd-tight-regexp in fontset.el). */
6422 {
6423 int len = strlen (remainder);
6424 if (len > 0 && remainder[len-1] == '-')
6425 remainder[len-1] = 0;
6426 }
6427 encoding = remainder;
6428 #if 0
6429 if (strncmp (encoding, "*-", 2) == 0)
6430 encoding += 2;
6431 #endif
6432 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6433 }
6434 else
6435 {
6436 int fields;
6437 char name[100], height[10], width[10], weight[20];
6438
6439 fields = sscanf (lpxstr,
6440 "%99[^:]:%9[^:]:%9[^:]:%19s",
6441 name, height, width, weight);
6442
6443 if (fields == EOF) return (FALSE);
6444
6445 if (fields > 0)
6446 {
6447 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6448 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6449 }
6450 else
6451 {
6452 lplogfont->lfFaceName[0] = 0;
6453 }
6454
6455 fields--;
6456
6457 if (fields > 0)
6458 lplogfont->lfHeight = atoi (height);
6459
6460 fields--;
6461
6462 if (fields > 0)
6463 lplogfont->lfWidth = atoi (width);
6464
6465 fields--;
6466
6467 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6468 }
6469
6470 /* This makes TrueType fonts work better. */
6471 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6472
6473 return (TRUE);
6474 }
6475
6476 /* Strip the pixel height and point height from the given xlfd, and
6477 return the pixel height. If no pixel height is specified, calculate
6478 one from the point height, or if that isn't defined either, return
6479 0 (which usually signifies a scalable font).
6480 */
6481 static int
6482 xlfd_strip_height (char *fontname)
6483 {
6484 int pixel_height, field_number;
6485 char *read_from, *write_to;
6486
6487 xassert (fontname);
6488
6489 pixel_height = field_number = 0;
6490 write_to = NULL;
6491
6492 /* Look for height fields. */
6493 for (read_from = fontname; *read_from; read_from++)
6494 {
6495 if (*read_from == '-')
6496 {
6497 field_number++;
6498 if (field_number == 7) /* Pixel height. */
6499 {
6500 read_from++;
6501 write_to = read_from;
6502
6503 /* Find end of field. */
6504 for (;*read_from && *read_from != '-'; read_from++)
6505 ;
6506
6507 /* Split the fontname at end of field. */
6508 if (*read_from)
6509 {
6510 *read_from = '\0';
6511 read_from++;
6512 }
6513 pixel_height = atoi (write_to);
6514 /* Blank out field. */
6515 if (read_from > write_to)
6516 {
6517 *write_to = '-';
6518 write_to++;
6519 }
6520 /* If the pixel height field is at the end (partial xlfd),
6521 return now. */
6522 else
6523 return pixel_height;
6524
6525 /* If we got a pixel height, the point height can be
6526 ignored. Just blank it out and break now. */
6527 if (pixel_height)
6528 {
6529 /* Find end of point size field. */
6530 for (; *read_from && *read_from != '-'; read_from++)
6531 ;
6532
6533 if (*read_from)
6534 read_from++;
6535
6536 /* Blank out the point size field. */
6537 if (read_from > write_to)
6538 {
6539 *write_to = '-';
6540 write_to++;
6541 }
6542 else
6543 return pixel_height;
6544
6545 break;
6546 }
6547 /* If the point height is already blank, break now. */
6548 if (*read_from == '-')
6549 {
6550 read_from++;
6551 break;
6552 }
6553 }
6554 else if (field_number == 8)
6555 {
6556 /* If we didn't get a pixel height, try to get the point
6557 height and convert that. */
6558 int point_size;
6559 char *point_size_start = read_from++;
6560
6561 /* Find end of field. */
6562 for (; *read_from && *read_from != '-'; read_from++)
6563 ;
6564
6565 if (*read_from)
6566 {
6567 *read_from = '\0';
6568 read_from++;
6569 }
6570
6571 point_size = atoi (point_size_start);
6572
6573 /* Convert to pixel height. */
6574 pixel_height = point_size
6575 * one_w32_display_info.height_in / 720;
6576
6577 /* Blank out this field and break. */
6578 *write_to = '-';
6579 write_to++;
6580 break;
6581 }
6582 }
6583 }
6584
6585 /* Shift the rest of the font spec into place. */
6586 if (write_to && read_from > write_to)
6587 {
6588 for (; *read_from; read_from++, write_to++)
6589 *write_to = *read_from;
6590 *write_to = '\0';
6591 }
6592
6593 return pixel_height;
6594 }
6595
6596 /* Assume parameter 1 is fully qualified, no wildcards. */
6597 static BOOL
6598 w32_font_match (fontname, pattern)
6599 char * fontname;
6600 char * pattern;
6601 {
6602 char *regex = alloca (strlen (pattern) * 2 + 3);
6603 char *font_name_copy = alloca (strlen (fontname) + 1);
6604 char *ptr;
6605
6606 /* Copy fontname so we can modify it during comparison. */
6607 strcpy (font_name_copy, fontname);
6608
6609 ptr = regex;
6610 *ptr++ = '^';
6611
6612 /* Turn pattern into a regexp and do a regexp match. */
6613 for (; *pattern; pattern++)
6614 {
6615 if (*pattern == '?')
6616 *ptr++ = '.';
6617 else if (*pattern == '*')
6618 {
6619 *ptr++ = '.';
6620 *ptr++ = '*';
6621 }
6622 else
6623 *ptr++ = *pattern;
6624 }
6625 *ptr = '$';
6626 *(ptr + 1) = '\0';
6627
6628 /* Strip out font heights and compare them seperately, since
6629 rounding error can cause mismatches. This also allows a
6630 comparison between a font that declares only a pixel height and a
6631 pattern that declares the point height.
6632 */
6633 {
6634 int font_height, pattern_height;
6635
6636 font_height = xlfd_strip_height (font_name_copy);
6637 pattern_height = xlfd_strip_height (regex);
6638
6639 /* Compare now, and don't bother doing expensive regexp matching
6640 if the heights differ. */
6641 if (font_height && pattern_height && (font_height != pattern_height))
6642 return FALSE;
6643 }
6644
6645 return (fast_c_string_match_ignore_case (build_string (regex),
6646 font_name_copy) >= 0);
6647 }
6648
6649 /* Callback functions, and a structure holding info they need, for
6650 listing system fonts on W32. We need one set of functions to do the
6651 job properly, but these don't work on NT 3.51 and earlier, so we
6652 have a second set which don't handle character sets properly to
6653 fall back on.
6654
6655 In both cases, there are two passes made. The first pass gets one
6656 font from each family, the second pass lists all the fonts from
6657 each family. */
6658
6659 typedef struct enumfont_t
6660 {
6661 HDC hdc;
6662 int numFonts;
6663 LOGFONT logfont;
6664 XFontStruct *size_ref;
6665 Lisp_Object *pattern;
6666 Lisp_Object *tail;
6667 } enumfont_t;
6668
6669 static int CALLBACK
6670 enum_font_cb2 (lplf, lptm, FontType, lpef)
6671 ENUMLOGFONT * lplf;
6672 NEWTEXTMETRIC * lptm;
6673 int FontType;
6674 enumfont_t * lpef;
6675 {
6676 /* Ignore struck out and underlined versions of fonts. */
6677 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6678 return 1;
6679
6680 /* Only return fonts with names starting with @ if they were
6681 explicitly specified, since Microsoft uses an initial @ to
6682 denote fonts for vertical writing, without providing a more
6683 convenient way of identifying them. */
6684 if (lplf->elfLogFont.lfFaceName[0] == '@'
6685 && lpef->logfont.lfFaceName[0] != '@')
6686 return 1;
6687
6688 /* Check that the character set matches if it was specified */
6689 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6690 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6691 return 1;
6692
6693 {
6694 char buf[100];
6695 Lisp_Object width = Qnil;
6696 char *charset = NULL;
6697
6698 /* Truetype fonts do not report their true metrics until loaded */
6699 if (FontType != RASTER_FONTTYPE)
6700 {
6701 if (!NILP (*(lpef->pattern)))
6702 {
6703 /* Scalable fonts are as big as you want them to be. */
6704 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6705 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6706 width = make_number (lpef->logfont.lfWidth);
6707 }
6708 else
6709 {
6710 lplf->elfLogFont.lfHeight = 0;
6711 lplf->elfLogFont.lfWidth = 0;
6712 }
6713 }
6714
6715 /* Make sure the height used here is the same as everywhere
6716 else (ie character height, not cell height). */
6717 if (lplf->elfLogFont.lfHeight > 0)
6718 {
6719 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6720 if (FontType == RASTER_FONTTYPE)
6721 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6722 else
6723 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6724 }
6725
6726 if (!NILP (*(lpef->pattern)))
6727 {
6728 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
6729
6730 /* Ensure that charset is valid for this font. */
6731 if (charset
6732 && (x_to_w32_charset (charset) != lplf->elfLogFont.lfCharSet))
6733 charset = NULL;
6734 }
6735
6736 /* TODO: List all relevant charsets if charset not specified. */
6737 if (!w32_to_x_font (&(lplf->elfLogFont), buf, 100, charset))
6738 return 1;
6739
6740 if (NILP (*(lpef->pattern))
6741 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
6742 {
6743 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
6744 lpef->tail = &(XCDR (*lpef->tail));
6745 lpef->numFonts++;
6746 }
6747 }
6748
6749 return 1;
6750 }
6751
6752 static int CALLBACK
6753 enum_font_cb1 (lplf, lptm, FontType, lpef)
6754 ENUMLOGFONT * lplf;
6755 NEWTEXTMETRIC * lptm;
6756 int FontType;
6757 enumfont_t * lpef;
6758 {
6759 return EnumFontFamilies (lpef->hdc,
6760 lplf->elfLogFont.lfFaceName,
6761 (FONTENUMPROC) enum_font_cb2,
6762 (LPARAM) lpef);
6763 }
6764
6765
6766 static int CALLBACK
6767 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6768 ENUMLOGFONTEX * lplf;
6769 NEWTEXTMETRICEX * lptm;
6770 int font_type;
6771 enumfont_t * lpef;
6772 {
6773 /* We are not interested in the extra info we get back from the 'Ex
6774 version - only the fact that we get character set variations
6775 enumerated seperately. */
6776 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6777 font_type, lpef);
6778 }
6779
6780 static int CALLBACK
6781 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6782 ENUMLOGFONTEX * lplf;
6783 NEWTEXTMETRICEX * lptm;
6784 int font_type;
6785 enumfont_t * lpef;
6786 {
6787 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6788 FARPROC enum_font_families_ex
6789 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6790 /* We don't really expect EnumFontFamiliesEx to disappear once we
6791 get here, so don't bother handling it gracefully. */
6792 if (enum_font_families_ex == NULL)
6793 error ("gdi32.dll has disappeared!");
6794 return enum_font_families_ex (lpef->hdc,
6795 &lplf->elfLogFont,
6796 (FONTENUMPROC) enum_fontex_cb2,
6797 (LPARAM) lpef, 0);
6798 }
6799
6800 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6801 and xterm.c in Emacs 20.3) */
6802
6803 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6804 {
6805 char *fontname, *ptnstr;
6806 Lisp_Object list, tem, newlist = Qnil;
6807 int n_fonts = 0;
6808
6809 list = Vw32_bdf_filename_alist;
6810 ptnstr = XSTRING (pattern)->data;
6811
6812 for ( ; CONSP (list); list = XCDR (list))
6813 {
6814 tem = XCAR (list);
6815 if (CONSP (tem))
6816 fontname = XSTRING (XCAR (tem))->data;
6817 else if (STRINGP (tem))
6818 fontname = XSTRING (tem)->data;
6819 else
6820 continue;
6821
6822 if (w32_font_match (fontname, ptnstr))
6823 {
6824 newlist = Fcons (XCAR (tem), newlist);
6825 n_fonts++;
6826 if (n_fonts >= max_names)
6827 break;
6828 }
6829 }
6830
6831 return newlist;
6832 }
6833
6834 static Lisp_Object w32_list_synthesized_fonts (FRAME_PTR f,
6835 Lisp_Object pattern,
6836 int size, int max_names);
6837
6838 /* Return a list of names of available fonts matching PATTERN on frame
6839 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6840 to be listed. Frame F NULL means we have not yet created any
6841 frame, which means we can't get proper size info, as we don't have
6842 a device context to use for GetTextMetrics.
6843 MAXNAMES sets a limit on how many fonts to match. */
6844
6845 Lisp_Object
6846 w32_list_fonts (f, pattern, size, maxnames)
6847 struct frame *f;
6848 Lisp_Object pattern;
6849 int size;
6850 int maxnames;
6851 {
6852 Lisp_Object patterns, key = Qnil, tem, tpat;
6853 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6854 struct w32_display_info *dpyinfo = &one_w32_display_info;
6855 int n_fonts = 0;
6856
6857 patterns = Fassoc (pattern, Valternate_fontname_alist);
6858 if (NILP (patterns))
6859 patterns = Fcons (pattern, Qnil);
6860
6861 for (; CONSP (patterns); patterns = XCDR (patterns))
6862 {
6863 enumfont_t ef;
6864 int codepage;
6865
6866 tpat = XCAR (patterns);
6867
6868 if (!STRINGP (tpat))
6869 continue;
6870
6871 /* Avoid expensive EnumFontFamilies functions if we are not
6872 going to be able to output one of these anyway. */
6873 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
6874 if (codepage != CP_8BIT && codepage != CP_UNICODE
6875 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6876 && !IsValidCodePage(codepage))
6877 continue;
6878
6879 /* See if we cached the result for this particular query.
6880 The cache is an alist of the form:
6881 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6882 */
6883 if (tem = XCDR (dpyinfo->name_list_element),
6884 !NILP (list = Fassoc (tpat, tem)))
6885 {
6886 list = Fcdr_safe (list);
6887 /* We have a cached list. Don't have to get the list again. */
6888 goto label_cached;
6889 }
6890
6891 BLOCK_INPUT;
6892 /* At first, put PATTERN in the cache. */
6893 list = Qnil;
6894 ef.pattern = &tpat;
6895 ef.tail = &list;
6896 ef.numFonts = 0;
6897
6898 /* Use EnumFontFamiliesEx where it is available, as it knows
6899 about character sets. Fall back to EnumFontFamilies for
6900 older versions of NT that don't support the 'Ex function. */
6901 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
6902 {
6903 LOGFONT font_match_pattern;
6904 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6905 FARPROC enum_font_families_ex
6906 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6907
6908 /* We do our own pattern matching so we can handle wildcards. */
6909 font_match_pattern.lfFaceName[0] = 0;
6910 font_match_pattern.lfPitchAndFamily = 0;
6911 /* We can use the charset, because if it is a wildcard it will
6912 be DEFAULT_CHARSET anyway. */
6913 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6914
6915 ef.hdc = GetDC (dpyinfo->root_window);
6916
6917 if (enum_font_families_ex)
6918 enum_font_families_ex (ef.hdc,
6919 &font_match_pattern,
6920 (FONTENUMPROC) enum_fontex_cb1,
6921 (LPARAM) &ef, 0);
6922 else
6923 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6924 (LPARAM)&ef);
6925
6926 ReleaseDC (dpyinfo->root_window, ef.hdc);
6927 }
6928
6929 UNBLOCK_INPUT;
6930
6931 /* Make a list of the fonts we got back.
6932 Store that in the font cache for the display. */
6933 XSETCDR (dpyinfo->name_list_element,
6934 Fcons (Fcons (tpat, list),
6935 XCDR (dpyinfo->name_list_element)));
6936
6937 label_cached:
6938 if (NILP (list)) continue; /* Try the remaining alternatives. */
6939
6940 newlist = second_best = Qnil;
6941
6942 /* Make a list of the fonts that have the right width. */
6943 for (; CONSP (list); list = XCDR (list))
6944 {
6945 int found_size;
6946 tem = XCAR (list);
6947
6948 if (!CONSP (tem))
6949 continue;
6950 if (NILP (XCAR (tem)))
6951 continue;
6952 if (!size)
6953 {
6954 newlist = Fcons (XCAR (tem), newlist);
6955 n_fonts++;
6956 if (n_fonts >= maxnames)
6957 break;
6958 else
6959 continue;
6960 }
6961 if (!INTEGERP (XCDR (tem)))
6962 {
6963 /* Since we don't yet know the size of the font, we must
6964 load it and try GetTextMetrics. */
6965 W32FontStruct thisinfo;
6966 LOGFONT lf;
6967 HDC hdc;
6968 HANDLE oldobj;
6969
6970 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
6971 continue;
6972
6973 BLOCK_INPUT;
6974 thisinfo.bdf = NULL;
6975 thisinfo.hfont = CreateFontIndirect (&lf);
6976 if (thisinfo.hfont == NULL)
6977 continue;
6978
6979 hdc = GetDC (dpyinfo->root_window);
6980 oldobj = SelectObject (hdc, thisinfo.hfont);
6981 if (GetTextMetrics (hdc, &thisinfo.tm))
6982 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
6983 else
6984 XSETCDR (tem, make_number (0));
6985 SelectObject (hdc, oldobj);
6986 ReleaseDC (dpyinfo->root_window, hdc);
6987 DeleteObject(thisinfo.hfont);
6988 UNBLOCK_INPUT;
6989 }
6990 found_size = XINT (XCDR (tem));
6991 if (found_size == size)
6992 {
6993 newlist = Fcons (XCAR (tem), newlist);
6994 n_fonts++;
6995 if (n_fonts >= maxnames)
6996 break;
6997 }
6998 /* keep track of the closest matching size in case
6999 no exact match is found. */
7000 else if (found_size > 0)
7001 {
7002 if (NILP (second_best))
7003 second_best = tem;
7004
7005 else if (found_size < size)
7006 {
7007 if (XINT (XCDR (second_best)) > size
7008 || XINT (XCDR (second_best)) < found_size)
7009 second_best = tem;
7010 }
7011 else
7012 {
7013 if (XINT (XCDR (second_best)) > size
7014 && XINT (XCDR (second_best)) >
7015 found_size)
7016 second_best = tem;
7017 }
7018 }
7019 }
7020
7021 if (!NILP (newlist))
7022 break;
7023 else if (!NILP (second_best))
7024 {
7025 newlist = Fcons (XCAR (second_best), Qnil);
7026 break;
7027 }
7028 }
7029
7030 /* Include any bdf fonts. */
7031 if (n_fonts < maxnames)
7032 {
7033 Lisp_Object combined[2];
7034 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7035 combined[1] = newlist;
7036 newlist = Fnconc(2, combined);
7037 }
7038
7039 /* If we can't find a font that matches, check if Windows would be
7040 able to synthesize it from a different style. */
7041 if (NILP (newlist) && !NILP (Vw32_enable_synthesized_fonts))
7042 newlist = w32_list_synthesized_fonts (f, pattern, size, maxnames);
7043
7044 return newlist;
7045 }
7046
7047 static Lisp_Object
7048 w32_list_synthesized_fonts (f, pattern, size, max_names)
7049 FRAME_PTR f;
7050 Lisp_Object pattern;
7051 int size;
7052 int max_names;
7053 {
7054 int fields;
7055 char *full_pattn, *new_pattn, foundary[50], family[50], *pattn_part2;
7056 char style[20], slant;
7057 Lisp_Object matches, tem, synthed_matches = Qnil;
7058
7059 full_pattn = XSTRING (pattern)->data;
7060
7061 pattn_part2 = alloca (XSTRING (pattern)->size + 1);
7062 /* Allow some space for wildcard expansion. */
7063 new_pattn = alloca (XSTRING (pattern)->size + 100);
7064
7065 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%19[^-]-%c-%s",
7066 foundary, family, style, &slant, pattn_part2);
7067 if (fields == EOF || fields < 5)
7068 return Qnil;
7069
7070 /* If the style and slant are wildcards already there is no point
7071 checking again (and we don't want to keep recursing). */
7072 if (*style == '*' && slant == '*')
7073 return Qnil;
7074
7075 sprintf (new_pattn, "-%s-%s-*-*-%s", foundary, family, pattn_part2);
7076
7077 matches = w32_list_fonts (f, build_string (new_pattn), size, max_names);
7078
7079 for ( ; CONSP (matches); matches = XCDR (matches))
7080 {
7081 tem = XCAR (matches);
7082 if (!STRINGP (tem))
7083 continue;
7084
7085 full_pattn = XSTRING (tem)->data;
7086 fields = sscanf (full_pattn, "-%49[^-]-%49[^-]-%*[^-]-%*c-%s",
7087 foundary, family, pattn_part2);
7088 if (fields == EOF || fields < 3)
7089 continue;
7090
7091 sprintf (new_pattn, "-%s-%s-%s-%c-%s", foundary, family, style,
7092 slant, pattn_part2);
7093
7094 synthed_matches = Fcons (build_string (new_pattn),
7095 synthed_matches);
7096 }
7097
7098 return synthed_matches;
7099 }
7100
7101
7102 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7103 struct font_info *
7104 w32_get_font_info (f, font_idx)
7105 FRAME_PTR f;
7106 int font_idx;
7107 {
7108 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7109 }
7110
7111
7112 struct font_info*
7113 w32_query_font (struct frame *f, char *fontname)
7114 {
7115 int i;
7116 struct font_info *pfi;
7117
7118 pfi = FRAME_W32_FONT_TABLE (f);
7119
7120 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7121 {
7122 if (strcmp(pfi->name, fontname) == 0) return pfi;
7123 }
7124
7125 return NULL;
7126 }
7127
7128 /* Find a CCL program for a font specified by FONTP, and set the member
7129 `encoder' of the structure. */
7130
7131 void
7132 w32_find_ccl_program (fontp)
7133 struct font_info *fontp;
7134 {
7135 Lisp_Object list, elt;
7136
7137 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7138 {
7139 elt = XCAR (list);
7140 if (CONSP (elt)
7141 && STRINGP (XCAR (elt))
7142 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7143 >= 0))
7144 break;
7145 }
7146 if (! NILP (list))
7147 {
7148 struct ccl_program *ccl
7149 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7150
7151 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7152 xfree (ccl);
7153 else
7154 fontp->font_encoder = ccl;
7155 }
7156 }
7157
7158 \f
7159 /* Find BDF files in a specified directory. (use GCPRO when calling,
7160 as this calls lisp to get a directory listing). */
7161 static Lisp_Object
7162 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7163 {
7164 Lisp_Object filelist, list = Qnil;
7165 char fontname[100];
7166
7167 if (!STRINGP(directory))
7168 return Qnil;
7169
7170 filelist = Fdirectory_files (directory, Qt,
7171 build_string (".*\\.[bB][dD][fF]"), Qt);
7172
7173 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7174 {
7175 Lisp_Object filename = XCAR (filelist);
7176 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7177 store_in_alist (&list, build_string (fontname), filename);
7178 }
7179 return list;
7180 }
7181
7182 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7183 1, 1, 0,
7184 doc: /* Return a list of BDF fonts in DIR.
7185 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7186 which do not contain an xlfd description will not be included in the
7187 list. DIR may be a list of directories. */)
7188 (directory)
7189 Lisp_Object directory;
7190 {
7191 Lisp_Object list = Qnil;
7192 struct gcpro gcpro1, gcpro2;
7193
7194 if (!CONSP (directory))
7195 return w32_find_bdf_fonts_in_dir (directory);
7196
7197 for ( ; CONSP (directory); directory = XCDR (directory))
7198 {
7199 Lisp_Object pair[2];
7200 pair[0] = list;
7201 pair[1] = Qnil;
7202 GCPRO2 (directory, list);
7203 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7204 list = Fnconc( 2, pair );
7205 UNGCPRO;
7206 }
7207 return list;
7208 }
7209
7210 \f
7211 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7212 doc: /* Internal function called by `color-defined-p', which see. */)
7213 (color, frame)
7214 Lisp_Object color, frame;
7215 {
7216 XColor foo;
7217 FRAME_PTR f = check_x_frame (frame);
7218
7219 CHECK_STRING (color);
7220
7221 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7222 return Qt;
7223 else
7224 return Qnil;
7225 }
7226
7227 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7228 doc: /* Internal function called by `color-values', which see. */)
7229 (color, frame)
7230 Lisp_Object color, frame;
7231 {
7232 XColor foo;
7233 FRAME_PTR f = check_x_frame (frame);
7234
7235 CHECK_STRING (color);
7236
7237 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7238 {
7239 Lisp_Object rgb[3];
7240
7241 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7242 | GetRValue (foo.pixel));
7243 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7244 | GetGValue (foo.pixel));
7245 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7246 | GetBValue (foo.pixel));
7247 return Flist (3, rgb);
7248 }
7249 else
7250 return Qnil;
7251 }
7252
7253 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7254 doc: /* Internal function called by `display-color-p', which see. */)
7255 (display)
7256 Lisp_Object display;
7257 {
7258 struct w32_display_info *dpyinfo = check_x_display_info (display);
7259
7260 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7261 return Qnil;
7262
7263 return Qt;
7264 }
7265
7266 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7267 Sx_display_grayscale_p, 0, 1, 0,
7268 doc: /* Return t if the X display supports shades of gray.
7269 Note that color displays do support shades of gray.
7270 The optional argument DISPLAY specifies which display to ask about.
7271 DISPLAY should be either a frame or a display name (a string).
7272 If omitted or nil, that stands for the selected frame's display. */)
7273 (display)
7274 Lisp_Object display;
7275 {
7276 struct w32_display_info *dpyinfo = check_x_display_info (display);
7277
7278 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7279 return Qnil;
7280
7281 return Qt;
7282 }
7283
7284 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7285 Sx_display_pixel_width, 0, 1, 0,
7286 doc: /* Returns the width in pixels of DISPLAY.
7287 The optional argument DISPLAY specifies which display to ask about.
7288 DISPLAY should be either a frame or a display name (a string).
7289 If omitted or nil, that stands for the selected frame's display. */)
7290 (display)
7291 Lisp_Object display;
7292 {
7293 struct w32_display_info *dpyinfo = check_x_display_info (display);
7294
7295 return make_number (dpyinfo->width);
7296 }
7297
7298 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7299 Sx_display_pixel_height, 0, 1, 0,
7300 doc: /* Returns the height in pixels of DISPLAY.
7301 The optional argument DISPLAY specifies which display to ask about.
7302 DISPLAY should be either a frame or a display name (a string).
7303 If omitted or nil, that stands for the selected frame's display. */)
7304 (display)
7305 Lisp_Object display;
7306 {
7307 struct w32_display_info *dpyinfo = check_x_display_info (display);
7308
7309 return make_number (dpyinfo->height);
7310 }
7311
7312 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7313 0, 1, 0,
7314 doc: /* Returns the number of bitplanes of DISPLAY.
7315 The optional argument DISPLAY specifies which display to ask about.
7316 DISPLAY should be either a frame or a display name (a string).
7317 If omitted or nil, that stands for the selected frame's display. */)
7318 (display)
7319 Lisp_Object display;
7320 {
7321 struct w32_display_info *dpyinfo = check_x_display_info (display);
7322
7323 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7324 }
7325
7326 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7327 0, 1, 0,
7328 doc: /* Returns the number of color cells of DISPLAY.
7329 The optional argument DISPLAY specifies which display to ask about.
7330 DISPLAY should be either a frame or a display name (a string).
7331 If omitted or nil, that stands for the selected frame's display. */)
7332 (display)
7333 Lisp_Object display;
7334 {
7335 struct w32_display_info *dpyinfo = check_x_display_info (display);
7336 HDC hdc;
7337 int cap;
7338
7339 hdc = GetDC (dpyinfo->root_window);
7340 if (dpyinfo->has_palette)
7341 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7342 else
7343 cap = GetDeviceCaps (hdc,NUMCOLORS);
7344
7345 if (cap < 0)
7346 cap = 1 << (dpyinfo->n_planes * dpyinfo->n_cbits);
7347
7348 ReleaseDC (dpyinfo->root_window, hdc);
7349
7350 return make_number (cap);
7351 }
7352
7353 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7354 Sx_server_max_request_size,
7355 0, 1, 0,
7356 doc: /* Returns the maximum request size of the server of DISPLAY.
7357 The optional argument DISPLAY specifies which display to ask about.
7358 DISPLAY should be either a frame or a display name (a string).
7359 If omitted or nil, that stands for the selected frame's display. */)
7360 (display)
7361 Lisp_Object display;
7362 {
7363 struct w32_display_info *dpyinfo = check_x_display_info (display);
7364
7365 return make_number (1);
7366 }
7367
7368 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7369 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7370 The optional argument DISPLAY specifies which display to ask about.
7371 DISPLAY should be either a frame or a display name (a string).
7372 If omitted or nil, that stands for the selected frame's display. */)
7373 (display)
7374 Lisp_Object display;
7375 {
7376 return build_string ("Microsoft Corp.");
7377 }
7378
7379 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7380 doc: /* Returns the version numbers of the server of DISPLAY.
7381 The value is a list of three integers: the major and minor
7382 version numbers, and the vendor-specific release
7383 number. See also the function `x-server-vendor'.
7384
7385 The optional argument DISPLAY specifies which display to ask about.
7386 DISPLAY should be either a frame or a display name (a string).
7387 If omitted or nil, that stands for the selected frame's display. */)
7388 (display)
7389 Lisp_Object display;
7390 {
7391 return Fcons (make_number (w32_major_version),
7392 Fcons (make_number (w32_minor_version),
7393 Fcons (make_number (w32_build_number), Qnil)));
7394 }
7395
7396 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7397 doc: /* Returns the number of screens on the server of DISPLAY.
7398 The optional argument DISPLAY specifies which display to ask about.
7399 DISPLAY should be either a frame or a display name (a string).
7400 If omitted or nil, that stands for the selected frame's display. */)
7401 (display)
7402 Lisp_Object display;
7403 {
7404 return make_number (1);
7405 }
7406
7407 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7408 Sx_display_mm_height, 0, 1, 0,
7409 doc: /* Returns the height in millimeters of DISPLAY.
7410 The optional argument DISPLAY specifies which display to ask about.
7411 DISPLAY should be either a frame or a display name (a string).
7412 If omitted or nil, that stands for the selected frame's display. */)
7413 (display)
7414 Lisp_Object display;
7415 {
7416 struct w32_display_info *dpyinfo = check_x_display_info (display);
7417 HDC hdc;
7418 int cap;
7419
7420 hdc = GetDC (dpyinfo->root_window);
7421
7422 cap = GetDeviceCaps (hdc, VERTSIZE);
7423
7424 ReleaseDC (dpyinfo->root_window, hdc);
7425
7426 return make_number (cap);
7427 }
7428
7429 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7430 doc: /* Returns the width in millimeters of DISPLAY.
7431 The optional argument DISPLAY specifies which display to ask about.
7432 DISPLAY should be either a frame or a display name (a string).
7433 If omitted or nil, that stands for the selected frame's display. */)
7434 (display)
7435 Lisp_Object display;
7436 {
7437 struct w32_display_info *dpyinfo = check_x_display_info (display);
7438
7439 HDC hdc;
7440 int cap;
7441
7442 hdc = GetDC (dpyinfo->root_window);
7443
7444 cap = GetDeviceCaps (hdc, HORZSIZE);
7445
7446 ReleaseDC (dpyinfo->root_window, hdc);
7447
7448 return make_number (cap);
7449 }
7450
7451 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7452 Sx_display_backing_store, 0, 1, 0,
7453 doc: /* Returns an indication of whether DISPLAY does backing store.
7454 The value may be `always', `when-mapped', or `not-useful'.
7455 The optional argument DISPLAY specifies which display to ask about.
7456 DISPLAY should be either a frame or a display name (a string).
7457 If omitted or nil, that stands for the selected frame's display. */)
7458 (display)
7459 Lisp_Object display;
7460 {
7461 return intern ("not-useful");
7462 }
7463
7464 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7465 Sx_display_visual_class, 0, 1, 0,
7466 doc: /* Returns the visual class of DISPLAY.
7467 The value is one of the symbols `static-gray', `gray-scale',
7468 `static-color', `pseudo-color', `true-color', or `direct-color'.
7469
7470 The optional argument DISPLAY specifies which display to ask about.
7471 DISPLAY should be either a frame or a display name (a string).
7472 If omitted or nil, that stands for the selected frame's display. */)
7473 (display)
7474 Lisp_Object display;
7475 {
7476 struct w32_display_info *dpyinfo = check_x_display_info (display);
7477 Lisp_Object result = Qnil;
7478
7479 if (dpyinfo->has_palette)
7480 result = intern ("pseudo-color");
7481 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7482 result = intern ("static-grey");
7483 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7484 result = intern ("static-color");
7485 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7486 result = intern ("true-color");
7487
7488 return result;
7489 }
7490
7491 DEFUN ("x-display-save-under", Fx_display_save_under,
7492 Sx_display_save_under, 0, 1, 0,
7493 doc: /* Returns t if DISPLAY supports the save-under feature.
7494 The optional argument DISPLAY specifies which display to ask about.
7495 DISPLAY should be either a frame or a display name (a string).
7496 If omitted or nil, that stands for the selected frame's display. */)
7497 (display)
7498 Lisp_Object display;
7499 {
7500 return Qnil;
7501 }
7502 \f
7503 int
7504 x_pixel_width (f)
7505 register struct frame *f;
7506 {
7507 return PIXEL_WIDTH (f);
7508 }
7509
7510 int
7511 x_pixel_height (f)
7512 register struct frame *f;
7513 {
7514 return PIXEL_HEIGHT (f);
7515 }
7516
7517 int
7518 x_char_width (f)
7519 register struct frame *f;
7520 {
7521 return FONT_WIDTH (f->output_data.w32->font);
7522 }
7523
7524 int
7525 x_char_height (f)
7526 register struct frame *f;
7527 {
7528 return f->output_data.w32->line_height;
7529 }
7530
7531 int
7532 x_screen_planes (f)
7533 register struct frame *f;
7534 {
7535 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7536 }
7537 \f
7538 /* Return the display structure for the display named NAME.
7539 Open a new connection if necessary. */
7540
7541 struct w32_display_info *
7542 x_display_info_for_name (name)
7543 Lisp_Object name;
7544 {
7545 Lisp_Object names;
7546 struct w32_display_info *dpyinfo;
7547
7548 CHECK_STRING (name);
7549
7550 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7551 dpyinfo;
7552 dpyinfo = dpyinfo->next, names = XCDR (names))
7553 {
7554 Lisp_Object tem;
7555 tem = Fstring_equal (XCAR (XCAR (names)), name);
7556 if (!NILP (tem))
7557 return dpyinfo;
7558 }
7559
7560 /* Use this general default value to start with. */
7561 Vx_resource_name = Vinvocation_name;
7562
7563 validate_x_resource_name ();
7564
7565 dpyinfo = w32_term_init (name, (unsigned char *)0,
7566 (char *) XSTRING (Vx_resource_name)->data);
7567
7568 if (dpyinfo == 0)
7569 error ("Cannot connect to server %s", XSTRING (name)->data);
7570
7571 w32_in_use = 1;
7572 XSETFASTINT (Vwindow_system_version, 3);
7573
7574 return dpyinfo;
7575 }
7576
7577 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
7578 1, 3, 0, doc: /* Open a connection to a server.
7579 DISPLAY is the name of the display to connect to.
7580 Optional second arg XRM-STRING is a string of resources in xrdb format.
7581 If the optional third arg MUST-SUCCEED is non-nil,
7582 terminate Emacs if we can't open the connection. */)
7583 (display, xrm_string, must_succeed)
7584 Lisp_Object display, xrm_string, must_succeed;
7585 {
7586 unsigned char *xrm_option;
7587 struct w32_display_info *dpyinfo;
7588
7589 /* If initialization has already been done, return now to avoid
7590 overwriting critical parts of one_w32_display_info. */
7591 if (w32_in_use)
7592 return Qnil;
7593
7594 CHECK_STRING (display);
7595 if (! NILP (xrm_string))
7596 CHECK_STRING (xrm_string);
7597
7598 if (! EQ (Vwindow_system, intern ("w32")))
7599 error ("Not using Microsoft Windows");
7600
7601 /* Allow color mapping to be defined externally; first look in user's
7602 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
7603 {
7604 Lisp_Object color_file;
7605 struct gcpro gcpro1;
7606
7607 color_file = build_string("~/rgb.txt");
7608
7609 GCPRO1 (color_file);
7610
7611 if (NILP (Ffile_readable_p (color_file)))
7612 color_file =
7613 Fexpand_file_name (build_string ("rgb.txt"),
7614 Fsymbol_value (intern ("data-directory")));
7615
7616 Vw32_color_map = Fw32_load_color_file (color_file);
7617
7618 UNGCPRO;
7619 }
7620 if (NILP (Vw32_color_map))
7621 Vw32_color_map = Fw32_default_color_map ();
7622
7623 if (! NILP (xrm_string))
7624 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
7625 else
7626 xrm_option = (unsigned char *) 0;
7627
7628 /* Use this general default value to start with. */
7629 /* First remove .exe suffix from invocation-name - it looks ugly. */
7630 {
7631 char basename[ MAX_PATH ], *str;
7632
7633 strcpy (basename, XSTRING (Vinvocation_name)->data);
7634 str = strrchr (basename, '.');
7635 if (str) *str = 0;
7636 Vinvocation_name = build_string (basename);
7637 }
7638 Vx_resource_name = Vinvocation_name;
7639
7640 validate_x_resource_name ();
7641
7642 /* This is what opens the connection and sets x_current_display.
7643 This also initializes many symbols, such as those used for input. */
7644 dpyinfo = w32_term_init (display, xrm_option,
7645 (char *) XSTRING (Vx_resource_name)->data);
7646
7647 if (dpyinfo == 0)
7648 {
7649 if (!NILP (must_succeed))
7650 fatal ("Cannot connect to server %s.\n",
7651 XSTRING (display)->data);
7652 else
7653 error ("Cannot connect to server %s", XSTRING (display)->data);
7654 }
7655
7656 w32_in_use = 1;
7657
7658 XSETFASTINT (Vwindow_system_version, 3);
7659 return Qnil;
7660 }
7661
7662 DEFUN ("x-close-connection", Fx_close_connection,
7663 Sx_close_connection, 1, 1, 0,
7664 doc: /* Close the connection to DISPLAY's server.
7665 For DISPLAY, specify either a frame or a display name (a string).
7666 If DISPLAY is nil, that stands for the selected frame's display. */)
7667 (display)
7668 Lisp_Object display;
7669 {
7670 struct w32_display_info *dpyinfo = check_x_display_info (display);
7671 int i;
7672
7673 if (dpyinfo->reference_count > 0)
7674 error ("Display still has frames on it");
7675
7676 BLOCK_INPUT;
7677 /* Free the fonts in the font table. */
7678 for (i = 0; i < dpyinfo->n_fonts; i++)
7679 if (dpyinfo->font_table[i].name)
7680 {
7681 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7682 xfree (dpyinfo->font_table[i].full_name);
7683 xfree (dpyinfo->font_table[i].name);
7684 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7685 }
7686 x_destroy_all_bitmaps (dpyinfo);
7687
7688 x_delete_display (dpyinfo);
7689 UNBLOCK_INPUT;
7690
7691 return Qnil;
7692 }
7693
7694 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7695 doc: /* Return the list of display names that Emacs has connections to. */)
7696 ()
7697 {
7698 Lisp_Object tail, result;
7699
7700 result = Qnil;
7701 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
7702 result = Fcons (XCAR (XCAR (tail)), result);
7703
7704 return result;
7705 }
7706
7707 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7708 doc: /* This is a noop on W32 systems. */)
7709 (on, display)
7710 Lisp_Object display, on;
7711 {
7712 return Qnil;
7713 }
7714
7715 \f
7716 \f
7717 /***********************************************************************
7718 Image types
7719 ***********************************************************************/
7720
7721 /* Value is the number of elements of vector VECTOR. */
7722
7723 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
7724
7725 /* List of supported image types. Use define_image_type to add new
7726 types. Use lookup_image_type to find a type for a given symbol. */
7727
7728 static struct image_type *image_types;
7729
7730 /* The symbol `image' which is the car of the lists used to represent
7731 images in Lisp. */
7732
7733 extern Lisp_Object Qimage;
7734
7735 /* The symbol `xbm' which is used as the type symbol for XBM images. */
7736
7737 Lisp_Object Qxbm;
7738
7739 /* Keywords. */
7740
7741 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
7742 extern Lisp_Object QCdata;
7743 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
7744 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
7745 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
7746
7747 /* Other symbols. */
7748
7749 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
7750
7751 /* Time in seconds after which images should be removed from the cache
7752 if not displayed. */
7753
7754 Lisp_Object Vimage_cache_eviction_delay;
7755
7756 /* Function prototypes. */
7757
7758 static void define_image_type P_ ((struct image_type *type));
7759 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
7760 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
7761 static void x_laplace P_ ((struct frame *, struct image *));
7762 static void x_emboss P_ ((struct frame *, struct image *));
7763 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
7764 Lisp_Object));
7765
7766
7767 /* Define a new image type from TYPE. This adds a copy of TYPE to
7768 image_types and adds the symbol *TYPE->type to Vimage_types. */
7769
7770 static void
7771 define_image_type (type)
7772 struct image_type *type;
7773 {
7774 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
7775 The initialized data segment is read-only. */
7776 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
7777 bcopy (type, p, sizeof *p);
7778 p->next = image_types;
7779 image_types = p;
7780 Vimage_types = Fcons (*p->type, Vimage_types);
7781 }
7782
7783
7784 /* Look up image type SYMBOL, and return a pointer to its image_type
7785 structure. Value is null if SYMBOL is not a known image type. */
7786
7787 static INLINE struct image_type *
7788 lookup_image_type (symbol)
7789 Lisp_Object symbol;
7790 {
7791 struct image_type *type;
7792
7793 for (type = image_types; type; type = type->next)
7794 if (EQ (symbol, *type->type))
7795 break;
7796
7797 return type;
7798 }
7799
7800
7801 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
7802 valid image specification is a list whose car is the symbol
7803 `image', and whose rest is a property list. The property list must
7804 contain a value for key `:type'. That value must be the name of a
7805 supported image type. The rest of the property list depends on the
7806 image type. */
7807
7808 int
7809 valid_image_p (object)
7810 Lisp_Object object;
7811 {
7812 int valid_p = 0;
7813
7814 if (CONSP (object) && EQ (XCAR (object), Qimage))
7815 {
7816 Lisp_Object tem;
7817
7818 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
7819 if (EQ (XCAR (tem), QCtype))
7820 {
7821 tem = XCDR (tem);
7822 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
7823 {
7824 struct image_type *type;
7825 type = lookup_image_type (XCAR (tem));
7826 if (type)
7827 valid_p = type->valid_p (object);
7828 }
7829
7830 break;
7831 }
7832 }
7833
7834 return valid_p;
7835 }
7836
7837
7838 /* Log error message with format string FORMAT and argument ARG.
7839 Signaling an error, e.g. when an image cannot be loaded, is not a
7840 good idea because this would interrupt redisplay, and the error
7841 message display would lead to another redisplay. This function
7842 therefore simply displays a message. */
7843
7844 static void
7845 image_error (format, arg1, arg2)
7846 char *format;
7847 Lisp_Object arg1, arg2;
7848 {
7849 add_to_log (format, arg1, arg2);
7850 }
7851
7852
7853 \f
7854 /***********************************************************************
7855 Image specifications
7856 ***********************************************************************/
7857
7858 enum image_value_type
7859 {
7860 IMAGE_DONT_CHECK_VALUE_TYPE,
7861 IMAGE_STRING_VALUE,
7862 IMAGE_STRING_OR_NIL_VALUE,
7863 IMAGE_SYMBOL_VALUE,
7864 IMAGE_POSITIVE_INTEGER_VALUE,
7865 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
7866 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
7867 IMAGE_ASCENT_VALUE,
7868 IMAGE_INTEGER_VALUE,
7869 IMAGE_FUNCTION_VALUE,
7870 IMAGE_NUMBER_VALUE,
7871 IMAGE_BOOL_VALUE
7872 };
7873
7874 /* Structure used when parsing image specifications. */
7875
7876 struct image_keyword
7877 {
7878 /* Name of keyword. */
7879 char *name;
7880
7881 /* The type of value allowed. */
7882 enum image_value_type type;
7883
7884 /* Non-zero means key must be present. */
7885 int mandatory_p;
7886
7887 /* Used to recognize duplicate keywords in a property list. */
7888 int count;
7889
7890 /* The value that was found. */
7891 Lisp_Object value;
7892 };
7893
7894
7895 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
7896 int, Lisp_Object));
7897 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
7898
7899
7900 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
7901 has the format (image KEYWORD VALUE ...). One of the keyword/
7902 value pairs must be `:type TYPE'. KEYWORDS is a vector of
7903 image_keywords structures of size NKEYWORDS describing other
7904 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
7905
7906 static int
7907 parse_image_spec (spec, keywords, nkeywords, type)
7908 Lisp_Object spec;
7909 struct image_keyword *keywords;
7910 int nkeywords;
7911 Lisp_Object type;
7912 {
7913 int i;
7914 Lisp_Object plist;
7915
7916 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
7917 return 0;
7918
7919 plist = XCDR (spec);
7920 while (CONSP (plist))
7921 {
7922 Lisp_Object key, value;
7923
7924 /* First element of a pair must be a symbol. */
7925 key = XCAR (plist);
7926 plist = XCDR (plist);
7927 if (!SYMBOLP (key))
7928 return 0;
7929
7930 /* There must follow a value. */
7931 if (!CONSP (plist))
7932 return 0;
7933 value = XCAR (plist);
7934 plist = XCDR (plist);
7935
7936 /* Find key in KEYWORDS. Error if not found. */
7937 for (i = 0; i < nkeywords; ++i)
7938 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
7939 break;
7940
7941 if (i == nkeywords)
7942 continue;
7943
7944 /* Record that we recognized the keyword. If a keywords
7945 was found more than once, it's an error. */
7946 keywords[i].value = value;
7947 ++keywords[i].count;
7948
7949 if (keywords[i].count > 1)
7950 return 0;
7951
7952 /* Check type of value against allowed type. */
7953 switch (keywords[i].type)
7954 {
7955 case IMAGE_STRING_VALUE:
7956 if (!STRINGP (value))
7957 return 0;
7958 break;
7959
7960 case IMAGE_STRING_OR_NIL_VALUE:
7961 if (!STRINGP (value) && !NILP (value))
7962 return 0;
7963 break;
7964
7965 case IMAGE_SYMBOL_VALUE:
7966 if (!SYMBOLP (value))
7967 return 0;
7968 break;
7969
7970 case IMAGE_POSITIVE_INTEGER_VALUE:
7971 if (!INTEGERP (value) || XINT (value) <= 0)
7972 return 0;
7973 break;
7974
7975 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
7976 if (INTEGERP (value) && XINT (value) >= 0)
7977 break;
7978 if (CONSP (value)
7979 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
7980 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
7981 break;
7982 return 0;
7983
7984 case IMAGE_ASCENT_VALUE:
7985 if (SYMBOLP (value) && EQ (value, Qcenter))
7986 break;
7987 else if (INTEGERP (value)
7988 && XINT (value) >= 0
7989 && XINT (value) <= 100)
7990 break;
7991 return 0;
7992
7993 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
7994 if (!INTEGERP (value) || XINT (value) < 0)
7995 return 0;
7996 break;
7997
7998 case IMAGE_DONT_CHECK_VALUE_TYPE:
7999 break;
8000
8001 case IMAGE_FUNCTION_VALUE:
8002 value = indirect_function (value);
8003 if (SUBRP (value)
8004 || COMPILEDP (value)
8005 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8006 break;
8007 return 0;
8008
8009 case IMAGE_NUMBER_VALUE:
8010 if (!INTEGERP (value) && !FLOATP (value))
8011 return 0;
8012 break;
8013
8014 case IMAGE_INTEGER_VALUE:
8015 if (!INTEGERP (value))
8016 return 0;
8017 break;
8018
8019 case IMAGE_BOOL_VALUE:
8020 if (!NILP (value) && !EQ (value, Qt))
8021 return 0;
8022 break;
8023
8024 default:
8025 abort ();
8026 break;
8027 }
8028
8029 if (EQ (key, QCtype) && !EQ (type, value))
8030 return 0;
8031 }
8032
8033 /* Check that all mandatory fields are present. */
8034 for (i = 0; i < nkeywords; ++i)
8035 if (keywords[i].mandatory_p && keywords[i].count == 0)
8036 return 0;
8037
8038 return NILP (plist);
8039 }
8040
8041
8042 /* Return the value of KEY in image specification SPEC. Value is nil
8043 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8044 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8045
8046 static Lisp_Object
8047 image_spec_value (spec, key, found)
8048 Lisp_Object spec, key;
8049 int *found;
8050 {
8051 Lisp_Object tail;
8052
8053 xassert (valid_image_p (spec));
8054
8055 for (tail = XCDR (spec);
8056 CONSP (tail) && CONSP (XCDR (tail));
8057 tail = XCDR (XCDR (tail)))
8058 {
8059 if (EQ (XCAR (tail), key))
8060 {
8061 if (found)
8062 *found = 1;
8063 return XCAR (XCDR (tail));
8064 }
8065 }
8066
8067 if (found)
8068 *found = 0;
8069 return Qnil;
8070 }
8071
8072
8073
8074 \f
8075 /***********************************************************************
8076 Image type independent image structures
8077 ***********************************************************************/
8078
8079 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8080 static void free_image P_ ((struct frame *f, struct image *img));
8081
8082
8083 /* Allocate and return a new image structure for image specification
8084 SPEC. SPEC has a hash value of HASH. */
8085
8086 static struct image *
8087 make_image (spec, hash)
8088 Lisp_Object spec;
8089 unsigned hash;
8090 {
8091 struct image *img = (struct image *) xmalloc (sizeof *img);
8092
8093 xassert (valid_image_p (spec));
8094 bzero (img, sizeof *img);
8095 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8096 xassert (img->type != NULL);
8097 img->spec = spec;
8098 img->data.lisp_val = Qnil;
8099 img->ascent = DEFAULT_IMAGE_ASCENT;
8100 img->hash = hash;
8101 return img;
8102 }
8103
8104
8105 /* Free image IMG which was used on frame F, including its resources. */
8106
8107 static void
8108 free_image (f, img)
8109 struct frame *f;
8110 struct image *img;
8111 {
8112 if (img)
8113 {
8114 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8115
8116 /* Remove IMG from the hash table of its cache. */
8117 if (img->prev)
8118 img->prev->next = img->next;
8119 else
8120 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8121
8122 if (img->next)
8123 img->next->prev = img->prev;
8124
8125 c->images[img->id] = NULL;
8126
8127 /* Free resources, then free IMG. */
8128 img->type->free (f, img);
8129 xfree (img);
8130 }
8131 }
8132
8133
8134 /* Prepare image IMG for display on frame F. Must be called before
8135 drawing an image. */
8136
8137 void
8138 prepare_image_for_display (f, img)
8139 struct frame *f;
8140 struct image *img;
8141 {
8142 EMACS_TIME t;
8143
8144 /* We're about to display IMG, so set its timestamp to `now'. */
8145 EMACS_GET_TIME (t);
8146 img->timestamp = EMACS_SECS (t);
8147
8148 /* If IMG doesn't have a pixmap yet, load it now, using the image
8149 type dependent loader function. */
8150 if (img->pixmap == 0 && !img->load_failed_p)
8151 img->load_failed_p = img->type->load (f, img) == 0;
8152 }
8153
8154
8155 /* Value is the number of pixels for the ascent of image IMG when
8156 drawn in face FACE. */
8157
8158 int
8159 image_ascent (img, face)
8160 struct image *img;
8161 struct face *face;
8162 {
8163 int height = img->height + img->vmargin;
8164 int ascent;
8165
8166 if (img->ascent == CENTERED_IMAGE_ASCENT)
8167 {
8168 if (face->font)
8169 ascent = height / 2 - (FONT_DESCENT(face->font)
8170 - FONT_BASE(face->font)) / 2;
8171 else
8172 ascent = height / 2;
8173 }
8174 else
8175 ascent = height * img->ascent / 100.0;
8176
8177 return ascent;
8178 }
8179
8180
8181 \f
8182 /***********************************************************************
8183 Helper functions for X image types
8184 ***********************************************************************/
8185
8186 static void x_clear_image P_ ((struct frame *f, struct image *img));
8187 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8188 struct image *img,
8189 Lisp_Object color_name,
8190 unsigned long dflt));
8191
8192 /* Free X resources of image IMG which is used on frame F. */
8193
8194 static void
8195 x_clear_image (f, img)
8196 struct frame *f;
8197 struct image *img;
8198 {
8199 #if 0 /* TODO: W32 image support */
8200
8201 if (img->pixmap)
8202 {
8203 BLOCK_INPUT;
8204 XFreePixmap (NULL, img->pixmap);
8205 img->pixmap = 0;
8206 UNBLOCK_INPUT;
8207 }
8208
8209 if (img->ncolors)
8210 {
8211 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8212
8213 /* If display has an immutable color map, freeing colors is not
8214 necessary and some servers don't allow it. So don't do it. */
8215 if (class != StaticColor
8216 && class != StaticGray
8217 && class != TrueColor)
8218 {
8219 Colormap cmap;
8220 BLOCK_INPUT;
8221 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8222 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8223 img->ncolors, 0);
8224 UNBLOCK_INPUT;
8225 }
8226
8227 xfree (img->colors);
8228 img->colors = NULL;
8229 img->ncolors = 0;
8230 }
8231 #endif
8232 }
8233
8234
8235 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8236 cannot be allocated, use DFLT. Add a newly allocated color to
8237 IMG->colors, so that it can be freed again. Value is the pixel
8238 color. */
8239
8240 static unsigned long
8241 x_alloc_image_color (f, img, color_name, dflt)
8242 struct frame *f;
8243 struct image *img;
8244 Lisp_Object color_name;
8245 unsigned long dflt;
8246 {
8247 #if 0 /* TODO: allocing colors. */
8248 XColor color;
8249 unsigned long result;
8250
8251 xassert (STRINGP (color_name));
8252
8253 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8254 {
8255 /* This isn't called frequently so we get away with simply
8256 reallocating the color vector to the needed size, here. */
8257 ++img->ncolors;
8258 img->colors =
8259 (unsigned long *) xrealloc (img->colors,
8260 img->ncolors * sizeof *img->colors);
8261 img->colors[img->ncolors - 1] = color.pixel;
8262 result = color.pixel;
8263 }
8264 else
8265 result = dflt;
8266 return result;
8267 #endif
8268 return 0;
8269 }
8270
8271
8272 \f
8273 /***********************************************************************
8274 Image Cache
8275 ***********************************************************************/
8276
8277 static void cache_image P_ ((struct frame *f, struct image *img));
8278 static void postprocess_image P_ ((struct frame *, struct image *));
8279
8280
8281 /* Return a new, initialized image cache that is allocated from the
8282 heap. Call free_image_cache to free an image cache. */
8283
8284 struct image_cache *
8285 make_image_cache ()
8286 {
8287 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8288 int size;
8289
8290 bzero (c, sizeof *c);
8291 c->size = 50;
8292 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8293 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8294 c->buckets = (struct image **) xmalloc (size);
8295 bzero (c->buckets, size);
8296 return c;
8297 }
8298
8299
8300 /* Free image cache of frame F. Be aware that X frames share images
8301 caches. */
8302
8303 void
8304 free_image_cache (f)
8305 struct frame *f;
8306 {
8307 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8308 if (c)
8309 {
8310 int i;
8311
8312 /* Cache should not be referenced by any frame when freed. */
8313 xassert (c->refcount == 0);
8314
8315 for (i = 0; i < c->used; ++i)
8316 free_image (f, c->images[i]);
8317 xfree (c->images);
8318 xfree (c);
8319 xfree (c->buckets);
8320 FRAME_X_IMAGE_CACHE (f) = NULL;
8321 }
8322 }
8323
8324
8325 /* Clear image cache of frame F. FORCE_P non-zero means free all
8326 images. FORCE_P zero means clear only images that haven't been
8327 displayed for some time. Should be called from time to time to
8328 reduce the number of loaded images. If image-eviction-seconds is
8329 non-nil, this frees images in the cache which weren't displayed for
8330 at least that many seconds. */
8331
8332 void
8333 clear_image_cache (f, force_p)
8334 struct frame *f;
8335 int force_p;
8336 {
8337 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8338
8339 if (c && INTEGERP (Vimage_cache_eviction_delay))
8340 {
8341 EMACS_TIME t;
8342 unsigned long old;
8343 int i, any_freed_p = 0;
8344
8345 EMACS_GET_TIME (t);
8346 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8347
8348 for (i = 0; i < c->used; ++i)
8349 {
8350 struct image *img = c->images[i];
8351 if (img != NULL
8352 && (force_p
8353 || (img->timestamp > old)))
8354 {
8355 free_image (f, img);
8356 any_freed_p = 1;
8357 }
8358 }
8359
8360 /* We may be clearing the image cache because, for example,
8361 Emacs was iconified for a longer period of time. In that
8362 case, current matrices may still contain references to
8363 images freed above. So, clear these matrices. */
8364 if (any_freed_p)
8365 {
8366 clear_current_matrices (f);
8367 ++windows_or_buffers_changed;
8368 }
8369 }
8370 }
8371
8372
8373 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8374 0, 1, 0,
8375 doc: /* Clear the image cache of FRAME.
8376 FRAME nil or omitted means use the selected frame.
8377 FRAME t means clear the image caches of all frames. */)
8378 (frame)
8379 Lisp_Object frame;
8380 {
8381 if (EQ (frame, Qt))
8382 {
8383 Lisp_Object tail;
8384
8385 FOR_EACH_FRAME (tail, frame)
8386 if (FRAME_W32_P (XFRAME (frame)))
8387 clear_image_cache (XFRAME (frame), 1);
8388 }
8389 else
8390 clear_image_cache (check_x_frame (frame), 1);
8391
8392 return Qnil;
8393 }
8394
8395
8396 /* Compute masks and transform image IMG on frame F, as specified
8397 by the image's specification, */
8398
8399 static void
8400 postprocess_image (f, img)
8401 struct frame *f;
8402 struct image *img;
8403 {
8404 #if 0 /* TODO: image support. */
8405 /* Manipulation of the image's mask. */
8406 if (img->pixmap)
8407 {
8408 Lisp_Object conversion, spec;
8409 Lisp_Object mask;
8410
8411 spec = img->spec;
8412
8413 /* `:heuristic-mask t'
8414 `:mask heuristic'
8415 means build a mask heuristically.
8416 `:heuristic-mask (R G B)'
8417 `:mask (heuristic (R G B))'
8418 means build a mask from color (R G B) in the
8419 image.
8420 `:mask nil'
8421 means remove a mask, if any. */
8422
8423 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8424 if (!NILP (mask))
8425 x_build_heuristic_mask (f, img, mask);
8426 else
8427 {
8428 int found_p;
8429
8430 mask = image_spec_value (spec, QCmask, &found_p);
8431
8432 if (EQ (mask, Qheuristic))
8433 x_build_heuristic_mask (f, img, Qt);
8434 else if (CONSP (mask)
8435 && EQ (XCAR (mask), Qheuristic))
8436 {
8437 if (CONSP (XCDR (mask)))
8438 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
8439 else
8440 x_build_heuristic_mask (f, img, XCDR (mask));
8441 }
8442 else if (NILP (mask) && found_p && img->mask)
8443 {
8444 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8445 img->mask = NULL;
8446 }
8447 }
8448
8449
8450 /* Should we apply an image transformation algorithm? */
8451 conversion = image_spec_value (spec, QCconversion, NULL);
8452 if (EQ (conversion, Qdisabled))
8453 x_disable_image (f, img);
8454 else if (EQ (conversion, Qlaplace))
8455 x_laplace (f, img);
8456 else if (EQ (conversion, Qemboss))
8457 x_emboss (f, img);
8458 else if (CONSP (conversion)
8459 && EQ (XCAR (conversion), Qedge_detection))
8460 {
8461 Lisp_Object tem;
8462 tem = XCDR (conversion);
8463 if (CONSP (tem))
8464 x_edge_detection (f, img,
8465 Fplist_get (tem, QCmatrix),
8466 Fplist_get (tem, QCcolor_adjustment));
8467 }
8468 }
8469 #endif
8470 }
8471
8472
8473 /* Return the id of image with Lisp specification SPEC on frame F.
8474 SPEC must be a valid Lisp image specification (see valid_image_p). */
8475
8476 int
8477 lookup_image (f, spec)
8478 struct frame *f;
8479 Lisp_Object spec;
8480 {
8481 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8482 struct image *img;
8483 int i;
8484 unsigned hash;
8485 struct gcpro gcpro1;
8486 EMACS_TIME now;
8487
8488 /* F must be a window-system frame, and SPEC must be a valid image
8489 specification. */
8490 xassert (FRAME_WINDOW_P (f));
8491 xassert (valid_image_p (spec));
8492
8493 GCPRO1 (spec);
8494
8495 /* Look up SPEC in the hash table of the image cache. */
8496 hash = sxhash (spec, 0);
8497 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
8498
8499 for (img = c->buckets[i]; img; img = img->next)
8500 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
8501 break;
8502
8503 /* If not found, create a new image and cache it. */
8504 if (img == NULL)
8505 {
8506 extern Lisp_Object Qpostscript;
8507
8508 BLOCK_INPUT;
8509 img = make_image (spec, hash);
8510 cache_image (f, img);
8511 img->load_failed_p = img->type->load (f, img) == 0;
8512
8513 /* If we can't load the image, and we don't have a width and
8514 height, use some arbitrary width and height so that we can
8515 draw a rectangle for it. */
8516 if (img->load_failed_p)
8517 {
8518 Lisp_Object value;
8519
8520 value = image_spec_value (spec, QCwidth, NULL);
8521 img->width = (INTEGERP (value)
8522 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
8523 value = image_spec_value (spec, QCheight, NULL);
8524 img->height = (INTEGERP (value)
8525 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
8526 }
8527 else
8528 {
8529 /* Handle image type independent image attributes
8530 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF'. */
8531 Lisp_Object ascent, margin, relief;
8532
8533 ascent = image_spec_value (spec, QCascent, NULL);
8534 if (INTEGERP (ascent))
8535 img->ascent = XFASTINT (ascent);
8536 else if (EQ (ascent, Qcenter))
8537 img->ascent = CENTERED_IMAGE_ASCENT;
8538
8539 margin = image_spec_value (spec, QCmargin, NULL);
8540 if (INTEGERP (margin) && XINT (margin) >= 0)
8541 img->vmargin = img->hmargin = XFASTINT (margin);
8542 else if (CONSP (margin) && INTEGERP (XCAR (margin))
8543 && INTEGERP (XCDR (margin)))
8544 {
8545 if (XINT (XCAR (margin)) > 0)
8546 img->hmargin = XFASTINT (XCAR (margin));
8547 if (XINT (XCDR (margin)) > 0)
8548 img->vmargin = XFASTINT (XCDR (margin));
8549 }
8550
8551 relief = image_spec_value (spec, QCrelief, NULL);
8552 if (INTEGERP (relief))
8553 {
8554 img->relief = XINT (relief);
8555 img->hmargin += abs (img->relief);
8556 img->vmargin += abs (img->relief);
8557 }
8558
8559 /* Do image transformations and compute masks, unless we
8560 don't have the image yet. */
8561 if (!EQ (*img->type->type, Qpostscript))
8562 postprocess_image (f, img);
8563 }
8564
8565 UNBLOCK_INPUT;
8566 xassert (!interrupt_input_blocked);
8567 }
8568
8569 /* We're using IMG, so set its timestamp to `now'. */
8570 EMACS_GET_TIME (now);
8571 img->timestamp = EMACS_SECS (now);
8572
8573 UNGCPRO;
8574
8575 /* Value is the image id. */
8576 return img->id;
8577 }
8578
8579
8580 /* Cache image IMG in the image cache of frame F. */
8581
8582 static void
8583 cache_image (f, img)
8584 struct frame *f;
8585 struct image *img;
8586 {
8587 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8588 int i;
8589
8590 /* Find a free slot in c->images. */
8591 for (i = 0; i < c->used; ++i)
8592 if (c->images[i] == NULL)
8593 break;
8594
8595 /* If no free slot found, maybe enlarge c->images. */
8596 if (i == c->used && c->used == c->size)
8597 {
8598 c->size *= 2;
8599 c->images = (struct image **) xrealloc (c->images,
8600 c->size * sizeof *c->images);
8601 }
8602
8603 /* Add IMG to c->images, and assign IMG an id. */
8604 c->images[i] = img;
8605 img->id = i;
8606 if (i == c->used)
8607 ++c->used;
8608
8609 /* Add IMG to the cache's hash table. */
8610 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
8611 img->next = c->buckets[i];
8612 if (img->next)
8613 img->next->prev = img;
8614 img->prev = NULL;
8615 c->buckets[i] = img;
8616 }
8617
8618
8619 /* Call FN on every image in the image cache of frame F. Used to mark
8620 Lisp Objects in the image cache. */
8621
8622 void
8623 forall_images_in_image_cache (f, fn)
8624 struct frame *f;
8625 void (*fn) P_ ((struct image *img));
8626 {
8627 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
8628 {
8629 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8630 if (c)
8631 {
8632 int i;
8633 for (i = 0; i < c->used; ++i)
8634 if (c->images[i])
8635 fn (c->images[i]);
8636 }
8637 }
8638 }
8639
8640
8641 \f
8642 /***********************************************************************
8643 W32 support code
8644 ***********************************************************************/
8645
8646 #if 0 /* TODO: W32 specific image code. */
8647
8648 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
8649 XImage **, Pixmap *));
8650 static void x_destroy_x_image P_ ((XImage *));
8651 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
8652
8653
8654 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
8655 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
8656 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
8657 via xmalloc. Print error messages via image_error if an error
8658 occurs. Value is non-zero if successful. */
8659
8660 static int
8661 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
8662 struct frame *f;
8663 int width, height, depth;
8664 XImage **ximg;
8665 Pixmap *pixmap;
8666 {
8667 #if 0 /* TODO: Image support for W32 */
8668 Display *display = FRAME_W32_DISPLAY (f);
8669 Screen *screen = FRAME_X_SCREEN (f);
8670 Window window = FRAME_W32_WINDOW (f);
8671
8672 xassert (interrupt_input_blocked);
8673
8674 if (depth <= 0)
8675 depth = DefaultDepthOfScreen (screen);
8676 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
8677 depth, ZPixmap, 0, NULL, width, height,
8678 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
8679 if (*ximg == NULL)
8680 {
8681 image_error ("Unable to allocate X image", Qnil, Qnil);
8682 return 0;
8683 }
8684
8685 /* Allocate image raster. */
8686 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
8687
8688 /* Allocate a pixmap of the same size. */
8689 *pixmap = XCreatePixmap (display, window, width, height, depth);
8690 if (*pixmap == 0)
8691 {
8692 x_destroy_x_image (*ximg);
8693 *ximg = NULL;
8694 image_error ("Unable to create X pixmap", Qnil, Qnil);
8695 return 0;
8696 }
8697 #endif
8698 return 1;
8699 }
8700
8701
8702 /* Destroy XImage XIMG. Free XIMG->data. */
8703
8704 static void
8705 x_destroy_x_image (ximg)
8706 XImage *ximg;
8707 {
8708 xassert (interrupt_input_blocked);
8709 if (ximg)
8710 {
8711 xfree (ximg->data);
8712 ximg->data = NULL;
8713 XDestroyImage (ximg);
8714 }
8715 }
8716
8717
8718 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
8719 are width and height of both the image and pixmap. */
8720
8721 static void
8722 x_put_x_image (f, ximg, pixmap, width, height)
8723 struct frame *f;
8724 XImage *ximg;
8725 Pixmap pixmap;
8726 {
8727 GC gc;
8728
8729 xassert (interrupt_input_blocked);
8730 gc = XCreateGC (NULL, pixmap, 0, NULL);
8731 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
8732 XFreeGC (NULL, gc);
8733 }
8734
8735 #endif
8736
8737 \f
8738 /***********************************************************************
8739 File Handling
8740 ***********************************************************************/
8741
8742 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
8743 static char *slurp_file P_ ((char *, int *));
8744
8745
8746 /* Find image file FILE. Look in data-directory, then
8747 x-bitmap-file-path. Value is the full name of the file found, or
8748 nil if not found. */
8749
8750 static Lisp_Object
8751 x_find_image_file (file)
8752 Lisp_Object file;
8753 {
8754 Lisp_Object file_found, search_path;
8755 struct gcpro gcpro1, gcpro2;
8756 int fd;
8757
8758 file_found = Qnil;
8759 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
8760 GCPRO2 (file_found, search_path);
8761
8762 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
8763 fd = openp (search_path, file, Qnil, &file_found, 0);
8764
8765 if (fd == -1)
8766 file_found = Qnil;
8767 else
8768 close (fd);
8769
8770 UNGCPRO;
8771 return file_found;
8772 }
8773
8774
8775 /* Read FILE into memory. Value is a pointer to a buffer allocated
8776 with xmalloc holding FILE's contents. Value is null if an error
8777 occurred. *SIZE is set to the size of the file. */
8778
8779 static char *
8780 slurp_file (file, size)
8781 char *file;
8782 int *size;
8783 {
8784 FILE *fp = NULL;
8785 char *buf = NULL;
8786 struct stat st;
8787
8788 if (stat (file, &st) == 0
8789 && (fp = fopen (file, "r")) != NULL
8790 && (buf = (char *) xmalloc (st.st_size),
8791 fread (buf, 1, st.st_size, fp) == st.st_size))
8792 {
8793 *size = st.st_size;
8794 fclose (fp);
8795 }
8796 else
8797 {
8798 if (fp)
8799 fclose (fp);
8800 if (buf)
8801 {
8802 xfree (buf);
8803 buf = NULL;
8804 }
8805 }
8806
8807 return buf;
8808 }
8809
8810
8811 \f
8812 /***********************************************************************
8813 XBM images
8814 ***********************************************************************/
8815
8816 static int xbm_load P_ ((struct frame *f, struct image *img));
8817 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
8818 Lisp_Object file));
8819 static int xbm_image_p P_ ((Lisp_Object object));
8820 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
8821 unsigned char **));
8822
8823
8824 /* Indices of image specification fields in xbm_format, below. */
8825
8826 enum xbm_keyword_index
8827 {
8828 XBM_TYPE,
8829 XBM_FILE,
8830 XBM_WIDTH,
8831 XBM_HEIGHT,
8832 XBM_DATA,
8833 XBM_FOREGROUND,
8834 XBM_BACKGROUND,
8835 XBM_ASCENT,
8836 XBM_MARGIN,
8837 XBM_RELIEF,
8838 XBM_ALGORITHM,
8839 XBM_HEURISTIC_MASK,
8840 XBM_LAST
8841 };
8842
8843 /* Vector of image_keyword structures describing the format
8844 of valid XBM image specifications. */
8845
8846 static struct image_keyword xbm_format[XBM_LAST] =
8847 {
8848 {":type", IMAGE_SYMBOL_VALUE, 1},
8849 {":file", IMAGE_STRING_VALUE, 0},
8850 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8851 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
8852 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8853 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
8854 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
8855 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
8856 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
8857 {":relief", IMAGE_INTEGER_VALUE, 0},
8858 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
8859 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
8860 };
8861
8862 /* Structure describing the image type XBM. */
8863
8864 static struct image_type xbm_type =
8865 {
8866 &Qxbm,
8867 xbm_image_p,
8868 xbm_load,
8869 x_clear_image,
8870 NULL
8871 };
8872
8873 /* Tokens returned from xbm_scan. */
8874
8875 enum xbm_token
8876 {
8877 XBM_TK_IDENT = 256,
8878 XBM_TK_NUMBER
8879 };
8880
8881
8882 /* Return non-zero if OBJECT is a valid XBM-type image specification.
8883 A valid specification is a list starting with the symbol `image'
8884 The rest of the list is a property list which must contain an
8885 entry `:type xbm..
8886
8887 If the specification specifies a file to load, it must contain
8888 an entry `:file FILENAME' where FILENAME is a string.
8889
8890 If the specification is for a bitmap loaded from memory it must
8891 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
8892 WIDTH and HEIGHT are integers > 0. DATA may be:
8893
8894 1. a string large enough to hold the bitmap data, i.e. it must
8895 have a size >= (WIDTH + 7) / 8 * HEIGHT
8896
8897 2. a bool-vector of size >= WIDTH * HEIGHT
8898
8899 3. a vector of strings or bool-vectors, one for each line of the
8900 bitmap.
8901
8902 Both the file and data forms may contain the additional entries
8903 `:background COLOR' and `:foreground COLOR'. If not present,
8904 foreground and background of the frame on which the image is
8905 displayed, is used. */
8906
8907 static int
8908 xbm_image_p (object)
8909 Lisp_Object object;
8910 {
8911 struct image_keyword kw[XBM_LAST];
8912
8913 bcopy (xbm_format, kw, sizeof kw);
8914 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
8915 return 0;
8916
8917 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
8918
8919 if (kw[XBM_FILE].count)
8920 {
8921 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
8922 return 0;
8923 }
8924 else
8925 {
8926 Lisp_Object data;
8927 int width, height;
8928
8929 /* Entries for `:width', `:height' and `:data' must be present. */
8930 if (!kw[XBM_WIDTH].count
8931 || !kw[XBM_HEIGHT].count
8932 || !kw[XBM_DATA].count)
8933 return 0;
8934
8935 data = kw[XBM_DATA].value;
8936 width = XFASTINT (kw[XBM_WIDTH].value);
8937 height = XFASTINT (kw[XBM_HEIGHT].value);
8938
8939 /* Check type of data, and width and height against contents of
8940 data. */
8941 if (VECTORP (data))
8942 {
8943 int i;
8944
8945 /* Number of elements of the vector must be >= height. */
8946 if (XVECTOR (data)->size < height)
8947 return 0;
8948
8949 /* Each string or bool-vector in data must be large enough
8950 for one line of the image. */
8951 for (i = 0; i < height; ++i)
8952 {
8953 Lisp_Object elt = XVECTOR (data)->contents[i];
8954
8955 if (STRINGP (elt))
8956 {
8957 if (XSTRING (elt)->size
8958 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
8959 return 0;
8960 }
8961 else if (BOOL_VECTOR_P (elt))
8962 {
8963 if (XBOOL_VECTOR (elt)->size < width)
8964 return 0;
8965 }
8966 else
8967 return 0;
8968 }
8969 }
8970 else if (STRINGP (data))
8971 {
8972 if (XSTRING (data)->size
8973 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
8974 return 0;
8975 }
8976 else if (BOOL_VECTOR_P (data))
8977 {
8978 if (XBOOL_VECTOR (data)->size < width * height)
8979 return 0;
8980 }
8981 else
8982 return 0;
8983 }
8984
8985 /* Baseline must be a value between 0 and 100 (a percentage). */
8986 if (kw[XBM_ASCENT].count
8987 && XFASTINT (kw[XBM_ASCENT].value) > 100)
8988 return 0;
8989
8990 return 1;
8991 }
8992
8993
8994 /* Scan a bitmap file. FP is the stream to read from. Value is
8995 either an enumerator from enum xbm_token, or a character for a
8996 single-character token, or 0 at end of file. If scanning an
8997 identifier, store the lexeme of the identifier in SVAL. If
8998 scanning a number, store its value in *IVAL. */
8999
9000 static int
9001 xbm_scan (s, end, sval, ival)
9002 char **s, *end;
9003 char *sval;
9004 int *ival;
9005 {
9006 int c;
9007
9008 loop:
9009
9010 /* Skip white space. */
9011 while (*s < end &&(c = *(*s)++, isspace (c)))
9012 ;
9013
9014 if (*s >= end)
9015 c = 0;
9016 else if (isdigit (c))
9017 {
9018 int value = 0, digit;
9019
9020 if (c == '0' && *s < end)
9021 {
9022 c = *(*s)++;
9023 if (c == 'x' || c == 'X')
9024 {
9025 while (*s < end)
9026 {
9027 c = *(*s)++;
9028 if (isdigit (c))
9029 digit = c - '0';
9030 else if (c >= 'a' && c <= 'f')
9031 digit = c - 'a' + 10;
9032 else if (c >= 'A' && c <= 'F')
9033 digit = c - 'A' + 10;
9034 else
9035 break;
9036 value = 16 * value + digit;
9037 }
9038 }
9039 else if (isdigit (c))
9040 {
9041 value = c - '0';
9042 while (*s < end
9043 && (c = *(*s)++, isdigit (c)))
9044 value = 8 * value + c - '0';
9045 }
9046 }
9047 else
9048 {
9049 value = c - '0';
9050 while (*s < end
9051 && (c = *(*s)++, isdigit (c)))
9052 value = 10 * value + c - '0';
9053 }
9054
9055 if (*s < end)
9056 *s = *s - 1;
9057 *ival = value;
9058 c = XBM_TK_NUMBER;
9059 }
9060 else if (isalpha (c) || c == '_')
9061 {
9062 *sval++ = c;
9063 while (*s < end
9064 && (c = *(*s)++, (isalnum (c) || c == '_')))
9065 *sval++ = c;
9066 *sval = 0;
9067 if (*s < end)
9068 *s = *s - 1;
9069 c = XBM_TK_IDENT;
9070 }
9071 else if (c == '/' && **s == '*')
9072 {
9073 /* C-style comment. */
9074 ++*s;
9075 while (**s && (**s != '*' || *(*s + 1) != '/'))
9076 ++*s;
9077 if (**s)
9078 {
9079 *s += 2;
9080 goto loop;
9081 }
9082 }
9083
9084 return c;
9085 }
9086
9087
9088 /* Replacement for XReadBitmapFileData which isn't available under old
9089 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9090 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9091 the image. Return in *DATA the bitmap data allocated with xmalloc.
9092 Value is non-zero if successful. DATA null means just test if
9093 CONTENTS looks like an in-memory XBM file. */
9094
9095 static int
9096 xbm_read_bitmap_data (contents, end, width, height, data)
9097 char *contents, *end;
9098 int *width, *height;
9099 unsigned char **data;
9100 {
9101 char *s = contents;
9102 char buffer[BUFSIZ];
9103 int padding_p = 0;
9104 int v10 = 0;
9105 int bytes_per_line, i, nbytes;
9106 unsigned char *p;
9107 int value;
9108 int LA1;
9109
9110 #define match() \
9111 LA1 = xbm_scan (contents, end, buffer, &value)
9112
9113 #define expect(TOKEN) \
9114 if (LA1 != (TOKEN)) \
9115 goto failure; \
9116 else \
9117 match ()
9118
9119 #define expect_ident(IDENT) \
9120 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9121 match (); \
9122 else \
9123 goto failure
9124
9125 *width = *height = -1;
9126 if (data)
9127 *data = NULL;
9128 LA1 = xbm_scan (&s, end, buffer, &value);
9129
9130 /* Parse defines for width, height and hot-spots. */
9131 while (LA1 == '#')
9132 {
9133 match ();
9134 expect_ident ("define");
9135 expect (XBM_TK_IDENT);
9136
9137 if (LA1 == XBM_TK_NUMBER);
9138 {
9139 char *p = strrchr (buffer, '_');
9140 p = p ? p + 1 : buffer;
9141 if (strcmp (p, "width") == 0)
9142 *width = value;
9143 else if (strcmp (p, "height") == 0)
9144 *height = value;
9145 }
9146 expect (XBM_TK_NUMBER);
9147 }
9148
9149 if (*width < 0 || *height < 0)
9150 goto failure;
9151 else if (data == NULL)
9152 goto success;
9153
9154 /* Parse bits. Must start with `static'. */
9155 expect_ident ("static");
9156 if (LA1 == XBM_TK_IDENT)
9157 {
9158 if (strcmp (buffer, "unsigned") == 0)
9159 {
9160 match ();
9161 expect_ident ("char");
9162 }
9163 else if (strcmp (buffer, "short") == 0)
9164 {
9165 match ();
9166 v10 = 1;
9167 if (*width % 16 && *width % 16 < 9)
9168 padding_p = 1;
9169 }
9170 else if (strcmp (buffer, "char") == 0)
9171 match ();
9172 else
9173 goto failure;
9174 }
9175 else
9176 goto failure;
9177
9178 expect (XBM_TK_IDENT);
9179 expect ('[');
9180 expect (']');
9181 expect ('=');
9182 expect ('{');
9183
9184 bytes_per_line = (*width + 7) / 8 + padding_p;
9185 nbytes = bytes_per_line * *height;
9186 p = *data = (char *) xmalloc (nbytes);
9187
9188 if (v10)
9189 {
9190
9191 for (i = 0; i < nbytes; i += 2)
9192 {
9193 int val = value;
9194 expect (XBM_TK_NUMBER);
9195
9196 *p++ = val;
9197 if (!padding_p || ((i + 2) % bytes_per_line))
9198 *p++ = value >> 8;
9199
9200 if (LA1 == ',' || LA1 == '}')
9201 match ();
9202 else
9203 goto failure;
9204 }
9205 }
9206 else
9207 {
9208 for (i = 0; i < nbytes; ++i)
9209 {
9210 int val = value;
9211 expect (XBM_TK_NUMBER);
9212
9213 *p++ = val;
9214
9215 if (LA1 == ',' || LA1 == '}')
9216 match ();
9217 else
9218 goto failure;
9219 }
9220 }
9221
9222 success:
9223 return 1;
9224
9225 failure:
9226
9227 if (data && *data)
9228 {
9229 xfree (*data);
9230 *data = NULL;
9231 }
9232 return 0;
9233
9234 #undef match
9235 #undef expect
9236 #undef expect_ident
9237 }
9238
9239
9240 /* Load XBM image IMG which will be displayed on frame F from buffer
9241 CONTENTS. END is the end of the buffer. Value is non-zero if
9242 successful. */
9243
9244 static int
9245 xbm_load_image (f, img, contents, end)
9246 struct frame *f;
9247 struct image *img;
9248 char *contents, *end;
9249 {
9250 int rc;
9251 unsigned char *data;
9252 int success_p = 0;
9253
9254 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
9255 if (rc)
9256 {
9257 int depth = one_w32_display_info.n_cbits;
9258 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9259 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9260 Lisp_Object value;
9261
9262 xassert (img->width > 0 && img->height > 0);
9263
9264 /* Get foreground and background colors, maybe allocate colors. */
9265 value = image_spec_value (img->spec, QCforeground, NULL);
9266 if (!NILP (value))
9267 foreground = x_alloc_image_color (f, img, value, foreground);
9268
9269 value = image_spec_value (img->spec, QCbackground, NULL);
9270 if (!NILP (value))
9271 background = x_alloc_image_color (f, img, value, background);
9272
9273 #if 0 /* TODO : Port image display to W32 */
9274 img->pixmap
9275 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9276 FRAME_W32_WINDOW (f),
9277 data,
9278 img->width, img->height,
9279 foreground, background,
9280 depth);
9281 xfree (data);
9282
9283 if (img->pixmap == 0)
9284 {
9285 x_clear_image (f, img);
9286 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
9287 }
9288 else
9289 success_p = 1;
9290 #endif
9291 }
9292 else
9293 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9294
9295 return success_p;
9296 }
9297
9298
9299 /* Value is non-zero if DATA looks like an in-memory XBM file. */
9300
9301 static int
9302 xbm_file_p (data)
9303 Lisp_Object data;
9304 {
9305 int w, h;
9306 return (STRINGP (data)
9307 && xbm_read_bitmap_data (XSTRING (data)->data,
9308 (XSTRING (data)->data
9309 + STRING_BYTES (XSTRING (data))),
9310 &w, &h, NULL));
9311 }
9312
9313
9314 /* Fill image IMG which is used on frame F with pixmap data. Value is
9315 non-zero if successful. */
9316
9317 static int
9318 xbm_load (f, img)
9319 struct frame *f;
9320 struct image *img;
9321 {
9322 int success_p = 0;
9323 Lisp_Object file_name;
9324
9325 xassert (xbm_image_p (img->spec));
9326
9327 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9328 file_name = image_spec_value (img->spec, QCfile, NULL);
9329 if (STRINGP (file_name))
9330 {
9331 Lisp_Object file;
9332 char *contents;
9333 int size;
9334 struct gcpro gcpro1;
9335
9336 file = x_find_image_file (file_name);
9337 GCPRO1 (file);
9338 if (!STRINGP (file))
9339 {
9340 image_error ("Cannot find image file `%s'", file_name, Qnil);
9341 UNGCPRO;
9342 return 0;
9343 }
9344
9345 contents = slurp_file (XSTRING (file)->data, &size);
9346 if (contents == NULL)
9347 {
9348 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9349 UNGCPRO;
9350 return 0;
9351 }
9352
9353 success_p = xbm_load_image (f, img, contents, contents + size);
9354 UNGCPRO;
9355 }
9356 else
9357 {
9358 struct image_keyword fmt[XBM_LAST];
9359 Lisp_Object data;
9360 int depth;
9361 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9362 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9363 char *bits;
9364 int parsed_p;
9365 int in_memory_file_p = 0;
9366
9367 /* See if data looks like an in-memory XBM file. */
9368 data = image_spec_value (img->spec, QCdata, NULL);
9369 in_memory_file_p = xbm_file_p (data);
9370
9371 /* Parse the list specification. */
9372 bcopy (xbm_format, fmt, sizeof fmt);
9373 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9374 xassert (parsed_p);
9375
9376 /* Get specified width, and height. */
9377 if (!in_memory_file_p)
9378 {
9379 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9380 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9381 xassert (img->width > 0 && img->height > 0);
9382 }
9383 /* Get foreground and background colors, maybe allocate colors. */
9384 if (fmt[XBM_FOREGROUND].count
9385 && STRINGP (fmt[XBM_FOREGROUND].value))
9386 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9387 foreground);
9388 if (fmt[XBM_BACKGROUND].count
9389 && STRINGP (fmt[XBM_BACKGROUND].value))
9390 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9391 background);
9392
9393 if (in_memory_file_p)
9394 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9395 (XSTRING (data)->data
9396 + STRING_BYTES (XSTRING (data))));
9397 else
9398 {
9399 if (VECTORP (data))
9400 {
9401 int i;
9402 char *p;
9403 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9404
9405 p = bits = (char *) alloca (nbytes * img->height);
9406 for (i = 0; i < img->height; ++i, p += nbytes)
9407 {
9408 Lisp_Object line = XVECTOR (data)->contents[i];
9409 if (STRINGP (line))
9410 bcopy (XSTRING (line)->data, p, nbytes);
9411 else
9412 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
9413 }
9414 }
9415 else if (STRINGP (data))
9416 bits = XSTRING (data)->data;
9417 else
9418 bits = XBOOL_VECTOR (data)->data;
9419 #ifdef TODO /* image support. */
9420 /* Create the pixmap. */
9421 depth = DefaultDepthOfScreen (FRAME_X_SCREEN (f));
9422 img->pixmap
9423 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
9424 FRAME_X_WINDOW (f),
9425 bits,
9426 img->width, img->height,
9427 foreground, background,
9428 depth);
9429 #endif
9430 if (img->pixmap)
9431 success_p = 1;
9432 else
9433 {
9434 image_error ("Unable to create pixmap for XBM image `%s'",
9435 img->spec, Qnil);
9436 x_clear_image (f, img);
9437 }
9438 }
9439 }
9440
9441 return success_p;
9442 }
9443
9444
9445 \f
9446 /***********************************************************************
9447 XPM images
9448 ***********************************************************************/
9449
9450 #if HAVE_XPM
9451
9452 static int xpm_image_p P_ ((Lisp_Object object));
9453 static int xpm_load P_ ((struct frame *f, struct image *img));
9454 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
9455
9456 #include "X11/xpm.h"
9457
9458 /* The symbol `xpm' identifying XPM-format images. */
9459
9460 Lisp_Object Qxpm;
9461
9462 /* Indices of image specification fields in xpm_format, below. */
9463
9464 enum xpm_keyword_index
9465 {
9466 XPM_TYPE,
9467 XPM_FILE,
9468 XPM_DATA,
9469 XPM_ASCENT,
9470 XPM_MARGIN,
9471 XPM_RELIEF,
9472 XPM_ALGORITHM,
9473 XPM_HEURISTIC_MASK,
9474 XPM_COLOR_SYMBOLS,
9475 XPM_LAST
9476 };
9477
9478 /* Vector of image_keyword structures describing the format
9479 of valid XPM image specifications. */
9480
9481 static struct image_keyword xpm_format[XPM_LAST] =
9482 {
9483 {":type", IMAGE_SYMBOL_VALUE, 1},
9484 {":file", IMAGE_STRING_VALUE, 0},
9485 {":data", IMAGE_STRING_VALUE, 0},
9486 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9487 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9488 {":relief", IMAGE_INTEGER_VALUE, 0},
9489 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9490 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9491 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9492 };
9493
9494 /* Structure describing the image type XBM. */
9495
9496 static struct image_type xpm_type =
9497 {
9498 &Qxpm,
9499 xpm_image_p,
9500 xpm_load,
9501 x_clear_image,
9502 NULL
9503 };
9504
9505
9506 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
9507 for XPM images. Such a list must consist of conses whose car and
9508 cdr are strings. */
9509
9510 static int
9511 xpm_valid_color_symbols_p (color_symbols)
9512 Lisp_Object color_symbols;
9513 {
9514 while (CONSP (color_symbols))
9515 {
9516 Lisp_Object sym = XCAR (color_symbols);
9517 if (!CONSP (sym)
9518 || !STRINGP (XCAR (sym))
9519 || !STRINGP (XCDR (sym)))
9520 break;
9521 color_symbols = XCDR (color_symbols);
9522 }
9523
9524 return NILP (color_symbols);
9525 }
9526
9527
9528 /* Value is non-zero if OBJECT is a valid XPM image specification. */
9529
9530 static int
9531 xpm_image_p (object)
9532 Lisp_Object object;
9533 {
9534 struct image_keyword fmt[XPM_LAST];
9535 bcopy (xpm_format, fmt, sizeof fmt);
9536 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
9537 /* Either `:file' or `:data' must be present. */
9538 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
9539 /* Either no `:color-symbols' or it's a list of conses
9540 whose car and cdr are strings. */
9541 && (fmt[XPM_COLOR_SYMBOLS].count == 0
9542 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
9543 && (fmt[XPM_ASCENT].count == 0
9544 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
9545 }
9546
9547
9548 /* Load image IMG which will be displayed on frame F. Value is
9549 non-zero if successful. */
9550
9551 static int
9552 xpm_load (f, img)
9553 struct frame *f;
9554 struct image *img;
9555 {
9556 int rc, i;
9557 XpmAttributes attrs;
9558 Lisp_Object specified_file, color_symbols;
9559
9560 /* Configure the XPM lib. Use the visual of frame F. Allocate
9561 close colors. Return colors allocated. */
9562 bzero (&attrs, sizeof attrs);
9563 attrs.visual = FRAME_X_VISUAL (f);
9564 attrs.colormap = FRAME_X_COLORMAP (f);
9565 attrs.valuemask |= XpmVisual;
9566 attrs.valuemask |= XpmColormap;
9567 attrs.valuemask |= XpmReturnAllocPixels;
9568 #ifdef XpmAllocCloseColors
9569 attrs.alloc_close_colors = 1;
9570 attrs.valuemask |= XpmAllocCloseColors;
9571 #else
9572 attrs.closeness = 600;
9573 attrs.valuemask |= XpmCloseness;
9574 #endif
9575
9576 /* If image specification contains symbolic color definitions, add
9577 these to `attrs'. */
9578 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
9579 if (CONSP (color_symbols))
9580 {
9581 Lisp_Object tail;
9582 XpmColorSymbol *xpm_syms;
9583 int i, size;
9584
9585 attrs.valuemask |= XpmColorSymbols;
9586
9587 /* Count number of symbols. */
9588 attrs.numsymbols = 0;
9589 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
9590 ++attrs.numsymbols;
9591
9592 /* Allocate an XpmColorSymbol array. */
9593 size = attrs.numsymbols * sizeof *xpm_syms;
9594 xpm_syms = (XpmColorSymbol *) alloca (size);
9595 bzero (xpm_syms, size);
9596 attrs.colorsymbols = xpm_syms;
9597
9598 /* Fill the color symbol array. */
9599 for (tail = color_symbols, i = 0;
9600 CONSP (tail);
9601 ++i, tail = XCDR (tail))
9602 {
9603 Lisp_Object name = XCAR (XCAR (tail));
9604 Lisp_Object color = XCDR (XCAR (tail));
9605 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
9606 strcpy (xpm_syms[i].name, XSTRING (name)->data);
9607 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
9608 strcpy (xpm_syms[i].value, XSTRING (color)->data);
9609 }
9610 }
9611
9612 /* Create a pixmap for the image, either from a file, or from a
9613 string buffer containing data in the same format as an XPM file. */
9614 BLOCK_INPUT;
9615 specified_file = image_spec_value (img->spec, QCfile, NULL);
9616 if (STRINGP (specified_file))
9617 {
9618 Lisp_Object file = x_find_image_file (specified_file);
9619 if (!STRINGP (file))
9620 {
9621 image_error ("Cannot find image file `%s'", specified_file, Qnil);
9622 UNBLOCK_INPUT;
9623 return 0;
9624 }
9625
9626 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
9627 XSTRING (file)->data, &img->pixmap, &img->mask,
9628 &attrs);
9629 }
9630 else
9631 {
9632 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
9633 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
9634 XSTRING (buffer)->data,
9635 &img->pixmap, &img->mask,
9636 &attrs);
9637 }
9638 UNBLOCK_INPUT;
9639
9640 if (rc == XpmSuccess)
9641 {
9642 /* Remember allocated colors. */
9643 img->ncolors = attrs.nalloc_pixels;
9644 img->colors = (unsigned long *) xmalloc (img->ncolors
9645 * sizeof *img->colors);
9646 for (i = 0; i < attrs.nalloc_pixels; ++i)
9647 img->colors[i] = attrs.alloc_pixels[i];
9648
9649 img->width = attrs.width;
9650 img->height = attrs.height;
9651 xassert (img->width > 0 && img->height > 0);
9652
9653 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
9654 BLOCK_INPUT;
9655 XpmFreeAttributes (&attrs);
9656 UNBLOCK_INPUT;
9657 }
9658 else
9659 {
9660 switch (rc)
9661 {
9662 case XpmOpenFailed:
9663 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
9664 break;
9665
9666 case XpmFileInvalid:
9667 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
9668 break;
9669
9670 case XpmNoMemory:
9671 image_error ("Out of memory (%s)", img->spec, Qnil);
9672 break;
9673
9674 case XpmColorFailed:
9675 image_error ("Color allocation error (%s)", img->spec, Qnil);
9676 break;
9677
9678 default:
9679 image_error ("Unknown error (%s)", img->spec, Qnil);
9680 break;
9681 }
9682 }
9683
9684 return rc == XpmSuccess;
9685 }
9686
9687 #endif /* HAVE_XPM != 0 */
9688
9689 \f
9690 #if 0 /* TODO : Color tables on W32. */
9691 /***********************************************************************
9692 Color table
9693 ***********************************************************************/
9694
9695 /* An entry in the color table mapping an RGB color to a pixel color. */
9696
9697 struct ct_color
9698 {
9699 int r, g, b;
9700 unsigned long pixel;
9701
9702 /* Next in color table collision list. */
9703 struct ct_color *next;
9704 };
9705
9706 /* The bucket vector size to use. Must be prime. */
9707
9708 #define CT_SIZE 101
9709
9710 /* Value is a hash of the RGB color given by R, G, and B. */
9711
9712 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
9713
9714 /* The color hash table. */
9715
9716 struct ct_color **ct_table;
9717
9718 /* Number of entries in the color table. */
9719
9720 int ct_colors_allocated;
9721
9722 /* Function prototypes. */
9723
9724 static void init_color_table P_ ((void));
9725 static void free_color_table P_ ((void));
9726 static unsigned long *colors_in_color_table P_ ((int *n));
9727 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
9728 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
9729
9730
9731 /* Initialize the color table. */
9732
9733 static void
9734 init_color_table ()
9735 {
9736 int size = CT_SIZE * sizeof (*ct_table);
9737 ct_table = (struct ct_color **) xmalloc (size);
9738 bzero (ct_table, size);
9739 ct_colors_allocated = 0;
9740 }
9741
9742
9743 /* Free memory associated with the color table. */
9744
9745 static void
9746 free_color_table ()
9747 {
9748 int i;
9749 struct ct_color *p, *next;
9750
9751 for (i = 0; i < CT_SIZE; ++i)
9752 for (p = ct_table[i]; p; p = next)
9753 {
9754 next = p->next;
9755 xfree (p);
9756 }
9757
9758 xfree (ct_table);
9759 ct_table = NULL;
9760 }
9761
9762
9763 /* Value is a pixel color for RGB color R, G, B on frame F. If an
9764 entry for that color already is in the color table, return the
9765 pixel color of that entry. Otherwise, allocate a new color for R,
9766 G, B, and make an entry in the color table. */
9767
9768 static unsigned long
9769 lookup_rgb_color (f, r, g, b)
9770 struct frame *f;
9771 int r, g, b;
9772 {
9773 unsigned hash = CT_HASH_RGB (r, g, b);
9774 int i = hash % CT_SIZE;
9775 struct ct_color *p;
9776
9777 for (p = ct_table[i]; p; p = p->next)
9778 if (p->r == r && p->g == g && p->b == b)
9779 break;
9780
9781 if (p == NULL)
9782 {
9783 COLORREF color;
9784 Colormap cmap;
9785 int rc;
9786
9787 color = PALETTERGB (r, g, b);
9788
9789 ++ct_colors_allocated;
9790
9791 p = (struct ct_color *) xmalloc (sizeof *p);
9792 p->r = r;
9793 p->g = g;
9794 p->b = b;
9795 p->pixel = color;
9796 p->next = ct_table[i];
9797 ct_table[i] = p;
9798 }
9799
9800 return p->pixel;
9801 }
9802
9803
9804 /* Look up pixel color PIXEL which is used on frame F in the color
9805 table. If not already present, allocate it. Value is PIXEL. */
9806
9807 static unsigned long
9808 lookup_pixel_color (f, pixel)
9809 struct frame *f;
9810 unsigned long pixel;
9811 {
9812 int i = pixel % CT_SIZE;
9813 struct ct_color *p;
9814
9815 for (p = ct_table[i]; p; p = p->next)
9816 if (p->pixel == pixel)
9817 break;
9818
9819 if (p == NULL)
9820 {
9821 XColor color;
9822 Colormap cmap;
9823 int rc;
9824
9825 BLOCK_INPUT;
9826
9827 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
9828 color.pixel = pixel;
9829 XQueryColor (NULL, cmap, &color);
9830 rc = x_alloc_nearest_color (f, cmap, &color);
9831 UNBLOCK_INPUT;
9832
9833 if (rc)
9834 {
9835 ++ct_colors_allocated;
9836
9837 p = (struct ct_color *) xmalloc (sizeof *p);
9838 p->r = color.red;
9839 p->g = color.green;
9840 p->b = color.blue;
9841 p->pixel = pixel;
9842 p->next = ct_table[i];
9843 ct_table[i] = p;
9844 }
9845 else
9846 return FRAME_FOREGROUND_PIXEL (f);
9847 }
9848 return p->pixel;
9849 }
9850
9851
9852 /* Value is a vector of all pixel colors contained in the color table,
9853 allocated via xmalloc. Set *N to the number of colors. */
9854
9855 static unsigned long *
9856 colors_in_color_table (n)
9857 int *n;
9858 {
9859 int i, j;
9860 struct ct_color *p;
9861 unsigned long *colors;
9862
9863 if (ct_colors_allocated == 0)
9864 {
9865 *n = 0;
9866 colors = NULL;
9867 }
9868 else
9869 {
9870 colors = (unsigned long *) xmalloc (ct_colors_allocated
9871 * sizeof *colors);
9872 *n = ct_colors_allocated;
9873
9874 for (i = j = 0; i < CT_SIZE; ++i)
9875 for (p = ct_table[i]; p; p = p->next)
9876 colors[j++] = p->pixel;
9877 }
9878
9879 return colors;
9880 }
9881
9882 #endif /* TODO */
9883
9884 \f
9885 /***********************************************************************
9886 Algorithms
9887 ***********************************************************************/
9888 #if 0 /* TODO: image support. */
9889 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
9890 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
9891 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
9892
9893 /* Non-zero means draw a cross on images having `:conversion
9894 disabled'. */
9895
9896 int cross_disabled_images;
9897
9898 /* Edge detection matrices for different edge-detection
9899 strategies. */
9900
9901 static int emboss_matrix[9] = {
9902 /* x - 1 x x + 1 */
9903 2, -1, 0, /* y - 1 */
9904 -1, 0, 1, /* y */
9905 0, 1, -2 /* y + 1 */
9906 };
9907
9908 static int laplace_matrix[9] = {
9909 /* x - 1 x x + 1 */
9910 1, 0, 0, /* y - 1 */
9911 0, 0, 0, /* y */
9912 0, 0, -1 /* y + 1 */
9913 };
9914
9915 /* Value is the intensity of the color whose red/green/blue values
9916 are R, G, and B. */
9917
9918 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
9919
9920
9921 /* On frame F, return an array of XColor structures describing image
9922 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
9923 non-zero means also fill the red/green/blue members of the XColor
9924 structures. Value is a pointer to the array of XColors structures,
9925 allocated with xmalloc; it must be freed by the caller. */
9926
9927 static XColor *
9928 x_to_xcolors (f, img, rgb_p)
9929 struct frame *f;
9930 struct image *img;
9931 int rgb_p;
9932 {
9933 int x, y;
9934 XColor *colors, *p;
9935 XImage *ximg;
9936
9937 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
9938
9939 /* Get the X image IMG->pixmap. */
9940 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
9941 0, 0, img->width, img->height, ~0, ZPixmap);
9942
9943 /* Fill the `pixel' members of the XColor array. I wished there
9944 were an easy and portable way to circumvent XGetPixel. */
9945 p = colors;
9946 for (y = 0; y < img->height; ++y)
9947 {
9948 XColor *row = p;
9949
9950 for (x = 0; x < img->width; ++x, ++p)
9951 p->pixel = XGetPixel (ximg, x, y);
9952
9953 if (rgb_p)
9954 x_query_colors (f, row, img->width);
9955 }
9956
9957 XDestroyImage (ximg);
9958 return colors;
9959 }
9960
9961
9962 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
9963 RGB members are set. F is the frame on which this all happens.
9964 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
9965
9966 static void
9967 x_from_xcolors (f, img, colors)
9968 struct frame *f;
9969 struct image *img;
9970 XColor *colors;
9971 {
9972 int x, y;
9973 XImage *oimg;
9974 Pixmap pixmap;
9975 XColor *p;
9976
9977 init_color_table ();
9978
9979 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
9980 &oimg, &pixmap);
9981 p = colors;
9982 for (y = 0; y < img->height; ++y)
9983 for (x = 0; x < img->width; ++x, ++p)
9984 {
9985 unsigned long pixel;
9986 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
9987 XPutPixel (oimg, x, y, pixel);
9988 }
9989
9990 xfree (colors);
9991 x_clear_image_1 (f, img, 1, 0, 1);
9992
9993 x_put_x_image (f, oimg, pixmap, img->width, img->height);
9994 x_destroy_x_image (oimg);
9995 img->pixmap = pixmap;
9996 img->colors = colors_in_color_table (&img->ncolors);
9997 free_color_table ();
9998 }
9999
10000
10001 /* On frame F, perform edge-detection on image IMG.
10002
10003 MATRIX is a nine-element array specifying the transformation
10004 matrix. See emboss_matrix for an example.
10005
10006 COLOR_ADJUST is a color adjustment added to each pixel of the
10007 outgoing image. */
10008
10009 static void
10010 x_detect_edges (f, img, matrix, color_adjust)
10011 struct frame *f;
10012 struct image *img;
10013 int matrix[9], color_adjust;
10014 {
10015 XColor *colors = x_to_xcolors (f, img, 1);
10016 XColor *new, *p;
10017 int x, y, i, sum;
10018
10019 for (i = sum = 0; i < 9; ++i)
10020 sum += abs (matrix[i]);
10021
10022 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10023
10024 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10025
10026 for (y = 0; y < img->height; ++y)
10027 {
10028 p = COLOR (new, 0, y);
10029 p->red = p->green = p->blue = 0xffff/2;
10030 p = COLOR (new, img->width - 1, y);
10031 p->red = p->green = p->blue = 0xffff/2;
10032 }
10033
10034 for (x = 1; x < img->width - 1; ++x)
10035 {
10036 p = COLOR (new, x, 0);
10037 p->red = p->green = p->blue = 0xffff/2;
10038 p = COLOR (new, x, img->height - 1);
10039 p->red = p->green = p->blue = 0xffff/2;
10040 }
10041
10042 for (y = 1; y < img->height - 1; ++y)
10043 {
10044 p = COLOR (new, 1, y);
10045
10046 for (x = 1; x < img->width - 1; ++x, ++p)
10047 {
10048 int r, g, b, y1, x1;
10049
10050 r = g = b = i = 0;
10051 for (y1 = y - 1; y1 < y + 2; ++y1)
10052 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10053 if (matrix[i])
10054 {
10055 XColor *t = COLOR (colors, x1, y1);
10056 r += matrix[i] * t->red;
10057 g += matrix[i] * t->green;
10058 b += matrix[i] * t->blue;
10059 }
10060
10061 r = (r / sum + color_adjust) & 0xffff;
10062 g = (g / sum + color_adjust) & 0xffff;
10063 b = (b / sum + color_adjust) & 0xffff;
10064 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10065 }
10066 }
10067
10068 xfree (colors);
10069 x_from_xcolors (f, img, new);
10070
10071 #undef COLOR
10072 }
10073
10074
10075 /* Perform the pre-defined `emboss' edge-detection on image IMG
10076 on frame F. */
10077
10078 static void
10079 x_emboss (f, img)
10080 struct frame *f;
10081 struct image *img;
10082 {
10083 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10084 }
10085
10086
10087 /* Transform image IMG which is used on frame F with a Laplace
10088 edge-detection algorithm. The result is an image that can be used
10089 to draw disabled buttons, for example. */
10090
10091 static void
10092 x_laplace (f, img)
10093 struct frame *f;
10094 struct image *img;
10095 {
10096 x_detect_edges (f, img, laplace_matrix, 45000);
10097 }
10098
10099
10100 /* Perform edge-detection on image IMG on frame F, with specified
10101 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10102
10103 MATRIX must be either
10104
10105 - a list of at least 9 numbers in row-major form
10106 - a vector of at least 9 numbers
10107
10108 COLOR_ADJUST nil means use a default; otherwise it must be a
10109 number. */
10110
10111 static void
10112 x_edge_detection (f, img, matrix, color_adjust)
10113 struct frame *f;
10114 struct image *img;
10115 Lisp_Object matrix, color_adjust;
10116 {
10117 int i = 0;
10118 int trans[9];
10119
10120 if (CONSP (matrix))
10121 {
10122 for (i = 0;
10123 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10124 ++i, matrix = XCDR (matrix))
10125 trans[i] = XFLOATINT (XCAR (matrix));
10126 }
10127 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10128 {
10129 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10130 trans[i] = XFLOATINT (AREF (matrix, i));
10131 }
10132
10133 if (NILP (color_adjust))
10134 color_adjust = make_number (0xffff / 2);
10135
10136 if (i == 9 && NUMBERP (color_adjust))
10137 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10138 }
10139
10140
10141 /* Transform image IMG on frame F so that it looks disabled. */
10142
10143 static void
10144 x_disable_image (f, img)
10145 struct frame *f;
10146 struct image *img;
10147 {
10148 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10149
10150 if (dpyinfo->n_planes >= 2)
10151 {
10152 /* Color (or grayscale). Convert to gray, and equalize. Just
10153 drawing such images with a stipple can look very odd, so
10154 we're using this method instead. */
10155 XColor *colors = x_to_xcolors (f, img, 1);
10156 XColor *p, *end;
10157 const int h = 15000;
10158 const int l = 30000;
10159
10160 for (p = colors, end = colors + img->width * img->height;
10161 p < end;
10162 ++p)
10163 {
10164 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10165 int i2 = (0xffff - h - l) * i / 0xffff + l;
10166 p->red = p->green = p->blue = i2;
10167 }
10168
10169 x_from_xcolors (f, img, colors);
10170 }
10171
10172 /* Draw a cross over the disabled image, if we must or if we
10173 should. */
10174 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10175 {
10176 Display *dpy = FRAME_X_DISPLAY (f);
10177 GC gc;
10178
10179 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10180 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10181 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10182 img->width - 1, img->height - 1);
10183 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10184 img->width - 1, 0);
10185 XFreeGC (dpy, gc);
10186
10187 if (img->mask)
10188 {
10189 gc = XCreateGC (dpy, img->mask, 0, NULL);
10190 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10191 XDrawLine (dpy, img->mask, gc, 0, 0,
10192 img->width - 1, img->height - 1);
10193 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10194 img->width - 1, 0);
10195 XFreeGC (dpy, gc);
10196 }
10197 }
10198 }
10199
10200
10201 /* Build a mask for image IMG which is used on frame F. FILE is the
10202 name of an image file, for error messages. HOW determines how to
10203 determine the background color of IMG. If it is a list '(R G B)',
10204 with R, G, and B being integers >= 0, take that as the color of the
10205 background. Otherwise, determine the background color of IMG
10206 heuristically. Value is non-zero if successful. */
10207
10208 static int
10209 x_build_heuristic_mask (f, img, how)
10210 struct frame *f;
10211 struct image *img;
10212 Lisp_Object how;
10213 {
10214 Display *dpy = FRAME_W32_DISPLAY (f);
10215 XImage *ximg, *mask_img;
10216 int x, y, rc, look_at_corners_p;
10217 unsigned long bg;
10218
10219 BLOCK_INPUT;
10220
10221 /* Create an image and pixmap serving as mask. */
10222 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10223 &mask_img, &img->mask);
10224 if (!rc)
10225 {
10226 UNBLOCK_INPUT;
10227 return 0;
10228 }
10229
10230 /* Get the X image of IMG->pixmap. */
10231 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10232 ~0, ZPixmap);
10233
10234 /* Determine the background color of ximg. If HOW is `(R G B)'
10235 take that as color. Otherwise, try to determine the color
10236 heuristically. */
10237 look_at_corners_p = 1;
10238
10239 if (CONSP (how))
10240 {
10241 int rgb[3], i = 0;
10242
10243 while (i < 3
10244 && CONSP (how)
10245 && NATNUMP (XCAR (how)))
10246 {
10247 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10248 how = XCDR (how);
10249 }
10250
10251 if (i == 3 && NILP (how))
10252 {
10253 char color_name[30];
10254 XColor exact, color;
10255 Colormap cmap;
10256
10257 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
10258
10259 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10260 if (XLookupColor (dpy, cmap, color_name, &exact, &color))
10261 {
10262 bg = color.pixel;
10263 look_at_corners_p = 0;
10264 }
10265 }
10266 }
10267
10268 if (look_at_corners_p)
10269 {
10270 unsigned long corners[4];
10271 int i, best_count;
10272
10273 /* Get the colors at the corners of ximg. */
10274 corners[0] = XGetPixel (ximg, 0, 0);
10275 corners[1] = XGetPixel (ximg, img->width - 1, 0);
10276 corners[2] = XGetPixel (ximg, img->width - 1, img->height - 1);
10277 corners[3] = XGetPixel (ximg, 0, img->height - 1);
10278
10279 /* Choose the most frequently found color as background. */
10280 for (i = best_count = 0; i < 4; ++i)
10281 {
10282 int j, n;
10283
10284 for (j = n = 0; j < 4; ++j)
10285 if (corners[i] == corners[j])
10286 ++n;
10287
10288 if (n > best_count)
10289 bg = corners[i], best_count = n;
10290 }
10291 }
10292
10293 /* Set all bits in mask_img to 1 whose color in ximg is different
10294 from the background color bg. */
10295 for (y = 0; y < img->height; ++y)
10296 for (x = 0; x < img->width; ++x)
10297 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10298
10299 /* Put mask_img into img->mask. */
10300 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10301 x_destroy_x_image (mask_img);
10302 XDestroyImage (ximg);
10303
10304 UNBLOCK_INPUT;
10305
10306 return 1;
10307 }
10308 #endif /* TODO */
10309
10310 \f
10311 /***********************************************************************
10312 PBM (mono, gray, color)
10313 ***********************************************************************/
10314 #ifdef HAVE_PBM
10315
10316 static int pbm_image_p P_ ((Lisp_Object object));
10317 static int pbm_load P_ ((struct frame *f, struct image *img));
10318 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10319
10320 /* The symbol `pbm' identifying images of this type. */
10321
10322 Lisp_Object Qpbm;
10323
10324 /* Indices of image specification fields in gs_format, below. */
10325
10326 enum pbm_keyword_index
10327 {
10328 PBM_TYPE,
10329 PBM_FILE,
10330 PBM_DATA,
10331 PBM_ASCENT,
10332 PBM_MARGIN,
10333 PBM_RELIEF,
10334 PBM_ALGORITHM,
10335 PBM_HEURISTIC_MASK,
10336 PBM_LAST
10337 };
10338
10339 /* Vector of image_keyword structures describing the format
10340 of valid user-defined image specifications. */
10341
10342 static struct image_keyword pbm_format[PBM_LAST] =
10343 {
10344 {":type", IMAGE_SYMBOL_VALUE, 1},
10345 {":file", IMAGE_STRING_VALUE, 0},
10346 {":data", IMAGE_STRING_VALUE, 0},
10347 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10348 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10349 {":relief", IMAGE_INTEGER_VALUE, 0},
10350 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10351 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10352 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10353 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10354 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10355 };
10356
10357 /* Structure describing the image type `pbm'. */
10358
10359 static struct image_type pbm_type =
10360 {
10361 &Qpbm,
10362 pbm_image_p,
10363 pbm_load,
10364 x_clear_image,
10365 NULL
10366 };
10367
10368
10369 /* Return non-zero if OBJECT is a valid PBM image specification. */
10370
10371 static int
10372 pbm_image_p (object)
10373 Lisp_Object object;
10374 {
10375 struct image_keyword fmt[PBM_LAST];
10376
10377 bcopy (pbm_format, fmt, sizeof fmt);
10378
10379 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10380 || (fmt[PBM_ASCENT].count
10381 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10382 return 0;
10383
10384 /* Must specify either :data or :file. */
10385 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10386 }
10387
10388
10389 /* Scan a decimal number from *S and return it. Advance *S while
10390 reading the number. END is the end of the string. Value is -1 at
10391 end of input. */
10392
10393 static int
10394 pbm_scan_number (s, end)
10395 unsigned char **s, *end;
10396 {
10397 int c, val = -1;
10398
10399 while (*s < end)
10400 {
10401 /* Skip white-space. */
10402 while (*s < end && (c = *(*s)++, isspace (c)))
10403 ;
10404
10405 if (c == '#')
10406 {
10407 /* Skip comment to end of line. */
10408 while (*s < end && (c = *(*s)++, c != '\n'))
10409 ;
10410 }
10411 else if (isdigit (c))
10412 {
10413 /* Read decimal number. */
10414 val = c - '0';
10415 while (*s < end && (c = *(*s)++, isdigit (c)))
10416 val = 10 * val + c - '0';
10417 break;
10418 }
10419 else
10420 break;
10421 }
10422
10423 return val;
10424 }
10425
10426
10427 /* Read FILE into memory. Value is a pointer to a buffer allocated
10428 with xmalloc holding FILE's contents. Value is null if an error
10429 occured. *SIZE is set to the size of the file. */
10430
10431 static char *
10432 pbm_read_file (file, size)
10433 Lisp_Object file;
10434 int *size;
10435 {
10436 FILE *fp = NULL;
10437 char *buf = NULL;
10438 struct stat st;
10439
10440 if (stat (XSTRING (file)->data, &st) == 0
10441 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
10442 && (buf = (char *) xmalloc (st.st_size),
10443 fread (buf, 1, st.st_size, fp) == st.st_size))
10444 {
10445 *size = st.st_size;
10446 fclose (fp);
10447 }
10448 else
10449 {
10450 if (fp)
10451 fclose (fp);
10452 if (buf)
10453 {
10454 xfree (buf);
10455 buf = NULL;
10456 }
10457 }
10458
10459 return buf;
10460 }
10461
10462
10463 /* Load PBM image IMG for use on frame F. */
10464
10465 static int
10466 pbm_load (f, img)
10467 struct frame *f;
10468 struct image *img;
10469 {
10470 int raw_p, x, y;
10471 int width, height, max_color_idx = 0;
10472 XImage *ximg;
10473 Lisp_Object file, specified_file;
10474 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
10475 struct gcpro gcpro1;
10476 unsigned char *contents = NULL;
10477 unsigned char *end, *p;
10478 int size;
10479
10480 specified_file = image_spec_value (img->spec, QCfile, NULL);
10481 file = Qnil;
10482 GCPRO1 (file);
10483
10484 if (STRINGP (specified_file))
10485 {
10486 file = x_find_image_file (specified_file);
10487 if (!STRINGP (file))
10488 {
10489 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10490 UNGCPRO;
10491 return 0;
10492 }
10493
10494 contents = slurp_file (XSTRING (file)->data, &size);
10495 if (contents == NULL)
10496 {
10497 image_error ("Error reading `%s'", file, Qnil);
10498 UNGCPRO;
10499 return 0;
10500 }
10501
10502 p = contents;
10503 end = contents + size;
10504 }
10505 else
10506 {
10507 Lisp_Object data;
10508 data = image_spec_value (img->spec, QCdata, NULL);
10509 p = XSTRING (data)->data;
10510 end = p + STRING_BYTES (XSTRING (data));
10511 }
10512
10513 /* Check magic number. */
10514 if (end - p < 2 || *p++ != 'P')
10515 {
10516 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10517 error:
10518 xfree (contents);
10519 UNGCPRO;
10520 return 0;
10521 }
10522
10523 switch (*p++)
10524 {
10525 case '1':
10526 raw_p = 0, type = PBM_MONO;
10527 break;
10528
10529 case '2':
10530 raw_p = 0, type = PBM_GRAY;
10531 break;
10532
10533 case '3':
10534 raw_p = 0, type = PBM_COLOR;
10535 break;
10536
10537 case '4':
10538 raw_p = 1, type = PBM_MONO;
10539 break;
10540
10541 case '5':
10542 raw_p = 1, type = PBM_GRAY;
10543 break;
10544
10545 case '6':
10546 raw_p = 1, type = PBM_COLOR;
10547 break;
10548
10549 default:
10550 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
10551 goto error;
10552 }
10553
10554 /* Read width, height, maximum color-component. Characters
10555 starting with `#' up to the end of a line are ignored. */
10556 width = pbm_scan_number (&p, end);
10557 height = pbm_scan_number (&p, end);
10558
10559 if (type != PBM_MONO)
10560 {
10561 max_color_idx = pbm_scan_number (&p, end);
10562 if (raw_p && max_color_idx > 255)
10563 max_color_idx = 255;
10564 }
10565
10566 if (width < 0
10567 || height < 0
10568 || (type != PBM_MONO && max_color_idx < 0))
10569 goto error;
10570
10571 if (!x_create_x_image_and_pixmap (f, width, height, 0,
10572 &ximg, &img->pixmap))
10573 goto error;
10574
10575 /* Initialize the color hash table. */
10576 init_color_table ();
10577
10578 if (type == PBM_MONO)
10579 {
10580 int c = 0, g;
10581 struct image_keyword fmt[PBM_LAST];
10582 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
10583 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
10584
10585 /* Parse the image specification. */
10586 bcopy (pbm_format, fmt, sizeof fmt);
10587 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
10588
10589 /* Get foreground and background colors, maybe allocate colors. */
10590 if (fmt[PBM_FOREGROUND].count
10591 && STRINGP (fmt[PBM_FOREGROUND].value))
10592 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
10593 if (fmt[PBM_BACKGROUND].count
10594 && STRINGP (fmt[PBM_BACKGROUND].value))
10595 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
10596
10597 for (y = 0; y < height; ++y)
10598 for (x = 0; x < width; ++x)
10599 {
10600 if (raw_p)
10601 {
10602 if ((x & 7) == 0)
10603 c = *p++;
10604 g = c & 0x80;
10605 c <<= 1;
10606 }
10607 else
10608 g = pbm_scan_number (&p, end);
10609
10610 XPutPixel (ximg, x, y, g ? fg : bg);
10611 }
10612 }
10613 else
10614 {
10615 for (y = 0; y < height; ++y)
10616 for (x = 0; x < width; ++x)
10617 {
10618 int r, g, b;
10619
10620 if (type == PBM_GRAY)
10621 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
10622 else if (raw_p)
10623 {
10624 r = *p++;
10625 g = *p++;
10626 b = *p++;
10627 }
10628 else
10629 {
10630 r = pbm_scan_number (&p, end);
10631 g = pbm_scan_number (&p, end);
10632 b = pbm_scan_number (&p, end);
10633 }
10634
10635 if (r < 0 || g < 0 || b < 0)
10636 {
10637 xfree (ximg->data);
10638 ximg->data = NULL;
10639 XDestroyImage (ximg);
10640 image_error ("Invalid pixel value in image `%s'",
10641 img->spec, Qnil);
10642 goto error;
10643 }
10644
10645 /* RGB values are now in the range 0..max_color_idx.
10646 Scale this to the range 0..0xffff supported by X. */
10647 r = (double) r * 65535 / max_color_idx;
10648 g = (double) g * 65535 / max_color_idx;
10649 b = (double) b * 65535 / max_color_idx;
10650 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
10651 }
10652 }
10653
10654 /* Store in IMG->colors the colors allocated for the image, and
10655 free the color table. */
10656 img->colors = colors_in_color_table (&img->ncolors);
10657 free_color_table ();
10658
10659 /* Put the image into a pixmap. */
10660 x_put_x_image (f, ximg, img->pixmap, width, height);
10661 x_destroy_x_image (ximg);
10662
10663 img->width = width;
10664 img->height = height;
10665
10666 UNGCPRO;
10667 xfree (contents);
10668 return 1;
10669 }
10670 #endif /* HAVE_PBM */
10671
10672 \f
10673 /***********************************************************************
10674 PNG
10675 ***********************************************************************/
10676
10677 #if HAVE_PNG
10678
10679 #include <png.h>
10680
10681 /* Function prototypes. */
10682
10683 static int png_image_p P_ ((Lisp_Object object));
10684 static int png_load P_ ((struct frame *f, struct image *img));
10685
10686 /* The symbol `png' identifying images of this type. */
10687
10688 Lisp_Object Qpng;
10689
10690 /* Indices of image specification fields in png_format, below. */
10691
10692 enum png_keyword_index
10693 {
10694 PNG_TYPE,
10695 PNG_DATA,
10696 PNG_FILE,
10697 PNG_ASCENT,
10698 PNG_MARGIN,
10699 PNG_RELIEF,
10700 PNG_ALGORITHM,
10701 PNG_HEURISTIC_MASK,
10702 PNG_LAST
10703 };
10704
10705 /* Vector of image_keyword structures describing the format
10706 of valid user-defined image specifications. */
10707
10708 static struct image_keyword png_format[PNG_LAST] =
10709 {
10710 {":type", IMAGE_SYMBOL_VALUE, 1},
10711 {":data", IMAGE_STRING_VALUE, 0},
10712 {":file", IMAGE_STRING_VALUE, 0},
10713 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10714 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10715 {":relief", IMAGE_INTEGER_VALUE, 0},
10716 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10717 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
10718 };
10719
10720 /* Structure describing the image type `png'. */
10721
10722 static struct image_type png_type =
10723 {
10724 &Qpng,
10725 png_image_p,
10726 png_load,
10727 x_clear_image,
10728 NULL
10729 };
10730
10731
10732 /* Return non-zero if OBJECT is a valid PNG image specification. */
10733
10734 static int
10735 png_image_p (object)
10736 Lisp_Object object;
10737 {
10738 struct image_keyword fmt[PNG_LAST];
10739 bcopy (png_format, fmt, sizeof fmt);
10740
10741 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
10742 || (fmt[PNG_ASCENT].count
10743 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
10744 return 0;
10745
10746 /* Must specify either the :data or :file keyword. */
10747 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
10748 }
10749
10750
10751 /* Error and warning handlers installed when the PNG library
10752 is initialized. */
10753
10754 static void
10755 my_png_error (png_ptr, msg)
10756 png_struct *png_ptr;
10757 char *msg;
10758 {
10759 xassert (png_ptr != NULL);
10760 image_error ("PNG error: %s", build_string (msg), Qnil);
10761 longjmp (png_ptr->jmpbuf, 1);
10762 }
10763
10764
10765 static void
10766 my_png_warning (png_ptr, msg)
10767 png_struct *png_ptr;
10768 char *msg;
10769 {
10770 xassert (png_ptr != NULL);
10771 image_error ("PNG warning: %s", build_string (msg), Qnil);
10772 }
10773
10774 /* Memory source for PNG decoding. */
10775
10776 struct png_memory_storage
10777 {
10778 unsigned char *bytes; /* The data */
10779 size_t len; /* How big is it? */
10780 int index; /* Where are we? */
10781 };
10782
10783
10784 /* Function set as reader function when reading PNG image from memory.
10785 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
10786 bytes from the input to DATA. */
10787
10788 static void
10789 png_read_from_memory (png_ptr, data, length)
10790 png_structp png_ptr;
10791 png_bytep data;
10792 png_size_t length;
10793 {
10794 struct png_memory_storage *tbr
10795 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
10796
10797 if (length > tbr->len - tbr->index)
10798 png_error (png_ptr, "Read error");
10799
10800 bcopy (tbr->bytes + tbr->index, data, length);
10801 tbr->index = tbr->index + length;
10802 }
10803
10804 /* Load PNG image IMG for use on frame F. Value is non-zero if
10805 successful. */
10806
10807 static int
10808 png_load (f, img)
10809 struct frame *f;
10810 struct image *img;
10811 {
10812 Lisp_Object file, specified_file;
10813 Lisp_Object specified_data;
10814 int x, y, i;
10815 XImage *ximg, *mask_img = NULL;
10816 struct gcpro gcpro1;
10817 png_struct *png_ptr = NULL;
10818 png_info *info_ptr = NULL, *end_info = NULL;
10819 FILE *fp = NULL;
10820 png_byte sig[8];
10821 png_byte *pixels = NULL;
10822 png_byte **rows = NULL;
10823 png_uint_32 width, height;
10824 int bit_depth, color_type, interlace_type;
10825 png_byte channels;
10826 png_uint_32 row_bytes;
10827 int transparent_p;
10828 char *gamma_str;
10829 double screen_gamma, image_gamma;
10830 int intent;
10831 struct png_memory_storage tbr; /* Data to be read */
10832
10833 /* Find out what file to load. */
10834 specified_file = image_spec_value (img->spec, QCfile, NULL);
10835 specified_data = image_spec_value (img->spec, QCdata, NULL);
10836 file = Qnil;
10837 GCPRO1 (file);
10838
10839 if (NILP (specified_data))
10840 {
10841 file = x_find_image_file (specified_file);
10842 if (!STRINGP (file))
10843 {
10844 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10845 UNGCPRO;
10846 return 0;
10847 }
10848
10849 /* Open the image file. */
10850 fp = fopen (XSTRING (file)->data, "rb");
10851 if (!fp)
10852 {
10853 image_error ("Cannot open image file `%s'", file, Qnil);
10854 UNGCPRO;
10855 fclose (fp);
10856 return 0;
10857 }
10858
10859 /* Check PNG signature. */
10860 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
10861 || !png_check_sig (sig, sizeof sig))
10862 {
10863 image_error ("Not a PNG file:` %s'", file, Qnil);
10864 UNGCPRO;
10865 fclose (fp);
10866 return 0;
10867 }
10868 }
10869 else
10870 {
10871 /* Read from memory. */
10872 tbr.bytes = XSTRING (specified_data)->data;
10873 tbr.len = STRING_BYTES (XSTRING (specified_data));
10874 tbr.index = 0;
10875
10876 /* Check PNG signature. */
10877 if (tbr.len < sizeof sig
10878 || !png_check_sig (tbr.bytes, sizeof sig))
10879 {
10880 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
10881 UNGCPRO;
10882 return 0;
10883 }
10884
10885 /* Need to skip past the signature. */
10886 tbr.bytes += sizeof (sig);
10887 }
10888
10889 /* Initialize read and info structs for PNG lib. */
10890 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
10891 my_png_error, my_png_warning);
10892 if (!png_ptr)
10893 {
10894 if (fp) fclose (fp);
10895 UNGCPRO;
10896 return 0;
10897 }
10898
10899 info_ptr = png_create_info_struct (png_ptr);
10900 if (!info_ptr)
10901 {
10902 png_destroy_read_struct (&png_ptr, NULL, NULL);
10903 if (fp) fclose (fp);
10904 UNGCPRO;
10905 return 0;
10906 }
10907
10908 end_info = png_create_info_struct (png_ptr);
10909 if (!end_info)
10910 {
10911 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
10912 if (fp) fclose (fp);
10913 UNGCPRO;
10914 return 0;
10915 }
10916
10917 /* Set error jump-back. We come back here when the PNG library
10918 detects an error. */
10919 if (setjmp (png_ptr->jmpbuf))
10920 {
10921 error:
10922 if (png_ptr)
10923 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
10924 xfree (pixels);
10925 xfree (rows);
10926 if (fp) fclose (fp);
10927 UNGCPRO;
10928 return 0;
10929 }
10930
10931 /* Read image info. */
10932 if (!NILP (specified_data))
10933 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
10934 else
10935 png_init_io (png_ptr, fp);
10936
10937 png_set_sig_bytes (png_ptr, sizeof sig);
10938 png_read_info (png_ptr, info_ptr);
10939 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
10940 &interlace_type, NULL, NULL);
10941
10942 /* If image contains simply transparency data, we prefer to
10943 construct a clipping mask. */
10944 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
10945 transparent_p = 1;
10946 else
10947 transparent_p = 0;
10948
10949 /* This function is easier to write if we only have to handle
10950 one data format: RGB or RGBA with 8 bits per channel. Let's
10951 transform other formats into that format. */
10952
10953 /* Strip more than 8 bits per channel. */
10954 if (bit_depth == 16)
10955 png_set_strip_16 (png_ptr);
10956
10957 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
10958 if available. */
10959 png_set_expand (png_ptr);
10960
10961 /* Convert grayscale images to RGB. */
10962 if (color_type == PNG_COLOR_TYPE_GRAY
10963 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
10964 png_set_gray_to_rgb (png_ptr);
10965
10966 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
10967 gamma_str = getenv ("SCREEN_GAMMA");
10968 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
10969
10970 /* Tell the PNG lib to handle gamma correction for us. */
10971
10972 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
10973 if (png_get_sRGB (png_ptr, info_ptr, &intent))
10974 /* There is a special chunk in the image specifying the gamma. */
10975 png_set_sRGB (png_ptr, info_ptr, intent);
10976 else
10977 #endif
10978 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
10979 /* Image contains gamma information. */
10980 png_set_gamma (png_ptr, screen_gamma, image_gamma);
10981 else
10982 /* Use a default of 0.5 for the image gamma. */
10983 png_set_gamma (png_ptr, screen_gamma, 0.5);
10984
10985 /* Handle alpha channel by combining the image with a background
10986 color. Do this only if a real alpha channel is supplied. For
10987 simple transparency, we prefer a clipping mask. */
10988 if (!transparent_p)
10989 {
10990 png_color_16 *image_background;
10991
10992 if (png_get_bKGD (png_ptr, info_ptr, &image_background))
10993 /* Image contains a background color with which to
10994 combine the image. */
10995 png_set_background (png_ptr, image_background,
10996 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
10997 else
10998 {
10999 /* Image does not contain a background color with which
11000 to combine the image data via an alpha channel. Use
11001 the frame's background instead. */
11002 XColor color;
11003 Colormap cmap;
11004 png_color_16 frame_background;
11005
11006 BLOCK_INPUT;
11007 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
11008 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11009 XQueryColor (FRAME_W32_DISPLAY (f), cmap, &color);
11010 UNBLOCK_INPUT;
11011
11012 bzero (&frame_background, sizeof frame_background);
11013 frame_background.red = color.red;
11014 frame_background.green = color.green;
11015 frame_background.blue = color.blue;
11016
11017 png_set_background (png_ptr, &frame_background,
11018 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11019 }
11020 }
11021
11022 /* Update info structure. */
11023 png_read_update_info (png_ptr, info_ptr);
11024
11025 /* Get number of channels. Valid values are 1 for grayscale images
11026 and images with a palette, 2 for grayscale images with transparency
11027 information (alpha channel), 3 for RGB images, and 4 for RGB
11028 images with alpha channel, i.e. RGBA. If conversions above were
11029 sufficient we should only have 3 or 4 channels here. */
11030 channels = png_get_channels (png_ptr, info_ptr);
11031 xassert (channels == 3 || channels == 4);
11032
11033 /* Number of bytes needed for one row of the image. */
11034 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11035
11036 /* Allocate memory for the image. */
11037 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11038 rows = (png_byte **) xmalloc (height * sizeof *rows);
11039 for (i = 0; i < height; ++i)
11040 rows[i] = pixels + i * row_bytes;
11041
11042 /* Read the entire image. */
11043 png_read_image (png_ptr, rows);
11044 png_read_end (png_ptr, info_ptr);
11045 if (fp)
11046 {
11047 fclose (fp);
11048 fp = NULL;
11049 }
11050
11051 BLOCK_INPUT;
11052
11053 /* Create the X image and pixmap. */
11054 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11055 &img->pixmap))
11056 {
11057 UNBLOCK_INPUT;
11058 goto error;
11059 }
11060
11061 /* Create an image and pixmap serving as mask if the PNG image
11062 contains an alpha channel. */
11063 if (channels == 4
11064 && !transparent_p
11065 && !x_create_x_image_and_pixmap (f, width, height, 1,
11066 &mask_img, &img->mask))
11067 {
11068 x_destroy_x_image (ximg);
11069 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11070 img->pixmap = 0;
11071 UNBLOCK_INPUT;
11072 goto error;
11073 }
11074
11075 /* Fill the X image and mask from PNG data. */
11076 init_color_table ();
11077
11078 for (y = 0; y < height; ++y)
11079 {
11080 png_byte *p = rows[y];
11081
11082 for (x = 0; x < width; ++x)
11083 {
11084 unsigned r, g, b;
11085
11086 r = *p++ << 8;
11087 g = *p++ << 8;
11088 b = *p++ << 8;
11089 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11090
11091 /* An alpha channel, aka mask channel, associates variable
11092 transparency with an image. Where other image formats
11093 support binary transparency---fully transparent or fully
11094 opaque---PNG allows up to 254 levels of partial transparency.
11095 The PNG library implements partial transparency by combining
11096 the image with a specified background color.
11097
11098 I'm not sure how to handle this here nicely: because the
11099 background on which the image is displayed may change, for
11100 real alpha channel support, it would be necessary to create
11101 a new image for each possible background.
11102
11103 What I'm doing now is that a mask is created if we have
11104 boolean transparency information. Otherwise I'm using
11105 the frame's background color to combine the image with. */
11106
11107 if (channels == 4)
11108 {
11109 if (mask_img)
11110 XPutPixel (mask_img, x, y, *p > 0);
11111 ++p;
11112 }
11113 }
11114 }
11115
11116 /* Remember colors allocated for this image. */
11117 img->colors = colors_in_color_table (&img->ncolors);
11118 free_color_table ();
11119
11120 /* Clean up. */
11121 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11122 xfree (rows);
11123 xfree (pixels);
11124
11125 img->width = width;
11126 img->height = height;
11127
11128 /* Put the image into the pixmap, then free the X image and its buffer. */
11129 x_put_x_image (f, ximg, img->pixmap, width, height);
11130 x_destroy_x_image (ximg);
11131
11132 /* Same for the mask. */
11133 if (mask_img)
11134 {
11135 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11136 x_destroy_x_image (mask_img);
11137 }
11138
11139 UNBLOCK_INPUT;
11140 UNGCPRO;
11141 return 1;
11142 }
11143
11144 #endif /* HAVE_PNG != 0 */
11145
11146
11147 \f
11148 /***********************************************************************
11149 JPEG
11150 ***********************************************************************/
11151
11152 #if HAVE_JPEG
11153
11154 /* Work around a warning about HAVE_STDLIB_H being redefined in
11155 jconfig.h. */
11156 #ifdef HAVE_STDLIB_H
11157 #define HAVE_STDLIB_H_1
11158 #undef HAVE_STDLIB_H
11159 #endif /* HAVE_STLIB_H */
11160
11161 #include <jpeglib.h>
11162 #include <jerror.h>
11163 #include <setjmp.h>
11164
11165 #ifdef HAVE_STLIB_H_1
11166 #define HAVE_STDLIB_H 1
11167 #endif
11168
11169 static int jpeg_image_p P_ ((Lisp_Object object));
11170 static int jpeg_load P_ ((struct frame *f, struct image *img));
11171
11172 /* The symbol `jpeg' identifying images of this type. */
11173
11174 Lisp_Object Qjpeg;
11175
11176 /* Indices of image specification fields in gs_format, below. */
11177
11178 enum jpeg_keyword_index
11179 {
11180 JPEG_TYPE,
11181 JPEG_DATA,
11182 JPEG_FILE,
11183 JPEG_ASCENT,
11184 JPEG_MARGIN,
11185 JPEG_RELIEF,
11186 JPEG_ALGORITHM,
11187 JPEG_HEURISTIC_MASK,
11188 JPEG_LAST
11189 };
11190
11191 /* Vector of image_keyword structures describing the format
11192 of valid user-defined image specifications. */
11193
11194 static struct image_keyword jpeg_format[JPEG_LAST] =
11195 {
11196 {":type", IMAGE_SYMBOL_VALUE, 1},
11197 {":data", IMAGE_STRING_VALUE, 0},
11198 {":file", IMAGE_STRING_VALUE, 0},
11199 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11200 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11201 {":relief", IMAGE_INTEGER_VALUE, 0},
11202 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11203 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11204 };
11205
11206 /* Structure describing the image type `jpeg'. */
11207
11208 static struct image_type jpeg_type =
11209 {
11210 &Qjpeg,
11211 jpeg_image_p,
11212 jpeg_load,
11213 x_clear_image,
11214 NULL
11215 };
11216
11217
11218 /* Return non-zero if OBJECT is a valid JPEG image specification. */
11219
11220 static int
11221 jpeg_image_p (object)
11222 Lisp_Object object;
11223 {
11224 struct image_keyword fmt[JPEG_LAST];
11225
11226 bcopy (jpeg_format, fmt, sizeof fmt);
11227
11228 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11229 || (fmt[JPEG_ASCENT].count
11230 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11231 return 0;
11232
11233 /* Must specify either the :data or :file keyword. */
11234 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11235 }
11236
11237
11238 struct my_jpeg_error_mgr
11239 {
11240 struct jpeg_error_mgr pub;
11241 jmp_buf setjmp_buffer;
11242 };
11243
11244 static void
11245 my_error_exit (cinfo)
11246 j_common_ptr cinfo;
11247 {
11248 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11249 longjmp (mgr->setjmp_buffer, 1);
11250 }
11251
11252 /* Init source method for JPEG data source manager. Called by
11253 jpeg_read_header() before any data is actually read. See
11254 libjpeg.doc from the JPEG lib distribution. */
11255
11256 static void
11257 our_init_source (cinfo)
11258 j_decompress_ptr cinfo;
11259 {
11260 }
11261
11262
11263 /* Fill input buffer method for JPEG data source manager. Called
11264 whenever more data is needed. We read the whole image in one step,
11265 so this only adds a fake end of input marker at the end. */
11266
11267 static boolean
11268 our_fill_input_buffer (cinfo)
11269 j_decompress_ptr cinfo;
11270 {
11271 /* Insert a fake EOI marker. */
11272 struct jpeg_source_mgr *src = cinfo->src;
11273 static JOCTET buffer[2];
11274
11275 buffer[0] = (JOCTET) 0xFF;
11276 buffer[1] = (JOCTET) JPEG_EOI;
11277
11278 src->next_input_byte = buffer;
11279 src->bytes_in_buffer = 2;
11280 return TRUE;
11281 }
11282
11283
11284 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11285 is the JPEG data source manager. */
11286
11287 static void
11288 our_skip_input_data (cinfo, num_bytes)
11289 j_decompress_ptr cinfo;
11290 long num_bytes;
11291 {
11292 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11293
11294 if (src)
11295 {
11296 if (num_bytes > src->bytes_in_buffer)
11297 ERREXIT (cinfo, JERR_INPUT_EOF);
11298
11299 src->bytes_in_buffer -= num_bytes;
11300 src->next_input_byte += num_bytes;
11301 }
11302 }
11303
11304
11305 /* Method to terminate data source. Called by
11306 jpeg_finish_decompress() after all data has been processed. */
11307
11308 static void
11309 our_term_source (cinfo)
11310 j_decompress_ptr cinfo;
11311 {
11312 }
11313
11314
11315 /* Set up the JPEG lib for reading an image from DATA which contains
11316 LEN bytes. CINFO is the decompression info structure created for
11317 reading the image. */
11318
11319 static void
11320 jpeg_memory_src (cinfo, data, len)
11321 j_decompress_ptr cinfo;
11322 JOCTET *data;
11323 unsigned int len;
11324 {
11325 struct jpeg_source_mgr *src;
11326
11327 if (cinfo->src == NULL)
11328 {
11329 /* First time for this JPEG object? */
11330 cinfo->src = (struct jpeg_source_mgr *)
11331 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11332 sizeof (struct jpeg_source_mgr));
11333 src = (struct jpeg_source_mgr *) cinfo->src;
11334 src->next_input_byte = data;
11335 }
11336
11337 src = (struct jpeg_source_mgr *) cinfo->src;
11338 src->init_source = our_init_source;
11339 src->fill_input_buffer = our_fill_input_buffer;
11340 src->skip_input_data = our_skip_input_data;
11341 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11342 src->term_source = our_term_source;
11343 src->bytes_in_buffer = len;
11344 src->next_input_byte = data;
11345 }
11346
11347
11348 /* Load image IMG for use on frame F. Patterned after example.c
11349 from the JPEG lib. */
11350
11351 static int
11352 jpeg_load (f, img)
11353 struct frame *f;
11354 struct image *img;
11355 {
11356 struct jpeg_decompress_struct cinfo;
11357 struct my_jpeg_error_mgr mgr;
11358 Lisp_Object file, specified_file;
11359 Lisp_Object specified_data;
11360 FILE *fp = NULL;
11361 JSAMPARRAY buffer;
11362 int row_stride, x, y;
11363 XImage *ximg = NULL;
11364 int rc;
11365 unsigned long *colors;
11366 int width, height;
11367 struct gcpro gcpro1;
11368
11369 /* Open the JPEG file. */
11370 specified_file = image_spec_value (img->spec, QCfile, NULL);
11371 specified_data = image_spec_value (img->spec, QCdata, NULL);
11372 file = Qnil;
11373 GCPRO1 (file);
11374
11375 if (NILP (specified_data))
11376 {
11377 file = x_find_image_file (specified_file);
11378 if (!STRINGP (file))
11379 {
11380 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11381 UNGCPRO;
11382 return 0;
11383 }
11384
11385 fp = fopen (XSTRING (file)->data, "r");
11386 if (fp == NULL)
11387 {
11388 image_error ("Cannot open `%s'", file, Qnil);
11389 UNGCPRO;
11390 return 0;
11391 }
11392 }
11393
11394 /* Customize libjpeg's error handling to call my_error_exit when an
11395 error is detected. This function will perform a longjmp. */
11396 mgr.pub.error_exit = my_error_exit;
11397 cinfo.err = jpeg_std_error (&mgr.pub);
11398
11399 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
11400 {
11401 if (rc == 1)
11402 {
11403 /* Called from my_error_exit. Display a JPEG error. */
11404 char buffer[JMSG_LENGTH_MAX];
11405 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
11406 image_error ("Error reading JPEG image `%s': %s", img->spec,
11407 build_string (buffer));
11408 }
11409
11410 /* Close the input file and destroy the JPEG object. */
11411 if (fp)
11412 fclose (fp);
11413 jpeg_destroy_decompress (&cinfo);
11414
11415 BLOCK_INPUT;
11416
11417 /* If we already have an XImage, free that. */
11418 x_destroy_x_image (ximg);
11419
11420 /* Free pixmap and colors. */
11421 x_clear_image (f, img);
11422
11423 UNBLOCK_INPUT;
11424 UNGCPRO;
11425 return 0;
11426 }
11427
11428 /* Create the JPEG decompression object. Let it read from fp.
11429 Read the JPEG image header. */
11430 jpeg_create_decompress (&cinfo);
11431
11432 if (NILP (specified_data))
11433 jpeg_stdio_src (&cinfo, fp);
11434 else
11435 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
11436 STRING_BYTES (XSTRING (specified_data)));
11437
11438 jpeg_read_header (&cinfo, TRUE);
11439
11440 /* Customize decompression so that color quantization will be used.
11441 Start decompression. */
11442 cinfo.quantize_colors = TRUE;
11443 jpeg_start_decompress (&cinfo);
11444 width = img->width = cinfo.output_width;
11445 height = img->height = cinfo.output_height;
11446
11447 BLOCK_INPUT;
11448
11449 /* Create X image and pixmap. */
11450 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11451 &img->pixmap))
11452 {
11453 UNBLOCK_INPUT;
11454 longjmp (mgr.setjmp_buffer, 2);
11455 }
11456
11457 /* Allocate colors. When color quantization is used,
11458 cinfo.actual_number_of_colors has been set with the number of
11459 colors generated, and cinfo.colormap is a two-dimensional array
11460 of color indices in the range 0..cinfo.actual_number_of_colors.
11461 No more than 255 colors will be generated. */
11462 {
11463 int i, ir, ig, ib;
11464
11465 if (cinfo.out_color_components > 2)
11466 ir = 0, ig = 1, ib = 2;
11467 else if (cinfo.out_color_components > 1)
11468 ir = 0, ig = 1, ib = 0;
11469 else
11470 ir = 0, ig = 0, ib = 0;
11471
11472 /* Use the color table mechanism because it handles colors that
11473 cannot be allocated nicely. Such colors will be replaced with
11474 a default color, and we don't have to care about which colors
11475 can be freed safely, and which can't. */
11476 init_color_table ();
11477 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
11478 * sizeof *colors);
11479
11480 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
11481 {
11482 /* Multiply RGB values with 255 because X expects RGB values
11483 in the range 0..0xffff. */
11484 int r = cinfo.colormap[ir][i] << 8;
11485 int g = cinfo.colormap[ig][i] << 8;
11486 int b = cinfo.colormap[ib][i] << 8;
11487 colors[i] = lookup_rgb_color (f, r, g, b);
11488 }
11489
11490 /* Remember those colors actually allocated. */
11491 img->colors = colors_in_color_table (&img->ncolors);
11492 free_color_table ();
11493 }
11494
11495 /* Read pixels. */
11496 row_stride = width * cinfo.output_components;
11497 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
11498 row_stride, 1);
11499 for (y = 0; y < height; ++y)
11500 {
11501 jpeg_read_scanlines (&cinfo, buffer, 1);
11502 for (x = 0; x < cinfo.output_width; ++x)
11503 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
11504 }
11505
11506 /* Clean up. */
11507 jpeg_finish_decompress (&cinfo);
11508 jpeg_destroy_decompress (&cinfo);
11509 if (fp)
11510 fclose (fp);
11511
11512 /* Put the image into the pixmap. */
11513 x_put_x_image (f, ximg, img->pixmap, width, height);
11514 x_destroy_x_image (ximg);
11515 UNBLOCK_INPUT;
11516 UNGCPRO;
11517 return 1;
11518 }
11519
11520 #endif /* HAVE_JPEG */
11521
11522
11523 \f
11524 /***********************************************************************
11525 TIFF
11526 ***********************************************************************/
11527
11528 #if HAVE_TIFF
11529
11530 #include <tiffio.h>
11531
11532 static int tiff_image_p P_ ((Lisp_Object object));
11533 static int tiff_load P_ ((struct frame *f, struct image *img));
11534
11535 /* The symbol `tiff' identifying images of this type. */
11536
11537 Lisp_Object Qtiff;
11538
11539 /* Indices of image specification fields in tiff_format, below. */
11540
11541 enum tiff_keyword_index
11542 {
11543 TIFF_TYPE,
11544 TIFF_DATA,
11545 TIFF_FILE,
11546 TIFF_ASCENT,
11547 TIFF_MARGIN,
11548 TIFF_RELIEF,
11549 TIFF_ALGORITHM,
11550 TIFF_HEURISTIC_MASK,
11551 TIFF_LAST
11552 };
11553
11554 /* Vector of image_keyword structures describing the format
11555 of valid user-defined image specifications. */
11556
11557 static struct image_keyword tiff_format[TIFF_LAST] =
11558 {
11559 {":type", IMAGE_SYMBOL_VALUE, 1},
11560 {":data", IMAGE_STRING_VALUE, 0},
11561 {":file", IMAGE_STRING_VALUE, 0},
11562 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11563 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11564 {":relief", IMAGE_INTEGER_VALUE, 0},
11565 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11566 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
11567 };
11568
11569 /* Structure describing the image type `tiff'. */
11570
11571 static struct image_type tiff_type =
11572 {
11573 &Qtiff,
11574 tiff_image_p,
11575 tiff_load,
11576 x_clear_image,
11577 NULL
11578 };
11579
11580
11581 /* Return non-zero if OBJECT is a valid TIFF image specification. */
11582
11583 static int
11584 tiff_image_p (object)
11585 Lisp_Object object;
11586 {
11587 struct image_keyword fmt[TIFF_LAST];
11588 bcopy (tiff_format, fmt, sizeof fmt);
11589
11590 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
11591 || (fmt[TIFF_ASCENT].count
11592 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
11593 return 0;
11594
11595 /* Must specify either the :data or :file keyword. */
11596 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
11597 }
11598
11599
11600 /* Reading from a memory buffer for TIFF images Based on the PNG
11601 memory source, but we have to provide a lot of extra functions.
11602 Blah.
11603
11604 We really only need to implement read and seek, but I am not
11605 convinced that the TIFF library is smart enough not to destroy
11606 itself if we only hand it the function pointers we need to
11607 override. */
11608
11609 typedef struct
11610 {
11611 unsigned char *bytes;
11612 size_t len;
11613 int index;
11614 }
11615 tiff_memory_source;
11616
11617 static size_t
11618 tiff_read_from_memory (data, buf, size)
11619 thandle_t data;
11620 tdata_t buf;
11621 tsize_t size;
11622 {
11623 tiff_memory_source *src = (tiff_memory_source *) data;
11624
11625 if (size > src->len - src->index)
11626 return (size_t) -1;
11627 bcopy (src->bytes + src->index, buf, size);
11628 src->index += size;
11629 return size;
11630 }
11631
11632 static size_t
11633 tiff_write_from_memory (data, buf, size)
11634 thandle_t data;
11635 tdata_t buf;
11636 tsize_t size;
11637 {
11638 return (size_t) -1;
11639 }
11640
11641 static toff_t
11642 tiff_seek_in_memory (data, off, whence)
11643 thandle_t data;
11644 toff_t off;
11645 int whence;
11646 {
11647 tiff_memory_source *src = (tiff_memory_source *) data;
11648 int idx;
11649
11650 switch (whence)
11651 {
11652 case SEEK_SET: /* Go from beginning of source. */
11653 idx = off;
11654 break;
11655
11656 case SEEK_END: /* Go from end of source. */
11657 idx = src->len + off;
11658 break;
11659
11660 case SEEK_CUR: /* Go from current position. */
11661 idx = src->index + off;
11662 break;
11663
11664 default: /* Invalid `whence'. */
11665 return -1;
11666 }
11667
11668 if (idx > src->len || idx < 0)
11669 return -1;
11670
11671 src->index = idx;
11672 return src->index;
11673 }
11674
11675 static int
11676 tiff_close_memory (data)
11677 thandle_t data;
11678 {
11679 /* NOOP */
11680 return 0;
11681 }
11682
11683 static int
11684 tiff_mmap_memory (data, pbase, psize)
11685 thandle_t data;
11686 tdata_t *pbase;
11687 toff_t *psize;
11688 {
11689 /* It is already _IN_ memory. */
11690 return 0;
11691 }
11692
11693 static void
11694 tiff_unmap_memory (data, base, size)
11695 thandle_t data;
11696 tdata_t base;
11697 toff_t size;
11698 {
11699 /* We don't need to do this. */
11700 }
11701
11702 static toff_t
11703 tiff_size_of_memory (data)
11704 thandle_t data;
11705 {
11706 return ((tiff_memory_source *) data)->len;
11707 }
11708
11709
11710 static void
11711 tiff_error_handler (title, format, ap)
11712 const char *title, *format;
11713 va_list ap;
11714 {
11715 char buf[512];
11716 int len;
11717
11718 len = sprintf (buf, "TIFF error: %s ", title);
11719 vsprintf (buf + len, format, ap);
11720 add_to_log (buf, Qnil, Qnil);
11721 }
11722
11723
11724 static void
11725 tiff_warning_handler (title, format, ap)
11726 const char *title, *format;
11727 va_list ap;
11728 {
11729 char buf[512];
11730 int len;
11731
11732 len = sprintf (buf, "TIFF warning: %s ", title);
11733 vsprintf (buf + len, format, ap);
11734 add_to_log (buf, Qnil, Qnil);
11735 }
11736
11737
11738 /* Load TIFF image IMG for use on frame F. Value is non-zero if
11739 successful. */
11740
11741 static int
11742 tiff_load (f, img)
11743 struct frame *f;
11744 struct image *img;
11745 {
11746 Lisp_Object file, specified_file;
11747 Lisp_Object specified_data;
11748 TIFF *tiff;
11749 int width, height, x, y;
11750 uint32 *buf;
11751 int rc;
11752 XImage *ximg;
11753 struct gcpro gcpro1;
11754 tiff_memory_source memsrc;
11755
11756 specified_file = image_spec_value (img->spec, QCfile, NULL);
11757 specified_data = image_spec_value (img->spec, QCdata, NULL);
11758 file = Qnil;
11759 GCPRO1 (file);
11760
11761 TIFFSetErrorHandler (tiff_error_handler);
11762 TIFFSetWarningHandler (tiff_warning_handler);
11763
11764 if (NILP (specified_data))
11765 {
11766 /* Read from a file */
11767 file = x_find_image_file (specified_file);
11768 if (!STRINGP (file))
11769 {
11770 image_error ("Cannot find image file `%s'", file, Qnil);
11771 UNGCPRO;
11772 return 0;
11773 }
11774
11775 /* Try to open the image file. */
11776 tiff = TIFFOpen (XSTRING (file)->data, "r");
11777 if (tiff == NULL)
11778 {
11779 image_error ("Cannot open `%s'", file, Qnil);
11780 UNGCPRO;
11781 return 0;
11782 }
11783 }
11784 else
11785 {
11786 /* Memory source! */
11787 memsrc.bytes = XSTRING (specified_data)->data;
11788 memsrc.len = STRING_BYTES (XSTRING (specified_data));
11789 memsrc.index = 0;
11790
11791 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
11792 (TIFFReadWriteProc) tiff_read_from_memory,
11793 (TIFFReadWriteProc) tiff_write_from_memory,
11794 tiff_seek_in_memory,
11795 tiff_close_memory,
11796 tiff_size_of_memory,
11797 tiff_mmap_memory,
11798 tiff_unmap_memory);
11799
11800 if (!tiff)
11801 {
11802 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
11803 UNGCPRO;
11804 return 0;
11805 }
11806 }
11807
11808 /* Get width and height of the image, and allocate a raster buffer
11809 of width x height 32-bit values. */
11810 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
11811 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
11812 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
11813
11814 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
11815 TIFFClose (tiff);
11816 if (!rc)
11817 {
11818 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
11819 xfree (buf);
11820 UNGCPRO;
11821 return 0;
11822 }
11823
11824 /* Create the X image and pixmap. */
11825 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11826 {
11827 xfree (buf);
11828 UNGCPRO;
11829 return 0;
11830 }
11831
11832 /* Initialize the color table. */
11833 init_color_table ();
11834
11835 /* Process the pixel raster. Origin is in the lower-left corner. */
11836 for (y = 0; y < height; ++y)
11837 {
11838 uint32 *row = buf + y * width;
11839
11840 for (x = 0; x < width; ++x)
11841 {
11842 uint32 abgr = row[x];
11843 int r = TIFFGetR (abgr) << 8;
11844 int g = TIFFGetG (abgr) << 8;
11845 int b = TIFFGetB (abgr) << 8;
11846 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
11847 }
11848 }
11849
11850 /* Remember the colors allocated for the image. Free the color table. */
11851 img->colors = colors_in_color_table (&img->ncolors);
11852 free_color_table ();
11853
11854 /* Put the image into the pixmap, then free the X image and its buffer. */
11855 x_put_x_image (f, ximg, img->pixmap, width, height);
11856 x_destroy_x_image (ximg);
11857 xfree (buf);
11858
11859 img->width = width;
11860 img->height = height;
11861
11862 UNGCPRO;
11863 return 1;
11864 }
11865
11866 #endif /* HAVE_TIFF != 0 */
11867
11868
11869 \f
11870 /***********************************************************************
11871 GIF
11872 ***********************************************************************/
11873
11874 #if HAVE_GIF
11875
11876 #include <gif_lib.h>
11877
11878 static int gif_image_p P_ ((Lisp_Object object));
11879 static int gif_load P_ ((struct frame *f, struct image *img));
11880
11881 /* The symbol `gif' identifying images of this type. */
11882
11883 Lisp_Object Qgif;
11884
11885 /* Indices of image specification fields in gif_format, below. */
11886
11887 enum gif_keyword_index
11888 {
11889 GIF_TYPE,
11890 GIF_DATA,
11891 GIF_FILE,
11892 GIF_ASCENT,
11893 GIF_MARGIN,
11894 GIF_RELIEF,
11895 GIF_ALGORITHM,
11896 GIF_HEURISTIC_MASK,
11897 GIF_IMAGE,
11898 GIF_LAST
11899 };
11900
11901 /* Vector of image_keyword structures describing the format
11902 of valid user-defined image specifications. */
11903
11904 static struct image_keyword gif_format[GIF_LAST] =
11905 {
11906 {":type", IMAGE_SYMBOL_VALUE, 1},
11907 {":data", IMAGE_STRING_VALUE, 0},
11908 {":file", IMAGE_STRING_VALUE, 0},
11909 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11910 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11911 {":relief", IMAGE_INTEGER_VALUE, 0},
11912 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11913 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11914 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0}
11915 };
11916
11917 /* Structure describing the image type `gif'. */
11918
11919 static struct image_type gif_type =
11920 {
11921 &Qgif,
11922 gif_image_p,
11923 gif_load,
11924 x_clear_image,
11925 NULL
11926 };
11927
11928 /* Return non-zero if OBJECT is a valid GIF image specification. */
11929
11930 static int
11931 gif_image_p (object)
11932 Lisp_Object object;
11933 {
11934 struct image_keyword fmt[GIF_LAST];
11935 bcopy (gif_format, fmt, sizeof fmt);
11936
11937 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
11938 || (fmt[GIF_ASCENT].count
11939 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
11940 return 0;
11941
11942 /* Must specify either the :data or :file keyword. */
11943 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
11944 }
11945
11946 /* Reading a GIF image from memory
11947 Based on the PNG memory stuff to a certain extent. */
11948
11949 typedef struct
11950 {
11951 unsigned char *bytes;
11952 size_t len;
11953 int index;
11954 }
11955 gif_memory_source;
11956
11957 /* Make the current memory source available to gif_read_from_memory.
11958 It's done this way because not all versions of libungif support
11959 a UserData field in the GifFileType structure. */
11960 static gif_memory_source *current_gif_memory_src;
11961
11962 static int
11963 gif_read_from_memory (file, buf, len)
11964 GifFileType *file;
11965 GifByteType *buf;
11966 int len;
11967 {
11968 gif_memory_source *src = current_gif_memory_src;
11969
11970 if (len > src->len - src->index)
11971 return -1;
11972
11973 bcopy (src->bytes + src->index, buf, len);
11974 src->index += len;
11975 return len;
11976 }
11977
11978
11979 /* Load GIF image IMG for use on frame F. Value is non-zero if
11980 successful. */
11981
11982 static int
11983 gif_load (f, img)
11984 struct frame *f;
11985 struct image *img;
11986 {
11987 Lisp_Object file, specified_file;
11988 Lisp_Object specified_data;
11989 int rc, width, height, x, y, i;
11990 XImage *ximg;
11991 ColorMapObject *gif_color_map;
11992 unsigned long pixel_colors[256];
11993 GifFileType *gif;
11994 struct gcpro gcpro1;
11995 Lisp_Object image;
11996 int ino, image_left, image_top, image_width, image_height;
11997 gif_memory_source memsrc;
11998 unsigned char *raster;
11999
12000 specified_file = image_spec_value (img->spec, QCfile, NULL);
12001 specified_data = image_spec_value (img->spec, QCdata, NULL);
12002 file = Qnil;
12003 GCPRO1 (file);
12004
12005 if (NILP (specified_data))
12006 {
12007 file = x_find_image_file (specified_file);
12008 if (!STRINGP (file))
12009 {
12010 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12011 UNGCPRO;
12012 return 0;
12013 }
12014
12015 /* Open the GIF file. */
12016 gif = DGifOpenFileName (XSTRING (file)->data);
12017 if (gif == NULL)
12018 {
12019 image_error ("Cannot open `%s'", file, Qnil);
12020 UNGCPRO;
12021 return 0;
12022 }
12023 }
12024 else
12025 {
12026 /* Read from memory! */
12027 current_gif_memory_src = &memsrc;
12028 memsrc.bytes = XSTRING (specified_data)->data;
12029 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12030 memsrc.index = 0;
12031
12032 gif = DGifOpen(&memsrc, gif_read_from_memory);
12033 if (!gif)
12034 {
12035 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12036 UNGCPRO;
12037 return 0;
12038 }
12039 }
12040
12041 /* Read entire contents. */
12042 rc = DGifSlurp (gif);
12043 if (rc == GIF_ERROR)
12044 {
12045 image_error ("Error reading `%s'", img->spec, Qnil);
12046 DGifCloseFile (gif);
12047 UNGCPRO;
12048 return 0;
12049 }
12050
12051 image = image_spec_value (img->spec, QCindex, NULL);
12052 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12053 if (ino >= gif->ImageCount)
12054 {
12055 image_error ("Invalid image number `%s' in image `%s'",
12056 image, img->spec);
12057 DGifCloseFile (gif);
12058 UNGCPRO;
12059 return 0;
12060 }
12061
12062 width = img->width = gif->SWidth;
12063 height = img->height = gif->SHeight;
12064
12065 BLOCK_INPUT;
12066
12067 /* Create the X image and pixmap. */
12068 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12069 {
12070 UNBLOCK_INPUT;
12071 DGifCloseFile (gif);
12072 UNGCPRO;
12073 return 0;
12074 }
12075
12076 /* Allocate colors. */
12077 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12078 if (!gif_color_map)
12079 gif_color_map = gif->SColorMap;
12080 init_color_table ();
12081 bzero (pixel_colors, sizeof pixel_colors);
12082
12083 for (i = 0; i < gif_color_map->ColorCount; ++i)
12084 {
12085 int r = gif_color_map->Colors[i].Red << 8;
12086 int g = gif_color_map->Colors[i].Green << 8;
12087 int b = gif_color_map->Colors[i].Blue << 8;
12088 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12089 }
12090
12091 img->colors = colors_in_color_table (&img->ncolors);
12092 free_color_table ();
12093
12094 /* Clear the part of the screen image that are not covered by
12095 the image from the GIF file. Full animated GIF support
12096 requires more than can be done here (see the gif89 spec,
12097 disposal methods). Let's simply assume that the part
12098 not covered by a sub-image is in the frame's background color. */
12099 image_top = gif->SavedImages[ino].ImageDesc.Top;
12100 image_left = gif->SavedImages[ino].ImageDesc.Left;
12101 image_width = gif->SavedImages[ino].ImageDesc.Width;
12102 image_height = gif->SavedImages[ino].ImageDesc.Height;
12103
12104 for (y = 0; y < image_top; ++y)
12105 for (x = 0; x < width; ++x)
12106 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12107
12108 for (y = image_top + image_height; y < height; ++y)
12109 for (x = 0; x < width; ++x)
12110 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12111
12112 for (y = image_top; y < image_top + image_height; ++y)
12113 {
12114 for (x = 0; x < image_left; ++x)
12115 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12116 for (x = image_left + image_width; x < width; ++x)
12117 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12118 }
12119
12120 /* Read the GIF image into the X image. We use a local variable
12121 `raster' here because RasterBits below is a char *, and invites
12122 problems with bytes >= 0x80. */
12123 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12124
12125 if (gif->SavedImages[ino].ImageDesc.Interlace)
12126 {
12127 static int interlace_start[] = {0, 4, 2, 1};
12128 static int interlace_increment[] = {8, 8, 4, 2};
12129 int pass, inc;
12130 int row = interlace_start[0];
12131
12132 pass = 0;
12133
12134 for (y = 0; y < image_height; y++)
12135 {
12136 if (row >= image_height)
12137 {
12138 row = interlace_start[++pass];
12139 while (row >= image_height)
12140 row = interlace_start[++pass];
12141 }
12142
12143 for (x = 0; x < image_width; x++)
12144 {
12145 int i = raster[(y * image_width) + x];
12146 XPutPixel (ximg, x + image_left, row + image_top,
12147 pixel_colors[i]);
12148 }
12149
12150 row += interlace_increment[pass];
12151 }
12152 }
12153 else
12154 {
12155 for (y = 0; y < image_height; ++y)
12156 for (x = 0; x < image_width; ++x)
12157 {
12158 int i = raster[y* image_width + x];
12159 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12160 }
12161 }
12162
12163 DGifCloseFile (gif);
12164
12165 /* Put the image into the pixmap, then free the X image and its buffer. */
12166 x_put_x_image (f, ximg, img->pixmap, width, height);
12167 x_destroy_x_image (ximg);
12168 UNBLOCK_INPUT;
12169
12170 UNGCPRO;
12171 return 1;
12172 }
12173
12174 #endif /* HAVE_GIF != 0 */
12175
12176
12177 \f
12178 /***********************************************************************
12179 Ghostscript
12180 ***********************************************************************/
12181
12182 Lisp_Object Qpostscript;
12183
12184 #ifdef HAVE_GHOSTSCRIPT
12185 static int gs_image_p P_ ((Lisp_Object object));
12186 static int gs_load P_ ((struct frame *f, struct image *img));
12187 static void gs_clear_image P_ ((struct frame *f, struct image *img));
12188
12189 /* The symbol `postscript' identifying images of this type. */
12190
12191 /* Keyword symbols. */
12192
12193 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12194
12195 /* Indices of image specification fields in gs_format, below. */
12196
12197 enum gs_keyword_index
12198 {
12199 GS_TYPE,
12200 GS_PT_WIDTH,
12201 GS_PT_HEIGHT,
12202 GS_FILE,
12203 GS_LOADER,
12204 GS_BOUNDING_BOX,
12205 GS_ASCENT,
12206 GS_MARGIN,
12207 GS_RELIEF,
12208 GS_ALGORITHM,
12209 GS_HEURISTIC_MASK,
12210 GS_LAST
12211 };
12212
12213 /* Vector of image_keyword structures describing the format
12214 of valid user-defined image specifications. */
12215
12216 static struct image_keyword gs_format[GS_LAST] =
12217 {
12218 {":type", IMAGE_SYMBOL_VALUE, 1},
12219 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12220 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12221 {":file", IMAGE_STRING_VALUE, 1},
12222 {":loader", IMAGE_FUNCTION_VALUE, 0},
12223 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12224 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12225 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12226 {":relief", IMAGE_INTEGER_VALUE, 0},
12227 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12228 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
12229 };
12230
12231 /* Structure describing the image type `ghostscript'. */
12232
12233 static struct image_type gs_type =
12234 {
12235 &Qpostscript,
12236 gs_image_p,
12237 gs_load,
12238 gs_clear_image,
12239 NULL
12240 };
12241
12242
12243 /* Free X resources of Ghostscript image IMG which is used on frame F. */
12244
12245 static void
12246 gs_clear_image (f, img)
12247 struct frame *f;
12248 struct image *img;
12249 {
12250 /* IMG->data.ptr_val may contain a recorded colormap. */
12251 xfree (img->data.ptr_val);
12252 x_clear_image (f, img);
12253 }
12254
12255
12256 /* Return non-zero if OBJECT is a valid Ghostscript image
12257 specification. */
12258
12259 static int
12260 gs_image_p (object)
12261 Lisp_Object object;
12262 {
12263 struct image_keyword fmt[GS_LAST];
12264 Lisp_Object tem;
12265 int i;
12266
12267 bcopy (gs_format, fmt, sizeof fmt);
12268
12269 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12270 || (fmt[GS_ASCENT].count
12271 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12272 return 0;
12273
12274 /* Bounding box must be a list or vector containing 4 integers. */
12275 tem = fmt[GS_BOUNDING_BOX].value;
12276 if (CONSP (tem))
12277 {
12278 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12279 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12280 return 0;
12281 if (!NILP (tem))
12282 return 0;
12283 }
12284 else if (VECTORP (tem))
12285 {
12286 if (XVECTOR (tem)->size != 4)
12287 return 0;
12288 for (i = 0; i < 4; ++i)
12289 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12290 return 0;
12291 }
12292 else
12293 return 0;
12294
12295 return 1;
12296 }
12297
12298
12299 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
12300 if successful. */
12301
12302 static int
12303 gs_load (f, img)
12304 struct frame *f;
12305 struct image *img;
12306 {
12307 char buffer[100];
12308 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12309 struct gcpro gcpro1, gcpro2;
12310 Lisp_Object frame;
12311 double in_width, in_height;
12312 Lisp_Object pixel_colors = Qnil;
12313
12314 /* Compute pixel size of pixmap needed from the given size in the
12315 image specification. Sizes in the specification are in pt. 1 pt
12316 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12317 info. */
12318 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12319 in_width = XFASTINT (pt_width) / 72.0;
12320 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12321 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12322 in_height = XFASTINT (pt_height) / 72.0;
12323 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12324
12325 /* Create the pixmap. */
12326 BLOCK_INPUT;
12327 xassert (img->pixmap == 0);
12328 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12329 img->width, img->height,
12330 DefaultDepthOfScreen (FRAME_X_SCREEN (f)));
12331 UNBLOCK_INPUT;
12332
12333 if (!img->pixmap)
12334 {
12335 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12336 return 0;
12337 }
12338
12339 /* Call the loader to fill the pixmap. It returns a process object
12340 if successful. We do not record_unwind_protect here because
12341 other places in redisplay like calling window scroll functions
12342 don't either. Let the Lisp loader use `unwind-protect' instead. */
12343 GCPRO2 (window_and_pixmap_id, pixel_colors);
12344
12345 sprintf (buffer, "%lu %lu",
12346 (unsigned long) FRAME_W32_WINDOW (f),
12347 (unsigned long) img->pixmap);
12348 window_and_pixmap_id = build_string (buffer);
12349
12350 sprintf (buffer, "%lu %lu",
12351 FRAME_FOREGROUND_PIXEL (f),
12352 FRAME_BACKGROUND_PIXEL (f));
12353 pixel_colors = build_string (buffer);
12354
12355 XSETFRAME (frame, f);
12356 loader = image_spec_value (img->spec, QCloader, NULL);
12357 if (NILP (loader))
12358 loader = intern ("gs-load-image");
12359
12360 img->data.lisp_val = call6 (loader, frame, img->spec,
12361 make_number (img->width),
12362 make_number (img->height),
12363 window_and_pixmap_id,
12364 pixel_colors);
12365 UNGCPRO;
12366 return PROCESSP (img->data.lisp_val);
12367 }
12368
12369
12370 /* Kill the Ghostscript process that was started to fill PIXMAP on
12371 frame F. Called from XTread_socket when receiving an event
12372 telling Emacs that Ghostscript has finished drawing. */
12373
12374 void
12375 x_kill_gs_process (pixmap, f)
12376 Pixmap pixmap;
12377 struct frame *f;
12378 {
12379 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
12380 int class, i;
12381 struct image *img;
12382
12383 /* Find the image containing PIXMAP. */
12384 for (i = 0; i < c->used; ++i)
12385 if (c->images[i]->pixmap == pixmap)
12386 break;
12387
12388 /* Should someone in between have cleared the image cache, for
12389 instance, give up. */
12390 if (i == c->used)
12391 return;
12392
12393 /* Kill the GS process. We should have found PIXMAP in the image
12394 cache and its image should contain a process object. */
12395 img = c->images[i];
12396 xassert (PROCESSP (img->data.lisp_val));
12397 Fkill_process (img->data.lisp_val, Qnil);
12398 img->data.lisp_val = Qnil;
12399
12400 /* On displays with a mutable colormap, figure out the colors
12401 allocated for the image by looking at the pixels of an XImage for
12402 img->pixmap. */
12403 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
12404 if (class != StaticColor && class != StaticGray && class != TrueColor)
12405 {
12406 XImage *ximg;
12407
12408 BLOCK_INPUT;
12409
12410 /* Try to get an XImage for img->pixmep. */
12411 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
12412 0, 0, img->width, img->height, ~0, ZPixmap);
12413 if (ximg)
12414 {
12415 int x, y;
12416
12417 /* Initialize the color table. */
12418 init_color_table ();
12419
12420 /* For each pixel of the image, look its color up in the
12421 color table. After having done so, the color table will
12422 contain an entry for each color used by the image. */
12423 for (y = 0; y < img->height; ++y)
12424 for (x = 0; x < img->width; ++x)
12425 {
12426 unsigned long pixel = XGetPixel (ximg, x, y);
12427 lookup_pixel_color (f, pixel);
12428 }
12429
12430 /* Record colors in the image. Free color table and XImage. */
12431 img->colors = colors_in_color_table (&img->ncolors);
12432 free_color_table ();
12433 XDestroyImage (ximg);
12434
12435 #if 0 /* This doesn't seem to be the case. If we free the colors
12436 here, we get a BadAccess later in x_clear_image when
12437 freeing the colors. */
12438 /* We have allocated colors once, but Ghostscript has also
12439 allocated colors on behalf of us. So, to get the
12440 reference counts right, free them once. */
12441 if (img->ncolors)
12442 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
12443 img->colors, img->ncolors, 0);
12444 #endif
12445 }
12446 else
12447 image_error ("Cannot get X image of `%s'; colors will not be freed",
12448 img->spec, Qnil);
12449
12450 UNBLOCK_INPUT;
12451 }
12452
12453 /* Now that we have the pixmap, compute mask and transform the
12454 image if requested. */
12455 BLOCK_INPUT;
12456 postprocess_image (f, img);
12457 UNBLOCK_INPUT;
12458 }
12459
12460 #endif /* HAVE_GHOSTSCRIPT */
12461
12462 \f
12463 /***********************************************************************
12464 Window properties
12465 ***********************************************************************/
12466
12467 DEFUN ("x-change-window-property", Fx_change_window_property,
12468 Sx_change_window_property, 2, 3, 0,
12469 doc: /* Change window property PROP to VALUE on the X window of FRAME.
12470 PROP and VALUE must be strings. FRAME nil or omitted means use the
12471 selected frame. Value is VALUE. */)
12472 (prop, value, frame)
12473 Lisp_Object frame, prop, value;
12474 {
12475 #if 0 /* TODO : port window properties to W32 */
12476 struct frame *f = check_x_frame (frame);
12477 Atom prop_atom;
12478
12479 CHECK_STRING (prop);
12480 CHECK_STRING (value);
12481
12482 BLOCK_INPUT;
12483 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12484 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12485 prop_atom, XA_STRING, 8, PropModeReplace,
12486 XSTRING (value)->data, XSTRING (value)->size);
12487
12488 /* Make sure the property is set when we return. */
12489 XFlush (FRAME_W32_DISPLAY (f));
12490 UNBLOCK_INPUT;
12491
12492 #endif /* TODO */
12493
12494 return value;
12495 }
12496
12497
12498 DEFUN ("x-delete-window-property", Fx_delete_window_property,
12499 Sx_delete_window_property, 1, 2, 0,
12500 doc: /* Remove window property PROP from X window of FRAME.
12501 FRAME nil or omitted means use the selected frame. Value is PROP. */)
12502 (prop, frame)
12503 Lisp_Object prop, frame;
12504 {
12505 #if 0 /* TODO : port window properties to W32 */
12506
12507 struct frame *f = check_x_frame (frame);
12508 Atom prop_atom;
12509
12510 CHECK_STRING (prop);
12511 BLOCK_INPUT;
12512 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12513 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
12514
12515 /* Make sure the property is removed when we return. */
12516 XFlush (FRAME_W32_DISPLAY (f));
12517 UNBLOCK_INPUT;
12518 #endif /* TODO */
12519
12520 return prop;
12521 }
12522
12523
12524 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
12525 1, 2, 0,
12526 doc: /* Value is the value of window property PROP on FRAME.
12527 If FRAME is nil or omitted, use the selected frame. Value is nil
12528 if FRAME hasn't a property with name PROP or if PROP has no string
12529 value. */)
12530 (prop, frame)
12531 Lisp_Object prop, frame;
12532 {
12533 #if 0 /* TODO : port window properties to W32 */
12534
12535 struct frame *f = check_x_frame (frame);
12536 Atom prop_atom;
12537 int rc;
12538 Lisp_Object prop_value = Qnil;
12539 char *tmp_data = NULL;
12540 Atom actual_type;
12541 int actual_format;
12542 unsigned long actual_size, bytes_remaining;
12543
12544 CHECK_STRING (prop);
12545 BLOCK_INPUT;
12546 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
12547 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12548 prop_atom, 0, 0, False, XA_STRING,
12549 &actual_type, &actual_format, &actual_size,
12550 &bytes_remaining, (unsigned char **) &tmp_data);
12551 if (rc == Success)
12552 {
12553 int size = bytes_remaining;
12554
12555 XFree (tmp_data);
12556 tmp_data = NULL;
12557
12558 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12559 prop_atom, 0, bytes_remaining,
12560 False, XA_STRING,
12561 &actual_type, &actual_format,
12562 &actual_size, &bytes_remaining,
12563 (unsigned char **) &tmp_data);
12564 if (rc == Success)
12565 prop_value = make_string (tmp_data, size);
12566
12567 XFree (tmp_data);
12568 }
12569
12570 UNBLOCK_INPUT;
12571
12572 return prop_value;
12573
12574 #endif /* TODO */
12575 return Qnil;
12576 }
12577
12578
12579 \f
12580 /***********************************************************************
12581 Busy cursor
12582 ***********************************************************************/
12583
12584 /* If non-null, an asynchronous timer that, when it expires, displays
12585 an hourglass cursor on all frames. */
12586
12587 static struct atimer *hourglass_atimer;
12588
12589 /* Non-zero means an hourglass cursor is currently shown. */
12590
12591 static int hourglass_shown_p;
12592
12593 /* Number of seconds to wait before displaying an hourglass cursor. */
12594
12595 static Lisp_Object Vhourglass_delay;
12596
12597 /* Default number of seconds to wait before displaying an hourglass
12598 cursor. */
12599
12600 #define DEFAULT_HOURGLASS_DELAY 1
12601
12602 /* Function prototypes. */
12603
12604 static void show_hourglass P_ ((struct atimer *));
12605 static void hide_hourglass P_ ((void));
12606
12607
12608 /* Cancel a currently active hourglass timer, and start a new one. */
12609
12610 void
12611 start_hourglass ()
12612 {
12613 #if 0 /* TODO: cursor shape changes. */
12614 EMACS_TIME delay;
12615 int secs, usecs = 0;
12616
12617 cancel_hourglass ();
12618
12619 if (INTEGERP (Vhourglass_delay)
12620 && XINT (Vhourglass_delay) > 0)
12621 secs = XFASTINT (Vhourglass_delay);
12622 else if (FLOATP (Vhourglass_delay)
12623 && XFLOAT_DATA (Vhourglass_delay) > 0)
12624 {
12625 Lisp_Object tem;
12626 tem = Ftruncate (Vhourglass_delay, Qnil);
12627 secs = XFASTINT (tem);
12628 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
12629 }
12630 else
12631 secs = DEFAULT_HOURGLASS_DELAY;
12632
12633 EMACS_SET_SECS_USECS (delay, secs, usecs);
12634 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
12635 show_hourglass, NULL);
12636 #endif
12637 }
12638
12639
12640 /* Cancel the hourglass cursor timer if active, hide an hourglass
12641 cursor if shown. */
12642
12643 void
12644 cancel_hourglass ()
12645 {
12646 if (hourglass_atimer)
12647 {
12648 cancel_atimer (hourglass_atimer);
12649 hourglass_atimer = NULL;
12650 }
12651
12652 if (hourglass_shown_p)
12653 hide_hourglass ();
12654 }
12655
12656
12657 /* Timer function of hourglass_atimer. TIMER is equal to
12658 hourglass_atimer.
12659
12660 Display an hourglass cursor on all frames by mapping the frames'
12661 hourglass_window. Set the hourglass_p flag in the frames'
12662 output_data.x structure to indicate that an hourglass cursor is
12663 shown on the frames. */
12664
12665 static void
12666 show_hourglass (timer)
12667 struct atimer *timer;
12668 {
12669 #if 0 /* TODO: cursor shape changes. */
12670 /* The timer implementation will cancel this timer automatically
12671 after this function has run. Set hourglass_atimer to null
12672 so that we know the timer doesn't have to be canceled. */
12673 hourglass_atimer = NULL;
12674
12675 if (!hourglass_shown_p)
12676 {
12677 Lisp_Object rest, frame;
12678
12679 BLOCK_INPUT;
12680
12681 FOR_EACH_FRAME (rest, frame)
12682 if (FRAME_W32_P (XFRAME (frame)))
12683 {
12684 struct frame *f = XFRAME (frame);
12685
12686 f->output_data.w32->hourglass_p = 1;
12687
12688 if (!f->output_data.w32->hourglass_window)
12689 {
12690 unsigned long mask = CWCursor;
12691 XSetWindowAttributes attrs;
12692
12693 attrs.cursor = f->output_data.w32->hourglass_cursor;
12694
12695 f->output_data.w32->hourglass_window
12696 = XCreateWindow (FRAME_X_DISPLAY (f),
12697 FRAME_OUTER_WINDOW (f),
12698 0, 0, 32000, 32000, 0, 0,
12699 InputOnly,
12700 CopyFromParent,
12701 mask, &attrs);
12702 }
12703
12704 XMapRaised (FRAME_X_DISPLAY (f),
12705 f->output_data.w32->hourglass_window);
12706 XFlush (FRAME_X_DISPLAY (f));
12707 }
12708
12709 hourglass_shown_p = 1;
12710 UNBLOCK_INPUT;
12711 }
12712 #endif
12713 }
12714
12715
12716 /* Hide the hourglass cursor on all frames, if it is currently shown. */
12717
12718 static void
12719 hide_hourglass ()
12720 {
12721 #if 0 /* TODO: cursor shape changes. */
12722 if (hourglass_shown_p)
12723 {
12724 Lisp_Object rest, frame;
12725
12726 BLOCK_INPUT;
12727 FOR_EACH_FRAME (rest, frame)
12728 {
12729 struct frame *f = XFRAME (frame);
12730
12731 if (FRAME_W32_P (f)
12732 /* Watch out for newly created frames. */
12733 && f->output_data.x->hourglass_window)
12734 {
12735 XUnmapWindow (FRAME_X_DISPLAY (f),
12736 f->output_data.x->hourglass_window);
12737 /* Sync here because XTread_socket looks at the
12738 hourglass_p flag that is reset to zero below. */
12739 XSync (FRAME_X_DISPLAY (f), False);
12740 f->output_data.x->hourglass_p = 0;
12741 }
12742 }
12743
12744 hourglass_shown_p = 0;
12745 UNBLOCK_INPUT;
12746 }
12747 #endif
12748 }
12749
12750
12751 \f
12752 /***********************************************************************
12753 Tool tips
12754 ***********************************************************************/
12755
12756 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
12757 Lisp_Object, Lisp_Object));
12758 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
12759 Lisp_Object, int, int, int *, int *));
12760
12761 /* The frame of a currently visible tooltip. */
12762
12763 Lisp_Object tip_frame;
12764
12765 /* If non-nil, a timer started that hides the last tooltip when it
12766 fires. */
12767
12768 Lisp_Object tip_timer;
12769 Window tip_window;
12770
12771 /* If non-nil, a vector of 3 elements containing the last args
12772 with which x-show-tip was called. See there. */
12773
12774 Lisp_Object last_show_tip_args;
12775
12776 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
12777
12778 Lisp_Object Vx_max_tooltip_size;
12779
12780
12781 static Lisp_Object
12782 unwind_create_tip_frame (frame)
12783 Lisp_Object frame;
12784 {
12785 Lisp_Object deleted;
12786
12787 deleted = unwind_create_frame (frame);
12788 if (EQ (deleted, Qt))
12789 {
12790 tip_window = NULL;
12791 tip_frame = Qnil;
12792 }
12793
12794 return deleted;
12795 }
12796
12797
12798 /* Create a frame for a tooltip on the display described by DPYINFO.
12799 PARMS is a list of frame parameters. TEXT is the string to
12800 display in the tip frame. Value is the frame.
12801
12802 Note that functions called here, esp. x_default_parameter can
12803 signal errors, for instance when a specified color name is
12804 undefined. We have to make sure that we're in a consistent state
12805 when this happens. */
12806
12807 static Lisp_Object
12808 x_create_tip_frame (dpyinfo, parms, text)
12809 struct w32_display_info *dpyinfo;
12810 Lisp_Object parms, text;
12811 {
12812 #if 0 /* TODO : w32 version */
12813 struct frame *f;
12814 Lisp_Object frame, tem;
12815 Lisp_Object name;
12816 long window_prompting = 0;
12817 int width, height;
12818 int count = BINDING_STACK_SIZE ();
12819 struct gcpro gcpro1, gcpro2, gcpro3;
12820 struct kboard *kb;
12821 int face_change_count_before = face_change_count;
12822 Lisp_Object buffer;
12823 struct buffer *old_buffer;
12824
12825 check_x ();
12826
12827 /* Use this general default value to start with until we know if
12828 this frame has a specified name. */
12829 Vx_resource_name = Vinvocation_name;
12830
12831 #ifdef MULTI_KBOARD
12832 kb = dpyinfo->kboard;
12833 #else
12834 kb = &the_only_kboard;
12835 #endif
12836
12837 /* Get the name of the frame to use for resource lookup. */
12838 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
12839 if (!STRINGP (name)
12840 && !EQ (name, Qunbound)
12841 && !NILP (name))
12842 error ("Invalid frame name--not a string or nil");
12843 Vx_resource_name = name;
12844
12845 frame = Qnil;
12846 GCPRO3 (parms, name, frame);
12847 f = make_frame (1);
12848 XSETFRAME (frame, f);
12849
12850 buffer = Fget_buffer_create (build_string (" *tip*"));
12851 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
12852 old_buffer = current_buffer;
12853 set_buffer_internal_1 (XBUFFER (buffer));
12854 current_buffer->truncate_lines = Qnil;
12855 Ferase_buffer ();
12856 Finsert (1, &text);
12857 set_buffer_internal_1 (old_buffer);
12858
12859 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
12860 record_unwind_protect (unwind_create_tip_frame, frame);
12861
12862 /* By setting the output method, we're essentially saying that
12863 the frame is live, as per FRAME_LIVE_P. If we get a signal
12864 from this point on, x_destroy_window might screw up reference
12865 counts etc. */
12866 f->output_method = output_w32;
12867 f->output_data.w32 =
12868 (struct w32_output *) xmalloc (sizeof (struct w32_output));
12869 bzero (f->output_data.w32, sizeof (struct w32_output));
12870 #if 0
12871 f->output_data.w32->icon_bitmap = -1;
12872 #endif
12873 f->output_data.w32->fontset = -1;
12874 f->icon_name = Qnil;
12875
12876 #ifdef GLYPH_DEBUG
12877 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
12878 dpyinfo_refcount = dpyinfo->reference_count;
12879 #endif /* GLYPH_DEBUG */
12880 #ifdef MULTI_KBOARD
12881 FRAME_KBOARD (f) = kb;
12882 #endif
12883 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12884 f->output_data.w32->explicit_parent = 0;
12885
12886 /* Set the name; the functions to which we pass f expect the name to
12887 be set. */
12888 if (EQ (name, Qunbound) || NILP (name))
12889 {
12890 f->name = build_string (dpyinfo->x_id_name);
12891 f->explicit_name = 0;
12892 }
12893 else
12894 {
12895 f->name = name;
12896 f->explicit_name = 1;
12897 /* use the frame's title when getting resources for this frame. */
12898 specbind (Qx_resource_name, name);
12899 }
12900
12901 /* Extract the window parameters from the supplied values
12902 that are needed to determine window geometry. */
12903 {
12904 Lisp_Object font;
12905
12906 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
12907
12908 BLOCK_INPUT;
12909 /* First, try whatever font the caller has specified. */
12910 if (STRINGP (font))
12911 {
12912 tem = Fquery_fontset (font, Qnil);
12913 if (STRINGP (tem))
12914 font = x_new_fontset (f, XSTRING (tem)->data);
12915 else
12916 font = x_new_font (f, XSTRING (font)->data);
12917 }
12918
12919 /* Try out a font which we hope has bold and italic variations. */
12920 if (!STRINGP (font))
12921 font = x_new_font (f, "-*-courier new-normal-r-*-*-*-100-*-*-*-*-iso8859-1");
12922 if (!STRINGP (font))
12923 font = x_new_font (f, "-misc-fixed-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12924 if (! STRINGP (font))
12925 font = x_new_font (f, "-*-*-medium-r-normal-*-*-140-*-*-c-*-iso8859-1");
12926 if (! STRINGP (font))
12927 /* This was formerly the first thing tried, but it finds too many fonts
12928 and takes too long. */
12929 font = x_new_font (f, "-*-*-medium-r-*-*-*-*-*-*-c-*-iso8859-1");
12930 /* If those didn't work, look for something which will at least work. */
12931 if (! STRINGP (font))
12932 font = x_new_font (f, "-*-fixed-*-*-*-*-*-140-*-*-c-*-iso8859-1");
12933 UNBLOCK_INPUT;
12934 if (! STRINGP (font))
12935 font = build_string ("fixed");
12936
12937 x_default_parameter (f, parms, Qfont, font,
12938 "font", "Font", RES_TYPE_STRING);
12939 }
12940
12941 x_default_parameter (f, parms, Qborder_width, make_number (2),
12942 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
12943
12944 /* This defaults to 2 in order to match xterm. We recognize either
12945 internalBorderWidth or internalBorder (which is what xterm calls
12946 it). */
12947 if (NILP (Fassq (Qinternal_border_width, parms)))
12948 {
12949 Lisp_Object value;
12950
12951 value = w32_get_arg (parms, Qinternal_border_width,
12952 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
12953 if (! EQ (value, Qunbound))
12954 parms = Fcons (Fcons (Qinternal_border_width, value),
12955 parms);
12956 }
12957
12958 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
12959 "internalBorderWidth", "internalBorderWidth",
12960 RES_TYPE_NUMBER);
12961
12962 /* Also do the stuff which must be set before the window exists. */
12963 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
12964 "foreground", "Foreground", RES_TYPE_STRING);
12965 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
12966 "background", "Background", RES_TYPE_STRING);
12967 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
12968 "pointerColor", "Foreground", RES_TYPE_STRING);
12969 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
12970 "cursorColor", "Foreground", RES_TYPE_STRING);
12971 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
12972 "borderColor", "BorderColor", RES_TYPE_STRING);
12973
12974 /* Init faces before x_default_parameter is called for scroll-bar
12975 parameters because that function calls x_set_scroll_bar_width,
12976 which calls change_frame_size, which calls Fset_window_buffer,
12977 which runs hooks, which call Fvertical_motion. At the end, we
12978 end up in init_iterator with a null face cache, which should not
12979 happen. */
12980 init_frame_faces (f);
12981
12982 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
12983 window_prompting = x_figure_window_size (f, parms);
12984
12985 if (window_prompting & XNegative)
12986 {
12987 if (window_prompting & YNegative)
12988 f->output_data.w32->win_gravity = SouthEastGravity;
12989 else
12990 f->output_data.w32->win_gravity = NorthEastGravity;
12991 }
12992 else
12993 {
12994 if (window_prompting & YNegative)
12995 f->output_data.w32->win_gravity = SouthWestGravity;
12996 else
12997 f->output_data.w32->win_gravity = NorthWestGravity;
12998 }
12999
13000 f->output_data.w32->size_hint_flags = window_prompting;
13001 {
13002 XSetWindowAttributes attrs;
13003 unsigned long mask;
13004
13005 BLOCK_INPUT;
13006 mask = CWBackPixel | CWOverrideRedirect | CWEventMask;
13007 if (DoesSaveUnders (dpyinfo->screen))
13008 mask |= CWSaveUnder;
13009
13010 /* Window managers looks at the override-redirect flag to
13011 determine whether or net to give windows a decoration (Xlib
13012 3.2.8). */
13013 attrs.override_redirect = True;
13014 attrs.save_under = True;
13015 attrs.background_pixel = FRAME_BACKGROUND_PIXEL (f);
13016 /* Arrange for getting MapNotify and UnmapNotify events. */
13017 attrs.event_mask = StructureNotifyMask;
13018 tip_window
13019 = FRAME_W32_WINDOW (f)
13020 = XCreateWindow (FRAME_W32_DISPLAY (f),
13021 FRAME_W32_DISPLAY_INFO (f)->root_window,
13022 /* x, y, width, height */
13023 0, 0, 1, 1,
13024 /* Border. */
13025 1,
13026 CopyFromParent, InputOutput, CopyFromParent,
13027 mask, &attrs);
13028 UNBLOCK_INPUT;
13029 }
13030
13031 x_make_gc (f);
13032
13033 x_default_parameter (f, parms, Qauto_raise, Qnil,
13034 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13035 x_default_parameter (f, parms, Qauto_lower, Qnil,
13036 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13037 x_default_parameter (f, parms, Qcursor_type, Qbox,
13038 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13039
13040 /* Dimensions, especially f->height, must be done via change_frame_size.
13041 Change will not be effected unless different from the current
13042 f->height. */
13043 width = f->width;
13044 height = f->height;
13045 f->height = 0;
13046 SET_FRAME_WIDTH (f, 0);
13047 change_frame_size (f, height, width, 1, 0, 0);
13048
13049 /* Set up faces after all frame parameters are known. This call
13050 also merges in face attributes specified for new frames.
13051
13052 Frame parameters may be changed if .Xdefaults contains
13053 specifications for the default font. For example, if there is an
13054 `Emacs.default.attributeBackground: pink', the `background-color'
13055 attribute of the frame get's set, which let's the internal border
13056 of the tooltip frame appear in pink. Prevent this. */
13057 {
13058 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13059
13060 /* Set tip_frame here, so that */
13061 tip_frame = frame;
13062 call1 (Qface_set_after_frame_default, frame);
13063
13064 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13065 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13066 Qnil));
13067 }
13068
13069 f->no_split = 1;
13070
13071 UNGCPRO;
13072
13073 /* It is now ok to make the frame official even if we get an error
13074 below. And the frame needs to be on Vframe_list or making it
13075 visible won't work. */
13076 Vframe_list = Fcons (frame, Vframe_list);
13077
13078 /* Now that the frame is official, it counts as a reference to
13079 its display. */
13080 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13081
13082 /* Setting attributes of faces of the tooltip frame from resources
13083 and similar will increment face_change_count, which leads to the
13084 clearing of all current matrices. Since this isn't necessary
13085 here, avoid it by resetting face_change_count to the value it
13086 had before we created the tip frame. */
13087 face_change_count = face_change_count_before;
13088
13089 /* Discard the unwind_protect. */
13090 return unbind_to (count, frame);
13091 #endif /* TODO */
13092 return Qnil;
13093 }
13094
13095
13096 /* Compute where to display tip frame F. PARMS is the list of frame
13097 parameters for F. DX and DY are specified offsets from the current
13098 location of the mouse. WIDTH and HEIGHT are the width and height
13099 of the tooltip. Return coordinates relative to the root window of
13100 the display in *ROOT_X, and *ROOT_Y. */
13101
13102 static void
13103 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13104 struct frame *f;
13105 Lisp_Object parms, dx, dy;
13106 int width, height;
13107 int *root_x, *root_y;
13108 {
13109 #ifdef TODO /* Tool tips not supported. */
13110 Lisp_Object left, top;
13111 int win_x, win_y;
13112 Window root, child;
13113 unsigned pmask;
13114
13115 /* User-specified position? */
13116 left = Fcdr (Fassq (Qleft, parms));
13117 top = Fcdr (Fassq (Qtop, parms));
13118
13119 /* Move the tooltip window where the mouse pointer is. Resize and
13120 show it. */
13121 if (!INTEGERP (left) && !INTEGERP (top))
13122 {
13123 BLOCK_INPUT;
13124 XQueryPointer (FRAME_X_DISPLAY (f), FRAME_X_DISPLAY_INFO (f)->root_window,
13125 &root, &child, root_x, root_y, &win_x, &win_y, &pmask);
13126 UNBLOCK_INPUT;
13127 }
13128
13129 if (INTEGERP (top))
13130 *root_y = XINT (top);
13131 else if (*root_y + XINT (dy) - height < 0)
13132 *root_y -= XINT (dy);
13133 else
13134 {
13135 *root_y -= height;
13136 *root_y += XINT (dy);
13137 }
13138
13139 if (INTEGERP (left))
13140 *root_x = XINT (left);
13141 else if (*root_x + XINT (dx) + width > FRAME_X_DISPLAY_INFO (f)->width)
13142 *root_x -= width + XINT (dx);
13143 else
13144 *root_x += XINT (dx);
13145
13146 #endif /* Tooltip support. */
13147 }
13148
13149
13150 #ifdef TODO /* Tooltip support not complete. */
13151 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13152 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13153 A tooltip window is a small window displaying a string.
13154
13155 FRAME nil or omitted means use the selected frame.
13156
13157 PARMS is an optional list of frame parameters which can be
13158 used to change the tooltip's appearance.
13159
13160 Automatically hide the tooltip after TIMEOUT seconds.
13161 TIMEOUT nil means use the default timeout of 5 seconds.
13162
13163 If the list of frame parameters PARAMS contains a `left' parameters,
13164 the tooltip is displayed at that x-position. Otherwise it is
13165 displayed at the mouse position, with offset DX added (default is 5 if
13166 DX isn't specified). Likewise for the y-position; if a `top' frame
13167 parameter is specified, it determines the y-position of the tooltip
13168 window, otherwise it is displayed at the mouse position, with offset
13169 DY added (default is -10).
13170
13171 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13172 Text larger than the specified size is clipped. */)
13173 (string, frame, parms, timeout, dx, dy)
13174 Lisp_Object string, frame, parms, timeout, dx, dy;
13175 {
13176 struct frame *f;
13177 struct window *w;
13178 Lisp_Object buffer, top, left, max_width, max_height;
13179 int root_x, root_y;
13180 struct buffer *old_buffer;
13181 struct text_pos pos;
13182 int i, width, height;
13183 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13184 int old_windows_or_buffers_changed = windows_or_buffers_changed;
13185 int count = specpdl_ptr - specpdl;
13186
13187 specbind (Qinhibit_redisplay, Qt);
13188
13189 GCPRO4 (string, parms, frame, timeout);
13190
13191 CHECK_STRING (string);
13192 f = check_x_frame (frame);
13193 if (NILP (timeout))
13194 timeout = make_number (5);
13195 else
13196 CHECK_NATNUM (timeout);
13197
13198 if (NILP (dx))
13199 dx = make_number (5);
13200 else
13201 CHECK_NUMBER (dx);
13202
13203 if (NILP (dy))
13204 dy = make_number (-10);
13205 else
13206 CHECK_NUMBER (dy);
13207
13208 if (NILP (last_show_tip_args))
13209 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13210
13211 if (!NILP (tip_frame))
13212 {
13213 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13214 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13215 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13216
13217 if (EQ (frame, last_frame)
13218 && !NILP (Fequal (last_string, string))
13219 && !NILP (Fequal (last_parms, parms)))
13220 {
13221 struct frame *f = XFRAME (tip_frame);
13222
13223 /* Only DX and DY have changed. */
13224 if (!NILP (tip_timer))
13225 {
13226 Lisp_Object timer = tip_timer;
13227 tip_timer = Qnil;
13228 call1 (Qcancel_timer, timer);
13229 }
13230
13231 BLOCK_INPUT;
13232 compute_tip_xy (f, parms, dx, dy, &root_x, &root_y);
13233 XMoveWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
13234 root_x, root_y - PIXEL_HEIGHT (f));
13235 UNBLOCK_INPUT;
13236 goto start_timer;
13237 }
13238 }
13239
13240 /* Hide a previous tip, if any. */
13241 Fx_hide_tip ();
13242
13243 ASET (last_show_tip_args, 0, string);
13244 ASET (last_show_tip_args, 1, frame);
13245 ASET (last_show_tip_args, 2, parms);
13246
13247 /* Add default values to frame parameters. */
13248 if (NILP (Fassq (Qname, parms)))
13249 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13250 if (NILP (Fassq (Qinternal_border_width, parms)))
13251 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13252 if (NILP (Fassq (Qborder_width, parms)))
13253 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13254 if (NILP (Fassq (Qborder_color, parms)))
13255 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13256 if (NILP (Fassq (Qbackground_color, parms)))
13257 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13258 parms);
13259
13260 /* Create a frame for the tooltip, and record it in the global
13261 variable tip_frame. */
13262 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms);
13263 f = XFRAME (frame);
13264
13265 /* Set up the frame's root window. */
13266 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13267 w->left = w->top = make_number (0);
13268
13269 if (CONSP (Vx_max_tooltip_size)
13270 && INTEGERP (XCAR (Vx_max_tooltip_size))
13271 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13272 && INTEGERP (XCDR (Vx_max_tooltip_size))
13273 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13274 {
13275 w->width = XCAR (Vx_max_tooltip_size);
13276 w->height = XCDR (Vx_max_tooltip_size);
13277 }
13278 else
13279 {
13280 w->width = make_number (80);
13281 w->height = make_number (40);
13282 }
13283
13284 f->window_width = XINT (w->width);
13285 adjust_glyphs (f);
13286 w->pseudo_window_p = 1;
13287
13288 /* Display the tooltip text in a temporary buffer. */
13289 old_buffer = current_buffer;
13290 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13291 current_buffer->truncate_lines = Qnil;
13292 clear_glyph_matrix (w->desired_matrix);
13293 clear_glyph_matrix (w->current_matrix);
13294 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13295 try_window (FRAME_ROOT_WINDOW (f), pos);
13296
13297 /* Compute width and height of the tooltip. */
13298 width = height = 0;
13299 for (i = 0; i < w->desired_matrix->nrows; ++i)
13300 {
13301 struct glyph_row *row = &w->desired_matrix->rows[i];
13302 struct glyph *last;
13303 int row_width;
13304
13305 /* Stop at the first empty row at the end. */
13306 if (!row->enabled_p || !row->displays_text_p)
13307 break;
13308
13309 /* Let the row go over the full width of the frame. */
13310 row->full_width_p = 1;
13311
13312 /* There's a glyph at the end of rows that is use to place
13313 the cursor there. Don't include the width of this glyph. */
13314 if (row->used[TEXT_AREA])
13315 {
13316 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13317 row_width = row->pixel_width - last->pixel_width;
13318 }
13319 else
13320 row_width = row->pixel_width;
13321
13322 height += row->height;
13323 width = max (width, row_width);
13324 }
13325
13326 /* Add the frame's internal border to the width and height the X
13327 window should have. */
13328 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13329 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13330
13331 /* Move the tooltip window where the mouse pointer is. Resize and
13332 show it. */
13333 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
13334
13335 BLOCK_INPUT;
13336 XMoveResizeWindow (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f),
13337 root_x, root_y - height, width, height);
13338 XMapRaised (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f));
13339 UNBLOCK_INPUT;
13340
13341 /* Draw into the window. */
13342 w->must_be_updated_p = 1;
13343 update_single_window (w, 1);
13344
13345 /* Restore original current buffer. */
13346 set_buffer_internal_1 (old_buffer);
13347 windows_or_buffers_changed = old_windows_or_buffers_changed;
13348
13349 start_timer:
13350 /* Let the tip disappear after timeout seconds. */
13351 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13352 intern ("x-hide-tip"));
13353
13354 UNGCPRO;
13355 return unbind_to (count, Qnil);
13356 }
13357
13358
13359 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
13360 doc: /* Hide the current tooltip window, if there is any.
13361 Value is t if tooltip was open, nil otherwise. */)
13362 ()
13363 {
13364 int count;
13365 Lisp_Object deleted, frame, timer;
13366 struct gcpro gcpro1, gcpro2;
13367
13368 /* Return quickly if nothing to do. */
13369 if (NILP (tip_timer) && NILP (tip_frame))
13370 return Qnil;
13371
13372 frame = tip_frame;
13373 timer = tip_timer;
13374 GCPRO2 (frame, timer);
13375 tip_frame = tip_timer = deleted = Qnil;
13376
13377 count = BINDING_STACK_SIZE ();
13378 specbind (Qinhibit_redisplay, Qt);
13379 specbind (Qinhibit_quit, Qt);
13380
13381 if (!NILP (timer))
13382 call1 (Qcancel_timer, timer);
13383
13384 if (FRAMEP (frame))
13385 {
13386 Fdelete_frame (frame, Qnil);
13387 deleted = Qt;
13388 }
13389
13390 UNGCPRO;
13391 return unbind_to (count, deleted);
13392 }
13393 #endif
13394
13395
13396 \f
13397 /***********************************************************************
13398 File selection dialog
13399 ***********************************************************************/
13400
13401 extern Lisp_Object Qfile_name_history;
13402
13403 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
13404 doc: /* Read file name, prompting with PROMPT in directory DIR.
13405 Use a file selection dialog.
13406 Select DEFAULT-FILENAME in the dialog's file selection box, if
13407 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
13408 (prompt, dir, default_filename, mustmatch)
13409 Lisp_Object prompt, dir, default_filename, mustmatch;
13410 {
13411 struct frame *f = SELECTED_FRAME ();
13412 Lisp_Object file = Qnil;
13413 int count = specpdl_ptr - specpdl;
13414 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
13415 char filename[MAX_PATH + 1];
13416 char init_dir[MAX_PATH + 1];
13417 int use_dialog_p = 1;
13418
13419 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
13420 CHECK_STRING (prompt);
13421 CHECK_STRING (dir);
13422
13423 /* Create the dialog with PROMPT as title, using DIR as initial
13424 directory and using "*" as pattern. */
13425 dir = Fexpand_file_name (dir, Qnil);
13426 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
13427 init_dir[MAX_PATH] = '\0';
13428 unixtodos_filename (init_dir);
13429
13430 if (STRINGP (default_filename))
13431 {
13432 char *file_name_only;
13433 char *full_path_name = XSTRING (default_filename)->data;
13434
13435 unixtodos_filename (full_path_name);
13436
13437 file_name_only = strrchr (full_path_name, '\\');
13438 if (!file_name_only)
13439 file_name_only = full_path_name;
13440 else
13441 {
13442 file_name_only++;
13443
13444 /* If default_file_name is a directory, don't use the open
13445 file dialog, as it does not support selecting
13446 directories. */
13447 if (!(*file_name_only))
13448 use_dialog_p = 0;
13449 }
13450
13451 strncpy (filename, file_name_only, MAX_PATH);
13452 filename[MAX_PATH] = '\0';
13453 }
13454 else
13455 filename[0] = '\0';
13456
13457 if (use_dialog_p)
13458 {
13459 OPENFILENAME file_details;
13460
13461 /* Prevent redisplay. */
13462 specbind (Qinhibit_redisplay, Qt);
13463 BLOCK_INPUT;
13464
13465 bzero (&file_details, sizeof (file_details));
13466 file_details.lStructSize = sizeof (file_details);
13467 file_details.hwndOwner = FRAME_W32_WINDOW (f);
13468 /* Undocumented Bug in Common File Dialog:
13469 If a filter is not specified, shell links are not resolved. */
13470 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
13471 file_details.lpstrFile = filename;
13472 file_details.nMaxFile = sizeof (filename);
13473 file_details.lpstrInitialDir = init_dir;
13474 file_details.lpstrTitle = XSTRING (prompt)->data;
13475 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
13476
13477 if (!NILP (mustmatch))
13478 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
13479
13480 if (GetOpenFileName (&file_details))
13481 {
13482 dostounix_filename (filename);
13483 file = build_string (filename);
13484 }
13485 else
13486 file = Qnil;
13487
13488 UNBLOCK_INPUT;
13489 file = unbind_to (count, file);
13490 }
13491 /* Open File dialog will not allow folders to be selected, so resort
13492 to minibuffer completing reads for directories. */
13493 else
13494 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
13495 dir, mustmatch, dir, Qfile_name_history,
13496 default_filename, Qnil);
13497
13498 UNGCPRO;
13499
13500 /* Make "Cancel" equivalent to C-g. */
13501 if (NILP (file))
13502 Fsignal (Qquit, Qnil);
13503
13504 return unbind_to (count, file);
13505 }
13506
13507
13508 \f
13509 /***********************************************************************
13510 w32 specialized functions
13511 ***********************************************************************/
13512
13513 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 1, 0,
13514 doc: /* Select a font using the W32 font dialog.
13515 Returns an X font string corresponding to the selection. */)
13516 (frame)
13517 Lisp_Object frame;
13518 {
13519 FRAME_PTR f = check_x_frame (frame);
13520 CHOOSEFONT cf;
13521 LOGFONT lf;
13522 TEXTMETRIC tm;
13523 HDC hdc;
13524 HANDLE oldobj;
13525 char buf[100];
13526
13527 bzero (&cf, sizeof (cf));
13528 bzero (&lf, sizeof (lf));
13529
13530 cf.lStructSize = sizeof (cf);
13531 cf.hwndOwner = FRAME_W32_WINDOW (f);
13532 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS;
13533 cf.lpLogFont = &lf;
13534
13535 /* Initialize as much of the font details as we can from the current
13536 default font. */
13537 hdc = GetDC (FRAME_W32_WINDOW (f));
13538 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
13539 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
13540 if (GetTextMetrics (hdc, &tm))
13541 {
13542 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
13543 lf.lfWeight = tm.tmWeight;
13544 lf.lfItalic = tm.tmItalic;
13545 lf.lfUnderline = tm.tmUnderlined;
13546 lf.lfStrikeOut = tm.tmStruckOut;
13547 lf.lfCharSet = tm.tmCharSet;
13548 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
13549 }
13550 SelectObject (hdc, oldobj);
13551 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
13552
13553 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
13554 return Qnil;
13555
13556 return build_string (buf);
13557 }
13558
13559 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
13560 Sw32_send_sys_command, 1, 2, 0,
13561 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
13562 Some useful values for command are 0xf030 to maximise frame (0xf020
13563 to minimize), 0xf120 to restore frame to original size, and 0xf100
13564 to activate the menubar for keyboard access. 0xf140 activates the
13565 screen saver if defined.
13566
13567 If optional parameter FRAME is not specified, use selected frame. */)
13568 (command, frame)
13569 Lisp_Object command, frame;
13570 {
13571 FRAME_PTR f = check_x_frame (frame);
13572
13573 CHECK_NUMBER (command);
13574
13575 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
13576
13577 return Qnil;
13578 }
13579
13580 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
13581 doc: /* Get Windows to perform OPERATION on DOCUMENT.
13582 This is a wrapper around the ShellExecute system function, which
13583 invokes the application registered to handle OPERATION for DOCUMENT.
13584 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
13585 nil for the default action), and DOCUMENT is typically the name of a
13586 document file or URL, but can also be a program executable to run or
13587 a directory to open in the Windows Explorer.
13588
13589 If DOCUMENT is a program executable, PARAMETERS can be a string
13590 containing command line parameters, but otherwise should be nil.
13591
13592 SHOW-FLAG can be used to control whether the invoked application is hidden
13593 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
13594 otherwise it is an integer representing a ShowWindow flag:
13595
13596 0 - start hidden
13597 1 - start normally
13598 3 - start maximized
13599 6 - start minimized */)
13600 (operation, document, parameters, show_flag)
13601 Lisp_Object operation, document, parameters, show_flag;
13602 {
13603 Lisp_Object current_dir;
13604
13605 CHECK_STRING (document);
13606
13607 /* Encode filename and current directory. */
13608 current_dir = ENCODE_FILE (current_buffer->directory);
13609 document = ENCODE_FILE (document);
13610 if ((int) ShellExecute (NULL,
13611 (STRINGP (operation) ?
13612 XSTRING (operation)->data : NULL),
13613 XSTRING (document)->data,
13614 (STRINGP (parameters) ?
13615 XSTRING (parameters)->data : NULL),
13616 XSTRING (current_dir)->data,
13617 (INTEGERP (show_flag) ?
13618 XINT (show_flag) : SW_SHOWDEFAULT))
13619 > 32)
13620 return Qt;
13621 error ("ShellExecute failed: %s", w32_strerror (0));
13622 }
13623
13624 /* Lookup virtual keycode from string representing the name of a
13625 non-ascii keystroke into the corresponding virtual key, using
13626 lispy_function_keys. */
13627 static int
13628 lookup_vk_code (char *key)
13629 {
13630 int i;
13631
13632 for (i = 0; i < 256; i++)
13633 if (lispy_function_keys[i] != 0
13634 && strcmp (lispy_function_keys[i], key) == 0)
13635 return i;
13636
13637 return -1;
13638 }
13639
13640 /* Convert a one-element vector style key sequence to a hot key
13641 definition. */
13642 static int
13643 w32_parse_hot_key (key)
13644 Lisp_Object key;
13645 {
13646 /* Copied from Fdefine_key and store_in_keymap. */
13647 register Lisp_Object c;
13648 int vk_code;
13649 int lisp_modifiers;
13650 int w32_modifiers;
13651 struct gcpro gcpro1;
13652
13653 CHECK_VECTOR (key);
13654
13655 if (XFASTINT (Flength (key)) != 1)
13656 return Qnil;
13657
13658 GCPRO1 (key);
13659
13660 c = Faref (key, make_number (0));
13661
13662 if (CONSP (c) && lucid_event_type_list_p (c))
13663 c = Fevent_convert_list (c);
13664
13665 UNGCPRO;
13666
13667 if (! INTEGERP (c) && ! SYMBOLP (c))
13668 error ("Key definition is invalid");
13669
13670 /* Work out the base key and the modifiers. */
13671 if (SYMBOLP (c))
13672 {
13673 c = parse_modifiers (c);
13674 lisp_modifiers = Fcar (Fcdr (c));
13675 c = Fcar (c);
13676 if (!SYMBOLP (c))
13677 abort ();
13678 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
13679 }
13680 else if (INTEGERP (c))
13681 {
13682 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
13683 /* Many ascii characters are their own virtual key code. */
13684 vk_code = XINT (c) & CHARACTERBITS;
13685 }
13686
13687 if (vk_code < 0 || vk_code > 255)
13688 return Qnil;
13689
13690 if ((lisp_modifiers & meta_modifier) != 0
13691 && !NILP (Vw32_alt_is_meta))
13692 lisp_modifiers |= alt_modifier;
13693
13694 /* Supply defs missing from mingw32. */
13695 #ifndef MOD_ALT
13696 #define MOD_ALT 0x0001
13697 #define MOD_CONTROL 0x0002
13698 #define MOD_SHIFT 0x0004
13699 #define MOD_WIN 0x0008
13700 #endif
13701
13702 /* Convert lisp modifiers to Windows hot-key form. */
13703 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
13704 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
13705 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
13706 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
13707
13708 return HOTKEY (vk_code, w32_modifiers);
13709 }
13710
13711 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
13712 Sw32_register_hot_key, 1, 1, 0,
13713 doc: /* Register KEY as a hot-key combination.
13714 Certain key combinations like Alt-Tab are reserved for system use on
13715 Windows, and therefore are normally intercepted by the system. However,
13716 most of these key combinations can be received by registering them as
13717 hot-keys, overriding their special meaning.
13718
13719 KEY must be a one element key definition in vector form that would be
13720 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
13721 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
13722 is always interpreted as the Windows modifier keys.
13723
13724 The return value is the hotkey-id if registered, otherwise nil. */)
13725 (key)
13726 Lisp_Object key;
13727 {
13728 key = w32_parse_hot_key (key);
13729
13730 if (NILP (Fmemq (key, w32_grabbed_keys)))
13731 {
13732 /* Reuse an empty slot if possible. */
13733 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
13734
13735 /* Safe to add new key to list, even if we have focus. */
13736 if (NILP (item))
13737 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
13738 else
13739 XSETCAR (item, key);
13740
13741 /* Notify input thread about new hot-key definition, so that it
13742 takes effect without needing to switch focus. */
13743 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
13744 (WPARAM) key, 0);
13745 }
13746
13747 return key;
13748 }
13749
13750 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
13751 Sw32_unregister_hot_key, 1, 1, 0,
13752 doc: /* Unregister HOTKEY as a hot-key combination. */)
13753 (key)
13754 Lisp_Object key;
13755 {
13756 Lisp_Object item;
13757
13758 if (!INTEGERP (key))
13759 key = w32_parse_hot_key (key);
13760
13761 item = Fmemq (key, w32_grabbed_keys);
13762
13763 if (!NILP (item))
13764 {
13765 /* Notify input thread about hot-key definition being removed, so
13766 that it takes effect without needing focus switch. */
13767 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
13768 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
13769 {
13770 MSG msg;
13771 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13772 }
13773 return Qt;
13774 }
13775 return Qnil;
13776 }
13777
13778 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
13779 Sw32_registered_hot_keys, 0, 0, 0,
13780 doc: /* Return list of registered hot-key IDs. */)
13781 ()
13782 {
13783 return Fcopy_sequence (w32_grabbed_keys);
13784 }
13785
13786 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
13787 Sw32_reconstruct_hot_key, 1, 1, 0,
13788 doc: /* Convert hot-key ID to a lisp key combination. */)
13789 (hotkeyid)
13790 Lisp_Object hotkeyid;
13791 {
13792 int vk_code, w32_modifiers;
13793 Lisp_Object key;
13794
13795 CHECK_NUMBER (hotkeyid);
13796
13797 vk_code = HOTKEY_VK_CODE (hotkeyid);
13798 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
13799
13800 if (lispy_function_keys[vk_code])
13801 key = intern (lispy_function_keys[vk_code]);
13802 else
13803 key = make_number (vk_code);
13804
13805 key = Fcons (key, Qnil);
13806 if (w32_modifiers & MOD_SHIFT)
13807 key = Fcons (Qshift, key);
13808 if (w32_modifiers & MOD_CONTROL)
13809 key = Fcons (Qctrl, key);
13810 if (w32_modifiers & MOD_ALT)
13811 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
13812 if (w32_modifiers & MOD_WIN)
13813 key = Fcons (Qhyper, key);
13814
13815 return key;
13816 }
13817
13818 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
13819 Sw32_toggle_lock_key, 1, 2, 0,
13820 doc: /* Toggle the state of the lock key KEY.
13821 KEY can be `capslock', `kp-numlock', or `scroll'.
13822 If the optional parameter NEW-STATE is a number, then the state of KEY
13823 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
13824 (key, new_state)
13825 Lisp_Object key, new_state;
13826 {
13827 int vk_code;
13828
13829 if (EQ (key, intern ("capslock")))
13830 vk_code = VK_CAPITAL;
13831 else if (EQ (key, intern ("kp-numlock")))
13832 vk_code = VK_NUMLOCK;
13833 else if (EQ (key, intern ("scroll")))
13834 vk_code = VK_SCROLL;
13835 else
13836 return Qnil;
13837
13838 if (!dwWindowsThreadId)
13839 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
13840
13841 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
13842 (WPARAM) vk_code, (LPARAM) new_state))
13843 {
13844 MSG msg;
13845 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
13846 return make_number (msg.wParam);
13847 }
13848 return Qnil;
13849 }
13850 \f
13851 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
13852 doc: /* Return storage information about the file system FILENAME is on.
13853 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
13854 storage of the file system, FREE is the free storage, and AVAIL is the
13855 storage available to a non-superuser. All 3 numbers are in bytes.
13856 If the underlying system call fails, value is nil. */)
13857 (filename)
13858 Lisp_Object filename;
13859 {
13860 Lisp_Object encoded, value;
13861
13862 CHECK_STRING (filename);
13863 filename = Fexpand_file_name (filename, Qnil);
13864 encoded = ENCODE_FILE (filename);
13865
13866 value = Qnil;
13867
13868 /* Determining the required information on Windows turns out, sadly,
13869 to be more involved than one would hope. The original Win32 api
13870 call for this will return bogus information on some systems, but we
13871 must dynamically probe for the replacement api, since that was
13872 added rather late on. */
13873 {
13874 HMODULE hKernel = GetModuleHandle ("kernel32");
13875 BOOL (*pfn_GetDiskFreeSpaceEx)
13876 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
13877 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
13878
13879 /* On Windows, we may need to specify the root directory of the
13880 volume holding FILENAME. */
13881 char rootname[MAX_PATH];
13882 char *name = XSTRING (encoded)->data;
13883
13884 /* find the root name of the volume if given */
13885 if (isalpha (name[0]) && name[1] == ':')
13886 {
13887 rootname[0] = name[0];
13888 rootname[1] = name[1];
13889 rootname[2] = '\\';
13890 rootname[3] = 0;
13891 }
13892 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
13893 {
13894 char *str = rootname;
13895 int slashes = 4;
13896 do
13897 {
13898 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
13899 break;
13900 *str++ = *name++;
13901 }
13902 while ( *name );
13903
13904 *str++ = '\\';
13905 *str = 0;
13906 }
13907
13908 if (pfn_GetDiskFreeSpaceEx)
13909 {
13910 LARGE_INTEGER availbytes;
13911 LARGE_INTEGER freebytes;
13912 LARGE_INTEGER totalbytes;
13913
13914 if (pfn_GetDiskFreeSpaceEx(rootname,
13915 &availbytes,
13916 &totalbytes,
13917 &freebytes))
13918 value = list3 (make_float ((double) totalbytes.QuadPart),
13919 make_float ((double) freebytes.QuadPart),
13920 make_float ((double) availbytes.QuadPart));
13921 }
13922 else
13923 {
13924 DWORD sectors_per_cluster;
13925 DWORD bytes_per_sector;
13926 DWORD free_clusters;
13927 DWORD total_clusters;
13928
13929 if (GetDiskFreeSpace(rootname,
13930 &sectors_per_cluster,
13931 &bytes_per_sector,
13932 &free_clusters,
13933 &total_clusters))
13934 value = list3 (make_float ((double) total_clusters
13935 * sectors_per_cluster * bytes_per_sector),
13936 make_float ((double) free_clusters
13937 * sectors_per_cluster * bytes_per_sector),
13938 make_float ((double) free_clusters
13939 * sectors_per_cluster * bytes_per_sector));
13940 }
13941 }
13942
13943 return value;
13944 }
13945 \f
13946 syms_of_w32fns ()
13947 {
13948 /* This is zero if not using MS-Windows. */
13949 w32_in_use = 0;
13950
13951 /* The section below is built by the lisp expression at the top of the file,
13952 just above where these variables are declared. */
13953 /*&&& init symbols here &&&*/
13954 Qauto_raise = intern ("auto-raise");
13955 staticpro (&Qauto_raise);
13956 Qauto_lower = intern ("auto-lower");
13957 staticpro (&Qauto_lower);
13958 Qbar = intern ("bar");
13959 staticpro (&Qbar);
13960 Qborder_color = intern ("border-color");
13961 staticpro (&Qborder_color);
13962 Qborder_width = intern ("border-width");
13963 staticpro (&Qborder_width);
13964 Qbox = intern ("box");
13965 staticpro (&Qbox);
13966 Qcursor_color = intern ("cursor-color");
13967 staticpro (&Qcursor_color);
13968 Qcursor_type = intern ("cursor-type");
13969 staticpro (&Qcursor_type);
13970 Qgeometry = intern ("geometry");
13971 staticpro (&Qgeometry);
13972 Qicon_left = intern ("icon-left");
13973 staticpro (&Qicon_left);
13974 Qicon_top = intern ("icon-top");
13975 staticpro (&Qicon_top);
13976 Qicon_type = intern ("icon-type");
13977 staticpro (&Qicon_type);
13978 Qicon_name = intern ("icon-name");
13979 staticpro (&Qicon_name);
13980 Qinternal_border_width = intern ("internal-border-width");
13981 staticpro (&Qinternal_border_width);
13982 Qleft = intern ("left");
13983 staticpro (&Qleft);
13984 Qright = intern ("right");
13985 staticpro (&Qright);
13986 Qmouse_color = intern ("mouse-color");
13987 staticpro (&Qmouse_color);
13988 Qnone = intern ("none");
13989 staticpro (&Qnone);
13990 Qparent_id = intern ("parent-id");
13991 staticpro (&Qparent_id);
13992 Qscroll_bar_width = intern ("scroll-bar-width");
13993 staticpro (&Qscroll_bar_width);
13994 Qsuppress_icon = intern ("suppress-icon");
13995 staticpro (&Qsuppress_icon);
13996 Qundefined_color = intern ("undefined-color");
13997 staticpro (&Qundefined_color);
13998 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
13999 staticpro (&Qvertical_scroll_bars);
14000 Qvisibility = intern ("visibility");
14001 staticpro (&Qvisibility);
14002 Qwindow_id = intern ("window-id");
14003 staticpro (&Qwindow_id);
14004 Qx_frame_parameter = intern ("x-frame-parameter");
14005 staticpro (&Qx_frame_parameter);
14006 Qx_resource_name = intern ("x-resource-name");
14007 staticpro (&Qx_resource_name);
14008 Quser_position = intern ("user-position");
14009 staticpro (&Quser_position);
14010 Quser_size = intern ("user-size");
14011 staticpro (&Quser_size);
14012 Qscreen_gamma = intern ("screen-gamma");
14013 staticpro (&Qscreen_gamma);
14014 Qline_spacing = intern ("line-spacing");
14015 staticpro (&Qline_spacing);
14016 Qcenter = intern ("center");
14017 staticpro (&Qcenter);
14018 Qcancel_timer = intern ("cancel-timer");
14019 staticpro (&Qcancel_timer);
14020 /* This is the end of symbol initialization. */
14021
14022 Qhyper = intern ("hyper");
14023 staticpro (&Qhyper);
14024 Qsuper = intern ("super");
14025 staticpro (&Qsuper);
14026 Qmeta = intern ("meta");
14027 staticpro (&Qmeta);
14028 Qalt = intern ("alt");
14029 staticpro (&Qalt);
14030 Qctrl = intern ("ctrl");
14031 staticpro (&Qctrl);
14032 Qcontrol = intern ("control");
14033 staticpro (&Qcontrol);
14034 Qshift = intern ("shift");
14035 staticpro (&Qshift);
14036
14037 /* Text property `display' should be nonsticky by default. */
14038 Vtext_property_default_nonsticky
14039 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14040
14041
14042 Qlaplace = intern ("laplace");
14043 staticpro (&Qlaplace);
14044 Qemboss = intern ("emboss");
14045 staticpro (&Qemboss);
14046 Qedge_detection = intern ("edge-detection");
14047 staticpro (&Qedge_detection);
14048 Qheuristic = intern ("heuristic");
14049 staticpro (&Qheuristic);
14050 QCmatrix = intern (":matrix");
14051 staticpro (&QCmatrix);
14052 QCcolor_adjustment = intern (":color-adjustment");
14053 staticpro (&QCcolor_adjustment);
14054 QCmask = intern (":mask");
14055 staticpro (&QCmask);
14056
14057 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14058 staticpro (&Qface_set_after_frame_default);
14059
14060 Fput (Qundefined_color, Qerror_conditions,
14061 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14062 Fput (Qundefined_color, Qerror_message,
14063 build_string ("Undefined color"));
14064
14065 staticpro (&w32_grabbed_keys);
14066 w32_grabbed_keys = Qnil;
14067
14068 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14069 doc: /* An array of color name mappings for windows. */);
14070 Vw32_color_map = Qnil;
14071
14072 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14073 doc: /* Non-nil if alt key presses are passed on to Windows.
14074 When non-nil, for example, alt pressed and released and then space will
14075 open the System menu. When nil, Emacs silently swallows alt key events. */);
14076 Vw32_pass_alt_to_system = Qnil;
14077
14078 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
14079 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14080 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
14081 Vw32_alt_is_meta = Qt;
14082
14083 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
14084 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
14085 XSETINT (Vw32_quit_key, 0);
14086
14087 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14088 &Vw32_pass_lwindow_to_system,
14089 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14090 When non-nil, the Start menu is opened by tapping the key. */);
14091 Vw32_pass_lwindow_to_system = Qt;
14092
14093 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14094 &Vw32_pass_rwindow_to_system,
14095 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14096 When non-nil, the Start menu is opened by tapping the key. */);
14097 Vw32_pass_rwindow_to_system = Qt;
14098
14099 DEFVAR_INT ("w32-phantom-key-code",
14100 &Vw32_phantom_key_code,
14101 doc: /* Virtual key code used to generate \"phantom\" key presses.
14102 Value is a number between 0 and 255.
14103
14104 Phantom key presses are generated in order to stop the system from
14105 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14106 `w32-pass-rwindow-to-system' is nil. */);
14107 /* Although 255 is technically not a valid key code, it works and
14108 means that this hack won't interfere with any real key code. */
14109 Vw32_phantom_key_code = 255;
14110
14111 DEFVAR_LISP ("w32-enable-num-lock",
14112 &Vw32_enable_num_lock,
14113 doc: /* Non-nil if Num Lock should act normally.
14114 Set to nil to see Num Lock as the key `kp-numlock'. */);
14115 Vw32_enable_num_lock = Qt;
14116
14117 DEFVAR_LISP ("w32-enable-caps-lock",
14118 &Vw32_enable_caps_lock,
14119 doc: /* Non-nil if Caps Lock should act normally.
14120 Set to nil to see Caps Lock as the key `capslock'. */);
14121 Vw32_enable_caps_lock = Qt;
14122
14123 DEFVAR_LISP ("w32-scroll-lock-modifier",
14124 &Vw32_scroll_lock_modifier,
14125 doc: /* Modifier to use for the Scroll Lock on state.
14126 The value can be hyper, super, meta, alt, control or shift for the
14127 respective modifier, or nil to see Scroll Lock as the key `scroll'.
14128 Any other value will cause the key to be ignored. */);
14129 Vw32_scroll_lock_modifier = Qt;
14130
14131 DEFVAR_LISP ("w32-lwindow-modifier",
14132 &Vw32_lwindow_modifier,
14133 doc: /* Modifier to use for the left \"Windows\" key.
14134 The value can be hyper, super, meta, alt, control or shift for the
14135 respective modifier, or nil to appear as the key `lwindow'.
14136 Any other value will cause the key to be ignored. */);
14137 Vw32_lwindow_modifier = Qnil;
14138
14139 DEFVAR_LISP ("w32-rwindow-modifier",
14140 &Vw32_rwindow_modifier,
14141 doc: /* Modifier to use for the right \"Windows\" key.
14142 The value can be hyper, super, meta, alt, control or shift for the
14143 respective modifier, or nil to appear as the key `rwindow'.
14144 Any other value will cause the key to be ignored. */);
14145 Vw32_rwindow_modifier = Qnil;
14146
14147 DEFVAR_LISP ("w32-apps-modifier",
14148 &Vw32_apps_modifier,
14149 doc: /* Modifier to use for the \"Apps\" key.
14150 The value can be hyper, super, meta, alt, control or shift for the
14151 respective modifier, or nil to appear as the key `apps'.
14152 Any other value will cause the key to be ignored. */);
14153 Vw32_apps_modifier = Qnil;
14154
14155 DEFVAR_LISP ("w32-enable-synthesized-fonts", &Vw32_enable_synthesized_fonts,
14156 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
14157 Vw32_enable_synthesized_fonts = Qnil;
14158
14159 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
14160 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
14161 Vw32_enable_palette = Qt;
14162
14163 DEFVAR_INT ("w32-mouse-button-tolerance",
14164 &Vw32_mouse_button_tolerance,
14165 doc: /* Analogue of double click interval for faking middle mouse events.
14166 The value is the minimum time in milliseconds that must elapse between
14167 left/right button down events before they are considered distinct events.
14168 If both mouse buttons are depressed within this interval, a middle mouse
14169 button down event is generated instead. */);
14170 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
14171
14172 DEFVAR_INT ("w32-mouse-move-interval",
14173 &Vw32_mouse_move_interval,
14174 doc: /* Minimum interval between mouse move events.
14175 The value is the minimum time in milliseconds that must elapse between
14176 successive mouse move (or scroll bar drag) events before they are
14177 reported as lisp events. */);
14178 XSETINT (Vw32_mouse_move_interval, 0);
14179
14180 init_x_parm_symbols ();
14181
14182 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
14183 doc: /* List of directories to search for bitmap files for w32. */);
14184 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14185
14186 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
14187 doc: /* The shape of the pointer when over text.
14188 Changing the value does not affect existing frames
14189 unless you set the mouse color. */);
14190 Vx_pointer_shape = Qnil;
14191
14192 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
14193 doc: /* The name Emacs uses to look up resources; for internal use only.
14194 `x-get-resource' uses this as the first component of the instance name
14195 when requesting resource values.
14196 Emacs initially sets `x-resource-name' to the name under which Emacs
14197 was invoked, or to the value specified with the `-name' or `-rn'
14198 switches, if present. */);
14199 Vx_resource_name = Qnil;
14200
14201 Vx_nontext_pointer_shape = Qnil;
14202
14203 Vx_mode_pointer_shape = Qnil;
14204
14205 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
14206 doc: /* The shape of the pointer when Emacs is busy.
14207 This variable takes effect when you create a new frame
14208 or when you set the mouse color. */);
14209 Vx_hourglass_pointer_shape = Qnil;
14210
14211 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
14212 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
14213 display_hourglass_p = 1;
14214
14215 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
14216 doc: /* *Seconds to wait before displaying an hourglass pointer.
14217 Value must be an integer or float. */);
14218 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
14219
14220 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
14221 &Vx_sensitive_text_pointer_shape,
14222 doc: /* The shape of the pointer when over mouse-sensitive text.
14223 This variable takes effect when you create a new frame
14224 or when you set the mouse color. */);
14225 Vx_sensitive_text_pointer_shape = Qnil;
14226
14227 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14228 &Vx_window_horizontal_drag_shape,
14229 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14230 This variable takes effect when you create a new frame
14231 or when you set the mouse color. */);
14232 Vx_window_horizontal_drag_shape = Qnil;
14233
14234 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
14235 doc: /* A string indicating the foreground color of the cursor box. */);
14236 Vx_cursor_fore_pixel = Qnil;
14237
14238 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
14239 doc: /* Maximum size for tooltips.
14240 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
14241 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14242
14243 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
14244 doc: /* Non-nil if no window manager is in use.
14245 Emacs doesn't try to figure this out; this is always nil
14246 unless you set it to something else. */);
14247 /* We don't have any way to find this out, so set it to nil
14248 and maybe the user would like to set it to t. */
14249 Vx_no_window_manager = Qnil;
14250
14251 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14252 &Vx_pixel_size_width_font_regexp,
14253 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14254
14255 Since Emacs gets width of a font matching with this regexp from
14256 PIXEL_SIZE field of the name, font finding mechanism gets faster for
14257 such a font. This is especially effective for such large fonts as
14258 Chinese, Japanese, and Korean. */);
14259 Vx_pixel_size_width_font_regexp = Qnil;
14260
14261 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
14262 doc: /* Time after which cached images are removed from the cache.
14263 When an image has not been displayed this many seconds, remove it
14264 from the image cache. Value must be an integer or nil with nil
14265 meaning don't clear the cache. */);
14266 Vimage_cache_eviction_delay = make_number (30 * 60);
14267
14268 DEFVAR_LISP ("w32-bdf-filename-alist",
14269 &Vw32_bdf_filename_alist,
14270 doc: /* List of bdf fonts and their corresponding filenames. */);
14271 Vw32_bdf_filename_alist = Qnil;
14272
14273 DEFVAR_BOOL ("w32-strict-fontnames",
14274 &w32_strict_fontnames,
14275 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14276 Default is nil, which allows old fontnames that are not XLFD compliant,
14277 and allows third-party CJK display to work by specifying false charset
14278 fields to trick Emacs into translating to Big5, SJIS etc.
14279 Setting this to t will prevent wrong fonts being selected when
14280 fontsets are automatically created. */);
14281 w32_strict_fontnames = 0;
14282
14283 DEFVAR_BOOL ("w32-strict-painting",
14284 &w32_strict_painting,
14285 doc: /* Non-nil means use strict rules for repainting frames.
14286 Set this to nil to get the old behaviour for repainting; this should
14287 only be necessary if the default setting causes problems. */);
14288 w32_strict_painting = 1;
14289
14290 DEFVAR_LISP ("w32-system-coding-system",
14291 &Vw32_system_coding_system,
14292 doc: /* Coding system used by Windows system functions, such as for font names. */);
14293 Vw32_system_coding_system = Qnil;
14294
14295 DEFVAR_LISP ("w32-charset-info-alist",
14296 &Vw32_charset_info_alist,
14297 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14298 Each entry should be of the form:
14299
14300 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14301
14302 where CHARSET_NAME is a string used in font names to identify the charset,
14303 WINDOWS_CHARSET is a symbol that can be one of:
14304 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14305 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14306 w32-charset-chinesebig5,
14307 #ifdef JOHAB_CHARSET
14308 w32-charset-johab, w32-charset-hebrew,
14309 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14310 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14311 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
14312 #endif
14313 #ifdef UNICODE_CHARSET
14314 w32-charset-unicode,
14315 #endif
14316 or w32-charset-oem.
14317 CODEPAGE should be an integer specifying the codepage that should be used
14318 to display the character set, t to do no translation and output as Unicode,
14319 or nil to do no translation and output as 8 bit (or multibyte on far-east
14320 versions of Windows) characters. */);
14321 Vw32_charset_info_alist = Qnil;
14322
14323 staticpro (&Qw32_charset_ansi);
14324 Qw32_charset_ansi = intern ("w32-charset-ansi");
14325 staticpro (&Qw32_charset_symbol);
14326 Qw32_charset_symbol = intern ("w32-charset-symbol");
14327 staticpro (&Qw32_charset_shiftjis);
14328 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
14329 staticpro (&Qw32_charset_hangeul);
14330 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
14331 staticpro (&Qw32_charset_chinesebig5);
14332 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
14333 staticpro (&Qw32_charset_gb2312);
14334 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
14335 staticpro (&Qw32_charset_oem);
14336 Qw32_charset_oem = intern ("w32-charset-oem");
14337
14338 #ifdef JOHAB_CHARSET
14339 {
14340 static int w32_extra_charsets_defined = 1;
14341 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
14342 doc: /* Internal variable. */);
14343
14344 staticpro (&Qw32_charset_johab);
14345 Qw32_charset_johab = intern ("w32-charset-johab");
14346 staticpro (&Qw32_charset_easteurope);
14347 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
14348 staticpro (&Qw32_charset_turkish);
14349 Qw32_charset_turkish = intern ("w32-charset-turkish");
14350 staticpro (&Qw32_charset_baltic);
14351 Qw32_charset_baltic = intern ("w32-charset-baltic");
14352 staticpro (&Qw32_charset_russian);
14353 Qw32_charset_russian = intern ("w32-charset-russian");
14354 staticpro (&Qw32_charset_arabic);
14355 Qw32_charset_arabic = intern ("w32-charset-arabic");
14356 staticpro (&Qw32_charset_greek);
14357 Qw32_charset_greek = intern ("w32-charset-greek");
14358 staticpro (&Qw32_charset_hebrew);
14359 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
14360 staticpro (&Qw32_charset_vietnamese);
14361 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
14362 staticpro (&Qw32_charset_thai);
14363 Qw32_charset_thai = intern ("w32-charset-thai");
14364 staticpro (&Qw32_charset_mac);
14365 Qw32_charset_mac = intern ("w32-charset-mac");
14366 }
14367 #endif
14368
14369 #ifdef UNICODE_CHARSET
14370 {
14371 static int w32_unicode_charset_defined = 1;
14372 DEFVAR_BOOL ("w32-unicode-charset-defined",
14373 &w32_unicode_charset_defined,
14374 doc: /* Internal variable. */);
14375
14376 staticpro (&Qw32_charset_unicode);
14377 Qw32_charset_unicode = intern ("w32-charset-unicode");
14378 #endif
14379
14380 defsubr (&Sx_get_resource);
14381 #if 0 /* TODO: Port to W32 */
14382 defsubr (&Sx_change_window_property);
14383 defsubr (&Sx_delete_window_property);
14384 defsubr (&Sx_window_property);
14385 #endif
14386 defsubr (&Sxw_display_color_p);
14387 defsubr (&Sx_display_grayscale_p);
14388 defsubr (&Sxw_color_defined_p);
14389 defsubr (&Sxw_color_values);
14390 defsubr (&Sx_server_max_request_size);
14391 defsubr (&Sx_server_vendor);
14392 defsubr (&Sx_server_version);
14393 defsubr (&Sx_display_pixel_width);
14394 defsubr (&Sx_display_pixel_height);
14395 defsubr (&Sx_display_mm_width);
14396 defsubr (&Sx_display_mm_height);
14397 defsubr (&Sx_display_screens);
14398 defsubr (&Sx_display_planes);
14399 defsubr (&Sx_display_color_cells);
14400 defsubr (&Sx_display_visual_class);
14401 defsubr (&Sx_display_backing_store);
14402 defsubr (&Sx_display_save_under);
14403 defsubr (&Sx_parse_geometry);
14404 defsubr (&Sx_create_frame);
14405 defsubr (&Sx_open_connection);
14406 defsubr (&Sx_close_connection);
14407 defsubr (&Sx_display_list);
14408 defsubr (&Sx_synchronize);
14409
14410 /* W32 specific functions */
14411
14412 defsubr (&Sw32_focus_frame);
14413 defsubr (&Sw32_select_font);
14414 defsubr (&Sw32_define_rgb_color);
14415 defsubr (&Sw32_default_color_map);
14416 defsubr (&Sw32_load_color_file);
14417 defsubr (&Sw32_send_sys_command);
14418 defsubr (&Sw32_shell_execute);
14419 defsubr (&Sw32_register_hot_key);
14420 defsubr (&Sw32_unregister_hot_key);
14421 defsubr (&Sw32_registered_hot_keys);
14422 defsubr (&Sw32_reconstruct_hot_key);
14423 defsubr (&Sw32_toggle_lock_key);
14424 defsubr (&Sw32_find_bdf_fonts);
14425
14426 defsubr (&Sfile_system_info);
14427
14428 /* Setting callback functions for fontset handler. */
14429 get_font_info_func = w32_get_font_info;
14430
14431 #if 0 /* This function pointer doesn't seem to be used anywhere.
14432 And the pointer assigned has the wrong type, anyway. */
14433 list_fonts_func = w32_list_fonts;
14434 #endif
14435
14436 load_font_func = w32_load_font;
14437 find_ccl_program_func = w32_find_ccl_program;
14438 query_font_func = w32_query_font;
14439 set_frame_fontset_func = x_set_font;
14440 check_window_system_func = check_w32;
14441
14442 #if 0 /* TODO Image support for W32 */
14443 /* Images. */
14444 Qxbm = intern ("xbm");
14445 staticpro (&Qxbm);
14446 QCtype = intern (":type");
14447 staticpro (&QCtype);
14448 QCconversion = intern (":conversion");
14449 staticpro (&QCconversion);
14450 QCheuristic_mask = intern (":heuristic-mask");
14451 staticpro (&QCheuristic_mask);
14452 QCcolor_symbols = intern (":color-symbols");
14453 staticpro (&QCcolor_symbols);
14454 QCascent = intern (":ascent");
14455 staticpro (&QCascent);
14456 QCmargin = intern (":margin");
14457 staticpro (&QCmargin);
14458 QCrelief = intern (":relief");
14459 staticpro (&QCrelief);
14460 Qpostscript = intern ("postscript");
14461 staticpro (&Qpostscript);
14462 QCloader = intern (":loader");
14463 staticpro (&QCloader);
14464 QCbounding_box = intern (":bounding-box");
14465 staticpro (&QCbounding_box);
14466 QCpt_width = intern (":pt-width");
14467 staticpro (&QCpt_width);
14468 QCpt_height = intern (":pt-height");
14469 staticpro (&QCpt_height);
14470 QCindex = intern (":index");
14471 staticpro (&QCindex);
14472 Qpbm = intern ("pbm");
14473 staticpro (&Qpbm);
14474
14475 #if HAVE_XPM
14476 Qxpm = intern ("xpm");
14477 staticpro (&Qxpm);
14478 #endif
14479
14480 #if HAVE_JPEG
14481 Qjpeg = intern ("jpeg");
14482 staticpro (&Qjpeg);
14483 #endif
14484
14485 #if HAVE_TIFF
14486 Qtiff = intern ("tiff");
14487 staticpro (&Qtiff);
14488 #endif
14489
14490 #if HAVE_GIF
14491 Qgif = intern ("gif");
14492 staticpro (&Qgif);
14493 #endif
14494
14495 #if HAVE_PNG
14496 Qpng = intern ("png");
14497 staticpro (&Qpng);
14498 #endif
14499
14500 defsubr (&Sclear_image_cache);
14501
14502 #if GLYPH_DEBUG
14503 defsubr (&Simagep);
14504 defsubr (&Slookup_image);
14505 #endif
14506 #endif /* TODO */
14507
14508 hourglass_atimer = NULL;
14509 hourglass_shown_p = 0;
14510 #ifdef TODO /* Tooltip support not complete. */
14511 defsubr (&Sx_show_tip);
14512 defsubr (&Sx_hide_tip);
14513 #endif
14514 tip_timer = Qnil;
14515 staticpro (&tip_timer);
14516 tip_frame = Qnil;
14517 staticpro (&tip_frame);
14518
14519 defsubr (&Sx_file_dialog);
14520 }
14521
14522
14523 void
14524 init_xfns ()
14525 {
14526 image_types = NULL;
14527 Vimage_types = Qnil;
14528
14529 #if 0 /* TODO : Image support for W32 */
14530 define_image_type (&xbm_type);
14531 define_image_type (&gs_type);
14532 define_image_type (&pbm_type);
14533
14534 #if HAVE_XPM
14535 define_image_type (&xpm_type);
14536 #endif
14537
14538 #if HAVE_JPEG
14539 define_image_type (&jpeg_type);
14540 #endif
14541
14542 #if HAVE_TIFF
14543 define_image_type (&tiff_type);
14544 #endif
14545
14546 #if HAVE_GIF
14547 define_image_type (&gif_type);
14548 #endif
14549
14550 #if HAVE_PNG
14551 define_image_type (&png_type);
14552 #endif
14553 #endif /* TODO */
14554 }
14555
14556 #undef abort
14557
14558 void
14559 w32_abort()
14560 {
14561 int button;
14562 button = MessageBox (NULL,
14563 "A fatal error has occurred!\n\n"
14564 "Select Abort to exit, Retry to debug, Ignore to continue",
14565 "Emacs Abort Dialog",
14566 MB_ICONEXCLAMATION | MB_TASKMODAL
14567 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
14568 switch (button)
14569 {
14570 case IDRETRY:
14571 DebugBreak ();
14572 break;
14573 case IDIGNORE:
14574 break;
14575 case IDABORT:
14576 default:
14577 abort ();
14578 break;
14579 }
14580 }
14581
14582 /* For convenience when debugging. */
14583 int
14584 w32_last_error()
14585 {
14586 return GetLastError ();
14587 }