(file_dialog_callback): New function.
[bpt/emacs.git] / 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 #include <dlgs.h>
56 #define FILE_NAME_TEXT_FIELD edt1
57
58 extern void free_frame_menubar ();
59 extern void x_compute_fringe_widths P_ ((struct frame *, int));
60 extern double atof ();
61 extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
62 extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
63 extern void w32_free_menu_strings P_ ((HWND));
64
65 extern int quit_char;
66
67 /* A definition of XColor for non-X frames. */
68 #ifndef HAVE_X_WINDOWS
69 typedef struct {
70 unsigned long pixel;
71 unsigned short red, green, blue;
72 char flags;
73 char pad;
74 } XColor;
75 #endif
76
77 extern char *lispy_function_keys[];
78
79 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
80 it, and including `bitmaps/gray' more than once is a problem when
81 config.h defines `static' as an empty replacement string. */
82
83 int gray_bitmap_width = gray_width;
84 int gray_bitmap_height = gray_height;
85 unsigned char *gray_bitmap_bits = gray_bits;
86
87 /* The colormap for converting color names to RGB values */
88 Lisp_Object Vw32_color_map;
89
90 /* Non nil if alt key presses are passed on to Windows. */
91 Lisp_Object Vw32_pass_alt_to_system;
92
93 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
94 to alt_modifier. */
95 Lisp_Object Vw32_alt_is_meta;
96
97 /* If non-zero, the windows virtual key code for an alternative quit key. */
98 Lisp_Object Vw32_quit_key;
99
100 /* Non nil if left window key events are passed on to Windows (this only
101 affects whether "tapping" the key opens the Start menu). */
102 Lisp_Object Vw32_pass_lwindow_to_system;
103
104 /* Non nil if right window key events are passed on to Windows (this
105 only affects whether "tapping" the key opens the Start menu). */
106 Lisp_Object Vw32_pass_rwindow_to_system;
107
108 /* Virtual key code used to generate "phantom" key presses in order
109 to stop system from acting on Windows key events. */
110 Lisp_Object Vw32_phantom_key_code;
111
112 /* Modifier associated with the left "Windows" key, or nil to act as a
113 normal key. */
114 Lisp_Object Vw32_lwindow_modifier;
115
116 /* Modifier associated with the right "Windows" key, or nil to act as a
117 normal key. */
118 Lisp_Object Vw32_rwindow_modifier;
119
120 /* Modifier associated with the "Apps" key, or nil to act as a normal
121 key. */
122 Lisp_Object Vw32_apps_modifier;
123
124 /* Value is nil if Num Lock acts as a function key. */
125 Lisp_Object Vw32_enable_num_lock;
126
127 /* Value is nil if Caps Lock acts as a function key. */
128 Lisp_Object Vw32_enable_caps_lock;
129
130 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
131 Lisp_Object Vw32_scroll_lock_modifier;
132
133 /* Switch to control whether we inhibit requests for synthesized bold
134 and italic versions of fonts. */
135 int w32_enable_synthesized_fonts;
136
137 /* Enable palette management. */
138 Lisp_Object Vw32_enable_palette;
139
140 /* Control how close left/right button down events must be to
141 be converted to a middle button down event. */
142 Lisp_Object Vw32_mouse_button_tolerance;
143
144 /* Minimum interval between mouse movement (and scroll bar drag)
145 events that are passed on to the event loop. */
146 Lisp_Object Vw32_mouse_move_interval;
147
148 /* Flag to indicate if XBUTTON events should be passed on to Windows. */
149 int w32_pass_extra_mouse_buttons_to_system;
150
151 /* The name we're using in resource queries. */
152 Lisp_Object Vx_resource_name;
153
154 /* Non nil if no window manager is in use. */
155 Lisp_Object Vx_no_window_manager;
156
157 /* Non-zero means we're allowed to display a hourglass pointer. */
158
159 int display_hourglass_p;
160
161 /* The background and shape of the mouse pointer, and shape when not
162 over text or in the modeline. */
163
164 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
165 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
166
167 /* The shape when over mouse-sensitive text. */
168
169 Lisp_Object Vx_sensitive_text_pointer_shape;
170
171 /* Color of chars displayed in cursor box. */
172
173 Lisp_Object Vx_cursor_fore_pixel;
174
175 /* Nonzero if using Windows. */
176
177 static int w32_in_use;
178
179 /* Search path for bitmap files. */
180
181 Lisp_Object Vx_bitmap_file_path;
182
183 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
184
185 Lisp_Object Vx_pixel_size_width_font_regexp;
186
187 /* Alist of bdf fonts and the files that define them. */
188 Lisp_Object Vw32_bdf_filename_alist;
189
190 /* A flag to control whether fonts are matched strictly or not. */
191 int w32_strict_fontnames;
192
193 /* A flag to control whether we should only repaint if GetUpdateRect
194 indicates there is an update region. */
195 int w32_strict_painting;
196
197 /* Associative list linking character set strings to Windows codepages. */
198 Lisp_Object Vw32_charset_info_alist;
199
200 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
201 #ifndef VIETNAMESE_CHARSET
202 #define VIETNAMESE_CHARSET 163
203 #endif
204
205 Lisp_Object Qauto_raise;
206 Lisp_Object Qauto_lower;
207 Lisp_Object Qbar, Qhbar;
208 Lisp_Object Qborder_color;
209 Lisp_Object Qborder_width;
210 Lisp_Object Qbox;
211 Lisp_Object Qcursor_color;
212 Lisp_Object Qcursor_type;
213 Lisp_Object Qgeometry;
214 Lisp_Object Qicon_left;
215 Lisp_Object Qicon_top;
216 Lisp_Object Qicon_type;
217 Lisp_Object Qicon_name;
218 Lisp_Object Qinternal_border_width;
219 Lisp_Object Qleft;
220 Lisp_Object Qright;
221 Lisp_Object Qmouse_color;
222 Lisp_Object Qnone;
223 Lisp_Object Qparent_id;
224 Lisp_Object Qscroll_bar_width;
225 Lisp_Object Qsuppress_icon;
226 Lisp_Object Qundefined_color;
227 Lisp_Object Qvertical_scroll_bars;
228 Lisp_Object Qvisibility;
229 Lisp_Object Qwindow_id;
230 Lisp_Object Qx_frame_parameter;
231 Lisp_Object Qx_resource_name;
232 Lisp_Object Quser_position;
233 Lisp_Object Quser_size;
234 Lisp_Object Qscreen_gamma;
235 Lisp_Object Qline_spacing;
236 Lisp_Object Qcenter;
237 Lisp_Object Qcancel_timer;
238 Lisp_Object Qhyper;
239 Lisp_Object Qsuper;
240 Lisp_Object Qmeta;
241 Lisp_Object Qalt;
242 Lisp_Object Qctrl;
243 Lisp_Object Qcontrol;
244 Lisp_Object Qshift;
245
246 Lisp_Object Qw32_charset_ansi;
247 Lisp_Object Qw32_charset_default;
248 Lisp_Object Qw32_charset_symbol;
249 Lisp_Object Qw32_charset_shiftjis;
250 Lisp_Object Qw32_charset_hangeul;
251 Lisp_Object Qw32_charset_gb2312;
252 Lisp_Object Qw32_charset_chinesebig5;
253 Lisp_Object Qw32_charset_oem;
254
255 #ifndef JOHAB_CHARSET
256 #define JOHAB_CHARSET 130
257 #endif
258 #ifdef JOHAB_CHARSET
259 Lisp_Object Qw32_charset_easteurope;
260 Lisp_Object Qw32_charset_turkish;
261 Lisp_Object Qw32_charset_baltic;
262 Lisp_Object Qw32_charset_russian;
263 Lisp_Object Qw32_charset_arabic;
264 Lisp_Object Qw32_charset_greek;
265 Lisp_Object Qw32_charset_hebrew;
266 Lisp_Object Qw32_charset_vietnamese;
267 Lisp_Object Qw32_charset_thai;
268 Lisp_Object Qw32_charset_johab;
269 Lisp_Object Qw32_charset_mac;
270 #endif
271
272 #ifdef UNICODE_CHARSET
273 Lisp_Object Qw32_charset_unicode;
274 #endif
275
276 Lisp_Object Qfullscreen;
277 Lisp_Object Qfullwidth;
278 Lisp_Object Qfullheight;
279 Lisp_Object Qfullboth;
280
281 extern Lisp_Object Qtop;
282 extern Lisp_Object Qdisplay;
283
284 /* State variables for emulating a three button mouse. */
285 #define LMOUSE 1
286 #define MMOUSE 2
287 #define RMOUSE 4
288
289 static int button_state = 0;
290 static W32Msg saved_mouse_button_msg;
291 static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
292 static W32Msg saved_mouse_move_msg;
293 static unsigned mouse_move_timer = 0;
294
295 /* Window that is tracking the mouse. */
296 static HWND track_mouse_window;
297 FARPROC track_mouse_event_fn;
298
299 /* W95 mousewheel handler */
300 unsigned int msh_mousewheel = 0;
301
302 /* Timers */
303 #define MOUSE_BUTTON_ID 1
304 #define MOUSE_MOVE_ID 2
305 #define MENU_FREE_ID 3
306 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
307 is received. */
308 #define MENU_FREE_DELAY 1000
309 static unsigned menu_free_timer = 0;
310
311 /* The below are defined in frame.c. */
312
313 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
314 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
315 extern Lisp_Object Qtool_bar_lines;
316
317 extern Lisp_Object Vwindow_system_version;
318
319 Lisp_Object Qface_set_after_frame_default;
320
321 #ifdef GLYPH_DEBUG
322 int image_cache_refcount, dpyinfo_refcount;
323 #endif
324
325
326 /* From w32term.c. */
327 extern Lisp_Object Vw32_num_mouse_buttons;
328 extern Lisp_Object Vw32_recognize_altgr;
329
330 extern HWND w32_system_caret_hwnd;
331
332 extern int w32_system_caret_height;
333 extern int w32_system_caret_x;
334 extern int w32_system_caret_y;
335 extern int w32_use_visible_system_caret;
336
337 static HWND w32_visible_system_caret_hwnd;
338
339 \f
340 /* Error if we are not connected to MS-Windows. */
341 void
342 check_w32 ()
343 {
344 if (! w32_in_use)
345 error ("MS-Windows not in use or not initialized");
346 }
347
348 /* Nonzero if we can use mouse menus.
349 You should not call this unless HAVE_MENUS is defined. */
350
351 int
352 have_menus_p ()
353 {
354 return w32_in_use;
355 }
356
357 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
358 and checking validity for W32. */
359
360 FRAME_PTR
361 check_x_frame (frame)
362 Lisp_Object frame;
363 {
364 FRAME_PTR f;
365
366 if (NILP (frame))
367 frame = selected_frame;
368 CHECK_LIVE_FRAME (frame);
369 f = XFRAME (frame);
370 if (! FRAME_W32_P (f))
371 error ("non-w32 frame used");
372 return f;
373 }
374
375 /* Let the user specify an display with a frame.
376 nil stands for the selected frame--or, if that is not a w32 frame,
377 the first display on the list. */
378
379 static struct w32_display_info *
380 check_x_display_info (frame)
381 Lisp_Object frame;
382 {
383 if (NILP (frame))
384 {
385 struct frame *sf = XFRAME (selected_frame);
386
387 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
388 return FRAME_W32_DISPLAY_INFO (sf);
389 else
390 return &one_w32_display_info;
391 }
392 else if (STRINGP (frame))
393 return x_display_info_for_name (frame);
394 else
395 {
396 FRAME_PTR f;
397
398 CHECK_LIVE_FRAME (frame);
399 f = XFRAME (frame);
400 if (! FRAME_W32_P (f))
401 error ("non-w32 frame used");
402 return FRAME_W32_DISPLAY_INFO (f);
403 }
404 }
405 \f
406 /* Return the Emacs frame-object corresponding to an w32 window.
407 It could be the frame's main window or an icon window. */
408
409 /* This function can be called during GC, so use GC_xxx type test macros. */
410
411 struct frame *
412 x_window_to_frame (dpyinfo, wdesc)
413 struct w32_display_info *dpyinfo;
414 HWND wdesc;
415 {
416 Lisp_Object tail, frame;
417 struct frame *f;
418
419 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
420 {
421 frame = XCAR (tail);
422 if (!GC_FRAMEP (frame))
423 continue;
424 f = XFRAME (frame);
425 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
426 continue;
427 if (f->output_data.w32->hourglass_window == wdesc)
428 return f;
429
430 if (FRAME_W32_WINDOW (f) == wdesc)
431 return f;
432 }
433 return 0;
434 }
435
436 \f
437
438 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
439 id, which is just an int that this section returns. Bitmaps are
440 reference counted so they can be shared among frames.
441
442 Bitmap indices are guaranteed to be > 0, so a negative number can
443 be used to indicate no bitmap.
444
445 If you use x_create_bitmap_from_data, then you must keep track of
446 the bitmaps yourself. That is, creating a bitmap from the same
447 data more than once will not be caught. */
448
449
450 /* Functions to access the contents of a bitmap, given an id. */
451
452 int
453 x_bitmap_height (f, id)
454 FRAME_PTR f;
455 int id;
456 {
457 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
458 }
459
460 int
461 x_bitmap_width (f, id)
462 FRAME_PTR f;
463 int id;
464 {
465 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
466 }
467
468 int
469 x_bitmap_pixmap (f, id)
470 FRAME_PTR f;
471 int id;
472 {
473 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
474 }
475
476
477 /* Allocate a new bitmap record. Returns index of new record. */
478
479 static int
480 x_allocate_bitmap_record (f)
481 FRAME_PTR f;
482 {
483 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
484 int i;
485
486 if (dpyinfo->bitmaps == NULL)
487 {
488 dpyinfo->bitmaps_size = 10;
489 dpyinfo->bitmaps
490 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
491 dpyinfo->bitmaps_last = 1;
492 return 1;
493 }
494
495 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
496 return ++dpyinfo->bitmaps_last;
497
498 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
499 if (dpyinfo->bitmaps[i].refcount == 0)
500 return i + 1;
501
502 dpyinfo->bitmaps_size *= 2;
503 dpyinfo->bitmaps
504 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
505 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
506 return ++dpyinfo->bitmaps_last;
507 }
508
509 /* Add one reference to the reference count of the bitmap with id ID. */
510
511 void
512 x_reference_bitmap (f, id)
513 FRAME_PTR f;
514 int id;
515 {
516 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
517 }
518
519 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
520
521 int
522 x_create_bitmap_from_data (f, bits, width, height)
523 struct frame *f;
524 char *bits;
525 unsigned int width, height;
526 {
527 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
528 Pixmap bitmap;
529 int id;
530
531 bitmap = CreateBitmap (width, height,
532 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
533 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
534 bits);
535
536 if (! bitmap)
537 return -1;
538
539 id = x_allocate_bitmap_record (f);
540 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
541 dpyinfo->bitmaps[id - 1].file = NULL;
542 dpyinfo->bitmaps[id - 1].hinst = NULL;
543 dpyinfo->bitmaps[id - 1].refcount = 1;
544 dpyinfo->bitmaps[id - 1].depth = 1;
545 dpyinfo->bitmaps[id - 1].height = height;
546 dpyinfo->bitmaps[id - 1].width = width;
547
548 return id;
549 }
550
551 /* Create bitmap from file FILE for frame F. */
552
553 int
554 x_create_bitmap_from_file (f, file)
555 struct frame *f;
556 Lisp_Object file;
557 {
558 return -1;
559 #if 0 /* TODO : bitmap support */
560 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
561 unsigned int width, height;
562 HBITMAP bitmap;
563 int xhot, yhot, result, id;
564 Lisp_Object found;
565 int fd;
566 char *filename;
567 HINSTANCE hinst;
568
569 /* Look for an existing bitmap with the same name. */
570 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
571 {
572 if (dpyinfo->bitmaps[id].refcount
573 && dpyinfo->bitmaps[id].file
574 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
575 {
576 ++dpyinfo->bitmaps[id].refcount;
577 return id + 1;
578 }
579 }
580
581 /* Search bitmap-file-path for the file, if appropriate. */
582 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, Qnil);
583 if (fd < 0)
584 return -1;
585 emacs_close (fd);
586
587 filename = (char *) XSTRING (found)->data;
588
589 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
590
591 if (hinst == NULL)
592 return -1;
593
594
595 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
596 filename, &width, &height, &bitmap, &xhot, &yhot);
597 if (result != BitmapSuccess)
598 return -1;
599
600 id = x_allocate_bitmap_record (f);
601 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
602 dpyinfo->bitmaps[id - 1].refcount = 1;
603 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
604 dpyinfo->bitmaps[id - 1].depth = 1;
605 dpyinfo->bitmaps[id - 1].height = height;
606 dpyinfo->bitmaps[id - 1].width = width;
607 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
608
609 return id;
610 #endif /* TODO */
611 }
612
613 /* Remove reference to bitmap with id number ID. */
614
615 void
616 x_destroy_bitmap (f, id)
617 FRAME_PTR f;
618 int id;
619 {
620 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
621
622 if (id > 0)
623 {
624 --dpyinfo->bitmaps[id - 1].refcount;
625 if (dpyinfo->bitmaps[id - 1].refcount == 0)
626 {
627 BLOCK_INPUT;
628 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
629 if (dpyinfo->bitmaps[id - 1].file)
630 {
631 xfree (dpyinfo->bitmaps[id - 1].file);
632 dpyinfo->bitmaps[id - 1].file = NULL;
633 }
634 UNBLOCK_INPUT;
635 }
636 }
637 }
638
639 /* Free all the bitmaps for the display specified by DPYINFO. */
640
641 static void
642 x_destroy_all_bitmaps (dpyinfo)
643 struct w32_display_info *dpyinfo;
644 {
645 int i;
646 for (i = 0; i < dpyinfo->bitmaps_last; i++)
647 if (dpyinfo->bitmaps[i].refcount > 0)
648 {
649 DeleteObject (dpyinfo->bitmaps[i].pixmap);
650 if (dpyinfo->bitmaps[i].file)
651 xfree (dpyinfo->bitmaps[i].file);
652 }
653 dpyinfo->bitmaps_last = 0;
654 }
655 \f
656 /* Connect the frame-parameter names for W32 frames
657 to the ways of passing the parameter values to the window system.
658
659 The name of a parameter, as a Lisp symbol,
660 has an `x-frame-parameter' property which is an integer in Lisp
661 but can be interpreted as an `enum x_frame_parm' in C. */
662
663 enum x_frame_parm
664 {
665 X_PARM_FOREGROUND_COLOR,
666 X_PARM_BACKGROUND_COLOR,
667 X_PARM_MOUSE_COLOR,
668 X_PARM_CURSOR_COLOR,
669 X_PARM_BORDER_COLOR,
670 X_PARM_ICON_TYPE,
671 X_PARM_FONT,
672 X_PARM_BORDER_WIDTH,
673 X_PARM_INTERNAL_BORDER_WIDTH,
674 X_PARM_NAME,
675 X_PARM_AUTORAISE,
676 X_PARM_AUTOLOWER,
677 X_PARM_VERT_SCROLL_BAR,
678 X_PARM_VISIBILITY,
679 X_PARM_MENU_BAR_LINES
680 };
681
682
683 struct x_frame_parm_table
684 {
685 char *name;
686 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
687 };
688
689 BOOL my_show_window P_ ((struct frame *, HWND, int));
690 void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
691 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
692 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
693 static void x_change_window_heights P_ ((Lisp_Object, int));
694 /* TODO: Native Input Method support; see x_create_im. */
695 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
701 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
702 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
703 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
704 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
705 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
706 static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
707 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
708 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
709 Lisp_Object));
710 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
711 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
712 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
713 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
714 Lisp_Object));
715 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
716 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
717 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
718 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
719 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
720 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
721 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
722 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
723 Lisp_Object));
724
725 static struct x_frame_parm_table x_frame_parms[] =
726 {
727 {"auto-raise", x_set_autoraise},
728 {"auto-lower", x_set_autolower},
729 {"background-color", x_set_background_color},
730 {"border-color", x_set_border_color},
731 {"border-width", x_set_border_width},
732 {"cursor-color", x_set_cursor_color},
733 {"cursor-type", x_set_cursor_type},
734 {"font", x_set_font},
735 {"foreground-color", x_set_foreground_color},
736 {"icon-name", x_set_icon_name},
737 {"icon-type", x_set_icon_type},
738 {"internal-border-width", x_set_internal_border_width},
739 {"menu-bar-lines", x_set_menu_bar_lines},
740 {"mouse-color", x_set_mouse_color},
741 {"name", x_explicitly_set_name},
742 {"scroll-bar-width", x_set_scroll_bar_width},
743 {"title", x_set_title},
744 {"unsplittable", x_set_unsplittable},
745 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
746 {"visibility", x_set_visibility},
747 {"tool-bar-lines", x_set_tool_bar_lines},
748 {"screen-gamma", x_set_screen_gamma},
749 {"line-spacing", x_set_line_spacing},
750 {"left-fringe", x_set_fringe_width},
751 {"right-fringe", x_set_fringe_width},
752 {"fullscreen", x_set_fullscreen},
753 };
754
755 /* Attach the `x-frame-parameter' properties to
756 the Lisp symbol names of parameters relevant to W32. */
757
758 void
759 init_x_parm_symbols ()
760 {
761 int i;
762
763 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
764 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
765 make_number (i));
766 }
767 \f
768 /* Really try to move where we want to be in case of fullscreen. Some WMs
769 moves the window where we tell them. Some (mwm, twm) moves the outer
770 window manager window there instead.
771 Try to compensate for those WM here. */
772 static void
773 x_fullscreen_move (f, new_top, new_left)
774 struct frame *f;
775 int new_top;
776 int new_left;
777 {
778 if (new_top != f->output_data.w32->top_pos
779 || new_left != f->output_data.w32->left_pos)
780 {
781 int move_x = new_left;
782 int move_y = new_top;
783
784 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
785 x_set_offset (f, move_x, move_y, 1);
786 }
787 }
788
789 /* Change the parameters of frame F as specified by ALIST.
790 If a parameter is not specially recognized, do nothing;
791 otherwise call the `x_set_...' function for that parameter. */
792
793 void
794 x_set_frame_parameters (f, alist)
795 FRAME_PTR f;
796 Lisp_Object alist;
797 {
798 Lisp_Object tail;
799
800 /* If both of these parameters are present, it's more efficient to
801 set them both at once. So we wait until we've looked at the
802 entire list before we set them. */
803 int width, height;
804
805 /* Same here. */
806 Lisp_Object left, top;
807
808 /* Same with these. */
809 Lisp_Object icon_left, icon_top;
810
811 /* Record in these vectors all the parms specified. */
812 Lisp_Object *parms;
813 Lisp_Object *values;
814 int i, p;
815 int left_no_change = 0, top_no_change = 0;
816 int icon_left_no_change = 0, icon_top_no_change = 0;
817 int fullscreen_is_being_set = 0;
818
819 struct gcpro gcpro1, gcpro2;
820
821 i = 0;
822 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
823 i++;
824
825 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
826 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
827
828 /* Extract parm names and values into those vectors. */
829
830 i = 0;
831 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
832 {
833 Lisp_Object elt;
834
835 elt = Fcar (tail);
836 parms[i] = Fcar (elt);
837 values[i] = Fcdr (elt);
838 i++;
839 }
840 /* TAIL and ALIST are not used again below here. */
841 alist = tail = Qnil;
842
843 GCPRO2 (*parms, *values);
844 gcpro1.nvars = i;
845 gcpro2.nvars = i;
846
847 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
848 because their values appear in VALUES and strings are not valid. */
849 top = left = Qunbound;
850 icon_left = icon_top = Qunbound;
851
852 /* Provide default values for HEIGHT and WIDTH. */
853 if (FRAME_NEW_WIDTH (f))
854 width = FRAME_NEW_WIDTH (f);
855 else
856 width = FRAME_WIDTH (f);
857
858 if (FRAME_NEW_HEIGHT (f))
859 height = FRAME_NEW_HEIGHT (f);
860 else
861 height = FRAME_HEIGHT (f);
862
863 /* Process foreground_color and background_color before anything else.
864 They are independent of other properties, but other properties (e.g.,
865 cursor_color) are dependent upon them. */
866 /* Process default font as well, since fringe widths depends on it. */
867 for (p = 0; p < i; p++)
868 {
869 Lisp_Object prop, val;
870
871 prop = parms[p];
872 val = values[p];
873 if (EQ (prop, Qforeground_color)
874 || EQ (prop, Qbackground_color)
875 || EQ (prop, Qfont)
876 || EQ (prop, Qfullscreen))
877 {
878 register Lisp_Object param_index, old_value;
879
880 old_value = get_frame_param (f, prop);
881 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
882
883 if (NILP (Fequal (val, old_value)))
884 {
885 store_frame_param (f, prop, val);
886
887 param_index = Fget (prop, Qx_frame_parameter);
888 if (NATNUMP (param_index)
889 && (XFASTINT (param_index)
890 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
891 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
892 }
893 }
894 }
895
896 /* Now process them in reverse of specified order. */
897 for (i--; i >= 0; i--)
898 {
899 Lisp_Object prop, val;
900
901 prop = parms[i];
902 val = values[i];
903
904 if (EQ (prop, Qwidth) && NUMBERP (val))
905 width = XFASTINT (val);
906 else if (EQ (prop, Qheight) && NUMBERP (val))
907 height = XFASTINT (val);
908 else if (EQ (prop, Qtop))
909 top = val;
910 else if (EQ (prop, Qleft))
911 left = val;
912 else if (EQ (prop, Qicon_top))
913 icon_top = val;
914 else if (EQ (prop, Qicon_left))
915 icon_left = val;
916 else if (EQ (prop, Qforeground_color)
917 || EQ (prop, Qbackground_color)
918 || EQ (prop, Qfont)
919 || EQ (prop, Qfullscreen))
920 /* Processed above. */
921 continue;
922 else
923 {
924 register Lisp_Object param_index, old_value;
925
926 old_value = get_frame_param (f, prop);
927
928 store_frame_param (f, prop, val);
929
930 param_index = Fget (prop, Qx_frame_parameter);
931 if (NATNUMP (param_index)
932 && (XFASTINT (param_index)
933 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
934 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
935 }
936 }
937
938 /* Don't die if just one of these was set. */
939 if (EQ (left, Qunbound))
940 {
941 left_no_change = 1;
942 if (f->output_data.w32->left_pos < 0)
943 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
944 else
945 XSETINT (left, f->output_data.w32->left_pos);
946 }
947 if (EQ (top, Qunbound))
948 {
949 top_no_change = 1;
950 if (f->output_data.w32->top_pos < 0)
951 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
952 else
953 XSETINT (top, f->output_data.w32->top_pos);
954 }
955
956 /* If one of the icon positions was not set, preserve or default it. */
957 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
958 {
959 icon_left_no_change = 1;
960 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
961 if (NILP (icon_left))
962 XSETINT (icon_left, 0);
963 }
964 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
965 {
966 icon_top_no_change = 1;
967 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
968 if (NILP (icon_top))
969 XSETINT (icon_top, 0);
970 }
971
972 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
973 {
974 /* If the frame is visible already and the fullscreen parameter is
975 being set, it is too late to set WM manager hints to specify
976 size and position.
977 Here we first get the width, height and position that applies to
978 fullscreen. We then move the frame to the appropriate
979 position. Resize of the frame is taken care of in the code after
980 this if-statement. */
981 int new_left, new_top;
982
983 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
984 x_fullscreen_move (f, new_top, new_left);
985 }
986
987 /* Don't set these parameters unless they've been explicitly
988 specified. The window might be mapped or resized while we're in
989 this function, and we don't want to override that unless the lisp
990 code has asked for it.
991
992 Don't set these parameters unless they actually differ from the
993 window's current parameters; the window may not actually exist
994 yet. */
995 {
996 Lisp_Object frame;
997
998 check_frame_size (f, &height, &width);
999
1000 XSETFRAME (frame, f);
1001
1002 if (width != FRAME_WIDTH (f)
1003 || height != FRAME_HEIGHT (f)
1004 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
1005 Fset_frame_size (frame, make_number (width), make_number (height));
1006
1007 if ((!NILP (left) || !NILP (top))
1008 && ! (left_no_change && top_no_change)
1009 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1010 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
1011 {
1012 int leftpos = 0;
1013 int toppos = 0;
1014
1015 /* Record the signs. */
1016 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
1017 if (EQ (left, Qminus))
1018 f->output_data.w32->size_hint_flags |= XNegative;
1019 else if (INTEGERP (left))
1020 {
1021 leftpos = XINT (left);
1022 if (leftpos < 0)
1023 f->output_data.w32->size_hint_flags |= XNegative;
1024 }
1025 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1026 && CONSP (XCDR (left))
1027 && INTEGERP (XCAR (XCDR (left))))
1028 {
1029 leftpos = - XINT (XCAR (XCDR (left)));
1030 f->output_data.w32->size_hint_flags |= XNegative;
1031 }
1032 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1033 && CONSP (XCDR (left))
1034 && INTEGERP (XCAR (XCDR (left))))
1035 {
1036 leftpos = XINT (XCAR (XCDR (left)));
1037 }
1038
1039 if (EQ (top, Qminus))
1040 f->output_data.w32->size_hint_flags |= YNegative;
1041 else if (INTEGERP (top))
1042 {
1043 toppos = XINT (top);
1044 if (toppos < 0)
1045 f->output_data.w32->size_hint_flags |= YNegative;
1046 }
1047 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1048 && CONSP (XCDR (top))
1049 && INTEGERP (XCAR (XCDR (top))))
1050 {
1051 toppos = - XINT (XCAR (XCDR (top)));
1052 f->output_data.w32->size_hint_flags |= YNegative;
1053 }
1054 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1055 && CONSP (XCDR (top))
1056 && INTEGERP (XCAR (XCDR (top))))
1057 {
1058 toppos = XINT (XCAR (XCDR (top)));
1059 }
1060
1061
1062 /* Store the numeric value of the position. */
1063 f->output_data.w32->top_pos = toppos;
1064 f->output_data.w32->left_pos = leftpos;
1065
1066 f->output_data.w32->win_gravity = NorthWestGravity;
1067
1068 /* Actually set that position, and convert to absolute. */
1069 x_set_offset (f, leftpos, toppos, -1);
1070 }
1071
1072 if ((!NILP (icon_left) || !NILP (icon_top))
1073 && ! (icon_left_no_change && icon_top_no_change))
1074 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1075 }
1076
1077 UNGCPRO;
1078 }
1079
1080 /* Store the screen positions of frame F into XPTR and YPTR.
1081 These are the positions of the containing window manager window,
1082 not Emacs's own window. */
1083
1084 void
1085 x_real_positions (f, xptr, yptr)
1086 FRAME_PTR f;
1087 int *xptr, *yptr;
1088 {
1089 POINT pt;
1090 RECT rect;
1091
1092 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1093 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1094
1095 pt.x = rect.left;
1096 pt.y = rect.top;
1097
1098 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1099
1100 /* Remember x_pixels_diff and y_pixels_diff. */
1101 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1102 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1103
1104 *xptr = pt.x;
1105 *yptr = pt.y;
1106 }
1107
1108 /* Insert a description of internally-recorded parameters of frame X
1109 into the parameter alist *ALISTPTR that is to be given to the user.
1110 Only parameters that are specific to W32
1111 and whose values are not correctly recorded in the frame's
1112 param_alist need to be considered here. */
1113
1114 void
1115 x_report_frame_params (f, alistptr)
1116 struct frame *f;
1117 Lisp_Object *alistptr;
1118 {
1119 char buf[16];
1120 Lisp_Object tem;
1121
1122 /* Represent negative positions (off the top or left screen edge)
1123 in a way that Fmodify_frame_parameters will understand correctly. */
1124 XSETINT (tem, f->output_data.w32->left_pos);
1125 if (f->output_data.w32->left_pos >= 0)
1126 store_in_alist (alistptr, Qleft, tem);
1127 else
1128 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1129
1130 XSETINT (tem, f->output_data.w32->top_pos);
1131 if (f->output_data.w32->top_pos >= 0)
1132 store_in_alist (alistptr, Qtop, tem);
1133 else
1134 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1135
1136 store_in_alist (alistptr, Qborder_width,
1137 make_number (f->output_data.w32->border_width));
1138 store_in_alist (alistptr, Qinternal_border_width,
1139 make_number (f->output_data.w32->internal_border_width));
1140 store_in_alist (alistptr, Qleft_fringe,
1141 make_number (f->output_data.w32->left_fringe_width));
1142 store_in_alist (alistptr, Qright_fringe,
1143 make_number (f->output_data.w32->right_fringe_width));
1144 store_in_alist (alistptr, Qscroll_bar_width,
1145 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1146 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1147 : 0));
1148 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1149 store_in_alist (alistptr, Qwindow_id,
1150 build_string (buf));
1151 store_in_alist (alistptr, Qicon_name, f->icon_name);
1152 FRAME_SAMPLE_VISIBILITY (f);
1153 store_in_alist (alistptr, Qvisibility,
1154 (FRAME_VISIBLE_P (f) ? Qt
1155 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1156 store_in_alist (alistptr, Qdisplay,
1157 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1158 }
1159 \f
1160
1161 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1162 Sw32_define_rgb_color, 4, 4, 0,
1163 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1164 This adds or updates a named color to w32-color-map, making it
1165 available for use. The original entry's RGB ref is returned, or nil
1166 if the entry is new. */)
1167 (red, green, blue, name)
1168 Lisp_Object red, green, blue, name;
1169 {
1170 Lisp_Object rgb;
1171 Lisp_Object oldrgb = Qnil;
1172 Lisp_Object entry;
1173
1174 CHECK_NUMBER (red);
1175 CHECK_NUMBER (green);
1176 CHECK_NUMBER (blue);
1177 CHECK_STRING (name);
1178
1179 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1180
1181 BLOCK_INPUT;
1182
1183 /* replace existing entry in w32-color-map or add new entry. */
1184 entry = Fassoc (name, Vw32_color_map);
1185 if (NILP (entry))
1186 {
1187 entry = Fcons (name, rgb);
1188 Vw32_color_map = Fcons (entry, Vw32_color_map);
1189 }
1190 else
1191 {
1192 oldrgb = Fcdr (entry);
1193 Fsetcdr (entry, rgb);
1194 }
1195
1196 UNBLOCK_INPUT;
1197
1198 return (oldrgb);
1199 }
1200
1201 DEFUN ("w32-load-color-file", Fw32_load_color_file,
1202 Sw32_load_color_file, 1, 1, 0,
1203 doc: /* Create an alist of color entries from an external file.
1204 Assign this value to w32-color-map to replace the existing color map.
1205
1206 The file should define one named RGB color per line like so:
1207 R G B name
1208 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
1209 (filename)
1210 Lisp_Object filename;
1211 {
1212 FILE *fp;
1213 Lisp_Object cmap = Qnil;
1214 Lisp_Object abspath;
1215
1216 CHECK_STRING (filename);
1217 abspath = Fexpand_file_name (filename, Qnil);
1218
1219 fp = fopen (XSTRING (filename)->data, "rt");
1220 if (fp)
1221 {
1222 char buf[512];
1223 int red, green, blue;
1224 int num;
1225
1226 BLOCK_INPUT;
1227
1228 while (fgets (buf, sizeof (buf), fp) != NULL) {
1229 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1230 {
1231 char *name = buf + num;
1232 num = strlen (name) - 1;
1233 if (name[num] == '\n')
1234 name[num] = 0;
1235 cmap = Fcons (Fcons (build_string (name),
1236 make_number (RGB (red, green, blue))),
1237 cmap);
1238 }
1239 }
1240 fclose (fp);
1241
1242 UNBLOCK_INPUT;
1243 }
1244
1245 return cmap;
1246 }
1247
1248 /* The default colors for the w32 color map */
1249 typedef struct colormap_t
1250 {
1251 char *name;
1252 COLORREF colorref;
1253 } colormap_t;
1254
1255 colormap_t w32_color_map[] =
1256 {
1257 {"snow" , PALETTERGB (255,250,250)},
1258 {"ghost white" , PALETTERGB (248,248,255)},
1259 {"GhostWhite" , PALETTERGB (248,248,255)},
1260 {"white smoke" , PALETTERGB (245,245,245)},
1261 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1262 {"gainsboro" , PALETTERGB (220,220,220)},
1263 {"floral white" , PALETTERGB (255,250,240)},
1264 {"FloralWhite" , PALETTERGB (255,250,240)},
1265 {"old lace" , PALETTERGB (253,245,230)},
1266 {"OldLace" , PALETTERGB (253,245,230)},
1267 {"linen" , PALETTERGB (250,240,230)},
1268 {"antique white" , PALETTERGB (250,235,215)},
1269 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1270 {"papaya whip" , PALETTERGB (255,239,213)},
1271 {"PapayaWhip" , PALETTERGB (255,239,213)},
1272 {"blanched almond" , PALETTERGB (255,235,205)},
1273 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1274 {"bisque" , PALETTERGB (255,228,196)},
1275 {"peach puff" , PALETTERGB (255,218,185)},
1276 {"PeachPuff" , PALETTERGB (255,218,185)},
1277 {"navajo white" , PALETTERGB (255,222,173)},
1278 {"NavajoWhite" , PALETTERGB (255,222,173)},
1279 {"moccasin" , PALETTERGB (255,228,181)},
1280 {"cornsilk" , PALETTERGB (255,248,220)},
1281 {"ivory" , PALETTERGB (255,255,240)},
1282 {"lemon chiffon" , PALETTERGB (255,250,205)},
1283 {"LemonChiffon" , PALETTERGB (255,250,205)},
1284 {"seashell" , PALETTERGB (255,245,238)},
1285 {"honeydew" , PALETTERGB (240,255,240)},
1286 {"mint cream" , PALETTERGB (245,255,250)},
1287 {"MintCream" , PALETTERGB (245,255,250)},
1288 {"azure" , PALETTERGB (240,255,255)},
1289 {"alice blue" , PALETTERGB (240,248,255)},
1290 {"AliceBlue" , PALETTERGB (240,248,255)},
1291 {"lavender" , PALETTERGB (230,230,250)},
1292 {"lavender blush" , PALETTERGB (255,240,245)},
1293 {"LavenderBlush" , PALETTERGB (255,240,245)},
1294 {"misty rose" , PALETTERGB (255,228,225)},
1295 {"MistyRose" , PALETTERGB (255,228,225)},
1296 {"white" , PALETTERGB (255,255,255)},
1297 {"black" , PALETTERGB ( 0, 0, 0)},
1298 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1299 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1300 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1301 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1302 {"dim gray" , PALETTERGB (105,105,105)},
1303 {"DimGray" , PALETTERGB (105,105,105)},
1304 {"dim grey" , PALETTERGB (105,105,105)},
1305 {"DimGrey" , PALETTERGB (105,105,105)},
1306 {"slate gray" , PALETTERGB (112,128,144)},
1307 {"SlateGray" , PALETTERGB (112,128,144)},
1308 {"slate grey" , PALETTERGB (112,128,144)},
1309 {"SlateGrey" , PALETTERGB (112,128,144)},
1310 {"light slate gray" , PALETTERGB (119,136,153)},
1311 {"LightSlateGray" , PALETTERGB (119,136,153)},
1312 {"light slate grey" , PALETTERGB (119,136,153)},
1313 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1314 {"gray" , PALETTERGB (190,190,190)},
1315 {"grey" , PALETTERGB (190,190,190)},
1316 {"light grey" , PALETTERGB (211,211,211)},
1317 {"LightGrey" , PALETTERGB (211,211,211)},
1318 {"light gray" , PALETTERGB (211,211,211)},
1319 {"LightGray" , PALETTERGB (211,211,211)},
1320 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1321 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1322 {"navy" , PALETTERGB ( 0, 0,128)},
1323 {"navy blue" , PALETTERGB ( 0, 0,128)},
1324 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1325 {"cornflower blue" , PALETTERGB (100,149,237)},
1326 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1327 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1328 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1329 {"slate blue" , PALETTERGB (106, 90,205)},
1330 {"SlateBlue" , PALETTERGB (106, 90,205)},
1331 {"medium slate blue" , PALETTERGB (123,104,238)},
1332 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1333 {"light slate blue" , PALETTERGB (132,112,255)},
1334 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1335 {"medium blue" , PALETTERGB ( 0, 0,205)},
1336 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1337 {"royal blue" , PALETTERGB ( 65,105,225)},
1338 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1339 {"blue" , PALETTERGB ( 0, 0,255)},
1340 {"dodger blue" , PALETTERGB ( 30,144,255)},
1341 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1342 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1343 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1344 {"sky blue" , PALETTERGB (135,206,235)},
1345 {"SkyBlue" , PALETTERGB (135,206,235)},
1346 {"light sky blue" , PALETTERGB (135,206,250)},
1347 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1348 {"steel blue" , PALETTERGB ( 70,130,180)},
1349 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1350 {"light steel blue" , PALETTERGB (176,196,222)},
1351 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1352 {"light blue" , PALETTERGB (173,216,230)},
1353 {"LightBlue" , PALETTERGB (173,216,230)},
1354 {"powder blue" , PALETTERGB (176,224,230)},
1355 {"PowderBlue" , PALETTERGB (176,224,230)},
1356 {"pale turquoise" , PALETTERGB (175,238,238)},
1357 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1358 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1359 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1360 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1361 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1362 {"turquoise" , PALETTERGB ( 64,224,208)},
1363 {"cyan" , PALETTERGB ( 0,255,255)},
1364 {"light cyan" , PALETTERGB (224,255,255)},
1365 {"LightCyan" , PALETTERGB (224,255,255)},
1366 {"cadet blue" , PALETTERGB ( 95,158,160)},
1367 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1368 {"medium aquamarine" , PALETTERGB (102,205,170)},
1369 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1370 {"aquamarine" , PALETTERGB (127,255,212)},
1371 {"dark green" , PALETTERGB ( 0,100, 0)},
1372 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1373 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1374 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1375 {"dark sea green" , PALETTERGB (143,188,143)},
1376 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1377 {"sea green" , PALETTERGB ( 46,139, 87)},
1378 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1379 {"medium sea green" , PALETTERGB ( 60,179,113)},
1380 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1381 {"light sea green" , PALETTERGB ( 32,178,170)},
1382 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1383 {"pale green" , PALETTERGB (152,251,152)},
1384 {"PaleGreen" , PALETTERGB (152,251,152)},
1385 {"spring green" , PALETTERGB ( 0,255,127)},
1386 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1387 {"lawn green" , PALETTERGB (124,252, 0)},
1388 {"LawnGreen" , PALETTERGB (124,252, 0)},
1389 {"green" , PALETTERGB ( 0,255, 0)},
1390 {"chartreuse" , PALETTERGB (127,255, 0)},
1391 {"medium spring green" , PALETTERGB ( 0,250,154)},
1392 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1393 {"green yellow" , PALETTERGB (173,255, 47)},
1394 {"GreenYellow" , PALETTERGB (173,255, 47)},
1395 {"lime green" , PALETTERGB ( 50,205, 50)},
1396 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1397 {"yellow green" , PALETTERGB (154,205, 50)},
1398 {"YellowGreen" , PALETTERGB (154,205, 50)},
1399 {"forest green" , PALETTERGB ( 34,139, 34)},
1400 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1401 {"olive drab" , PALETTERGB (107,142, 35)},
1402 {"OliveDrab" , PALETTERGB (107,142, 35)},
1403 {"dark khaki" , PALETTERGB (189,183,107)},
1404 {"DarkKhaki" , PALETTERGB (189,183,107)},
1405 {"khaki" , PALETTERGB (240,230,140)},
1406 {"pale goldenrod" , PALETTERGB (238,232,170)},
1407 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1408 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1409 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1410 {"light yellow" , PALETTERGB (255,255,224)},
1411 {"LightYellow" , PALETTERGB (255,255,224)},
1412 {"yellow" , PALETTERGB (255,255, 0)},
1413 {"gold" , PALETTERGB (255,215, 0)},
1414 {"light goldenrod" , PALETTERGB (238,221,130)},
1415 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1416 {"goldenrod" , PALETTERGB (218,165, 32)},
1417 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1418 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1419 {"rosy brown" , PALETTERGB (188,143,143)},
1420 {"RosyBrown" , PALETTERGB (188,143,143)},
1421 {"indian red" , PALETTERGB (205, 92, 92)},
1422 {"IndianRed" , PALETTERGB (205, 92, 92)},
1423 {"saddle brown" , PALETTERGB (139, 69, 19)},
1424 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1425 {"sienna" , PALETTERGB (160, 82, 45)},
1426 {"peru" , PALETTERGB (205,133, 63)},
1427 {"burlywood" , PALETTERGB (222,184,135)},
1428 {"beige" , PALETTERGB (245,245,220)},
1429 {"wheat" , PALETTERGB (245,222,179)},
1430 {"sandy brown" , PALETTERGB (244,164, 96)},
1431 {"SandyBrown" , PALETTERGB (244,164, 96)},
1432 {"tan" , PALETTERGB (210,180,140)},
1433 {"chocolate" , PALETTERGB (210,105, 30)},
1434 {"firebrick" , PALETTERGB (178,34, 34)},
1435 {"brown" , PALETTERGB (165,42, 42)},
1436 {"dark salmon" , PALETTERGB (233,150,122)},
1437 {"DarkSalmon" , PALETTERGB (233,150,122)},
1438 {"salmon" , PALETTERGB (250,128,114)},
1439 {"light salmon" , PALETTERGB (255,160,122)},
1440 {"LightSalmon" , PALETTERGB (255,160,122)},
1441 {"orange" , PALETTERGB (255,165, 0)},
1442 {"dark orange" , PALETTERGB (255,140, 0)},
1443 {"DarkOrange" , PALETTERGB (255,140, 0)},
1444 {"coral" , PALETTERGB (255,127, 80)},
1445 {"light coral" , PALETTERGB (240,128,128)},
1446 {"LightCoral" , PALETTERGB (240,128,128)},
1447 {"tomato" , PALETTERGB (255, 99, 71)},
1448 {"orange red" , PALETTERGB (255, 69, 0)},
1449 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1450 {"red" , PALETTERGB (255, 0, 0)},
1451 {"hot pink" , PALETTERGB (255,105,180)},
1452 {"HotPink" , PALETTERGB (255,105,180)},
1453 {"deep pink" , PALETTERGB (255, 20,147)},
1454 {"DeepPink" , PALETTERGB (255, 20,147)},
1455 {"pink" , PALETTERGB (255,192,203)},
1456 {"light pink" , PALETTERGB (255,182,193)},
1457 {"LightPink" , PALETTERGB (255,182,193)},
1458 {"pale violet red" , PALETTERGB (219,112,147)},
1459 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1460 {"maroon" , PALETTERGB (176, 48, 96)},
1461 {"medium violet red" , PALETTERGB (199, 21,133)},
1462 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1463 {"violet red" , PALETTERGB (208, 32,144)},
1464 {"VioletRed" , PALETTERGB (208, 32,144)},
1465 {"magenta" , PALETTERGB (255, 0,255)},
1466 {"violet" , PALETTERGB (238,130,238)},
1467 {"plum" , PALETTERGB (221,160,221)},
1468 {"orchid" , PALETTERGB (218,112,214)},
1469 {"medium orchid" , PALETTERGB (186, 85,211)},
1470 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1471 {"dark orchid" , PALETTERGB (153, 50,204)},
1472 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1473 {"dark violet" , PALETTERGB (148, 0,211)},
1474 {"DarkViolet" , PALETTERGB (148, 0,211)},
1475 {"blue violet" , PALETTERGB (138, 43,226)},
1476 {"BlueViolet" , PALETTERGB (138, 43,226)},
1477 {"purple" , PALETTERGB (160, 32,240)},
1478 {"medium purple" , PALETTERGB (147,112,219)},
1479 {"MediumPurple" , PALETTERGB (147,112,219)},
1480 {"thistle" , PALETTERGB (216,191,216)},
1481 {"gray0" , PALETTERGB ( 0, 0, 0)},
1482 {"grey0" , PALETTERGB ( 0, 0, 0)},
1483 {"dark grey" , PALETTERGB (169,169,169)},
1484 {"DarkGrey" , PALETTERGB (169,169,169)},
1485 {"dark gray" , PALETTERGB (169,169,169)},
1486 {"DarkGray" , PALETTERGB (169,169,169)},
1487 {"dark blue" , PALETTERGB ( 0, 0,139)},
1488 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1489 {"dark cyan" , PALETTERGB ( 0,139,139)},
1490 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1491 {"dark magenta" , PALETTERGB (139, 0,139)},
1492 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1493 {"dark red" , PALETTERGB (139, 0, 0)},
1494 {"DarkRed" , PALETTERGB (139, 0, 0)},
1495 {"light green" , PALETTERGB (144,238,144)},
1496 {"LightGreen" , PALETTERGB (144,238,144)},
1497 };
1498
1499 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1500 0, 0, 0, doc: /* Return the default color map. */)
1501 ()
1502 {
1503 int i;
1504 colormap_t *pc = w32_color_map;
1505 Lisp_Object cmap;
1506
1507 BLOCK_INPUT;
1508
1509 cmap = Qnil;
1510
1511 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1512 pc++, i++)
1513 cmap = Fcons (Fcons (build_string (pc->name),
1514 make_number (pc->colorref)),
1515 cmap);
1516
1517 UNBLOCK_INPUT;
1518
1519 return (cmap);
1520 }
1521
1522 Lisp_Object
1523 w32_to_x_color (rgb)
1524 Lisp_Object rgb;
1525 {
1526 Lisp_Object color;
1527
1528 CHECK_NUMBER (rgb);
1529
1530 BLOCK_INPUT;
1531
1532 color = Frassq (rgb, Vw32_color_map);
1533
1534 UNBLOCK_INPUT;
1535
1536 if (!NILP (color))
1537 return (Fcar (color));
1538 else
1539 return Qnil;
1540 }
1541
1542 COLORREF
1543 w32_color_map_lookup (colorname)
1544 char *colorname;
1545 {
1546 Lisp_Object tail, ret = Qnil;
1547
1548 BLOCK_INPUT;
1549
1550 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1551 {
1552 register Lisp_Object elt, tem;
1553
1554 elt = Fcar (tail);
1555 if (!CONSP (elt)) continue;
1556
1557 tem = Fcar (elt);
1558
1559 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1560 {
1561 ret = XUINT (Fcdr (elt));
1562 break;
1563 }
1564
1565 QUIT;
1566 }
1567
1568
1569 UNBLOCK_INPUT;
1570
1571 return ret;
1572 }
1573
1574 COLORREF
1575 x_to_w32_color (colorname)
1576 char * colorname;
1577 {
1578 register Lisp_Object ret = Qnil;
1579
1580 BLOCK_INPUT;
1581
1582 if (colorname[0] == '#')
1583 {
1584 /* Could be an old-style RGB Device specification. */
1585 char *color;
1586 int size;
1587 color = colorname + 1;
1588
1589 size = strlen(color);
1590 if (size == 3 || size == 6 || size == 9 || size == 12)
1591 {
1592 UINT colorval;
1593 int i, pos;
1594 pos = 0;
1595 size /= 3;
1596 colorval = 0;
1597
1598 for (i = 0; i < 3; i++)
1599 {
1600 char *end;
1601 char t;
1602 unsigned long value;
1603
1604 /* The check for 'x' in the following conditional takes into
1605 account the fact that strtol allows a "0x" in front of
1606 our numbers, and we don't. */
1607 if (!isxdigit(color[0]) || color[1] == 'x')
1608 break;
1609 t = color[size];
1610 color[size] = '\0';
1611 value = strtoul(color, &end, 16);
1612 color[size] = t;
1613 if (errno == ERANGE || end - color != size)
1614 break;
1615 switch (size)
1616 {
1617 case 1:
1618 value = value * 0x10;
1619 break;
1620 case 2:
1621 break;
1622 case 3:
1623 value /= 0x10;
1624 break;
1625 case 4:
1626 value /= 0x100;
1627 break;
1628 }
1629 colorval |= (value << pos);
1630 pos += 0x8;
1631 if (i == 2)
1632 {
1633 UNBLOCK_INPUT;
1634 return (colorval);
1635 }
1636 color = end;
1637 }
1638 }
1639 }
1640 else if (strnicmp(colorname, "rgb:", 4) == 0)
1641 {
1642 char *color;
1643 UINT colorval;
1644 int i, pos;
1645 pos = 0;
1646
1647 colorval = 0;
1648 color = colorname + 4;
1649 for (i = 0; i < 3; i++)
1650 {
1651 char *end;
1652 unsigned long value;
1653
1654 /* The check for 'x' in the following conditional takes into
1655 account the fact that strtol allows a "0x" in front of
1656 our numbers, and we don't. */
1657 if (!isxdigit(color[0]) || color[1] == 'x')
1658 break;
1659 value = strtoul(color, &end, 16);
1660 if (errno == ERANGE)
1661 break;
1662 switch (end - color)
1663 {
1664 case 1:
1665 value = value * 0x10 + value;
1666 break;
1667 case 2:
1668 break;
1669 case 3:
1670 value /= 0x10;
1671 break;
1672 case 4:
1673 value /= 0x100;
1674 break;
1675 default:
1676 value = ULONG_MAX;
1677 }
1678 if (value == ULONG_MAX)
1679 break;
1680 colorval |= (value << pos);
1681 pos += 0x8;
1682 if (i == 2)
1683 {
1684 if (*end != '\0')
1685 break;
1686 UNBLOCK_INPUT;
1687 return (colorval);
1688 }
1689 if (*end != '/')
1690 break;
1691 color = end + 1;
1692 }
1693 }
1694 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1695 {
1696 /* This is an RGB Intensity specification. */
1697 char *color;
1698 UINT colorval;
1699 int i, pos;
1700 pos = 0;
1701
1702 colorval = 0;
1703 color = colorname + 5;
1704 for (i = 0; i < 3; i++)
1705 {
1706 char *end;
1707 double value;
1708 UINT val;
1709
1710 value = strtod(color, &end);
1711 if (errno == ERANGE)
1712 break;
1713 if (value < 0.0 || value > 1.0)
1714 break;
1715 val = (UINT)(0x100 * value);
1716 /* We used 0x100 instead of 0xFF to give an continuous
1717 range between 0.0 and 1.0 inclusive. The next statement
1718 fixes the 1.0 case. */
1719 if (val == 0x100)
1720 val = 0xFF;
1721 colorval |= (val << pos);
1722 pos += 0x8;
1723 if (i == 2)
1724 {
1725 if (*end != '\0')
1726 break;
1727 UNBLOCK_INPUT;
1728 return (colorval);
1729 }
1730 if (*end != '/')
1731 break;
1732 color = end + 1;
1733 }
1734 }
1735 /* I am not going to attempt to handle any of the CIE color schemes
1736 or TekHVC, since I don't know the algorithms for conversion to
1737 RGB. */
1738
1739 /* If we fail to lookup the color name in w32_color_map, then check the
1740 colorname to see if it can be crudely approximated: If the X color
1741 ends in a number (e.g., "darkseagreen2"), strip the number and
1742 return the result of looking up the base color name. */
1743 ret = w32_color_map_lookup (colorname);
1744 if (NILP (ret))
1745 {
1746 int len = strlen (colorname);
1747
1748 if (isdigit (colorname[len - 1]))
1749 {
1750 char *ptr, *approx = alloca (len + 1);
1751
1752 strcpy (approx, colorname);
1753 ptr = &approx[len - 1];
1754 while (ptr > approx && isdigit (*ptr))
1755 *ptr-- = '\0';
1756
1757 ret = w32_color_map_lookup (approx);
1758 }
1759 }
1760
1761 UNBLOCK_INPUT;
1762 return ret;
1763 }
1764
1765
1766 void
1767 w32_regenerate_palette (FRAME_PTR f)
1768 {
1769 struct w32_palette_entry * list;
1770 LOGPALETTE * log_palette;
1771 HPALETTE new_palette;
1772 int i;
1773
1774 /* don't bother trying to create palette if not supported */
1775 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1776 return;
1777
1778 log_palette = (LOGPALETTE *)
1779 alloca (sizeof (LOGPALETTE) +
1780 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1781 log_palette->palVersion = 0x300;
1782 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1783
1784 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1785 for (i = 0;
1786 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1787 i++, list = list->next)
1788 log_palette->palPalEntry[i] = list->entry;
1789
1790 new_palette = CreatePalette (log_palette);
1791
1792 enter_crit ();
1793
1794 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1795 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1796 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1797
1798 /* Realize display palette and garbage all frames. */
1799 release_frame_dc (f, get_frame_dc (f));
1800
1801 leave_crit ();
1802 }
1803
1804 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1805 #define SET_W32_COLOR(pe, color) \
1806 do \
1807 { \
1808 pe.peRed = GetRValue (color); \
1809 pe.peGreen = GetGValue (color); \
1810 pe.peBlue = GetBValue (color); \
1811 pe.peFlags = 0; \
1812 } while (0)
1813
1814 #if 0
1815 /* Keep these around in case we ever want to track color usage. */
1816 void
1817 w32_map_color (FRAME_PTR f, COLORREF color)
1818 {
1819 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1820
1821 if (NILP (Vw32_enable_palette))
1822 return;
1823
1824 /* check if color is already mapped */
1825 while (list)
1826 {
1827 if (W32_COLOR (list->entry) == color)
1828 {
1829 ++list->refcount;
1830 return;
1831 }
1832 list = list->next;
1833 }
1834
1835 /* not already mapped, so add to list and recreate Windows palette */
1836 list = (struct w32_palette_entry *)
1837 xmalloc (sizeof (struct w32_palette_entry));
1838 SET_W32_COLOR (list->entry, color);
1839 list->refcount = 1;
1840 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1841 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1842 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1843
1844 /* set flag that palette must be regenerated */
1845 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1846 }
1847
1848 void
1849 w32_unmap_color (FRAME_PTR f, COLORREF color)
1850 {
1851 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1852 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1853
1854 if (NILP (Vw32_enable_palette))
1855 return;
1856
1857 /* check if color is already mapped */
1858 while (list)
1859 {
1860 if (W32_COLOR (list->entry) == color)
1861 {
1862 if (--list->refcount == 0)
1863 {
1864 *prev = list->next;
1865 xfree (list);
1866 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1867 break;
1868 }
1869 else
1870 return;
1871 }
1872 prev = &list->next;
1873 list = list->next;
1874 }
1875
1876 /* set flag that palette must be regenerated */
1877 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1878 }
1879 #endif
1880
1881
1882 /* Gamma-correct COLOR on frame F. */
1883
1884 void
1885 gamma_correct (f, color)
1886 struct frame *f;
1887 COLORREF *color;
1888 {
1889 if (f->gamma)
1890 {
1891 *color = PALETTERGB (
1892 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1893 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1894 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1895 }
1896 }
1897
1898
1899 /* Decide if color named COLOR is valid for the display associated with
1900 the selected frame; if so, return the rgb values in COLOR_DEF.
1901 If ALLOC is nonzero, allocate a new colormap cell. */
1902
1903 int
1904 w32_defined_color (f, color, color_def, alloc)
1905 FRAME_PTR f;
1906 char *color;
1907 XColor *color_def;
1908 int alloc;
1909 {
1910 register Lisp_Object tem;
1911 COLORREF w32_color_ref;
1912
1913 tem = x_to_w32_color (color);
1914
1915 if (!NILP (tem))
1916 {
1917 if (f)
1918 {
1919 /* Apply gamma correction. */
1920 w32_color_ref = XUINT (tem);
1921 gamma_correct (f, &w32_color_ref);
1922 XSETINT (tem, w32_color_ref);
1923 }
1924
1925 /* Map this color to the palette if it is enabled. */
1926 if (!NILP (Vw32_enable_palette))
1927 {
1928 struct w32_palette_entry * entry =
1929 one_w32_display_info.color_list;
1930 struct w32_palette_entry ** prev =
1931 &one_w32_display_info.color_list;
1932
1933 /* check if color is already mapped */
1934 while (entry)
1935 {
1936 if (W32_COLOR (entry->entry) == XUINT (tem))
1937 break;
1938 prev = &entry->next;
1939 entry = entry->next;
1940 }
1941
1942 if (entry == NULL && alloc)
1943 {
1944 /* not already mapped, so add to list */
1945 entry = (struct w32_palette_entry *)
1946 xmalloc (sizeof (struct w32_palette_entry));
1947 SET_W32_COLOR (entry->entry, XUINT (tem));
1948 entry->next = NULL;
1949 *prev = entry;
1950 one_w32_display_info.num_colors++;
1951
1952 /* set flag that palette must be regenerated */
1953 one_w32_display_info.regen_palette = TRUE;
1954 }
1955 }
1956 /* Ensure COLORREF value is snapped to nearest color in (default)
1957 palette by simulating the PALETTERGB macro. This works whether
1958 or not the display device has a palette. */
1959 w32_color_ref = XUINT (tem) | 0x2000000;
1960
1961 color_def->pixel = w32_color_ref;
1962 color_def->red = GetRValue (w32_color_ref);
1963 color_def->green = GetGValue (w32_color_ref);
1964 color_def->blue = GetBValue (w32_color_ref);
1965
1966 return 1;
1967 }
1968 else
1969 {
1970 return 0;
1971 }
1972 }
1973
1974 /* Given a string ARG naming a color, compute a pixel value from it
1975 suitable for screen F.
1976 If F is not a color screen, return DEF (default) regardless of what
1977 ARG says. */
1978
1979 int
1980 x_decode_color (f, arg, def)
1981 FRAME_PTR f;
1982 Lisp_Object arg;
1983 int def;
1984 {
1985 XColor cdef;
1986
1987 CHECK_STRING (arg);
1988
1989 if (strcmp (XSTRING (arg)->data, "black") == 0)
1990 return BLACK_PIX_DEFAULT (f);
1991 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1992 return WHITE_PIX_DEFAULT (f);
1993
1994 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1995 return def;
1996
1997 /* w32_defined_color is responsible for coping with failures
1998 by looking for a near-miss. */
1999 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
2000 return cdef.pixel;
2001
2002 /* defined_color failed; return an ultimate default. */
2003 return def;
2004 }
2005 \f
2006 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2007 the previous value of that parameter, NEW_VALUE is the new value. */
2008
2009 static void
2010 x_set_line_spacing (f, new_value, old_value)
2011 struct frame *f;
2012 Lisp_Object new_value, old_value;
2013 {
2014 if (NILP (new_value))
2015 f->extra_line_spacing = 0;
2016 else if (NATNUMP (new_value))
2017 f->extra_line_spacing = XFASTINT (new_value);
2018 else
2019 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
2020 Fcons (new_value, Qnil)));
2021 if (FRAME_VISIBLE_P (f))
2022 redraw_frame (f);
2023 }
2024
2025
2026 /* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2027 the previous value of that parameter, NEW_VALUE is the new value. */
2028
2029 static void
2030 x_set_fullscreen (f, new_value, old_value)
2031 struct frame *f;
2032 Lisp_Object new_value, old_value;
2033 {
2034 if (NILP (new_value))
2035 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2036 else if (EQ (new_value, Qfullboth))
2037 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2038 else if (EQ (new_value, Qfullwidth))
2039 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2040 else if (EQ (new_value, Qfullheight))
2041 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2042 }
2043
2044
2045 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2046 the previous value of that parameter, NEW_VALUE is the new value. */
2047
2048 static void
2049 x_set_screen_gamma (f, new_value, old_value)
2050 struct frame *f;
2051 Lisp_Object new_value, old_value;
2052 {
2053 if (NILP (new_value))
2054 f->gamma = 0;
2055 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2056 /* The value 0.4545 is the normal viewing gamma. */
2057 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2058 else
2059 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
2060 Fcons (new_value, Qnil)));
2061
2062 clear_face_cache (0);
2063 }
2064
2065
2066 /* Functions called only from `x_set_frame_param'
2067 to set individual parameters.
2068
2069 If FRAME_W32_WINDOW (f) is 0,
2070 the frame is being created and its window does not exist yet.
2071 In that case, just record the parameter's new value
2072 in the standard place; do not attempt to change the window. */
2073
2074 void
2075 x_set_foreground_color (f, arg, oldval)
2076 struct frame *f;
2077 Lisp_Object arg, oldval;
2078 {
2079 struct w32_output *x = f->output_data.w32;
2080 PIX_TYPE fg, old_fg;
2081
2082 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2083 old_fg = FRAME_FOREGROUND_PIXEL (f);
2084 FRAME_FOREGROUND_PIXEL (f) = fg;
2085
2086 if (FRAME_W32_WINDOW (f) != 0)
2087 {
2088 if (x->cursor_pixel == old_fg)
2089 x->cursor_pixel = fg;
2090
2091 update_face_from_frame_parameter (f, Qforeground_color, arg);
2092 if (FRAME_VISIBLE_P (f))
2093 redraw_frame (f);
2094 }
2095 }
2096
2097 void
2098 x_set_background_color (f, arg, oldval)
2099 struct frame *f;
2100 Lisp_Object arg, oldval;
2101 {
2102 FRAME_BACKGROUND_PIXEL (f)
2103 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2104
2105 if (FRAME_W32_WINDOW (f) != 0)
2106 {
2107 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2108 FRAME_BACKGROUND_PIXEL (f));
2109
2110 update_face_from_frame_parameter (f, Qbackground_color, arg);
2111
2112 if (FRAME_VISIBLE_P (f))
2113 redraw_frame (f);
2114 }
2115 }
2116
2117 void
2118 x_set_mouse_color (f, arg, oldval)
2119 struct frame *f;
2120 Lisp_Object arg, oldval;
2121 {
2122 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2123 int count;
2124 int mask_color;
2125
2126 if (!EQ (Qnil, arg))
2127 f->output_data.w32->mouse_pixel
2128 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2129 mask_color = FRAME_BACKGROUND_PIXEL (f);
2130
2131 /* Don't let pointers be invisible. */
2132 if (mask_color == f->output_data.w32->mouse_pixel
2133 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2134 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2135
2136 #if 0 /* TODO : cursor changes */
2137 BLOCK_INPUT;
2138
2139 /* It's not okay to crash if the user selects a screwy cursor. */
2140 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2141
2142 if (!EQ (Qnil, Vx_pointer_shape))
2143 {
2144 CHECK_NUMBER (Vx_pointer_shape);
2145 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2146 }
2147 else
2148 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2149 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2150
2151 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2152 {
2153 CHECK_NUMBER (Vx_nontext_pointer_shape);
2154 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2155 XINT (Vx_nontext_pointer_shape));
2156 }
2157 else
2158 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2159 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2160
2161 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2162 {
2163 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2164 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2165 XINT (Vx_hourglass_pointer_shape));
2166 }
2167 else
2168 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2169 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2170
2171 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2172 if (!EQ (Qnil, Vx_mode_pointer_shape))
2173 {
2174 CHECK_NUMBER (Vx_mode_pointer_shape);
2175 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2176 XINT (Vx_mode_pointer_shape));
2177 }
2178 else
2179 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2180 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2181
2182 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2183 {
2184 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2185 cross_cursor
2186 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2187 XINT (Vx_sensitive_text_pointer_shape));
2188 }
2189 else
2190 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2191
2192 if (!NILP (Vx_window_horizontal_drag_shape))
2193 {
2194 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2195 horizontal_drag_cursor
2196 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2197 XINT (Vx_window_horizontal_drag_shape));
2198 }
2199 else
2200 horizontal_drag_cursor
2201 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2202
2203 /* Check and report errors with the above calls. */
2204 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2205 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2206
2207 {
2208 XColor fore_color, back_color;
2209
2210 fore_color.pixel = f->output_data.w32->mouse_pixel;
2211 back_color.pixel = mask_color;
2212 XQueryColor (FRAME_W32_DISPLAY (f),
2213 DefaultColormap (FRAME_W32_DISPLAY (f),
2214 DefaultScreen (FRAME_W32_DISPLAY (f))),
2215 &fore_color);
2216 XQueryColor (FRAME_W32_DISPLAY (f),
2217 DefaultColormap (FRAME_W32_DISPLAY (f),
2218 DefaultScreen (FRAME_W32_DISPLAY (f))),
2219 &back_color);
2220 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2221 &fore_color, &back_color);
2222 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2223 &fore_color, &back_color);
2224 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2225 &fore_color, &back_color);
2226 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2227 &fore_color, &back_color);
2228 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2229 &fore_color, &back_color);
2230 }
2231
2232 if (FRAME_W32_WINDOW (f) != 0)
2233 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2234
2235 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2236 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2237 f->output_data.w32->text_cursor = cursor;
2238
2239 if (nontext_cursor != f->output_data.w32->nontext_cursor
2240 && f->output_data.w32->nontext_cursor != 0)
2241 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2242 f->output_data.w32->nontext_cursor = nontext_cursor;
2243
2244 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2245 && f->output_data.w32->hourglass_cursor != 0)
2246 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2247 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2248
2249 if (mode_cursor != f->output_data.w32->modeline_cursor
2250 && f->output_data.w32->modeline_cursor != 0)
2251 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2252 f->output_data.w32->modeline_cursor = mode_cursor;
2253
2254 if (cross_cursor != f->output_data.w32->cross_cursor
2255 && f->output_data.w32->cross_cursor != 0)
2256 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2257 f->output_data.w32->cross_cursor = cross_cursor;
2258
2259 XFlush (FRAME_W32_DISPLAY (f));
2260 UNBLOCK_INPUT;
2261
2262 update_face_from_frame_parameter (f, Qmouse_color, arg);
2263 #endif /* TODO */
2264 }
2265
2266 /* Defined in w32term.c. */
2267 void x_update_cursor (struct frame *f, int on_p);
2268
2269 void
2270 x_set_cursor_color (f, arg, oldval)
2271 struct frame *f;
2272 Lisp_Object arg, oldval;
2273 {
2274 unsigned long fore_pixel, pixel;
2275
2276 if (!NILP (Vx_cursor_fore_pixel))
2277 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2278 WHITE_PIX_DEFAULT (f));
2279 else
2280 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2281
2282 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2283
2284 /* Make sure that the cursor color differs from the background color. */
2285 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2286 {
2287 pixel = f->output_data.w32->mouse_pixel;
2288 if (pixel == fore_pixel)
2289 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2290 }
2291
2292 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
2293 f->output_data.w32->cursor_pixel = pixel;
2294
2295 if (FRAME_W32_WINDOW (f) != 0)
2296 {
2297 BLOCK_INPUT;
2298 /* Update frame's cursor_gc. */
2299 f->output_data.w32->cursor_gc->foreground = fore_pixel;
2300 f->output_data.w32->cursor_gc->background = pixel;
2301
2302 UNBLOCK_INPUT;
2303
2304 if (FRAME_VISIBLE_P (f))
2305 {
2306 x_update_cursor (f, 0);
2307 x_update_cursor (f, 1);
2308 }
2309 }
2310
2311 update_face_from_frame_parameter (f, Qcursor_color, arg);
2312 }
2313
2314 /* Set the border-color of frame F to pixel value PIX.
2315 Note that this does not fully take effect if done before
2316 F has an window. */
2317 void
2318 x_set_border_pixel (f, pix)
2319 struct frame *f;
2320 int pix;
2321 {
2322 f->output_data.w32->border_pixel = pix;
2323
2324 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2325 {
2326 if (FRAME_VISIBLE_P (f))
2327 redraw_frame (f);
2328 }
2329 }
2330
2331 /* Set the border-color of frame F to value described by ARG.
2332 ARG can be a string naming a color.
2333 The border-color is used for the border that is drawn by the server.
2334 Note that this does not fully take effect if done before
2335 F has a window; it must be redone when the window is created. */
2336
2337 void
2338 x_set_border_color (f, arg, oldval)
2339 struct frame *f;
2340 Lisp_Object arg, oldval;
2341 {
2342 int pix;
2343
2344 CHECK_STRING (arg);
2345 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2346 x_set_border_pixel (f, pix);
2347 update_face_from_frame_parameter (f, Qborder_color, arg);
2348 }
2349
2350 /* Value is the internal representation of the specified cursor type
2351 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2352 of the bar cursor. */
2353
2354 enum text_cursor_kinds
2355 x_specified_cursor_type (arg, width)
2356 Lisp_Object arg;
2357 int *width;
2358 {
2359 enum text_cursor_kinds type;
2360
2361 if (EQ (arg, Qbar))
2362 {
2363 type = BAR_CURSOR;
2364 *width = 2;
2365 }
2366 else if (CONSP (arg)
2367 && EQ (XCAR (arg), Qbar)
2368 && INTEGERP (XCDR (arg))
2369 && XINT (XCDR (arg)) >= 0)
2370 {
2371 type = BAR_CURSOR;
2372 *width = XINT (XCDR (arg));
2373 }
2374 else if (EQ (arg, Qhbar))
2375 {
2376 type = HBAR_CURSOR;
2377 *width = 2;
2378 }
2379 else if (CONSP (arg)
2380 && EQ (XCAR (arg), Qhbar)
2381 && INTEGERP (XCDR (arg))
2382 && XINT (XCDR (arg)) >= 0)
2383 {
2384 type = HBAR_CURSOR;
2385 *width = XINT (XCDR (arg));
2386 }
2387 else if (NILP (arg))
2388 type = NO_CURSOR;
2389 else
2390 /* Treat anything unknown as "box cursor".
2391 It was bad to signal an error; people have trouble fixing
2392 .Xdefaults with Emacs, when it has something bad in it. */
2393 type = FILLED_BOX_CURSOR;
2394
2395 return type;
2396 }
2397
2398 void
2399 x_set_cursor_type (f, arg, oldval)
2400 FRAME_PTR f;
2401 Lisp_Object arg, oldval;
2402 {
2403 int width;
2404
2405 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2406 f->output_data.w32->cursor_width = width;
2407
2408 /* Make sure the cursor gets redrawn. This is overkill, but how
2409 often do people change cursor types? */
2410 update_mode_lines++;
2411 }
2412 \f
2413 void
2414 x_set_icon_type (f, arg, oldval)
2415 struct frame *f;
2416 Lisp_Object arg, oldval;
2417 {
2418 int result;
2419
2420 if (NILP (arg) && NILP (oldval))
2421 return;
2422
2423 if (STRINGP (arg) && STRINGP (oldval)
2424 && EQ (Fstring_equal (oldval, arg), Qt))
2425 return;
2426
2427 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2428 return;
2429
2430 BLOCK_INPUT;
2431
2432 result = x_bitmap_icon (f, arg);
2433 if (result)
2434 {
2435 UNBLOCK_INPUT;
2436 error ("No icon window available");
2437 }
2438
2439 UNBLOCK_INPUT;
2440 }
2441
2442 /* Return non-nil if frame F wants a bitmap icon. */
2443
2444 Lisp_Object
2445 x_icon_type (f)
2446 FRAME_PTR f;
2447 {
2448 Lisp_Object tem;
2449
2450 tem = assq_no_quit (Qicon_type, f->param_alist);
2451 if (CONSP (tem))
2452 return XCDR (tem);
2453 else
2454 return Qnil;
2455 }
2456
2457 void
2458 x_set_icon_name (f, arg, oldval)
2459 struct frame *f;
2460 Lisp_Object arg, oldval;
2461 {
2462 if (STRINGP (arg))
2463 {
2464 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2465 return;
2466 }
2467 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2468 return;
2469
2470 f->icon_name = arg;
2471
2472 #if 0
2473 if (f->output_data.w32->icon_bitmap != 0)
2474 return;
2475
2476 BLOCK_INPUT;
2477
2478 result = x_text_icon (f,
2479 (char *) XSTRING ((!NILP (f->icon_name)
2480 ? f->icon_name
2481 : !NILP (f->title)
2482 ? f->title
2483 : f->name))->data);
2484
2485 if (result)
2486 {
2487 UNBLOCK_INPUT;
2488 error ("No icon window available");
2489 }
2490
2491 /* If the window was unmapped (and its icon was mapped),
2492 the new icon is not mapped, so map the window in its stead. */
2493 if (FRAME_VISIBLE_P (f))
2494 {
2495 #ifdef USE_X_TOOLKIT
2496 XtPopup (f->output_data.w32->widget, XtGrabNone);
2497 #endif
2498 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2499 }
2500
2501 XFlush (FRAME_W32_DISPLAY (f));
2502 UNBLOCK_INPUT;
2503 #endif
2504 }
2505
2506 extern Lisp_Object x_new_font ();
2507 extern Lisp_Object x_new_fontset();
2508
2509 void
2510 x_set_font (f, arg, oldval)
2511 struct frame *f;
2512 Lisp_Object arg, oldval;
2513 {
2514 Lisp_Object result;
2515 Lisp_Object fontset_name;
2516 Lisp_Object frame;
2517 int old_fontset = FRAME_FONTSET(f);
2518
2519 CHECK_STRING (arg);
2520
2521 fontset_name = Fquery_fontset (arg, Qnil);
2522
2523 BLOCK_INPUT;
2524 result = (STRINGP (fontset_name)
2525 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2526 : x_new_font (f, XSTRING (arg)->data));
2527 UNBLOCK_INPUT;
2528
2529 if (EQ (result, Qnil))
2530 error ("Font `%s' is not defined", XSTRING (arg)->data);
2531 else if (EQ (result, Qt))
2532 error ("The characters of the given font have varying widths");
2533 else if (STRINGP (result))
2534 {
2535 if (STRINGP (fontset_name))
2536 {
2537 /* Fontset names are built from ASCII font names, so the
2538 names may be equal despite there was a change. */
2539 if (old_fontset == FRAME_FONTSET (f))
2540 return;
2541 }
2542 else if (!NILP (Fequal (result, oldval)))
2543 return;
2544
2545 store_frame_param (f, Qfont, result);
2546 recompute_basic_faces (f);
2547 }
2548 else
2549 abort ();
2550
2551 do_pending_window_change (0);
2552
2553 /* Don't call `face-set-after-frame-default' when faces haven't been
2554 initialized yet. This is the case when called from
2555 Fx_create_frame. In that case, the X widget or window doesn't
2556 exist either, and we can end up in x_report_frame_params with a
2557 null widget which gives a segfault. */
2558 if (FRAME_FACE_CACHE (f))
2559 {
2560 XSETFRAME (frame, f);
2561 call1 (Qface_set_after_frame_default, frame);
2562 }
2563 }
2564
2565 static void
2566 x_set_fringe_width (f, new_value, old_value)
2567 struct frame *f;
2568 Lisp_Object new_value, old_value;
2569 {
2570 x_compute_fringe_widths (f, 1);
2571 }
2572
2573 void
2574 x_set_border_width (f, arg, oldval)
2575 struct frame *f;
2576 Lisp_Object arg, oldval;
2577 {
2578 CHECK_NUMBER (arg);
2579
2580 if (XINT (arg) == f->output_data.w32->border_width)
2581 return;
2582
2583 if (FRAME_W32_WINDOW (f) != 0)
2584 error ("Cannot change the border width of a window");
2585
2586 f->output_data.w32->border_width = XINT (arg);
2587 }
2588
2589 void
2590 x_set_internal_border_width (f, arg, oldval)
2591 struct frame *f;
2592 Lisp_Object arg, oldval;
2593 {
2594 int old = f->output_data.w32->internal_border_width;
2595
2596 CHECK_NUMBER (arg);
2597 f->output_data.w32->internal_border_width = XINT (arg);
2598 if (f->output_data.w32->internal_border_width < 0)
2599 f->output_data.w32->internal_border_width = 0;
2600
2601 if (f->output_data.w32->internal_border_width == old)
2602 return;
2603
2604 if (FRAME_W32_WINDOW (f) != 0)
2605 {
2606 x_set_window_size (f, 0, f->width, f->height);
2607 SET_FRAME_GARBAGED (f);
2608 do_pending_window_change (0);
2609 }
2610 else
2611 SET_FRAME_GARBAGED (f);
2612 }
2613
2614 void
2615 x_set_visibility (f, value, oldval)
2616 struct frame *f;
2617 Lisp_Object value, oldval;
2618 {
2619 Lisp_Object frame;
2620 XSETFRAME (frame, f);
2621
2622 if (NILP (value))
2623 Fmake_frame_invisible (frame, Qt);
2624 else if (EQ (value, Qicon))
2625 Ficonify_frame (frame);
2626 else
2627 Fmake_frame_visible (frame);
2628 }
2629
2630 \f
2631 /* Change window heights in windows rooted in WINDOW by N lines. */
2632
2633 static void
2634 x_change_window_heights (window, n)
2635 Lisp_Object window;
2636 int n;
2637 {
2638 struct window *w = XWINDOW (window);
2639
2640 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2641 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2642
2643 if (INTEGERP (w->orig_top))
2644 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2645 if (INTEGERP (w->orig_height))
2646 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2647
2648 /* Handle just the top child in a vertical split. */
2649 if (!NILP (w->vchild))
2650 x_change_window_heights (w->vchild, n);
2651
2652 /* Adjust all children in a horizontal split. */
2653 for (window = w->hchild; !NILP (window); window = w->next)
2654 {
2655 w = XWINDOW (window);
2656 x_change_window_heights (window, n);
2657 }
2658 }
2659
2660 void
2661 x_set_menu_bar_lines (f, value, oldval)
2662 struct frame *f;
2663 Lisp_Object value, oldval;
2664 {
2665 int nlines;
2666 int olines = FRAME_MENU_BAR_LINES (f);
2667
2668 /* Right now, menu bars don't work properly in minibuf-only frames;
2669 most of the commands try to apply themselves to the minibuffer
2670 frame itself, and get an error because you can't switch buffers
2671 in or split the minibuffer window. */
2672 if (FRAME_MINIBUF_ONLY_P (f))
2673 return;
2674
2675 if (INTEGERP (value))
2676 nlines = XINT (value);
2677 else
2678 nlines = 0;
2679
2680 FRAME_MENU_BAR_LINES (f) = 0;
2681 if (nlines)
2682 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2683 else
2684 {
2685 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2686 free_frame_menubar (f);
2687 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2688
2689 /* Adjust the frame size so that the client (text) dimensions
2690 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2691 set correctly. */
2692 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2693 do_pending_window_change (0);
2694 }
2695 adjust_glyphs (f);
2696 }
2697
2698
2699 /* Set the number of lines used for the tool bar of frame F to VALUE.
2700 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2701 is the old number of tool bar lines. This function changes the
2702 height of all windows on frame F to match the new tool bar height.
2703 The frame's height doesn't change. */
2704
2705 void
2706 x_set_tool_bar_lines (f, value, oldval)
2707 struct frame *f;
2708 Lisp_Object value, oldval;
2709 {
2710 int delta, nlines, root_height;
2711 Lisp_Object root_window;
2712
2713 /* Treat tool bars like menu bars. */
2714 if (FRAME_MINIBUF_ONLY_P (f))
2715 return;
2716
2717 /* Use VALUE only if an integer >= 0. */
2718 if (INTEGERP (value) && XINT (value) >= 0)
2719 nlines = XFASTINT (value);
2720 else
2721 nlines = 0;
2722
2723 /* Make sure we redisplay all windows in this frame. */
2724 ++windows_or_buffers_changed;
2725
2726 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2727
2728 /* Don't resize the tool-bar to more than we have room for. */
2729 root_window = FRAME_ROOT_WINDOW (f);
2730 root_height = XINT (XWINDOW (root_window)->height);
2731 if (root_height - delta < 1)
2732 {
2733 delta = root_height - 1;
2734 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2735 }
2736
2737 FRAME_TOOL_BAR_LINES (f) = nlines;
2738 x_change_window_heights (root_window, delta);
2739 adjust_glyphs (f);
2740
2741 /* We also have to make sure that the internal border at the top of
2742 the frame, below the menu bar or tool bar, is redrawn when the
2743 tool bar disappears. This is so because the internal border is
2744 below the tool bar if one is displayed, but is below the menu bar
2745 if there isn't a tool bar. The tool bar draws into the area
2746 below the menu bar. */
2747 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2748 {
2749 updating_frame = f;
2750 clear_frame ();
2751 clear_current_matrices (f);
2752 updating_frame = NULL;
2753 }
2754
2755 /* If the tool bar gets smaller, the internal border below it
2756 has to be cleared. It was formerly part of the display
2757 of the larger tool bar, and updating windows won't clear it. */
2758 if (delta < 0)
2759 {
2760 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2761 int width = PIXEL_WIDTH (f);
2762 int y = nlines * CANON_Y_UNIT (f);
2763
2764 BLOCK_INPUT;
2765 {
2766 HDC hdc = get_frame_dc (f);
2767 w32_clear_area (f, hdc, 0, y, width, height);
2768 release_frame_dc (f, hdc);
2769 }
2770 UNBLOCK_INPUT;
2771
2772 if (WINDOWP (f->tool_bar_window))
2773 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2774 }
2775 }
2776
2777
2778 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2779 w32_id_name.
2780
2781 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2782 name; if NAME is a string, set F's name to NAME and set
2783 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2784
2785 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2786 suggesting a new name, which lisp code should override; if
2787 F->explicit_name is set, ignore the new name; otherwise, set it. */
2788
2789 void
2790 x_set_name (f, name, explicit)
2791 struct frame *f;
2792 Lisp_Object name;
2793 int explicit;
2794 {
2795 /* Make sure that requests from lisp code override requests from
2796 Emacs redisplay code. */
2797 if (explicit)
2798 {
2799 /* If we're switching from explicit to implicit, we had better
2800 update the mode lines and thereby update the title. */
2801 if (f->explicit_name && NILP (name))
2802 update_mode_lines = 1;
2803
2804 f->explicit_name = ! NILP (name);
2805 }
2806 else if (f->explicit_name)
2807 return;
2808
2809 /* If NAME is nil, set the name to the w32_id_name. */
2810 if (NILP (name))
2811 {
2812 /* Check for no change needed in this very common case
2813 before we do any consing. */
2814 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2815 XSTRING (f->name)->data))
2816 return;
2817 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2818 }
2819 else
2820 CHECK_STRING (name);
2821
2822 /* Don't change the name if it's already NAME. */
2823 if (! NILP (Fstring_equal (name, f->name)))
2824 return;
2825
2826 f->name = name;
2827
2828 /* For setting the frame title, the title parameter should override
2829 the name parameter. */
2830 if (! NILP (f->title))
2831 name = f->title;
2832
2833 if (FRAME_W32_WINDOW (f))
2834 {
2835 if (STRING_MULTIBYTE (name))
2836 name = ENCODE_SYSTEM (name);
2837
2838 BLOCK_INPUT;
2839 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2840 UNBLOCK_INPUT;
2841 }
2842 }
2843
2844 /* This function should be called when the user's lisp code has
2845 specified a name for the frame; the name will override any set by the
2846 redisplay code. */
2847 void
2848 x_explicitly_set_name (f, arg, oldval)
2849 FRAME_PTR f;
2850 Lisp_Object arg, oldval;
2851 {
2852 x_set_name (f, arg, 1);
2853 }
2854
2855 /* This function should be called by Emacs redisplay code to set the
2856 name; names set this way will never override names set by the user's
2857 lisp code. */
2858 void
2859 x_implicitly_set_name (f, arg, oldval)
2860 FRAME_PTR f;
2861 Lisp_Object arg, oldval;
2862 {
2863 x_set_name (f, arg, 0);
2864 }
2865 \f
2866 /* Change the title of frame F to NAME.
2867 If NAME is nil, use the frame name as the title.
2868
2869 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2870 name; if NAME is a string, set F's name to NAME and set
2871 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2872
2873 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2874 suggesting a new name, which lisp code should override; if
2875 F->explicit_name is set, ignore the new name; otherwise, set it. */
2876
2877 void
2878 x_set_title (f, name, old_name)
2879 struct frame *f;
2880 Lisp_Object name, old_name;
2881 {
2882 /* Don't change the title if it's already NAME. */
2883 if (EQ (name, f->title))
2884 return;
2885
2886 update_mode_lines = 1;
2887
2888 f->title = name;
2889
2890 if (NILP (name))
2891 name = f->name;
2892
2893 if (FRAME_W32_WINDOW (f))
2894 {
2895 if (STRING_MULTIBYTE (name))
2896 name = ENCODE_SYSTEM (name);
2897
2898 BLOCK_INPUT;
2899 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2900 UNBLOCK_INPUT;
2901 }
2902 }
2903 \f
2904 void
2905 x_set_autoraise (f, arg, oldval)
2906 struct frame *f;
2907 Lisp_Object arg, oldval;
2908 {
2909 f->auto_raise = !EQ (Qnil, arg);
2910 }
2911
2912 void
2913 x_set_autolower (f, arg, oldval)
2914 struct frame *f;
2915 Lisp_Object arg, oldval;
2916 {
2917 f->auto_lower = !EQ (Qnil, arg);
2918 }
2919
2920 void
2921 x_set_unsplittable (f, arg, oldval)
2922 struct frame *f;
2923 Lisp_Object arg, oldval;
2924 {
2925 f->no_split = !NILP (arg);
2926 }
2927
2928 void
2929 x_set_vertical_scroll_bars (f, arg, oldval)
2930 struct frame *f;
2931 Lisp_Object arg, oldval;
2932 {
2933 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2934 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2935 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2936 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2937 {
2938 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2939 vertical_scroll_bar_none :
2940 /* Put scroll bars on the right by default, as is conventional
2941 on MS-Windows. */
2942 EQ (Qleft, arg)
2943 ? vertical_scroll_bar_left
2944 : vertical_scroll_bar_right;
2945
2946 /* We set this parameter before creating the window for the
2947 frame, so we can get the geometry right from the start.
2948 However, if the window hasn't been created yet, we shouldn't
2949 call x_set_window_size. */
2950 if (FRAME_W32_WINDOW (f))
2951 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2952 do_pending_window_change (0);
2953 }
2954 }
2955
2956 void
2957 x_set_scroll_bar_width (f, arg, oldval)
2958 struct frame *f;
2959 Lisp_Object arg, oldval;
2960 {
2961 int wid = FONT_WIDTH (f->output_data.w32->font);
2962
2963 if (NILP (arg))
2964 {
2965 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2966 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2967 wid - 1) / wid;
2968 if (FRAME_W32_WINDOW (f))
2969 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2970 do_pending_window_change (0);
2971 }
2972 else if (INTEGERP (arg) && XINT (arg) > 0
2973 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2974 {
2975 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2976 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2977 + wid-1) / wid;
2978 if (FRAME_W32_WINDOW (f))
2979 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2980 do_pending_window_change (0);
2981 }
2982 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2983 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2984 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2985 }
2986 \f
2987 /* Subroutines of creating an frame. */
2988
2989 /* Make sure that Vx_resource_name is set to a reasonable value.
2990 Fix it up, or set it to `emacs' if it is too hopeless. */
2991
2992 static void
2993 validate_x_resource_name ()
2994 {
2995 int len = 0;
2996 /* Number of valid characters in the resource name. */
2997 int good_count = 0;
2998 /* Number of invalid characters in the resource name. */
2999 int bad_count = 0;
3000 Lisp_Object new;
3001 int i;
3002
3003 if (STRINGP (Vx_resource_name))
3004 {
3005 unsigned char *p = XSTRING (Vx_resource_name)->data;
3006 int i;
3007
3008 len = STRING_BYTES (XSTRING (Vx_resource_name));
3009
3010 /* Only letters, digits, - and _ are valid in resource names.
3011 Count the valid characters and count the invalid ones. */
3012 for (i = 0; i < len; i++)
3013 {
3014 int c = p[i];
3015 if (! ((c >= 'a' && c <= 'z')
3016 || (c >= 'A' && c <= 'Z')
3017 || (c >= '0' && c <= '9')
3018 || c == '-' || c == '_'))
3019 bad_count++;
3020 else
3021 good_count++;
3022 }
3023 }
3024 else
3025 /* Not a string => completely invalid. */
3026 bad_count = 5, good_count = 0;
3027
3028 /* If name is valid already, return. */
3029 if (bad_count == 0)
3030 return;
3031
3032 /* If name is entirely invalid, or nearly so, use `emacs'. */
3033 if (good_count == 0
3034 || (good_count == 1 && bad_count > 0))
3035 {
3036 Vx_resource_name = build_string ("emacs");
3037 return;
3038 }
3039
3040 /* Name is partly valid. Copy it and replace the invalid characters
3041 with underscores. */
3042
3043 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3044
3045 for (i = 0; i < len; i++)
3046 {
3047 int c = XSTRING (new)->data[i];
3048 if (! ((c >= 'a' && c <= 'z')
3049 || (c >= 'A' && c <= 'Z')
3050 || (c >= '0' && c <= '9')
3051 || c == '-' || c == '_'))
3052 XSTRING (new)->data[i] = '_';
3053 }
3054 }
3055
3056
3057 extern char *x_get_string_resource ();
3058
3059 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3060 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3061 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3062 class, where INSTANCE is the name under which Emacs was invoked, or
3063 the name specified by the `-name' or `-rn' command-line arguments.
3064
3065 The optional arguments COMPONENT and SUBCLASS add to the key and the
3066 class, respectively. You must specify both of them or neither.
3067 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3068 and the class is `Emacs.CLASS.SUBCLASS'. */)
3069 (attribute, class, component, subclass)
3070 Lisp_Object attribute, class, component, subclass;
3071 {
3072 register char *value;
3073 char *name_key;
3074 char *class_key;
3075
3076 CHECK_STRING (attribute);
3077 CHECK_STRING (class);
3078
3079 if (!NILP (component))
3080 CHECK_STRING (component);
3081 if (!NILP (subclass))
3082 CHECK_STRING (subclass);
3083 if (NILP (component) != NILP (subclass))
3084 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3085
3086 validate_x_resource_name ();
3087
3088 /* Allocate space for the components, the dots which separate them,
3089 and the final '\0'. Make them big enough for the worst case. */
3090 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
3091 + (STRINGP (component)
3092 ? STRING_BYTES (XSTRING (component)) : 0)
3093 + STRING_BYTES (XSTRING (attribute))
3094 + 3);
3095
3096 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3097 + STRING_BYTES (XSTRING (class))
3098 + (STRINGP (subclass)
3099 ? STRING_BYTES (XSTRING (subclass)) : 0)
3100 + 3);
3101
3102 /* Start with emacs.FRAMENAME for the name (the specific one)
3103 and with `Emacs' for the class key (the general one). */
3104 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3105 strcpy (class_key, EMACS_CLASS);
3106
3107 strcat (class_key, ".");
3108 strcat (class_key, XSTRING (class)->data);
3109
3110 if (!NILP (component))
3111 {
3112 strcat (class_key, ".");
3113 strcat (class_key, XSTRING (subclass)->data);
3114
3115 strcat (name_key, ".");
3116 strcat (name_key, XSTRING (component)->data);
3117 }
3118
3119 strcat (name_key, ".");
3120 strcat (name_key, XSTRING (attribute)->data);
3121
3122 value = x_get_string_resource (Qnil,
3123 name_key, class_key);
3124
3125 if (value != (char *) 0)
3126 return build_string (value);
3127 else
3128 return Qnil;
3129 }
3130
3131 /* Used when C code wants a resource value. */
3132
3133 char *
3134 x_get_resource_string (attribute, class)
3135 char *attribute, *class;
3136 {
3137 char *name_key;
3138 char *class_key;
3139 struct frame *sf = SELECTED_FRAME ();
3140
3141 /* Allocate space for the components, the dots which separate them,
3142 and the final '\0'. */
3143 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3144 + strlen (attribute) + 2);
3145 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3146 + strlen (class) + 2);
3147
3148 sprintf (name_key, "%s.%s",
3149 XSTRING (Vinvocation_name)->data,
3150 attribute);
3151 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3152
3153 return x_get_string_resource (sf, name_key, class_key);
3154 }
3155
3156 /* Types we might convert a resource string into. */
3157 enum resource_types
3158 {
3159 RES_TYPE_NUMBER,
3160 RES_TYPE_FLOAT,
3161 RES_TYPE_BOOLEAN,
3162 RES_TYPE_STRING,
3163 RES_TYPE_SYMBOL
3164 };
3165
3166 /* Return the value of parameter PARAM.
3167
3168 First search ALIST, then Vdefault_frame_alist, then the X defaults
3169 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3170
3171 Convert the resource to the type specified by desired_type.
3172
3173 If no default is specified, return Qunbound. If you call
3174 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3175 and don't let it get stored in any Lisp-visible variables! */
3176
3177 static Lisp_Object
3178 w32_get_arg (alist, param, attribute, class, type)
3179 Lisp_Object alist, param;
3180 char *attribute;
3181 char *class;
3182 enum resource_types type;
3183 {
3184 register Lisp_Object tem;
3185
3186 tem = Fassq (param, alist);
3187 if (EQ (tem, Qnil))
3188 tem = Fassq (param, Vdefault_frame_alist);
3189 if (EQ (tem, Qnil))
3190 {
3191
3192 if (attribute)
3193 {
3194 tem = Fx_get_resource (build_string (attribute),
3195 build_string (class),
3196 Qnil, Qnil);
3197
3198 if (NILP (tem))
3199 return Qunbound;
3200
3201 switch (type)
3202 {
3203 case RES_TYPE_NUMBER:
3204 return make_number (atoi (XSTRING (tem)->data));
3205
3206 case RES_TYPE_FLOAT:
3207 return make_float (atof (XSTRING (tem)->data));
3208
3209 case RES_TYPE_BOOLEAN:
3210 tem = Fdowncase (tem);
3211 if (!strcmp (XSTRING (tem)->data, "on")
3212 || !strcmp (XSTRING (tem)->data, "true"))
3213 return Qt;
3214 else
3215 return Qnil;
3216
3217 case RES_TYPE_STRING:
3218 return tem;
3219
3220 case RES_TYPE_SYMBOL:
3221 /* As a special case, we map the values `true' and `on'
3222 to Qt, and `false' and `off' to Qnil. */
3223 {
3224 Lisp_Object lower;
3225 lower = Fdowncase (tem);
3226 if (!strcmp (XSTRING (lower)->data, "on")
3227 || !strcmp (XSTRING (lower)->data, "true"))
3228 return Qt;
3229 else if (!strcmp (XSTRING (lower)->data, "off")
3230 || !strcmp (XSTRING (lower)->data, "false"))
3231 return Qnil;
3232 else
3233 return Fintern (tem, Qnil);
3234 }
3235
3236 default:
3237 abort ();
3238 }
3239 }
3240 else
3241 return Qunbound;
3242 }
3243 return Fcdr (tem);
3244 }
3245
3246 /* Record in frame F the specified or default value according to ALIST
3247 of the parameter named PROP (a Lisp symbol).
3248 If no value is specified for PROP, look for an X default for XPROP
3249 on the frame named NAME.
3250 If that is not found either, use the value DEFLT. */
3251
3252 static Lisp_Object
3253 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3254 struct frame *f;
3255 Lisp_Object alist;
3256 Lisp_Object prop;
3257 Lisp_Object deflt;
3258 char *xprop;
3259 char *xclass;
3260 enum resource_types type;
3261 {
3262 Lisp_Object tem;
3263
3264 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3265 if (EQ (tem, Qunbound))
3266 tem = deflt;
3267 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3268 return tem;
3269 }
3270 \f
3271 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3272 doc: /* Parse an X-style geometry string STRING.
3273 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3274 The properties returned may include `top', `left', `height', and `width'.
3275 The value of `left' or `top' may be an integer,
3276 or a list (+ N) meaning N pixels relative to top/left corner,
3277 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3278 (string)
3279 Lisp_Object string;
3280 {
3281 int geometry, x, y;
3282 unsigned int width, height;
3283 Lisp_Object result;
3284
3285 CHECK_STRING (string);
3286
3287 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3288 &x, &y, &width, &height);
3289
3290 result = Qnil;
3291 if (geometry & XValue)
3292 {
3293 Lisp_Object element;
3294
3295 if (x >= 0 && (geometry & XNegative))
3296 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3297 else if (x < 0 && ! (geometry & XNegative))
3298 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3299 else
3300 element = Fcons (Qleft, make_number (x));
3301 result = Fcons (element, result);
3302 }
3303
3304 if (geometry & YValue)
3305 {
3306 Lisp_Object element;
3307
3308 if (y >= 0 && (geometry & YNegative))
3309 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3310 else if (y < 0 && ! (geometry & YNegative))
3311 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3312 else
3313 element = Fcons (Qtop, make_number (y));
3314 result = Fcons (element, result);
3315 }
3316
3317 if (geometry & WidthValue)
3318 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3319 if (geometry & HeightValue)
3320 result = Fcons (Fcons (Qheight, make_number (height)), result);
3321
3322 return result;
3323 }
3324
3325 /* Calculate the desired size and position of this window,
3326 and return the flags saying which aspects were specified.
3327
3328 This function does not make the coordinates positive. */
3329
3330 #define DEFAULT_ROWS 40
3331 #define DEFAULT_COLS 80
3332
3333 static int
3334 x_figure_window_size (f, parms)
3335 struct frame *f;
3336 Lisp_Object parms;
3337 {
3338 register Lisp_Object tem0, tem1, tem2;
3339 long window_prompting = 0;
3340
3341 /* Default values if we fall through.
3342 Actually, if that happens we should get
3343 window manager prompting. */
3344 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3345 f->height = DEFAULT_ROWS;
3346 /* Window managers expect that if program-specified
3347 positions are not (0,0), they're intentional, not defaults. */
3348 f->output_data.w32->top_pos = 0;
3349 f->output_data.w32->left_pos = 0;
3350
3351 /* Ensure that old new_width and new_height will not override the
3352 values set here. */
3353 FRAME_NEW_WIDTH (f) = 0;
3354 FRAME_NEW_HEIGHT (f) = 0;
3355
3356 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3357 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3358 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3359 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3360 {
3361 if (!EQ (tem0, Qunbound))
3362 {
3363 CHECK_NUMBER (tem0);
3364 f->height = XINT (tem0);
3365 }
3366 if (!EQ (tem1, Qunbound))
3367 {
3368 CHECK_NUMBER (tem1);
3369 SET_FRAME_WIDTH (f, XINT (tem1));
3370 }
3371 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3372 window_prompting |= USSize;
3373 else
3374 window_prompting |= PSize;
3375 }
3376
3377 f->output_data.w32->vertical_scroll_bar_extra
3378 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3379 ? 0
3380 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3381 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3382 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3383
3384 x_compute_fringe_widths (f, 0);
3385
3386 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3387 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3388
3389 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3390 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3391 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3392 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3393 {
3394 if (EQ (tem0, Qminus))
3395 {
3396 f->output_data.w32->top_pos = 0;
3397 window_prompting |= YNegative;
3398 }
3399 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3400 && CONSP (XCDR (tem0))
3401 && INTEGERP (XCAR (XCDR (tem0))))
3402 {
3403 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3404 window_prompting |= YNegative;
3405 }
3406 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3407 && CONSP (XCDR (tem0))
3408 && INTEGERP (XCAR (XCDR (tem0))))
3409 {
3410 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3411 }
3412 else if (EQ (tem0, Qunbound))
3413 f->output_data.w32->top_pos = 0;
3414 else
3415 {
3416 CHECK_NUMBER (tem0);
3417 f->output_data.w32->top_pos = XINT (tem0);
3418 if (f->output_data.w32->top_pos < 0)
3419 window_prompting |= YNegative;
3420 }
3421
3422 if (EQ (tem1, Qminus))
3423 {
3424 f->output_data.w32->left_pos = 0;
3425 window_prompting |= XNegative;
3426 }
3427 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3428 && CONSP (XCDR (tem1))
3429 && INTEGERP (XCAR (XCDR (tem1))))
3430 {
3431 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3432 window_prompting |= XNegative;
3433 }
3434 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3435 && CONSP (XCDR (tem1))
3436 && INTEGERP (XCAR (XCDR (tem1))))
3437 {
3438 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3439 }
3440 else if (EQ (tem1, Qunbound))
3441 f->output_data.w32->left_pos = 0;
3442 else
3443 {
3444 CHECK_NUMBER (tem1);
3445 f->output_data.w32->left_pos = XINT (tem1);
3446 if (f->output_data.w32->left_pos < 0)
3447 window_prompting |= XNegative;
3448 }
3449
3450 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3451 window_prompting |= USPosition;
3452 else
3453 window_prompting |= PPosition;
3454 }
3455
3456 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3457 {
3458 int left, top;
3459 int width, height;
3460
3461 /* It takes both for some WM:s to place it where we want */
3462 window_prompting = USPosition | PPosition;
3463 x_fullscreen_adjust (f, &width, &height, &top, &left);
3464 f->width = width;
3465 f->height = height;
3466 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3467 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3468 f->output_data.w32->left_pos = left;
3469 f->output_data.w32->top_pos = top;
3470 }
3471
3472 return window_prompting;
3473 }
3474
3475 \f
3476
3477 extern LRESULT CALLBACK w32_wnd_proc ();
3478
3479 BOOL
3480 w32_init_class (hinst)
3481 HINSTANCE hinst;
3482 {
3483 WNDCLASS wc;
3484
3485 wc.style = CS_HREDRAW | CS_VREDRAW;
3486 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3487 wc.cbClsExtra = 0;
3488 wc.cbWndExtra = WND_EXTRA_BYTES;
3489 wc.hInstance = hinst;
3490 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3491 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3492 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3493 wc.lpszMenuName = NULL;
3494 wc.lpszClassName = EMACS_CLASS;
3495
3496 return (RegisterClass (&wc));
3497 }
3498
3499 HWND
3500 w32_createscrollbar (f, bar)
3501 struct frame *f;
3502 struct scroll_bar * bar;
3503 {
3504 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3505 /* Position and size of scroll bar. */
3506 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3507 XINT(bar->top),
3508 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3509 XINT(bar->height),
3510 FRAME_W32_WINDOW (f),
3511 NULL,
3512 hinst,
3513 NULL));
3514 }
3515
3516 void
3517 w32_createwindow (f)
3518 struct frame *f;
3519 {
3520 HWND hwnd;
3521 RECT rect;
3522
3523 rect.left = rect.top = 0;
3524 rect.right = PIXEL_WIDTH (f);
3525 rect.bottom = PIXEL_HEIGHT (f);
3526
3527 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3528 FRAME_EXTERNAL_MENU_BAR (f));
3529
3530 /* Do first time app init */
3531
3532 if (!hprevinst)
3533 {
3534 w32_init_class (hinst);
3535 }
3536
3537 FRAME_W32_WINDOW (f) = hwnd
3538 = CreateWindow (EMACS_CLASS,
3539 f->namebuf,
3540 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3541 f->output_data.w32->left_pos,
3542 f->output_data.w32->top_pos,
3543 rect.right - rect.left,
3544 rect.bottom - rect.top,
3545 NULL,
3546 NULL,
3547 hinst,
3548 NULL);
3549
3550 if (hwnd)
3551 {
3552 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3553 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3554 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3555 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3556 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3557
3558 /* Enable drag-n-drop. */
3559 DragAcceptFiles (hwnd, TRUE);
3560
3561 /* Do this to discard the default setting specified by our parent. */
3562 ShowWindow (hwnd, SW_HIDE);
3563 }
3564 }
3565
3566 void
3567 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3568 W32Msg * wmsg;
3569 HWND hwnd;
3570 UINT msg;
3571 WPARAM wParam;
3572 LPARAM lParam;
3573 {
3574 wmsg->msg.hwnd = hwnd;
3575 wmsg->msg.message = msg;
3576 wmsg->msg.wParam = wParam;
3577 wmsg->msg.lParam = lParam;
3578 wmsg->msg.time = GetMessageTime ();
3579
3580 post_msg (wmsg);
3581 }
3582
3583 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3584 between left and right keys as advertised. We test for this
3585 support dynamically, and set a flag when the support is absent. If
3586 absent, we keep track of the left and right control and alt keys
3587 ourselves. This is particularly necessary on keyboards that rely
3588 upon the AltGr key, which is represented as having the left control
3589 and right alt keys pressed. For these keyboards, we need to know
3590 when the left alt key has been pressed in addition to the AltGr key
3591 so that we can properly support M-AltGr-key sequences (such as M-@
3592 on Swedish keyboards). */
3593
3594 #define EMACS_LCONTROL 0
3595 #define EMACS_RCONTROL 1
3596 #define EMACS_LMENU 2
3597 #define EMACS_RMENU 3
3598
3599 static int modifiers[4];
3600 static int modifiers_recorded;
3601 static int modifier_key_support_tested;
3602
3603 static void
3604 test_modifier_support (unsigned int wparam)
3605 {
3606 unsigned int l, r;
3607
3608 if (wparam != VK_CONTROL && wparam != VK_MENU)
3609 return;
3610 if (wparam == VK_CONTROL)
3611 {
3612 l = VK_LCONTROL;
3613 r = VK_RCONTROL;
3614 }
3615 else
3616 {
3617 l = VK_LMENU;
3618 r = VK_RMENU;
3619 }
3620 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3621 modifiers_recorded = 1;
3622 else
3623 modifiers_recorded = 0;
3624 modifier_key_support_tested = 1;
3625 }
3626
3627 static void
3628 record_keydown (unsigned int wparam, unsigned int lparam)
3629 {
3630 int i;
3631
3632 if (!modifier_key_support_tested)
3633 test_modifier_support (wparam);
3634
3635 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3636 return;
3637
3638 if (wparam == VK_CONTROL)
3639 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3640 else
3641 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3642
3643 modifiers[i] = 1;
3644 }
3645
3646 static void
3647 record_keyup (unsigned int wparam, unsigned int lparam)
3648 {
3649 int i;
3650
3651 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3652 return;
3653
3654 if (wparam == VK_CONTROL)
3655 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3656 else
3657 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3658
3659 modifiers[i] = 0;
3660 }
3661
3662 /* Emacs can lose focus while a modifier key has been pressed. When
3663 it regains focus, be conservative and clear all modifiers since
3664 we cannot reconstruct the left and right modifier state. */
3665 static void
3666 reset_modifiers ()
3667 {
3668 SHORT ctrl, alt;
3669
3670 if (GetFocus () == NULL)
3671 /* Emacs doesn't have keyboard focus. Do nothing. */
3672 return;
3673
3674 ctrl = GetAsyncKeyState (VK_CONTROL);
3675 alt = GetAsyncKeyState (VK_MENU);
3676
3677 if (!(ctrl & 0x08000))
3678 /* Clear any recorded control modifier state. */
3679 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3680
3681 if (!(alt & 0x08000))
3682 /* Clear any recorded alt modifier state. */
3683 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3684
3685 /* Update the state of all modifier keys, because modifiers used in
3686 hot-key combinations can get stuck on if Emacs loses focus as a
3687 result of a hot-key being pressed. */
3688 {
3689 BYTE keystate[256];
3690
3691 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3692
3693 GetKeyboardState (keystate);
3694 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3695 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3696 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3697 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3698 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3699 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3700 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3701 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3702 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3703 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3704 SetKeyboardState (keystate);
3705 }
3706 }
3707
3708 /* Synchronize modifier state with what is reported with the current
3709 keystroke. Even if we cannot distinguish between left and right
3710 modifier keys, we know that, if no modifiers are set, then neither
3711 the left or right modifier should be set. */
3712 static void
3713 sync_modifiers ()
3714 {
3715 if (!modifiers_recorded)
3716 return;
3717
3718 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3719 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3720
3721 if (!(GetKeyState (VK_MENU) & 0x8000))
3722 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3723 }
3724
3725 static int
3726 modifier_set (int vkey)
3727 {
3728 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3729 return (GetKeyState (vkey) & 0x1);
3730 if (!modifiers_recorded)
3731 return (GetKeyState (vkey) & 0x8000);
3732
3733 switch (vkey)
3734 {
3735 case VK_LCONTROL:
3736 return modifiers[EMACS_LCONTROL];
3737 case VK_RCONTROL:
3738 return modifiers[EMACS_RCONTROL];
3739 case VK_LMENU:
3740 return modifiers[EMACS_LMENU];
3741 case VK_RMENU:
3742 return modifiers[EMACS_RMENU];
3743 }
3744 return (GetKeyState (vkey) & 0x8000);
3745 }
3746
3747 /* Convert between the modifier bits W32 uses and the modifier bits
3748 Emacs uses. */
3749
3750 unsigned int
3751 w32_key_to_modifier (int key)
3752 {
3753 Lisp_Object key_mapping;
3754
3755 switch (key)
3756 {
3757 case VK_LWIN:
3758 key_mapping = Vw32_lwindow_modifier;
3759 break;
3760 case VK_RWIN:
3761 key_mapping = Vw32_rwindow_modifier;
3762 break;
3763 case VK_APPS:
3764 key_mapping = Vw32_apps_modifier;
3765 break;
3766 case VK_SCROLL:
3767 key_mapping = Vw32_scroll_lock_modifier;
3768 break;
3769 default:
3770 key_mapping = Qnil;
3771 }
3772
3773 /* NB. This code runs in the input thread, asychronously to the lisp
3774 thread, so we must be careful to ensure access to lisp data is
3775 thread-safe. The following code is safe because the modifier
3776 variable values are updated atomically from lisp and symbols are
3777 not relocated by GC. Also, we don't have to worry about seeing GC
3778 markbits here. */
3779 if (EQ (key_mapping, Qhyper))
3780 return hyper_modifier;
3781 if (EQ (key_mapping, Qsuper))
3782 return super_modifier;
3783 if (EQ (key_mapping, Qmeta))
3784 return meta_modifier;
3785 if (EQ (key_mapping, Qalt))
3786 return alt_modifier;
3787 if (EQ (key_mapping, Qctrl))
3788 return ctrl_modifier;
3789 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3790 return ctrl_modifier;
3791 if (EQ (key_mapping, Qshift))
3792 return shift_modifier;
3793
3794 /* Don't generate any modifier if not explicitly requested. */
3795 return 0;
3796 }
3797
3798 unsigned int
3799 w32_get_modifiers ()
3800 {
3801 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3802 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3803 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3804 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3805 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3806 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3807 (modifier_set (VK_MENU) ?
3808 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3809 }
3810
3811 /* We map the VK_* modifiers into console modifier constants
3812 so that we can use the same routines to handle both console
3813 and window input. */
3814
3815 static int
3816 construct_console_modifiers ()
3817 {
3818 int mods;
3819
3820 mods = 0;
3821 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3822 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3823 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3824 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3825 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3826 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3827 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3828 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3829 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3830 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3831 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3832
3833 return mods;
3834 }
3835
3836 static int
3837 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3838 {
3839 int mods;
3840
3841 /* Convert to emacs modifiers. */
3842 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3843
3844 return mods;
3845 }
3846
3847 unsigned int
3848 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3849 {
3850 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3851 return virt_key;
3852
3853 if (virt_key == VK_RETURN)
3854 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3855
3856 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3857 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3858
3859 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3860 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3861
3862 if (virt_key == VK_CLEAR)
3863 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3864
3865 return virt_key;
3866 }
3867
3868 /* List of special key combinations which w32 would normally capture,
3869 but emacs should grab instead. Not directly visible to lisp, to
3870 simplify synchronization. Each item is an integer encoding a virtual
3871 key code and modifier combination to capture. */
3872 Lisp_Object w32_grabbed_keys;
3873
3874 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3875 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3876 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3877 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3878
3879 /* Register hot-keys for reserved key combinations when Emacs has
3880 keyboard focus, since this is the only way Emacs can receive key
3881 combinations like Alt-Tab which are used by the system. */
3882
3883 static void
3884 register_hot_keys (hwnd)
3885 HWND hwnd;
3886 {
3887 Lisp_Object keylist;
3888
3889 /* Use GC_CONSP, since we are called asynchronously. */
3890 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3891 {
3892 Lisp_Object key = XCAR (keylist);
3893
3894 /* Deleted entries get set to nil. */
3895 if (!INTEGERP (key))
3896 continue;
3897
3898 RegisterHotKey (hwnd, HOTKEY_ID (key),
3899 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3900 }
3901 }
3902
3903 static void
3904 unregister_hot_keys (hwnd)
3905 HWND hwnd;
3906 {
3907 Lisp_Object keylist;
3908
3909 /* Use GC_CONSP, since we are called asynchronously. */
3910 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3911 {
3912 Lisp_Object key = XCAR (keylist);
3913
3914 if (!INTEGERP (key))
3915 continue;
3916
3917 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3918 }
3919 }
3920
3921 /* Main message dispatch loop. */
3922
3923 static void
3924 w32_msg_pump (deferred_msg * msg_buf)
3925 {
3926 MSG msg;
3927 int result;
3928 HWND focus_window;
3929
3930 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3931
3932 while (GetMessage (&msg, NULL, 0, 0))
3933 {
3934 if (msg.hwnd == NULL)
3935 {
3936 switch (msg.message)
3937 {
3938 case WM_NULL:
3939 /* Produced by complete_deferred_msg; just ignore. */
3940 break;
3941 case WM_EMACS_CREATEWINDOW:
3942 w32_createwindow ((struct frame *) msg.wParam);
3943 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3944 abort ();
3945 break;
3946 case WM_EMACS_SETLOCALE:
3947 SetThreadLocale (msg.wParam);
3948 /* Reply is not expected. */
3949 break;
3950 case WM_EMACS_SETKEYBOARDLAYOUT:
3951 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3952 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3953 result, 0))
3954 abort ();
3955 break;
3956 case WM_EMACS_REGISTER_HOT_KEY:
3957 focus_window = GetFocus ();
3958 if (focus_window != NULL)
3959 RegisterHotKey (focus_window,
3960 HOTKEY_ID (msg.wParam),
3961 HOTKEY_MODIFIERS (msg.wParam),
3962 HOTKEY_VK_CODE (msg.wParam));
3963 /* Reply is not expected. */
3964 break;
3965 case WM_EMACS_UNREGISTER_HOT_KEY:
3966 focus_window = GetFocus ();
3967 if (focus_window != NULL)
3968 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3969 /* Mark item as erased. NB: this code must be
3970 thread-safe. The next line is okay because the cons
3971 cell is never made into garbage and is not relocated by
3972 GC. */
3973 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
3974 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3975 abort ();
3976 break;
3977 case WM_EMACS_TOGGLE_LOCK_KEY:
3978 {
3979 int vk_code = (int) msg.wParam;
3980 int cur_state = (GetKeyState (vk_code) & 1);
3981 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3982
3983 /* NB: This code must be thread-safe. It is safe to
3984 call NILP because symbols are not relocated by GC,
3985 and pointer here is not touched by GC (so the markbit
3986 can't be set). Numbers are safe because they are
3987 immediate values. */
3988 if (NILP (new_state)
3989 || (NUMBERP (new_state)
3990 && ((XUINT (new_state)) & 1) != cur_state))
3991 {
3992 one_w32_display_info.faked_key = vk_code;
3993
3994 keybd_event ((BYTE) vk_code,
3995 (BYTE) MapVirtualKey (vk_code, 0),
3996 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3997 keybd_event ((BYTE) vk_code,
3998 (BYTE) MapVirtualKey (vk_code, 0),
3999 KEYEVENTF_EXTENDEDKEY | 0, 0);
4000 keybd_event ((BYTE) vk_code,
4001 (BYTE) MapVirtualKey (vk_code, 0),
4002 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4003 cur_state = !cur_state;
4004 }
4005 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
4006 cur_state, 0))
4007 abort ();
4008 }
4009 break;
4010 default:
4011 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
4012 }
4013 }
4014 else
4015 {
4016 DispatchMessage (&msg);
4017 }
4018
4019 /* Exit nested loop when our deferred message has completed. */
4020 if (msg_buf->completed)
4021 break;
4022 }
4023 }
4024
4025 deferred_msg * deferred_msg_head;
4026
4027 static deferred_msg *
4028 find_deferred_msg (HWND hwnd, UINT msg)
4029 {
4030 deferred_msg * item;
4031
4032 /* Don't actually need synchronization for read access, since
4033 modification of single pointer is always atomic. */
4034 /* enter_crit (); */
4035
4036 for (item = deferred_msg_head; item != NULL; item = item->next)
4037 if (item->w32msg.msg.hwnd == hwnd
4038 && item->w32msg.msg.message == msg)
4039 break;
4040
4041 /* leave_crit (); */
4042
4043 return item;
4044 }
4045
4046 static LRESULT
4047 send_deferred_msg (deferred_msg * msg_buf,
4048 HWND hwnd,
4049 UINT msg,
4050 WPARAM wParam,
4051 LPARAM lParam)
4052 {
4053 /* Only input thread can send deferred messages. */
4054 if (GetCurrentThreadId () != dwWindowsThreadId)
4055 abort ();
4056
4057 /* It is an error to send a message that is already deferred. */
4058 if (find_deferred_msg (hwnd, msg) != NULL)
4059 abort ();
4060
4061 /* Enforced synchronization is not needed because this is the only
4062 function that alters deferred_msg_head, and the following critical
4063 section is guaranteed to only be serially reentered (since only the
4064 input thread can call us). */
4065
4066 /* enter_crit (); */
4067
4068 msg_buf->completed = 0;
4069 msg_buf->next = deferred_msg_head;
4070 deferred_msg_head = msg_buf;
4071 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4072
4073 /* leave_crit (); */
4074
4075 /* Start a new nested message loop to process other messages until
4076 this one is completed. */
4077 w32_msg_pump (msg_buf);
4078
4079 deferred_msg_head = msg_buf->next;
4080
4081 return msg_buf->result;
4082 }
4083
4084 void
4085 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4086 {
4087 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4088
4089 if (msg_buf == NULL)
4090 /* Message may have been cancelled, so don't abort(). */
4091 return;
4092
4093 msg_buf->result = result;
4094 msg_buf->completed = 1;
4095
4096 /* Ensure input thread is woken so it notices the completion. */
4097 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4098 }
4099
4100 void
4101 cancel_all_deferred_msgs ()
4102 {
4103 deferred_msg * item;
4104
4105 /* Don't actually need synchronization for read access, since
4106 modification of single pointer is always atomic. */
4107 /* enter_crit (); */
4108
4109 for (item = deferred_msg_head; item != NULL; item = item->next)
4110 {
4111 item->result = 0;
4112 item->completed = 1;
4113 }
4114
4115 /* leave_crit (); */
4116
4117 /* Ensure input thread is woken so it notices the completion. */
4118 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4119 }
4120
4121 DWORD
4122 w32_msg_worker (dw)
4123 DWORD dw;
4124 {
4125 MSG msg;
4126 deferred_msg dummy_buf;
4127
4128 /* Ensure our message queue is created */
4129
4130 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
4131
4132 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4133 abort ();
4134
4135 memset (&dummy_buf, 0, sizeof (dummy_buf));
4136 dummy_buf.w32msg.msg.hwnd = NULL;
4137 dummy_buf.w32msg.msg.message = WM_NULL;
4138
4139 /* This is the inital message loop which should only exit when the
4140 application quits. */
4141 w32_msg_pump (&dummy_buf);
4142
4143 return 0;
4144 }
4145
4146 static void
4147 post_character_message (hwnd, msg, wParam, lParam, modifiers)
4148 HWND hwnd;
4149 UINT msg;
4150 WPARAM wParam;
4151 LPARAM lParam;
4152 DWORD modifiers;
4153
4154 {
4155 W32Msg wmsg;
4156
4157 wmsg.dwModifiers = modifiers;
4158
4159 /* Detect quit_char and set quit-flag directly. Note that we
4160 still need to post a message to ensure the main thread will be
4161 woken up if blocked in sys_select(), but we do NOT want to post
4162 the quit_char message itself (because it will usually be as if
4163 the user had typed quit_char twice). Instead, we post a dummy
4164 message that has no particular effect. */
4165 {
4166 int c = wParam;
4167 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4168 c = make_ctrl_char (c) & 0377;
4169 if (c == quit_char
4170 || (wmsg.dwModifiers == 0 &&
4171 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
4172 {
4173 Vquit_flag = Qt;
4174
4175 /* The choice of message is somewhat arbitrary, as long as
4176 the main thread handler just ignores it. */
4177 msg = WM_NULL;
4178
4179 /* Interrupt any blocking system calls. */
4180 signal_quit ();
4181
4182 /* As a safety precaution, forcibly complete any deferred
4183 messages. This is a kludge, but I don't see any particularly
4184 clean way to handle the situation where a deferred message is
4185 "dropped" in the lisp thread, and will thus never be
4186 completed, eg. by the user trying to activate the menubar
4187 when the lisp thread is busy, and then typing C-g when the
4188 menubar doesn't open promptly (with the result that the
4189 menubar never responds at all because the deferred
4190 WM_INITMENU message is never completed). Another problem
4191 situation is when the lisp thread calls SendMessage (to send
4192 a window manager command) when a message has been deferred;
4193 the lisp thread gets blocked indefinitely waiting for the
4194 deferred message to be completed, which itself is waiting for
4195 the lisp thread to respond.
4196
4197 Note that we don't want to block the input thread waiting for
4198 a reponse from the lisp thread (although that would at least
4199 solve the deadlock problem above), because we want to be able
4200 to receive C-g to interrupt the lisp thread. */
4201 cancel_all_deferred_msgs ();
4202 }
4203 }
4204
4205 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4206 }
4207
4208 /* Main window procedure */
4209
4210 LRESULT CALLBACK
4211 w32_wnd_proc (hwnd, msg, wParam, lParam)
4212 HWND hwnd;
4213 UINT msg;
4214 WPARAM wParam;
4215 LPARAM lParam;
4216 {
4217 struct frame *f;
4218 struct w32_display_info *dpyinfo = &one_w32_display_info;
4219 W32Msg wmsg;
4220 int windows_translate;
4221 int key;
4222
4223 /* Note that it is okay to call x_window_to_frame, even though we are
4224 not running in the main lisp thread, because frame deletion
4225 requires the lisp thread to synchronize with this thread. Thus, if
4226 a frame struct is returned, it can be used without concern that the
4227 lisp thread might make it disappear while we are using it.
4228
4229 NB. Walking the frame list in this thread is safe (as long as
4230 writes of Lisp_Object slots are atomic, which they are on Windows).
4231 Although delete-frame can destructively modify the frame list while
4232 we are walking it, a garbage collection cannot occur until after
4233 delete-frame has synchronized with this thread.
4234
4235 It is also safe to use functions that make GDI calls, such as
4236 w32_clear_rect, because these functions must obtain a DC handle
4237 from the frame struct using get_frame_dc which is thread-aware. */
4238
4239 switch (msg)
4240 {
4241 case WM_ERASEBKGND:
4242 f = x_window_to_frame (dpyinfo, hwnd);
4243 if (f)
4244 {
4245 HDC hdc = get_frame_dc (f);
4246 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4247 w32_clear_rect (f, hdc, &wmsg.rect);
4248 release_frame_dc (f, hdc);
4249
4250 #if defined (W32_DEBUG_DISPLAY)
4251 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4252 f,
4253 wmsg.rect.left, wmsg.rect.top,
4254 wmsg.rect.right, wmsg.rect.bottom));
4255 #endif /* W32_DEBUG_DISPLAY */
4256 }
4257 return 1;
4258 case WM_PALETTECHANGED:
4259 /* ignore our own changes */
4260 if ((HWND)wParam != hwnd)
4261 {
4262 f = x_window_to_frame (dpyinfo, hwnd);
4263 if (f)
4264 /* get_frame_dc will realize our palette and force all
4265 frames to be redrawn if needed. */
4266 release_frame_dc (f, get_frame_dc (f));
4267 }
4268 return 0;
4269 case WM_PAINT:
4270 {
4271 PAINTSTRUCT paintStruct;
4272 RECT update_rect;
4273 bzero (&update_rect, sizeof (update_rect));
4274
4275 f = x_window_to_frame (dpyinfo, hwnd);
4276 if (f == 0)
4277 {
4278 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4279 return 0;
4280 }
4281
4282 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4283 fails. Apparently this can happen under some
4284 circumstances. */
4285 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
4286 {
4287 enter_crit ();
4288 BeginPaint (hwnd, &paintStruct);
4289
4290 /* The rectangles returned by GetUpdateRect and BeginPaint
4291 do not always match. Play it safe by assuming both areas
4292 are invalid. */
4293 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
4294
4295 #if defined (W32_DEBUG_DISPLAY)
4296 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4297 f,
4298 wmsg.rect.left, wmsg.rect.top,
4299 wmsg.rect.right, wmsg.rect.bottom));
4300 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4301 update_rect.left, update_rect.top,
4302 update_rect.right, update_rect.bottom));
4303 #endif
4304 EndPaint (hwnd, &paintStruct);
4305 leave_crit ();
4306
4307 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4308
4309 return 0;
4310 }
4311
4312 /* If GetUpdateRect returns 0 (meaning there is no update
4313 region), assume the whole window needs to be repainted. */
4314 GetClientRect(hwnd, &wmsg.rect);
4315 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4316 return 0;
4317 }
4318
4319 case WM_INPUTLANGCHANGE:
4320 /* Inform lisp thread of keyboard layout changes. */
4321 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4322
4323 /* Clear dead keys in the keyboard state; for simplicity only
4324 preserve modifier key states. */
4325 {
4326 int i;
4327 BYTE keystate[256];
4328
4329 GetKeyboardState (keystate);
4330 for (i = 0; i < 256; i++)
4331 if (1
4332 && i != VK_SHIFT
4333 && i != VK_LSHIFT
4334 && i != VK_RSHIFT
4335 && i != VK_CAPITAL
4336 && i != VK_NUMLOCK
4337 && i != VK_SCROLL
4338 && i != VK_CONTROL
4339 && i != VK_LCONTROL
4340 && i != VK_RCONTROL
4341 && i != VK_MENU
4342 && i != VK_LMENU
4343 && i != VK_RMENU
4344 && i != VK_LWIN
4345 && i != VK_RWIN)
4346 keystate[i] = 0;
4347 SetKeyboardState (keystate);
4348 }
4349 goto dflt;
4350
4351 case WM_HOTKEY:
4352 /* Synchronize hot keys with normal input. */
4353 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4354 return (0);
4355
4356 case WM_KEYUP:
4357 case WM_SYSKEYUP:
4358 record_keyup (wParam, lParam);
4359 goto dflt;
4360
4361 case WM_KEYDOWN:
4362 case WM_SYSKEYDOWN:
4363 /* Ignore keystrokes we fake ourself; see below. */
4364 if (dpyinfo->faked_key == wParam)
4365 {
4366 dpyinfo->faked_key = 0;
4367 /* Make sure TranslateMessage sees them though (as long as
4368 they don't produce WM_CHAR messages). This ensures that
4369 indicator lights are toggled promptly on Windows 9x, for
4370 example. */
4371 if (lispy_function_keys[wParam] != 0)
4372 {
4373 windows_translate = 1;
4374 goto translate;
4375 }
4376 return 0;
4377 }
4378
4379 /* Synchronize modifiers with current keystroke. */
4380 sync_modifiers ();
4381 record_keydown (wParam, lParam);
4382 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4383
4384 windows_translate = 0;
4385
4386 switch (wParam)
4387 {
4388 case VK_LWIN:
4389 if (NILP (Vw32_pass_lwindow_to_system))
4390 {
4391 /* Prevent system from acting on keyup (which opens the
4392 Start menu if no other key was pressed) by simulating a
4393 press of Space which we will ignore. */
4394 if (GetAsyncKeyState (wParam) & 1)
4395 {
4396 if (NUMBERP (Vw32_phantom_key_code))
4397 key = XUINT (Vw32_phantom_key_code) & 255;
4398 else
4399 key = VK_SPACE;
4400 dpyinfo->faked_key = key;
4401 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4402 }
4403 }
4404 if (!NILP (Vw32_lwindow_modifier))
4405 return 0;
4406 break;
4407 case VK_RWIN:
4408 if (NILP (Vw32_pass_rwindow_to_system))
4409 {
4410 if (GetAsyncKeyState (wParam) & 1)
4411 {
4412 if (NUMBERP (Vw32_phantom_key_code))
4413 key = XUINT (Vw32_phantom_key_code) & 255;
4414 else
4415 key = VK_SPACE;
4416 dpyinfo->faked_key = key;
4417 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4418 }
4419 }
4420 if (!NILP (Vw32_rwindow_modifier))
4421 return 0;
4422 break;
4423 case VK_APPS:
4424 if (!NILP (Vw32_apps_modifier))
4425 return 0;
4426 break;
4427 case VK_MENU:
4428 if (NILP (Vw32_pass_alt_to_system))
4429 /* Prevent DefWindowProc from activating the menu bar if an
4430 Alt key is pressed and released by itself. */
4431 return 0;
4432 windows_translate = 1;
4433 break;
4434 case VK_CAPITAL:
4435 /* Decide whether to treat as modifier or function key. */
4436 if (NILP (Vw32_enable_caps_lock))
4437 goto disable_lock_key;
4438 windows_translate = 1;
4439 break;
4440 case VK_NUMLOCK:
4441 /* Decide whether to treat as modifier or function key. */
4442 if (NILP (Vw32_enable_num_lock))
4443 goto disable_lock_key;
4444 windows_translate = 1;
4445 break;
4446 case VK_SCROLL:
4447 /* Decide whether to treat as modifier or function key. */
4448 if (NILP (Vw32_scroll_lock_modifier))
4449 goto disable_lock_key;
4450 windows_translate = 1;
4451 break;
4452 disable_lock_key:
4453 /* Ensure the appropriate lock key state (and indicator light)
4454 remains in the same state. We do this by faking another
4455 press of the relevant key. Apparently, this really is the
4456 only way to toggle the state of the indicator lights. */
4457 dpyinfo->faked_key = wParam;
4458 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4459 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4460 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4461 KEYEVENTF_EXTENDEDKEY | 0, 0);
4462 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4463 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4464 /* Ensure indicator lights are updated promptly on Windows 9x
4465 (TranslateMessage apparently does this), after forwarding
4466 input event. */
4467 post_character_message (hwnd, msg, wParam, lParam,
4468 w32_get_key_modifiers (wParam, lParam));
4469 windows_translate = 1;
4470 break;
4471 case VK_CONTROL:
4472 case VK_SHIFT:
4473 case VK_PROCESSKEY: /* Generated by IME. */
4474 windows_translate = 1;
4475 break;
4476 case VK_CANCEL:
4477 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4478 which is confusing for purposes of key binding; convert
4479 VK_CANCEL events into VK_PAUSE events. */
4480 wParam = VK_PAUSE;
4481 break;
4482 case VK_PAUSE:
4483 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4484 for purposes of key binding; convert these back into
4485 VK_NUMLOCK events, at least when we want to see NumLock key
4486 presses. (Note that there is never any possibility that
4487 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4488 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4489 wParam = VK_NUMLOCK;
4490 break;
4491 default:
4492 /* If not defined as a function key, change it to a WM_CHAR message. */
4493 if (lispy_function_keys[wParam] == 0)
4494 {
4495 DWORD modifiers = construct_console_modifiers ();
4496
4497 if (!NILP (Vw32_recognize_altgr)
4498 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4499 {
4500 /* Always let TranslateMessage handle AltGr key chords;
4501 for some reason, ToAscii doesn't always process AltGr
4502 chords correctly. */
4503 windows_translate = 1;
4504 }
4505 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4506 {
4507 /* Handle key chords including any modifiers other
4508 than shift directly, in order to preserve as much
4509 modifier information as possible. */
4510 if ('A' <= wParam && wParam <= 'Z')
4511 {
4512 /* Don't translate modified alphabetic keystrokes,
4513 so the user doesn't need to constantly switch
4514 layout to type control or meta keystrokes when
4515 the normal layout translates alphabetic
4516 characters to non-ascii characters. */
4517 if (!modifier_set (VK_SHIFT))
4518 wParam += ('a' - 'A');
4519 msg = WM_CHAR;
4520 }
4521 else
4522 {
4523 /* Try to handle other keystrokes by determining the
4524 base character (ie. translating the base key plus
4525 shift modifier). */
4526 int add;
4527 int isdead = 0;
4528 KEY_EVENT_RECORD key;
4529
4530 key.bKeyDown = TRUE;
4531 key.wRepeatCount = 1;
4532 key.wVirtualKeyCode = wParam;
4533 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4534 key.uChar.AsciiChar = 0;
4535 key.dwControlKeyState = modifiers;
4536
4537 add = w32_kbd_patch_key (&key);
4538 /* 0 means an unrecognised keycode, negative means
4539 dead key. Ignore both. */
4540 while (--add >= 0)
4541 {
4542 /* Forward asciified character sequence. */
4543 post_character_message
4544 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4545 w32_get_key_modifiers (wParam, lParam));
4546 w32_kbd_patch_key (&key);
4547 }
4548 return 0;
4549 }
4550 }
4551 else
4552 {
4553 /* Let TranslateMessage handle everything else. */
4554 windows_translate = 1;
4555 }
4556 }
4557 }
4558
4559 translate:
4560 if (windows_translate)
4561 {
4562 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4563
4564 windows_msg.time = GetMessageTime ();
4565 TranslateMessage (&windows_msg);
4566 goto dflt;
4567 }
4568
4569 /* Fall through */
4570
4571 case WM_SYSCHAR:
4572 case WM_CHAR:
4573 post_character_message (hwnd, msg, wParam, lParam,
4574 w32_get_key_modifiers (wParam, lParam));
4575 break;
4576
4577 /* Simulate middle mouse button events when left and right buttons
4578 are used together, but only if user has two button mouse. */
4579 case WM_LBUTTONDOWN:
4580 case WM_RBUTTONDOWN:
4581 if (XINT (Vw32_num_mouse_buttons) > 2)
4582 goto handle_plain_button;
4583
4584 {
4585 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4586 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4587
4588 if (button_state & this)
4589 return 0;
4590
4591 if (button_state == 0)
4592 SetCapture (hwnd);
4593
4594 button_state |= this;
4595
4596 if (button_state & other)
4597 {
4598 if (mouse_button_timer)
4599 {
4600 KillTimer (hwnd, mouse_button_timer);
4601 mouse_button_timer = 0;
4602
4603 /* Generate middle mouse event instead. */
4604 msg = WM_MBUTTONDOWN;
4605 button_state |= MMOUSE;
4606 }
4607 else if (button_state & MMOUSE)
4608 {
4609 /* Ignore button event if we've already generated a
4610 middle mouse down event. This happens if the
4611 user releases and press one of the two buttons
4612 after we've faked a middle mouse event. */
4613 return 0;
4614 }
4615 else
4616 {
4617 /* Flush out saved message. */
4618 post_msg (&saved_mouse_button_msg);
4619 }
4620 wmsg.dwModifiers = w32_get_modifiers ();
4621 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4622
4623 /* Clear message buffer. */
4624 saved_mouse_button_msg.msg.hwnd = 0;
4625 }
4626 else
4627 {
4628 /* Hold onto message for now. */
4629 mouse_button_timer =
4630 SetTimer (hwnd, MOUSE_BUTTON_ID,
4631 XINT (Vw32_mouse_button_tolerance), NULL);
4632 saved_mouse_button_msg.msg.hwnd = hwnd;
4633 saved_mouse_button_msg.msg.message = msg;
4634 saved_mouse_button_msg.msg.wParam = wParam;
4635 saved_mouse_button_msg.msg.lParam = lParam;
4636 saved_mouse_button_msg.msg.time = GetMessageTime ();
4637 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4638 }
4639 }
4640 return 0;
4641
4642 case WM_LBUTTONUP:
4643 case WM_RBUTTONUP:
4644 if (XINT (Vw32_num_mouse_buttons) > 2)
4645 goto handle_plain_button;
4646
4647 {
4648 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4649 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4650
4651 if ((button_state & this) == 0)
4652 return 0;
4653
4654 button_state &= ~this;
4655
4656 if (button_state & MMOUSE)
4657 {
4658 /* Only generate event when second button is released. */
4659 if ((button_state & other) == 0)
4660 {
4661 msg = WM_MBUTTONUP;
4662 button_state &= ~MMOUSE;
4663
4664 if (button_state) abort ();
4665 }
4666 else
4667 return 0;
4668 }
4669 else
4670 {
4671 /* Flush out saved message if necessary. */
4672 if (saved_mouse_button_msg.msg.hwnd)
4673 {
4674 post_msg (&saved_mouse_button_msg);
4675 }
4676 }
4677 wmsg.dwModifiers = w32_get_modifiers ();
4678 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4679
4680 /* Always clear message buffer and cancel timer. */
4681 saved_mouse_button_msg.msg.hwnd = 0;
4682 KillTimer (hwnd, mouse_button_timer);
4683 mouse_button_timer = 0;
4684
4685 if (button_state == 0)
4686 ReleaseCapture ();
4687 }
4688 return 0;
4689
4690 case WM_XBUTTONDOWN:
4691 case WM_XBUTTONUP:
4692 if (w32_pass_extra_mouse_buttons_to_system)
4693 goto dflt;
4694 /* else fall through and process them. */
4695 case WM_MBUTTONDOWN:
4696 case WM_MBUTTONUP:
4697 handle_plain_button:
4698 {
4699 BOOL up;
4700 int button;
4701
4702 if (parse_button (msg, HIWORD (wParam), &button, &up))
4703 {
4704 if (up) ReleaseCapture ();
4705 else SetCapture (hwnd);
4706 button = (button == 0) ? LMOUSE :
4707 ((button == 1) ? MMOUSE : RMOUSE);
4708 if (up)
4709 button_state &= ~button;
4710 else
4711 button_state |= button;
4712 }
4713 }
4714
4715 wmsg.dwModifiers = w32_get_modifiers ();
4716 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4717
4718 /* Need to return true for XBUTTON messages, false for others,
4719 to indicate that we processed the message. */
4720 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
4721
4722 case WM_MOUSEMOVE:
4723 /* If the mouse has just moved into the frame, start tracking
4724 it, so we will be notified when it leaves the frame. Mouse
4725 tracking only works under W98 and NT4 and later. On earlier
4726 versions, there is no way of telling when the mouse leaves the
4727 frame, so we just have to put up with help-echo and mouse
4728 highlighting remaining while the frame is not active. */
4729 if (track_mouse_event_fn && !track_mouse_window)
4730 {
4731 TRACKMOUSEEVENT tme;
4732 tme.cbSize = sizeof (tme);
4733 tme.dwFlags = TME_LEAVE;
4734 tme.hwndTrack = hwnd;
4735
4736 track_mouse_event_fn (&tme);
4737 track_mouse_window = hwnd;
4738 }
4739 case WM_VSCROLL:
4740 if (XINT (Vw32_mouse_move_interval) <= 0
4741 || (msg == WM_MOUSEMOVE && button_state == 0))
4742 {
4743 wmsg.dwModifiers = w32_get_modifiers ();
4744 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4745 return 0;
4746 }
4747
4748 /* Hang onto mouse move and scroll messages for a bit, to avoid
4749 sending such events to Emacs faster than it can process them.
4750 If we get more events before the timer from the first message
4751 expires, we just replace the first message. */
4752
4753 if (saved_mouse_move_msg.msg.hwnd == 0)
4754 mouse_move_timer =
4755 SetTimer (hwnd, MOUSE_MOVE_ID,
4756 XINT (Vw32_mouse_move_interval), NULL);
4757
4758 /* Hold onto message for now. */
4759 saved_mouse_move_msg.msg.hwnd = hwnd;
4760 saved_mouse_move_msg.msg.message = msg;
4761 saved_mouse_move_msg.msg.wParam = wParam;
4762 saved_mouse_move_msg.msg.lParam = lParam;
4763 saved_mouse_move_msg.msg.time = GetMessageTime ();
4764 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4765
4766 return 0;
4767
4768 case WM_MOUSEWHEEL:
4769 wmsg.dwModifiers = w32_get_modifiers ();
4770 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4771 return 0;
4772
4773 case WM_DROPFILES:
4774 wmsg.dwModifiers = w32_get_modifiers ();
4775 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4776 return 0;
4777
4778 case WM_TIMER:
4779 /* Flush out saved messages if necessary. */
4780 if (wParam == mouse_button_timer)
4781 {
4782 if (saved_mouse_button_msg.msg.hwnd)
4783 {
4784 post_msg (&saved_mouse_button_msg);
4785 saved_mouse_button_msg.msg.hwnd = 0;
4786 }
4787 KillTimer (hwnd, mouse_button_timer);
4788 mouse_button_timer = 0;
4789 }
4790 else if (wParam == mouse_move_timer)
4791 {
4792 if (saved_mouse_move_msg.msg.hwnd)
4793 {
4794 post_msg (&saved_mouse_move_msg);
4795 saved_mouse_move_msg.msg.hwnd = 0;
4796 }
4797 KillTimer (hwnd, mouse_move_timer);
4798 mouse_move_timer = 0;
4799 }
4800 else if (wParam == menu_free_timer)
4801 {
4802 KillTimer (hwnd, menu_free_timer);
4803 menu_free_timer = 0;
4804 f = x_window_to_frame (dpyinfo, hwnd);
4805 if (!f->output_data.w32->menu_command_in_progress)
4806 {
4807 /* Free memory used by owner-drawn and help-echo strings. */
4808 w32_free_menu_strings (hwnd);
4809 f->output_data.w32->menubar_active = 0;
4810 }
4811 }
4812 return 0;
4813
4814 case WM_NCACTIVATE:
4815 /* Windows doesn't send us focus messages when putting up and
4816 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4817 The only indication we get that something happened is receiving
4818 this message afterwards. So this is a good time to reset our
4819 keyboard modifiers' state. */
4820 reset_modifiers ();
4821 goto dflt;
4822
4823 case WM_INITMENU:
4824 button_state = 0;
4825 ReleaseCapture ();
4826 /* We must ensure menu bar is fully constructed and up to date
4827 before allowing user interaction with it. To achieve this
4828 we send this message to the lisp thread and wait for a
4829 reply (whose value is not actually needed) to indicate that
4830 the menu bar is now ready for use, so we can now return.
4831
4832 To remain responsive in the meantime, we enter a nested message
4833 loop that can process all other messages.
4834
4835 However, we skip all this if the message results from calling
4836 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4837 thread a message because it is blocked on us at this point. We
4838 set menubar_active before calling TrackPopupMenu to indicate
4839 this (there is no possibility of confusion with real menubar
4840 being active). */
4841
4842 f = x_window_to_frame (dpyinfo, hwnd);
4843 if (f
4844 && (f->output_data.w32->menubar_active
4845 /* We can receive this message even in the absence of a
4846 menubar (ie. when the system menu is activated) - in this
4847 case we do NOT want to forward the message, otherwise it
4848 will cause the menubar to suddenly appear when the user
4849 had requested it to be turned off! */
4850 || f->output_data.w32->menubar_widget == NULL))
4851 return 0;
4852
4853 {
4854 deferred_msg msg_buf;
4855
4856 /* Detect if message has already been deferred; in this case
4857 we cannot return any sensible value to ignore this. */
4858 if (find_deferred_msg (hwnd, msg) != NULL)
4859 abort ();
4860
4861 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4862 }
4863
4864 case WM_EXITMENULOOP:
4865 f = x_window_to_frame (dpyinfo, hwnd);
4866
4867 /* If a menu command is not already in progress, check again
4868 after a short delay, since Windows often (always?) sends the
4869 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4870 if (f && !f->output_data.w32->menu_command_in_progress)
4871 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
4872 goto dflt;
4873
4874 case WM_MENUSELECT:
4875 /* Direct handling of help_echo in menus. Should be safe now
4876 that we generate the help_echo by placing a help event in the
4877 keyboard buffer. */
4878 {
4879 HMENU menu = (HMENU) lParam;
4880 UINT menu_item = (UINT) LOWORD (wParam);
4881 UINT flags = (UINT) HIWORD (wParam);
4882
4883 w32_menu_display_help (hwnd, menu, menu_item, flags);
4884 }
4885 return 0;
4886
4887 case WM_MEASUREITEM:
4888 f = x_window_to_frame (dpyinfo, hwnd);
4889 if (f)
4890 {
4891 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4892
4893 if (pMis->CtlType == ODT_MENU)
4894 {
4895 /* Work out dimensions for popup menu titles. */
4896 char * title = (char *) pMis->itemData;
4897 HDC hdc = GetDC (hwnd);
4898 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4899 LOGFONT menu_logfont;
4900 HFONT old_font;
4901 SIZE size;
4902
4903 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4904 menu_logfont.lfWeight = FW_BOLD;
4905 menu_font = CreateFontIndirect (&menu_logfont);
4906 old_font = SelectObject (hdc, menu_font);
4907
4908 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4909 if (title)
4910 {
4911 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4912 pMis->itemWidth = size.cx;
4913 if (pMis->itemHeight < size.cy)
4914 pMis->itemHeight = size.cy;
4915 }
4916 else
4917 pMis->itemWidth = 0;
4918
4919 SelectObject (hdc, old_font);
4920 DeleteObject (menu_font);
4921 ReleaseDC (hwnd, hdc);
4922 return TRUE;
4923 }
4924 }
4925 return 0;
4926
4927 case WM_DRAWITEM:
4928 f = x_window_to_frame (dpyinfo, hwnd);
4929 if (f)
4930 {
4931 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4932
4933 if (pDis->CtlType == ODT_MENU)
4934 {
4935 /* Draw popup menu title. */
4936 char * title = (char *) pDis->itemData;
4937 if (title)
4938 {
4939 HDC hdc = pDis->hDC;
4940 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4941 LOGFONT menu_logfont;
4942 HFONT old_font;
4943
4944 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4945 menu_logfont.lfWeight = FW_BOLD;
4946 menu_font = CreateFontIndirect (&menu_logfont);
4947 old_font = SelectObject (hdc, menu_font);
4948
4949 /* Always draw title as if not selected. */
4950 ExtTextOut (hdc,
4951 pDis->rcItem.left
4952 + GetSystemMetrics (SM_CXMENUCHECK),
4953 pDis->rcItem.top,
4954 ETO_OPAQUE, &pDis->rcItem,
4955 title, strlen (title), NULL);
4956
4957 SelectObject (hdc, old_font);
4958 DeleteObject (menu_font);
4959 }
4960 return TRUE;
4961 }
4962 }
4963 return 0;
4964
4965 #if 0
4966 /* Still not right - can't distinguish between clicks in the
4967 client area of the frame from clicks forwarded from the scroll
4968 bars - may have to hook WM_NCHITTEST to remember the mouse
4969 position and then check if it is in the client area ourselves. */
4970 case WM_MOUSEACTIVATE:
4971 /* Discard the mouse click that activates a frame, allowing the
4972 user to click anywhere without changing point (or worse!).
4973 Don't eat mouse clicks on scrollbars though!! */
4974 if (LOWORD (lParam) == HTCLIENT )
4975 return MA_ACTIVATEANDEAT;
4976 goto dflt;
4977 #endif
4978
4979 case WM_MOUSELEAVE:
4980 /* No longer tracking mouse. */
4981 track_mouse_window = NULL;
4982
4983 case WM_ACTIVATEAPP:
4984 case WM_ACTIVATE:
4985 case WM_WINDOWPOSCHANGED:
4986 case WM_SHOWWINDOW:
4987 /* Inform lisp thread that a frame might have just been obscured
4988 or exposed, so should recheck visibility of all frames. */
4989 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4990 goto dflt;
4991
4992 case WM_SETFOCUS:
4993 dpyinfo->faked_key = 0;
4994 reset_modifiers ();
4995 register_hot_keys (hwnd);
4996 goto command;
4997 case WM_KILLFOCUS:
4998 unregister_hot_keys (hwnd);
4999 button_state = 0;
5000 ReleaseCapture ();
5001 /* Relinquish the system caret. */
5002 if (w32_system_caret_hwnd)
5003 {
5004 w32_visible_system_caret_hwnd = NULL;
5005 w32_system_caret_hwnd = NULL;
5006 DestroyCaret ();
5007 }
5008 goto command;
5009 case WM_COMMAND:
5010 f = x_window_to_frame (dpyinfo, hwnd);
5011 if (f && HIWORD (wParam) == 0)
5012 {
5013 f->output_data.w32->menu_command_in_progress = 1;
5014 if (menu_free_timer)
5015 {
5016 KillTimer (hwnd, menu_free_timer);
5017 menu_free_timer = 0;
5018 }
5019 }
5020 case WM_MOVE:
5021 case WM_SIZE:
5022 command:
5023 wmsg.dwModifiers = w32_get_modifiers ();
5024 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5025 goto dflt;
5026
5027 case WM_CLOSE:
5028 wmsg.dwModifiers = w32_get_modifiers ();
5029 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5030 return 0;
5031
5032 case WM_WINDOWPOSCHANGING:
5033 /* Don't restrict the sizing of tip frames. */
5034 if (hwnd == tip_window)
5035 return 0;
5036 {
5037 WINDOWPLACEMENT wp;
5038 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
5039
5040 wp.length = sizeof (WINDOWPLACEMENT);
5041 GetWindowPlacement (hwnd, &wp);
5042
5043 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
5044 {
5045 RECT rect;
5046 int wdiff;
5047 int hdiff;
5048 DWORD font_width;
5049 DWORD line_height;
5050 DWORD internal_border;
5051 DWORD scrollbar_extra;
5052 RECT wr;
5053
5054 wp.length = sizeof(wp);
5055 GetWindowRect (hwnd, &wr);
5056
5057 enter_crit ();
5058
5059 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5060 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5061 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5062 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
5063
5064 leave_crit ();
5065
5066 memset (&rect, 0, sizeof (rect));
5067 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5068 GetMenu (hwnd) != NULL);
5069
5070 /* Force width and height of client area to be exact
5071 multiples of the character cell dimensions. */
5072 wdiff = (lppos->cx - (rect.right - rect.left)
5073 - 2 * internal_border - scrollbar_extra)
5074 % font_width;
5075 hdiff = (lppos->cy - (rect.bottom - rect.top)
5076 - 2 * internal_border)
5077 % line_height;
5078
5079 if (wdiff || hdiff)
5080 {
5081 /* For right/bottom sizing we can just fix the sizes.
5082 However for top/left sizing we will need to fix the X
5083 and Y positions as well. */
5084
5085 lppos->cx -= wdiff;
5086 lppos->cy -= hdiff;
5087
5088 if (wp.showCmd != SW_SHOWMAXIMIZED
5089 && (lppos->flags & SWP_NOMOVE) == 0)
5090 {
5091 if (lppos->x != wr.left || lppos->y != wr.top)
5092 {
5093 lppos->x += wdiff;
5094 lppos->y += hdiff;
5095 }
5096 else
5097 {
5098 lppos->flags |= SWP_NOMOVE;
5099 }
5100 }
5101
5102 return 0;
5103 }
5104 }
5105 }
5106
5107 goto dflt;
5108
5109 case WM_GETMINMAXINFO:
5110 /* Hack to correct bug that allows Emacs frames to be resized
5111 below the Minimum Tracking Size. */
5112 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
5113 /* Hack to allow resizing the Emacs frame above the screen size.
5114 Note that Windows 9x limits coordinates to 16-bits. */
5115 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5116 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
5117 return 0;
5118
5119 case WM_EMACS_CREATESCROLLBAR:
5120 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5121 (struct scroll_bar *) lParam);
5122
5123 case WM_EMACS_SHOWWINDOW:
5124 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5125
5126 case WM_EMACS_SETFOREGROUND:
5127 {
5128 HWND foreground_window;
5129 DWORD foreground_thread, retval;
5130
5131 /* On NT 5.0, and apparently Windows 98, it is necessary to
5132 attach to the thread that currently has focus in order to
5133 pull the focus away from it. */
5134 foreground_window = GetForegroundWindow ();
5135 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5136 if (!foreground_window
5137 || foreground_thread == GetCurrentThreadId ()
5138 || !AttachThreadInput (GetCurrentThreadId (),
5139 foreground_thread, TRUE))
5140 foreground_thread = 0;
5141
5142 retval = SetForegroundWindow ((HWND) wParam);
5143
5144 /* Detach from the previous foreground thread. */
5145 if (foreground_thread)
5146 AttachThreadInput (GetCurrentThreadId (),
5147 foreground_thread, FALSE);
5148
5149 return retval;
5150 }
5151
5152 case WM_EMACS_SETWINDOWPOS:
5153 {
5154 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5155 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5156 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5157 }
5158
5159 case WM_EMACS_DESTROYWINDOW:
5160 DragAcceptFiles ((HWND) wParam, FALSE);
5161 return DestroyWindow ((HWND) wParam);
5162
5163 case WM_EMACS_HIDE_CARET:
5164 return HideCaret (hwnd);
5165
5166 case WM_EMACS_SHOW_CARET:
5167 return ShowCaret (hwnd);
5168
5169 case WM_EMACS_DESTROY_CARET:
5170 w32_system_caret_hwnd = NULL;
5171 w32_visible_system_caret_hwnd = NULL;
5172 return DestroyCaret ();
5173
5174 case WM_EMACS_TRACK_CARET:
5175 /* If there is currently no system caret, create one. */
5176 if (w32_system_caret_hwnd == NULL)
5177 {
5178 /* Use the default caret width, and avoid changing it
5179 unneccesarily, as it confuses screen reader software. */
5180 w32_system_caret_hwnd = hwnd;
5181 CreateCaret (hwnd, NULL, 0,
5182 w32_system_caret_height);
5183 }
5184
5185 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5186 return 0;
5187 /* Ensure visible caret gets turned on when requested. */
5188 else if (w32_use_visible_system_caret
5189 && w32_visible_system_caret_hwnd != hwnd)
5190 {
5191 w32_visible_system_caret_hwnd = hwnd;
5192 return ShowCaret (hwnd);
5193 }
5194 /* Ensure visible caret gets turned off when requested. */
5195 else if (!w32_use_visible_system_caret
5196 && w32_visible_system_caret_hwnd)
5197 {
5198 w32_visible_system_caret_hwnd = NULL;
5199 return HideCaret (hwnd);
5200 }
5201 else
5202 return 1;
5203
5204 case WM_EMACS_TRACKPOPUPMENU:
5205 {
5206 UINT flags;
5207 POINT *pos;
5208 int retval;
5209 pos = (POINT *)lParam;
5210 flags = TPM_CENTERALIGN;
5211 if (button_state & LMOUSE)
5212 flags |= TPM_LEFTBUTTON;
5213 else if (button_state & RMOUSE)
5214 flags |= TPM_RIGHTBUTTON;
5215
5216 /* Remember we did a SetCapture on the initial mouse down event,
5217 so for safety, we make sure the capture is cancelled now. */
5218 ReleaseCapture ();
5219 button_state = 0;
5220
5221 /* Use menubar_active to indicate that WM_INITMENU is from
5222 TrackPopupMenu below, and should be ignored. */
5223 f = x_window_to_frame (dpyinfo, hwnd);
5224 if (f)
5225 f->output_data.w32->menubar_active = 1;
5226
5227 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5228 0, hwnd, NULL))
5229 {
5230 MSG amsg;
5231 /* Eat any mouse messages during popupmenu */
5232 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5233 PM_REMOVE));
5234 /* Get the menu selection, if any */
5235 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5236 {
5237 retval = LOWORD (amsg.wParam);
5238 }
5239 else
5240 {
5241 retval = 0;
5242 }
5243 }
5244 else
5245 {
5246 retval = -1;
5247 }
5248
5249 return retval;
5250 }
5251
5252 default:
5253 /* Check for messages registered at runtime. */
5254 if (msg == msh_mousewheel)
5255 {
5256 wmsg.dwModifiers = w32_get_modifiers ();
5257 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5258 return 0;
5259 }
5260
5261 dflt:
5262 return DefWindowProc (hwnd, msg, wParam, lParam);
5263 }
5264
5265
5266 /* The most common default return code for handled messages is 0. */
5267 return 0;
5268 }
5269
5270 void
5271 my_create_window (f)
5272 struct frame * f;
5273 {
5274 MSG msg;
5275
5276 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5277 abort ();
5278 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5279 }
5280
5281
5282 /* Create a tooltip window. Unlike my_create_window, we do not do this
5283 indirectly via the Window thread, as we do not need to process Window
5284 messages for the tooltip. Creating tooltips indirectly also creates
5285 deadlocks when tooltips are created for menu items. */
5286 void
5287 my_create_tip_window (f)
5288 struct frame *f;
5289 {
5290 RECT rect;
5291
5292 rect.left = rect.top = 0;
5293 rect.right = PIXEL_WIDTH (f);
5294 rect.bottom = PIXEL_HEIGHT (f);
5295
5296 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5297 FRAME_EXTERNAL_MENU_BAR (f));
5298
5299 tip_window = FRAME_W32_WINDOW (f)
5300 = CreateWindow (EMACS_CLASS,
5301 f->namebuf,
5302 f->output_data.w32->dwStyle,
5303 f->output_data.w32->left_pos,
5304 f->output_data.w32->top_pos,
5305 rect.right - rect.left,
5306 rect.bottom - rect.top,
5307 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5308 NULL,
5309 hinst,
5310 NULL);
5311
5312 if (tip_window)
5313 {
5314 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5315 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5316 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5317 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5318
5319 /* Tip frames have no scrollbars. */
5320 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
5321
5322 /* Do this to discard the default setting specified by our parent. */
5323 ShowWindow (tip_window, SW_HIDE);
5324 }
5325 }
5326
5327
5328 /* Create and set up the w32 window for frame F. */
5329
5330 static void
5331 w32_window (f, window_prompting, minibuffer_only)
5332 struct frame *f;
5333 long window_prompting;
5334 int minibuffer_only;
5335 {
5336 BLOCK_INPUT;
5337
5338 /* Use the resource name as the top-level window name
5339 for looking up resources. Make a non-Lisp copy
5340 for the window manager, so GC relocation won't bother it.
5341
5342 Elsewhere we specify the window name for the window manager. */
5343
5344 {
5345 char *str = (char *) XSTRING (Vx_resource_name)->data;
5346 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5347 strcpy (f->namebuf, str);
5348 }
5349
5350 my_create_window (f);
5351
5352 validate_x_resource_name ();
5353
5354 /* x_set_name normally ignores requests to set the name if the
5355 requested name is the same as the current name. This is the one
5356 place where that assumption isn't correct; f->name is set, but
5357 the server hasn't been told. */
5358 {
5359 Lisp_Object name;
5360 int explicit = f->explicit_name;
5361
5362 f->explicit_name = 0;
5363 name = f->name;
5364 f->name = Qnil;
5365 x_set_name (f, name, explicit);
5366 }
5367
5368 UNBLOCK_INPUT;
5369
5370 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5371 initialize_frame_menubar (f);
5372
5373 if (FRAME_W32_WINDOW (f) == 0)
5374 error ("Unable to create window");
5375 }
5376
5377 /* Handle the icon stuff for this window. Perhaps later we might
5378 want an x_set_icon_position which can be called interactively as
5379 well. */
5380
5381 static void
5382 x_icon (f, parms)
5383 struct frame *f;
5384 Lisp_Object parms;
5385 {
5386 Lisp_Object icon_x, icon_y;
5387
5388 /* Set the position of the icon. Note that Windows 95 groups all
5389 icons in the tray. */
5390 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5391 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5392 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5393 {
5394 CHECK_NUMBER (icon_x);
5395 CHECK_NUMBER (icon_y);
5396 }
5397 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5398 error ("Both left and top icon corners of icon must be specified");
5399
5400 BLOCK_INPUT;
5401
5402 if (! EQ (icon_x, Qunbound))
5403 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5404
5405 #if 0 /* TODO */
5406 /* Start up iconic or window? */
5407 x_wm_set_window_state
5408 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5409 ? IconicState
5410 : NormalState));
5411
5412 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5413 ? f->icon_name
5414 : f->name))->data);
5415 #endif
5416
5417 UNBLOCK_INPUT;
5418 }
5419
5420
5421 static void
5422 x_make_gc (f)
5423 struct frame *f;
5424 {
5425 XGCValues gc_values;
5426
5427 BLOCK_INPUT;
5428
5429 /* Create the GC's of this frame.
5430 Note that many default values are used. */
5431
5432 /* Normal video */
5433 gc_values.font = f->output_data.w32->font;
5434
5435 /* Cursor has cursor-color background, background-color foreground. */
5436 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5437 gc_values.background = f->output_data.w32->cursor_pixel;
5438 f->output_data.w32->cursor_gc
5439 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5440 (GCFont | GCForeground | GCBackground),
5441 &gc_values);
5442
5443 /* Reliefs. */
5444 f->output_data.w32->white_relief.gc = 0;
5445 f->output_data.w32->black_relief.gc = 0;
5446
5447 UNBLOCK_INPUT;
5448 }
5449
5450
5451 /* Handler for signals raised during x_create_frame and
5452 x_create_top_frame. FRAME is the frame which is partially
5453 constructed. */
5454
5455 static Lisp_Object
5456 unwind_create_frame (frame)
5457 Lisp_Object frame;
5458 {
5459 struct frame *f = XFRAME (frame);
5460
5461 /* If frame is ``official'', nothing to do. */
5462 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5463 {
5464 #ifdef GLYPH_DEBUG
5465 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5466 #endif
5467
5468 x_free_frame_resources (f);
5469
5470 /* Check that reference counts are indeed correct. */
5471 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5472 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5473
5474 return Qt;
5475 }
5476
5477 return Qnil;
5478 }
5479
5480
5481 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5482 1, 1, 0,
5483 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5484 Returns an Emacs frame object.
5485 ALIST is an alist of frame parameters.
5486 If the parameters specify that the frame should not have a minibuffer,
5487 and do not specify a specific minibuffer window to use,
5488 then `default-minibuffer-frame' must be a frame whose minibuffer can
5489 be shared by the new frame.
5490
5491 This function is an internal primitive--use `make-frame' instead. */)
5492 (parms)
5493 Lisp_Object parms;
5494 {
5495 struct frame *f;
5496 Lisp_Object frame, tem;
5497 Lisp_Object name;
5498 int minibuffer_only = 0;
5499 long window_prompting = 0;
5500 int width, height;
5501 int count = BINDING_STACK_SIZE ();
5502 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5503 Lisp_Object display;
5504 struct w32_display_info *dpyinfo = NULL;
5505 Lisp_Object parent;
5506 struct kboard *kb;
5507
5508 check_w32 ();
5509
5510 /* Use this general default value to start with
5511 until we know if this frame has a specified name. */
5512 Vx_resource_name = Vinvocation_name;
5513
5514 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5515 if (EQ (display, Qunbound))
5516 display = Qnil;
5517 dpyinfo = check_x_display_info (display);
5518 #ifdef MULTI_KBOARD
5519 kb = dpyinfo->kboard;
5520 #else
5521 kb = &the_only_kboard;
5522 #endif
5523
5524 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5525 if (!STRINGP (name)
5526 && ! EQ (name, Qunbound)
5527 && ! NILP (name))
5528 error ("Invalid frame name--not a string or nil");
5529
5530 if (STRINGP (name))
5531 Vx_resource_name = name;
5532
5533 /* See if parent window is specified. */
5534 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5535 if (EQ (parent, Qunbound))
5536 parent = Qnil;
5537 if (! NILP (parent))
5538 CHECK_NUMBER (parent);
5539
5540 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5541 /* No need to protect DISPLAY because that's not used after passing
5542 it to make_frame_without_minibuffer. */
5543 frame = Qnil;
5544 GCPRO4 (parms, parent, name, frame);
5545 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5546 RES_TYPE_SYMBOL);
5547 if (EQ (tem, Qnone) || NILP (tem))
5548 f = make_frame_without_minibuffer (Qnil, kb, display);
5549 else if (EQ (tem, Qonly))
5550 {
5551 f = make_minibuffer_frame ();
5552 minibuffer_only = 1;
5553 }
5554 else if (WINDOWP (tem))
5555 f = make_frame_without_minibuffer (tem, kb, display);
5556 else
5557 f = make_frame (1);
5558
5559 XSETFRAME (frame, f);
5560
5561 /* Note that Windows does support scroll bars. */
5562 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5563 /* By default, make scrollbars the system standard width. */
5564 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5565
5566 f->output_method = output_w32;
5567 f->output_data.w32 =
5568 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5569 bzero (f->output_data.w32, sizeof (struct w32_output));
5570 FRAME_FONTSET (f) = -1;
5571 record_unwind_protect (unwind_create_frame, frame);
5572
5573 f->icon_name
5574 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5575 if (! STRINGP (f->icon_name))
5576 f->icon_name = Qnil;
5577
5578 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5579 #ifdef MULTI_KBOARD
5580 FRAME_KBOARD (f) = kb;
5581 #endif
5582
5583 /* Specify the parent under which to make this window. */
5584
5585 if (!NILP (parent))
5586 {
5587 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5588 f->output_data.w32->explicit_parent = 1;
5589 }
5590 else
5591 {
5592 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5593 f->output_data.w32->explicit_parent = 0;
5594 }
5595
5596 /* Set the name; the functions to which we pass f expect the name to
5597 be set. */
5598 if (EQ (name, Qunbound) || NILP (name))
5599 {
5600 f->name = build_string (dpyinfo->w32_id_name);
5601 f->explicit_name = 0;
5602 }
5603 else
5604 {
5605 f->name = name;
5606 f->explicit_name = 1;
5607 /* use the frame's title when getting resources for this frame. */
5608 specbind (Qx_resource_name, name);
5609 }
5610
5611 /* Extract the window parameters from the supplied values
5612 that are needed to determine window geometry. */
5613 {
5614 Lisp_Object font;
5615
5616 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5617
5618 BLOCK_INPUT;
5619 /* First, try whatever font the caller has specified. */
5620 if (STRINGP (font))
5621 {
5622 tem = Fquery_fontset (font, Qnil);
5623 if (STRINGP (tem))
5624 font = x_new_fontset (f, XSTRING (tem)->data);
5625 else
5626 font = x_new_font (f, XSTRING (font)->data);
5627 }
5628 /* Try out a font which we hope has bold and italic variations. */
5629 if (!STRINGP (font))
5630 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5631 if (! STRINGP (font))
5632 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5633 /* If those didn't work, look for something which will at least work. */
5634 if (! STRINGP (font))
5635 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5636 UNBLOCK_INPUT;
5637 if (! STRINGP (font))
5638 font = build_string ("Fixedsys");
5639
5640 x_default_parameter (f, parms, Qfont, font,
5641 "font", "Font", RES_TYPE_STRING);
5642 }
5643
5644 x_default_parameter (f, parms, Qborder_width, make_number (2),
5645 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5646 /* This defaults to 2 in order to match xterm. We recognize either
5647 internalBorderWidth or internalBorder (which is what xterm calls
5648 it). */
5649 if (NILP (Fassq (Qinternal_border_width, parms)))
5650 {
5651 Lisp_Object value;
5652
5653 value = w32_get_arg (parms, Qinternal_border_width,
5654 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5655 if (! EQ (value, Qunbound))
5656 parms = Fcons (Fcons (Qinternal_border_width, value),
5657 parms);
5658 }
5659 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5660 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5661 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5662 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5663 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5664
5665 /* Also do the stuff which must be set before the window exists. */
5666 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5667 "foreground", "Foreground", RES_TYPE_STRING);
5668 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5669 "background", "Background", RES_TYPE_STRING);
5670 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5671 "pointerColor", "Foreground", RES_TYPE_STRING);
5672 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5673 "cursorColor", "Foreground", RES_TYPE_STRING);
5674 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5675 "borderColor", "BorderColor", RES_TYPE_STRING);
5676 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5677 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5678 x_default_parameter (f, parms, Qline_spacing, Qnil,
5679 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5680 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5681 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5682 x_default_parameter (f, parms, Qright_fringe, Qnil,
5683 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
5684
5685
5686 /* Init faces before x_default_parameter is called for scroll-bar
5687 parameters because that function calls x_set_scroll_bar_width,
5688 which calls change_frame_size, which calls Fset_window_buffer,
5689 which runs hooks, which call Fvertical_motion. At the end, we
5690 end up in init_iterator with a null face cache, which should not
5691 happen. */
5692 init_frame_faces (f);
5693
5694 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5695 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5696 x_default_parameter (f, parms, Qtool_bar_lines, make_number (1),
5697 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5698
5699 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5700 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5701 x_default_parameter (f, parms, Qtitle, Qnil,
5702 "title", "Title", RES_TYPE_STRING);
5703 x_default_parameter (f, parms, Qfullscreen, Qnil,
5704 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
5705
5706 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5707 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5708
5709 /* Add the tool-bar height to the initial frame height so that the
5710 user gets a text display area of the size he specified with -g or
5711 via .Xdefaults. Later changes of the tool-bar height don't
5712 change the frame size. This is done so that users can create
5713 tall Emacs frames without having to guess how tall the tool-bar
5714 will get. */
5715 if (FRAME_TOOL_BAR_LINES (f))
5716 {
5717 int margin, relief, bar_height;
5718
5719 relief = (tool_bar_button_relief >= 0
5720 ? tool_bar_button_relief
5721 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5722
5723 if (INTEGERP (Vtool_bar_button_margin)
5724 && XINT (Vtool_bar_button_margin) > 0)
5725 margin = XFASTINT (Vtool_bar_button_margin);
5726 else if (CONSP (Vtool_bar_button_margin)
5727 && INTEGERP (XCDR (Vtool_bar_button_margin))
5728 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5729 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5730 else
5731 margin = 0;
5732
5733 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5734 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5735 }
5736
5737 window_prompting = x_figure_window_size (f, parms);
5738
5739 if (window_prompting & XNegative)
5740 {
5741 if (window_prompting & YNegative)
5742 f->output_data.w32->win_gravity = SouthEastGravity;
5743 else
5744 f->output_data.w32->win_gravity = NorthEastGravity;
5745 }
5746 else
5747 {
5748 if (window_prompting & YNegative)
5749 f->output_data.w32->win_gravity = SouthWestGravity;
5750 else
5751 f->output_data.w32->win_gravity = NorthWestGravity;
5752 }
5753
5754 f->output_data.w32->size_hint_flags = window_prompting;
5755
5756 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5757 f->no_split = minibuffer_only || EQ (tem, Qt);
5758
5759 w32_window (f, window_prompting, minibuffer_only);
5760 x_icon (f, parms);
5761
5762 x_make_gc (f);
5763
5764 /* Now consider the frame official. */
5765 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5766 Vframe_list = Fcons (frame, Vframe_list);
5767
5768 /* We need to do this after creating the window, so that the
5769 icon-creation functions can say whose icon they're describing. */
5770 x_default_parameter (f, parms, Qicon_type, Qnil,
5771 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5772
5773 x_default_parameter (f, parms, Qauto_raise, Qnil,
5774 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5775 x_default_parameter (f, parms, Qauto_lower, Qnil,
5776 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5777 x_default_parameter (f, parms, Qcursor_type, Qbox,
5778 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5779 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5780 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5781
5782 /* Dimensions, especially f->height, must be done via change_frame_size.
5783 Change will not be effected unless different from the current
5784 f->height. */
5785 width = f->width;
5786 height = f->height;
5787
5788 f->height = 0;
5789 SET_FRAME_WIDTH (f, 0);
5790 change_frame_size (f, height, width, 1, 0, 0);
5791
5792 /* Tell the server what size and position, etc, we want, and how
5793 badly we want them. This should be done after we have the menu
5794 bar so that its size can be taken into account. */
5795 BLOCK_INPUT;
5796 x_wm_set_size_hint (f, window_prompting, 0);
5797 UNBLOCK_INPUT;
5798
5799 /* Avoid a bug that causes the new frame to never become visible if
5800 an echo area message is displayed during the following call1. */
5801 specbind(Qredisplay_dont_pause, Qt);
5802
5803 /* Set up faces after all frame parameters are known. This call
5804 also merges in face attributes specified for new frames. If we
5805 don't do this, the `menu' face for instance won't have the right
5806 colors, and the menu bar won't appear in the specified colors for
5807 new frames. */
5808 call1 (Qface_set_after_frame_default, frame);
5809
5810 /* Make the window appear on the frame and enable display, unless
5811 the caller says not to. However, with explicit parent, Emacs
5812 cannot control visibility, so don't try. */
5813 if (! f->output_data.w32->explicit_parent)
5814 {
5815 Lisp_Object visibility;
5816
5817 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5818 if (EQ (visibility, Qunbound))
5819 visibility = Qt;
5820
5821 if (EQ (visibility, Qicon))
5822 x_iconify_frame (f);
5823 else if (! NILP (visibility))
5824 x_make_frame_visible (f);
5825 else
5826 /* Must have been Qnil. */
5827 ;
5828 }
5829 UNGCPRO;
5830
5831 /* Make sure windows on this frame appear in calls to next-window
5832 and similar functions. */
5833 Vwindow_list = Qnil;
5834
5835 return unbind_to (count, frame);
5836 }
5837
5838 /* FRAME is used only to get a handle on the X display. We don't pass the
5839 display info directly because we're called from frame.c, which doesn't
5840 know about that structure. */
5841 Lisp_Object
5842 x_get_focus_frame (frame)
5843 struct frame *frame;
5844 {
5845 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5846 Lisp_Object xfocus;
5847 if (! dpyinfo->w32_focus_frame)
5848 return Qnil;
5849
5850 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5851 return xfocus;
5852 }
5853
5854 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5855 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
5856 (frame)
5857 Lisp_Object frame;
5858 {
5859 x_focus_on_frame (check_x_frame (frame));
5860 return Qnil;
5861 }
5862
5863 \f
5864 /* Return the charset portion of a font name. */
5865 char * xlfd_charset_of_font (char * fontname)
5866 {
5867 char *charset, *encoding;
5868
5869 encoding = strrchr(fontname, '-');
5870 if (!encoding || encoding == fontname)
5871 return NULL;
5872
5873 for (charset = encoding - 1; charset >= fontname; charset--)
5874 if (*charset == '-')
5875 break;
5876
5877 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5878 return NULL;
5879
5880 return charset + 1;
5881 }
5882
5883 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5884 int size, char* filename);
5885 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5886 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5887 char * charset);
5888 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5889
5890 static struct font_info *
5891 w32_load_system_font (f,fontname,size)
5892 struct frame *f;
5893 char * fontname;
5894 int size;
5895 {
5896 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5897 Lisp_Object font_names;
5898
5899 /* Get a list of all the fonts that match this name. Once we
5900 have a list of matching fonts, we compare them against the fonts
5901 we already have loaded by comparing names. */
5902 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5903
5904 if (!NILP (font_names))
5905 {
5906 Lisp_Object tail;
5907 int i;
5908
5909 /* First check if any are already loaded, as that is cheaper
5910 than loading another one. */
5911 for (i = 0; i < dpyinfo->n_fonts; i++)
5912 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5913 if (dpyinfo->font_table[i].name
5914 && (!strcmp (dpyinfo->font_table[i].name,
5915 XSTRING (XCAR (tail))->data)
5916 || !strcmp (dpyinfo->font_table[i].full_name,
5917 XSTRING (XCAR (tail))->data)))
5918 return (dpyinfo->font_table + i);
5919
5920 fontname = (char *) XSTRING (XCAR (font_names))->data;
5921 }
5922 else if (w32_strict_fontnames)
5923 {
5924 /* If EnumFontFamiliesEx was available, we got a full list of
5925 fonts back so stop now to avoid the possibility of loading a
5926 random font. If we had to fall back to EnumFontFamilies, the
5927 list is incomplete, so continue whether the font we want was
5928 listed or not. */
5929 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5930 FARPROC enum_font_families_ex
5931 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5932 if (enum_font_families_ex)
5933 return NULL;
5934 }
5935
5936 /* Load the font and add it to the table. */
5937 {
5938 char *full_name, *encoding, *charset;
5939 XFontStruct *font;
5940 struct font_info *fontp;
5941 LOGFONT lf;
5942 BOOL ok;
5943 int codepage;
5944 int i;
5945
5946 if (!fontname || !x_to_w32_font (fontname, &lf))
5947 return (NULL);
5948
5949 if (!*lf.lfFaceName)
5950 /* If no name was specified for the font, we get a random font
5951 from CreateFontIndirect - this is not particularly
5952 desirable, especially since CreateFontIndirect does not
5953 fill out the missing name in lf, so we never know what we
5954 ended up with. */
5955 return NULL;
5956
5957 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5958 since those fonts leave garbage behind. */
5959 lf.lfQuality = ANTIALIASED_QUALITY;
5960
5961 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5962 bzero (font, sizeof (*font));
5963
5964 /* Set bdf to NULL to indicate that this is a Windows font. */
5965 font->bdf = NULL;
5966
5967 BLOCK_INPUT;
5968
5969 font->hfont = CreateFontIndirect (&lf);
5970
5971 if (font->hfont == NULL)
5972 {
5973 ok = FALSE;
5974 }
5975 else
5976 {
5977 HDC hdc;
5978 HANDLE oldobj;
5979
5980 codepage = w32_codepage_for_font (fontname);
5981
5982 hdc = GetDC (dpyinfo->root_window);
5983 oldobj = SelectObject (hdc, font->hfont);
5984
5985 ok = GetTextMetrics (hdc, &font->tm);
5986 if (codepage == CP_UNICODE)
5987 font->double_byte_p = 1;
5988 else
5989 {
5990 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5991 don't report themselves as double byte fonts, when
5992 patently they are. So instead of trusting
5993 GetFontLanguageInfo, we check the properties of the
5994 codepage directly, since that is ultimately what we are
5995 working from anyway. */
5996 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5997 CPINFO cpi = {0};
5998 GetCPInfo (codepage, &cpi);
5999 font->double_byte_p = cpi.MaxCharSize > 1;
6000 }
6001
6002 SelectObject (hdc, oldobj);
6003 ReleaseDC (dpyinfo->root_window, hdc);
6004 /* Fill out details in lf according to the font that was
6005 actually loaded. */
6006 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
6007 lf.lfWidth = font->tm.tmAveCharWidth;
6008 lf.lfWeight = font->tm.tmWeight;
6009 lf.lfItalic = font->tm.tmItalic;
6010 lf.lfCharSet = font->tm.tmCharSet;
6011 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
6012 ? VARIABLE_PITCH : FIXED_PITCH);
6013 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
6014 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
6015
6016 w32_cache_char_metrics (font);
6017 }
6018
6019 UNBLOCK_INPUT;
6020
6021 if (!ok)
6022 {
6023 w32_unload_font (dpyinfo, font);
6024 return (NULL);
6025 }
6026
6027 /* Find a free slot in the font table. */
6028 for (i = 0; i < dpyinfo->n_fonts; ++i)
6029 if (dpyinfo->font_table[i].name == NULL)
6030 break;
6031
6032 /* If no free slot found, maybe enlarge the font table. */
6033 if (i == dpyinfo->n_fonts
6034 && dpyinfo->n_fonts == dpyinfo->font_table_size)
6035 {
6036 int sz;
6037 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6038 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
6039 dpyinfo->font_table
6040 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
6041 }
6042
6043 fontp = dpyinfo->font_table + i;
6044 if (i == dpyinfo->n_fonts)
6045 ++dpyinfo->n_fonts;
6046
6047 /* Now fill in the slots of *FONTP. */
6048 BLOCK_INPUT;
6049 fontp->font = font;
6050 fontp->font_idx = i;
6051 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6052 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6053
6054 charset = xlfd_charset_of_font (fontname);
6055
6056 /* Cache the W32 codepage for a font. This makes w32_encode_char
6057 (called for every glyph during redisplay) much faster. */
6058 fontp->codepage = codepage;
6059
6060 /* Work out the font's full name. */
6061 full_name = (char *)xmalloc (100);
6062 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
6063 fontp->full_name = full_name;
6064 else
6065 {
6066 /* If all else fails - just use the name we used to load it. */
6067 xfree (full_name);
6068 fontp->full_name = fontp->name;
6069 }
6070
6071 fontp->size = FONT_WIDTH (font);
6072 fontp->height = FONT_HEIGHT (font);
6073
6074 /* The slot `encoding' specifies how to map a character
6075 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
6076 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6077 (0:0x20..0x7F, 1:0xA0..0xFF,
6078 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
6079 2:0xA020..0xFF7F). For the moment, we don't know which charset
6080 uses this font. So, we set information in fontp->encoding[1]
6081 which is never used by any charset. If mapping can't be
6082 decided, set FONT_ENCODING_NOT_DECIDED. */
6083
6084 /* SJIS fonts need to be set to type 4, all others seem to work as
6085 type FONT_ENCODING_NOT_DECIDED. */
6086 encoding = strrchr (fontp->name, '-');
6087 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
6088 fontp->encoding[1] = 4;
6089 else
6090 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
6091
6092 /* The following three values are set to 0 under W32, which is
6093 what they get set to if XGetFontProperty fails under X. */
6094 fontp->baseline_offset = 0;
6095 fontp->relative_compose = 0;
6096 fontp->default_ascent = 0;
6097
6098 /* Set global flag fonts_changed_p to non-zero if the font loaded
6099 has a character with a smaller width than any other character
6100 before, or if the font loaded has a smaller height than any
6101 other font loaded before. If this happens, it will make a
6102 glyph matrix reallocation necessary. */
6103 fonts_changed_p |= x_compute_min_glyph_bounds (f);
6104 UNBLOCK_INPUT;
6105 return fontp;
6106 }
6107 }
6108
6109 /* Load font named FONTNAME of size SIZE for frame F, and return a
6110 pointer to the structure font_info while allocating it dynamically.
6111 If loading fails, return NULL. */
6112 struct font_info *
6113 w32_load_font (f,fontname,size)
6114 struct frame *f;
6115 char * fontname;
6116 int size;
6117 {
6118 Lisp_Object bdf_fonts;
6119 struct font_info *retval = NULL;
6120
6121 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
6122
6123 while (!retval && CONSP (bdf_fonts))
6124 {
6125 char *bdf_name, *bdf_file;
6126 Lisp_Object bdf_pair;
6127
6128 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6129 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6130 bdf_file = XSTRING (XCDR (bdf_pair))->data;
6131
6132 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6133
6134 bdf_fonts = XCDR (bdf_fonts);
6135 }
6136
6137 if (retval)
6138 return retval;
6139
6140 return w32_load_system_font(f, fontname, size);
6141 }
6142
6143
6144 void
6145 w32_unload_font (dpyinfo, font)
6146 struct w32_display_info *dpyinfo;
6147 XFontStruct * font;
6148 {
6149 if (font)
6150 {
6151 if (font->per_char) xfree (font->per_char);
6152 if (font->bdf) w32_free_bdf_font (font->bdf);
6153
6154 if (font->hfont) DeleteObject(font->hfont);
6155 xfree (font);
6156 }
6157 }
6158
6159 /* The font conversion stuff between x and w32 */
6160
6161 /* X font string is as follows (from faces.el)
6162 * (let ((- "[-?]")
6163 * (foundry "[^-]+")
6164 * (family "[^-]+")
6165 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6166 * (weight\? "\\([^-]*\\)") ; 1
6167 * (slant "\\([ior]\\)") ; 2
6168 * (slant\? "\\([^-]?\\)") ; 2
6169 * (swidth "\\([^-]*\\)") ; 3
6170 * (adstyle "[^-]*") ; 4
6171 * (pixelsize "[0-9]+")
6172 * (pointsize "[0-9][0-9]+")
6173 * (resx "[0-9][0-9]+")
6174 * (resy "[0-9][0-9]+")
6175 * (spacing "[cmp?*]")
6176 * (avgwidth "[0-9]+")
6177 * (registry "[^-]+")
6178 * (encoding "[^-]+")
6179 * )
6180 */
6181
6182 static LONG
6183 x_to_w32_weight (lpw)
6184 char * lpw;
6185 {
6186 if (!lpw) return (FW_DONTCARE);
6187
6188 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6189 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6190 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6191 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
6192 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
6193 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6194 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6195 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6196 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6197 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
6198 else
6199 return FW_DONTCARE;
6200 }
6201
6202
6203 static char *
6204 w32_to_x_weight (fnweight)
6205 int fnweight;
6206 {
6207 if (fnweight >= FW_HEAVY) return "heavy";
6208 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6209 if (fnweight >= FW_BOLD) return "bold";
6210 if (fnweight >= FW_SEMIBOLD) return "demibold";
6211 if (fnweight >= FW_MEDIUM) return "medium";
6212 if (fnweight >= FW_NORMAL) return "normal";
6213 if (fnweight >= FW_LIGHT) return "light";
6214 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6215 if (fnweight >= FW_THIN) return "thin";
6216 else
6217 return "*";
6218 }
6219
6220 static LONG
6221 x_to_w32_charset (lpcs)
6222 char * lpcs;
6223 {
6224 Lisp_Object this_entry, w32_charset;
6225 char *charset;
6226 int len = strlen (lpcs);
6227
6228 /* Support "*-#nnn" format for unknown charsets. */
6229 if (strncmp (lpcs, "*-#", 3) == 0)
6230 return atoi (lpcs + 3);
6231
6232 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6233 charset = alloca (len + 1);
6234 strcpy (charset, lpcs);
6235 lpcs = strchr (charset, '*');
6236 if (lpcs)
6237 *lpcs = 0;
6238
6239 /* Look through w32-charset-info-alist for the character set.
6240 Format of each entry is
6241 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6242 */
6243 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6244
6245 if (NILP(this_entry))
6246 {
6247 /* At startup, we want iso8859-1 fonts to come up properly. */
6248 if (stricmp(charset, "iso8859-1") == 0)
6249 return ANSI_CHARSET;
6250 else
6251 return DEFAULT_CHARSET;
6252 }
6253
6254 w32_charset = Fcar (Fcdr (this_entry));
6255
6256 /* Translate Lisp symbol to number. */
6257 if (w32_charset == Qw32_charset_ansi)
6258 return ANSI_CHARSET;
6259 if (w32_charset == Qw32_charset_symbol)
6260 return SYMBOL_CHARSET;
6261 if (w32_charset == Qw32_charset_shiftjis)
6262 return SHIFTJIS_CHARSET;
6263 if (w32_charset == Qw32_charset_hangeul)
6264 return HANGEUL_CHARSET;
6265 if (w32_charset == Qw32_charset_chinesebig5)
6266 return CHINESEBIG5_CHARSET;
6267 if (w32_charset == Qw32_charset_gb2312)
6268 return GB2312_CHARSET;
6269 if (w32_charset == Qw32_charset_oem)
6270 return OEM_CHARSET;
6271 #ifdef JOHAB_CHARSET
6272 if (w32_charset == Qw32_charset_johab)
6273 return JOHAB_CHARSET;
6274 if (w32_charset == Qw32_charset_easteurope)
6275 return EASTEUROPE_CHARSET;
6276 if (w32_charset == Qw32_charset_turkish)
6277 return TURKISH_CHARSET;
6278 if (w32_charset == Qw32_charset_baltic)
6279 return BALTIC_CHARSET;
6280 if (w32_charset == Qw32_charset_russian)
6281 return RUSSIAN_CHARSET;
6282 if (w32_charset == Qw32_charset_arabic)
6283 return ARABIC_CHARSET;
6284 if (w32_charset == Qw32_charset_greek)
6285 return GREEK_CHARSET;
6286 if (w32_charset == Qw32_charset_hebrew)
6287 return HEBREW_CHARSET;
6288 if (w32_charset == Qw32_charset_vietnamese)
6289 return VIETNAMESE_CHARSET;
6290 if (w32_charset == Qw32_charset_thai)
6291 return THAI_CHARSET;
6292 if (w32_charset == Qw32_charset_mac)
6293 return MAC_CHARSET;
6294 #endif /* JOHAB_CHARSET */
6295 #ifdef UNICODE_CHARSET
6296 if (w32_charset == Qw32_charset_unicode)
6297 return UNICODE_CHARSET;
6298 #endif
6299
6300 return DEFAULT_CHARSET;
6301 }
6302
6303
6304 static char *
6305 w32_to_x_charset (fncharset)
6306 int fncharset;
6307 {
6308 static char buf[32];
6309 Lisp_Object charset_type;
6310
6311 switch (fncharset)
6312 {
6313 case ANSI_CHARSET:
6314 /* Handle startup case of w32-charset-info-alist not
6315 being set up yet. */
6316 if (NILP(Vw32_charset_info_alist))
6317 return "iso8859-1";
6318 charset_type = Qw32_charset_ansi;
6319 break;
6320 case DEFAULT_CHARSET:
6321 charset_type = Qw32_charset_default;
6322 break;
6323 case SYMBOL_CHARSET:
6324 charset_type = Qw32_charset_symbol;
6325 break;
6326 case SHIFTJIS_CHARSET:
6327 charset_type = Qw32_charset_shiftjis;
6328 break;
6329 case HANGEUL_CHARSET:
6330 charset_type = Qw32_charset_hangeul;
6331 break;
6332 case GB2312_CHARSET:
6333 charset_type = Qw32_charset_gb2312;
6334 break;
6335 case CHINESEBIG5_CHARSET:
6336 charset_type = Qw32_charset_chinesebig5;
6337 break;
6338 case OEM_CHARSET:
6339 charset_type = Qw32_charset_oem;
6340 break;
6341
6342 /* More recent versions of Windows (95 and NT4.0) define more
6343 character sets. */
6344 #ifdef EASTEUROPE_CHARSET
6345 case EASTEUROPE_CHARSET:
6346 charset_type = Qw32_charset_easteurope;
6347 break;
6348 case TURKISH_CHARSET:
6349 charset_type = Qw32_charset_turkish;
6350 break;
6351 case BALTIC_CHARSET:
6352 charset_type = Qw32_charset_baltic;
6353 break;
6354 case RUSSIAN_CHARSET:
6355 charset_type = Qw32_charset_russian;
6356 break;
6357 case ARABIC_CHARSET:
6358 charset_type = Qw32_charset_arabic;
6359 break;
6360 case GREEK_CHARSET:
6361 charset_type = Qw32_charset_greek;
6362 break;
6363 case HEBREW_CHARSET:
6364 charset_type = Qw32_charset_hebrew;
6365 break;
6366 case VIETNAMESE_CHARSET:
6367 charset_type = Qw32_charset_vietnamese;
6368 break;
6369 case THAI_CHARSET:
6370 charset_type = Qw32_charset_thai;
6371 break;
6372 case MAC_CHARSET:
6373 charset_type = Qw32_charset_mac;
6374 break;
6375 case JOHAB_CHARSET:
6376 charset_type = Qw32_charset_johab;
6377 break;
6378 #endif
6379
6380 #ifdef UNICODE_CHARSET
6381 case UNICODE_CHARSET:
6382 charset_type = Qw32_charset_unicode;
6383 break;
6384 #endif
6385 default:
6386 /* Encode numerical value of unknown charset. */
6387 sprintf (buf, "*-#%u", fncharset);
6388 return buf;
6389 }
6390
6391 {
6392 Lisp_Object rest;
6393 char * best_match = NULL;
6394
6395 /* Look through w32-charset-info-alist for the character set.
6396 Prefer ISO codepages, and prefer lower numbers in the ISO
6397 range. Only return charsets for codepages which are installed.
6398
6399 Format of each entry is
6400 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6401 */
6402 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6403 {
6404 char * x_charset;
6405 Lisp_Object w32_charset;
6406 Lisp_Object codepage;
6407
6408 Lisp_Object this_entry = XCAR (rest);
6409
6410 /* Skip invalid entries in alist. */
6411 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6412 || !CONSP (XCDR (this_entry))
6413 || !SYMBOLP (XCAR (XCDR (this_entry))))
6414 continue;
6415
6416 x_charset = XSTRING (XCAR (this_entry))->data;
6417 w32_charset = XCAR (XCDR (this_entry));
6418 codepage = XCDR (XCDR (this_entry));
6419
6420 /* Look for Same charset and a valid codepage (or non-int
6421 which means ignore). */
6422 if (w32_charset == charset_type
6423 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6424 || IsValidCodePage (XINT (codepage))))
6425 {
6426 /* If we don't have a match already, then this is the
6427 best. */
6428 if (!best_match)
6429 best_match = x_charset;
6430 /* If this is an ISO codepage, and the best so far isn't,
6431 then this is better. */
6432 else if (strnicmp (best_match, "iso", 3) != 0
6433 && strnicmp (x_charset, "iso", 3) == 0)
6434 best_match = x_charset;
6435 /* If both are ISO8859 codepages, choose the one with the
6436 lowest number in the encoding field. */
6437 else if (strnicmp (best_match, "iso8859-", 8) == 0
6438 && strnicmp (x_charset, "iso8859-", 8) == 0)
6439 {
6440 int best_enc = atoi (best_match + 8);
6441 int this_enc = atoi (x_charset + 8);
6442 if (this_enc > 0 && this_enc < best_enc)
6443 best_match = x_charset;
6444 }
6445 }
6446 }
6447
6448 /* If no match, encode the numeric value. */
6449 if (!best_match)
6450 {
6451 sprintf (buf, "*-#%u", fncharset);
6452 return buf;
6453 }
6454
6455 strncpy(buf, best_match, 31);
6456 buf[31] = '\0';
6457 return buf;
6458 }
6459 }
6460
6461
6462 /* Return all the X charsets that map to a font. */
6463 static Lisp_Object
6464 w32_to_all_x_charsets (fncharset)
6465 int fncharset;
6466 {
6467 static char buf[32];
6468 Lisp_Object charset_type;
6469 Lisp_Object retval = Qnil;
6470
6471 switch (fncharset)
6472 {
6473 case ANSI_CHARSET:
6474 /* Handle startup case of w32-charset-info-alist not
6475 being set up yet. */
6476 if (NILP(Vw32_charset_info_alist))
6477 return Fcons (build_string ("iso8859-1"), Qnil);
6478
6479 charset_type = Qw32_charset_ansi;
6480 break;
6481 case DEFAULT_CHARSET:
6482 charset_type = Qw32_charset_default;
6483 break;
6484 case SYMBOL_CHARSET:
6485 charset_type = Qw32_charset_symbol;
6486 break;
6487 case SHIFTJIS_CHARSET:
6488 charset_type = Qw32_charset_shiftjis;
6489 break;
6490 case HANGEUL_CHARSET:
6491 charset_type = Qw32_charset_hangeul;
6492 break;
6493 case GB2312_CHARSET:
6494 charset_type = Qw32_charset_gb2312;
6495 break;
6496 case CHINESEBIG5_CHARSET:
6497 charset_type = Qw32_charset_chinesebig5;
6498 break;
6499 case OEM_CHARSET:
6500 charset_type = Qw32_charset_oem;
6501 break;
6502
6503 /* More recent versions of Windows (95 and NT4.0) define more
6504 character sets. */
6505 #ifdef EASTEUROPE_CHARSET
6506 case EASTEUROPE_CHARSET:
6507 charset_type = Qw32_charset_easteurope;
6508 break;
6509 case TURKISH_CHARSET:
6510 charset_type = Qw32_charset_turkish;
6511 break;
6512 case BALTIC_CHARSET:
6513 charset_type = Qw32_charset_baltic;
6514 break;
6515 case RUSSIAN_CHARSET:
6516 charset_type = Qw32_charset_russian;
6517 break;
6518 case ARABIC_CHARSET:
6519 charset_type = Qw32_charset_arabic;
6520 break;
6521 case GREEK_CHARSET:
6522 charset_type = Qw32_charset_greek;
6523 break;
6524 case HEBREW_CHARSET:
6525 charset_type = Qw32_charset_hebrew;
6526 break;
6527 case VIETNAMESE_CHARSET:
6528 charset_type = Qw32_charset_vietnamese;
6529 break;
6530 case THAI_CHARSET:
6531 charset_type = Qw32_charset_thai;
6532 break;
6533 case MAC_CHARSET:
6534 charset_type = Qw32_charset_mac;
6535 break;
6536 case JOHAB_CHARSET:
6537 charset_type = Qw32_charset_johab;
6538 break;
6539 #endif
6540
6541 #ifdef UNICODE_CHARSET
6542 case UNICODE_CHARSET:
6543 charset_type = Qw32_charset_unicode;
6544 break;
6545 #endif
6546 default:
6547 /* Encode numerical value of unknown charset. */
6548 sprintf (buf, "*-#%u", fncharset);
6549 return Fcons (build_string (buf), Qnil);
6550 }
6551
6552 {
6553 Lisp_Object rest;
6554 /* Look through w32-charset-info-alist for the character set.
6555 Only return charsets for codepages which are installed.
6556
6557 Format of each entry in Vw32_charset_info_alist is
6558 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6559 */
6560 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6561 {
6562 Lisp_Object x_charset;
6563 Lisp_Object w32_charset;
6564 Lisp_Object codepage;
6565
6566 Lisp_Object this_entry = XCAR (rest);
6567
6568 /* Skip invalid entries in alist. */
6569 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6570 || !CONSP (XCDR (this_entry))
6571 || !SYMBOLP (XCAR (XCDR (this_entry))))
6572 continue;
6573
6574 x_charset = XCAR (this_entry);
6575 w32_charset = XCAR (XCDR (this_entry));
6576 codepage = XCDR (XCDR (this_entry));
6577
6578 /* Look for Same charset and a valid codepage (or non-int
6579 which means ignore). */
6580 if (w32_charset == charset_type
6581 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6582 || IsValidCodePage (XINT (codepage))))
6583 {
6584 retval = Fcons (x_charset, retval);
6585 }
6586 }
6587
6588 /* If no match, encode the numeric value. */
6589 if (NILP (retval))
6590 {
6591 sprintf (buf, "*-#%u", fncharset);
6592 return Fcons (build_string (buf), Qnil);
6593 }
6594
6595 return retval;
6596 }
6597 }
6598
6599 /* Get the Windows codepage corresponding to the specified font. The
6600 charset info in the font name is used to look up
6601 w32-charset-to-codepage-alist. */
6602 int
6603 w32_codepage_for_font (char *fontname)
6604 {
6605 Lisp_Object codepage, entry;
6606 char *charset_str, *charset, *end;
6607
6608 if (NILP (Vw32_charset_info_alist))
6609 return CP_DEFAULT;
6610
6611 /* Extract charset part of font string. */
6612 charset = xlfd_charset_of_font (fontname);
6613
6614 if (!charset)
6615 return CP_UNKNOWN;
6616
6617 charset_str = (char *) alloca (strlen (charset) + 1);
6618 strcpy (charset_str, charset);
6619
6620 #if 0
6621 /* Remove leading "*-". */
6622 if (strncmp ("*-", charset_str, 2) == 0)
6623 charset = charset_str + 2;
6624 else
6625 #endif
6626 charset = charset_str;
6627
6628 /* Stop match at wildcard (including preceding '-'). */
6629 if (end = strchr (charset, '*'))
6630 {
6631 if (end > charset && *(end-1) == '-')
6632 end--;
6633 *end = '\0';
6634 }
6635
6636 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6637 if (NILP (entry))
6638 return CP_UNKNOWN;
6639
6640 codepage = Fcdr (Fcdr (entry));
6641
6642 if (NILP (codepage))
6643 return CP_8BIT;
6644 else if (XFASTINT (codepage) == XFASTINT (Qt))
6645 return CP_UNICODE;
6646 else if (INTEGERP (codepage))
6647 return XINT (codepage);
6648 else
6649 return CP_UNKNOWN;
6650 }
6651
6652
6653 static BOOL
6654 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6655 LOGFONT * lplogfont;
6656 char * lpxstr;
6657 int len;
6658 char * specific_charset;
6659 {
6660 char* fonttype;
6661 char *fontname;
6662 char height_pixels[8];
6663 char height_dpi[8];
6664 char width_pixels[8];
6665 char *fontname_dash;
6666 int display_resy = (int) one_w32_display_info.resy;
6667 int display_resx = (int) one_w32_display_info.resx;
6668 int bufsz;
6669 struct coding_system coding;
6670
6671 if (!lpxstr) abort ();
6672
6673 if (!lplogfont)
6674 return FALSE;
6675
6676 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6677 fonttype = "raster";
6678 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6679 fonttype = "outline";
6680 else
6681 fonttype = "unknown";
6682
6683 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
6684 &coding);
6685 coding.src_multibyte = 0;
6686 coding.dst_multibyte = 1;
6687 coding.mode |= CODING_MODE_LAST_BLOCK;
6688 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6689
6690 fontname = alloca(sizeof(*fontname) * bufsz);
6691 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6692 strlen(lplogfont->lfFaceName), bufsz - 1);
6693 *(fontname + coding.produced) = '\0';
6694
6695 /* Replace dashes with underscores so the dashes are not
6696 misinterpreted. */
6697 fontname_dash = fontname;
6698 while (fontname_dash = strchr (fontname_dash, '-'))
6699 *fontname_dash = '_';
6700
6701 if (lplogfont->lfHeight)
6702 {
6703 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6704 sprintf (height_dpi, "%u",
6705 abs (lplogfont->lfHeight) * 720 / display_resy);
6706 }
6707 else
6708 {
6709 strcpy (height_pixels, "*");
6710 strcpy (height_dpi, "*");
6711 }
6712 if (lplogfont->lfWidth)
6713 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6714 else
6715 strcpy (width_pixels, "*");
6716
6717 _snprintf (lpxstr, len - 1,
6718 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6719 fonttype, /* foundry */
6720 fontname, /* family */
6721 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6722 lplogfont->lfItalic?'i':'r', /* slant */
6723 /* setwidth name */
6724 /* add style name */
6725 height_pixels, /* pixel size */
6726 height_dpi, /* point size */
6727 display_resx, /* resx */
6728 display_resy, /* resy */
6729 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6730 ? 'p' : 'c', /* spacing */
6731 width_pixels, /* avg width */
6732 specific_charset ? specific_charset
6733 : w32_to_x_charset (lplogfont->lfCharSet)
6734 /* charset registry and encoding */
6735 );
6736
6737 lpxstr[len - 1] = 0; /* just to be sure */
6738 return (TRUE);
6739 }
6740
6741 static BOOL
6742 x_to_w32_font (lpxstr, lplogfont)
6743 char * lpxstr;
6744 LOGFONT * lplogfont;
6745 {
6746 struct coding_system coding;
6747
6748 if (!lplogfont) return (FALSE);
6749
6750 memset (lplogfont, 0, sizeof (*lplogfont));
6751
6752 /* Set default value for each field. */
6753 #if 1
6754 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6755 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6756 lplogfont->lfQuality = DEFAULT_QUALITY;
6757 #else
6758 /* go for maximum quality */
6759 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6760 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6761 lplogfont->lfQuality = PROOF_QUALITY;
6762 #endif
6763
6764 lplogfont->lfCharSet = DEFAULT_CHARSET;
6765 lplogfont->lfWeight = FW_DONTCARE;
6766 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6767
6768 if (!lpxstr)
6769 return FALSE;
6770
6771 /* Provide a simple escape mechanism for specifying Windows font names
6772 * directly -- if font spec does not beginning with '-', assume this
6773 * format:
6774 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6775 */
6776
6777 if (*lpxstr == '-')
6778 {
6779 int fields, tem;
6780 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6781 width[10], resy[10], remainder[50];
6782 char * encoding;
6783 int dpi = (int) one_w32_display_info.resy;
6784
6785 fields = sscanf (lpxstr,
6786 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6787 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6788 if (fields == EOF)
6789 return (FALSE);
6790
6791 /* In the general case when wildcards cover more than one field,
6792 we don't know which field is which, so don't fill any in.
6793 However, we need to cope with this particular form, which is
6794 generated by font_list_1 (invoked by try_font_list):
6795 "-raster-6x10-*-gb2312*-*"
6796 and make sure to correctly parse the charset field. */
6797 if (fields == 3)
6798 {
6799 fields = sscanf (lpxstr,
6800 "-%*[^-]-%49[^-]-*-%49s",
6801 name, remainder);
6802 }
6803 else if (fields < 9)
6804 {
6805 fields = 0;
6806 remainder[0] = 0;
6807 }
6808
6809 if (fields > 0 && name[0] != '*')
6810 {
6811 int bufsize;
6812 unsigned char *buf;
6813
6814 setup_coding_system
6815 (Fcheck_coding_system (Vlocale_coding_system), &coding);
6816 coding.src_multibyte = 1;
6817 coding.dst_multibyte = 1;
6818 bufsize = encoding_buffer_size (&coding, strlen (name));
6819 buf = (unsigned char *) alloca (bufsize);
6820 coding.mode |= CODING_MODE_LAST_BLOCK;
6821 encode_coding (&coding, name, buf, strlen (name), bufsize);
6822 if (coding.produced >= LF_FACESIZE)
6823 coding.produced = LF_FACESIZE - 1;
6824 buf[coding.produced] = 0;
6825 strcpy (lplogfont->lfFaceName, buf);
6826 }
6827 else
6828 {
6829 lplogfont->lfFaceName[0] = '\0';
6830 }
6831
6832 fields--;
6833
6834 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6835
6836 fields--;
6837
6838 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6839
6840 fields--;
6841
6842 if (fields > 0 && pixels[0] != '*')
6843 lplogfont->lfHeight = atoi (pixels);
6844
6845 fields--;
6846 fields--;
6847 if (fields > 0 && resy[0] != '*')
6848 {
6849 tem = atoi (resy);
6850 if (tem > 0) dpi = tem;
6851 }
6852
6853 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6854 lplogfont->lfHeight = atoi (height) * dpi / 720;
6855
6856 if (fields > 0)
6857 lplogfont->lfPitchAndFamily =
6858 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6859
6860 fields--;
6861
6862 if (fields > 0 && width[0] != '*')
6863 lplogfont->lfWidth = atoi (width) / 10;
6864
6865 fields--;
6866
6867 /* Strip the trailing '-' if present. (it shouldn't be, as it
6868 fails the test against xlfd-tight-regexp in fontset.el). */
6869 {
6870 int len = strlen (remainder);
6871 if (len > 0 && remainder[len-1] == '-')
6872 remainder[len-1] = 0;
6873 }
6874 encoding = remainder;
6875 #if 0
6876 if (strncmp (encoding, "*-", 2) == 0)
6877 encoding += 2;
6878 #endif
6879 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6880 }
6881 else
6882 {
6883 int fields;
6884 char name[100], height[10], width[10], weight[20];
6885
6886 fields = sscanf (lpxstr,
6887 "%99[^:]:%9[^:]:%9[^:]:%19s",
6888 name, height, width, weight);
6889
6890 if (fields == EOF) return (FALSE);
6891
6892 if (fields > 0)
6893 {
6894 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6895 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6896 }
6897 else
6898 {
6899 lplogfont->lfFaceName[0] = 0;
6900 }
6901
6902 fields--;
6903
6904 if (fields > 0)
6905 lplogfont->lfHeight = atoi (height);
6906
6907 fields--;
6908
6909 if (fields > 0)
6910 lplogfont->lfWidth = atoi (width);
6911
6912 fields--;
6913
6914 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6915 }
6916
6917 /* This makes TrueType fonts work better. */
6918 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6919
6920 return (TRUE);
6921 }
6922
6923 /* Strip the pixel height and point height from the given xlfd, and
6924 return the pixel height. If no pixel height is specified, calculate
6925 one from the point height, or if that isn't defined either, return
6926 0 (which usually signifies a scalable font).
6927 */
6928 static int
6929 xlfd_strip_height (char *fontname)
6930 {
6931 int pixel_height, field_number;
6932 char *read_from, *write_to;
6933
6934 xassert (fontname);
6935
6936 pixel_height = field_number = 0;
6937 write_to = NULL;
6938
6939 /* Look for height fields. */
6940 for (read_from = fontname; *read_from; read_from++)
6941 {
6942 if (*read_from == '-')
6943 {
6944 field_number++;
6945 if (field_number == 7) /* Pixel height. */
6946 {
6947 read_from++;
6948 write_to = read_from;
6949
6950 /* Find end of field. */
6951 for (;*read_from && *read_from != '-'; read_from++)
6952 ;
6953
6954 /* Split the fontname at end of field. */
6955 if (*read_from)
6956 {
6957 *read_from = '\0';
6958 read_from++;
6959 }
6960 pixel_height = atoi (write_to);
6961 /* Blank out field. */
6962 if (read_from > write_to)
6963 {
6964 *write_to = '-';
6965 write_to++;
6966 }
6967 /* If the pixel height field is at the end (partial xlfd),
6968 return now. */
6969 else
6970 return pixel_height;
6971
6972 /* If we got a pixel height, the point height can be
6973 ignored. Just blank it out and break now. */
6974 if (pixel_height)
6975 {
6976 /* Find end of point size field. */
6977 for (; *read_from && *read_from != '-'; read_from++)
6978 ;
6979
6980 if (*read_from)
6981 read_from++;
6982
6983 /* Blank out the point size field. */
6984 if (read_from > write_to)
6985 {
6986 *write_to = '-';
6987 write_to++;
6988 }
6989 else
6990 return pixel_height;
6991
6992 break;
6993 }
6994 /* If the point height is already blank, break now. */
6995 if (*read_from == '-')
6996 {
6997 read_from++;
6998 break;
6999 }
7000 }
7001 else if (field_number == 8)
7002 {
7003 /* If we didn't get a pixel height, try to get the point
7004 height and convert that. */
7005 int point_size;
7006 char *point_size_start = read_from++;
7007
7008 /* Find end of field. */
7009 for (; *read_from && *read_from != '-'; read_from++)
7010 ;
7011
7012 if (*read_from)
7013 {
7014 *read_from = '\0';
7015 read_from++;
7016 }
7017
7018 point_size = atoi (point_size_start);
7019
7020 /* Convert to pixel height. */
7021 pixel_height = point_size
7022 * one_w32_display_info.height_in / 720;
7023
7024 /* Blank out this field and break. */
7025 *write_to = '-';
7026 write_to++;
7027 break;
7028 }
7029 }
7030 }
7031
7032 /* Shift the rest of the font spec into place. */
7033 if (write_to && read_from > write_to)
7034 {
7035 for (; *read_from; read_from++, write_to++)
7036 *write_to = *read_from;
7037 *write_to = '\0';
7038 }
7039
7040 return pixel_height;
7041 }
7042
7043 /* Assume parameter 1 is fully qualified, no wildcards. */
7044 static BOOL
7045 w32_font_match (fontname, pattern)
7046 char * fontname;
7047 char * pattern;
7048 {
7049 char *regex = alloca (strlen (pattern) * 2 + 3);
7050 char *font_name_copy = alloca (strlen (fontname) + 1);
7051 char *ptr;
7052
7053 /* Copy fontname so we can modify it during comparison. */
7054 strcpy (font_name_copy, fontname);
7055
7056 ptr = regex;
7057 *ptr++ = '^';
7058
7059 /* Turn pattern into a regexp and do a regexp match. */
7060 for (; *pattern; pattern++)
7061 {
7062 if (*pattern == '?')
7063 *ptr++ = '.';
7064 else if (*pattern == '*')
7065 {
7066 *ptr++ = '.';
7067 *ptr++ = '*';
7068 }
7069 else
7070 *ptr++ = *pattern;
7071 }
7072 *ptr = '$';
7073 *(ptr + 1) = '\0';
7074
7075 /* Strip out font heights and compare them seperately, since
7076 rounding error can cause mismatches. This also allows a
7077 comparison between a font that declares only a pixel height and a
7078 pattern that declares the point height.
7079 */
7080 {
7081 int font_height, pattern_height;
7082
7083 font_height = xlfd_strip_height (font_name_copy);
7084 pattern_height = xlfd_strip_height (regex);
7085
7086 /* Compare now, and don't bother doing expensive regexp matching
7087 if the heights differ. */
7088 if (font_height && pattern_height && (font_height != pattern_height))
7089 return FALSE;
7090 }
7091
7092 return (fast_c_string_match_ignore_case (build_string (regex),
7093 font_name_copy) >= 0);
7094 }
7095
7096 /* Callback functions, and a structure holding info they need, for
7097 listing system fonts on W32. We need one set of functions to do the
7098 job properly, but these don't work on NT 3.51 and earlier, so we
7099 have a second set which don't handle character sets properly to
7100 fall back on.
7101
7102 In both cases, there are two passes made. The first pass gets one
7103 font from each family, the second pass lists all the fonts from
7104 each family. */
7105
7106 typedef struct enumfont_t
7107 {
7108 HDC hdc;
7109 int numFonts;
7110 LOGFONT logfont;
7111 XFontStruct *size_ref;
7112 Lisp_Object pattern;
7113 Lisp_Object list;
7114 } enumfont_t;
7115
7116
7117 static void
7118 enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7119
7120
7121 static int CALLBACK
7122 enum_font_cb2 (lplf, lptm, FontType, lpef)
7123 ENUMLOGFONT * lplf;
7124 NEWTEXTMETRIC * lptm;
7125 int FontType;
7126 enumfont_t * lpef;
7127 {
7128 /* Ignore struck out and underlined versions of fonts. */
7129 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7130 return 1;
7131
7132 /* Only return fonts with names starting with @ if they were
7133 explicitly specified, since Microsoft uses an initial @ to
7134 denote fonts for vertical writing, without providing a more
7135 convenient way of identifying them. */
7136 if (lplf->elfLogFont.lfFaceName[0] == '@'
7137 && lpef->logfont.lfFaceName[0] != '@')
7138 return 1;
7139
7140 /* Check that the character set matches if it was specified */
7141 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7142 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
7143 return 1;
7144
7145 if (FontType == RASTER_FONTTYPE)
7146 {
7147 /* DBCS raster fonts have problems displaying, so skip them. */
7148 int charset = lplf->elfLogFont.lfCharSet;
7149 if (charset == SHIFTJIS_CHARSET
7150 || charset == HANGEUL_CHARSET
7151 || charset == CHINESEBIG5_CHARSET
7152 || charset == GB2312_CHARSET
7153 #ifdef JOHAB_CHARSET
7154 || charset == JOHAB_CHARSET
7155 #endif
7156 )
7157 return 1;
7158 }
7159
7160 {
7161 char buf[100];
7162 Lisp_Object width = Qnil;
7163 Lisp_Object charset_list = Qnil;
7164 char *charset = NULL;
7165
7166 /* Truetype fonts do not report their true metrics until loaded */
7167 if (FontType != RASTER_FONTTYPE)
7168 {
7169 if (!NILP (lpef->pattern))
7170 {
7171 /* Scalable fonts are as big as you want them to be. */
7172 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7173 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7174 width = make_number (lpef->logfont.lfWidth);
7175 }
7176 else
7177 {
7178 lplf->elfLogFont.lfHeight = 0;
7179 lplf->elfLogFont.lfWidth = 0;
7180 }
7181 }
7182
7183 /* Make sure the height used here is the same as everywhere
7184 else (ie character height, not cell height). */
7185 if (lplf->elfLogFont.lfHeight > 0)
7186 {
7187 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7188 if (FontType == RASTER_FONTTYPE)
7189 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7190 else
7191 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7192 }
7193
7194 if (!NILP (lpef->pattern))
7195 {
7196 charset = xlfd_charset_of_font (XSTRING(lpef->pattern)->data);
7197
7198 /* We already checked charsets above, but DEFAULT_CHARSET
7199 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7200 if (charset
7201 && strncmp (charset, "*-*", 3) != 0
7202 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7203 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7204 return 1;
7205 }
7206
7207 if (charset)
7208 charset_list = Fcons (build_string (charset), Qnil);
7209 else
7210 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
7211
7212 /* Loop through the charsets. */
7213 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
7214 {
7215 Lisp_Object this_charset = Fcar (charset_list);
7216 charset = XSTRING (this_charset)->data;
7217
7218 /* List bold and italic variations if w32-enable-synthesized-fonts
7219 is non-nil and this is a plain font. */
7220 if (w32_enable_synthesized_fonts
7221 && lplf->elfLogFont.lfWeight == FW_NORMAL
7222 && lplf->elfLogFont.lfItalic == FALSE)
7223 {
7224 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7225 charset, width);
7226 /* bold. */
7227 lplf->elfLogFont.lfWeight = FW_BOLD;
7228 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7229 charset, width);
7230 /* bold italic. */
7231 lplf->elfLogFont.lfItalic = TRUE;
7232 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7233 charset, width);
7234 /* italic. */
7235 lplf->elfLogFont.lfWeight = FW_NORMAL;
7236 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7237 charset, width);
7238 }
7239 else
7240 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7241 charset, width);
7242 }
7243 }
7244
7245 return 1;
7246 }
7247
7248 static void
7249 enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7250 enumfont_t * lpef;
7251 LOGFONT * logfont;
7252 char * match_charset;
7253 Lisp_Object width;
7254 {
7255 char buf[100];
7256
7257 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7258 return;
7259
7260 if (NILP (lpef->pattern)
7261 || w32_font_match (buf, XSTRING (lpef->pattern)->data))
7262 {
7263 /* Check if we already listed this font. This may happen if
7264 w32_enable_synthesized_fonts is non-nil, and there are real
7265 bold and italic versions of the font. */
7266 Lisp_Object font_name = build_string (buf);
7267 if (NILP (Fmember (font_name, lpef->list)))
7268 {
7269 Lisp_Object entry = Fcons (font_name, width);
7270 lpef->list = Fcons (entry, lpef->list);
7271 lpef->numFonts++;
7272 }
7273 }
7274 }
7275
7276
7277 static int CALLBACK
7278 enum_font_cb1 (lplf, lptm, FontType, lpef)
7279 ENUMLOGFONT * lplf;
7280 NEWTEXTMETRIC * lptm;
7281 int FontType;
7282 enumfont_t * lpef;
7283 {
7284 return EnumFontFamilies (lpef->hdc,
7285 lplf->elfLogFont.lfFaceName,
7286 (FONTENUMPROC) enum_font_cb2,
7287 (LPARAM) lpef);
7288 }
7289
7290
7291 static int CALLBACK
7292 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7293 ENUMLOGFONTEX * lplf;
7294 NEWTEXTMETRICEX * lptm;
7295 int font_type;
7296 enumfont_t * lpef;
7297 {
7298 /* We are not interested in the extra info we get back from the 'Ex
7299 version - only the fact that we get character set variations
7300 enumerated seperately. */
7301 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7302 font_type, lpef);
7303 }
7304
7305 static int CALLBACK
7306 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7307 ENUMLOGFONTEX * lplf;
7308 NEWTEXTMETRICEX * lptm;
7309 int font_type;
7310 enumfont_t * lpef;
7311 {
7312 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7313 FARPROC enum_font_families_ex
7314 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7315 /* We don't really expect EnumFontFamiliesEx to disappear once we
7316 get here, so don't bother handling it gracefully. */
7317 if (enum_font_families_ex == NULL)
7318 error ("gdi32.dll has disappeared!");
7319 return enum_font_families_ex (lpef->hdc,
7320 &lplf->elfLogFont,
7321 (FONTENUMPROC) enum_fontex_cb2,
7322 (LPARAM) lpef, 0);
7323 }
7324
7325 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
7326 and xterm.c in Emacs 20.3) */
7327
7328 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
7329 {
7330 char *fontname, *ptnstr;
7331 Lisp_Object list, tem, newlist = Qnil;
7332 int n_fonts = 0;
7333
7334 list = Vw32_bdf_filename_alist;
7335 ptnstr = XSTRING (pattern)->data;
7336
7337 for ( ; CONSP (list); list = XCDR (list))
7338 {
7339 tem = XCAR (list);
7340 if (CONSP (tem))
7341 fontname = XSTRING (XCAR (tem))->data;
7342 else if (STRINGP (tem))
7343 fontname = XSTRING (tem)->data;
7344 else
7345 continue;
7346
7347 if (w32_font_match (fontname, ptnstr))
7348 {
7349 newlist = Fcons (XCAR (tem), newlist);
7350 n_fonts++;
7351 if (n_fonts >= max_names)
7352 break;
7353 }
7354 }
7355
7356 return newlist;
7357 }
7358
7359
7360 /* Return a list of names of available fonts matching PATTERN on frame
7361 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7362 to be listed. Frame F NULL means we have not yet created any
7363 frame, which means we can't get proper size info, as we don't have
7364 a device context to use for GetTextMetrics.
7365 MAXNAMES sets a limit on how many fonts to match. */
7366
7367 Lisp_Object
7368 w32_list_fonts (f, pattern, size, maxnames)
7369 struct frame *f;
7370 Lisp_Object pattern;
7371 int size;
7372 int maxnames;
7373 {
7374 Lisp_Object patterns, key = Qnil, tem, tpat;
7375 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
7376 struct w32_display_info *dpyinfo = &one_w32_display_info;
7377 int n_fonts = 0;
7378
7379 patterns = Fassoc (pattern, Valternate_fontname_alist);
7380 if (NILP (patterns))
7381 patterns = Fcons (pattern, Qnil);
7382
7383 for (; CONSP (patterns); patterns = XCDR (patterns))
7384 {
7385 enumfont_t ef;
7386 int codepage;
7387
7388 tpat = XCAR (patterns);
7389
7390 if (!STRINGP (tpat))
7391 continue;
7392
7393 /* Avoid expensive EnumFontFamilies functions if we are not
7394 going to be able to output one of these anyway. */
7395 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7396 if (codepage != CP_8BIT && codepage != CP_UNICODE
7397 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7398 && !IsValidCodePage(codepage))
7399 continue;
7400
7401 /* See if we cached the result for this particular query.
7402 The cache is an alist of the form:
7403 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7404 */
7405 if (tem = XCDR (dpyinfo->name_list_element),
7406 !NILP (list = Fassoc (tpat, tem)))
7407 {
7408 list = Fcdr_safe (list);
7409 /* We have a cached list. Don't have to get the list again. */
7410 goto label_cached;
7411 }
7412
7413 BLOCK_INPUT;
7414 /* At first, put PATTERN in the cache. */
7415 ef.pattern = tpat;
7416 ef.list = Qnil;
7417 ef.numFonts = 0;
7418
7419 /* Use EnumFontFamiliesEx where it is available, as it knows
7420 about character sets. Fall back to EnumFontFamilies for
7421 older versions of NT that don't support the 'Ex function. */
7422 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
7423 {
7424 LOGFONT font_match_pattern;
7425 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7426 FARPROC enum_font_families_ex
7427 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7428
7429 /* We do our own pattern matching so we can handle wildcards. */
7430 font_match_pattern.lfFaceName[0] = 0;
7431 font_match_pattern.lfPitchAndFamily = 0;
7432 /* We can use the charset, because if it is a wildcard it will
7433 be DEFAULT_CHARSET anyway. */
7434 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7435
7436 ef.hdc = GetDC (dpyinfo->root_window);
7437
7438 if (enum_font_families_ex)
7439 enum_font_families_ex (ef.hdc,
7440 &font_match_pattern,
7441 (FONTENUMPROC) enum_fontex_cb1,
7442 (LPARAM) &ef, 0);
7443 else
7444 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7445 (LPARAM)&ef);
7446
7447 ReleaseDC (dpyinfo->root_window, ef.hdc);
7448 }
7449
7450 UNBLOCK_INPUT;
7451 list = ef.list;
7452
7453 /* Make a list of the fonts we got back.
7454 Store that in the font cache for the display. */
7455 XSETCDR (dpyinfo->name_list_element,
7456 Fcons (Fcons (tpat, list),
7457 XCDR (dpyinfo->name_list_element)));
7458
7459 label_cached:
7460 if (NILP (list)) continue; /* Try the remaining alternatives. */
7461
7462 newlist = second_best = Qnil;
7463
7464 /* Make a list of the fonts that have the right width. */
7465 for (; CONSP (list); list = XCDR (list))
7466 {
7467 int found_size;
7468 tem = XCAR (list);
7469
7470 if (!CONSP (tem))
7471 continue;
7472 if (NILP (XCAR (tem)))
7473 continue;
7474 if (!size)
7475 {
7476 newlist = Fcons (XCAR (tem), newlist);
7477 n_fonts++;
7478 if (n_fonts >= maxnames)
7479 break;
7480 else
7481 continue;
7482 }
7483 if (!INTEGERP (XCDR (tem)))
7484 {
7485 /* Since we don't yet know the size of the font, we must
7486 load it and try GetTextMetrics. */
7487 W32FontStruct thisinfo;
7488 LOGFONT lf;
7489 HDC hdc;
7490 HANDLE oldobj;
7491
7492 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
7493 continue;
7494
7495 BLOCK_INPUT;
7496 thisinfo.bdf = NULL;
7497 thisinfo.hfont = CreateFontIndirect (&lf);
7498 if (thisinfo.hfont == NULL)
7499 continue;
7500
7501 hdc = GetDC (dpyinfo->root_window);
7502 oldobj = SelectObject (hdc, thisinfo.hfont);
7503 if (GetTextMetrics (hdc, &thisinfo.tm))
7504 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
7505 else
7506 XSETCDR (tem, make_number (0));
7507 SelectObject (hdc, oldobj);
7508 ReleaseDC (dpyinfo->root_window, hdc);
7509 DeleteObject(thisinfo.hfont);
7510 UNBLOCK_INPUT;
7511 }
7512 found_size = XINT (XCDR (tem));
7513 if (found_size == size)
7514 {
7515 newlist = Fcons (XCAR (tem), newlist);
7516 n_fonts++;
7517 if (n_fonts >= maxnames)
7518 break;
7519 }
7520 /* keep track of the closest matching size in case
7521 no exact match is found. */
7522 else if (found_size > 0)
7523 {
7524 if (NILP (second_best))
7525 second_best = tem;
7526
7527 else if (found_size < size)
7528 {
7529 if (XINT (XCDR (second_best)) > size
7530 || XINT (XCDR (second_best)) < found_size)
7531 second_best = tem;
7532 }
7533 else
7534 {
7535 if (XINT (XCDR (second_best)) > size
7536 && XINT (XCDR (second_best)) >
7537 found_size)
7538 second_best = tem;
7539 }
7540 }
7541 }
7542
7543 if (!NILP (newlist))
7544 break;
7545 else if (!NILP (second_best))
7546 {
7547 newlist = Fcons (XCAR (second_best), Qnil);
7548 break;
7549 }
7550 }
7551
7552 /* Include any bdf fonts. */
7553 if (n_fonts < maxnames)
7554 {
7555 Lisp_Object combined[2];
7556 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7557 combined[1] = newlist;
7558 newlist = Fnconc(2, combined);
7559 }
7560
7561 return newlist;
7562 }
7563
7564
7565 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7566 struct font_info *
7567 w32_get_font_info (f, font_idx)
7568 FRAME_PTR f;
7569 int font_idx;
7570 {
7571 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7572 }
7573
7574
7575 struct font_info*
7576 w32_query_font (struct frame *f, char *fontname)
7577 {
7578 int i;
7579 struct font_info *pfi;
7580
7581 pfi = FRAME_W32_FONT_TABLE (f);
7582
7583 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7584 {
7585 if (strcmp(pfi->name, fontname) == 0) return pfi;
7586 }
7587
7588 return NULL;
7589 }
7590
7591 /* Find a CCL program for a font specified by FONTP, and set the member
7592 `encoder' of the structure. */
7593
7594 void
7595 w32_find_ccl_program (fontp)
7596 struct font_info *fontp;
7597 {
7598 Lisp_Object list, elt;
7599
7600 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7601 {
7602 elt = XCAR (list);
7603 if (CONSP (elt)
7604 && STRINGP (XCAR (elt))
7605 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7606 >= 0))
7607 break;
7608 }
7609 if (! NILP (list))
7610 {
7611 struct ccl_program *ccl
7612 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7613
7614 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7615 xfree (ccl);
7616 else
7617 fontp->font_encoder = ccl;
7618 }
7619 }
7620
7621 \f
7622 /* Find BDF files in a specified directory. (use GCPRO when calling,
7623 as this calls lisp to get a directory listing). */
7624 static Lisp_Object
7625 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7626 {
7627 Lisp_Object filelist, list = Qnil;
7628 char fontname[100];
7629
7630 if (!STRINGP(directory))
7631 return Qnil;
7632
7633 filelist = Fdirectory_files (directory, Qt,
7634 build_string (".*\\.[bB][dD][fF]"), Qt);
7635
7636 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7637 {
7638 Lisp_Object filename = XCAR (filelist);
7639 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7640 store_in_alist (&list, build_string (fontname), filename);
7641 }
7642 return list;
7643 }
7644
7645 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7646 1, 1, 0,
7647 doc: /* Return a list of BDF fonts in DIR.
7648 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7649 which do not contain an xlfd description will not be included in the
7650 list. DIR may be a list of directories. */)
7651 (directory)
7652 Lisp_Object directory;
7653 {
7654 Lisp_Object list = Qnil;
7655 struct gcpro gcpro1, gcpro2;
7656
7657 if (!CONSP (directory))
7658 return w32_find_bdf_fonts_in_dir (directory);
7659
7660 for ( ; CONSP (directory); directory = XCDR (directory))
7661 {
7662 Lisp_Object pair[2];
7663 pair[0] = list;
7664 pair[1] = Qnil;
7665 GCPRO2 (directory, list);
7666 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7667 list = Fnconc( 2, pair );
7668 UNGCPRO;
7669 }
7670 return list;
7671 }
7672
7673 \f
7674 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7675 doc: /* Internal function called by `color-defined-p', which see. */)
7676 (color, frame)
7677 Lisp_Object color, frame;
7678 {
7679 XColor foo;
7680 FRAME_PTR f = check_x_frame (frame);
7681
7682 CHECK_STRING (color);
7683
7684 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7685 return Qt;
7686 else
7687 return Qnil;
7688 }
7689
7690 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7691 doc: /* Internal function called by `color-values', which see. */)
7692 (color, frame)
7693 Lisp_Object color, frame;
7694 {
7695 XColor foo;
7696 FRAME_PTR f = check_x_frame (frame);
7697
7698 CHECK_STRING (color);
7699
7700 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7701 {
7702 Lisp_Object rgb[3];
7703
7704 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7705 | GetRValue (foo.pixel));
7706 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7707 | GetGValue (foo.pixel));
7708 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7709 | GetBValue (foo.pixel));
7710 return Flist (3, rgb);
7711 }
7712 else
7713 return Qnil;
7714 }
7715
7716 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7717 doc: /* Internal function called by `display-color-p', which see. */)
7718 (display)
7719 Lisp_Object display;
7720 {
7721 struct w32_display_info *dpyinfo = check_x_display_info (display);
7722
7723 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7724 return Qnil;
7725
7726 return Qt;
7727 }
7728
7729 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7730 Sx_display_grayscale_p, 0, 1, 0,
7731 doc: /* Return t if the X display supports shades of gray.
7732 Note that color displays do support shades of gray.
7733 The optional argument DISPLAY specifies which display to ask about.
7734 DISPLAY should be either a frame or a display name (a string).
7735 If omitted or nil, that stands for the selected frame's display. */)
7736 (display)
7737 Lisp_Object display;
7738 {
7739 struct w32_display_info *dpyinfo = check_x_display_info (display);
7740
7741 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7742 return Qnil;
7743
7744 return Qt;
7745 }
7746
7747 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7748 Sx_display_pixel_width, 0, 1, 0,
7749 doc: /* Returns the width in pixels of DISPLAY.
7750 The optional argument DISPLAY specifies which display to ask about.
7751 DISPLAY should be either a frame or a display name (a string).
7752 If omitted or nil, that stands for the selected frame's display. */)
7753 (display)
7754 Lisp_Object display;
7755 {
7756 struct w32_display_info *dpyinfo = check_x_display_info (display);
7757
7758 return make_number (dpyinfo->width);
7759 }
7760
7761 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7762 Sx_display_pixel_height, 0, 1, 0,
7763 doc: /* Returns the height in pixels of DISPLAY.
7764 The optional argument DISPLAY specifies which display to ask about.
7765 DISPLAY should be either a frame or a display name (a string).
7766 If omitted or nil, that stands for the selected frame's display. */)
7767 (display)
7768 Lisp_Object display;
7769 {
7770 struct w32_display_info *dpyinfo = check_x_display_info (display);
7771
7772 return make_number (dpyinfo->height);
7773 }
7774
7775 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7776 0, 1, 0,
7777 doc: /* Returns the number of bitplanes of DISPLAY.
7778 The optional argument DISPLAY specifies which display to ask about.
7779 DISPLAY should be either a frame or a display name (a string).
7780 If omitted or nil, that stands for the selected frame's display. */)
7781 (display)
7782 Lisp_Object display;
7783 {
7784 struct w32_display_info *dpyinfo = check_x_display_info (display);
7785
7786 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7787 }
7788
7789 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7790 0, 1, 0,
7791 doc: /* Returns the number of color cells of DISPLAY.
7792 The optional argument DISPLAY specifies which display to ask about.
7793 DISPLAY should be either a frame or a display name (a string).
7794 If omitted or nil, that stands for the selected frame's display. */)
7795 (display)
7796 Lisp_Object display;
7797 {
7798 struct w32_display_info *dpyinfo = check_x_display_info (display);
7799 HDC hdc;
7800 int cap;
7801
7802 hdc = GetDC (dpyinfo->root_window);
7803 if (dpyinfo->has_palette)
7804 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7805 else
7806 cap = GetDeviceCaps (hdc,NUMCOLORS);
7807
7808 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7809 and because probably is more meaningful on Windows anyway */
7810 if (cap < 0)
7811 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7812
7813 ReleaseDC (dpyinfo->root_window, hdc);
7814
7815 return make_number (cap);
7816 }
7817
7818 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7819 Sx_server_max_request_size,
7820 0, 1, 0,
7821 doc: /* Returns the maximum request size of the server of DISPLAY.
7822 The optional argument DISPLAY specifies which display to ask about.
7823 DISPLAY should be either a frame or a display name (a string).
7824 If omitted or nil, that stands for the selected frame's display. */)
7825 (display)
7826 Lisp_Object display;
7827 {
7828 struct w32_display_info *dpyinfo = check_x_display_info (display);
7829
7830 return make_number (1);
7831 }
7832
7833 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7834 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7835 The optional argument DISPLAY specifies which display to ask about.
7836 DISPLAY should be either a frame or a display name (a string).
7837 If omitted or nil, that stands for the selected frame's display. */)
7838 (display)
7839 Lisp_Object display;
7840 {
7841 return build_string ("Microsoft Corp.");
7842 }
7843
7844 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7845 doc: /* Returns the version numbers of the server of DISPLAY.
7846 The value is a list of three integers: the major and minor
7847 version numbers, and the vendor-specific release
7848 number. See also the function `x-server-vendor'.
7849
7850 The optional argument DISPLAY specifies which display to ask about.
7851 DISPLAY should be either a frame or a display name (a string).
7852 If omitted or nil, that stands for the selected frame's display. */)
7853 (display)
7854 Lisp_Object display;
7855 {
7856 return Fcons (make_number (w32_major_version),
7857 Fcons (make_number (w32_minor_version),
7858 Fcons (make_number (w32_build_number), Qnil)));
7859 }
7860
7861 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7862 doc: /* Returns the number of screens on the server of DISPLAY.
7863 The optional argument DISPLAY specifies which display to ask about.
7864 DISPLAY should be either a frame or a display name (a string).
7865 If omitted or nil, that stands for the selected frame's display. */)
7866 (display)
7867 Lisp_Object display;
7868 {
7869 return make_number (1);
7870 }
7871
7872 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7873 Sx_display_mm_height, 0, 1, 0,
7874 doc: /* Returns the height in millimeters of DISPLAY.
7875 The optional argument DISPLAY specifies which display to ask about.
7876 DISPLAY should be either a frame or a display name (a string).
7877 If omitted or nil, that stands for the selected frame's display. */)
7878 (display)
7879 Lisp_Object display;
7880 {
7881 struct w32_display_info *dpyinfo = check_x_display_info (display);
7882 HDC hdc;
7883 int cap;
7884
7885 hdc = GetDC (dpyinfo->root_window);
7886
7887 cap = GetDeviceCaps (hdc, VERTSIZE);
7888
7889 ReleaseDC (dpyinfo->root_window, hdc);
7890
7891 return make_number (cap);
7892 }
7893
7894 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7895 doc: /* Returns the width in millimeters of DISPLAY.
7896 The optional argument DISPLAY specifies which display to ask about.
7897 DISPLAY should be either a frame or a display name (a string).
7898 If omitted or nil, that stands for the selected frame's display. */)
7899 (display)
7900 Lisp_Object display;
7901 {
7902 struct w32_display_info *dpyinfo = check_x_display_info (display);
7903
7904 HDC hdc;
7905 int cap;
7906
7907 hdc = GetDC (dpyinfo->root_window);
7908
7909 cap = GetDeviceCaps (hdc, HORZSIZE);
7910
7911 ReleaseDC (dpyinfo->root_window, hdc);
7912
7913 return make_number (cap);
7914 }
7915
7916 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7917 Sx_display_backing_store, 0, 1, 0,
7918 doc: /* Returns an indication of whether DISPLAY does backing store.
7919 The value may be `always', `when-mapped', or `not-useful'.
7920 The optional argument DISPLAY specifies which display to ask about.
7921 DISPLAY should be either a frame or a display name (a string).
7922 If omitted or nil, that stands for the selected frame's display. */)
7923 (display)
7924 Lisp_Object display;
7925 {
7926 return intern ("not-useful");
7927 }
7928
7929 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7930 Sx_display_visual_class, 0, 1, 0,
7931 doc: /* Returns the visual class of DISPLAY.
7932 The value is one of the symbols `static-gray', `gray-scale',
7933 `static-color', `pseudo-color', `true-color', or `direct-color'.
7934
7935 The optional argument DISPLAY specifies which display to ask about.
7936 DISPLAY should be either a frame or a display name (a string).
7937 If omitted or nil, that stands for the selected frame's display. */)
7938 (display)
7939 Lisp_Object display;
7940 {
7941 struct w32_display_info *dpyinfo = check_x_display_info (display);
7942 Lisp_Object result = Qnil;
7943
7944 if (dpyinfo->has_palette)
7945 result = intern ("pseudo-color");
7946 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7947 result = intern ("static-grey");
7948 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7949 result = intern ("static-color");
7950 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7951 result = intern ("true-color");
7952
7953 return result;
7954 }
7955
7956 DEFUN ("x-display-save-under", Fx_display_save_under,
7957 Sx_display_save_under, 0, 1, 0,
7958 doc: /* Returns t if DISPLAY supports the save-under feature.
7959 The optional argument DISPLAY specifies which display to ask about.
7960 DISPLAY should be either a frame or a display name (a string).
7961 If omitted or nil, that stands for the selected frame's display. */)
7962 (display)
7963 Lisp_Object display;
7964 {
7965 return Qnil;
7966 }
7967 \f
7968 int
7969 x_pixel_width (f)
7970 register struct frame *f;
7971 {
7972 return PIXEL_WIDTH (f);
7973 }
7974
7975 int
7976 x_pixel_height (f)
7977 register struct frame *f;
7978 {
7979 return PIXEL_HEIGHT (f);
7980 }
7981
7982 int
7983 x_char_width (f)
7984 register struct frame *f;
7985 {
7986 return FONT_WIDTH (f->output_data.w32->font);
7987 }
7988
7989 int
7990 x_char_height (f)
7991 register struct frame *f;
7992 {
7993 return f->output_data.w32->line_height;
7994 }
7995
7996 int
7997 x_screen_planes (f)
7998 register struct frame *f;
7999 {
8000 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
8001 }
8002 \f
8003 /* Return the display structure for the display named NAME.
8004 Open a new connection if necessary. */
8005
8006 struct w32_display_info *
8007 x_display_info_for_name (name)
8008 Lisp_Object name;
8009 {
8010 Lisp_Object names;
8011 struct w32_display_info *dpyinfo;
8012
8013 CHECK_STRING (name);
8014
8015 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
8016 dpyinfo;
8017 dpyinfo = dpyinfo->next, names = XCDR (names))
8018 {
8019 Lisp_Object tem;
8020 tem = Fstring_equal (XCAR (XCAR (names)), name);
8021 if (!NILP (tem))
8022 return dpyinfo;
8023 }
8024
8025 /* Use this general default value to start with. */
8026 Vx_resource_name = Vinvocation_name;
8027
8028 validate_x_resource_name ();
8029
8030 dpyinfo = w32_term_init (name, (unsigned char *)0,
8031 (char *) XSTRING (Vx_resource_name)->data);
8032
8033 if (dpyinfo == 0)
8034 error ("Cannot connect to server %s", XSTRING (name)->data);
8035
8036 w32_in_use = 1;
8037 XSETFASTINT (Vwindow_system_version, 3);
8038
8039 return dpyinfo;
8040 }
8041
8042 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
8043 1, 3, 0, doc: /* Open a connection to a server.
8044 DISPLAY is the name of the display to connect to.
8045 Optional second arg XRM-STRING is a string of resources in xrdb format.
8046 If the optional third arg MUST-SUCCEED is non-nil,
8047 terminate Emacs if we can't open the connection. */)
8048 (display, xrm_string, must_succeed)
8049 Lisp_Object display, xrm_string, must_succeed;
8050 {
8051 unsigned char *xrm_option;
8052 struct w32_display_info *dpyinfo;
8053
8054 /* If initialization has already been done, return now to avoid
8055 overwriting critical parts of one_w32_display_info. */
8056 if (w32_in_use)
8057 return Qnil;
8058
8059 CHECK_STRING (display);
8060 if (! NILP (xrm_string))
8061 CHECK_STRING (xrm_string);
8062
8063 if (! EQ (Vwindow_system, intern ("w32")))
8064 error ("Not using Microsoft Windows");
8065
8066 /* Allow color mapping to be defined externally; first look in user's
8067 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8068 {
8069 Lisp_Object color_file;
8070 struct gcpro gcpro1;
8071
8072 color_file = build_string("~/rgb.txt");
8073
8074 GCPRO1 (color_file);
8075
8076 if (NILP (Ffile_readable_p (color_file)))
8077 color_file =
8078 Fexpand_file_name (build_string ("rgb.txt"),
8079 Fsymbol_value (intern ("data-directory")));
8080
8081 Vw32_color_map = Fw32_load_color_file (color_file);
8082
8083 UNGCPRO;
8084 }
8085 if (NILP (Vw32_color_map))
8086 Vw32_color_map = Fw32_default_color_map ();
8087
8088 if (! NILP (xrm_string))
8089 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8090 else
8091 xrm_option = (unsigned char *) 0;
8092
8093 /* Use this general default value to start with. */
8094 /* First remove .exe suffix from invocation-name - it looks ugly. */
8095 {
8096 char basename[ MAX_PATH ], *str;
8097
8098 strcpy (basename, XSTRING (Vinvocation_name)->data);
8099 str = strrchr (basename, '.');
8100 if (str) *str = 0;
8101 Vinvocation_name = build_string (basename);
8102 }
8103 Vx_resource_name = Vinvocation_name;
8104
8105 validate_x_resource_name ();
8106
8107 /* This is what opens the connection and sets x_current_display.
8108 This also initializes many symbols, such as those used for input. */
8109 dpyinfo = w32_term_init (display, xrm_option,
8110 (char *) XSTRING (Vx_resource_name)->data);
8111
8112 if (dpyinfo == 0)
8113 {
8114 if (!NILP (must_succeed))
8115 fatal ("Cannot connect to server %s.\n",
8116 XSTRING (display)->data);
8117 else
8118 error ("Cannot connect to server %s", XSTRING (display)->data);
8119 }
8120
8121 w32_in_use = 1;
8122
8123 XSETFASTINT (Vwindow_system_version, 3);
8124 return Qnil;
8125 }
8126
8127 DEFUN ("x-close-connection", Fx_close_connection,
8128 Sx_close_connection, 1, 1, 0,
8129 doc: /* Close the connection to DISPLAY's server.
8130 For DISPLAY, specify either a frame or a display name (a string).
8131 If DISPLAY is nil, that stands for the selected frame's display. */)
8132 (display)
8133 Lisp_Object display;
8134 {
8135 struct w32_display_info *dpyinfo = check_x_display_info (display);
8136 int i;
8137
8138 if (dpyinfo->reference_count > 0)
8139 error ("Display still has frames on it");
8140
8141 BLOCK_INPUT;
8142 /* Free the fonts in the font table. */
8143 for (i = 0; i < dpyinfo->n_fonts; i++)
8144 if (dpyinfo->font_table[i].name)
8145 {
8146 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8147 xfree (dpyinfo->font_table[i].full_name);
8148 xfree (dpyinfo->font_table[i].name);
8149 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8150 }
8151 x_destroy_all_bitmaps (dpyinfo);
8152
8153 x_delete_display (dpyinfo);
8154 UNBLOCK_INPUT;
8155
8156 return Qnil;
8157 }
8158
8159 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
8160 doc: /* Return the list of display names that Emacs has connections to. */)
8161 ()
8162 {
8163 Lisp_Object tail, result;
8164
8165 result = Qnil;
8166 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8167 result = Fcons (XCAR (XCAR (tail)), result);
8168
8169 return result;
8170 }
8171
8172 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
8173 doc: /* This is a noop on W32 systems. */)
8174 (on, display)
8175 Lisp_Object display, on;
8176 {
8177 return Qnil;
8178 }
8179
8180 \f
8181 /***********************************************************************
8182 Image types
8183 ***********************************************************************/
8184
8185 /* Value is the number of elements of vector VECTOR. */
8186
8187 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8188
8189 /* List of supported image types. Use define_image_type to add new
8190 types. Use lookup_image_type to find a type for a given symbol. */
8191
8192 static struct image_type *image_types;
8193
8194 /* The symbol `image' which is the car of the lists used to represent
8195 images in Lisp. */
8196
8197 extern Lisp_Object Qimage;
8198
8199 /* The symbol `xbm' which is used as the type symbol for XBM images. */
8200
8201 Lisp_Object Qxbm;
8202
8203 /* Keywords. */
8204
8205 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
8206 extern Lisp_Object QCdata, QCtype;
8207 Lisp_Object QCascent, QCmargin, QCrelief;
8208 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
8209 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
8210
8211 /* Other symbols. */
8212
8213 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
8214
8215 /* Time in seconds after which images should be removed from the cache
8216 if not displayed. */
8217
8218 Lisp_Object Vimage_cache_eviction_delay;
8219
8220 /* Function prototypes. */
8221
8222 static void define_image_type P_ ((struct image_type *type));
8223 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8224 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8225 static void x_laplace P_ ((struct frame *, struct image *));
8226 static void x_emboss P_ ((struct frame *, struct image *));
8227 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8228 Lisp_Object));
8229
8230
8231 /* Define a new image type from TYPE. This adds a copy of TYPE to
8232 image_types and adds the symbol *TYPE->type to Vimage_types. */
8233
8234 static void
8235 define_image_type (type)
8236 struct image_type *type;
8237 {
8238 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8239 The initialized data segment is read-only. */
8240 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8241 bcopy (type, p, sizeof *p);
8242 p->next = image_types;
8243 image_types = p;
8244 Vimage_types = Fcons (*p->type, Vimage_types);
8245 }
8246
8247
8248 /* Look up image type SYMBOL, and return a pointer to its image_type
8249 structure. Value is null if SYMBOL is not a known image type. */
8250
8251 static INLINE struct image_type *
8252 lookup_image_type (symbol)
8253 Lisp_Object symbol;
8254 {
8255 struct image_type *type;
8256
8257 for (type = image_types; type; type = type->next)
8258 if (EQ (symbol, *type->type))
8259 break;
8260
8261 return type;
8262 }
8263
8264
8265 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
8266 valid image specification is a list whose car is the symbol
8267 `image', and whose rest is a property list. The property list must
8268 contain a value for key `:type'. That value must be the name of a
8269 supported image type. The rest of the property list depends on the
8270 image type. */
8271
8272 int
8273 valid_image_p (object)
8274 Lisp_Object object;
8275 {
8276 int valid_p = 0;
8277
8278 if (CONSP (object) && EQ (XCAR (object), Qimage))
8279 {
8280 Lisp_Object tem;
8281
8282 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8283 if (EQ (XCAR (tem), QCtype))
8284 {
8285 tem = XCDR (tem);
8286 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8287 {
8288 struct image_type *type;
8289 type = lookup_image_type (XCAR (tem));
8290 if (type)
8291 valid_p = type->valid_p (object);
8292 }
8293
8294 break;
8295 }
8296 }
8297
8298 return valid_p;
8299 }
8300
8301
8302 /* Log error message with format string FORMAT and argument ARG.
8303 Signaling an error, e.g. when an image cannot be loaded, is not a
8304 good idea because this would interrupt redisplay, and the error
8305 message display would lead to another redisplay. This function
8306 therefore simply displays a message. */
8307
8308 static void
8309 image_error (format, arg1, arg2)
8310 char *format;
8311 Lisp_Object arg1, arg2;
8312 {
8313 add_to_log (format, arg1, arg2);
8314 }
8315
8316
8317 \f
8318 /***********************************************************************
8319 Image specifications
8320 ***********************************************************************/
8321
8322 enum image_value_type
8323 {
8324 IMAGE_DONT_CHECK_VALUE_TYPE,
8325 IMAGE_STRING_VALUE,
8326 IMAGE_STRING_OR_NIL_VALUE,
8327 IMAGE_SYMBOL_VALUE,
8328 IMAGE_POSITIVE_INTEGER_VALUE,
8329 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
8330 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
8331 IMAGE_ASCENT_VALUE,
8332 IMAGE_INTEGER_VALUE,
8333 IMAGE_FUNCTION_VALUE,
8334 IMAGE_NUMBER_VALUE,
8335 IMAGE_BOOL_VALUE
8336 };
8337
8338 /* Structure used when parsing image specifications. */
8339
8340 struct image_keyword
8341 {
8342 /* Name of keyword. */
8343 char *name;
8344
8345 /* The type of value allowed. */
8346 enum image_value_type type;
8347
8348 /* Non-zero means key must be present. */
8349 int mandatory_p;
8350
8351 /* Used to recognize duplicate keywords in a property list. */
8352 int count;
8353
8354 /* The value that was found. */
8355 Lisp_Object value;
8356 };
8357
8358
8359 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8360 int, Lisp_Object));
8361 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8362
8363
8364 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
8365 has the format (image KEYWORD VALUE ...). One of the keyword/
8366 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8367 image_keywords structures of size NKEYWORDS describing other
8368 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8369
8370 static int
8371 parse_image_spec (spec, keywords, nkeywords, type)
8372 Lisp_Object spec;
8373 struct image_keyword *keywords;
8374 int nkeywords;
8375 Lisp_Object type;
8376 {
8377 int i;
8378 Lisp_Object plist;
8379
8380 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8381 return 0;
8382
8383 plist = XCDR (spec);
8384 while (CONSP (plist))
8385 {
8386 Lisp_Object key, value;
8387
8388 /* First element of a pair must be a symbol. */
8389 key = XCAR (plist);
8390 plist = XCDR (plist);
8391 if (!SYMBOLP (key))
8392 return 0;
8393
8394 /* There must follow a value. */
8395 if (!CONSP (plist))
8396 return 0;
8397 value = XCAR (plist);
8398 plist = XCDR (plist);
8399
8400 /* Find key in KEYWORDS. Error if not found. */
8401 for (i = 0; i < nkeywords; ++i)
8402 if (strcmp (keywords[i].name, XSTRING (SYMBOL_NAME (key))->data) == 0)
8403 break;
8404
8405 if (i == nkeywords)
8406 continue;
8407
8408 /* Record that we recognized the keyword. If a keywords
8409 was found more than once, it's an error. */
8410 keywords[i].value = value;
8411 ++keywords[i].count;
8412
8413 if (keywords[i].count > 1)
8414 return 0;
8415
8416 /* Check type of value against allowed type. */
8417 switch (keywords[i].type)
8418 {
8419 case IMAGE_STRING_VALUE:
8420 if (!STRINGP (value))
8421 return 0;
8422 break;
8423
8424 case IMAGE_STRING_OR_NIL_VALUE:
8425 if (!STRINGP (value) && !NILP (value))
8426 return 0;
8427 break;
8428
8429 case IMAGE_SYMBOL_VALUE:
8430 if (!SYMBOLP (value))
8431 return 0;
8432 break;
8433
8434 case IMAGE_POSITIVE_INTEGER_VALUE:
8435 if (!INTEGERP (value) || XINT (value) <= 0)
8436 return 0;
8437 break;
8438
8439 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8440 if (INTEGERP (value) && XINT (value) >= 0)
8441 break;
8442 if (CONSP (value)
8443 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8444 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8445 break;
8446 return 0;
8447
8448 case IMAGE_ASCENT_VALUE:
8449 if (SYMBOLP (value) && EQ (value, Qcenter))
8450 break;
8451 else if (INTEGERP (value)
8452 && XINT (value) >= 0
8453 && XINT (value) <= 100)
8454 break;
8455 return 0;
8456
8457 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8458 if (!INTEGERP (value) || XINT (value) < 0)
8459 return 0;
8460 break;
8461
8462 case IMAGE_DONT_CHECK_VALUE_TYPE:
8463 break;
8464
8465 case IMAGE_FUNCTION_VALUE:
8466 value = indirect_function (value);
8467 if (SUBRP (value)
8468 || COMPILEDP (value)
8469 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8470 break;
8471 return 0;
8472
8473 case IMAGE_NUMBER_VALUE:
8474 if (!INTEGERP (value) && !FLOATP (value))
8475 return 0;
8476 break;
8477
8478 case IMAGE_INTEGER_VALUE:
8479 if (!INTEGERP (value))
8480 return 0;
8481 break;
8482
8483 case IMAGE_BOOL_VALUE:
8484 if (!NILP (value) && !EQ (value, Qt))
8485 return 0;
8486 break;
8487
8488 default:
8489 abort ();
8490 break;
8491 }
8492
8493 if (EQ (key, QCtype) && !EQ (type, value))
8494 return 0;
8495 }
8496
8497 /* Check that all mandatory fields are present. */
8498 for (i = 0; i < nkeywords; ++i)
8499 if (keywords[i].mandatory_p && keywords[i].count == 0)
8500 return 0;
8501
8502 return NILP (plist);
8503 }
8504
8505
8506 /* Return the value of KEY in image specification SPEC. Value is nil
8507 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8508 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8509
8510 static Lisp_Object
8511 image_spec_value (spec, key, found)
8512 Lisp_Object spec, key;
8513 int *found;
8514 {
8515 Lisp_Object tail;
8516
8517 xassert (valid_image_p (spec));
8518
8519 for (tail = XCDR (spec);
8520 CONSP (tail) && CONSP (XCDR (tail));
8521 tail = XCDR (XCDR (tail)))
8522 {
8523 if (EQ (XCAR (tail), key))
8524 {
8525 if (found)
8526 *found = 1;
8527 return XCAR (XCDR (tail));
8528 }
8529 }
8530
8531 if (found)
8532 *found = 0;
8533 return Qnil;
8534 }
8535
8536
8537 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8538 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8539 PIXELS non-nil means return the size in pixels, otherwise return the
8540 size in canonical character units.
8541 FRAME is the frame on which the image will be displayed. FRAME nil
8542 or omitted means use the selected frame. */)
8543 (spec, pixels, frame)
8544 Lisp_Object spec, pixels, frame;
8545 {
8546 Lisp_Object size;
8547
8548 size = Qnil;
8549 if (valid_image_p (spec))
8550 {
8551 struct frame *f = check_x_frame (frame);
8552 int id = lookup_image (f, spec);
8553 struct image *img = IMAGE_FROM_ID (f, id);
8554 int width = img->width + 2 * img->hmargin;
8555 int height = img->height + 2 * img->vmargin;
8556
8557 if (NILP (pixels))
8558 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8559 make_float ((double) height / CANON_Y_UNIT (f)));
8560 else
8561 size = Fcons (make_number (width), make_number (height));
8562 }
8563 else
8564 error ("Invalid image specification");
8565
8566 return size;
8567 }
8568
8569
8570 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8571 doc: /* Return t if image SPEC has a mask bitmap.
8572 FRAME is the frame on which the image will be displayed. FRAME nil
8573 or omitted means use the selected frame. */)
8574 (spec, frame)
8575 Lisp_Object spec, frame;
8576 {
8577 Lisp_Object mask;
8578
8579 mask = Qnil;
8580 if (valid_image_p (spec))
8581 {
8582 struct frame *f = check_x_frame (frame);
8583 int id = lookup_image (f, spec);
8584 struct image *img = IMAGE_FROM_ID (f, id);
8585 if (img->mask)
8586 mask = Qt;
8587 }
8588 else
8589 error ("Invalid image specification");
8590
8591 return mask;
8592 }
8593
8594 \f
8595 /***********************************************************************
8596 Image type independent image structures
8597 ***********************************************************************/
8598
8599 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8600 static void free_image P_ ((struct frame *f, struct image *img));
8601
8602
8603 /* Allocate and return a new image structure for image specification
8604 SPEC. SPEC has a hash value of HASH. */
8605
8606 static struct image *
8607 make_image (spec, hash)
8608 Lisp_Object spec;
8609 unsigned hash;
8610 {
8611 struct image *img = (struct image *) xmalloc (sizeof *img);
8612
8613 xassert (valid_image_p (spec));
8614 bzero (img, sizeof *img);
8615 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8616 xassert (img->type != NULL);
8617 img->spec = spec;
8618 img->data.lisp_val = Qnil;
8619 img->ascent = DEFAULT_IMAGE_ASCENT;
8620 img->hash = hash;
8621 return img;
8622 }
8623
8624
8625 /* Free image IMG which was used on frame F, including its resources. */
8626
8627 static void
8628 free_image (f, img)
8629 struct frame *f;
8630 struct image *img;
8631 {
8632 if (img)
8633 {
8634 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8635
8636 /* Remove IMG from the hash table of its cache. */
8637 if (img->prev)
8638 img->prev->next = img->next;
8639 else
8640 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8641
8642 if (img->next)
8643 img->next->prev = img->prev;
8644
8645 c->images[img->id] = NULL;
8646
8647 /* Free resources, then free IMG. */
8648 img->type->free (f, img);
8649 xfree (img);
8650 }
8651 }
8652
8653
8654 /* Prepare image IMG for display on frame F. Must be called before
8655 drawing an image. */
8656
8657 void
8658 prepare_image_for_display (f, img)
8659 struct frame *f;
8660 struct image *img;
8661 {
8662 EMACS_TIME t;
8663
8664 /* We're about to display IMG, so set its timestamp to `now'. */
8665 EMACS_GET_TIME (t);
8666 img->timestamp = EMACS_SECS (t);
8667
8668 /* If IMG doesn't have a pixmap yet, load it now, using the image
8669 type dependent loader function. */
8670 if (img->pixmap == 0 && !img->load_failed_p)
8671 img->load_failed_p = img->type->load (f, img) == 0;
8672 }
8673
8674
8675 /* Value is the number of pixels for the ascent of image IMG when
8676 drawn in face FACE. */
8677
8678 int
8679 image_ascent (img, face)
8680 struct image *img;
8681 struct face *face;
8682 {
8683 int height = img->height + img->vmargin;
8684 int ascent;
8685
8686 if (img->ascent == CENTERED_IMAGE_ASCENT)
8687 {
8688 if (face->font)
8689 ascent = height / 2 - (FONT_DESCENT(face->font)
8690 - FONT_BASE(face->font)) / 2;
8691 else
8692 ascent = height / 2;
8693 }
8694 else
8695 ascent = (int) (height * img->ascent / 100.0);
8696
8697 return ascent;
8698 }
8699
8700
8701 \f
8702 /* Image background colors. */
8703
8704 /* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8705 context with the bitmap selected. */
8706 static COLORREF
8707 four_corners_best (ximg, width, height)
8708 HDC ximg;
8709 unsigned long width, height;
8710 {
8711 COLORREF corners[4], best;
8712 int i, best_count;
8713
8714 /* Get the colors at the corners of ximg. */
8715 corners[0] = GetPixel (ximg, 0, 0);
8716 corners[1] = GetPixel (ximg, width - 1, 0);
8717 corners[2] = GetPixel (ximg, width - 1, height - 1);
8718 corners[3] = GetPixel (ximg, 0, height - 1);
8719
8720 /* Choose the most frequently found color as background. */
8721 for (i = best_count = 0; i < 4; ++i)
8722 {
8723 int j, n;
8724
8725 for (j = n = 0; j < 4; ++j)
8726 if (corners[i] == corners[j])
8727 ++n;
8728
8729 if (n > best_count)
8730 best = corners[i], best_count = n;
8731 }
8732
8733 return best;
8734 }
8735
8736 /* Return the `background' field of IMG. If IMG doesn't have one yet,
8737 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8738 object to use for the heuristic. */
8739
8740 unsigned long
8741 image_background (img, f, ximg)
8742 struct image *img;
8743 struct frame *f;
8744 XImage *ximg;
8745 {
8746 if (! img->background_valid)
8747 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8748 {
8749 #if 0 /* TODO: Image support. */
8750 int free_ximg = !ximg;
8751
8752 if (! ximg)
8753 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8754 0, 0, img->width, img->height, ~0, ZPixmap);
8755
8756 img->background = four_corners_best (ximg, img->width, img->height);
8757
8758 if (free_ximg)
8759 XDestroyImage (ximg);
8760
8761 img->background_valid = 1;
8762 #endif
8763 }
8764
8765 return img->background;
8766 }
8767
8768 /* Return the `background_transparent' field of IMG. If IMG doesn't
8769 have one yet, it is guessed heuristically. If non-zero, MASK is an
8770 existing XImage object to use for the heuristic. */
8771
8772 int
8773 image_background_transparent (img, f, mask)
8774 struct image *img;
8775 struct frame *f;
8776 XImage *mask;
8777 {
8778 if (! img->background_transparent_valid)
8779 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8780 {
8781 #if 0 /* TODO: Image support. */
8782 if (img->mask)
8783 {
8784 int free_mask = !mask;
8785
8786 if (! mask)
8787 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8788 0, 0, img->width, img->height, ~0, ZPixmap);
8789
8790 img->background_transparent
8791 = !four_corners_best (mask, img->width, img->height);
8792
8793 if (free_mask)
8794 XDestroyImage (mask);
8795 }
8796 else
8797 #endif
8798 img->background_transparent = 0;
8799
8800 img->background_transparent_valid = 1;
8801 }
8802
8803 return img->background_transparent;
8804 }
8805
8806 \f
8807 /***********************************************************************
8808 Helper functions for X image types
8809 ***********************************************************************/
8810
8811 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8812 int, int));
8813 static void x_clear_image P_ ((struct frame *f, struct image *img));
8814 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8815 struct image *img,
8816 Lisp_Object color_name,
8817 unsigned long dflt));
8818
8819
8820 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8821 free the pixmap if any. MASK_P non-zero means clear the mask
8822 pixmap if any. COLORS_P non-zero means free colors allocated for
8823 the image, if any. */
8824
8825 static void
8826 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8827 struct frame *f;
8828 struct image *img;
8829 int pixmap_p, mask_p, colors_p;
8830 {
8831 if (pixmap_p && img->pixmap)
8832 {
8833 DeleteObject (img->pixmap);
8834 img->pixmap = NULL;
8835 img->background_valid = 0;
8836 }
8837
8838 if (mask_p && img->mask)
8839 {
8840 DeleteObject (img->mask);
8841 img->mask = NULL;
8842 img->background_transparent_valid = 0;
8843 }
8844
8845 if (colors_p && img->ncolors)
8846 {
8847 #if 0 /* TODO: color table support. */
8848 x_free_colors (f, img->colors, img->ncolors);
8849 #endif
8850 xfree (img->colors);
8851 img->colors = NULL;
8852 img->ncolors = 0;
8853 }
8854 }
8855
8856 /* Free X resources of image IMG which is used on frame F. */
8857
8858 static void
8859 x_clear_image (f, img)
8860 struct frame *f;
8861 struct image *img;
8862 {
8863 if (img->pixmap)
8864 {
8865 BLOCK_INPUT;
8866 DeleteObject (img->pixmap);
8867 img->pixmap = 0;
8868 UNBLOCK_INPUT;
8869 }
8870
8871 if (img->ncolors)
8872 {
8873 #if 0 /* TODO: color table support */
8874
8875 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8876
8877 /* If display has an immutable color map, freeing colors is not
8878 necessary and some servers don't allow it. So don't do it. */
8879 if (class != StaticColor
8880 && class != StaticGray
8881 && class != TrueColor)
8882 {
8883 Colormap cmap;
8884 BLOCK_INPUT;
8885 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8886 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8887 img->ncolors, 0);
8888 UNBLOCK_INPUT;
8889 }
8890 #endif
8891
8892 xfree (img->colors);
8893 img->colors = NULL;
8894 img->ncolors = 0;
8895 }
8896 }
8897
8898
8899 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8900 cannot be allocated, use DFLT. Add a newly allocated color to
8901 IMG->colors, so that it can be freed again. Value is the pixel
8902 color. */
8903
8904 static unsigned long
8905 x_alloc_image_color (f, img, color_name, dflt)
8906 struct frame *f;
8907 struct image *img;
8908 Lisp_Object color_name;
8909 unsigned long dflt;
8910 {
8911 XColor color;
8912 unsigned long result;
8913
8914 xassert (STRINGP (color_name));
8915
8916 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8917 {
8918 /* This isn't called frequently so we get away with simply
8919 reallocating the color vector to the needed size, here. */
8920 ++img->ncolors;
8921 img->colors =
8922 (unsigned long *) xrealloc (img->colors,
8923 img->ncolors * sizeof *img->colors);
8924 img->colors[img->ncolors - 1] = color.pixel;
8925 result = color.pixel;
8926 }
8927 else
8928 result = dflt;
8929 return result;
8930 }
8931
8932
8933 \f
8934 /***********************************************************************
8935 Image Cache
8936 ***********************************************************************/
8937
8938 static void cache_image P_ ((struct frame *f, struct image *img));
8939 static void postprocess_image P_ ((struct frame *, struct image *));
8940
8941
8942 /* Return a new, initialized image cache that is allocated from the
8943 heap. Call free_image_cache to free an image cache. */
8944
8945 struct image_cache *
8946 make_image_cache ()
8947 {
8948 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8949 int size;
8950
8951 bzero (c, sizeof *c);
8952 c->size = 50;
8953 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8954 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8955 c->buckets = (struct image **) xmalloc (size);
8956 bzero (c->buckets, size);
8957 return c;
8958 }
8959
8960
8961 /* Free image cache of frame F. Be aware that X frames share images
8962 caches. */
8963
8964 void
8965 free_image_cache (f)
8966 struct frame *f;
8967 {
8968 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8969 if (c)
8970 {
8971 int i;
8972
8973 /* Cache should not be referenced by any frame when freed. */
8974 xassert (c->refcount == 0);
8975
8976 for (i = 0; i < c->used; ++i)
8977 free_image (f, c->images[i]);
8978 xfree (c->images);
8979 xfree (c);
8980 xfree (c->buckets);
8981 FRAME_X_IMAGE_CACHE (f) = NULL;
8982 }
8983 }
8984
8985
8986 /* Clear image cache of frame F. FORCE_P non-zero means free all
8987 images. FORCE_P zero means clear only images that haven't been
8988 displayed for some time. Should be called from time to time to
8989 reduce the number of loaded images. If image-eviction-seconds is
8990 non-nil, this frees images in the cache which weren't displayed for
8991 at least that many seconds. */
8992
8993 void
8994 clear_image_cache (f, force_p)
8995 struct frame *f;
8996 int force_p;
8997 {
8998 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8999
9000 if (c && INTEGERP (Vimage_cache_eviction_delay))
9001 {
9002 EMACS_TIME t;
9003 unsigned long old;
9004 int i, nfreed;
9005
9006 EMACS_GET_TIME (t);
9007 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
9008
9009 /* Block input so that we won't be interrupted by a SIGIO
9010 while being in an inconsistent state. */
9011 BLOCK_INPUT;
9012
9013 for (i = nfreed = 0; i < c->used; ++i)
9014 {
9015 struct image *img = c->images[i];
9016 if (img != NULL
9017 && (force_p || (img->timestamp < old)))
9018 {
9019 free_image (f, img);
9020 ++nfreed;
9021 }
9022 }
9023
9024 /* We may be clearing the image cache because, for example,
9025 Emacs was iconified for a longer period of time. In that
9026 case, current matrices may still contain references to
9027 images freed above. So, clear these matrices. */
9028 if (nfreed)
9029 {
9030 Lisp_Object tail, frame;
9031
9032 FOR_EACH_FRAME (tail, frame)
9033 {
9034 struct frame *f = XFRAME (frame);
9035 if (FRAME_W32_P (f)
9036 && FRAME_X_IMAGE_CACHE (f) == c)
9037 clear_current_matrices (f);
9038 }
9039
9040 ++windows_or_buffers_changed;
9041 }
9042
9043 UNBLOCK_INPUT;
9044 }
9045 }
9046
9047
9048 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9049 0, 1, 0,
9050 doc: /* Clear the image cache of FRAME.
9051 FRAME nil or omitted means use the selected frame.
9052 FRAME t means clear the image caches of all frames. */)
9053 (frame)
9054 Lisp_Object frame;
9055 {
9056 if (EQ (frame, Qt))
9057 {
9058 Lisp_Object tail;
9059
9060 FOR_EACH_FRAME (tail, frame)
9061 if (FRAME_W32_P (XFRAME (frame)))
9062 clear_image_cache (XFRAME (frame), 1);
9063 }
9064 else
9065 clear_image_cache (check_x_frame (frame), 1);
9066
9067 return Qnil;
9068 }
9069
9070
9071 /* Compute masks and transform image IMG on frame F, as specified
9072 by the image's specification, */
9073
9074 static void
9075 postprocess_image (f, img)
9076 struct frame *f;
9077 struct image *img;
9078 {
9079 #if 0 /* TODO: image support. */
9080 /* Manipulation of the image's mask. */
9081 if (img->pixmap)
9082 {
9083 Lisp_Object conversion, spec;
9084 Lisp_Object mask;
9085
9086 spec = img->spec;
9087
9088 /* `:heuristic-mask t'
9089 `:mask heuristic'
9090 means build a mask heuristically.
9091 `:heuristic-mask (R G B)'
9092 `:mask (heuristic (R G B))'
9093 means build a mask from color (R G B) in the
9094 image.
9095 `:mask nil'
9096 means remove a mask, if any. */
9097
9098 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9099 if (!NILP (mask))
9100 x_build_heuristic_mask (f, img, mask);
9101 else
9102 {
9103 int found_p;
9104
9105 mask = image_spec_value (spec, QCmask, &found_p);
9106
9107 if (EQ (mask, Qheuristic))
9108 x_build_heuristic_mask (f, img, Qt);
9109 else if (CONSP (mask)
9110 && EQ (XCAR (mask), Qheuristic))
9111 {
9112 if (CONSP (XCDR (mask)))
9113 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9114 else
9115 x_build_heuristic_mask (f, img, XCDR (mask));
9116 }
9117 else if (NILP (mask) && found_p && img->mask)
9118 {
9119 DeleteObject (img->mask);
9120 img->mask = NULL;
9121 }
9122 }
9123
9124
9125 /* Should we apply an image transformation algorithm? */
9126 conversion = image_spec_value (spec, QCconversion, NULL);
9127 if (EQ (conversion, Qdisabled))
9128 x_disable_image (f, img);
9129 else if (EQ (conversion, Qlaplace))
9130 x_laplace (f, img);
9131 else if (EQ (conversion, Qemboss))
9132 x_emboss (f, img);
9133 else if (CONSP (conversion)
9134 && EQ (XCAR (conversion), Qedge_detection))
9135 {
9136 Lisp_Object tem;
9137 tem = XCDR (conversion);
9138 if (CONSP (tem))
9139 x_edge_detection (f, img,
9140 Fplist_get (tem, QCmatrix),
9141 Fplist_get (tem, QCcolor_adjustment));
9142 }
9143 }
9144 #endif
9145 }
9146
9147
9148 /* Return the id of image with Lisp specification SPEC on frame F.
9149 SPEC must be a valid Lisp image specification (see valid_image_p). */
9150
9151 int
9152 lookup_image (f, spec)
9153 struct frame *f;
9154 Lisp_Object spec;
9155 {
9156 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9157 struct image *img;
9158 int i;
9159 unsigned hash;
9160 struct gcpro gcpro1;
9161 EMACS_TIME now;
9162
9163 /* F must be a window-system frame, and SPEC must be a valid image
9164 specification. */
9165 xassert (FRAME_WINDOW_P (f));
9166 xassert (valid_image_p (spec));
9167
9168 GCPRO1 (spec);
9169
9170 /* Look up SPEC in the hash table of the image cache. */
9171 hash = sxhash (spec, 0);
9172 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9173
9174 for (img = c->buckets[i]; img; img = img->next)
9175 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9176 break;
9177
9178 /* If not found, create a new image and cache it. */
9179 if (img == NULL)
9180 {
9181 extern Lisp_Object Qpostscript;
9182
9183 BLOCK_INPUT;
9184 img = make_image (spec, hash);
9185 cache_image (f, img);
9186 img->load_failed_p = img->type->load (f, img) == 0;
9187
9188 /* If we can't load the image, and we don't have a width and
9189 height, use some arbitrary width and height so that we can
9190 draw a rectangle for it. */
9191 if (img->load_failed_p)
9192 {
9193 Lisp_Object value;
9194
9195 value = image_spec_value (spec, QCwidth, NULL);
9196 img->width = (INTEGERP (value)
9197 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9198 value = image_spec_value (spec, QCheight, NULL);
9199 img->height = (INTEGERP (value)
9200 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9201 }
9202 else
9203 {
9204 /* Handle image type independent image attributes
9205 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9206 `:background COLOR'. */
9207 Lisp_Object ascent, margin, relief, bg;
9208
9209 ascent = image_spec_value (spec, QCascent, NULL);
9210 if (INTEGERP (ascent))
9211 img->ascent = XFASTINT (ascent);
9212 else if (EQ (ascent, Qcenter))
9213 img->ascent = CENTERED_IMAGE_ASCENT;
9214
9215 margin = image_spec_value (spec, QCmargin, NULL);
9216 if (INTEGERP (margin) && XINT (margin) >= 0)
9217 img->vmargin = img->hmargin = XFASTINT (margin);
9218 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9219 && INTEGERP (XCDR (margin)))
9220 {
9221 if (XINT (XCAR (margin)) > 0)
9222 img->hmargin = XFASTINT (XCAR (margin));
9223 if (XINT (XCDR (margin)) > 0)
9224 img->vmargin = XFASTINT (XCDR (margin));
9225 }
9226
9227 relief = image_spec_value (spec, QCrelief, NULL);
9228 if (INTEGERP (relief))
9229 {
9230 img->relief = XINT (relief);
9231 img->hmargin += abs (img->relief);
9232 img->vmargin += abs (img->relief);
9233 }
9234
9235 if (! img->background_valid)
9236 {
9237 bg = image_spec_value (img->spec, QCbackground, NULL);
9238 if (!NILP (bg))
9239 {
9240 img->background
9241 = x_alloc_image_color (f, img, bg,
9242 FRAME_BACKGROUND_PIXEL (f));
9243 img->background_valid = 1;
9244 }
9245 }
9246
9247 /* Do image transformations and compute masks, unless we
9248 don't have the image yet. */
9249 if (!EQ (*img->type->type, Qpostscript))
9250 postprocess_image (f, img);
9251 }
9252
9253 UNBLOCK_INPUT;
9254 xassert (!interrupt_input_blocked);
9255 }
9256
9257 /* We're using IMG, so set its timestamp to `now'. */
9258 EMACS_GET_TIME (now);
9259 img->timestamp = EMACS_SECS (now);
9260
9261 UNGCPRO;
9262
9263 /* Value is the image id. */
9264 return img->id;
9265 }
9266
9267
9268 /* Cache image IMG in the image cache of frame F. */
9269
9270 static void
9271 cache_image (f, img)
9272 struct frame *f;
9273 struct image *img;
9274 {
9275 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9276 int i;
9277
9278 /* Find a free slot in c->images. */
9279 for (i = 0; i < c->used; ++i)
9280 if (c->images[i] == NULL)
9281 break;
9282
9283 /* If no free slot found, maybe enlarge c->images. */
9284 if (i == c->used && c->used == c->size)
9285 {
9286 c->size *= 2;
9287 c->images = (struct image **) xrealloc (c->images,
9288 c->size * sizeof *c->images);
9289 }
9290
9291 /* Add IMG to c->images, and assign IMG an id. */
9292 c->images[i] = img;
9293 img->id = i;
9294 if (i == c->used)
9295 ++c->used;
9296
9297 /* Add IMG to the cache's hash table. */
9298 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9299 img->next = c->buckets[i];
9300 if (img->next)
9301 img->next->prev = img;
9302 img->prev = NULL;
9303 c->buckets[i] = img;
9304 }
9305
9306
9307 /* Call FN on every image in the image cache of frame F. Used to mark
9308 Lisp Objects in the image cache. */
9309
9310 void
9311 forall_images_in_image_cache (f, fn)
9312 struct frame *f;
9313 void (*fn) P_ ((struct image *img));
9314 {
9315 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9316 {
9317 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9318 if (c)
9319 {
9320 int i;
9321 for (i = 0; i < c->used; ++i)
9322 if (c->images[i])
9323 fn (c->images[i]);
9324 }
9325 }
9326 }
9327
9328
9329 \f
9330 /***********************************************************************
9331 W32 support code
9332 ***********************************************************************/
9333
9334 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9335 XImage **, Pixmap *));
9336 static void x_destroy_x_image P_ ((XImage *));
9337 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9338
9339
9340 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9341 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9342 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
9343 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9344 DEPTH should indicate the bit depth of the image. Print error
9345 messages via image_error if an error occurs. Value is non-zero if
9346 successful. */
9347
9348 static int
9349 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9350 struct frame *f;
9351 int width, height, depth;
9352 XImage **ximg;
9353 Pixmap *pixmap;
9354 {
9355 BITMAPINFOHEADER *header;
9356 HDC hdc;
9357 int scanline_width_bits;
9358 int remainder;
9359 int palette_colors = 0;
9360
9361 if (depth == 0)
9362 depth = 24;
9363
9364 if (depth != 1 && depth != 4 && depth != 8
9365 && depth != 16 && depth != 24 && depth != 32)
9366 {
9367 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9368 return 0;
9369 }
9370
9371 scanline_width_bits = width * depth;
9372 remainder = scanline_width_bits % 32;
9373
9374 if (remainder)
9375 scanline_width_bits += 32 - remainder;
9376
9377 /* Bitmaps with a depth less than 16 need a palette. */
9378 /* BITMAPINFO structure already contains the first RGBQUAD. */
9379 if (depth < 16)
9380 palette_colors = 1 << depth - 1;
9381
9382 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
9383 if (*ximg == NULL)
9384 {
9385 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
9386 return 0;
9387 }
9388
9389 header = &((*ximg)->info.bmiHeader);
9390 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9391 header->biSize = sizeof (*header);
9392 header->biWidth = width;
9393 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9394 header->biPlanes = 1;
9395 header->biBitCount = depth;
9396 header->biCompression = BI_RGB;
9397 header->biClrUsed = palette_colors;
9398
9399 hdc = get_frame_dc (f);
9400
9401 /* Create a DIBSection and raster array for the bitmap,
9402 and store its handle in *pixmap. */
9403 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9404 &((*ximg)->data), NULL, 0);
9405
9406 /* Realize display palette and garbage all frames. */
9407 release_frame_dc (f, hdc);
9408
9409 if (*pixmap == NULL)
9410 {
9411 DWORD err = GetLastError();
9412 Lisp_Object errcode;
9413 /* All system errors are < 10000, so the following is safe. */
9414 XSETINT (errcode, (int) err);
9415 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
9416 x_destroy_x_image (*ximg);
9417 return 0;
9418 }
9419
9420 return 1;
9421 }
9422
9423
9424 /* Destroy XImage XIMG. Free XIMG->data. */
9425
9426 static void
9427 x_destroy_x_image (ximg)
9428 XImage *ximg;
9429 {
9430 xassert (interrupt_input_blocked);
9431 if (ximg)
9432 {
9433 /* Data will be freed by DestroyObject. */
9434 ximg->data = NULL;
9435 xfree (ximg);
9436 }
9437 }
9438
9439
9440 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9441 are width and height of both the image and pixmap. */
9442
9443 static void
9444 x_put_x_image (f, ximg, pixmap, width, height)
9445 struct frame *f;
9446 XImage *ximg;
9447 Pixmap pixmap;
9448 {
9449
9450 #if TODO /* W32 specific image code. */
9451 GC gc;
9452
9453 xassert (interrupt_input_blocked);
9454 gc = XCreateGC (NULL, pixmap, 0, NULL);
9455 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9456 XFreeGC (NULL, gc);
9457 #endif
9458 }
9459
9460 \f
9461 /***********************************************************************
9462 File Handling
9463 ***********************************************************************/
9464
9465 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
9466 static char *slurp_file P_ ((char *, int *));
9467
9468
9469 /* Find image file FILE. Look in data-directory, then
9470 x-bitmap-file-path. Value is the full name of the file found, or
9471 nil if not found. */
9472
9473 static Lisp_Object
9474 x_find_image_file (file)
9475 Lisp_Object file;
9476 {
9477 Lisp_Object file_found, search_path;
9478 struct gcpro gcpro1, gcpro2;
9479 int fd;
9480
9481 file_found = Qnil;
9482 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9483 GCPRO2 (file_found, search_path);
9484
9485 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
9486 fd = openp (search_path, file, Qnil, &file_found, Qnil);
9487
9488 if (fd == -1)
9489 file_found = Qnil;
9490 else
9491 close (fd);
9492
9493 UNGCPRO;
9494 return file_found;
9495 }
9496
9497
9498 /* Read FILE into memory. Value is a pointer to a buffer allocated
9499 with xmalloc holding FILE's contents. Value is null if an error
9500 occurred. *SIZE is set to the size of the file. */
9501
9502 static char *
9503 slurp_file (file, size)
9504 char *file;
9505 int *size;
9506 {
9507 FILE *fp = NULL;
9508 char *buf = NULL;
9509 struct stat st;
9510
9511 if (stat (file, &st) == 0
9512 && (fp = fopen (file, "r")) != NULL
9513 && (buf = (char *) xmalloc (st.st_size),
9514 fread (buf, 1, st.st_size, fp) == st.st_size))
9515 {
9516 *size = st.st_size;
9517 fclose (fp);
9518 }
9519 else
9520 {
9521 if (fp)
9522 fclose (fp);
9523 if (buf)
9524 {
9525 xfree (buf);
9526 buf = NULL;
9527 }
9528 }
9529
9530 return buf;
9531 }
9532
9533
9534 \f
9535 /***********************************************************************
9536 XBM images
9537 ***********************************************************************/
9538
9539 static int xbm_scan P_ ((char **, char *, char *, int *));
9540 static int xbm_load P_ ((struct frame *f, struct image *img));
9541 static int xbm_load_image P_ ((struct frame *f, struct image *img,
9542 char *, char *));
9543 static int xbm_image_p P_ ((Lisp_Object object));
9544 static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9545 unsigned char **));
9546 static int xbm_file_p P_ ((Lisp_Object));
9547
9548
9549 /* Indices of image specification fields in xbm_format, below. */
9550
9551 enum xbm_keyword_index
9552 {
9553 XBM_TYPE,
9554 XBM_FILE,
9555 XBM_WIDTH,
9556 XBM_HEIGHT,
9557 XBM_DATA,
9558 XBM_FOREGROUND,
9559 XBM_BACKGROUND,
9560 XBM_ASCENT,
9561 XBM_MARGIN,
9562 XBM_RELIEF,
9563 XBM_ALGORITHM,
9564 XBM_HEURISTIC_MASK,
9565 XBM_MASK,
9566 XBM_LAST
9567 };
9568
9569 /* Vector of image_keyword structures describing the format
9570 of valid XBM image specifications. */
9571
9572 static struct image_keyword xbm_format[XBM_LAST] =
9573 {
9574 {":type", IMAGE_SYMBOL_VALUE, 1},
9575 {":file", IMAGE_STRING_VALUE, 0},
9576 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9577 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9578 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9579 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9580 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9581 {":ascent", IMAGE_ASCENT_VALUE, 0},
9582 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9583 {":relief", IMAGE_INTEGER_VALUE, 0},
9584 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9585 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9586 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9587 };
9588
9589 /* Structure describing the image type XBM. */
9590
9591 static struct image_type xbm_type =
9592 {
9593 &Qxbm,
9594 xbm_image_p,
9595 xbm_load,
9596 x_clear_image,
9597 NULL
9598 };
9599
9600 /* Tokens returned from xbm_scan. */
9601
9602 enum xbm_token
9603 {
9604 XBM_TK_IDENT = 256,
9605 XBM_TK_NUMBER
9606 };
9607
9608
9609 /* Return non-zero if OBJECT is a valid XBM-type image specification.
9610 A valid specification is a list starting with the symbol `image'
9611 The rest of the list is a property list which must contain an
9612 entry `:type xbm..
9613
9614 If the specification specifies a file to load, it must contain
9615 an entry `:file FILENAME' where FILENAME is a string.
9616
9617 If the specification is for a bitmap loaded from memory it must
9618 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9619 WIDTH and HEIGHT are integers > 0. DATA may be:
9620
9621 1. a string large enough to hold the bitmap data, i.e. it must
9622 have a size >= (WIDTH + 7) / 8 * HEIGHT
9623
9624 2. a bool-vector of size >= WIDTH * HEIGHT
9625
9626 3. a vector of strings or bool-vectors, one for each line of the
9627 bitmap.
9628
9629 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9630 may not be specified in this case because they are defined in the
9631 XBM file.
9632
9633 Both the file and data forms may contain the additional entries
9634 `:background COLOR' and `:foreground COLOR'. If not present,
9635 foreground and background of the frame on which the image is
9636 displayed is used. */
9637
9638 static int
9639 xbm_image_p (object)
9640 Lisp_Object object;
9641 {
9642 struct image_keyword kw[XBM_LAST];
9643
9644 bcopy (xbm_format, kw, sizeof kw);
9645 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9646 return 0;
9647
9648 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9649
9650 if (kw[XBM_FILE].count)
9651 {
9652 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9653 return 0;
9654 }
9655 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9656 {
9657 /* In-memory XBM file. */
9658 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9659 return 0;
9660 }
9661 else
9662 {
9663 Lisp_Object data;
9664 int width, height;
9665
9666 /* Entries for `:width', `:height' and `:data' must be present. */
9667 if (!kw[XBM_WIDTH].count
9668 || !kw[XBM_HEIGHT].count
9669 || !kw[XBM_DATA].count)
9670 return 0;
9671
9672 data = kw[XBM_DATA].value;
9673 width = XFASTINT (kw[XBM_WIDTH].value);
9674 height = XFASTINT (kw[XBM_HEIGHT].value);
9675
9676 /* Check type of data, and width and height against contents of
9677 data. */
9678 if (VECTORP (data))
9679 {
9680 int i;
9681
9682 /* Number of elements of the vector must be >= height. */
9683 if (XVECTOR (data)->size < height)
9684 return 0;
9685
9686 /* Each string or bool-vector in data must be large enough
9687 for one line of the image. */
9688 for (i = 0; i < height; ++i)
9689 {
9690 Lisp_Object elt = XVECTOR (data)->contents[i];
9691
9692 if (STRINGP (elt))
9693 {
9694 if (XSTRING (elt)->size
9695 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9696 return 0;
9697 }
9698 else if (BOOL_VECTOR_P (elt))
9699 {
9700 if (XBOOL_VECTOR (elt)->size < width)
9701 return 0;
9702 }
9703 else
9704 return 0;
9705 }
9706 }
9707 else if (STRINGP (data))
9708 {
9709 if (XSTRING (data)->size
9710 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9711 return 0;
9712 }
9713 else if (BOOL_VECTOR_P (data))
9714 {
9715 if (XBOOL_VECTOR (data)->size < width * height)
9716 return 0;
9717 }
9718 else
9719 return 0;
9720 }
9721
9722 return 1;
9723 }
9724
9725
9726 /* Scan a bitmap file. FP is the stream to read from. Value is
9727 either an enumerator from enum xbm_token, or a character for a
9728 single-character token, or 0 at end of file. If scanning an
9729 identifier, store the lexeme of the identifier in SVAL. If
9730 scanning a number, store its value in *IVAL. */
9731
9732 static int
9733 xbm_scan (s, end, sval, ival)
9734 char **s, *end;
9735 char *sval;
9736 int *ival;
9737 {
9738 int c;
9739
9740 loop:
9741
9742 /* Skip white space. */
9743 while (*s < end && (c = *(*s)++, isspace (c)))
9744 ;
9745
9746 if (*s >= end)
9747 c = 0;
9748 else if (isdigit (c))
9749 {
9750 int value = 0, digit;
9751
9752 if (c == '0' && *s < end)
9753 {
9754 c = *(*s)++;
9755 if (c == 'x' || c == 'X')
9756 {
9757 while (*s < end)
9758 {
9759 c = *(*s)++;
9760 if (isdigit (c))
9761 digit = c - '0';
9762 else if (c >= 'a' && c <= 'f')
9763 digit = c - 'a' + 10;
9764 else if (c >= 'A' && c <= 'F')
9765 digit = c - 'A' + 10;
9766 else
9767 break;
9768 value = 16 * value + digit;
9769 }
9770 }
9771 else if (isdigit (c))
9772 {
9773 value = c - '0';
9774 while (*s < end
9775 && (c = *(*s)++, isdigit (c)))
9776 value = 8 * value + c - '0';
9777 }
9778 }
9779 else
9780 {
9781 value = c - '0';
9782 while (*s < end
9783 && (c = *(*s)++, isdigit (c)))
9784 value = 10 * value + c - '0';
9785 }
9786
9787 if (*s < end)
9788 *s = *s - 1;
9789 *ival = value;
9790 c = XBM_TK_NUMBER;
9791 }
9792 else if (isalpha (c) || c == '_')
9793 {
9794 *sval++ = c;
9795 while (*s < end
9796 && (c = *(*s)++, (isalnum (c) || c == '_')))
9797 *sval++ = c;
9798 *sval = 0;
9799 if (*s < end)
9800 *s = *s - 1;
9801 c = XBM_TK_IDENT;
9802 }
9803 else if (c == '/' && **s == '*')
9804 {
9805 /* C-style comment. */
9806 ++*s;
9807 while (**s && (**s != '*' || *(*s + 1) != '/'))
9808 ++*s;
9809 if (**s)
9810 {
9811 *s += 2;
9812 goto loop;
9813 }
9814 }
9815
9816 return c;
9817 }
9818
9819
9820 /* XBM bits seem to be backward within bytes compared with how
9821 Windows does things. */
9822 static unsigned char reflect_byte (unsigned char orig)
9823 {
9824 int i;
9825 unsigned char reflected = 0x00;
9826 for (i = 0; i < 8; i++)
9827 {
9828 if (orig & (0x01 << i))
9829 reflected |= 0x80 >> i;
9830 }
9831 return reflected;
9832 }
9833
9834
9835 /* Create a Windows bitmap from X bitmap data. */
9836 static HBITMAP
9837 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9838 {
9839 int i, j, w1, w2;
9840 char *bits, *p;
9841 HBITMAP bmp;
9842
9843 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9844 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
9845 bits = (char *) xmalloc (height * w2);
9846 bzero (bits, height * w2);
9847 for (i = 0; i < height; i++)
9848 {
9849 p = bits + i*w2;
9850 for (j = 0; j < w1; j++)
9851 *p++ = reflect_byte(*data++);
9852 }
9853 bmp = CreateBitmap (width, height, 1, 1, bits);
9854 xfree (bits);
9855
9856 return bmp;
9857 }
9858
9859
9860 /* Replacement for XReadBitmapFileData which isn't available under old
9861 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9862 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9863 the image. Return in *DATA the bitmap data allocated with xmalloc.
9864 Value is non-zero if successful. DATA null means just test if
9865 CONTENTS looks like an in-memory XBM file. */
9866
9867 static int
9868 xbm_read_bitmap_data (contents, end, width, height, data)
9869 char *contents, *end;
9870 int *width, *height;
9871 unsigned char **data;
9872 {
9873 char *s = contents;
9874 char buffer[BUFSIZ];
9875 int padding_p = 0;
9876 int v10 = 0;
9877 int bytes_per_line, i, nbytes;
9878 unsigned char *p;
9879 int value;
9880 int LA1;
9881
9882 #define match() \
9883 LA1 = xbm_scan (&s, end, buffer, &value)
9884
9885 #define expect(TOKEN) \
9886 if (LA1 != (TOKEN)) \
9887 goto failure; \
9888 else \
9889 match ()
9890
9891 #define expect_ident(IDENT) \
9892 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9893 match (); \
9894 else \
9895 goto failure
9896
9897 *width = *height = -1;
9898 if (data)
9899 *data = NULL;
9900 LA1 = xbm_scan (&s, end, buffer, &value);
9901
9902 /* Parse defines for width, height and hot-spots. */
9903 while (LA1 == '#')
9904 {
9905 match ();
9906 expect_ident ("define");
9907 expect (XBM_TK_IDENT);
9908
9909 if (LA1 == XBM_TK_NUMBER);
9910 {
9911 char *p = strrchr (buffer, '_');
9912 p = p ? p + 1 : buffer;
9913 if (strcmp (p, "width") == 0)
9914 *width = value;
9915 else if (strcmp (p, "height") == 0)
9916 *height = value;
9917 }
9918 expect (XBM_TK_NUMBER);
9919 }
9920
9921 if (*width < 0 || *height < 0)
9922 goto failure;
9923 else if (data == NULL)
9924 goto success;
9925
9926 /* Parse bits. Must start with `static'. */
9927 expect_ident ("static");
9928 if (LA1 == XBM_TK_IDENT)
9929 {
9930 if (strcmp (buffer, "unsigned") == 0)
9931 {
9932 match ();
9933 expect_ident ("char");
9934 }
9935 else if (strcmp (buffer, "short") == 0)
9936 {
9937 match ();
9938 v10 = 1;
9939 if (*width % 16 && *width % 16 < 9)
9940 padding_p = 1;
9941 }
9942 else if (strcmp (buffer, "char") == 0)
9943 match ();
9944 else
9945 goto failure;
9946 }
9947 else
9948 goto failure;
9949
9950 expect (XBM_TK_IDENT);
9951 expect ('[');
9952 expect (']');
9953 expect ('=');
9954 expect ('{');
9955
9956 bytes_per_line = (*width + 7) / 8 + padding_p;
9957 nbytes = bytes_per_line * *height;
9958 p = *data = (char *) xmalloc (nbytes);
9959
9960 if (v10)
9961 {
9962 for (i = 0; i < nbytes; i += 2)
9963 {
9964 int val = value;
9965 expect (XBM_TK_NUMBER);
9966
9967 *p++ = val;
9968 if (!padding_p || ((i + 2) % bytes_per_line))
9969 *p++ = value >> 8;
9970
9971 if (LA1 == ',' || LA1 == '}')
9972 match ();
9973 else
9974 goto failure;
9975 }
9976 }
9977 else
9978 {
9979 for (i = 0; i < nbytes; ++i)
9980 {
9981 int val = value;
9982 expect (XBM_TK_NUMBER);
9983
9984 *p++ = val;
9985
9986 if (LA1 == ',' || LA1 == '}')
9987 match ();
9988 else
9989 goto failure;
9990 }
9991 }
9992
9993 success:
9994 return 1;
9995
9996 failure:
9997
9998 if (data && *data)
9999 {
10000 xfree (*data);
10001 *data = NULL;
10002 }
10003 return 0;
10004
10005 #undef match
10006 #undef expect
10007 #undef expect_ident
10008 }
10009
10010
10011 /* Load XBM image IMG which will be displayed on frame F from buffer
10012 CONTENTS. END is the end of the buffer. Value is non-zero if
10013 successful. */
10014
10015 static int
10016 xbm_load_image (f, img, contents, end)
10017 struct frame *f;
10018 struct image *img;
10019 char *contents, *end;
10020 {
10021 int rc;
10022 unsigned char *data;
10023 int success_p = 0;
10024
10025 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
10026 if (rc)
10027 {
10028 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10029 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10030 Lisp_Object value;
10031
10032 xassert (img->width > 0 && img->height > 0);
10033
10034 /* Get foreground and background colors, maybe allocate colors. */
10035 value = image_spec_value (img->spec, QCforeground, NULL);
10036 if (!NILP (value))
10037 foreground = x_alloc_image_color (f, img, value, foreground);
10038 value = image_spec_value (img->spec, QCbackground, NULL);
10039 if (!NILP (value))
10040 {
10041 background = x_alloc_image_color (f, img, value, background);
10042 img->background = background;
10043 img->background_valid = 1;
10044 }
10045 img->pixmap
10046 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
10047
10048 xfree (data);
10049
10050 if (img->pixmap == 0)
10051 {
10052 x_clear_image (f, img);
10053 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
10054 }
10055 else
10056 success_p = 1;
10057 }
10058 else
10059 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10060
10061 return success_p;
10062 }
10063
10064
10065 /* Value is non-zero if DATA looks like an in-memory XBM file. */
10066
10067 static int
10068 xbm_file_p (data)
10069 Lisp_Object data;
10070 {
10071 int w, h;
10072 return (STRINGP (data)
10073 && xbm_read_bitmap_data (XSTRING (data)->data,
10074 (XSTRING (data)->data
10075 + STRING_BYTES (XSTRING (data))),
10076 &w, &h, NULL));
10077 }
10078
10079
10080 /* Fill image IMG which is used on frame F with pixmap data. Value is
10081 non-zero if successful. */
10082
10083 static int
10084 xbm_load (f, img)
10085 struct frame *f;
10086 struct image *img;
10087 {
10088 int success_p = 0;
10089 Lisp_Object file_name;
10090
10091 xassert (xbm_image_p (img->spec));
10092
10093 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10094 file_name = image_spec_value (img->spec, QCfile, NULL);
10095 if (STRINGP (file_name))
10096 {
10097 Lisp_Object file;
10098 char *contents;
10099 int size;
10100 struct gcpro gcpro1;
10101
10102 file = x_find_image_file (file_name);
10103 GCPRO1 (file);
10104 if (!STRINGP (file))
10105 {
10106 image_error ("Cannot find image file `%s'", file_name, Qnil);
10107 UNGCPRO;
10108 return 0;
10109 }
10110
10111 contents = slurp_file (XSTRING (file)->data, &size);
10112 if (contents == NULL)
10113 {
10114 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10115 UNGCPRO;
10116 return 0;
10117 }
10118
10119 success_p = xbm_load_image (f, img, contents, contents + size);
10120 UNGCPRO;
10121 }
10122 else
10123 {
10124 struct image_keyword fmt[XBM_LAST];
10125 Lisp_Object data;
10126 int depth;
10127 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10128 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10129 char *bits;
10130 int parsed_p;
10131 int in_memory_file_p = 0;
10132
10133 /* See if data looks like an in-memory XBM file. */
10134 data = image_spec_value (img->spec, QCdata, NULL);
10135 in_memory_file_p = xbm_file_p (data);
10136
10137 /* Parse the image specification. */
10138 bcopy (xbm_format, fmt, sizeof fmt);
10139 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10140 xassert (parsed_p);
10141
10142 /* Get specified width, and height. */
10143 if (!in_memory_file_p)
10144 {
10145 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10146 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10147 xassert (img->width > 0 && img->height > 0);
10148 }
10149
10150 /* Get foreground and background colors, maybe allocate colors. */
10151 if (fmt[XBM_FOREGROUND].count
10152 && STRINGP (fmt[XBM_FOREGROUND].value))
10153 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10154 foreground);
10155 if (fmt[XBM_BACKGROUND].count
10156 && STRINGP (fmt[XBM_BACKGROUND].value))
10157 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10158 background);
10159
10160 if (in_memory_file_p)
10161 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10162 (XSTRING (data)->data
10163 + STRING_BYTES (XSTRING (data))));
10164 else
10165 {
10166 if (VECTORP (data))
10167 {
10168 int i;
10169 char *p;
10170 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
10171
10172 p = bits = (char *) alloca (nbytes * img->height);
10173 for (i = 0; i < img->height; ++i, p += nbytes)
10174 {
10175 Lisp_Object line = XVECTOR (data)->contents[i];
10176 if (STRINGP (line))
10177 bcopy (XSTRING (line)->data, p, nbytes);
10178 else
10179 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10180 }
10181 }
10182 else if (STRINGP (data))
10183 bits = XSTRING (data)->data;
10184 else
10185 bits = XBOOL_VECTOR (data)->data;
10186
10187 /* Create the pixmap. */
10188 depth = one_w32_display_info.n_cbits;
10189 img->pixmap
10190 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10191 bits);
10192
10193 if (img->pixmap)
10194 success_p = 1;
10195 else
10196 {
10197 image_error ("Unable to create pixmap for XBM image `%s'",
10198 img->spec, Qnil);
10199 x_clear_image (f, img);
10200 }
10201 }
10202 }
10203
10204 return success_p;
10205 }
10206
10207
10208 \f
10209 /***********************************************************************
10210 XPM images
10211 ***********************************************************************/
10212
10213 #if HAVE_XPM
10214
10215 static int xpm_image_p P_ ((Lisp_Object object));
10216 static int xpm_load P_ ((struct frame *f, struct image *img));
10217 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10218
10219 #include "X11/xpm.h"
10220
10221 /* The symbol `xpm' identifying XPM-format images. */
10222
10223 Lisp_Object Qxpm;
10224
10225 /* Indices of image specification fields in xpm_format, below. */
10226
10227 enum xpm_keyword_index
10228 {
10229 XPM_TYPE,
10230 XPM_FILE,
10231 XPM_DATA,
10232 XPM_ASCENT,
10233 XPM_MARGIN,
10234 XPM_RELIEF,
10235 XPM_ALGORITHM,
10236 XPM_HEURISTIC_MASK,
10237 XPM_MASK,
10238 XPM_COLOR_SYMBOLS,
10239 XPM_BACKGROUND,
10240 XPM_LAST
10241 };
10242
10243 /* Vector of image_keyword structures describing the format
10244 of valid XPM image specifications. */
10245
10246 static struct image_keyword xpm_format[XPM_LAST] =
10247 {
10248 {":type", IMAGE_SYMBOL_VALUE, 1},
10249 {":file", IMAGE_STRING_VALUE, 0},
10250 {":data", IMAGE_STRING_VALUE, 0},
10251 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10252 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10253 {":relief", IMAGE_INTEGER_VALUE, 0},
10254 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10255 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10256 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10257 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10258 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10259 };
10260
10261 /* Structure describing the image type XBM. */
10262
10263 static struct image_type xpm_type =
10264 {
10265 &Qxpm,
10266 xpm_image_p,
10267 xpm_load,
10268 x_clear_image,
10269 NULL
10270 };
10271
10272
10273 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10274 for XPM images. Such a list must consist of conses whose car and
10275 cdr are strings. */
10276
10277 static int
10278 xpm_valid_color_symbols_p (color_symbols)
10279 Lisp_Object color_symbols;
10280 {
10281 while (CONSP (color_symbols))
10282 {
10283 Lisp_Object sym = XCAR (color_symbols);
10284 if (!CONSP (sym)
10285 || !STRINGP (XCAR (sym))
10286 || !STRINGP (XCDR (sym)))
10287 break;
10288 color_symbols = XCDR (color_symbols);
10289 }
10290
10291 return NILP (color_symbols);
10292 }
10293
10294
10295 /* Value is non-zero if OBJECT is a valid XPM image specification. */
10296
10297 static int
10298 xpm_image_p (object)
10299 Lisp_Object object;
10300 {
10301 struct image_keyword fmt[XPM_LAST];
10302 bcopy (xpm_format, fmt, sizeof fmt);
10303 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10304 /* Either `:file' or `:data' must be present. */
10305 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10306 /* Either no `:color-symbols' or it's a list of conses
10307 whose car and cdr are strings. */
10308 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10309 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10310 && (fmt[XPM_ASCENT].count == 0
10311 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10312 }
10313
10314
10315 /* Load image IMG which will be displayed on frame F. Value is
10316 non-zero if successful. */
10317
10318 static int
10319 xpm_load (f, img)
10320 struct frame *f;
10321 struct image *img;
10322 {
10323 int rc, i;
10324 XpmAttributes attrs;
10325 Lisp_Object specified_file, color_symbols;
10326
10327 /* Configure the XPM lib. Use the visual of frame F. Allocate
10328 close colors. Return colors allocated. */
10329 bzero (&attrs, sizeof attrs);
10330 attrs.visual = FRAME_X_VISUAL (f);
10331 attrs.colormap = FRAME_X_COLORMAP (f);
10332 attrs.valuemask |= XpmVisual;
10333 attrs.valuemask |= XpmColormap;
10334 attrs.valuemask |= XpmReturnAllocPixels;
10335 #ifdef XpmAllocCloseColors
10336 attrs.alloc_close_colors = 1;
10337 attrs.valuemask |= XpmAllocCloseColors;
10338 #else
10339 attrs.closeness = 600;
10340 attrs.valuemask |= XpmCloseness;
10341 #endif
10342
10343 /* If image specification contains symbolic color definitions, add
10344 these to `attrs'. */
10345 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10346 if (CONSP (color_symbols))
10347 {
10348 Lisp_Object tail;
10349 XpmColorSymbol *xpm_syms;
10350 int i, size;
10351
10352 attrs.valuemask |= XpmColorSymbols;
10353
10354 /* Count number of symbols. */
10355 attrs.numsymbols = 0;
10356 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10357 ++attrs.numsymbols;
10358
10359 /* Allocate an XpmColorSymbol array. */
10360 size = attrs.numsymbols * sizeof *xpm_syms;
10361 xpm_syms = (XpmColorSymbol *) alloca (size);
10362 bzero (xpm_syms, size);
10363 attrs.colorsymbols = xpm_syms;
10364
10365 /* Fill the color symbol array. */
10366 for (tail = color_symbols, i = 0;
10367 CONSP (tail);
10368 ++i, tail = XCDR (tail))
10369 {
10370 Lisp_Object name = XCAR (XCAR (tail));
10371 Lisp_Object color = XCDR (XCAR (tail));
10372 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10373 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10374 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10375 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10376 }
10377 }
10378
10379 /* Create a pixmap for the image, either from a file, or from a
10380 string buffer containing data in the same format as an XPM file. */
10381 BLOCK_INPUT;
10382 specified_file = image_spec_value (img->spec, QCfile, NULL);
10383 if (STRINGP (specified_file))
10384 {
10385 Lisp_Object file = x_find_image_file (specified_file);
10386 if (!STRINGP (file))
10387 {
10388 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10389 UNBLOCK_INPUT;
10390 return 0;
10391 }
10392
10393 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10394 XSTRING (file)->data, &img->pixmap, &img->mask,
10395 &attrs);
10396 }
10397 else
10398 {
10399 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10400 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10401 XSTRING (buffer)->data,
10402 &img->pixmap, &img->mask,
10403 &attrs);
10404 }
10405 UNBLOCK_INPUT;
10406
10407 if (rc == XpmSuccess)
10408 {
10409 /* Remember allocated colors. */
10410 img->ncolors = attrs.nalloc_pixels;
10411 img->colors = (unsigned long *) xmalloc (img->ncolors
10412 * sizeof *img->colors);
10413 for (i = 0; i < attrs.nalloc_pixels; ++i)
10414 img->colors[i] = attrs.alloc_pixels[i];
10415
10416 img->width = attrs.width;
10417 img->height = attrs.height;
10418 xassert (img->width > 0 && img->height > 0);
10419
10420 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10421 BLOCK_INPUT;
10422 XpmFreeAttributes (&attrs);
10423 UNBLOCK_INPUT;
10424 }
10425 else
10426 {
10427 switch (rc)
10428 {
10429 case XpmOpenFailed:
10430 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10431 break;
10432
10433 case XpmFileInvalid:
10434 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10435 break;
10436
10437 case XpmNoMemory:
10438 image_error ("Out of memory (%s)", img->spec, Qnil);
10439 break;
10440
10441 case XpmColorFailed:
10442 image_error ("Color allocation error (%s)", img->spec, Qnil);
10443 break;
10444
10445 default:
10446 image_error ("Unknown error (%s)", img->spec, Qnil);
10447 break;
10448 }
10449 }
10450
10451 return rc == XpmSuccess;
10452 }
10453
10454 #endif /* HAVE_XPM != 0 */
10455
10456 \f
10457 #if 0 /* TODO : Color tables on W32. */
10458 /***********************************************************************
10459 Color table
10460 ***********************************************************************/
10461
10462 /* An entry in the color table mapping an RGB color to a pixel color. */
10463
10464 struct ct_color
10465 {
10466 int r, g, b;
10467 unsigned long pixel;
10468
10469 /* Next in color table collision list. */
10470 struct ct_color *next;
10471 };
10472
10473 /* The bucket vector size to use. Must be prime. */
10474
10475 #define CT_SIZE 101
10476
10477 /* Value is a hash of the RGB color given by R, G, and B. */
10478
10479 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10480
10481 /* The color hash table. */
10482
10483 struct ct_color **ct_table;
10484
10485 /* Number of entries in the color table. */
10486
10487 int ct_colors_allocated;
10488
10489 /* Function prototypes. */
10490
10491 static void init_color_table P_ ((void));
10492 static void free_color_table P_ ((void));
10493 static unsigned long *colors_in_color_table P_ ((int *n));
10494 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10495 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10496
10497
10498 /* Initialize the color table. */
10499
10500 static void
10501 init_color_table ()
10502 {
10503 int size = CT_SIZE * sizeof (*ct_table);
10504 ct_table = (struct ct_color **) xmalloc (size);
10505 bzero (ct_table, size);
10506 ct_colors_allocated = 0;
10507 }
10508
10509
10510 /* Free memory associated with the color table. */
10511
10512 static void
10513 free_color_table ()
10514 {
10515 int i;
10516 struct ct_color *p, *next;
10517
10518 for (i = 0; i < CT_SIZE; ++i)
10519 for (p = ct_table[i]; p; p = next)
10520 {
10521 next = p->next;
10522 xfree (p);
10523 }
10524
10525 xfree (ct_table);
10526 ct_table = NULL;
10527 }
10528
10529
10530 /* Value is a pixel color for RGB color R, G, B on frame F. If an
10531 entry for that color already is in the color table, return the
10532 pixel color of that entry. Otherwise, allocate a new color for R,
10533 G, B, and make an entry in the color table. */
10534
10535 static unsigned long
10536 lookup_rgb_color (f, r, g, b)
10537 struct frame *f;
10538 int r, g, b;
10539 {
10540 unsigned hash = CT_HASH_RGB (r, g, b);
10541 int i = hash % CT_SIZE;
10542 struct ct_color *p;
10543
10544 for (p = ct_table[i]; p; p = p->next)
10545 if (p->r == r && p->g == g && p->b == b)
10546 break;
10547
10548 if (p == NULL)
10549 {
10550 COLORREF color;
10551 Colormap cmap;
10552 int rc;
10553
10554 color = PALETTERGB (r, g, b);
10555
10556 ++ct_colors_allocated;
10557
10558 p = (struct ct_color *) xmalloc (sizeof *p);
10559 p->r = r;
10560 p->g = g;
10561 p->b = b;
10562 p->pixel = color;
10563 p->next = ct_table[i];
10564 ct_table[i] = p;
10565 }
10566
10567 return p->pixel;
10568 }
10569
10570
10571 /* Look up pixel color PIXEL which is used on frame F in the color
10572 table. If not already present, allocate it. Value is PIXEL. */
10573
10574 static unsigned long
10575 lookup_pixel_color (f, pixel)
10576 struct frame *f;
10577 unsigned long pixel;
10578 {
10579 int i = pixel % CT_SIZE;
10580 struct ct_color *p;
10581
10582 for (p = ct_table[i]; p; p = p->next)
10583 if (p->pixel == pixel)
10584 break;
10585
10586 if (p == NULL)
10587 {
10588 XColor color;
10589 Colormap cmap;
10590 int rc;
10591
10592 BLOCK_INPUT;
10593
10594 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10595 color.pixel = pixel;
10596 XQueryColor (NULL, cmap, &color);
10597 rc = x_alloc_nearest_color (f, cmap, &color);
10598 UNBLOCK_INPUT;
10599
10600 if (rc)
10601 {
10602 ++ct_colors_allocated;
10603
10604 p = (struct ct_color *) xmalloc (sizeof *p);
10605 p->r = color.red;
10606 p->g = color.green;
10607 p->b = color.blue;
10608 p->pixel = pixel;
10609 p->next = ct_table[i];
10610 ct_table[i] = p;
10611 }
10612 else
10613 return FRAME_FOREGROUND_PIXEL (f);
10614 }
10615 return p->pixel;
10616 }
10617
10618
10619 /* Value is a vector of all pixel colors contained in the color table,
10620 allocated via xmalloc. Set *N to the number of colors. */
10621
10622 static unsigned long *
10623 colors_in_color_table (n)
10624 int *n;
10625 {
10626 int i, j;
10627 struct ct_color *p;
10628 unsigned long *colors;
10629
10630 if (ct_colors_allocated == 0)
10631 {
10632 *n = 0;
10633 colors = NULL;
10634 }
10635 else
10636 {
10637 colors = (unsigned long *) xmalloc (ct_colors_allocated
10638 * sizeof *colors);
10639 *n = ct_colors_allocated;
10640
10641 for (i = j = 0; i < CT_SIZE; ++i)
10642 for (p = ct_table[i]; p; p = p->next)
10643 colors[j++] = p->pixel;
10644 }
10645
10646 return colors;
10647 }
10648
10649 #endif /* TODO */
10650
10651 \f
10652 /***********************************************************************
10653 Algorithms
10654 ***********************************************************************/
10655 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10656 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10657 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10658 static void XPutPixel (XImage *, int, int, COLORREF);
10659
10660 /* Non-zero means draw a cross on images having `:conversion
10661 disabled'. */
10662
10663 int cross_disabled_images;
10664
10665 /* Edge detection matrices for different edge-detection
10666 strategies. */
10667
10668 static int emboss_matrix[9] = {
10669 /* x - 1 x x + 1 */
10670 2, -1, 0, /* y - 1 */
10671 -1, 0, 1, /* y */
10672 0, 1, -2 /* y + 1 */
10673 };
10674
10675 static int laplace_matrix[9] = {
10676 /* x - 1 x x + 1 */
10677 1, 0, 0, /* y - 1 */
10678 0, 0, 0, /* y */
10679 0, 0, -1 /* y + 1 */
10680 };
10681
10682 /* Value is the intensity of the color whose red/green/blue values
10683 are R, G, and B. */
10684
10685 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10686
10687
10688 /* On frame F, return an array of XColor structures describing image
10689 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10690 non-zero means also fill the red/green/blue members of the XColor
10691 structures. Value is a pointer to the array of XColors structures,
10692 allocated with xmalloc; it must be freed by the caller. */
10693
10694 static XColor *
10695 x_to_xcolors (f, img, rgb_p)
10696 struct frame *f;
10697 struct image *img;
10698 int rgb_p;
10699 {
10700 int x, y;
10701 XColor *colors, *p;
10702 XImage *ximg;
10703
10704 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10705 #if 0 /* TODO: implement image colors. */
10706 /* Get the X image IMG->pixmap. */
10707 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10708 0, 0, img->width, img->height, ~0, ZPixmap);
10709
10710 /* Fill the `pixel' members of the XColor array. I wished there
10711 were an easy and portable way to circumvent XGetPixel. */
10712 p = colors;
10713 for (y = 0; y < img->height; ++y)
10714 {
10715 XColor *row = p;
10716
10717 for (x = 0; x < img->width; ++x, ++p)
10718 p->pixel = XGetPixel (ximg, x, y);
10719
10720 if (rgb_p)
10721 x_query_colors (f, row, img->width);
10722 }
10723
10724 XDestroyImage (ximg);
10725 #endif
10726 return colors;
10727 }
10728
10729 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10730 created with CreateDIBSection, with the pointer to the bit values
10731 stored in ximg->data. */
10732
10733 static void XPutPixel (ximg, x, y, color)
10734 XImage * ximg;
10735 int x, y;
10736 COLORREF color;
10737 {
10738 int width = ximg->info.bmiHeader.biWidth;
10739 int height = ximg->info.bmiHeader.biHeight;
10740 int rowbytes = width * 3;
10741 unsigned char * pixel;
10742
10743 /* Don't support putting pixels in images with palettes. */
10744 xassert (ximg->info.bmiHeader.biBitCount == 24);
10745
10746 /* Ensure scanlines are aligned on 4 byte boundaries. */
10747 if (rowbytes % 4)
10748 rowbytes += 4 - (rowbytes % 4);
10749
10750 pixel = ximg->data + y * rowbytes + x * 3;
10751 *pixel = 255 - GetRValue (color);
10752 *(pixel + 1) = 255 - GetGValue (color);
10753 *(pixel + 2) = 255 - GetBValue (color);
10754 }
10755
10756
10757 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
10758 RGB members are set. F is the frame on which this all happens.
10759 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
10760
10761 static void
10762 x_from_xcolors (f, img, colors)
10763 struct frame *f;
10764 struct image *img;
10765 XColor *colors;
10766 {
10767 int x, y;
10768 XImage *oimg;
10769 Pixmap pixmap;
10770 XColor *p;
10771 #if 0 /* TODO: color tables. */
10772 init_color_table ();
10773 #endif
10774 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10775 &oimg, &pixmap);
10776 p = colors;
10777 for (y = 0; y < img->height; ++y)
10778 for (x = 0; x < img->width; ++x, ++p)
10779 {
10780 unsigned long pixel;
10781 #if 0 /* TODO: color tables. */
10782 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10783 #else
10784 pixel = PALETTERGB (p->red, p->green, p->blue);
10785 #endif
10786 XPutPixel (oimg, x, y, pixel);
10787 }
10788
10789 xfree (colors);
10790 x_clear_image_1 (f, img, 1, 0, 1);
10791
10792 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10793 x_destroy_x_image (oimg);
10794 img->pixmap = pixmap;
10795 #if 0 /* TODO: color tables. */
10796 img->colors = colors_in_color_table (&img->ncolors);
10797 free_color_table ();
10798 #endif
10799 }
10800
10801
10802 /* On frame F, perform edge-detection on image IMG.
10803
10804 MATRIX is a nine-element array specifying the transformation
10805 matrix. See emboss_matrix for an example.
10806
10807 COLOR_ADJUST is a color adjustment added to each pixel of the
10808 outgoing image. */
10809
10810 static void
10811 x_detect_edges (f, img, matrix, color_adjust)
10812 struct frame *f;
10813 struct image *img;
10814 int matrix[9], color_adjust;
10815 {
10816 XColor *colors = x_to_xcolors (f, img, 1);
10817 XColor *new, *p;
10818 int x, y, i, sum;
10819
10820 for (i = sum = 0; i < 9; ++i)
10821 sum += abs (matrix[i]);
10822
10823 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10824
10825 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10826
10827 for (y = 0; y < img->height; ++y)
10828 {
10829 p = COLOR (new, 0, y);
10830 p->red = p->green = p->blue = 0xffff/2;
10831 p = COLOR (new, img->width - 1, y);
10832 p->red = p->green = p->blue = 0xffff/2;
10833 }
10834
10835 for (x = 1; x < img->width - 1; ++x)
10836 {
10837 p = COLOR (new, x, 0);
10838 p->red = p->green = p->blue = 0xffff/2;
10839 p = COLOR (new, x, img->height - 1);
10840 p->red = p->green = p->blue = 0xffff/2;
10841 }
10842
10843 for (y = 1; y < img->height - 1; ++y)
10844 {
10845 p = COLOR (new, 1, y);
10846
10847 for (x = 1; x < img->width - 1; ++x, ++p)
10848 {
10849 int r, g, b, y1, x1;
10850
10851 r = g = b = i = 0;
10852 for (y1 = y - 1; y1 < y + 2; ++y1)
10853 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10854 if (matrix[i])
10855 {
10856 XColor *t = COLOR (colors, x1, y1);
10857 r += matrix[i] * t->red;
10858 g += matrix[i] * t->green;
10859 b += matrix[i] * t->blue;
10860 }
10861
10862 r = (r / sum + color_adjust) & 0xffff;
10863 g = (g / sum + color_adjust) & 0xffff;
10864 b = (b / sum + color_adjust) & 0xffff;
10865 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10866 }
10867 }
10868
10869 xfree (colors);
10870 x_from_xcolors (f, img, new);
10871
10872 #undef COLOR
10873 }
10874
10875
10876 /* Perform the pre-defined `emboss' edge-detection on image IMG
10877 on frame F. */
10878
10879 static void
10880 x_emboss (f, img)
10881 struct frame *f;
10882 struct image *img;
10883 {
10884 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10885 }
10886
10887
10888 /* Transform image IMG which is used on frame F with a Laplace
10889 edge-detection algorithm. The result is an image that can be used
10890 to draw disabled buttons, for example. */
10891
10892 static void
10893 x_laplace (f, img)
10894 struct frame *f;
10895 struct image *img;
10896 {
10897 x_detect_edges (f, img, laplace_matrix, 45000);
10898 }
10899
10900
10901 /* Perform edge-detection on image IMG on frame F, with specified
10902 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10903
10904 MATRIX must be either
10905
10906 - a list of at least 9 numbers in row-major form
10907 - a vector of at least 9 numbers
10908
10909 COLOR_ADJUST nil means use a default; otherwise it must be a
10910 number. */
10911
10912 static void
10913 x_edge_detection (f, img, matrix, color_adjust)
10914 struct frame *f;
10915 struct image *img;
10916 Lisp_Object matrix, color_adjust;
10917 {
10918 int i = 0;
10919 int trans[9];
10920
10921 if (CONSP (matrix))
10922 {
10923 for (i = 0;
10924 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10925 ++i, matrix = XCDR (matrix))
10926 trans[i] = XFLOATINT (XCAR (matrix));
10927 }
10928 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10929 {
10930 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10931 trans[i] = XFLOATINT (AREF (matrix, i));
10932 }
10933
10934 if (NILP (color_adjust))
10935 color_adjust = make_number (0xffff / 2);
10936
10937 if (i == 9 && NUMBERP (color_adjust))
10938 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10939 }
10940
10941
10942 /* Transform image IMG on frame F so that it looks disabled. */
10943
10944 static void
10945 x_disable_image (f, img)
10946 struct frame *f;
10947 struct image *img;
10948 {
10949 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10950
10951 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
10952 {
10953 /* Color (or grayscale). Convert to gray, and equalize. Just
10954 drawing such images with a stipple can look very odd, so
10955 we're using this method instead. */
10956 XColor *colors = x_to_xcolors (f, img, 1);
10957 XColor *p, *end;
10958 const int h = 15000;
10959 const int l = 30000;
10960
10961 for (p = colors, end = colors + img->width * img->height;
10962 p < end;
10963 ++p)
10964 {
10965 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10966 int i2 = (0xffff - h - l) * i / 0xffff + l;
10967 p->red = p->green = p->blue = i2;
10968 }
10969
10970 x_from_xcolors (f, img, colors);
10971 }
10972
10973 /* Draw a cross over the disabled image, if we must or if we
10974 should. */
10975 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
10976 {
10977 #if 0 /* TODO: full image support */
10978 Display *dpy = FRAME_X_DISPLAY (f);
10979 GC gc;
10980
10981 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10982 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10983 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10984 img->width - 1, img->height - 1);
10985 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10986 img->width - 1, 0);
10987 XFreeGC (dpy, gc);
10988
10989 if (img->mask)
10990 {
10991 gc = XCreateGC (dpy, img->mask, 0, NULL);
10992 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10993 XDrawLine (dpy, img->mask, gc, 0, 0,
10994 img->width - 1, img->height - 1);
10995 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10996 img->width - 1, 0);
10997 XFreeGC (dpy, gc);
10998 }
10999 #endif
11000 }
11001 }
11002
11003
11004 /* Build a mask for image IMG which is used on frame F. FILE is the
11005 name of an image file, for error messages. HOW determines how to
11006 determine the background color of IMG. If it is a list '(R G B)',
11007 with R, G, and B being integers >= 0, take that as the color of the
11008 background. Otherwise, determine the background color of IMG
11009 heuristically. Value is non-zero if successful. */
11010
11011 static int
11012 x_build_heuristic_mask (f, img, how)
11013 struct frame *f;
11014 struct image *img;
11015 Lisp_Object how;
11016 {
11017 #if 0 /* TODO: full image support. */
11018 Display *dpy = FRAME_W32_DISPLAY (f);
11019 XImage *ximg, *mask_img;
11020 int x, y, rc, use_img_background;
11021 unsigned long bg = 0;
11022
11023 if (img->mask)
11024 {
11025 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
11026 img->mask = None;
11027 img->background_transparent_valid = 0;
11028 }
11029
11030 /* Create an image and pixmap serving as mask. */
11031 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
11032 &mask_img, &img->mask);
11033 if (!rc)
11034 return 0;
11035
11036 /* Get the X image of IMG->pixmap. */
11037 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
11038 ~0, ZPixmap);
11039
11040 /* Determine the background color of ximg. If HOW is `(R G B)'
11041 take that as color. Otherwise, use the image's background color. */
11042 use_img_background = 1;
11043
11044 if (CONSP (how))
11045 {
11046 int rgb[3], i;
11047
11048 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
11049 {
11050 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11051 how = XCDR (how);
11052 }
11053
11054 if (i == 3 && NILP (how))
11055 {
11056 char color_name[30];
11057 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
11058 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
11059 use_img_background = 0;
11060 }
11061 }
11062
11063 if (use_img_background)
11064 bg = four_corners_best (ximg, img->width, img->height);
11065
11066 /* Set all bits in mask_img to 1 whose color in ximg is different
11067 from the background color bg. */
11068 for (y = 0; y < img->height; ++y)
11069 for (x = 0; x < img->width; ++x)
11070 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11071
11072 /* Fill in the background_transparent field while we have the mask handy. */
11073 image_background_transparent (img, f, mask_img);
11074
11075 /* Put mask_img into img->mask. */
11076 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11077 x_destroy_x_image (mask_img);
11078 XDestroyImage (ximg);
11079
11080 return 1;
11081 #else
11082 return 0;
11083 #endif
11084 }
11085
11086 \f
11087 /***********************************************************************
11088 PBM (mono, gray, color)
11089 ***********************************************************************/
11090
11091 static int pbm_image_p P_ ((Lisp_Object object));
11092 static int pbm_load P_ ((struct frame *f, struct image *img));
11093 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11094
11095 /* The symbol `pbm' identifying images of this type. */
11096
11097 Lisp_Object Qpbm;
11098
11099 /* Indices of image specification fields in gs_format, below. */
11100
11101 enum pbm_keyword_index
11102 {
11103 PBM_TYPE,
11104 PBM_FILE,
11105 PBM_DATA,
11106 PBM_ASCENT,
11107 PBM_MARGIN,
11108 PBM_RELIEF,
11109 PBM_ALGORITHM,
11110 PBM_HEURISTIC_MASK,
11111 PBM_MASK,
11112 PBM_FOREGROUND,
11113 PBM_BACKGROUND,
11114 PBM_LAST
11115 };
11116
11117 /* Vector of image_keyword structures describing the format
11118 of valid user-defined image specifications. */
11119
11120 static struct image_keyword pbm_format[PBM_LAST] =
11121 {
11122 {":type", IMAGE_SYMBOL_VALUE, 1},
11123 {":file", IMAGE_STRING_VALUE, 0},
11124 {":data", IMAGE_STRING_VALUE, 0},
11125 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11126 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11127 {":relief", IMAGE_INTEGER_VALUE, 0},
11128 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11129 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11130 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11131 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11132 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11133 };
11134
11135 /* Structure describing the image type `pbm'. */
11136
11137 static struct image_type pbm_type =
11138 {
11139 &Qpbm,
11140 pbm_image_p,
11141 pbm_load,
11142 x_clear_image,
11143 NULL
11144 };
11145
11146
11147 /* Return non-zero if OBJECT is a valid PBM image specification. */
11148
11149 static int
11150 pbm_image_p (object)
11151 Lisp_Object object;
11152 {
11153 struct image_keyword fmt[PBM_LAST];
11154
11155 bcopy (pbm_format, fmt, sizeof fmt);
11156
11157 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11158 || (fmt[PBM_ASCENT].count
11159 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11160 return 0;
11161
11162 /* Must specify either :data or :file. */
11163 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11164 }
11165
11166
11167 /* Scan a decimal number from *S and return it. Advance *S while
11168 reading the number. END is the end of the string. Value is -1 at
11169 end of input. */
11170
11171 static int
11172 pbm_scan_number (s, end)
11173 unsigned char **s, *end;
11174 {
11175 int c, val = -1;
11176
11177 while (*s < end)
11178 {
11179 /* Skip white-space. */
11180 while (*s < end && (c = *(*s)++, isspace (c)))
11181 ;
11182
11183 if (c == '#')
11184 {
11185 /* Skip comment to end of line. */
11186 while (*s < end && (c = *(*s)++, c != '\n'))
11187 ;
11188 }
11189 else if (isdigit (c))
11190 {
11191 /* Read decimal number. */
11192 val = c - '0';
11193 while (*s < end && (c = *(*s)++, isdigit (c)))
11194 val = 10 * val + c - '0';
11195 break;
11196 }
11197 else
11198 break;
11199 }
11200
11201 return val;
11202 }
11203
11204
11205 /* Read FILE into memory. Value is a pointer to a buffer allocated
11206 with xmalloc holding FILE's contents. Value is null if an error
11207 occured. *SIZE is set to the size of the file. */
11208
11209 static char *
11210 pbm_read_file (file, size)
11211 Lisp_Object file;
11212 int *size;
11213 {
11214 FILE *fp = NULL;
11215 char *buf = NULL;
11216 struct stat st;
11217
11218 if (stat (XSTRING (file)->data, &st) == 0
11219 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11220 && (buf = (char *) xmalloc (st.st_size),
11221 fread (buf, 1, st.st_size, fp) == st.st_size))
11222 {
11223 *size = st.st_size;
11224 fclose (fp);
11225 }
11226 else
11227 {
11228 if (fp)
11229 fclose (fp);
11230 if (buf)
11231 {
11232 xfree (buf);
11233 buf = NULL;
11234 }
11235 }
11236
11237 return buf;
11238 }
11239
11240
11241 /* Load PBM image IMG for use on frame F. */
11242
11243 static int
11244 pbm_load (f, img)
11245 struct frame *f;
11246 struct image *img;
11247 {
11248 int raw_p, x, y;
11249 int width, height, max_color_idx = 0;
11250 XImage *ximg;
11251 Lisp_Object file, specified_file;
11252 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11253 struct gcpro gcpro1;
11254 unsigned char *contents = NULL;
11255 unsigned char *end, *p;
11256 int size;
11257
11258 specified_file = image_spec_value (img->spec, QCfile, NULL);
11259 file = Qnil;
11260 GCPRO1 (file);
11261
11262 if (STRINGP (specified_file))
11263 {
11264 file = x_find_image_file (specified_file);
11265 if (!STRINGP (file))
11266 {
11267 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11268 UNGCPRO;
11269 return 0;
11270 }
11271
11272 contents = slurp_file (XSTRING (file)->data, &size);
11273 if (contents == NULL)
11274 {
11275 image_error ("Error reading `%s'", file, Qnil);
11276 UNGCPRO;
11277 return 0;
11278 }
11279
11280 p = contents;
11281 end = contents + size;
11282 }
11283 else
11284 {
11285 Lisp_Object data;
11286 data = image_spec_value (img->spec, QCdata, NULL);
11287 p = XSTRING (data)->data;
11288 end = p + STRING_BYTES (XSTRING (data));
11289 }
11290
11291 /* Check magic number. */
11292 if (end - p < 2 || *p++ != 'P')
11293 {
11294 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11295 error:
11296 xfree (contents);
11297 UNGCPRO;
11298 return 0;
11299 }
11300
11301 switch (*p++)
11302 {
11303 case '1':
11304 raw_p = 0, type = PBM_MONO;
11305 break;
11306
11307 case '2':
11308 raw_p = 0, type = PBM_GRAY;
11309 break;
11310
11311 case '3':
11312 raw_p = 0, type = PBM_COLOR;
11313 break;
11314
11315 case '4':
11316 raw_p = 1, type = PBM_MONO;
11317 break;
11318
11319 case '5':
11320 raw_p = 1, type = PBM_GRAY;
11321 break;
11322
11323 case '6':
11324 raw_p = 1, type = PBM_COLOR;
11325 break;
11326
11327 default:
11328 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11329 goto error;
11330 }
11331
11332 /* Read width, height, maximum color-component. Characters
11333 starting with `#' up to the end of a line are ignored. */
11334 width = pbm_scan_number (&p, end);
11335 height = pbm_scan_number (&p, end);
11336
11337 if (type != PBM_MONO)
11338 {
11339 max_color_idx = pbm_scan_number (&p, end);
11340 if (raw_p && max_color_idx > 255)
11341 max_color_idx = 255;
11342 }
11343
11344 if (width < 0
11345 || height < 0
11346 || (type != PBM_MONO && max_color_idx < 0))
11347 goto error;
11348
11349 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11350 goto error;
11351
11352 #if 0 /* TODO: color tables. */
11353 /* Initialize the color hash table. */
11354 init_color_table ();
11355 #endif
11356
11357 if (type == PBM_MONO)
11358 {
11359 int c = 0, g;
11360 struct image_keyword fmt[PBM_LAST];
11361 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11362 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11363
11364 /* Parse the image specification. */
11365 bcopy (pbm_format, fmt, sizeof fmt);
11366 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11367
11368 /* Get foreground and background colors, maybe allocate colors. */
11369 if (fmt[PBM_FOREGROUND].count
11370 && STRINGP (fmt[PBM_FOREGROUND].value))
11371 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11372 if (fmt[PBM_BACKGROUND].count
11373 && STRINGP (fmt[PBM_BACKGROUND].value))
11374 {
11375 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11376 img->background = bg;
11377 img->background_valid = 1;
11378 }
11379
11380 for (y = 0; y < height; ++y)
11381 for (x = 0; x < width; ++x)
11382 {
11383 if (raw_p)
11384 {
11385 if ((x & 7) == 0)
11386 c = *p++;
11387 g = c & 0x80;
11388 c <<= 1;
11389 }
11390 else
11391 g = pbm_scan_number (&p, end);
11392
11393 XPutPixel (ximg, x, y, g ? fg : bg);
11394 }
11395 }
11396 else
11397 {
11398 for (y = 0; y < height; ++y)
11399 for (x = 0; x < width; ++x)
11400 {
11401 int r, g, b;
11402
11403 if (type == PBM_GRAY)
11404 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11405 else if (raw_p)
11406 {
11407 r = *p++;
11408 g = *p++;
11409 b = *p++;
11410 }
11411 else
11412 {
11413 r = pbm_scan_number (&p, end);
11414 g = pbm_scan_number (&p, end);
11415 b = pbm_scan_number (&p, end);
11416 }
11417
11418 if (r < 0 || g < 0 || b < 0)
11419 {
11420 x_destroy_x_image (ximg);
11421 image_error ("Invalid pixel value in image `%s'",
11422 img->spec, Qnil);
11423 goto error;
11424 }
11425
11426 /* RGB values are now in the range 0..max_color_idx.
11427 Scale this to the range 0..0xff supported by W32. */
11428 r = (int) ((double) r * 255 / max_color_idx);
11429 g = (int) ((double) g * 255 / max_color_idx);
11430 b = (int) ((double) b * 255 / max_color_idx);
11431 XPutPixel (ximg, x, y,
11432 #if 0 /* TODO: color tables. */
11433 lookup_rgb_color (f, r, g, b));
11434 #else
11435 PALETTERGB (r, g, b));
11436 #endif
11437 }
11438 }
11439
11440 #if 0 /* TODO: color tables. */
11441 /* Store in IMG->colors the colors allocated for the image, and
11442 free the color table. */
11443 img->colors = colors_in_color_table (&img->ncolors);
11444 free_color_table ();
11445 #endif
11446 /* Maybe fill in the background field while we have ximg handy. */
11447 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11448 IMAGE_BACKGROUND (img, f, ximg);
11449
11450 /* Put the image into a pixmap. */
11451 x_put_x_image (f, ximg, img->pixmap, width, height);
11452 x_destroy_x_image (ximg);
11453
11454 img->width = width;
11455 img->height = height;
11456
11457 UNGCPRO;
11458 xfree (contents);
11459 return 1;
11460 }
11461
11462 \f
11463 /***********************************************************************
11464 PNG
11465 ***********************************************************************/
11466
11467 #if HAVE_PNG
11468
11469 #include <png.h>
11470
11471 /* Function prototypes. */
11472
11473 static int png_image_p P_ ((Lisp_Object object));
11474 static int png_load P_ ((struct frame *f, struct image *img));
11475
11476 /* The symbol `png' identifying images of this type. */
11477
11478 Lisp_Object Qpng;
11479
11480 /* Indices of image specification fields in png_format, below. */
11481
11482 enum png_keyword_index
11483 {
11484 PNG_TYPE,
11485 PNG_DATA,
11486 PNG_FILE,
11487 PNG_ASCENT,
11488 PNG_MARGIN,
11489 PNG_RELIEF,
11490 PNG_ALGORITHM,
11491 PNG_HEURISTIC_MASK,
11492 PNG_MASK,
11493 PNG_BACKGROUND,
11494 PNG_LAST
11495 };
11496
11497 /* Vector of image_keyword structures describing the format
11498 of valid user-defined image specifications. */
11499
11500 static struct image_keyword png_format[PNG_LAST] =
11501 {
11502 {":type", IMAGE_SYMBOL_VALUE, 1},
11503 {":data", IMAGE_STRING_VALUE, 0},
11504 {":file", IMAGE_STRING_VALUE, 0},
11505 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11506 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11507 {":relief", IMAGE_INTEGER_VALUE, 0},
11508 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11509 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11510 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11511 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11512 };
11513
11514 /* Structure describing the image type `png'. */
11515
11516 static struct image_type png_type =
11517 {
11518 &Qpng,
11519 png_image_p,
11520 png_load,
11521 x_clear_image,
11522 NULL
11523 };
11524
11525
11526 /* Return non-zero if OBJECT is a valid PNG image specification. */
11527
11528 static int
11529 png_image_p (object)
11530 Lisp_Object object;
11531 {
11532 struct image_keyword fmt[PNG_LAST];
11533 bcopy (png_format, fmt, sizeof fmt);
11534
11535 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11536 || (fmt[PNG_ASCENT].count
11537 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11538 return 0;
11539
11540 /* Must specify either the :data or :file keyword. */
11541 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11542 }
11543
11544
11545 /* Error and warning handlers installed when the PNG library
11546 is initialized. */
11547
11548 static void
11549 my_png_error (png_ptr, msg)
11550 png_struct *png_ptr;
11551 char *msg;
11552 {
11553 xassert (png_ptr != NULL);
11554 image_error ("PNG error: %s", build_string (msg), Qnil);
11555 longjmp (png_ptr->jmpbuf, 1);
11556 }
11557
11558
11559 static void
11560 my_png_warning (png_ptr, msg)
11561 png_struct *png_ptr;
11562 char *msg;
11563 {
11564 xassert (png_ptr != NULL);
11565 image_error ("PNG warning: %s", build_string (msg), Qnil);
11566 }
11567
11568 /* Memory source for PNG decoding. */
11569
11570 struct png_memory_storage
11571 {
11572 unsigned char *bytes; /* The data */
11573 size_t len; /* How big is it? */
11574 int index; /* Where are we? */
11575 };
11576
11577
11578 /* Function set as reader function when reading PNG image from memory.
11579 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11580 bytes from the input to DATA. */
11581
11582 static void
11583 png_read_from_memory (png_ptr, data, length)
11584 png_structp png_ptr;
11585 png_bytep data;
11586 png_size_t length;
11587 {
11588 struct png_memory_storage *tbr
11589 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11590
11591 if (length > tbr->len - tbr->index)
11592 png_error (png_ptr, "Read error");
11593
11594 bcopy (tbr->bytes + tbr->index, data, length);
11595 tbr->index = tbr->index + length;
11596 }
11597
11598 /* Load PNG image IMG for use on frame F. Value is non-zero if
11599 successful. */
11600
11601 static int
11602 png_load (f, img)
11603 struct frame *f;
11604 struct image *img;
11605 {
11606 Lisp_Object file, specified_file;
11607 Lisp_Object specified_data;
11608 int x, y, i;
11609 XImage *ximg, *mask_img = NULL;
11610 struct gcpro gcpro1;
11611 png_struct *png_ptr = NULL;
11612 png_info *info_ptr = NULL, *end_info = NULL;
11613 FILE *volatile fp = NULL;
11614 png_byte sig[8];
11615 png_byte *volatile pixels = NULL;
11616 png_byte **volatile rows = NULL;
11617 png_uint_32 width, height;
11618 int bit_depth, color_type, interlace_type;
11619 png_byte channels;
11620 png_uint_32 row_bytes;
11621 int transparent_p;
11622 char *gamma_str;
11623 double screen_gamma, image_gamma;
11624 int intent;
11625 struct png_memory_storage tbr; /* Data to be read */
11626
11627 /* Find out what file to load. */
11628 specified_file = image_spec_value (img->spec, QCfile, NULL);
11629 specified_data = image_spec_value (img->spec, QCdata, NULL);
11630 file = Qnil;
11631 GCPRO1 (file);
11632
11633 if (NILP (specified_data))
11634 {
11635 file = x_find_image_file (specified_file);
11636 if (!STRINGP (file))
11637 {
11638 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11639 UNGCPRO;
11640 return 0;
11641 }
11642
11643 /* Open the image file. */
11644 fp = fopen (XSTRING (file)->data, "rb");
11645 if (!fp)
11646 {
11647 image_error ("Cannot open image file `%s'", file, Qnil);
11648 UNGCPRO;
11649 fclose (fp);
11650 return 0;
11651 }
11652
11653 /* Check PNG signature. */
11654 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11655 || !png_check_sig (sig, sizeof sig))
11656 {
11657 image_error ("Not a PNG file:` %s'", file, Qnil);
11658 UNGCPRO;
11659 fclose (fp);
11660 return 0;
11661 }
11662 }
11663 else
11664 {
11665 /* Read from memory. */
11666 tbr.bytes = XSTRING (specified_data)->data;
11667 tbr.len = STRING_BYTES (XSTRING (specified_data));
11668 tbr.index = 0;
11669
11670 /* Check PNG signature. */
11671 if (tbr.len < sizeof sig
11672 || !png_check_sig (tbr.bytes, sizeof sig))
11673 {
11674 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11675 UNGCPRO;
11676 return 0;
11677 }
11678
11679 /* Need to skip past the signature. */
11680 tbr.bytes += sizeof (sig);
11681 }
11682
11683 /* Initialize read and info structs for PNG lib. */
11684 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11685 my_png_error, my_png_warning);
11686 if (!png_ptr)
11687 {
11688 if (fp) fclose (fp);
11689 UNGCPRO;
11690 return 0;
11691 }
11692
11693 info_ptr = png_create_info_struct (png_ptr);
11694 if (!info_ptr)
11695 {
11696 png_destroy_read_struct (&png_ptr, NULL, NULL);
11697 if (fp) fclose (fp);
11698 UNGCPRO;
11699 return 0;
11700 }
11701
11702 end_info = png_create_info_struct (png_ptr);
11703 if (!end_info)
11704 {
11705 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11706 if (fp) fclose (fp);
11707 UNGCPRO;
11708 return 0;
11709 }
11710
11711 /* Set error jump-back. We come back here when the PNG library
11712 detects an error. */
11713 if (setjmp (png_ptr->jmpbuf))
11714 {
11715 error:
11716 if (png_ptr)
11717 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11718 xfree (pixels);
11719 xfree (rows);
11720 if (fp) fclose (fp);
11721 UNGCPRO;
11722 return 0;
11723 }
11724
11725 /* Read image info. */
11726 if (!NILP (specified_data))
11727 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11728 else
11729 png_init_io (png_ptr, fp);
11730
11731 png_set_sig_bytes (png_ptr, sizeof sig);
11732 png_read_info (png_ptr, info_ptr);
11733 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11734 &interlace_type, NULL, NULL);
11735
11736 /* If image contains simply transparency data, we prefer to
11737 construct a clipping mask. */
11738 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11739 transparent_p = 1;
11740 else
11741 transparent_p = 0;
11742
11743 /* This function is easier to write if we only have to handle
11744 one data format: RGB or RGBA with 8 bits per channel. Let's
11745 transform other formats into that format. */
11746
11747 /* Strip more than 8 bits per channel. */
11748 if (bit_depth == 16)
11749 png_set_strip_16 (png_ptr);
11750
11751 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11752 if available. */
11753 png_set_expand (png_ptr);
11754
11755 /* Convert grayscale images to RGB. */
11756 if (color_type == PNG_COLOR_TYPE_GRAY
11757 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11758 png_set_gray_to_rgb (png_ptr);
11759
11760 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11761 gamma_str = getenv ("SCREEN_GAMMA");
11762 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11763
11764 /* Tell the PNG lib to handle gamma correction for us. */
11765
11766 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11767 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11768 /* There is a special chunk in the image specifying the gamma. */
11769 png_set_sRGB (png_ptr, info_ptr, intent);
11770 else
11771 #endif
11772 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11773 /* Image contains gamma information. */
11774 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11775 else
11776 /* Use a default of 0.5 for the image gamma. */
11777 png_set_gamma (png_ptr, screen_gamma, 0.5);
11778
11779 /* Handle alpha channel by combining the image with a background
11780 color. Do this only if a real alpha channel is supplied. For
11781 simple transparency, we prefer a clipping mask. */
11782 if (!transparent_p)
11783 {
11784 png_color_16 *image_background;
11785 Lisp_Object specified_bg
11786 = image_spec_value (img->spec, QCbackground, NULL);
11787
11788
11789 if (STRINGP (specified_bg))
11790 /* The user specified `:background', use that. */
11791 {
11792 COLORREF color;
11793 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11794 {
11795 png_color_16 user_bg;
11796
11797 bzero (&user_bg, sizeof user_bg);
11798 user_bg.red = color.red;
11799 user_bg.green = color.green;
11800 user_bg.blue = color.blue;
11801
11802 png_set_background (png_ptr, &user_bg,
11803 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11804 }
11805 }
11806 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
11807 /* Image contains a background color with which to
11808 combine the image. */
11809 png_set_background (png_ptr, image_background,
11810 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11811 else
11812 {
11813 /* Image does not contain a background color with which
11814 to combine the image data via an alpha channel. Use
11815 the frame's background instead. */
11816 XColor color;
11817 Colormap cmap;
11818 png_color_16 frame_background;
11819
11820 cmap = FRAME_X_COLORMAP (f);
11821 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11822 x_query_color (f, &color);
11823
11824 bzero (&frame_background, sizeof frame_background);
11825 frame_background.red = color.red;
11826 frame_background.green = color.green;
11827 frame_background.blue = color.blue;
11828
11829 png_set_background (png_ptr, &frame_background,
11830 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11831 }
11832 }
11833
11834 /* Update info structure. */
11835 png_read_update_info (png_ptr, info_ptr);
11836
11837 /* Get number of channels. Valid values are 1 for grayscale images
11838 and images with a palette, 2 for grayscale images with transparency
11839 information (alpha channel), 3 for RGB images, and 4 for RGB
11840 images with alpha channel, i.e. RGBA. If conversions above were
11841 sufficient we should only have 3 or 4 channels here. */
11842 channels = png_get_channels (png_ptr, info_ptr);
11843 xassert (channels == 3 || channels == 4);
11844
11845 /* Number of bytes needed for one row of the image. */
11846 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11847
11848 /* Allocate memory for the image. */
11849 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11850 rows = (png_byte **) xmalloc (height * sizeof *rows);
11851 for (i = 0; i < height; ++i)
11852 rows[i] = pixels + i * row_bytes;
11853
11854 /* Read the entire image. */
11855 png_read_image (png_ptr, rows);
11856 png_read_end (png_ptr, info_ptr);
11857 if (fp)
11858 {
11859 fclose (fp);
11860 fp = NULL;
11861 }
11862
11863 /* Create the X image and pixmap. */
11864 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11865 &img->pixmap))
11866 goto error;
11867
11868 /* Create an image and pixmap serving as mask if the PNG image
11869 contains an alpha channel. */
11870 if (channels == 4
11871 && !transparent_p
11872 && !x_create_x_image_and_pixmap (f, width, height, 1,
11873 &mask_img, &img->mask))
11874 {
11875 x_destroy_x_image (ximg);
11876 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11877 img->pixmap = 0;
11878 goto error;
11879 }
11880
11881 /* Fill the X image and mask from PNG data. */
11882 init_color_table ();
11883
11884 for (y = 0; y < height; ++y)
11885 {
11886 png_byte *p = rows[y];
11887
11888 for (x = 0; x < width; ++x)
11889 {
11890 unsigned r, g, b;
11891
11892 r = *p++ << 8;
11893 g = *p++ << 8;
11894 b = *p++ << 8;
11895 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11896
11897 /* An alpha channel, aka mask channel, associates variable
11898 transparency with an image. Where other image formats
11899 support binary transparency---fully transparent or fully
11900 opaque---PNG allows up to 254 levels of partial transparency.
11901 The PNG library implements partial transparency by combining
11902 the image with a specified background color.
11903
11904 I'm not sure how to handle this here nicely: because the
11905 background on which the image is displayed may change, for
11906 real alpha channel support, it would be necessary to create
11907 a new image for each possible background.
11908
11909 What I'm doing now is that a mask is created if we have
11910 boolean transparency information. Otherwise I'm using
11911 the frame's background color to combine the image with. */
11912
11913 if (channels == 4)
11914 {
11915 if (mask_img)
11916 XPutPixel (mask_img, x, y, *p > 0);
11917 ++p;
11918 }
11919 }
11920 }
11921
11922 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11923 /* Set IMG's background color from the PNG image, unless the user
11924 overrode it. */
11925 {
11926 png_color_16 *bg;
11927 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11928 {
11929 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11930 img->background_valid = 1;
11931 }
11932 }
11933
11934 /* Remember colors allocated for this image. */
11935 img->colors = colors_in_color_table (&img->ncolors);
11936 free_color_table ();
11937
11938 /* Clean up. */
11939 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11940 xfree (rows);
11941 xfree (pixels);
11942
11943 img->width = width;
11944 img->height = height;
11945
11946 /* Maybe fill in the background field while we have ximg handy. */
11947 IMAGE_BACKGROUND (img, f, ximg);
11948
11949 /* Put the image into the pixmap, then free the X image and its buffer. */
11950 x_put_x_image (f, ximg, img->pixmap, width, height);
11951 x_destroy_x_image (ximg);
11952
11953 /* Same for the mask. */
11954 if (mask_img)
11955 {
11956 /* Fill in the background_transparent field while we have the mask
11957 handy. */
11958 image_background_transparent (img, f, mask_img);
11959
11960 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11961 x_destroy_x_image (mask_img);
11962 }
11963
11964 UNGCPRO;
11965 return 1;
11966 }
11967
11968 #endif /* HAVE_PNG != 0 */
11969
11970
11971 \f
11972 /***********************************************************************
11973 JPEG
11974 ***********************************************************************/
11975
11976 #if HAVE_JPEG
11977
11978 /* Work around a warning about HAVE_STDLIB_H being redefined in
11979 jconfig.h. */
11980 #ifdef HAVE_STDLIB_H
11981 #define HAVE_STDLIB_H_1
11982 #undef HAVE_STDLIB_H
11983 #endif /* HAVE_STLIB_H */
11984
11985 #include <jpeglib.h>
11986 #include <jerror.h>
11987 #include <setjmp.h>
11988
11989 #ifdef HAVE_STLIB_H_1
11990 #define HAVE_STDLIB_H 1
11991 #endif
11992
11993 static int jpeg_image_p P_ ((Lisp_Object object));
11994 static int jpeg_load P_ ((struct frame *f, struct image *img));
11995
11996 /* The symbol `jpeg' identifying images of this type. */
11997
11998 Lisp_Object Qjpeg;
11999
12000 /* Indices of image specification fields in gs_format, below. */
12001
12002 enum jpeg_keyword_index
12003 {
12004 JPEG_TYPE,
12005 JPEG_DATA,
12006 JPEG_FILE,
12007 JPEG_ASCENT,
12008 JPEG_MARGIN,
12009 JPEG_RELIEF,
12010 JPEG_ALGORITHM,
12011 JPEG_HEURISTIC_MASK,
12012 JPEG_MASK,
12013 JPEG_BACKGROUND,
12014 JPEG_LAST
12015 };
12016
12017 /* Vector of image_keyword structures describing the format
12018 of valid user-defined image specifications. */
12019
12020 static struct image_keyword jpeg_format[JPEG_LAST] =
12021 {
12022 {":type", IMAGE_SYMBOL_VALUE, 1},
12023 {":data", IMAGE_STRING_VALUE, 0},
12024 {":file", IMAGE_STRING_VALUE, 0},
12025 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12026 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12027 {":relief", IMAGE_INTEGER_VALUE, 0},
12028 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12029 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12030 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12031 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12032 };
12033
12034 /* Structure describing the image type `jpeg'. */
12035
12036 static struct image_type jpeg_type =
12037 {
12038 &Qjpeg,
12039 jpeg_image_p,
12040 jpeg_load,
12041 x_clear_image,
12042 NULL
12043 };
12044
12045
12046 /* Return non-zero if OBJECT is a valid JPEG image specification. */
12047
12048 static int
12049 jpeg_image_p (object)
12050 Lisp_Object object;
12051 {
12052 struct image_keyword fmt[JPEG_LAST];
12053
12054 bcopy (jpeg_format, fmt, sizeof fmt);
12055
12056 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
12057 || (fmt[JPEG_ASCENT].count
12058 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12059 return 0;
12060
12061 /* Must specify either the :data or :file keyword. */
12062 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12063 }
12064
12065
12066 struct my_jpeg_error_mgr
12067 {
12068 struct jpeg_error_mgr pub;
12069 jmp_buf setjmp_buffer;
12070 };
12071
12072 static void
12073 my_error_exit (cinfo)
12074 j_common_ptr cinfo;
12075 {
12076 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12077 longjmp (mgr->setjmp_buffer, 1);
12078 }
12079
12080 /* Init source method for JPEG data source manager. Called by
12081 jpeg_read_header() before any data is actually read. See
12082 libjpeg.doc from the JPEG lib distribution. */
12083
12084 static void
12085 our_init_source (cinfo)
12086 j_decompress_ptr cinfo;
12087 {
12088 }
12089
12090
12091 /* Fill input buffer method for JPEG data source manager. Called
12092 whenever more data is needed. We read the whole image in one step,
12093 so this only adds a fake end of input marker at the end. */
12094
12095 static boolean
12096 our_fill_input_buffer (cinfo)
12097 j_decompress_ptr cinfo;
12098 {
12099 /* Insert a fake EOI marker. */
12100 struct jpeg_source_mgr *src = cinfo->src;
12101 static JOCTET buffer[2];
12102
12103 buffer[0] = (JOCTET) 0xFF;
12104 buffer[1] = (JOCTET) JPEG_EOI;
12105
12106 src->next_input_byte = buffer;
12107 src->bytes_in_buffer = 2;
12108 return TRUE;
12109 }
12110
12111
12112 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12113 is the JPEG data source manager. */
12114
12115 static void
12116 our_skip_input_data (cinfo, num_bytes)
12117 j_decompress_ptr cinfo;
12118 long num_bytes;
12119 {
12120 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12121
12122 if (src)
12123 {
12124 if (num_bytes > src->bytes_in_buffer)
12125 ERREXIT (cinfo, JERR_INPUT_EOF);
12126
12127 src->bytes_in_buffer -= num_bytes;
12128 src->next_input_byte += num_bytes;
12129 }
12130 }
12131
12132
12133 /* Method to terminate data source. Called by
12134 jpeg_finish_decompress() after all data has been processed. */
12135
12136 static void
12137 our_term_source (cinfo)
12138 j_decompress_ptr cinfo;
12139 {
12140 }
12141
12142
12143 /* Set up the JPEG lib for reading an image from DATA which contains
12144 LEN bytes. CINFO is the decompression info structure created for
12145 reading the image. */
12146
12147 static void
12148 jpeg_memory_src (cinfo, data, len)
12149 j_decompress_ptr cinfo;
12150 JOCTET *data;
12151 unsigned int len;
12152 {
12153 struct jpeg_source_mgr *src;
12154
12155 if (cinfo->src == NULL)
12156 {
12157 /* First time for this JPEG object? */
12158 cinfo->src = (struct jpeg_source_mgr *)
12159 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12160 sizeof (struct jpeg_source_mgr));
12161 src = (struct jpeg_source_mgr *) cinfo->src;
12162 src->next_input_byte = data;
12163 }
12164
12165 src = (struct jpeg_source_mgr *) cinfo->src;
12166 src->init_source = our_init_source;
12167 src->fill_input_buffer = our_fill_input_buffer;
12168 src->skip_input_data = our_skip_input_data;
12169 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12170 src->term_source = our_term_source;
12171 src->bytes_in_buffer = len;
12172 src->next_input_byte = data;
12173 }
12174
12175
12176 /* Load image IMG for use on frame F. Patterned after example.c
12177 from the JPEG lib. */
12178
12179 static int
12180 jpeg_load (f, img)
12181 struct frame *f;
12182 struct image *img;
12183 {
12184 struct jpeg_decompress_struct cinfo;
12185 struct my_jpeg_error_mgr mgr;
12186 Lisp_Object file, specified_file;
12187 Lisp_Object specified_data;
12188 FILE * volatile fp = NULL;
12189 JSAMPARRAY buffer;
12190 int row_stride, x, y;
12191 XImage *ximg = NULL;
12192 int rc;
12193 unsigned long *colors;
12194 int width, height;
12195 struct gcpro gcpro1;
12196
12197 /* Open the JPEG file. */
12198 specified_file = image_spec_value (img->spec, QCfile, NULL);
12199 specified_data = image_spec_value (img->spec, QCdata, NULL);
12200 file = Qnil;
12201 GCPRO1 (file);
12202
12203 if (NILP (specified_data))
12204 {
12205 file = x_find_image_file (specified_file);
12206 if (!STRINGP (file))
12207 {
12208 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12209 UNGCPRO;
12210 return 0;
12211 }
12212
12213 fp = fopen (XSTRING (file)->data, "r");
12214 if (fp == NULL)
12215 {
12216 image_error ("Cannot open `%s'", file, Qnil);
12217 UNGCPRO;
12218 return 0;
12219 }
12220 }
12221
12222 /* Customize libjpeg's error handling to call my_error_exit when an
12223 error is detected. This function will perform a longjmp. */
12224 cinfo.err = jpeg_std_error (&mgr.pub);
12225 mgr.pub.error_exit = my_error_exit;
12226
12227 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12228 {
12229 if (rc == 1)
12230 {
12231 /* Called from my_error_exit. Display a JPEG error. */
12232 char buffer[JMSG_LENGTH_MAX];
12233 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12234 image_error ("Error reading JPEG image `%s': %s", img->spec,
12235 build_string (buffer));
12236 }
12237
12238 /* Close the input file and destroy the JPEG object. */
12239 if (fp)
12240 fclose (fp);
12241 jpeg_destroy_decompress (&cinfo);
12242
12243 /* If we already have an XImage, free that. */
12244 x_destroy_x_image (ximg);
12245
12246 /* Free pixmap and colors. */
12247 x_clear_image (f, img);
12248
12249 UNGCPRO;
12250 return 0;
12251 }
12252
12253 /* Create the JPEG decompression object. Let it read from fp.
12254 Read the JPEG image header. */
12255 jpeg_create_decompress (&cinfo);
12256
12257 if (NILP (specified_data))
12258 jpeg_stdio_src (&cinfo, fp);
12259 else
12260 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12261 STRING_BYTES (XSTRING (specified_data)));
12262
12263 jpeg_read_header (&cinfo, TRUE);
12264
12265 /* Customize decompression so that color quantization will be used.
12266 Start decompression. */
12267 cinfo.quantize_colors = TRUE;
12268 jpeg_start_decompress (&cinfo);
12269 width = img->width = cinfo.output_width;
12270 height = img->height = cinfo.output_height;
12271
12272 /* Create X image and pixmap. */
12273 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12274 &img->pixmap))
12275 longjmp (mgr.setjmp_buffer, 2);
12276
12277 /* Allocate colors. When color quantization is used,
12278 cinfo.actual_number_of_colors has been set with the number of
12279 colors generated, and cinfo.colormap is a two-dimensional array
12280 of color indices in the range 0..cinfo.actual_number_of_colors.
12281 No more than 255 colors will be generated. */
12282 {
12283 int i, ir, ig, ib;
12284
12285 if (cinfo.out_color_components > 2)
12286 ir = 0, ig = 1, ib = 2;
12287 else if (cinfo.out_color_components > 1)
12288 ir = 0, ig = 1, ib = 0;
12289 else
12290 ir = 0, ig = 0, ib = 0;
12291
12292 /* Use the color table mechanism because it handles colors that
12293 cannot be allocated nicely. Such colors will be replaced with
12294 a default color, and we don't have to care about which colors
12295 can be freed safely, and which can't. */
12296 init_color_table ();
12297 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12298 * sizeof *colors);
12299
12300 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12301 {
12302 /* Multiply RGB values with 255 because X expects RGB values
12303 in the range 0..0xffff. */
12304 int r = cinfo.colormap[ir][i] << 8;
12305 int g = cinfo.colormap[ig][i] << 8;
12306 int b = cinfo.colormap[ib][i] << 8;
12307 colors[i] = lookup_rgb_color (f, r, g, b);
12308 }
12309
12310 /* Remember those colors actually allocated. */
12311 img->colors = colors_in_color_table (&img->ncolors);
12312 free_color_table ();
12313 }
12314
12315 /* Read pixels. */
12316 row_stride = width * cinfo.output_components;
12317 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12318 row_stride, 1);
12319 for (y = 0; y < height; ++y)
12320 {
12321 jpeg_read_scanlines (&cinfo, buffer, 1);
12322 for (x = 0; x < cinfo.output_width; ++x)
12323 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12324 }
12325
12326 /* Clean up. */
12327 jpeg_finish_decompress (&cinfo);
12328 jpeg_destroy_decompress (&cinfo);
12329 if (fp)
12330 fclose (fp);
12331
12332 /* Maybe fill in the background field while we have ximg handy. */
12333 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12334 IMAGE_BACKGROUND (img, f, ximg);
12335
12336 /* Put the image into the pixmap. */
12337 x_put_x_image (f, ximg, img->pixmap, width, height);
12338 x_destroy_x_image (ximg);
12339 UNBLOCK_INPUT;
12340 UNGCPRO;
12341 return 1;
12342 }
12343
12344 #endif /* HAVE_JPEG */
12345
12346
12347 \f
12348 /***********************************************************************
12349 TIFF
12350 ***********************************************************************/
12351
12352 #if HAVE_TIFF
12353
12354 #include <tiffio.h>
12355
12356 static int tiff_image_p P_ ((Lisp_Object object));
12357 static int tiff_load P_ ((struct frame *f, struct image *img));
12358
12359 /* The symbol `tiff' identifying images of this type. */
12360
12361 Lisp_Object Qtiff;
12362
12363 /* Indices of image specification fields in tiff_format, below. */
12364
12365 enum tiff_keyword_index
12366 {
12367 TIFF_TYPE,
12368 TIFF_DATA,
12369 TIFF_FILE,
12370 TIFF_ASCENT,
12371 TIFF_MARGIN,
12372 TIFF_RELIEF,
12373 TIFF_ALGORITHM,
12374 TIFF_HEURISTIC_MASK,
12375 TIFF_MASK,
12376 TIFF_BACKGROUND,
12377 TIFF_LAST
12378 };
12379
12380 /* Vector of image_keyword structures describing the format
12381 of valid user-defined image specifications. */
12382
12383 static struct image_keyword tiff_format[TIFF_LAST] =
12384 {
12385 {":type", IMAGE_SYMBOL_VALUE, 1},
12386 {":data", IMAGE_STRING_VALUE, 0},
12387 {":file", IMAGE_STRING_VALUE, 0},
12388 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12389 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12390 {":relief", IMAGE_INTEGER_VALUE, 0},
12391 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12392 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12393 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12394 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12395 };
12396
12397 /* Structure describing the image type `tiff'. */
12398
12399 static struct image_type tiff_type =
12400 {
12401 &Qtiff,
12402 tiff_image_p,
12403 tiff_load,
12404 x_clear_image,
12405 NULL
12406 };
12407
12408
12409 /* Return non-zero if OBJECT is a valid TIFF image specification. */
12410
12411 static int
12412 tiff_image_p (object)
12413 Lisp_Object object;
12414 {
12415 struct image_keyword fmt[TIFF_LAST];
12416 bcopy (tiff_format, fmt, sizeof fmt);
12417
12418 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12419 || (fmt[TIFF_ASCENT].count
12420 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12421 return 0;
12422
12423 /* Must specify either the :data or :file keyword. */
12424 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12425 }
12426
12427
12428 /* Reading from a memory buffer for TIFF images Based on the PNG
12429 memory source, but we have to provide a lot of extra functions.
12430 Blah.
12431
12432 We really only need to implement read and seek, but I am not
12433 convinced that the TIFF library is smart enough not to destroy
12434 itself if we only hand it the function pointers we need to
12435 override. */
12436
12437 typedef struct
12438 {
12439 unsigned char *bytes;
12440 size_t len;
12441 int index;
12442 }
12443 tiff_memory_source;
12444
12445 static size_t
12446 tiff_read_from_memory (data, buf, size)
12447 thandle_t data;
12448 tdata_t buf;
12449 tsize_t size;
12450 {
12451 tiff_memory_source *src = (tiff_memory_source *) data;
12452
12453 if (size > src->len - src->index)
12454 return (size_t) -1;
12455 bcopy (src->bytes + src->index, buf, size);
12456 src->index += size;
12457 return size;
12458 }
12459
12460 static size_t
12461 tiff_write_from_memory (data, buf, size)
12462 thandle_t data;
12463 tdata_t buf;
12464 tsize_t size;
12465 {
12466 return (size_t) -1;
12467 }
12468
12469 static toff_t
12470 tiff_seek_in_memory (data, off, whence)
12471 thandle_t data;
12472 toff_t off;
12473 int whence;
12474 {
12475 tiff_memory_source *src = (tiff_memory_source *) data;
12476 int idx;
12477
12478 switch (whence)
12479 {
12480 case SEEK_SET: /* Go from beginning of source. */
12481 idx = off;
12482 break;
12483
12484 case SEEK_END: /* Go from end of source. */
12485 idx = src->len + off;
12486 break;
12487
12488 case SEEK_CUR: /* Go from current position. */
12489 idx = src->index + off;
12490 break;
12491
12492 default: /* Invalid `whence'. */
12493 return -1;
12494 }
12495
12496 if (idx > src->len || idx < 0)
12497 return -1;
12498
12499 src->index = idx;
12500 return src->index;
12501 }
12502
12503 static int
12504 tiff_close_memory (data)
12505 thandle_t data;
12506 {
12507 /* NOOP */
12508 return 0;
12509 }
12510
12511 static int
12512 tiff_mmap_memory (data, pbase, psize)
12513 thandle_t data;
12514 tdata_t *pbase;
12515 toff_t *psize;
12516 {
12517 /* It is already _IN_ memory. */
12518 return 0;
12519 }
12520
12521 static void
12522 tiff_unmap_memory (data, base, size)
12523 thandle_t data;
12524 tdata_t base;
12525 toff_t size;
12526 {
12527 /* We don't need to do this. */
12528 }
12529
12530 static toff_t
12531 tiff_size_of_memory (data)
12532 thandle_t data;
12533 {
12534 return ((tiff_memory_source *) data)->len;
12535 }
12536
12537
12538 static void
12539 tiff_error_handler (title, format, ap)
12540 const char *title, *format;
12541 va_list ap;
12542 {
12543 char buf[512];
12544 int len;
12545
12546 len = sprintf (buf, "TIFF error: %s ", title);
12547 vsprintf (buf + len, format, ap);
12548 add_to_log (buf, Qnil, Qnil);
12549 }
12550
12551
12552 static void
12553 tiff_warning_handler (title, format, ap)
12554 const char *title, *format;
12555 va_list ap;
12556 {
12557 char buf[512];
12558 int len;
12559
12560 len = sprintf (buf, "TIFF warning: %s ", title);
12561 vsprintf (buf + len, format, ap);
12562 add_to_log (buf, Qnil, Qnil);
12563 }
12564
12565
12566 /* Load TIFF image IMG for use on frame F. Value is non-zero if
12567 successful. */
12568
12569 static int
12570 tiff_load (f, img)
12571 struct frame *f;
12572 struct image *img;
12573 {
12574 Lisp_Object file, specified_file;
12575 Lisp_Object specified_data;
12576 TIFF *tiff;
12577 int width, height, x, y;
12578 uint32 *buf;
12579 int rc;
12580 XImage *ximg;
12581 struct gcpro gcpro1;
12582 tiff_memory_source memsrc;
12583
12584 specified_file = image_spec_value (img->spec, QCfile, NULL);
12585 specified_data = image_spec_value (img->spec, QCdata, NULL);
12586 file = Qnil;
12587 GCPRO1 (file);
12588
12589 TIFFSetErrorHandler (tiff_error_handler);
12590 TIFFSetWarningHandler (tiff_warning_handler);
12591
12592 if (NILP (specified_data))
12593 {
12594 /* Read from a file */
12595 file = x_find_image_file (specified_file);
12596 if (!STRINGP (file))
12597 {
12598 image_error ("Cannot find image file `%s'", file, Qnil);
12599 UNGCPRO;
12600 return 0;
12601 }
12602
12603 /* Try to open the image file. */
12604 tiff = TIFFOpen (XSTRING (file)->data, "r");
12605 if (tiff == NULL)
12606 {
12607 image_error ("Cannot open `%s'", file, Qnil);
12608 UNGCPRO;
12609 return 0;
12610 }
12611 }
12612 else
12613 {
12614 /* Memory source! */
12615 memsrc.bytes = XSTRING (specified_data)->data;
12616 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12617 memsrc.index = 0;
12618
12619 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12620 (TIFFReadWriteProc) tiff_read_from_memory,
12621 (TIFFReadWriteProc) tiff_write_from_memory,
12622 tiff_seek_in_memory,
12623 tiff_close_memory,
12624 tiff_size_of_memory,
12625 tiff_mmap_memory,
12626 tiff_unmap_memory);
12627
12628 if (!tiff)
12629 {
12630 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12631 UNGCPRO;
12632 return 0;
12633 }
12634 }
12635
12636 /* Get width and height of the image, and allocate a raster buffer
12637 of width x height 32-bit values. */
12638 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12639 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12640 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12641
12642 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12643 TIFFClose (tiff);
12644 if (!rc)
12645 {
12646 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12647 xfree (buf);
12648 UNGCPRO;
12649 return 0;
12650 }
12651
12652 /* Create the X image and pixmap. */
12653 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12654 {
12655 xfree (buf);
12656 UNGCPRO;
12657 return 0;
12658 }
12659
12660 /* Initialize the color table. */
12661 init_color_table ();
12662
12663 /* Process the pixel raster. Origin is in the lower-left corner. */
12664 for (y = 0; y < height; ++y)
12665 {
12666 uint32 *row = buf + y * width;
12667
12668 for (x = 0; x < width; ++x)
12669 {
12670 uint32 abgr = row[x];
12671 int r = TIFFGetR (abgr) << 8;
12672 int g = TIFFGetG (abgr) << 8;
12673 int b = TIFFGetB (abgr) << 8;
12674 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12675 }
12676 }
12677
12678 /* Remember the colors allocated for the image. Free the color table. */
12679 img->colors = colors_in_color_table (&img->ncolors);
12680 free_color_table ();
12681
12682 img->width = width;
12683 img->height = height;
12684
12685 /* Maybe fill in the background field while we have ximg handy. */
12686 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12687 IMAGE_BACKGROUND (img, f, ximg);
12688
12689 /* Put the image into the pixmap, then free the X image and its buffer. */
12690 x_put_x_image (f, ximg, img->pixmap, width, height);
12691 x_destroy_x_image (ximg);
12692 xfree (buf);
12693
12694 UNGCPRO;
12695 return 1;
12696 }
12697
12698 #endif /* HAVE_TIFF != 0 */
12699
12700
12701 \f
12702 /***********************************************************************
12703 GIF
12704 ***********************************************************************/
12705
12706 #if HAVE_GIF
12707
12708 #include <gif_lib.h>
12709
12710 static int gif_image_p P_ ((Lisp_Object object));
12711 static int gif_load P_ ((struct frame *f, struct image *img));
12712
12713 /* The symbol `gif' identifying images of this type. */
12714
12715 Lisp_Object Qgif;
12716
12717 /* Indices of image specification fields in gif_format, below. */
12718
12719 enum gif_keyword_index
12720 {
12721 GIF_TYPE,
12722 GIF_DATA,
12723 GIF_FILE,
12724 GIF_ASCENT,
12725 GIF_MARGIN,
12726 GIF_RELIEF,
12727 GIF_ALGORITHM,
12728 GIF_HEURISTIC_MASK,
12729 GIF_MASK,
12730 GIF_IMAGE,
12731 GIF_BACKGROUND,
12732 GIF_LAST
12733 };
12734
12735 /* Vector of image_keyword structures describing the format
12736 of valid user-defined image specifications. */
12737
12738 static struct image_keyword gif_format[GIF_LAST] =
12739 {
12740 {":type", IMAGE_SYMBOL_VALUE, 1},
12741 {":data", IMAGE_STRING_VALUE, 0},
12742 {":file", IMAGE_STRING_VALUE, 0},
12743 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12744 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12745 {":relief", IMAGE_INTEGER_VALUE, 0},
12746 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12747 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12748 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12749 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12750 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12751 };
12752
12753 /* Structure describing the image type `gif'. */
12754
12755 static struct image_type gif_type =
12756 {
12757 &Qgif,
12758 gif_image_p,
12759 gif_load,
12760 x_clear_image,
12761 NULL
12762 };
12763
12764 /* Return non-zero if OBJECT is a valid GIF image specification. */
12765
12766 static int
12767 gif_image_p (object)
12768 Lisp_Object object;
12769 {
12770 struct image_keyword fmt[GIF_LAST];
12771 bcopy (gif_format, fmt, sizeof fmt);
12772
12773 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12774 || (fmt[GIF_ASCENT].count
12775 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12776 return 0;
12777
12778 /* Must specify either the :data or :file keyword. */
12779 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12780 }
12781
12782 /* Reading a GIF image from memory
12783 Based on the PNG memory stuff to a certain extent. */
12784
12785 typedef struct
12786 {
12787 unsigned char *bytes;
12788 size_t len;
12789 int index;
12790 }
12791 gif_memory_source;
12792
12793 /* Make the current memory source available to gif_read_from_memory.
12794 It's done this way because not all versions of libungif support
12795 a UserData field in the GifFileType structure. */
12796 static gif_memory_source *current_gif_memory_src;
12797
12798 static int
12799 gif_read_from_memory (file, buf, len)
12800 GifFileType *file;
12801 GifByteType *buf;
12802 int len;
12803 {
12804 gif_memory_source *src = current_gif_memory_src;
12805
12806 if (len > src->len - src->index)
12807 return -1;
12808
12809 bcopy (src->bytes + src->index, buf, len);
12810 src->index += len;
12811 return len;
12812 }
12813
12814
12815 /* Load GIF image IMG for use on frame F. Value is non-zero if
12816 successful. */
12817
12818 static int
12819 gif_load (f, img)
12820 struct frame *f;
12821 struct image *img;
12822 {
12823 Lisp_Object file, specified_file;
12824 Lisp_Object specified_data;
12825 int rc, width, height, x, y, i;
12826 XImage *ximg;
12827 ColorMapObject *gif_color_map;
12828 unsigned long pixel_colors[256];
12829 GifFileType *gif;
12830 struct gcpro gcpro1;
12831 Lisp_Object image;
12832 int ino, image_left, image_top, image_width, image_height;
12833 gif_memory_source memsrc;
12834 unsigned char *raster;
12835
12836 specified_file = image_spec_value (img->spec, QCfile, NULL);
12837 specified_data = image_spec_value (img->spec, QCdata, NULL);
12838 file = Qnil;
12839 GCPRO1 (file);
12840
12841 if (NILP (specified_data))
12842 {
12843 file = x_find_image_file (specified_file);
12844 if (!STRINGP (file))
12845 {
12846 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12847 UNGCPRO;
12848 return 0;
12849 }
12850
12851 /* Open the GIF file. */
12852 gif = DGifOpenFileName (XSTRING (file)->data);
12853 if (gif == NULL)
12854 {
12855 image_error ("Cannot open `%s'", file, Qnil);
12856 UNGCPRO;
12857 return 0;
12858 }
12859 }
12860 else
12861 {
12862 /* Read from memory! */
12863 current_gif_memory_src = &memsrc;
12864 memsrc.bytes = XSTRING (specified_data)->data;
12865 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12866 memsrc.index = 0;
12867
12868 gif = DGifOpen(&memsrc, gif_read_from_memory);
12869 if (!gif)
12870 {
12871 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12872 UNGCPRO;
12873 return 0;
12874 }
12875 }
12876
12877 /* Read entire contents. */
12878 rc = DGifSlurp (gif);
12879 if (rc == GIF_ERROR)
12880 {
12881 image_error ("Error reading `%s'", img->spec, Qnil);
12882 DGifCloseFile (gif);
12883 UNGCPRO;
12884 return 0;
12885 }
12886
12887 image = image_spec_value (img->spec, QCindex, NULL);
12888 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12889 if (ino >= gif->ImageCount)
12890 {
12891 image_error ("Invalid image number `%s' in image `%s'",
12892 image, img->spec);
12893 DGifCloseFile (gif);
12894 UNGCPRO;
12895 return 0;
12896 }
12897
12898 width = img->width = gif->SWidth;
12899 height = img->height = gif->SHeight;
12900
12901 /* Create the X image and pixmap. */
12902 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12903 {
12904 DGifCloseFile (gif);
12905 UNGCPRO;
12906 return 0;
12907 }
12908
12909 /* Allocate colors. */
12910 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12911 if (!gif_color_map)
12912 gif_color_map = gif->SColorMap;
12913 init_color_table ();
12914 bzero (pixel_colors, sizeof pixel_colors);
12915
12916 for (i = 0; i < gif_color_map->ColorCount; ++i)
12917 {
12918 int r = gif_color_map->Colors[i].Red << 8;
12919 int g = gif_color_map->Colors[i].Green << 8;
12920 int b = gif_color_map->Colors[i].Blue << 8;
12921 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12922 }
12923
12924 img->colors = colors_in_color_table (&img->ncolors);
12925 free_color_table ();
12926
12927 /* Clear the part of the screen image that are not covered by
12928 the image from the GIF file. Full animated GIF support
12929 requires more than can be done here (see the gif89 spec,
12930 disposal methods). Let's simply assume that the part
12931 not covered by a sub-image is in the frame's background color. */
12932 image_top = gif->SavedImages[ino].ImageDesc.Top;
12933 image_left = gif->SavedImages[ino].ImageDesc.Left;
12934 image_width = gif->SavedImages[ino].ImageDesc.Width;
12935 image_height = gif->SavedImages[ino].ImageDesc.Height;
12936
12937 for (y = 0; y < image_top; ++y)
12938 for (x = 0; x < width; ++x)
12939 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12940
12941 for (y = image_top + image_height; y < height; ++y)
12942 for (x = 0; x < width; ++x)
12943 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12944
12945 for (y = image_top; y < image_top + image_height; ++y)
12946 {
12947 for (x = 0; x < image_left; ++x)
12948 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12949 for (x = image_left + image_width; x < width; ++x)
12950 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12951 }
12952
12953 /* Read the GIF image into the X image. We use a local variable
12954 `raster' here because RasterBits below is a char *, and invites
12955 problems with bytes >= 0x80. */
12956 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12957
12958 if (gif->SavedImages[ino].ImageDesc.Interlace)
12959 {
12960 static int interlace_start[] = {0, 4, 2, 1};
12961 static int interlace_increment[] = {8, 8, 4, 2};
12962 int pass;
12963 int row = interlace_start[0];
12964
12965 pass = 0;
12966
12967 for (y = 0; y < image_height; y++)
12968 {
12969 if (row >= image_height)
12970 {
12971 row = interlace_start[++pass];
12972 while (row >= image_height)
12973 row = interlace_start[++pass];
12974 }
12975
12976 for (x = 0; x < image_width; x++)
12977 {
12978 int i = raster[(y * image_width) + x];
12979 XPutPixel (ximg, x + image_left, row + image_top,
12980 pixel_colors[i]);
12981 }
12982
12983 row += interlace_increment[pass];
12984 }
12985 }
12986 else
12987 {
12988 for (y = 0; y < image_height; ++y)
12989 for (x = 0; x < image_width; ++x)
12990 {
12991 int i = raster[y* image_width + x];
12992 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12993 }
12994 }
12995
12996 DGifCloseFile (gif);
12997
12998 /* Maybe fill in the background field while we have ximg handy. */
12999 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13000 IMAGE_BACKGROUND (img, f, ximg);
13001
13002 /* Put the image into the pixmap, then free the X image and its buffer. */
13003 x_put_x_image (f, ximg, img->pixmap, width, height);
13004 x_destroy_x_image (ximg);
13005
13006 UNGCPRO;
13007 return 1;
13008 }
13009
13010 #endif /* HAVE_GIF != 0 */
13011
13012
13013 \f
13014 /***********************************************************************
13015 Ghostscript
13016 ***********************************************************************/
13017
13018 Lisp_Object Qpostscript;
13019
13020 #ifdef HAVE_GHOSTSCRIPT
13021 static int gs_image_p P_ ((Lisp_Object object));
13022 static int gs_load P_ ((struct frame *f, struct image *img));
13023 static void gs_clear_image P_ ((struct frame *f, struct image *img));
13024
13025 /* The symbol `postscript' identifying images of this type. */
13026
13027 /* Keyword symbols. */
13028
13029 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13030
13031 /* Indices of image specification fields in gs_format, below. */
13032
13033 enum gs_keyword_index
13034 {
13035 GS_TYPE,
13036 GS_PT_WIDTH,
13037 GS_PT_HEIGHT,
13038 GS_FILE,
13039 GS_LOADER,
13040 GS_BOUNDING_BOX,
13041 GS_ASCENT,
13042 GS_MARGIN,
13043 GS_RELIEF,
13044 GS_ALGORITHM,
13045 GS_HEURISTIC_MASK,
13046 GS_MASK,
13047 GS_BACKGROUND,
13048 GS_LAST
13049 };
13050
13051 /* Vector of image_keyword structures describing the format
13052 of valid user-defined image specifications. */
13053
13054 static struct image_keyword gs_format[GS_LAST] =
13055 {
13056 {":type", IMAGE_SYMBOL_VALUE, 1},
13057 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13058 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13059 {":file", IMAGE_STRING_VALUE, 1},
13060 {":loader", IMAGE_FUNCTION_VALUE, 0},
13061 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13062 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
13063 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
13064 {":relief", IMAGE_INTEGER_VALUE, 0},
13065 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13066 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13067 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13068 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
13069 };
13070
13071 /* Structure describing the image type `ghostscript'. */
13072
13073 static struct image_type gs_type =
13074 {
13075 &Qpostscript,
13076 gs_image_p,
13077 gs_load,
13078 gs_clear_image,
13079 NULL
13080 };
13081
13082
13083 /* Free X resources of Ghostscript image IMG which is used on frame F. */
13084
13085 static void
13086 gs_clear_image (f, img)
13087 struct frame *f;
13088 struct image *img;
13089 {
13090 /* IMG->data.ptr_val may contain a recorded colormap. */
13091 xfree (img->data.ptr_val);
13092 x_clear_image (f, img);
13093 }
13094
13095
13096 /* Return non-zero if OBJECT is a valid Ghostscript image
13097 specification. */
13098
13099 static int
13100 gs_image_p (object)
13101 Lisp_Object object;
13102 {
13103 struct image_keyword fmt[GS_LAST];
13104 Lisp_Object tem;
13105 int i;
13106
13107 bcopy (gs_format, fmt, sizeof fmt);
13108
13109 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13110 || (fmt[GS_ASCENT].count
13111 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13112 return 0;
13113
13114 /* Bounding box must be a list or vector containing 4 integers. */
13115 tem = fmt[GS_BOUNDING_BOX].value;
13116 if (CONSP (tem))
13117 {
13118 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13119 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13120 return 0;
13121 if (!NILP (tem))
13122 return 0;
13123 }
13124 else if (VECTORP (tem))
13125 {
13126 if (XVECTOR (tem)->size != 4)
13127 return 0;
13128 for (i = 0; i < 4; ++i)
13129 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13130 return 0;
13131 }
13132 else
13133 return 0;
13134
13135 return 1;
13136 }
13137
13138
13139 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
13140 if successful. */
13141
13142 static int
13143 gs_load (f, img)
13144 struct frame *f;
13145 struct image *img;
13146 {
13147 char buffer[100];
13148 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13149 struct gcpro gcpro1, gcpro2;
13150 Lisp_Object frame;
13151 double in_width, in_height;
13152 Lisp_Object pixel_colors = Qnil;
13153
13154 /* Compute pixel size of pixmap needed from the given size in the
13155 image specification. Sizes in the specification are in pt. 1 pt
13156 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13157 info. */
13158 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13159 in_width = XFASTINT (pt_width) / 72.0;
13160 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13161 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13162 in_height = XFASTINT (pt_height) / 72.0;
13163 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13164
13165 /* Create the pixmap. */
13166 BLOCK_INPUT;
13167 xassert (img->pixmap == 0);
13168 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13169 img->width, img->height,
13170 one_w32_display_info.n_cbits);
13171 UNBLOCK_INPUT;
13172
13173 if (!img->pixmap)
13174 {
13175 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13176 return 0;
13177 }
13178
13179 /* Call the loader to fill the pixmap. It returns a process object
13180 if successful. We do not record_unwind_protect here because
13181 other places in redisplay like calling window scroll functions
13182 don't either. Let the Lisp loader use `unwind-protect' instead. */
13183 GCPRO2 (window_and_pixmap_id, pixel_colors);
13184
13185 sprintf (buffer, "%lu %lu",
13186 (unsigned long) FRAME_W32_WINDOW (f),
13187 (unsigned long) img->pixmap);
13188 window_and_pixmap_id = build_string (buffer);
13189
13190 sprintf (buffer, "%lu %lu",
13191 FRAME_FOREGROUND_PIXEL (f),
13192 FRAME_BACKGROUND_PIXEL (f));
13193 pixel_colors = build_string (buffer);
13194
13195 XSETFRAME (frame, f);
13196 loader = image_spec_value (img->spec, QCloader, NULL);
13197 if (NILP (loader))
13198 loader = intern ("gs-load-image");
13199
13200 img->data.lisp_val = call6 (loader, frame, img->spec,
13201 make_number (img->width),
13202 make_number (img->height),
13203 window_and_pixmap_id,
13204 pixel_colors);
13205 UNGCPRO;
13206 return PROCESSP (img->data.lisp_val);
13207 }
13208
13209
13210 /* Kill the Ghostscript process that was started to fill PIXMAP on
13211 frame F. Called from XTread_socket when receiving an event
13212 telling Emacs that Ghostscript has finished drawing. */
13213
13214 void
13215 x_kill_gs_process (pixmap, f)
13216 Pixmap pixmap;
13217 struct frame *f;
13218 {
13219 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13220 int class, i;
13221 struct image *img;
13222
13223 /* Find the image containing PIXMAP. */
13224 for (i = 0; i < c->used; ++i)
13225 if (c->images[i]->pixmap == pixmap)
13226 break;
13227
13228 /* Should someone in between have cleared the image cache, for
13229 instance, give up. */
13230 if (i == c->used)
13231 return;
13232
13233 /* Kill the GS process. We should have found PIXMAP in the image
13234 cache and its image should contain a process object. */
13235 img = c->images[i];
13236 xassert (PROCESSP (img->data.lisp_val));
13237 Fkill_process (img->data.lisp_val, Qnil);
13238 img->data.lisp_val = Qnil;
13239
13240 /* On displays with a mutable colormap, figure out the colors
13241 allocated for the image by looking at the pixels of an XImage for
13242 img->pixmap. */
13243 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13244 if (class != StaticColor && class != StaticGray && class != TrueColor)
13245 {
13246 XImage *ximg;
13247
13248 BLOCK_INPUT;
13249
13250 /* Try to get an XImage for img->pixmep. */
13251 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13252 0, 0, img->width, img->height, ~0, ZPixmap);
13253 if (ximg)
13254 {
13255 int x, y;
13256
13257 /* Initialize the color table. */
13258 init_color_table ();
13259
13260 /* For each pixel of the image, look its color up in the
13261 color table. After having done so, the color table will
13262 contain an entry for each color used by the image. */
13263 for (y = 0; y < img->height; ++y)
13264 for (x = 0; x < img->width; ++x)
13265 {
13266 unsigned long pixel = XGetPixel (ximg, x, y);
13267 lookup_pixel_color (f, pixel);
13268 }
13269
13270 /* Record colors in the image. Free color table and XImage. */
13271 img->colors = colors_in_color_table (&img->ncolors);
13272 free_color_table ();
13273 XDestroyImage (ximg);
13274
13275 #if 0 /* This doesn't seem to be the case. If we free the colors
13276 here, we get a BadAccess later in x_clear_image when
13277 freeing the colors. */
13278 /* We have allocated colors once, but Ghostscript has also
13279 allocated colors on behalf of us. So, to get the
13280 reference counts right, free them once. */
13281 if (img->ncolors)
13282 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
13283 img->colors, img->ncolors, 0);
13284 #endif
13285 }
13286 else
13287 image_error ("Cannot get X image of `%s'; colors will not be freed",
13288 img->spec, Qnil);
13289
13290 UNBLOCK_INPUT;
13291 }
13292
13293 /* Now that we have the pixmap, compute mask and transform the
13294 image if requested. */
13295 BLOCK_INPUT;
13296 postprocess_image (f, img);
13297 UNBLOCK_INPUT;
13298 }
13299
13300 #endif /* HAVE_GHOSTSCRIPT */
13301
13302 \f
13303 /***********************************************************************
13304 Window properties
13305 ***********************************************************************/
13306
13307 DEFUN ("x-change-window-property", Fx_change_window_property,
13308 Sx_change_window_property, 2, 3, 0,
13309 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13310 PROP and VALUE must be strings. FRAME nil or omitted means use the
13311 selected frame. Value is VALUE. */)
13312 (prop, value, frame)
13313 Lisp_Object frame, prop, value;
13314 {
13315 #if 0 /* TODO : port window properties to W32 */
13316 struct frame *f = check_x_frame (frame);
13317 Atom prop_atom;
13318
13319 CHECK_STRING (prop);
13320 CHECK_STRING (value);
13321
13322 BLOCK_INPUT;
13323 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13324 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13325 prop_atom, XA_STRING, 8, PropModeReplace,
13326 XSTRING (value)->data, XSTRING (value)->size);
13327
13328 /* Make sure the property is set when we return. */
13329 XFlush (FRAME_W32_DISPLAY (f));
13330 UNBLOCK_INPUT;
13331
13332 #endif /* TODO */
13333
13334 return value;
13335 }
13336
13337
13338 DEFUN ("x-delete-window-property", Fx_delete_window_property,
13339 Sx_delete_window_property, 1, 2, 0,
13340 doc: /* Remove window property PROP from X window of FRAME.
13341 FRAME nil or omitted means use the selected frame. Value is PROP. */)
13342 (prop, frame)
13343 Lisp_Object prop, frame;
13344 {
13345 #if 0 /* TODO : port window properties to W32 */
13346
13347 struct frame *f = check_x_frame (frame);
13348 Atom prop_atom;
13349
13350 CHECK_STRING (prop);
13351 BLOCK_INPUT;
13352 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13353 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13354
13355 /* Make sure the property is removed when we return. */
13356 XFlush (FRAME_W32_DISPLAY (f));
13357 UNBLOCK_INPUT;
13358 #endif /* TODO */
13359
13360 return prop;
13361 }
13362
13363
13364 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13365 1, 2, 0,
13366 doc: /* Value is the value of window property PROP on FRAME.
13367 If FRAME is nil or omitted, use the selected frame. Value is nil
13368 if FRAME hasn't a property with name PROP or if PROP has no string
13369 value. */)
13370 (prop, frame)
13371 Lisp_Object prop, frame;
13372 {
13373 #if 0 /* TODO : port window properties to W32 */
13374
13375 struct frame *f = check_x_frame (frame);
13376 Atom prop_atom;
13377 int rc;
13378 Lisp_Object prop_value = Qnil;
13379 char *tmp_data = NULL;
13380 Atom actual_type;
13381 int actual_format;
13382 unsigned long actual_size, bytes_remaining;
13383
13384 CHECK_STRING (prop);
13385 BLOCK_INPUT;
13386 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13387 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13388 prop_atom, 0, 0, False, XA_STRING,
13389 &actual_type, &actual_format, &actual_size,
13390 &bytes_remaining, (unsigned char **) &tmp_data);
13391 if (rc == Success)
13392 {
13393 int size = bytes_remaining;
13394
13395 XFree (tmp_data);
13396 tmp_data = NULL;
13397
13398 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13399 prop_atom, 0, bytes_remaining,
13400 False, XA_STRING,
13401 &actual_type, &actual_format,
13402 &actual_size, &bytes_remaining,
13403 (unsigned char **) &tmp_data);
13404 if (rc == Success)
13405 prop_value = make_string (tmp_data, size);
13406
13407 XFree (tmp_data);
13408 }
13409
13410 UNBLOCK_INPUT;
13411
13412 return prop_value;
13413
13414 #endif /* TODO */
13415 return Qnil;
13416 }
13417
13418
13419 \f
13420 /***********************************************************************
13421 Busy cursor
13422 ***********************************************************************/
13423
13424 /* If non-null, an asynchronous timer that, when it expires, displays
13425 an hourglass cursor on all frames. */
13426
13427 static struct atimer *hourglass_atimer;
13428
13429 /* Non-zero means an hourglass cursor is currently shown. */
13430
13431 static int hourglass_shown_p;
13432
13433 /* Number of seconds to wait before displaying an hourglass cursor. */
13434
13435 static Lisp_Object Vhourglass_delay;
13436
13437 /* Default number of seconds to wait before displaying an hourglass
13438 cursor. */
13439
13440 #define DEFAULT_HOURGLASS_DELAY 1
13441
13442 /* Function prototypes. */
13443
13444 static void show_hourglass P_ ((struct atimer *));
13445 static void hide_hourglass P_ ((void));
13446
13447
13448 /* Cancel a currently active hourglass timer, and start a new one. */
13449
13450 void
13451 start_hourglass ()
13452 {
13453 #if 0 /* TODO: cursor shape changes. */
13454 EMACS_TIME delay;
13455 int secs, usecs = 0;
13456
13457 cancel_hourglass ();
13458
13459 if (INTEGERP (Vhourglass_delay)
13460 && XINT (Vhourglass_delay) > 0)
13461 secs = XFASTINT (Vhourglass_delay);
13462 else if (FLOATP (Vhourglass_delay)
13463 && XFLOAT_DATA (Vhourglass_delay) > 0)
13464 {
13465 Lisp_Object tem;
13466 tem = Ftruncate (Vhourglass_delay, Qnil);
13467 secs = XFASTINT (tem);
13468 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
13469 }
13470 else
13471 secs = DEFAULT_HOURGLASS_DELAY;
13472
13473 EMACS_SET_SECS_USECS (delay, secs, usecs);
13474 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13475 show_hourglass, NULL);
13476 #endif
13477 }
13478
13479
13480 /* Cancel the hourglass cursor timer if active, hide an hourglass
13481 cursor if shown. */
13482
13483 void
13484 cancel_hourglass ()
13485 {
13486 if (hourglass_atimer)
13487 {
13488 cancel_atimer (hourglass_atimer);
13489 hourglass_atimer = NULL;
13490 }
13491
13492 if (hourglass_shown_p)
13493 hide_hourglass ();
13494 }
13495
13496
13497 /* Timer function of hourglass_atimer. TIMER is equal to
13498 hourglass_atimer.
13499
13500 Display an hourglass cursor on all frames by mapping the frames'
13501 hourglass_window. Set the hourglass_p flag in the frames'
13502 output_data.x structure to indicate that an hourglass cursor is
13503 shown on the frames. */
13504
13505 static void
13506 show_hourglass (timer)
13507 struct atimer *timer;
13508 {
13509 #if 0 /* TODO: cursor shape changes. */
13510 /* The timer implementation will cancel this timer automatically
13511 after this function has run. Set hourglass_atimer to null
13512 so that we know the timer doesn't have to be canceled. */
13513 hourglass_atimer = NULL;
13514
13515 if (!hourglass_shown_p)
13516 {
13517 Lisp_Object rest, frame;
13518
13519 BLOCK_INPUT;
13520
13521 FOR_EACH_FRAME (rest, frame)
13522 if (FRAME_W32_P (XFRAME (frame)))
13523 {
13524 struct frame *f = XFRAME (frame);
13525
13526 f->output_data.w32->hourglass_p = 1;
13527
13528 if (!f->output_data.w32->hourglass_window)
13529 {
13530 unsigned long mask = CWCursor;
13531 XSetWindowAttributes attrs;
13532
13533 attrs.cursor = f->output_data.w32->hourglass_cursor;
13534
13535 f->output_data.w32->hourglass_window
13536 = XCreateWindow (FRAME_X_DISPLAY (f),
13537 FRAME_OUTER_WINDOW (f),
13538 0, 0, 32000, 32000, 0, 0,
13539 InputOnly,
13540 CopyFromParent,
13541 mask, &attrs);
13542 }
13543
13544 XMapRaised (FRAME_X_DISPLAY (f),
13545 f->output_data.w32->hourglass_window);
13546 XFlush (FRAME_X_DISPLAY (f));
13547 }
13548
13549 hourglass_shown_p = 1;
13550 UNBLOCK_INPUT;
13551 }
13552 #endif
13553 }
13554
13555
13556 /* Hide the hourglass cursor on all frames, if it is currently shown. */
13557
13558 static void
13559 hide_hourglass ()
13560 {
13561 #if 0 /* TODO: cursor shape changes. */
13562 if (hourglass_shown_p)
13563 {
13564 Lisp_Object rest, frame;
13565
13566 BLOCK_INPUT;
13567 FOR_EACH_FRAME (rest, frame)
13568 {
13569 struct frame *f = XFRAME (frame);
13570
13571 if (FRAME_W32_P (f)
13572 /* Watch out for newly created frames. */
13573 && f->output_data.x->hourglass_window)
13574 {
13575 XUnmapWindow (FRAME_X_DISPLAY (f),
13576 f->output_data.x->hourglass_window);
13577 /* Sync here because XTread_socket looks at the
13578 hourglass_p flag that is reset to zero below. */
13579 XSync (FRAME_X_DISPLAY (f), False);
13580 f->output_data.x->hourglass_p = 0;
13581 }
13582 }
13583
13584 hourglass_shown_p = 0;
13585 UNBLOCK_INPUT;
13586 }
13587 #endif
13588 }
13589
13590
13591 \f
13592 /***********************************************************************
13593 Tool tips
13594 ***********************************************************************/
13595
13596 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
13597 Lisp_Object, Lisp_Object));
13598 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13599 Lisp_Object, int, int, int *, int *));
13600
13601 /* The frame of a currently visible tooltip. */
13602
13603 Lisp_Object tip_frame;
13604
13605 /* If non-nil, a timer started that hides the last tooltip when it
13606 fires. */
13607
13608 Lisp_Object tip_timer;
13609 Window tip_window;
13610
13611 /* If non-nil, a vector of 3 elements containing the last args
13612 with which x-show-tip was called. See there. */
13613
13614 Lisp_Object last_show_tip_args;
13615
13616 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13617
13618 Lisp_Object Vx_max_tooltip_size;
13619
13620
13621 static Lisp_Object
13622 unwind_create_tip_frame (frame)
13623 Lisp_Object frame;
13624 {
13625 Lisp_Object deleted;
13626
13627 deleted = unwind_create_frame (frame);
13628 if (EQ (deleted, Qt))
13629 {
13630 tip_window = NULL;
13631 tip_frame = Qnil;
13632 }
13633
13634 return deleted;
13635 }
13636
13637
13638 /* Create a frame for a tooltip on the display described by DPYINFO.
13639 PARMS is a list of frame parameters. TEXT is the string to
13640 display in the tip frame. Value is the frame.
13641
13642 Note that functions called here, esp. x_default_parameter can
13643 signal errors, for instance when a specified color name is
13644 undefined. We have to make sure that we're in a consistent state
13645 when this happens. */
13646
13647 static Lisp_Object
13648 x_create_tip_frame (dpyinfo, parms, text)
13649 struct w32_display_info *dpyinfo;
13650 Lisp_Object parms, text;
13651 {
13652 struct frame *f;
13653 Lisp_Object frame, tem;
13654 Lisp_Object name;
13655 long window_prompting = 0;
13656 int width, height;
13657 int count = BINDING_STACK_SIZE ();
13658 struct gcpro gcpro1, gcpro2, gcpro3;
13659 struct kboard *kb;
13660 int face_change_count_before = face_change_count;
13661 Lisp_Object buffer;
13662 struct buffer *old_buffer;
13663
13664 check_w32 ();
13665
13666 /* Use this general default value to start with until we know if
13667 this frame has a specified name. */
13668 Vx_resource_name = Vinvocation_name;
13669
13670 #ifdef MULTI_KBOARD
13671 kb = dpyinfo->kboard;
13672 #else
13673 kb = &the_only_kboard;
13674 #endif
13675
13676 /* Get the name of the frame to use for resource lookup. */
13677 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13678 if (!STRINGP (name)
13679 && !EQ (name, Qunbound)
13680 && !NILP (name))
13681 error ("Invalid frame name--not a string or nil");
13682 Vx_resource_name = name;
13683
13684 frame = Qnil;
13685 GCPRO3 (parms, name, frame);
13686 /* Make a frame without minibuffer nor mode-line. */
13687 f = make_frame (0);
13688 f->wants_modeline = 0;
13689 XSETFRAME (frame, f);
13690
13691 buffer = Fget_buffer_create (build_string (" *tip*"));
13692 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13693 old_buffer = current_buffer;
13694 set_buffer_internal_1 (XBUFFER (buffer));
13695 current_buffer->truncate_lines = Qnil;
13696 Ferase_buffer ();
13697 Finsert (1, &text);
13698 set_buffer_internal_1 (old_buffer);
13699
13700 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
13701 record_unwind_protect (unwind_create_tip_frame, frame);
13702
13703 /* By setting the output method, we're essentially saying that
13704 the frame is live, as per FRAME_LIVE_P. If we get a signal
13705 from this point on, x_destroy_window might screw up reference
13706 counts etc. */
13707 f->output_method = output_w32;
13708 f->output_data.w32 =
13709 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13710 bzero (f->output_data.w32, sizeof (struct w32_output));
13711
13712 FRAME_FONTSET (f) = -1;
13713 f->icon_name = Qnil;
13714
13715 #if 0 /* GLYPH_DEBUG TODO: image support. */
13716 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13717 dpyinfo_refcount = dpyinfo->reference_count;
13718 #endif /* GLYPH_DEBUG */
13719 #ifdef MULTI_KBOARD
13720 FRAME_KBOARD (f) = kb;
13721 #endif
13722 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13723 f->output_data.w32->explicit_parent = 0;
13724
13725 /* Set the name; the functions to which we pass f expect the name to
13726 be set. */
13727 if (EQ (name, Qunbound) || NILP (name))
13728 {
13729 f->name = build_string (dpyinfo->w32_id_name);
13730 f->explicit_name = 0;
13731 }
13732 else
13733 {
13734 f->name = name;
13735 f->explicit_name = 1;
13736 /* use the frame's title when getting resources for this frame. */
13737 specbind (Qx_resource_name, name);
13738 }
13739
13740 /* Extract the window parameters from the supplied values
13741 that are needed to determine window geometry. */
13742 {
13743 Lisp_Object font;
13744
13745 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13746
13747 BLOCK_INPUT;
13748 /* First, try whatever font the caller has specified. */
13749 if (STRINGP (font))
13750 {
13751 tem = Fquery_fontset (font, Qnil);
13752 if (STRINGP (tem))
13753 font = x_new_fontset (f, XSTRING (tem)->data);
13754 else
13755 font = x_new_font (f, XSTRING (font)->data);
13756 }
13757
13758 /* Try out a font which we hope has bold and italic variations. */
13759 if (!STRINGP (font))
13760 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
13761 if (! STRINGP (font))
13762 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
13763 /* If those didn't work, look for something which will at least work. */
13764 if (! STRINGP (font))
13765 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
13766 UNBLOCK_INPUT;
13767 if (! STRINGP (font))
13768 font = build_string ("Fixedsys");
13769
13770 x_default_parameter (f, parms, Qfont, font,
13771 "font", "Font", RES_TYPE_STRING);
13772 }
13773
13774 x_default_parameter (f, parms, Qborder_width, make_number (2),
13775 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
13776 /* This defaults to 2 in order to match xterm. We recognize either
13777 internalBorderWidth or internalBorder (which is what xterm calls
13778 it). */
13779 if (NILP (Fassq (Qinternal_border_width, parms)))
13780 {
13781 Lisp_Object value;
13782
13783 value = w32_get_arg (parms, Qinternal_border_width,
13784 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13785 if (! EQ (value, Qunbound))
13786 parms = Fcons (Fcons (Qinternal_border_width, value),
13787 parms);
13788 }
13789 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
13790 "internalBorderWidth", "internalBorderWidth",
13791 RES_TYPE_NUMBER);
13792
13793 /* Also do the stuff which must be set before the window exists. */
13794 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13795 "foreground", "Foreground", RES_TYPE_STRING);
13796 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13797 "background", "Background", RES_TYPE_STRING);
13798 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13799 "pointerColor", "Foreground", RES_TYPE_STRING);
13800 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13801 "cursorColor", "Foreground", RES_TYPE_STRING);
13802 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13803 "borderColor", "BorderColor", RES_TYPE_STRING);
13804
13805 /* Init faces before x_default_parameter is called for scroll-bar
13806 parameters because that function calls x_set_scroll_bar_width,
13807 which calls change_frame_size, which calls Fset_window_buffer,
13808 which runs hooks, which call Fvertical_motion. At the end, we
13809 end up in init_iterator with a null face cache, which should not
13810 happen. */
13811 init_frame_faces (f);
13812
13813 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
13814 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13815
13816 window_prompting = x_figure_window_size (f, parms);
13817
13818 /* No fringes on tip frame. */
13819 f->output_data.w32->fringes_extra = 0;
13820 f->output_data.w32->fringe_cols = 0;
13821 f->output_data.w32->left_fringe_width = 0;
13822 f->output_data.w32->right_fringe_width = 0;
13823
13824 if (window_prompting & XNegative)
13825 {
13826 if (window_prompting & YNegative)
13827 f->output_data.w32->win_gravity = SouthEastGravity;
13828 else
13829 f->output_data.w32->win_gravity = NorthEastGravity;
13830 }
13831 else
13832 {
13833 if (window_prompting & YNegative)
13834 f->output_data.w32->win_gravity = SouthWestGravity;
13835 else
13836 f->output_data.w32->win_gravity = NorthWestGravity;
13837 }
13838
13839 f->output_data.w32->size_hint_flags = window_prompting;
13840
13841 BLOCK_INPUT;
13842 my_create_tip_window (f);
13843 UNBLOCK_INPUT;
13844
13845 x_make_gc (f);
13846
13847 x_default_parameter (f, parms, Qauto_raise, Qnil,
13848 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13849 x_default_parameter (f, parms, Qauto_lower, Qnil,
13850 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13851 x_default_parameter (f, parms, Qcursor_type, Qbox,
13852 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13853
13854 /* Dimensions, especially f->height, must be done via change_frame_size.
13855 Change will not be effected unless different from the current
13856 f->height. */
13857 width = f->width;
13858 height = f->height;
13859 f->height = 0;
13860 SET_FRAME_WIDTH (f, 0);
13861 change_frame_size (f, height, width, 1, 0, 0);
13862
13863 /* Set up faces after all frame parameters are known. This call
13864 also merges in face attributes specified for new frames.
13865
13866 Frame parameters may be changed if .Xdefaults contains
13867 specifications for the default font. For example, if there is an
13868 `Emacs.default.attributeBackground: pink', the `background-color'
13869 attribute of the frame get's set, which let's the internal border
13870 of the tooltip frame appear in pink. Prevent this. */
13871 {
13872 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13873
13874 /* Set tip_frame here, so that */
13875 tip_frame = frame;
13876 call1 (Qface_set_after_frame_default, frame);
13877
13878 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13879 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13880 Qnil));
13881 }
13882
13883 f->no_split = 1;
13884
13885 UNGCPRO;
13886
13887 /* It is now ok to make the frame official even if we get an error
13888 below. And the frame needs to be on Vframe_list or making it
13889 visible won't work. */
13890 Vframe_list = Fcons (frame, Vframe_list);
13891
13892 /* Now that the frame is official, it counts as a reference to
13893 its display. */
13894 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13895
13896 /* Setting attributes of faces of the tooltip frame from resources
13897 and similar will increment face_change_count, which leads to the
13898 clearing of all current matrices. Since this isn't necessary
13899 here, avoid it by resetting face_change_count to the value it
13900 had before we created the tip frame. */
13901 face_change_count = face_change_count_before;
13902
13903 /* Discard the unwind_protect. */
13904 return unbind_to (count, frame);
13905 }
13906
13907
13908 /* Compute where to display tip frame F. PARMS is the list of frame
13909 parameters for F. DX and DY are specified offsets from the current
13910 location of the mouse. WIDTH and HEIGHT are the width and height
13911 of the tooltip. Return coordinates relative to the root window of
13912 the display in *ROOT_X, and *ROOT_Y. */
13913
13914 static void
13915 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13916 struct frame *f;
13917 Lisp_Object parms, dx, dy;
13918 int width, height;
13919 int *root_x, *root_y;
13920 {
13921 Lisp_Object left, top;
13922
13923 /* User-specified position? */
13924 left = Fcdr (Fassq (Qleft, parms));
13925 top = Fcdr (Fassq (Qtop, parms));
13926
13927 /* Move the tooltip window where the mouse pointer is. Resize and
13928 show it. */
13929 if (!INTEGERP (left) || !INTEGERP (top))
13930 {
13931 POINT pt;
13932
13933 BLOCK_INPUT;
13934 GetCursorPos (&pt);
13935 *root_x = pt.x;
13936 *root_y = pt.y;
13937 UNBLOCK_INPUT;
13938 }
13939
13940 if (INTEGERP (top))
13941 *root_y = XINT (top);
13942 else if (*root_y + XINT (dy) - height < 0)
13943 *root_y -= XINT (dy);
13944 else
13945 {
13946 *root_y -= height;
13947 *root_y += XINT (dy);
13948 }
13949
13950 if (INTEGERP (left))
13951 *root_x = XINT (left);
13952 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13953 /* It fits to the right of the pointer. */
13954 *root_x += XINT (dx);
13955 else if (width + XINT (dx) <= *root_x)
13956 /* It fits to the left of the pointer. */
13957 *root_x -= width + XINT (dx);
13958 else
13959 /* Put it left justified on the screen -- it ought to fit that way. */
13960 *root_x = 0;
13961 }
13962
13963
13964 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13965 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13966 A tooltip window is a small window displaying a string.
13967
13968 FRAME nil or omitted means use the selected frame.
13969
13970 PARMS is an optional list of frame parameters which can be
13971 used to change the tooltip's appearance.
13972
13973 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13974 means use the default timeout of 5 seconds.
13975
13976 If the list of frame parameters PARAMS contains a `left' parameter,
13977 the tooltip is displayed at that x-position. Otherwise it is
13978 displayed at the mouse position, with offset DX added (default is 5 if
13979 DX isn't specified). Likewise for the y-position; if a `top' frame
13980 parameter is specified, it determines the y-position of the tooltip
13981 window, otherwise it is displayed at the mouse position, with offset
13982 DY added (default is -10).
13983
13984 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13985 Text larger than the specified size is clipped. */)
13986 (string, frame, parms, timeout, dx, dy)
13987 Lisp_Object string, frame, parms, timeout, dx, dy;
13988 {
13989 struct frame *f;
13990 struct window *w;
13991 int root_x, root_y;
13992 struct buffer *old_buffer;
13993 struct text_pos pos;
13994 int i, width, height;
13995 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13996 int old_windows_or_buffers_changed = windows_or_buffers_changed;
13997 int count = BINDING_STACK_SIZE ();
13998
13999 specbind (Qinhibit_redisplay, Qt);
14000
14001 GCPRO4 (string, parms, frame, timeout);
14002
14003 CHECK_STRING (string);
14004 f = check_x_frame (frame);
14005 if (NILP (timeout))
14006 timeout = make_number (5);
14007 else
14008 CHECK_NATNUM (timeout);
14009
14010 if (NILP (dx))
14011 dx = make_number (5);
14012 else
14013 CHECK_NUMBER (dx);
14014
14015 if (NILP (dy))
14016 dy = make_number (-10);
14017 else
14018 CHECK_NUMBER (dy);
14019
14020 if (NILP (last_show_tip_args))
14021 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14022
14023 if (!NILP (tip_frame))
14024 {
14025 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14026 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14027 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14028
14029 if (EQ (frame, last_frame)
14030 && !NILP (Fequal (last_string, string))
14031 && !NILP (Fequal (last_parms, parms)))
14032 {
14033 struct frame *f = XFRAME (tip_frame);
14034
14035 /* Only DX and DY have changed. */
14036 if (!NILP (tip_timer))
14037 {
14038 Lisp_Object timer = tip_timer;
14039 tip_timer = Qnil;
14040 call1 (Qcancel_timer, timer);
14041 }
14042
14043 BLOCK_INPUT;
14044 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14045 PIXEL_HEIGHT (f), &root_x, &root_y);
14046
14047 /* Put tooltip in topmost group and in position. */
14048 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14049 root_x, root_y, 0, 0,
14050 SWP_NOSIZE | SWP_NOACTIVATE);
14051
14052 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14053 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14054 0, 0, 0, 0,
14055 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14056
14057 UNBLOCK_INPUT;
14058 goto start_timer;
14059 }
14060 }
14061
14062 /* Hide a previous tip, if any. */
14063 Fx_hide_tip ();
14064
14065 ASET (last_show_tip_args, 0, string);
14066 ASET (last_show_tip_args, 1, frame);
14067 ASET (last_show_tip_args, 2, parms);
14068
14069 /* Add default values to frame parameters. */
14070 if (NILP (Fassq (Qname, parms)))
14071 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14072 if (NILP (Fassq (Qinternal_border_width, parms)))
14073 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14074 if (NILP (Fassq (Qborder_width, parms)))
14075 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14076 if (NILP (Fassq (Qborder_color, parms)))
14077 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14078 if (NILP (Fassq (Qbackground_color, parms)))
14079 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14080 parms);
14081
14082 /* Block input until the tip has been fully drawn, to avoid crashes
14083 when drawing tips in menus. */
14084 BLOCK_INPUT;
14085
14086 /* Create a frame for the tooltip, and record it in the global
14087 variable tip_frame. */
14088 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
14089 f = XFRAME (frame);
14090
14091 /* Set up the frame's root window. */
14092 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14093 w->left = w->top = make_number (0);
14094
14095 if (CONSP (Vx_max_tooltip_size)
14096 && INTEGERP (XCAR (Vx_max_tooltip_size))
14097 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14098 && INTEGERP (XCDR (Vx_max_tooltip_size))
14099 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14100 {
14101 w->width = XCAR (Vx_max_tooltip_size);
14102 w->height = XCDR (Vx_max_tooltip_size);
14103 }
14104 else
14105 {
14106 w->width = make_number (80);
14107 w->height = make_number (40);
14108 }
14109
14110 f->window_width = XINT (w->width);
14111 adjust_glyphs (f);
14112 w->pseudo_window_p = 1;
14113
14114 /* Display the tooltip text in a temporary buffer. */
14115 old_buffer = current_buffer;
14116 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14117 current_buffer->truncate_lines = Qnil;
14118 clear_glyph_matrix (w->desired_matrix);
14119 clear_glyph_matrix (w->current_matrix);
14120 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14121 try_window (FRAME_ROOT_WINDOW (f), pos);
14122
14123 /* Compute width and height of the tooltip. */
14124 width = height = 0;
14125 for (i = 0; i < w->desired_matrix->nrows; ++i)
14126 {
14127 struct glyph_row *row = &w->desired_matrix->rows[i];
14128 struct glyph *last;
14129 int row_width;
14130
14131 /* Stop at the first empty row at the end. */
14132 if (!row->enabled_p || !row->displays_text_p)
14133 break;
14134
14135 /* Let the row go over the full width of the frame. */
14136 row->full_width_p = 1;
14137
14138 #ifdef TODO /* Investigate why some fonts need more width than is
14139 calculated for some tooltips. */
14140 /* There's a glyph at the end of rows that is use to place
14141 the cursor there. Don't include the width of this glyph. */
14142 if (row->used[TEXT_AREA])
14143 {
14144 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14145 row_width = row->pixel_width - last->pixel_width;
14146 }
14147 else
14148 #endif
14149 row_width = row->pixel_width;
14150
14151 /* TODO: find why tips do not draw along baseline as instructed. */
14152 height += row->height;
14153 width = max (width, row_width);
14154 }
14155
14156 /* Add the frame's internal border to the width and height the X
14157 window should have. */
14158 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14159 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14160
14161 /* Move the tooltip window where the mouse pointer is. Resize and
14162 show it. */
14163 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
14164
14165 {
14166 /* Adjust Window size to take border into account. */
14167 RECT rect;
14168 rect.left = rect.top = 0;
14169 rect.right = width;
14170 rect.bottom = height;
14171 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14172 FRAME_EXTERNAL_MENU_BAR (f));
14173
14174 /* Position and size tooltip, and put it in the topmost group. */
14175 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14176 root_x, root_y, rect.right - rect.left,
14177 rect.bottom - rect.top, SWP_NOACTIVATE);
14178
14179 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14180 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14181 0, 0, 0, 0,
14182 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14183
14184 /* Let redisplay know that we have made the frame visible already. */
14185 f->async_visible = 1;
14186
14187 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14188 }
14189
14190 /* Draw into the window. */
14191 w->must_be_updated_p = 1;
14192 update_single_window (w, 1);
14193
14194 UNBLOCK_INPUT;
14195
14196 /* Restore original current buffer. */
14197 set_buffer_internal_1 (old_buffer);
14198 windows_or_buffers_changed = old_windows_or_buffers_changed;
14199
14200 start_timer:
14201 /* Let the tip disappear after timeout seconds. */
14202 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14203 intern ("x-hide-tip"));
14204
14205 UNGCPRO;
14206 return unbind_to (count, Qnil);
14207 }
14208
14209
14210 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
14211 doc: /* Hide the current tooltip window, if there is any.
14212 Value is t if tooltip was open, nil otherwise. */)
14213 ()
14214 {
14215 int count;
14216 Lisp_Object deleted, frame, timer;
14217 struct gcpro gcpro1, gcpro2;
14218
14219 /* Return quickly if nothing to do. */
14220 if (NILP (tip_timer) && NILP (tip_frame))
14221 return Qnil;
14222
14223 frame = tip_frame;
14224 timer = tip_timer;
14225 GCPRO2 (frame, timer);
14226 tip_frame = tip_timer = deleted = Qnil;
14227
14228 count = BINDING_STACK_SIZE ();
14229 specbind (Qinhibit_redisplay, Qt);
14230 specbind (Qinhibit_quit, Qt);
14231
14232 if (!NILP (timer))
14233 call1 (Qcancel_timer, timer);
14234
14235 if (FRAMEP (frame))
14236 {
14237 Fdelete_frame (frame, Qnil);
14238 deleted = Qt;
14239 }
14240
14241 UNGCPRO;
14242 return unbind_to (count, deleted);
14243 }
14244
14245
14246 \f
14247 /***********************************************************************
14248 File selection dialog
14249 ***********************************************************************/
14250 extern Lisp_Object Qfile_name_history;
14251
14252 /* Callback for altering the behaviour of the Open File dialog.
14253 Makes the Filename text field contain "Current Directory" and be
14254 read-only when "Directories" is selected in the filter. This
14255 allows us to work around the fact that the standard Open File
14256 dialog does not support directories. */
14257 UINT CALLBACK
14258 file_dialog_callback (hwnd, msg, wParam, lParam)
14259 HWND hwnd;
14260 UINT msg;
14261 WPARAM wParam;
14262 LPARAM lParam;
14263 {
14264 if (msg == WM_NOTIFY)
14265 {
14266 OFNOTIFY * notify = (OFNOTIFY *)lParam;
14267 /* Detect when the Filter dropdown is changed. */
14268 if (notify->hdr.code == CDN_TYPECHANGE)
14269 {
14270 HWND dialog = GetParent (hwnd);
14271 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
14272
14273 /* Directories is in index 2. */
14274 if (notify->lpOFN->nFilterIndex == 2)
14275 {
14276 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14277 "Current Directory");
14278 EnableWindow (edit_control, FALSE);
14279 }
14280 else
14281 {
14282 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14283 "");
14284 EnableWindow (edit_control, TRUE);
14285 }
14286 }
14287 }
14288 return 0;
14289 }
14290
14291 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
14292 doc: /* Read file name, prompting with PROMPT in directory DIR.
14293 Use a file selection dialog.
14294 Select DEFAULT-FILENAME in the dialog's file selection box, if
14295 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
14296 (prompt, dir, default_filename, mustmatch)
14297 Lisp_Object prompt, dir, default_filename, mustmatch;
14298 {
14299 struct frame *f = SELECTED_FRAME ();
14300 Lisp_Object file = Qnil;
14301 int count = specpdl_ptr - specpdl;
14302 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14303 char filename[MAX_PATH + 1];
14304 char init_dir[MAX_PATH + 1];
14305
14306 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
14307 CHECK_STRING (prompt);
14308 CHECK_STRING (dir);
14309
14310 /* Create the dialog with PROMPT as title, using DIR as initial
14311 directory and using "*" as pattern. */
14312 dir = Fexpand_file_name (dir, Qnil);
14313 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14314 init_dir[MAX_PATH] = '\0';
14315 unixtodos_filename (init_dir);
14316
14317 if (STRINGP (default_filename))
14318 {
14319 char *file_name_only;
14320 char *full_path_name = XSTRING (default_filename)->data;
14321
14322 unixtodos_filename (full_path_name);
14323
14324 file_name_only = strrchr (full_path_name, '\\');
14325 if (!file_name_only)
14326 file_name_only = full_path_name;
14327 else
14328 {
14329 file_name_only++;
14330 }
14331
14332 strncpy (filename, file_name_only, MAX_PATH);
14333 filename[MAX_PATH] = '\0';
14334 }
14335 else
14336 filename[0] = '\0';
14337
14338 {
14339 OPENFILENAME file_details;
14340
14341 /* Prevent redisplay. */
14342 specbind (Qinhibit_redisplay, Qt);
14343 BLOCK_INPUT;
14344
14345 bzero (&file_details, sizeof (file_details));
14346 file_details.lStructSize = sizeof (file_details);
14347 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14348 /* Undocumented Bug in Common File Dialog:
14349 If a filter is not specified, shell links are not resolved. */
14350 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
14351 file_details.lpstrFile = filename;
14352 file_details.nMaxFile = sizeof (filename);
14353 file_details.lpstrInitialDir = init_dir;
14354 file_details.lpstrTitle = XSTRING (prompt)->data;
14355 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
14356 | OFN_EXPLORER | OFN_ENABLEHOOK);
14357 if (!NILP (mustmatch))
14358 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14359
14360 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
14361
14362 if (GetOpenFileName (&file_details))
14363 {
14364 dostounix_filename (filename);
14365 if (file_details.nFilterIndex == 2)
14366 {
14367 /* "Folder Only" selected - strip dummy file name. */
14368 char * last = strrchr (filename, '/');
14369 *last = '\0';
14370 }
14371
14372 file = DECODE_FILE(build_string (filename));
14373 }
14374 /* User cancelled the dialog without making a selection. */
14375 else if (!CommDlgExtendedError ())
14376 file = Qnil;
14377 /* An error occurred, fallback on reading from the mini-buffer. */
14378 else
14379 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14380 dir, mustmatch, dir, Qfile_name_history,
14381 default_filename, Qnil);
14382
14383 UNBLOCK_INPUT;
14384 file = unbind_to (count, file);
14385 }
14386
14387 UNGCPRO;
14388
14389 /* Make "Cancel" equivalent to C-g. */
14390 if (NILP (file))
14391 Fsignal (Qquit, Qnil);
14392
14393 return unbind_to (count, file);
14394 }
14395
14396
14397 \f
14398 /***********************************************************************
14399 w32 specialized functions
14400 ***********************************************************************/
14401
14402 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
14403 doc: /* Select a font using the W32 font dialog.
14404 Returns an X font string corresponding to the selection. */)
14405 (frame, include_proportional)
14406 Lisp_Object frame, include_proportional;
14407 {
14408 FRAME_PTR f = check_x_frame (frame);
14409 CHOOSEFONT cf;
14410 LOGFONT lf;
14411 TEXTMETRIC tm;
14412 HDC hdc;
14413 HANDLE oldobj;
14414 char buf[100];
14415
14416 bzero (&cf, sizeof (cf));
14417 bzero (&lf, sizeof (lf));
14418
14419 cf.lStructSize = sizeof (cf);
14420 cf.hwndOwner = FRAME_W32_WINDOW (f);
14421 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14422
14423 /* Unless include_proportional is non-nil, limit the selection to
14424 monospaced fonts. */
14425 if (NILP (include_proportional))
14426 cf.Flags |= CF_FIXEDPITCHONLY;
14427
14428 cf.lpLogFont = &lf;
14429
14430 /* Initialize as much of the font details as we can from the current
14431 default font. */
14432 hdc = GetDC (FRAME_W32_WINDOW (f));
14433 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14434 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14435 if (GetTextMetrics (hdc, &tm))
14436 {
14437 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14438 lf.lfWeight = tm.tmWeight;
14439 lf.lfItalic = tm.tmItalic;
14440 lf.lfUnderline = tm.tmUnderlined;
14441 lf.lfStrikeOut = tm.tmStruckOut;
14442 lf.lfCharSet = tm.tmCharSet;
14443 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14444 }
14445 SelectObject (hdc, oldobj);
14446 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
14447
14448 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
14449 return Qnil;
14450
14451 return build_string (buf);
14452 }
14453
14454 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14455 Sw32_send_sys_command, 1, 2, 0,
14456 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
14457 Some useful values for command are #xf030 to maximise frame (#xf020
14458 to minimize), #xf120 to restore frame to original size, and #xf100
14459 to activate the menubar for keyboard access. #xf140 activates the
14460 screen saver if defined.
14461
14462 If optional parameter FRAME is not specified, use selected frame. */)
14463 (command, frame)
14464 Lisp_Object command, frame;
14465 {
14466 FRAME_PTR f = check_x_frame (frame);
14467
14468 CHECK_NUMBER (command);
14469
14470 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
14471
14472 return Qnil;
14473 }
14474
14475 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
14476 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14477 This is a wrapper around the ShellExecute system function, which
14478 invokes the application registered to handle OPERATION for DOCUMENT.
14479 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14480 nil for the default action), and DOCUMENT is typically the name of a
14481 document file or URL, but can also be a program executable to run or
14482 a directory to open in the Windows Explorer.
14483
14484 If DOCUMENT is a program executable, PARAMETERS can be a string
14485 containing command line parameters, but otherwise should be nil.
14486
14487 SHOW-FLAG can be used to control whether the invoked application is hidden
14488 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14489 otherwise it is an integer representing a ShowWindow flag:
14490
14491 0 - start hidden
14492 1 - start normally
14493 3 - start maximized
14494 6 - start minimized */)
14495 (operation, document, parameters, show_flag)
14496 Lisp_Object operation, document, parameters, show_flag;
14497 {
14498 Lisp_Object current_dir;
14499
14500 CHECK_STRING (document);
14501
14502 /* Encode filename and current directory. */
14503 current_dir = ENCODE_FILE (current_buffer->directory);
14504 document = ENCODE_FILE (document);
14505 if ((int) ShellExecute (NULL,
14506 (STRINGP (operation) ?
14507 XSTRING (operation)->data : NULL),
14508 XSTRING (document)->data,
14509 (STRINGP (parameters) ?
14510 XSTRING (parameters)->data : NULL),
14511 XSTRING (current_dir)->data,
14512 (INTEGERP (show_flag) ?
14513 XINT (show_flag) : SW_SHOWDEFAULT))
14514 > 32)
14515 return Qt;
14516 error ("ShellExecute failed: %s", w32_strerror (0));
14517 }
14518
14519 /* Lookup virtual keycode from string representing the name of a
14520 non-ascii keystroke into the corresponding virtual key, using
14521 lispy_function_keys. */
14522 static int
14523 lookup_vk_code (char *key)
14524 {
14525 int i;
14526
14527 for (i = 0; i < 256; i++)
14528 if (lispy_function_keys[i] != 0
14529 && strcmp (lispy_function_keys[i], key) == 0)
14530 return i;
14531
14532 return -1;
14533 }
14534
14535 /* Convert a one-element vector style key sequence to a hot key
14536 definition. */
14537 static int
14538 w32_parse_hot_key (key)
14539 Lisp_Object key;
14540 {
14541 /* Copied from Fdefine_key and store_in_keymap. */
14542 register Lisp_Object c;
14543 int vk_code;
14544 int lisp_modifiers;
14545 int w32_modifiers;
14546 struct gcpro gcpro1;
14547
14548 CHECK_VECTOR (key);
14549
14550 if (XFASTINT (Flength (key)) != 1)
14551 return Qnil;
14552
14553 GCPRO1 (key);
14554
14555 c = Faref (key, make_number (0));
14556
14557 if (CONSP (c) && lucid_event_type_list_p (c))
14558 c = Fevent_convert_list (c);
14559
14560 UNGCPRO;
14561
14562 if (! INTEGERP (c) && ! SYMBOLP (c))
14563 error ("Key definition is invalid");
14564
14565 /* Work out the base key and the modifiers. */
14566 if (SYMBOLP (c))
14567 {
14568 c = parse_modifiers (c);
14569 lisp_modifiers = Fcar (Fcdr (c));
14570 c = Fcar (c);
14571 if (!SYMBOLP (c))
14572 abort ();
14573 vk_code = lookup_vk_code (XSTRING (SYMBOL_NAME (c))->data);
14574 }
14575 else if (INTEGERP (c))
14576 {
14577 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14578 /* Many ascii characters are their own virtual key code. */
14579 vk_code = XINT (c) & CHARACTERBITS;
14580 }
14581
14582 if (vk_code < 0 || vk_code > 255)
14583 return Qnil;
14584
14585 if ((lisp_modifiers & meta_modifier) != 0
14586 && !NILP (Vw32_alt_is_meta))
14587 lisp_modifiers |= alt_modifier;
14588
14589 /* Supply defs missing from mingw32. */
14590 #ifndef MOD_ALT
14591 #define MOD_ALT 0x0001
14592 #define MOD_CONTROL 0x0002
14593 #define MOD_SHIFT 0x0004
14594 #define MOD_WIN 0x0008
14595 #endif
14596
14597 /* Convert lisp modifiers to Windows hot-key form. */
14598 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14599 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14600 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14601 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14602
14603 return HOTKEY (vk_code, w32_modifiers);
14604 }
14605
14606 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14607 Sw32_register_hot_key, 1, 1, 0,
14608 doc: /* Register KEY as a hot-key combination.
14609 Certain key combinations like Alt-Tab are reserved for system use on
14610 Windows, and therefore are normally intercepted by the system. However,
14611 most of these key combinations can be received by registering them as
14612 hot-keys, overriding their special meaning.
14613
14614 KEY must be a one element key definition in vector form that would be
14615 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14616 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14617 is always interpreted as the Windows modifier keys.
14618
14619 The return value is the hotkey-id if registered, otherwise nil. */)
14620 (key)
14621 Lisp_Object key;
14622 {
14623 key = w32_parse_hot_key (key);
14624
14625 if (NILP (Fmemq (key, w32_grabbed_keys)))
14626 {
14627 /* Reuse an empty slot if possible. */
14628 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14629
14630 /* Safe to add new key to list, even if we have focus. */
14631 if (NILP (item))
14632 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14633 else
14634 XSETCAR (item, key);
14635
14636 /* Notify input thread about new hot-key definition, so that it
14637 takes effect without needing to switch focus. */
14638 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14639 (WPARAM) key, 0);
14640 }
14641
14642 return key;
14643 }
14644
14645 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14646 Sw32_unregister_hot_key, 1, 1, 0,
14647 doc: /* Unregister HOTKEY as a hot-key combination. */)
14648 (key)
14649 Lisp_Object key;
14650 {
14651 Lisp_Object item;
14652
14653 if (!INTEGERP (key))
14654 key = w32_parse_hot_key (key);
14655
14656 item = Fmemq (key, w32_grabbed_keys);
14657
14658 if (!NILP (item))
14659 {
14660 /* Notify input thread about hot-key definition being removed, so
14661 that it takes effect without needing focus switch. */
14662 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14663 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14664 {
14665 MSG msg;
14666 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14667 }
14668 return Qt;
14669 }
14670 return Qnil;
14671 }
14672
14673 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14674 Sw32_registered_hot_keys, 0, 0, 0,
14675 doc: /* Return list of registered hot-key IDs. */)
14676 ()
14677 {
14678 return Fcopy_sequence (w32_grabbed_keys);
14679 }
14680
14681 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14682 Sw32_reconstruct_hot_key, 1, 1, 0,
14683 doc: /* Convert hot-key ID to a lisp key combination. */)
14684 (hotkeyid)
14685 Lisp_Object hotkeyid;
14686 {
14687 int vk_code, w32_modifiers;
14688 Lisp_Object key;
14689
14690 CHECK_NUMBER (hotkeyid);
14691
14692 vk_code = HOTKEY_VK_CODE (hotkeyid);
14693 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14694
14695 if (lispy_function_keys[vk_code])
14696 key = intern (lispy_function_keys[vk_code]);
14697 else
14698 key = make_number (vk_code);
14699
14700 key = Fcons (key, Qnil);
14701 if (w32_modifiers & MOD_SHIFT)
14702 key = Fcons (Qshift, key);
14703 if (w32_modifiers & MOD_CONTROL)
14704 key = Fcons (Qctrl, key);
14705 if (w32_modifiers & MOD_ALT)
14706 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
14707 if (w32_modifiers & MOD_WIN)
14708 key = Fcons (Qhyper, key);
14709
14710 return key;
14711 }
14712
14713 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14714 Sw32_toggle_lock_key, 1, 2, 0,
14715 doc: /* Toggle the state of the lock key KEY.
14716 KEY can be `capslock', `kp-numlock', or `scroll'.
14717 If the optional parameter NEW-STATE is a number, then the state of KEY
14718 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
14719 (key, new_state)
14720 Lisp_Object key, new_state;
14721 {
14722 int vk_code;
14723
14724 if (EQ (key, intern ("capslock")))
14725 vk_code = VK_CAPITAL;
14726 else if (EQ (key, intern ("kp-numlock")))
14727 vk_code = VK_NUMLOCK;
14728 else if (EQ (key, intern ("scroll")))
14729 vk_code = VK_SCROLL;
14730 else
14731 return Qnil;
14732
14733 if (!dwWindowsThreadId)
14734 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14735
14736 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14737 (WPARAM) vk_code, (LPARAM) new_state))
14738 {
14739 MSG msg;
14740 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14741 return make_number (msg.wParam);
14742 }
14743 return Qnil;
14744 }
14745 \f
14746 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
14747 doc: /* Return storage information about the file system FILENAME is on.
14748 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14749 storage of the file system, FREE is the free storage, and AVAIL is the
14750 storage available to a non-superuser. All 3 numbers are in bytes.
14751 If the underlying system call fails, value is nil. */)
14752 (filename)
14753 Lisp_Object filename;
14754 {
14755 Lisp_Object encoded, value;
14756
14757 CHECK_STRING (filename);
14758 filename = Fexpand_file_name (filename, Qnil);
14759 encoded = ENCODE_FILE (filename);
14760
14761 value = Qnil;
14762
14763 /* Determining the required information on Windows turns out, sadly,
14764 to be more involved than one would hope. The original Win32 api
14765 call for this will return bogus information on some systems, but we
14766 must dynamically probe for the replacement api, since that was
14767 added rather late on. */
14768 {
14769 HMODULE hKernel = GetModuleHandle ("kernel32");
14770 BOOL (*pfn_GetDiskFreeSpaceEx)
14771 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14772 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14773
14774 /* On Windows, we may need to specify the root directory of the
14775 volume holding FILENAME. */
14776 char rootname[MAX_PATH];
14777 char *name = XSTRING (encoded)->data;
14778
14779 /* find the root name of the volume if given */
14780 if (isalpha (name[0]) && name[1] == ':')
14781 {
14782 rootname[0] = name[0];
14783 rootname[1] = name[1];
14784 rootname[2] = '\\';
14785 rootname[3] = 0;
14786 }
14787 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14788 {
14789 char *str = rootname;
14790 int slashes = 4;
14791 do
14792 {
14793 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14794 break;
14795 *str++ = *name++;
14796 }
14797 while ( *name );
14798
14799 *str++ = '\\';
14800 *str = 0;
14801 }
14802
14803 if (pfn_GetDiskFreeSpaceEx)
14804 {
14805 /* Unsigned large integers cannot be cast to double, so
14806 use signed ones instead. */
14807 LARGE_INTEGER availbytes;
14808 LARGE_INTEGER freebytes;
14809 LARGE_INTEGER totalbytes;
14810
14811 if (pfn_GetDiskFreeSpaceEx(rootname,
14812 (ULARGE_INTEGER *)&availbytes,
14813 (ULARGE_INTEGER *)&totalbytes,
14814 (ULARGE_INTEGER *)&freebytes))
14815 value = list3 (make_float ((double) totalbytes.QuadPart),
14816 make_float ((double) freebytes.QuadPart),
14817 make_float ((double) availbytes.QuadPart));
14818 }
14819 else
14820 {
14821 DWORD sectors_per_cluster;
14822 DWORD bytes_per_sector;
14823 DWORD free_clusters;
14824 DWORD total_clusters;
14825
14826 if (GetDiskFreeSpace(rootname,
14827 &sectors_per_cluster,
14828 &bytes_per_sector,
14829 &free_clusters,
14830 &total_clusters))
14831 value = list3 (make_float ((double) total_clusters
14832 * sectors_per_cluster * bytes_per_sector),
14833 make_float ((double) free_clusters
14834 * sectors_per_cluster * bytes_per_sector),
14835 make_float ((double) free_clusters
14836 * sectors_per_cluster * bytes_per_sector));
14837 }
14838 }
14839
14840 return value;
14841 }
14842 \f
14843 /***********************************************************************
14844 Initialization
14845 ***********************************************************************/
14846
14847 void
14848 syms_of_w32fns ()
14849 {
14850 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14851
14852 /* This is zero if not using MS-Windows. */
14853 w32_in_use = 0;
14854
14855 /* TrackMouseEvent not available in all versions of Windows, so must load
14856 it dynamically. Do it once, here, instead of every time it is used. */
14857 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14858 track_mouse_window = NULL;
14859
14860 w32_visible_system_caret_hwnd = NULL;
14861
14862 Qauto_raise = intern ("auto-raise");
14863 staticpro (&Qauto_raise);
14864 Qauto_lower = intern ("auto-lower");
14865 staticpro (&Qauto_lower);
14866 Qbar = intern ("bar");
14867 staticpro (&Qbar);
14868 Qhbar = intern ("hbar");
14869 staticpro (&Qhbar);
14870 Qborder_color = intern ("border-color");
14871 staticpro (&Qborder_color);
14872 Qborder_width = intern ("border-width");
14873 staticpro (&Qborder_width);
14874 Qbox = intern ("box");
14875 staticpro (&Qbox);
14876 Qcursor_color = intern ("cursor-color");
14877 staticpro (&Qcursor_color);
14878 Qcursor_type = intern ("cursor-type");
14879 staticpro (&Qcursor_type);
14880 Qgeometry = intern ("geometry");
14881 staticpro (&Qgeometry);
14882 Qicon_left = intern ("icon-left");
14883 staticpro (&Qicon_left);
14884 Qicon_top = intern ("icon-top");
14885 staticpro (&Qicon_top);
14886 Qicon_type = intern ("icon-type");
14887 staticpro (&Qicon_type);
14888 Qicon_name = intern ("icon-name");
14889 staticpro (&Qicon_name);
14890 Qinternal_border_width = intern ("internal-border-width");
14891 staticpro (&Qinternal_border_width);
14892 Qleft = intern ("left");
14893 staticpro (&Qleft);
14894 Qright = intern ("right");
14895 staticpro (&Qright);
14896 Qmouse_color = intern ("mouse-color");
14897 staticpro (&Qmouse_color);
14898 Qnone = intern ("none");
14899 staticpro (&Qnone);
14900 Qparent_id = intern ("parent-id");
14901 staticpro (&Qparent_id);
14902 Qscroll_bar_width = intern ("scroll-bar-width");
14903 staticpro (&Qscroll_bar_width);
14904 Qsuppress_icon = intern ("suppress-icon");
14905 staticpro (&Qsuppress_icon);
14906 Qundefined_color = intern ("undefined-color");
14907 staticpro (&Qundefined_color);
14908 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14909 staticpro (&Qvertical_scroll_bars);
14910 Qvisibility = intern ("visibility");
14911 staticpro (&Qvisibility);
14912 Qwindow_id = intern ("window-id");
14913 staticpro (&Qwindow_id);
14914 Qx_frame_parameter = intern ("x-frame-parameter");
14915 staticpro (&Qx_frame_parameter);
14916 Qx_resource_name = intern ("x-resource-name");
14917 staticpro (&Qx_resource_name);
14918 Quser_position = intern ("user-position");
14919 staticpro (&Quser_position);
14920 Quser_size = intern ("user-size");
14921 staticpro (&Quser_size);
14922 Qscreen_gamma = intern ("screen-gamma");
14923 staticpro (&Qscreen_gamma);
14924 Qline_spacing = intern ("line-spacing");
14925 staticpro (&Qline_spacing);
14926 Qcenter = intern ("center");
14927 staticpro (&Qcenter);
14928 Qcancel_timer = intern ("cancel-timer");
14929 staticpro (&Qcancel_timer);
14930 Qfullscreen = intern ("fullscreen");
14931 staticpro (&Qfullscreen);
14932 Qfullwidth = intern ("fullwidth");
14933 staticpro (&Qfullwidth);
14934 Qfullheight = intern ("fullheight");
14935 staticpro (&Qfullheight);
14936 Qfullboth = intern ("fullboth");
14937 staticpro (&Qfullboth);
14938
14939 Qhyper = intern ("hyper");
14940 staticpro (&Qhyper);
14941 Qsuper = intern ("super");
14942 staticpro (&Qsuper);
14943 Qmeta = intern ("meta");
14944 staticpro (&Qmeta);
14945 Qalt = intern ("alt");
14946 staticpro (&Qalt);
14947 Qctrl = intern ("ctrl");
14948 staticpro (&Qctrl);
14949 Qcontrol = intern ("control");
14950 staticpro (&Qcontrol);
14951 Qshift = intern ("shift");
14952 staticpro (&Qshift);
14953 /* This is the end of symbol initialization. */
14954
14955 /* Text property `display' should be nonsticky by default. */
14956 Vtext_property_default_nonsticky
14957 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14958
14959
14960 Qlaplace = intern ("laplace");
14961 staticpro (&Qlaplace);
14962 Qemboss = intern ("emboss");
14963 staticpro (&Qemboss);
14964 Qedge_detection = intern ("edge-detection");
14965 staticpro (&Qedge_detection);
14966 Qheuristic = intern ("heuristic");
14967 staticpro (&Qheuristic);
14968 QCmatrix = intern (":matrix");
14969 staticpro (&QCmatrix);
14970 QCcolor_adjustment = intern (":color-adjustment");
14971 staticpro (&QCcolor_adjustment);
14972 QCmask = intern (":mask");
14973 staticpro (&QCmask);
14974
14975 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14976 staticpro (&Qface_set_after_frame_default);
14977
14978 Fput (Qundefined_color, Qerror_conditions,
14979 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14980 Fput (Qundefined_color, Qerror_message,
14981 build_string ("Undefined color"));
14982
14983 staticpro (&w32_grabbed_keys);
14984 w32_grabbed_keys = Qnil;
14985
14986 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14987 doc: /* An array of color name mappings for windows. */);
14988 Vw32_color_map = Qnil;
14989
14990 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14991 doc: /* Non-nil if alt key presses are passed on to Windows.
14992 When non-nil, for example, alt pressed and released and then space will
14993 open the System menu. When nil, Emacs silently swallows alt key events. */);
14994 Vw32_pass_alt_to_system = Qnil;
14995
14996 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
14997 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14998 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
14999 Vw32_alt_is_meta = Qt;
15000
15001 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
15002 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
15003 XSETINT (Vw32_quit_key, 0);
15004
15005 DEFVAR_LISP ("w32-pass-lwindow-to-system",
15006 &Vw32_pass_lwindow_to_system,
15007 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
15008 When non-nil, the Start menu is opened by tapping the key. */);
15009 Vw32_pass_lwindow_to_system = Qt;
15010
15011 DEFVAR_LISP ("w32-pass-rwindow-to-system",
15012 &Vw32_pass_rwindow_to_system,
15013 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
15014 When non-nil, the Start menu is opened by tapping the key. */);
15015 Vw32_pass_rwindow_to_system = Qt;
15016
15017 DEFVAR_INT ("w32-phantom-key-code",
15018 &Vw32_phantom_key_code,
15019 doc: /* Virtual key code used to generate \"phantom\" key presses.
15020 Value is a number between 0 and 255.
15021
15022 Phantom key presses are generated in order to stop the system from
15023 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
15024 `w32-pass-rwindow-to-system' is nil. */);
15025 /* Although 255 is technically not a valid key code, it works and
15026 means that this hack won't interfere with any real key code. */
15027 Vw32_phantom_key_code = 255;
15028
15029 DEFVAR_LISP ("w32-enable-num-lock",
15030 &Vw32_enable_num_lock,
15031 doc: /* Non-nil if Num Lock should act normally.
15032 Set to nil to see Num Lock as the key `kp-numlock'. */);
15033 Vw32_enable_num_lock = Qt;
15034
15035 DEFVAR_LISP ("w32-enable-caps-lock",
15036 &Vw32_enable_caps_lock,
15037 doc: /* Non-nil if Caps Lock should act normally.
15038 Set to nil to see Caps Lock as the key `capslock'. */);
15039 Vw32_enable_caps_lock = Qt;
15040
15041 DEFVAR_LISP ("w32-scroll-lock-modifier",
15042 &Vw32_scroll_lock_modifier,
15043 doc: /* Modifier to use for the Scroll Lock on state.
15044 The value can be hyper, super, meta, alt, control or shift for the
15045 respective modifier, or nil to see Scroll Lock as the key `scroll'.
15046 Any other value will cause the key to be ignored. */);
15047 Vw32_scroll_lock_modifier = Qt;
15048
15049 DEFVAR_LISP ("w32-lwindow-modifier",
15050 &Vw32_lwindow_modifier,
15051 doc: /* Modifier to use for the left \"Windows\" key.
15052 The value can be hyper, super, meta, alt, control or shift for the
15053 respective modifier, or nil to appear as the key `lwindow'.
15054 Any other value will cause the key to be ignored. */);
15055 Vw32_lwindow_modifier = Qnil;
15056
15057 DEFVAR_LISP ("w32-rwindow-modifier",
15058 &Vw32_rwindow_modifier,
15059 doc: /* Modifier to use for the right \"Windows\" key.
15060 The value can be hyper, super, meta, alt, control or shift for the
15061 respective modifier, or nil to appear as the key `rwindow'.
15062 Any other value will cause the key to be ignored. */);
15063 Vw32_rwindow_modifier = Qnil;
15064
15065 DEFVAR_LISP ("w32-apps-modifier",
15066 &Vw32_apps_modifier,
15067 doc: /* Modifier to use for the \"Apps\" key.
15068 The value can be hyper, super, meta, alt, control or shift for the
15069 respective modifier, or nil to appear as the key `apps'.
15070 Any other value will cause the key to be ignored. */);
15071 Vw32_apps_modifier = Qnil;
15072
15073 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
15074 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
15075 w32_enable_synthesized_fonts = 0;
15076
15077 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
15078 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
15079 Vw32_enable_palette = Qt;
15080
15081 DEFVAR_INT ("w32-mouse-button-tolerance",
15082 &Vw32_mouse_button_tolerance,
15083 doc: /* Analogue of double click interval for faking middle mouse events.
15084 The value is the minimum time in milliseconds that must elapse between
15085 left/right button down events before they are considered distinct events.
15086 If both mouse buttons are depressed within this interval, a middle mouse
15087 button down event is generated instead. */);
15088 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
15089
15090 DEFVAR_INT ("w32-mouse-move-interval",
15091 &Vw32_mouse_move_interval,
15092 doc: /* Minimum interval between mouse move events.
15093 The value is the minimum time in milliseconds that must elapse between
15094 successive mouse move (or scroll bar drag) events before they are
15095 reported as lisp events. */);
15096 XSETINT (Vw32_mouse_move_interval, 0);
15097
15098 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15099 &w32_pass_extra_mouse_buttons_to_system,
15100 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15101 Recent versions of Windows support mice with up to five buttons.
15102 Since most applications don't support these extra buttons, most mouse
15103 drivers will allow you to map them to functions at the system level.
15104 If this variable is non-nil, Emacs will pass them on, allowing the
15105 system to handle them. */);
15106 w32_pass_extra_mouse_buttons_to_system = 0;
15107
15108 init_x_parm_symbols ();
15109
15110 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
15111 doc: /* List of directories to search for bitmap files for w32. */);
15112 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15113
15114 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
15115 doc: /* The shape of the pointer when over text.
15116 Changing the value does not affect existing frames
15117 unless you set the mouse color. */);
15118 Vx_pointer_shape = Qnil;
15119
15120 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
15121 doc: /* The name Emacs uses to look up resources; for internal use only.
15122 `x-get-resource' uses this as the first component of the instance name
15123 when requesting resource values.
15124 Emacs initially sets `x-resource-name' to the name under which Emacs
15125 was invoked, or to the value specified with the `-name' or `-rn'
15126 switches, if present. */);
15127 Vx_resource_name = Qnil;
15128
15129 Vx_nontext_pointer_shape = Qnil;
15130
15131 Vx_mode_pointer_shape = Qnil;
15132
15133 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
15134 doc: /* The shape of the pointer when Emacs is busy.
15135 This variable takes effect when you create a new frame
15136 or when you set the mouse color. */);
15137 Vx_hourglass_pointer_shape = Qnil;
15138
15139 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
15140 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
15141 display_hourglass_p = 1;
15142
15143 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
15144 doc: /* *Seconds to wait before displaying an hourglass pointer.
15145 Value must be an integer or float. */);
15146 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
15147
15148 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
15149 &Vx_sensitive_text_pointer_shape,
15150 doc: /* The shape of the pointer when over mouse-sensitive text.
15151 This variable takes effect when you create a new frame
15152 or when you set the mouse color. */);
15153 Vx_sensitive_text_pointer_shape = Qnil;
15154
15155 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15156 &Vx_window_horizontal_drag_shape,
15157 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15158 This variable takes effect when you create a new frame
15159 or when you set the mouse color. */);
15160 Vx_window_horizontal_drag_shape = Qnil;
15161
15162 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
15163 doc: /* A string indicating the foreground color of the cursor box. */);
15164 Vx_cursor_fore_pixel = Qnil;
15165
15166 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
15167 doc: /* Maximum size for tooltips.
15168 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
15169 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15170
15171 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
15172 doc: /* Non-nil if no window manager is in use.
15173 Emacs doesn't try to figure this out; this is always nil
15174 unless you set it to something else. */);
15175 /* We don't have any way to find this out, so set it to nil
15176 and maybe the user would like to set it to t. */
15177 Vx_no_window_manager = Qnil;
15178
15179 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15180 &Vx_pixel_size_width_font_regexp,
15181 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15182
15183 Since Emacs gets width of a font matching with this regexp from
15184 PIXEL_SIZE field of the name, font finding mechanism gets faster for
15185 such a font. This is especially effective for such large fonts as
15186 Chinese, Japanese, and Korean. */);
15187 Vx_pixel_size_width_font_regexp = Qnil;
15188
15189 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
15190 doc: /* Time after which cached images are removed from the cache.
15191 When an image has not been displayed this many seconds, remove it
15192 from the image cache. Value must be an integer or nil with nil
15193 meaning don't clear the cache. */);
15194 Vimage_cache_eviction_delay = make_number (30 * 60);
15195
15196 DEFVAR_LISP ("w32-bdf-filename-alist",
15197 &Vw32_bdf_filename_alist,
15198 doc: /* List of bdf fonts and their corresponding filenames. */);
15199 Vw32_bdf_filename_alist = Qnil;
15200
15201 DEFVAR_BOOL ("w32-strict-fontnames",
15202 &w32_strict_fontnames,
15203 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15204 Default is nil, which allows old fontnames that are not XLFD compliant,
15205 and allows third-party CJK display to work by specifying false charset
15206 fields to trick Emacs into translating to Big5, SJIS etc.
15207 Setting this to t will prevent wrong fonts being selected when
15208 fontsets are automatically created. */);
15209 w32_strict_fontnames = 0;
15210
15211 DEFVAR_BOOL ("w32-strict-painting",
15212 &w32_strict_painting,
15213 doc: /* Non-nil means use strict rules for repainting frames.
15214 Set this to nil to get the old behaviour for repainting; this should
15215 only be necessary if the default setting causes problems. */);
15216 w32_strict_painting = 1;
15217
15218 DEFVAR_LISP ("w32-charset-info-alist",
15219 &Vw32_charset_info_alist,
15220 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15221 Each entry should be of the form:
15222
15223 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15224
15225 where CHARSET_NAME is a string used in font names to identify the charset,
15226 WINDOWS_CHARSET is a symbol that can be one of:
15227 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15228 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15229 w32-charset-chinesebig5,
15230 #ifdef JOHAB_CHARSET
15231 w32-charset-johab, w32-charset-hebrew,
15232 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15233 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15234 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
15235 #endif
15236 #ifdef UNICODE_CHARSET
15237 w32-charset-unicode,
15238 #endif
15239 or w32-charset-oem.
15240 CODEPAGE should be an integer specifying the codepage that should be used
15241 to display the character set, t to do no translation and output as Unicode,
15242 or nil to do no translation and output as 8 bit (or multibyte on far-east
15243 versions of Windows) characters. */);
15244 Vw32_charset_info_alist = Qnil;
15245
15246 staticpro (&Qw32_charset_ansi);
15247 Qw32_charset_ansi = intern ("w32-charset-ansi");
15248 staticpro (&Qw32_charset_symbol);
15249 Qw32_charset_symbol = intern ("w32-charset-symbol");
15250 staticpro (&Qw32_charset_shiftjis);
15251 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
15252 staticpro (&Qw32_charset_hangeul);
15253 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
15254 staticpro (&Qw32_charset_chinesebig5);
15255 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15256 staticpro (&Qw32_charset_gb2312);
15257 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15258 staticpro (&Qw32_charset_oem);
15259 Qw32_charset_oem = intern ("w32-charset-oem");
15260
15261 #ifdef JOHAB_CHARSET
15262 {
15263 static int w32_extra_charsets_defined = 1;
15264 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15265 doc: /* Internal variable. */);
15266
15267 staticpro (&Qw32_charset_johab);
15268 Qw32_charset_johab = intern ("w32-charset-johab");
15269 staticpro (&Qw32_charset_easteurope);
15270 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15271 staticpro (&Qw32_charset_turkish);
15272 Qw32_charset_turkish = intern ("w32-charset-turkish");
15273 staticpro (&Qw32_charset_baltic);
15274 Qw32_charset_baltic = intern ("w32-charset-baltic");
15275 staticpro (&Qw32_charset_russian);
15276 Qw32_charset_russian = intern ("w32-charset-russian");
15277 staticpro (&Qw32_charset_arabic);
15278 Qw32_charset_arabic = intern ("w32-charset-arabic");
15279 staticpro (&Qw32_charset_greek);
15280 Qw32_charset_greek = intern ("w32-charset-greek");
15281 staticpro (&Qw32_charset_hebrew);
15282 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
15283 staticpro (&Qw32_charset_vietnamese);
15284 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
15285 staticpro (&Qw32_charset_thai);
15286 Qw32_charset_thai = intern ("w32-charset-thai");
15287 staticpro (&Qw32_charset_mac);
15288 Qw32_charset_mac = intern ("w32-charset-mac");
15289 }
15290 #endif
15291
15292 #ifdef UNICODE_CHARSET
15293 {
15294 static int w32_unicode_charset_defined = 1;
15295 DEFVAR_BOOL ("w32-unicode-charset-defined",
15296 &w32_unicode_charset_defined,
15297 doc: /* Internal variable. */);
15298
15299 staticpro (&Qw32_charset_unicode);
15300 Qw32_charset_unicode = intern ("w32-charset-unicode");
15301 #endif
15302
15303 defsubr (&Sx_get_resource);
15304 #if 0 /* TODO: Port to W32 */
15305 defsubr (&Sx_change_window_property);
15306 defsubr (&Sx_delete_window_property);
15307 defsubr (&Sx_window_property);
15308 #endif
15309 defsubr (&Sxw_display_color_p);
15310 defsubr (&Sx_display_grayscale_p);
15311 defsubr (&Sxw_color_defined_p);
15312 defsubr (&Sxw_color_values);
15313 defsubr (&Sx_server_max_request_size);
15314 defsubr (&Sx_server_vendor);
15315 defsubr (&Sx_server_version);
15316 defsubr (&Sx_display_pixel_width);
15317 defsubr (&Sx_display_pixel_height);
15318 defsubr (&Sx_display_mm_width);
15319 defsubr (&Sx_display_mm_height);
15320 defsubr (&Sx_display_screens);
15321 defsubr (&Sx_display_planes);
15322 defsubr (&Sx_display_color_cells);
15323 defsubr (&Sx_display_visual_class);
15324 defsubr (&Sx_display_backing_store);
15325 defsubr (&Sx_display_save_under);
15326 defsubr (&Sx_parse_geometry);
15327 defsubr (&Sx_create_frame);
15328 defsubr (&Sx_open_connection);
15329 defsubr (&Sx_close_connection);
15330 defsubr (&Sx_display_list);
15331 defsubr (&Sx_synchronize);
15332
15333 /* W32 specific functions */
15334
15335 defsubr (&Sw32_focus_frame);
15336 defsubr (&Sw32_select_font);
15337 defsubr (&Sw32_define_rgb_color);
15338 defsubr (&Sw32_default_color_map);
15339 defsubr (&Sw32_load_color_file);
15340 defsubr (&Sw32_send_sys_command);
15341 defsubr (&Sw32_shell_execute);
15342 defsubr (&Sw32_register_hot_key);
15343 defsubr (&Sw32_unregister_hot_key);
15344 defsubr (&Sw32_registered_hot_keys);
15345 defsubr (&Sw32_reconstruct_hot_key);
15346 defsubr (&Sw32_toggle_lock_key);
15347 defsubr (&Sw32_find_bdf_fonts);
15348
15349 defsubr (&Sfile_system_info);
15350
15351 /* Setting callback functions for fontset handler. */
15352 get_font_info_func = w32_get_font_info;
15353
15354 #if 0 /* This function pointer doesn't seem to be used anywhere.
15355 And the pointer assigned has the wrong type, anyway. */
15356 list_fonts_func = w32_list_fonts;
15357 #endif
15358
15359 load_font_func = w32_load_font;
15360 find_ccl_program_func = w32_find_ccl_program;
15361 query_font_func = w32_query_font;
15362 set_frame_fontset_func = x_set_font;
15363 check_window_system_func = check_w32;
15364
15365 /* Images. */
15366 Qxbm = intern ("xbm");
15367 staticpro (&Qxbm);
15368 QCconversion = intern (":conversion");
15369 staticpro (&QCconversion);
15370 QCheuristic_mask = intern (":heuristic-mask");
15371 staticpro (&QCheuristic_mask);
15372 QCcolor_symbols = intern (":color-symbols");
15373 staticpro (&QCcolor_symbols);
15374 QCascent = intern (":ascent");
15375 staticpro (&QCascent);
15376 QCmargin = intern (":margin");
15377 staticpro (&QCmargin);
15378 QCrelief = intern (":relief");
15379 staticpro (&QCrelief);
15380 Qpostscript = intern ("postscript");
15381 staticpro (&Qpostscript);
15382 #if 0 /* TODO: These need entries at top of file. */
15383 QCloader = intern (":loader");
15384 staticpro (&QCloader);
15385 QCbounding_box = intern (":bounding-box");
15386 staticpro (&QCbounding_box);
15387 QCpt_width = intern (":pt-width");
15388 staticpro (&QCpt_width);
15389 QCpt_height = intern (":pt-height");
15390 staticpro (&QCpt_height);
15391 #endif
15392 QCindex = intern (":index");
15393 staticpro (&QCindex);
15394 Qpbm = intern ("pbm");
15395 staticpro (&Qpbm);
15396
15397 #if HAVE_XPM
15398 Qxpm = intern ("xpm");
15399 staticpro (&Qxpm);
15400 #endif
15401
15402 #if HAVE_JPEG
15403 Qjpeg = intern ("jpeg");
15404 staticpro (&Qjpeg);
15405 #endif
15406
15407 #if HAVE_TIFF
15408 Qtiff = intern ("tiff");
15409 staticpro (&Qtiff);
15410 #endif
15411
15412 #if HAVE_GIF
15413 Qgif = intern ("gif");
15414 staticpro (&Qgif);
15415 #endif
15416
15417 #if HAVE_PNG
15418 Qpng = intern ("png");
15419 staticpro (&Qpng);
15420 #endif
15421
15422 defsubr (&Sclear_image_cache);
15423 defsubr (&Simage_size);
15424 defsubr (&Simage_mask_p);
15425
15426 #if GLYPH_DEBUG
15427 defsubr (&Simagep);
15428 defsubr (&Slookup_image);
15429 #endif
15430
15431 hourglass_atimer = NULL;
15432 hourglass_shown_p = 0;
15433 defsubr (&Sx_show_tip);
15434 defsubr (&Sx_hide_tip);
15435 tip_timer = Qnil;
15436 staticpro (&tip_timer);
15437 tip_frame = Qnil;
15438 staticpro (&tip_frame);
15439
15440 last_show_tip_args = Qnil;
15441 staticpro (&last_show_tip_args);
15442
15443 defsubr (&Sx_file_dialog);
15444 }
15445
15446
15447 void
15448 init_xfns ()
15449 {
15450 image_types = NULL;
15451 Vimage_types = Qnil;
15452
15453 define_image_type (&pbm_type);
15454 define_image_type (&xbm_type);
15455 #if 0 /* TODO : Image support for W32 */
15456 define_image_type (&gs_type);
15457 #endif
15458
15459 #if HAVE_XPM
15460 define_image_type (&xpm_type);
15461 #endif
15462
15463 #if HAVE_JPEG
15464 define_image_type (&jpeg_type);
15465 #endif
15466
15467 #if HAVE_TIFF
15468 define_image_type (&tiff_type);
15469 #endif
15470
15471 #if HAVE_GIF
15472 define_image_type (&gif_type);
15473 #endif
15474
15475 #if HAVE_PNG
15476 define_image_type (&png_type);
15477 #endif
15478 }
15479
15480 #undef abort
15481
15482 void
15483 w32_abort()
15484 {
15485 int button;
15486 button = MessageBox (NULL,
15487 "A fatal error has occurred!\n\n"
15488 "Select Abort to exit, Retry to debug, Ignore to continue",
15489 "Emacs Abort Dialog",
15490 MB_ICONEXCLAMATION | MB_TASKMODAL
15491 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15492 switch (button)
15493 {
15494 case IDRETRY:
15495 DebugBreak ();
15496 break;
15497 case IDIGNORE:
15498 break;
15499 case IDABORT:
15500 default:
15501 abort ();
15502 break;
15503 }
15504 }
15505
15506 /* For convenience when debugging. */
15507 int
15508 w32_last_error()
15509 {
15510 return GetLastError ();
15511 }