]> code.delx.au - gnu-emacs/blob - src/w32fns.c
*** empty log message ***
[gnu-emacs] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Added by Kevin Gallo */
23
24 #include <config.h>
25
26 #include <signal.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <errno.h>
30
31 #include "lisp.h"
32 #include "charset.h"
33 #include "dispextern.h"
34 #include "w32term.h"
35 #include "keyboard.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "buffer.h"
39 #include "fontset.h"
40 #include "intervals.h"
41 #include "blockinput.h"
42 #include "epaths.h"
43 #include "w32heap.h"
44 #include "termhooks.h"
45 #include "coding.h"
46 #include "ccl.h"
47 #include "systime.h"
48
49 #include "bitmaps/gray.xbm"
50
51 #include <commdlg.h>
52 #include <shellapi.h>
53 #include <ctype.h>
54
55 #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 = SPECPDL_INDEX ();
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 /* We explicitely disable composition handling because selection
6689 data should not contain any composition sequence. */
6690 coding.composing = COMPOSITION_DISABLED;
6691 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6692
6693 fontname = alloca(sizeof(*fontname) * bufsz);
6694 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6695 strlen(lplogfont->lfFaceName), bufsz - 1);
6696 *(fontname + coding.produced) = '\0';
6697
6698 /* Replace dashes with underscores so the dashes are not
6699 misinterpreted. */
6700 fontname_dash = fontname;
6701 while (fontname_dash = strchr (fontname_dash, '-'))
6702 *fontname_dash = '_';
6703
6704 if (lplogfont->lfHeight)
6705 {
6706 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6707 sprintf (height_dpi, "%u",
6708 abs (lplogfont->lfHeight) * 720 / display_resy);
6709 }
6710 else
6711 {
6712 strcpy (height_pixels, "*");
6713 strcpy (height_dpi, "*");
6714 }
6715 if (lplogfont->lfWidth)
6716 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6717 else
6718 strcpy (width_pixels, "*");
6719
6720 _snprintf (lpxstr, len - 1,
6721 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6722 fonttype, /* foundry */
6723 fontname, /* family */
6724 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6725 lplogfont->lfItalic?'i':'r', /* slant */
6726 /* setwidth name */
6727 /* add style name */
6728 height_pixels, /* pixel size */
6729 height_dpi, /* point size */
6730 display_resx, /* resx */
6731 display_resy, /* resy */
6732 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6733 ? 'p' : 'c', /* spacing */
6734 width_pixels, /* avg width */
6735 specific_charset ? specific_charset
6736 : w32_to_x_charset (lplogfont->lfCharSet)
6737 /* charset registry and encoding */
6738 );
6739
6740 lpxstr[len - 1] = 0; /* just to be sure */
6741 return (TRUE);
6742 }
6743
6744 static BOOL
6745 x_to_w32_font (lpxstr, lplogfont)
6746 char * lpxstr;
6747 LOGFONT * lplogfont;
6748 {
6749 struct coding_system coding;
6750
6751 if (!lplogfont) return (FALSE);
6752
6753 memset (lplogfont, 0, sizeof (*lplogfont));
6754
6755 /* Set default value for each field. */
6756 #if 1
6757 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6758 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6759 lplogfont->lfQuality = DEFAULT_QUALITY;
6760 #else
6761 /* go for maximum quality */
6762 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6763 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6764 lplogfont->lfQuality = PROOF_QUALITY;
6765 #endif
6766
6767 lplogfont->lfCharSet = DEFAULT_CHARSET;
6768 lplogfont->lfWeight = FW_DONTCARE;
6769 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6770
6771 if (!lpxstr)
6772 return FALSE;
6773
6774 /* Provide a simple escape mechanism for specifying Windows font names
6775 * directly -- if font spec does not beginning with '-', assume this
6776 * format:
6777 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6778 */
6779
6780 if (*lpxstr == '-')
6781 {
6782 int fields, tem;
6783 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6784 width[10], resy[10], remainder[50];
6785 char * encoding;
6786 int dpi = (int) one_w32_display_info.resy;
6787
6788 fields = sscanf (lpxstr,
6789 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6790 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6791 if (fields == EOF)
6792 return (FALSE);
6793
6794 /* In the general case when wildcards cover more than one field,
6795 we don't know which field is which, so don't fill any in.
6796 However, we need to cope with this particular form, which is
6797 generated by font_list_1 (invoked by try_font_list):
6798 "-raster-6x10-*-gb2312*-*"
6799 and make sure to correctly parse the charset field. */
6800 if (fields == 3)
6801 {
6802 fields = sscanf (lpxstr,
6803 "-%*[^-]-%49[^-]-*-%49s",
6804 name, remainder);
6805 }
6806 else if (fields < 9)
6807 {
6808 fields = 0;
6809 remainder[0] = 0;
6810 }
6811
6812 if (fields > 0 && name[0] != '*')
6813 {
6814 int bufsize;
6815 unsigned char *buf;
6816
6817 setup_coding_system
6818 (Fcheck_coding_system (Vlocale_coding_system), &coding);
6819 coding.src_multibyte = 1;
6820 coding.dst_multibyte = 1;
6821 bufsize = encoding_buffer_size (&coding, strlen (name));
6822 buf = (unsigned char *) alloca (bufsize);
6823 coding.mode |= CODING_MODE_LAST_BLOCK;
6824 encode_coding (&coding, name, buf, strlen (name), bufsize);
6825 if (coding.produced >= LF_FACESIZE)
6826 coding.produced = LF_FACESIZE - 1;
6827 buf[coding.produced] = 0;
6828 strcpy (lplogfont->lfFaceName, buf);
6829 }
6830 else
6831 {
6832 lplogfont->lfFaceName[0] = '\0';
6833 }
6834
6835 fields--;
6836
6837 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6838
6839 fields--;
6840
6841 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6842
6843 fields--;
6844
6845 if (fields > 0 && pixels[0] != '*')
6846 lplogfont->lfHeight = atoi (pixels);
6847
6848 fields--;
6849 fields--;
6850 if (fields > 0 && resy[0] != '*')
6851 {
6852 tem = atoi (resy);
6853 if (tem > 0) dpi = tem;
6854 }
6855
6856 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6857 lplogfont->lfHeight = atoi (height) * dpi / 720;
6858
6859 if (fields > 0)
6860 lplogfont->lfPitchAndFamily =
6861 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6862
6863 fields--;
6864
6865 if (fields > 0 && width[0] != '*')
6866 lplogfont->lfWidth = atoi (width) / 10;
6867
6868 fields--;
6869
6870 /* Strip the trailing '-' if present. (it shouldn't be, as it
6871 fails the test against xlfd-tight-regexp in fontset.el). */
6872 {
6873 int len = strlen (remainder);
6874 if (len > 0 && remainder[len-1] == '-')
6875 remainder[len-1] = 0;
6876 }
6877 encoding = remainder;
6878 #if 0
6879 if (strncmp (encoding, "*-", 2) == 0)
6880 encoding += 2;
6881 #endif
6882 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6883 }
6884 else
6885 {
6886 int fields;
6887 char name[100], height[10], width[10], weight[20];
6888
6889 fields = sscanf (lpxstr,
6890 "%99[^:]:%9[^:]:%9[^:]:%19s",
6891 name, height, width, weight);
6892
6893 if (fields == EOF) return (FALSE);
6894
6895 if (fields > 0)
6896 {
6897 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6898 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6899 }
6900 else
6901 {
6902 lplogfont->lfFaceName[0] = 0;
6903 }
6904
6905 fields--;
6906
6907 if (fields > 0)
6908 lplogfont->lfHeight = atoi (height);
6909
6910 fields--;
6911
6912 if (fields > 0)
6913 lplogfont->lfWidth = atoi (width);
6914
6915 fields--;
6916
6917 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6918 }
6919
6920 /* This makes TrueType fonts work better. */
6921 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6922
6923 return (TRUE);
6924 }
6925
6926 /* Strip the pixel height and point height from the given xlfd, and
6927 return the pixel height. If no pixel height is specified, calculate
6928 one from the point height, or if that isn't defined either, return
6929 0 (which usually signifies a scalable font).
6930 */
6931 static int
6932 xlfd_strip_height (char *fontname)
6933 {
6934 int pixel_height, field_number;
6935 char *read_from, *write_to;
6936
6937 xassert (fontname);
6938
6939 pixel_height = field_number = 0;
6940 write_to = NULL;
6941
6942 /* Look for height fields. */
6943 for (read_from = fontname; *read_from; read_from++)
6944 {
6945 if (*read_from == '-')
6946 {
6947 field_number++;
6948 if (field_number == 7) /* Pixel height. */
6949 {
6950 read_from++;
6951 write_to = read_from;
6952
6953 /* Find end of field. */
6954 for (;*read_from && *read_from != '-'; read_from++)
6955 ;
6956
6957 /* Split the fontname at end of field. */
6958 if (*read_from)
6959 {
6960 *read_from = '\0';
6961 read_from++;
6962 }
6963 pixel_height = atoi (write_to);
6964 /* Blank out field. */
6965 if (read_from > write_to)
6966 {
6967 *write_to = '-';
6968 write_to++;
6969 }
6970 /* If the pixel height field is at the end (partial xlfd),
6971 return now. */
6972 else
6973 return pixel_height;
6974
6975 /* If we got a pixel height, the point height can be
6976 ignored. Just blank it out and break now. */
6977 if (pixel_height)
6978 {
6979 /* Find end of point size field. */
6980 for (; *read_from && *read_from != '-'; read_from++)
6981 ;
6982
6983 if (*read_from)
6984 read_from++;
6985
6986 /* Blank out the point size field. */
6987 if (read_from > write_to)
6988 {
6989 *write_to = '-';
6990 write_to++;
6991 }
6992 else
6993 return pixel_height;
6994
6995 break;
6996 }
6997 /* If the point height is already blank, break now. */
6998 if (*read_from == '-')
6999 {
7000 read_from++;
7001 break;
7002 }
7003 }
7004 else if (field_number == 8)
7005 {
7006 /* If we didn't get a pixel height, try to get the point
7007 height and convert that. */
7008 int point_size;
7009 char *point_size_start = read_from++;
7010
7011 /* Find end of field. */
7012 for (; *read_from && *read_from != '-'; read_from++)
7013 ;
7014
7015 if (*read_from)
7016 {
7017 *read_from = '\0';
7018 read_from++;
7019 }
7020
7021 point_size = atoi (point_size_start);
7022
7023 /* Convert to pixel height. */
7024 pixel_height = point_size
7025 * one_w32_display_info.height_in / 720;
7026
7027 /* Blank out this field and break. */
7028 *write_to = '-';
7029 write_to++;
7030 break;
7031 }
7032 }
7033 }
7034
7035 /* Shift the rest of the font spec into place. */
7036 if (write_to && read_from > write_to)
7037 {
7038 for (; *read_from; read_from++, write_to++)
7039 *write_to = *read_from;
7040 *write_to = '\0';
7041 }
7042
7043 return pixel_height;
7044 }
7045
7046 /* Assume parameter 1 is fully qualified, no wildcards. */
7047 static BOOL
7048 w32_font_match (fontname, pattern)
7049 char * fontname;
7050 char * pattern;
7051 {
7052 char *regex = alloca (strlen (pattern) * 2 + 3);
7053 char *font_name_copy = alloca (strlen (fontname) + 1);
7054 char *ptr;
7055
7056 /* Copy fontname so we can modify it during comparison. */
7057 strcpy (font_name_copy, fontname);
7058
7059 ptr = regex;
7060 *ptr++ = '^';
7061
7062 /* Turn pattern into a regexp and do a regexp match. */
7063 for (; *pattern; pattern++)
7064 {
7065 if (*pattern == '?')
7066 *ptr++ = '.';
7067 else if (*pattern == '*')
7068 {
7069 *ptr++ = '.';
7070 *ptr++ = '*';
7071 }
7072 else
7073 *ptr++ = *pattern;
7074 }
7075 *ptr = '$';
7076 *(ptr + 1) = '\0';
7077
7078 /* Strip out font heights and compare them seperately, since
7079 rounding error can cause mismatches. This also allows a
7080 comparison between a font that declares only a pixel height and a
7081 pattern that declares the point height.
7082 */
7083 {
7084 int font_height, pattern_height;
7085
7086 font_height = xlfd_strip_height (font_name_copy);
7087 pattern_height = xlfd_strip_height (regex);
7088
7089 /* Compare now, and don't bother doing expensive regexp matching
7090 if the heights differ. */
7091 if (font_height && pattern_height && (font_height != pattern_height))
7092 return FALSE;
7093 }
7094
7095 return (fast_c_string_match_ignore_case (build_string (regex),
7096 font_name_copy) >= 0);
7097 }
7098
7099 /* Callback functions, and a structure holding info they need, for
7100 listing system fonts on W32. We need one set of functions to do the
7101 job properly, but these don't work on NT 3.51 and earlier, so we
7102 have a second set which don't handle character sets properly to
7103 fall back on.
7104
7105 In both cases, there are two passes made. The first pass gets one
7106 font from each family, the second pass lists all the fonts from
7107 each family. */
7108
7109 typedef struct enumfont_t
7110 {
7111 HDC hdc;
7112 int numFonts;
7113 LOGFONT logfont;
7114 XFontStruct *size_ref;
7115 Lisp_Object pattern;
7116 Lisp_Object list;
7117 } enumfont_t;
7118
7119
7120 static void
7121 enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7122
7123
7124 static int CALLBACK
7125 enum_font_cb2 (lplf, lptm, FontType, lpef)
7126 ENUMLOGFONT * lplf;
7127 NEWTEXTMETRIC * lptm;
7128 int FontType;
7129 enumfont_t * lpef;
7130 {
7131 /* Ignore struck out and underlined versions of fonts. */
7132 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7133 return 1;
7134
7135 /* Only return fonts with names starting with @ if they were
7136 explicitly specified, since Microsoft uses an initial @ to
7137 denote fonts for vertical writing, without providing a more
7138 convenient way of identifying them. */
7139 if (lplf->elfLogFont.lfFaceName[0] == '@'
7140 && lpef->logfont.lfFaceName[0] != '@')
7141 return 1;
7142
7143 /* Check that the character set matches if it was specified */
7144 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7145 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
7146 return 1;
7147
7148 if (FontType == RASTER_FONTTYPE)
7149 {
7150 /* DBCS raster fonts have problems displaying, so skip them. */
7151 int charset = lplf->elfLogFont.lfCharSet;
7152 if (charset == SHIFTJIS_CHARSET
7153 || charset == HANGEUL_CHARSET
7154 || charset == CHINESEBIG5_CHARSET
7155 || charset == GB2312_CHARSET
7156 #ifdef JOHAB_CHARSET
7157 || charset == JOHAB_CHARSET
7158 #endif
7159 )
7160 return 1;
7161 }
7162
7163 {
7164 char buf[100];
7165 Lisp_Object width = Qnil;
7166 Lisp_Object charset_list = Qnil;
7167 char *charset = NULL;
7168
7169 /* Truetype fonts do not report their true metrics until loaded */
7170 if (FontType != RASTER_FONTTYPE)
7171 {
7172 if (!NILP (lpef->pattern))
7173 {
7174 /* Scalable fonts are as big as you want them to be. */
7175 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7176 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7177 width = make_number (lpef->logfont.lfWidth);
7178 }
7179 else
7180 {
7181 lplf->elfLogFont.lfHeight = 0;
7182 lplf->elfLogFont.lfWidth = 0;
7183 }
7184 }
7185
7186 /* Make sure the height used here is the same as everywhere
7187 else (ie character height, not cell height). */
7188 if (lplf->elfLogFont.lfHeight > 0)
7189 {
7190 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7191 if (FontType == RASTER_FONTTYPE)
7192 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7193 else
7194 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7195 }
7196
7197 if (!NILP (lpef->pattern))
7198 {
7199 charset = xlfd_charset_of_font (XSTRING(lpef->pattern)->data);
7200
7201 /* We already checked charsets above, but DEFAULT_CHARSET
7202 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7203 if (charset
7204 && strncmp (charset, "*-*", 3) != 0
7205 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7206 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7207 return 1;
7208 }
7209
7210 if (charset)
7211 charset_list = Fcons (build_string (charset), Qnil);
7212 else
7213 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
7214
7215 /* Loop through the charsets. */
7216 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
7217 {
7218 Lisp_Object this_charset = Fcar (charset_list);
7219 charset = XSTRING (this_charset)->data;
7220
7221 /* List bold and italic variations if w32-enable-synthesized-fonts
7222 is non-nil and this is a plain font. */
7223 if (w32_enable_synthesized_fonts
7224 && lplf->elfLogFont.lfWeight == FW_NORMAL
7225 && lplf->elfLogFont.lfItalic == FALSE)
7226 {
7227 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7228 charset, width);
7229 /* bold. */
7230 lplf->elfLogFont.lfWeight = FW_BOLD;
7231 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7232 charset, width);
7233 /* bold italic. */
7234 lplf->elfLogFont.lfItalic = TRUE;
7235 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7236 charset, width);
7237 /* italic. */
7238 lplf->elfLogFont.lfWeight = FW_NORMAL;
7239 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7240 charset, width);
7241 }
7242 else
7243 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7244 charset, width);
7245 }
7246 }
7247
7248 return 1;
7249 }
7250
7251 static void
7252 enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7253 enumfont_t * lpef;
7254 LOGFONT * logfont;
7255 char * match_charset;
7256 Lisp_Object width;
7257 {
7258 char buf[100];
7259
7260 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7261 return;
7262
7263 if (NILP (lpef->pattern)
7264 || w32_font_match (buf, XSTRING (lpef->pattern)->data))
7265 {
7266 /* Check if we already listed this font. This may happen if
7267 w32_enable_synthesized_fonts is non-nil, and there are real
7268 bold and italic versions of the font. */
7269 Lisp_Object font_name = build_string (buf);
7270 if (NILP (Fmember (font_name, lpef->list)))
7271 {
7272 Lisp_Object entry = Fcons (font_name, width);
7273 lpef->list = Fcons (entry, lpef->list);
7274 lpef->numFonts++;
7275 }
7276 }
7277 }
7278
7279
7280 static int CALLBACK
7281 enum_font_cb1 (lplf, lptm, FontType, lpef)
7282 ENUMLOGFONT * lplf;
7283 NEWTEXTMETRIC * lptm;
7284 int FontType;
7285 enumfont_t * lpef;
7286 {
7287 return EnumFontFamilies (lpef->hdc,
7288 lplf->elfLogFont.lfFaceName,
7289 (FONTENUMPROC) enum_font_cb2,
7290 (LPARAM) lpef);
7291 }
7292
7293
7294 static int CALLBACK
7295 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7296 ENUMLOGFONTEX * lplf;
7297 NEWTEXTMETRICEX * lptm;
7298 int font_type;
7299 enumfont_t * lpef;
7300 {
7301 /* We are not interested in the extra info we get back from the 'Ex
7302 version - only the fact that we get character set variations
7303 enumerated seperately. */
7304 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7305 font_type, lpef);
7306 }
7307
7308 static int CALLBACK
7309 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7310 ENUMLOGFONTEX * lplf;
7311 NEWTEXTMETRICEX * lptm;
7312 int font_type;
7313 enumfont_t * lpef;
7314 {
7315 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7316 FARPROC enum_font_families_ex
7317 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7318 /* We don't really expect EnumFontFamiliesEx to disappear once we
7319 get here, so don't bother handling it gracefully. */
7320 if (enum_font_families_ex == NULL)
7321 error ("gdi32.dll has disappeared!");
7322 return enum_font_families_ex (lpef->hdc,
7323 &lplf->elfLogFont,
7324 (FONTENUMPROC) enum_fontex_cb2,
7325 (LPARAM) lpef, 0);
7326 }
7327
7328 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
7329 and xterm.c in Emacs 20.3) */
7330
7331 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
7332 {
7333 char *fontname, *ptnstr;
7334 Lisp_Object list, tem, newlist = Qnil;
7335 int n_fonts = 0;
7336
7337 list = Vw32_bdf_filename_alist;
7338 ptnstr = XSTRING (pattern)->data;
7339
7340 for ( ; CONSP (list); list = XCDR (list))
7341 {
7342 tem = XCAR (list);
7343 if (CONSP (tem))
7344 fontname = XSTRING (XCAR (tem))->data;
7345 else if (STRINGP (tem))
7346 fontname = XSTRING (tem)->data;
7347 else
7348 continue;
7349
7350 if (w32_font_match (fontname, ptnstr))
7351 {
7352 newlist = Fcons (XCAR (tem), newlist);
7353 n_fonts++;
7354 if (n_fonts >= max_names)
7355 break;
7356 }
7357 }
7358
7359 return newlist;
7360 }
7361
7362
7363 /* Return a list of names of available fonts matching PATTERN on frame
7364 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7365 to be listed. Frame F NULL means we have not yet created any
7366 frame, which means we can't get proper size info, as we don't have
7367 a device context to use for GetTextMetrics.
7368 MAXNAMES sets a limit on how many fonts to match. */
7369
7370 Lisp_Object
7371 w32_list_fonts (f, pattern, size, maxnames)
7372 struct frame *f;
7373 Lisp_Object pattern;
7374 int size;
7375 int maxnames;
7376 {
7377 Lisp_Object patterns, key = Qnil, tem, tpat;
7378 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
7379 struct w32_display_info *dpyinfo = &one_w32_display_info;
7380 int n_fonts = 0;
7381
7382 patterns = Fassoc (pattern, Valternate_fontname_alist);
7383 if (NILP (patterns))
7384 patterns = Fcons (pattern, Qnil);
7385
7386 for (; CONSP (patterns); patterns = XCDR (patterns))
7387 {
7388 enumfont_t ef;
7389 int codepage;
7390
7391 tpat = XCAR (patterns);
7392
7393 if (!STRINGP (tpat))
7394 continue;
7395
7396 /* Avoid expensive EnumFontFamilies functions if we are not
7397 going to be able to output one of these anyway. */
7398 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7399 if (codepage != CP_8BIT && codepage != CP_UNICODE
7400 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7401 && !IsValidCodePage(codepage))
7402 continue;
7403
7404 /* See if we cached the result for this particular query.
7405 The cache is an alist of the form:
7406 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7407 */
7408 if (tem = XCDR (dpyinfo->name_list_element),
7409 !NILP (list = Fassoc (tpat, tem)))
7410 {
7411 list = Fcdr_safe (list);
7412 /* We have a cached list. Don't have to get the list again. */
7413 goto label_cached;
7414 }
7415
7416 BLOCK_INPUT;
7417 /* At first, put PATTERN in the cache. */
7418 ef.pattern = tpat;
7419 ef.list = Qnil;
7420 ef.numFonts = 0;
7421
7422 /* Use EnumFontFamiliesEx where it is available, as it knows
7423 about character sets. Fall back to EnumFontFamilies for
7424 older versions of NT that don't support the 'Ex function. */
7425 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
7426 {
7427 LOGFONT font_match_pattern;
7428 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7429 FARPROC enum_font_families_ex
7430 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7431
7432 /* We do our own pattern matching so we can handle wildcards. */
7433 font_match_pattern.lfFaceName[0] = 0;
7434 font_match_pattern.lfPitchAndFamily = 0;
7435 /* We can use the charset, because if it is a wildcard it will
7436 be DEFAULT_CHARSET anyway. */
7437 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7438
7439 ef.hdc = GetDC (dpyinfo->root_window);
7440
7441 if (enum_font_families_ex)
7442 enum_font_families_ex (ef.hdc,
7443 &font_match_pattern,
7444 (FONTENUMPROC) enum_fontex_cb1,
7445 (LPARAM) &ef, 0);
7446 else
7447 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7448 (LPARAM)&ef);
7449
7450 ReleaseDC (dpyinfo->root_window, ef.hdc);
7451 }
7452
7453 UNBLOCK_INPUT;
7454 list = ef.list;
7455
7456 /* Make a list of the fonts we got back.
7457 Store that in the font cache for the display. */
7458 XSETCDR (dpyinfo->name_list_element,
7459 Fcons (Fcons (tpat, list),
7460 XCDR (dpyinfo->name_list_element)));
7461
7462 label_cached:
7463 if (NILP (list)) continue; /* Try the remaining alternatives. */
7464
7465 newlist = second_best = Qnil;
7466
7467 /* Make a list of the fonts that have the right width. */
7468 for (; CONSP (list); list = XCDR (list))
7469 {
7470 int found_size;
7471 tem = XCAR (list);
7472
7473 if (!CONSP (tem))
7474 continue;
7475 if (NILP (XCAR (tem)))
7476 continue;
7477 if (!size)
7478 {
7479 newlist = Fcons (XCAR (tem), newlist);
7480 n_fonts++;
7481 if (n_fonts >= maxnames)
7482 break;
7483 else
7484 continue;
7485 }
7486 if (!INTEGERP (XCDR (tem)))
7487 {
7488 /* Since we don't yet know the size of the font, we must
7489 load it and try GetTextMetrics. */
7490 W32FontStruct thisinfo;
7491 LOGFONT lf;
7492 HDC hdc;
7493 HANDLE oldobj;
7494
7495 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
7496 continue;
7497
7498 BLOCK_INPUT;
7499 thisinfo.bdf = NULL;
7500 thisinfo.hfont = CreateFontIndirect (&lf);
7501 if (thisinfo.hfont == NULL)
7502 continue;
7503
7504 hdc = GetDC (dpyinfo->root_window);
7505 oldobj = SelectObject (hdc, thisinfo.hfont);
7506 if (GetTextMetrics (hdc, &thisinfo.tm))
7507 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
7508 else
7509 XSETCDR (tem, make_number (0));
7510 SelectObject (hdc, oldobj);
7511 ReleaseDC (dpyinfo->root_window, hdc);
7512 DeleteObject(thisinfo.hfont);
7513 UNBLOCK_INPUT;
7514 }
7515 found_size = XINT (XCDR (tem));
7516 if (found_size == size)
7517 {
7518 newlist = Fcons (XCAR (tem), newlist);
7519 n_fonts++;
7520 if (n_fonts >= maxnames)
7521 break;
7522 }
7523 /* keep track of the closest matching size in case
7524 no exact match is found. */
7525 else if (found_size > 0)
7526 {
7527 if (NILP (second_best))
7528 second_best = tem;
7529
7530 else if (found_size < size)
7531 {
7532 if (XINT (XCDR (second_best)) > size
7533 || XINT (XCDR (second_best)) < found_size)
7534 second_best = tem;
7535 }
7536 else
7537 {
7538 if (XINT (XCDR (second_best)) > size
7539 && XINT (XCDR (second_best)) >
7540 found_size)
7541 second_best = tem;
7542 }
7543 }
7544 }
7545
7546 if (!NILP (newlist))
7547 break;
7548 else if (!NILP (second_best))
7549 {
7550 newlist = Fcons (XCAR (second_best), Qnil);
7551 break;
7552 }
7553 }
7554
7555 /* Include any bdf fonts. */
7556 if (n_fonts < maxnames)
7557 {
7558 Lisp_Object combined[2];
7559 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7560 combined[1] = newlist;
7561 newlist = Fnconc(2, combined);
7562 }
7563
7564 return newlist;
7565 }
7566
7567
7568 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7569 struct font_info *
7570 w32_get_font_info (f, font_idx)
7571 FRAME_PTR f;
7572 int font_idx;
7573 {
7574 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7575 }
7576
7577
7578 struct font_info*
7579 w32_query_font (struct frame *f, char *fontname)
7580 {
7581 int i;
7582 struct font_info *pfi;
7583
7584 pfi = FRAME_W32_FONT_TABLE (f);
7585
7586 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7587 {
7588 if (strcmp(pfi->name, fontname) == 0) return pfi;
7589 }
7590
7591 return NULL;
7592 }
7593
7594 /* Find a CCL program for a font specified by FONTP, and set the member
7595 `encoder' of the structure. */
7596
7597 void
7598 w32_find_ccl_program (fontp)
7599 struct font_info *fontp;
7600 {
7601 Lisp_Object list, elt;
7602
7603 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7604 {
7605 elt = XCAR (list);
7606 if (CONSP (elt)
7607 && STRINGP (XCAR (elt))
7608 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7609 >= 0))
7610 break;
7611 }
7612 if (! NILP (list))
7613 {
7614 struct ccl_program *ccl
7615 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7616
7617 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7618 xfree (ccl);
7619 else
7620 fontp->font_encoder = ccl;
7621 }
7622 }
7623
7624 \f
7625 /* Find BDF files in a specified directory. (use GCPRO when calling,
7626 as this calls lisp to get a directory listing). */
7627 static Lisp_Object
7628 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7629 {
7630 Lisp_Object filelist, list = Qnil;
7631 char fontname[100];
7632
7633 if (!STRINGP(directory))
7634 return Qnil;
7635
7636 filelist = Fdirectory_files (directory, Qt,
7637 build_string (".*\\.[bB][dD][fF]"), Qt);
7638
7639 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7640 {
7641 Lisp_Object filename = XCAR (filelist);
7642 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7643 store_in_alist (&list, build_string (fontname), filename);
7644 }
7645 return list;
7646 }
7647
7648 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7649 1, 1, 0,
7650 doc: /* Return a list of BDF fonts in DIR.
7651 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7652 which do not contain an xlfd description will not be included in the
7653 list. DIR may be a list of directories. */)
7654 (directory)
7655 Lisp_Object directory;
7656 {
7657 Lisp_Object list = Qnil;
7658 struct gcpro gcpro1, gcpro2;
7659
7660 if (!CONSP (directory))
7661 return w32_find_bdf_fonts_in_dir (directory);
7662
7663 for ( ; CONSP (directory); directory = XCDR (directory))
7664 {
7665 Lisp_Object pair[2];
7666 pair[0] = list;
7667 pair[1] = Qnil;
7668 GCPRO2 (directory, list);
7669 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7670 list = Fnconc( 2, pair );
7671 UNGCPRO;
7672 }
7673 return list;
7674 }
7675
7676 \f
7677 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7678 doc: /* Internal function called by `color-defined-p', which see. */)
7679 (color, frame)
7680 Lisp_Object color, frame;
7681 {
7682 XColor foo;
7683 FRAME_PTR f = check_x_frame (frame);
7684
7685 CHECK_STRING (color);
7686
7687 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7688 return Qt;
7689 else
7690 return Qnil;
7691 }
7692
7693 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7694 doc: /* Internal function called by `color-values', which see. */)
7695 (color, frame)
7696 Lisp_Object color, frame;
7697 {
7698 XColor foo;
7699 FRAME_PTR f = check_x_frame (frame);
7700
7701 CHECK_STRING (color);
7702
7703 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7704 {
7705 Lisp_Object rgb[3];
7706
7707 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7708 | GetRValue (foo.pixel));
7709 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7710 | GetGValue (foo.pixel));
7711 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7712 | GetBValue (foo.pixel));
7713 return Flist (3, rgb);
7714 }
7715 else
7716 return Qnil;
7717 }
7718
7719 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7720 doc: /* Internal function called by `display-color-p', which see. */)
7721 (display)
7722 Lisp_Object display;
7723 {
7724 struct w32_display_info *dpyinfo = check_x_display_info (display);
7725
7726 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7727 return Qnil;
7728
7729 return Qt;
7730 }
7731
7732 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7733 Sx_display_grayscale_p, 0, 1, 0,
7734 doc: /* Return t if the X display supports shades of gray.
7735 Note that color displays do support shades of gray.
7736 The optional argument DISPLAY specifies which display to ask about.
7737 DISPLAY should be either a frame or a display name (a string).
7738 If omitted or nil, that stands for the selected frame's display. */)
7739 (display)
7740 Lisp_Object display;
7741 {
7742 struct w32_display_info *dpyinfo = check_x_display_info (display);
7743
7744 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7745 return Qnil;
7746
7747 return Qt;
7748 }
7749
7750 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7751 Sx_display_pixel_width, 0, 1, 0,
7752 doc: /* Returns the width in pixels of DISPLAY.
7753 The optional argument DISPLAY specifies which display to ask about.
7754 DISPLAY should be either a frame or a display name (a string).
7755 If omitted or nil, that stands for the selected frame's display. */)
7756 (display)
7757 Lisp_Object display;
7758 {
7759 struct w32_display_info *dpyinfo = check_x_display_info (display);
7760
7761 return make_number (dpyinfo->width);
7762 }
7763
7764 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7765 Sx_display_pixel_height, 0, 1, 0,
7766 doc: /* Returns the height in pixels of DISPLAY.
7767 The optional argument DISPLAY specifies which display to ask about.
7768 DISPLAY should be either a frame or a display name (a string).
7769 If omitted or nil, that stands for the selected frame's display. */)
7770 (display)
7771 Lisp_Object display;
7772 {
7773 struct w32_display_info *dpyinfo = check_x_display_info (display);
7774
7775 return make_number (dpyinfo->height);
7776 }
7777
7778 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7779 0, 1, 0,
7780 doc: /* Returns the number of bitplanes of DISPLAY.
7781 The optional argument DISPLAY specifies which display to ask about.
7782 DISPLAY should be either a frame or a display name (a string).
7783 If omitted or nil, that stands for the selected frame's display. */)
7784 (display)
7785 Lisp_Object display;
7786 {
7787 struct w32_display_info *dpyinfo = check_x_display_info (display);
7788
7789 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7790 }
7791
7792 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7793 0, 1, 0,
7794 doc: /* Returns the number of color cells of DISPLAY.
7795 The optional argument DISPLAY specifies which display to ask about.
7796 DISPLAY should be either a frame or a display name (a string).
7797 If omitted or nil, that stands for the selected frame's display. */)
7798 (display)
7799 Lisp_Object display;
7800 {
7801 struct w32_display_info *dpyinfo = check_x_display_info (display);
7802 HDC hdc;
7803 int cap;
7804
7805 hdc = GetDC (dpyinfo->root_window);
7806 if (dpyinfo->has_palette)
7807 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7808 else
7809 cap = GetDeviceCaps (hdc,NUMCOLORS);
7810
7811 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7812 and because probably is more meaningful on Windows anyway */
7813 if (cap < 0)
7814 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7815
7816 ReleaseDC (dpyinfo->root_window, hdc);
7817
7818 return make_number (cap);
7819 }
7820
7821 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7822 Sx_server_max_request_size,
7823 0, 1, 0,
7824 doc: /* Returns the maximum request size of the server of DISPLAY.
7825 The optional argument DISPLAY specifies which display to ask about.
7826 DISPLAY should be either a frame or a display name (a string).
7827 If omitted or nil, that stands for the selected frame's display. */)
7828 (display)
7829 Lisp_Object display;
7830 {
7831 struct w32_display_info *dpyinfo = check_x_display_info (display);
7832
7833 return make_number (1);
7834 }
7835
7836 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7837 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7838 The optional argument DISPLAY specifies which display to ask about.
7839 DISPLAY should be either a frame or a display name (a string).
7840 If omitted or nil, that stands for the selected frame's display. */)
7841 (display)
7842 Lisp_Object display;
7843 {
7844 return build_string ("Microsoft Corp.");
7845 }
7846
7847 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7848 doc: /* Returns the version numbers of the server of DISPLAY.
7849 The value is a list of three integers: the major and minor
7850 version numbers, and the vendor-specific release
7851 number. See also the function `x-server-vendor'.
7852
7853 The optional argument DISPLAY specifies which display to ask about.
7854 DISPLAY should be either a frame or a display name (a string).
7855 If omitted or nil, that stands for the selected frame's display. */)
7856 (display)
7857 Lisp_Object display;
7858 {
7859 return Fcons (make_number (w32_major_version),
7860 Fcons (make_number (w32_minor_version),
7861 Fcons (make_number (w32_build_number), Qnil)));
7862 }
7863
7864 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7865 doc: /* Returns the number of screens on the server of DISPLAY.
7866 The optional argument DISPLAY specifies which display to ask about.
7867 DISPLAY should be either a frame or a display name (a string).
7868 If omitted or nil, that stands for the selected frame's display. */)
7869 (display)
7870 Lisp_Object display;
7871 {
7872 return make_number (1);
7873 }
7874
7875 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7876 Sx_display_mm_height, 0, 1, 0,
7877 doc: /* Returns the height in millimeters of DISPLAY.
7878 The optional argument DISPLAY specifies which display to ask about.
7879 DISPLAY should be either a frame or a display name (a string).
7880 If omitted or nil, that stands for the selected frame's display. */)
7881 (display)
7882 Lisp_Object display;
7883 {
7884 struct w32_display_info *dpyinfo = check_x_display_info (display);
7885 HDC hdc;
7886 int cap;
7887
7888 hdc = GetDC (dpyinfo->root_window);
7889
7890 cap = GetDeviceCaps (hdc, VERTSIZE);
7891
7892 ReleaseDC (dpyinfo->root_window, hdc);
7893
7894 return make_number (cap);
7895 }
7896
7897 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7898 doc: /* Returns the width in millimeters of DISPLAY.
7899 The optional argument DISPLAY specifies which display to ask about.
7900 DISPLAY should be either a frame or a display name (a string).
7901 If omitted or nil, that stands for the selected frame's display. */)
7902 (display)
7903 Lisp_Object display;
7904 {
7905 struct w32_display_info *dpyinfo = check_x_display_info (display);
7906
7907 HDC hdc;
7908 int cap;
7909
7910 hdc = GetDC (dpyinfo->root_window);
7911
7912 cap = GetDeviceCaps (hdc, HORZSIZE);
7913
7914 ReleaseDC (dpyinfo->root_window, hdc);
7915
7916 return make_number (cap);
7917 }
7918
7919 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7920 Sx_display_backing_store, 0, 1, 0,
7921 doc: /* Returns an indication of whether DISPLAY does backing store.
7922 The value may be `always', `when-mapped', or `not-useful'.
7923 The optional argument DISPLAY specifies which display to ask about.
7924 DISPLAY should be either a frame or a display name (a string).
7925 If omitted or nil, that stands for the selected frame's display. */)
7926 (display)
7927 Lisp_Object display;
7928 {
7929 return intern ("not-useful");
7930 }
7931
7932 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7933 Sx_display_visual_class, 0, 1, 0,
7934 doc: /* Returns the visual class of DISPLAY.
7935 The value is one of the symbols `static-gray', `gray-scale',
7936 `static-color', `pseudo-color', `true-color', or `direct-color'.
7937
7938 The optional argument DISPLAY specifies which display to ask about.
7939 DISPLAY should be either a frame or a display name (a string).
7940 If omitted or nil, that stands for the selected frame's display. */)
7941 (display)
7942 Lisp_Object display;
7943 {
7944 struct w32_display_info *dpyinfo = check_x_display_info (display);
7945 Lisp_Object result = Qnil;
7946
7947 if (dpyinfo->has_palette)
7948 result = intern ("pseudo-color");
7949 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7950 result = intern ("static-grey");
7951 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7952 result = intern ("static-color");
7953 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7954 result = intern ("true-color");
7955
7956 return result;
7957 }
7958
7959 DEFUN ("x-display-save-under", Fx_display_save_under,
7960 Sx_display_save_under, 0, 1, 0,
7961 doc: /* Returns t if DISPLAY supports the save-under feature.
7962 The optional argument DISPLAY specifies which display to ask about.
7963 DISPLAY should be either a frame or a display name (a string).
7964 If omitted or nil, that stands for the selected frame's display. */)
7965 (display)
7966 Lisp_Object display;
7967 {
7968 return Qnil;
7969 }
7970 \f
7971 int
7972 x_pixel_width (f)
7973 register struct frame *f;
7974 {
7975 return PIXEL_WIDTH (f);
7976 }
7977
7978 int
7979 x_pixel_height (f)
7980 register struct frame *f;
7981 {
7982 return PIXEL_HEIGHT (f);
7983 }
7984
7985 int
7986 x_char_width (f)
7987 register struct frame *f;
7988 {
7989 return FONT_WIDTH (f->output_data.w32->font);
7990 }
7991
7992 int
7993 x_char_height (f)
7994 register struct frame *f;
7995 {
7996 return f->output_data.w32->line_height;
7997 }
7998
7999 int
8000 x_screen_planes (f)
8001 register struct frame *f;
8002 {
8003 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
8004 }
8005 \f
8006 /* Return the display structure for the display named NAME.
8007 Open a new connection if necessary. */
8008
8009 struct w32_display_info *
8010 x_display_info_for_name (name)
8011 Lisp_Object name;
8012 {
8013 Lisp_Object names;
8014 struct w32_display_info *dpyinfo;
8015
8016 CHECK_STRING (name);
8017
8018 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
8019 dpyinfo;
8020 dpyinfo = dpyinfo->next, names = XCDR (names))
8021 {
8022 Lisp_Object tem;
8023 tem = Fstring_equal (XCAR (XCAR (names)), name);
8024 if (!NILP (tem))
8025 return dpyinfo;
8026 }
8027
8028 /* Use this general default value to start with. */
8029 Vx_resource_name = Vinvocation_name;
8030
8031 validate_x_resource_name ();
8032
8033 dpyinfo = w32_term_init (name, (unsigned char *)0,
8034 (char *) XSTRING (Vx_resource_name)->data);
8035
8036 if (dpyinfo == 0)
8037 error ("Cannot connect to server %s", XSTRING (name)->data);
8038
8039 w32_in_use = 1;
8040 XSETFASTINT (Vwindow_system_version, 3);
8041
8042 return dpyinfo;
8043 }
8044
8045 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
8046 1, 3, 0, doc: /* Open a connection to a server.
8047 DISPLAY is the name of the display to connect to.
8048 Optional second arg XRM-STRING is a string of resources in xrdb format.
8049 If the optional third arg MUST-SUCCEED is non-nil,
8050 terminate Emacs if we can't open the connection. */)
8051 (display, xrm_string, must_succeed)
8052 Lisp_Object display, xrm_string, must_succeed;
8053 {
8054 unsigned char *xrm_option;
8055 struct w32_display_info *dpyinfo;
8056
8057 /* If initialization has already been done, return now to avoid
8058 overwriting critical parts of one_w32_display_info. */
8059 if (w32_in_use)
8060 return Qnil;
8061
8062 CHECK_STRING (display);
8063 if (! NILP (xrm_string))
8064 CHECK_STRING (xrm_string);
8065
8066 if (! EQ (Vwindow_system, intern ("w32")))
8067 error ("Not using Microsoft Windows");
8068
8069 /* Allow color mapping to be defined externally; first look in user's
8070 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8071 {
8072 Lisp_Object color_file;
8073 struct gcpro gcpro1;
8074
8075 color_file = build_string("~/rgb.txt");
8076
8077 GCPRO1 (color_file);
8078
8079 if (NILP (Ffile_readable_p (color_file)))
8080 color_file =
8081 Fexpand_file_name (build_string ("rgb.txt"),
8082 Fsymbol_value (intern ("data-directory")));
8083
8084 Vw32_color_map = Fw32_load_color_file (color_file);
8085
8086 UNGCPRO;
8087 }
8088 if (NILP (Vw32_color_map))
8089 Vw32_color_map = Fw32_default_color_map ();
8090
8091 if (! NILP (xrm_string))
8092 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8093 else
8094 xrm_option = (unsigned char *) 0;
8095
8096 /* Use this general default value to start with. */
8097 /* First remove .exe suffix from invocation-name - it looks ugly. */
8098 {
8099 char basename[ MAX_PATH ], *str;
8100
8101 strcpy (basename, XSTRING (Vinvocation_name)->data);
8102 str = strrchr (basename, '.');
8103 if (str) *str = 0;
8104 Vinvocation_name = build_string (basename);
8105 }
8106 Vx_resource_name = Vinvocation_name;
8107
8108 validate_x_resource_name ();
8109
8110 /* This is what opens the connection and sets x_current_display.
8111 This also initializes many symbols, such as those used for input. */
8112 dpyinfo = w32_term_init (display, xrm_option,
8113 (char *) XSTRING (Vx_resource_name)->data);
8114
8115 if (dpyinfo == 0)
8116 {
8117 if (!NILP (must_succeed))
8118 fatal ("Cannot connect to server %s.\n",
8119 XSTRING (display)->data);
8120 else
8121 error ("Cannot connect to server %s", XSTRING (display)->data);
8122 }
8123
8124 w32_in_use = 1;
8125
8126 XSETFASTINT (Vwindow_system_version, 3);
8127 return Qnil;
8128 }
8129
8130 DEFUN ("x-close-connection", Fx_close_connection,
8131 Sx_close_connection, 1, 1, 0,
8132 doc: /* Close the connection to DISPLAY's server.
8133 For DISPLAY, specify either a frame or a display name (a string).
8134 If DISPLAY is nil, that stands for the selected frame's display. */)
8135 (display)
8136 Lisp_Object display;
8137 {
8138 struct w32_display_info *dpyinfo = check_x_display_info (display);
8139 int i;
8140
8141 if (dpyinfo->reference_count > 0)
8142 error ("Display still has frames on it");
8143
8144 BLOCK_INPUT;
8145 /* Free the fonts in the font table. */
8146 for (i = 0; i < dpyinfo->n_fonts; i++)
8147 if (dpyinfo->font_table[i].name)
8148 {
8149 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8150 xfree (dpyinfo->font_table[i].full_name);
8151 xfree (dpyinfo->font_table[i].name);
8152 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8153 }
8154 x_destroy_all_bitmaps (dpyinfo);
8155
8156 x_delete_display (dpyinfo);
8157 UNBLOCK_INPUT;
8158
8159 return Qnil;
8160 }
8161
8162 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
8163 doc: /* Return the list of display names that Emacs has connections to. */)
8164 ()
8165 {
8166 Lisp_Object tail, result;
8167
8168 result = Qnil;
8169 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8170 result = Fcons (XCAR (XCAR (tail)), result);
8171
8172 return result;
8173 }
8174
8175 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
8176 doc: /* This is a noop on W32 systems. */)
8177 (on, display)
8178 Lisp_Object display, on;
8179 {
8180 return Qnil;
8181 }
8182
8183 \f
8184 /***********************************************************************
8185 Image types
8186 ***********************************************************************/
8187
8188 /* Value is the number of elements of vector VECTOR. */
8189
8190 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8191
8192 /* List of supported image types. Use define_image_type to add new
8193 types. Use lookup_image_type to find a type for a given symbol. */
8194
8195 static struct image_type *image_types;
8196
8197 /* The symbol `image' which is the car of the lists used to represent
8198 images in Lisp. */
8199
8200 extern Lisp_Object Qimage;
8201
8202 /* The symbol `xbm' which is used as the type symbol for XBM images. */
8203
8204 Lisp_Object Qxbm;
8205
8206 /* Keywords. */
8207
8208 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
8209 extern Lisp_Object QCdata, QCtype;
8210 Lisp_Object QCascent, QCmargin, QCrelief;
8211 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
8212 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
8213
8214 /* Other symbols. */
8215
8216 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
8217
8218 /* Time in seconds after which images should be removed from the cache
8219 if not displayed. */
8220
8221 Lisp_Object Vimage_cache_eviction_delay;
8222
8223 /* Function prototypes. */
8224
8225 static void define_image_type P_ ((struct image_type *type));
8226 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8227 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8228 static void x_laplace P_ ((struct frame *, struct image *));
8229 static void x_emboss P_ ((struct frame *, struct image *));
8230 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8231 Lisp_Object));
8232
8233
8234 /* Define a new image type from TYPE. This adds a copy of TYPE to
8235 image_types and adds the symbol *TYPE->type to Vimage_types. */
8236
8237 static void
8238 define_image_type (type)
8239 struct image_type *type;
8240 {
8241 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8242 The initialized data segment is read-only. */
8243 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8244 bcopy (type, p, sizeof *p);
8245 p->next = image_types;
8246 image_types = p;
8247 Vimage_types = Fcons (*p->type, Vimage_types);
8248 }
8249
8250
8251 /* Look up image type SYMBOL, and return a pointer to its image_type
8252 structure. Value is null if SYMBOL is not a known image type. */
8253
8254 static INLINE struct image_type *
8255 lookup_image_type (symbol)
8256 Lisp_Object symbol;
8257 {
8258 struct image_type *type;
8259
8260 for (type = image_types; type; type = type->next)
8261 if (EQ (symbol, *type->type))
8262 break;
8263
8264 return type;
8265 }
8266
8267
8268 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
8269 valid image specification is a list whose car is the symbol
8270 `image', and whose rest is a property list. The property list must
8271 contain a value for key `:type'. That value must be the name of a
8272 supported image type. The rest of the property list depends on the
8273 image type. */
8274
8275 int
8276 valid_image_p (object)
8277 Lisp_Object object;
8278 {
8279 int valid_p = 0;
8280
8281 if (CONSP (object) && EQ (XCAR (object), Qimage))
8282 {
8283 Lisp_Object tem;
8284
8285 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8286 if (EQ (XCAR (tem), QCtype))
8287 {
8288 tem = XCDR (tem);
8289 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8290 {
8291 struct image_type *type;
8292 type = lookup_image_type (XCAR (tem));
8293 if (type)
8294 valid_p = type->valid_p (object);
8295 }
8296
8297 break;
8298 }
8299 }
8300
8301 return valid_p;
8302 }
8303
8304
8305 /* Log error message with format string FORMAT and argument ARG.
8306 Signaling an error, e.g. when an image cannot be loaded, is not a
8307 good idea because this would interrupt redisplay, and the error
8308 message display would lead to another redisplay. This function
8309 therefore simply displays a message. */
8310
8311 static void
8312 image_error (format, arg1, arg2)
8313 char *format;
8314 Lisp_Object arg1, arg2;
8315 {
8316 add_to_log (format, arg1, arg2);
8317 }
8318
8319
8320 \f
8321 /***********************************************************************
8322 Image specifications
8323 ***********************************************************************/
8324
8325 enum image_value_type
8326 {
8327 IMAGE_DONT_CHECK_VALUE_TYPE,
8328 IMAGE_STRING_VALUE,
8329 IMAGE_STRING_OR_NIL_VALUE,
8330 IMAGE_SYMBOL_VALUE,
8331 IMAGE_POSITIVE_INTEGER_VALUE,
8332 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
8333 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
8334 IMAGE_ASCENT_VALUE,
8335 IMAGE_INTEGER_VALUE,
8336 IMAGE_FUNCTION_VALUE,
8337 IMAGE_NUMBER_VALUE,
8338 IMAGE_BOOL_VALUE
8339 };
8340
8341 /* Structure used when parsing image specifications. */
8342
8343 struct image_keyword
8344 {
8345 /* Name of keyword. */
8346 char *name;
8347
8348 /* The type of value allowed. */
8349 enum image_value_type type;
8350
8351 /* Non-zero means key must be present. */
8352 int mandatory_p;
8353
8354 /* Used to recognize duplicate keywords in a property list. */
8355 int count;
8356
8357 /* The value that was found. */
8358 Lisp_Object value;
8359 };
8360
8361
8362 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8363 int, Lisp_Object));
8364 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8365
8366
8367 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
8368 has the format (image KEYWORD VALUE ...). One of the keyword/
8369 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8370 image_keywords structures of size NKEYWORDS describing other
8371 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8372
8373 static int
8374 parse_image_spec (spec, keywords, nkeywords, type)
8375 Lisp_Object spec;
8376 struct image_keyword *keywords;
8377 int nkeywords;
8378 Lisp_Object type;
8379 {
8380 int i;
8381 Lisp_Object plist;
8382
8383 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8384 return 0;
8385
8386 plist = XCDR (spec);
8387 while (CONSP (plist))
8388 {
8389 Lisp_Object key, value;
8390
8391 /* First element of a pair must be a symbol. */
8392 key = XCAR (plist);
8393 plist = XCDR (plist);
8394 if (!SYMBOLP (key))
8395 return 0;
8396
8397 /* There must follow a value. */
8398 if (!CONSP (plist))
8399 return 0;
8400 value = XCAR (plist);
8401 plist = XCDR (plist);
8402
8403 /* Find key in KEYWORDS. Error if not found. */
8404 for (i = 0; i < nkeywords; ++i)
8405 if (strcmp (keywords[i].name, XSTRING (SYMBOL_NAME (key))->data) == 0)
8406 break;
8407
8408 if (i == nkeywords)
8409 continue;
8410
8411 /* Record that we recognized the keyword. If a keywords
8412 was found more than once, it's an error. */
8413 keywords[i].value = value;
8414 ++keywords[i].count;
8415
8416 if (keywords[i].count > 1)
8417 return 0;
8418
8419 /* Check type of value against allowed type. */
8420 switch (keywords[i].type)
8421 {
8422 case IMAGE_STRING_VALUE:
8423 if (!STRINGP (value))
8424 return 0;
8425 break;
8426
8427 case IMAGE_STRING_OR_NIL_VALUE:
8428 if (!STRINGP (value) && !NILP (value))
8429 return 0;
8430 break;
8431
8432 case IMAGE_SYMBOL_VALUE:
8433 if (!SYMBOLP (value))
8434 return 0;
8435 break;
8436
8437 case IMAGE_POSITIVE_INTEGER_VALUE:
8438 if (!INTEGERP (value) || XINT (value) <= 0)
8439 return 0;
8440 break;
8441
8442 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8443 if (INTEGERP (value) && XINT (value) >= 0)
8444 break;
8445 if (CONSP (value)
8446 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8447 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8448 break;
8449 return 0;
8450
8451 case IMAGE_ASCENT_VALUE:
8452 if (SYMBOLP (value) && EQ (value, Qcenter))
8453 break;
8454 else if (INTEGERP (value)
8455 && XINT (value) >= 0
8456 && XINT (value) <= 100)
8457 break;
8458 return 0;
8459
8460 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8461 if (!INTEGERP (value) || XINT (value) < 0)
8462 return 0;
8463 break;
8464
8465 case IMAGE_DONT_CHECK_VALUE_TYPE:
8466 break;
8467
8468 case IMAGE_FUNCTION_VALUE:
8469 value = indirect_function (value);
8470 if (SUBRP (value)
8471 || COMPILEDP (value)
8472 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8473 break;
8474 return 0;
8475
8476 case IMAGE_NUMBER_VALUE:
8477 if (!INTEGERP (value) && !FLOATP (value))
8478 return 0;
8479 break;
8480
8481 case IMAGE_INTEGER_VALUE:
8482 if (!INTEGERP (value))
8483 return 0;
8484 break;
8485
8486 case IMAGE_BOOL_VALUE:
8487 if (!NILP (value) && !EQ (value, Qt))
8488 return 0;
8489 break;
8490
8491 default:
8492 abort ();
8493 break;
8494 }
8495
8496 if (EQ (key, QCtype) && !EQ (type, value))
8497 return 0;
8498 }
8499
8500 /* Check that all mandatory fields are present. */
8501 for (i = 0; i < nkeywords; ++i)
8502 if (keywords[i].mandatory_p && keywords[i].count == 0)
8503 return 0;
8504
8505 return NILP (plist);
8506 }
8507
8508
8509 /* Return the value of KEY in image specification SPEC. Value is nil
8510 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8511 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8512
8513 static Lisp_Object
8514 image_spec_value (spec, key, found)
8515 Lisp_Object spec, key;
8516 int *found;
8517 {
8518 Lisp_Object tail;
8519
8520 xassert (valid_image_p (spec));
8521
8522 for (tail = XCDR (spec);
8523 CONSP (tail) && CONSP (XCDR (tail));
8524 tail = XCDR (XCDR (tail)))
8525 {
8526 if (EQ (XCAR (tail), key))
8527 {
8528 if (found)
8529 *found = 1;
8530 return XCAR (XCDR (tail));
8531 }
8532 }
8533
8534 if (found)
8535 *found = 0;
8536 return Qnil;
8537 }
8538
8539
8540 DEFUN ("image-size", Fimage_size, Simage_size, 1, 3, 0,
8541 doc: /* Return the size of image SPEC as pair (WIDTH . HEIGHT).
8542 PIXELS non-nil means return the size in pixels, otherwise return the
8543 size in canonical character units.
8544 FRAME is the frame on which the image will be displayed. FRAME nil
8545 or omitted means use the selected frame. */)
8546 (spec, pixels, frame)
8547 Lisp_Object spec, pixels, frame;
8548 {
8549 Lisp_Object size;
8550
8551 size = Qnil;
8552 if (valid_image_p (spec))
8553 {
8554 struct frame *f = check_x_frame (frame);
8555 int id = lookup_image (f, spec);
8556 struct image *img = IMAGE_FROM_ID (f, id);
8557 int width = img->width + 2 * img->hmargin;
8558 int height = img->height + 2 * img->vmargin;
8559
8560 if (NILP (pixels))
8561 size = Fcons (make_float ((double) width / CANON_X_UNIT (f)),
8562 make_float ((double) height / CANON_Y_UNIT (f)));
8563 else
8564 size = Fcons (make_number (width), make_number (height));
8565 }
8566 else
8567 error ("Invalid image specification");
8568
8569 return size;
8570 }
8571
8572
8573 DEFUN ("image-mask-p", Fimage_mask_p, Simage_mask_p, 1, 2, 0,
8574 doc: /* Return t if image SPEC has a mask bitmap.
8575 FRAME is the frame on which the image will be displayed. FRAME nil
8576 or omitted means use the selected frame. */)
8577 (spec, frame)
8578 Lisp_Object spec, frame;
8579 {
8580 Lisp_Object mask;
8581
8582 mask = Qnil;
8583 if (valid_image_p (spec))
8584 {
8585 struct frame *f = check_x_frame (frame);
8586 int id = lookup_image (f, spec);
8587 struct image *img = IMAGE_FROM_ID (f, id);
8588 if (img->mask)
8589 mask = Qt;
8590 }
8591 else
8592 error ("Invalid image specification");
8593
8594 return mask;
8595 }
8596
8597 \f
8598 /***********************************************************************
8599 Image type independent image structures
8600 ***********************************************************************/
8601
8602 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8603 static void free_image P_ ((struct frame *f, struct image *img));
8604
8605
8606 /* Allocate and return a new image structure for image specification
8607 SPEC. SPEC has a hash value of HASH. */
8608
8609 static struct image *
8610 make_image (spec, hash)
8611 Lisp_Object spec;
8612 unsigned hash;
8613 {
8614 struct image *img = (struct image *) xmalloc (sizeof *img);
8615
8616 xassert (valid_image_p (spec));
8617 bzero (img, sizeof *img);
8618 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8619 xassert (img->type != NULL);
8620 img->spec = spec;
8621 img->data.lisp_val = Qnil;
8622 img->ascent = DEFAULT_IMAGE_ASCENT;
8623 img->hash = hash;
8624 return img;
8625 }
8626
8627
8628 /* Free image IMG which was used on frame F, including its resources. */
8629
8630 static void
8631 free_image (f, img)
8632 struct frame *f;
8633 struct image *img;
8634 {
8635 if (img)
8636 {
8637 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8638
8639 /* Remove IMG from the hash table of its cache. */
8640 if (img->prev)
8641 img->prev->next = img->next;
8642 else
8643 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8644
8645 if (img->next)
8646 img->next->prev = img->prev;
8647
8648 c->images[img->id] = NULL;
8649
8650 /* Free resources, then free IMG. */
8651 img->type->free (f, img);
8652 xfree (img);
8653 }
8654 }
8655
8656
8657 /* Prepare image IMG for display on frame F. Must be called before
8658 drawing an image. */
8659
8660 void
8661 prepare_image_for_display (f, img)
8662 struct frame *f;
8663 struct image *img;
8664 {
8665 EMACS_TIME t;
8666
8667 /* We're about to display IMG, so set its timestamp to `now'. */
8668 EMACS_GET_TIME (t);
8669 img->timestamp = EMACS_SECS (t);
8670
8671 /* If IMG doesn't have a pixmap yet, load it now, using the image
8672 type dependent loader function. */
8673 if (img->pixmap == 0 && !img->load_failed_p)
8674 img->load_failed_p = img->type->load (f, img) == 0;
8675 }
8676
8677
8678 /* Value is the number of pixels for the ascent of image IMG when
8679 drawn in face FACE. */
8680
8681 int
8682 image_ascent (img, face)
8683 struct image *img;
8684 struct face *face;
8685 {
8686 int height = img->height + img->vmargin;
8687 int ascent;
8688
8689 if (img->ascent == CENTERED_IMAGE_ASCENT)
8690 {
8691 if (face->font)
8692 ascent = height / 2 - (FONT_DESCENT(face->font)
8693 - FONT_BASE(face->font)) / 2;
8694 else
8695 ascent = height / 2;
8696 }
8697 else
8698 ascent = (int) (height * img->ascent / 100.0);
8699
8700 return ascent;
8701 }
8702
8703
8704 \f
8705 /* Image background colors. */
8706
8707 /* Find the "best" corner color of a bitmap. XIMG is assumed to a device
8708 context with the bitmap selected. */
8709 static COLORREF
8710 four_corners_best (ximg, width, height)
8711 HDC ximg;
8712 unsigned long width, height;
8713 {
8714 COLORREF corners[4], best;
8715 int i, best_count;
8716
8717 /* Get the colors at the corners of ximg. */
8718 corners[0] = GetPixel (ximg, 0, 0);
8719 corners[1] = GetPixel (ximg, width - 1, 0);
8720 corners[2] = GetPixel (ximg, width - 1, height - 1);
8721 corners[3] = GetPixel (ximg, 0, height - 1);
8722
8723 /* Choose the most frequently found color as background. */
8724 for (i = best_count = 0; i < 4; ++i)
8725 {
8726 int j, n;
8727
8728 for (j = n = 0; j < 4; ++j)
8729 if (corners[i] == corners[j])
8730 ++n;
8731
8732 if (n > best_count)
8733 best = corners[i], best_count = n;
8734 }
8735
8736 return best;
8737 }
8738
8739 /* Return the `background' field of IMG. If IMG doesn't have one yet,
8740 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8741 object to use for the heuristic. */
8742
8743 unsigned long
8744 image_background (img, f, ximg)
8745 struct image *img;
8746 struct frame *f;
8747 XImage *ximg;
8748 {
8749 if (! img->background_valid)
8750 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8751 {
8752 #if 0 /* TODO: Image support. */
8753 int free_ximg = !ximg;
8754
8755 if (! ximg)
8756 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8757 0, 0, img->width, img->height, ~0, ZPixmap);
8758
8759 img->background = four_corners_best (ximg, img->width, img->height);
8760
8761 if (free_ximg)
8762 XDestroyImage (ximg);
8763
8764 img->background_valid = 1;
8765 #endif
8766 }
8767
8768 return img->background;
8769 }
8770
8771 /* Return the `background_transparent' field of IMG. If IMG doesn't
8772 have one yet, it is guessed heuristically. If non-zero, MASK is an
8773 existing XImage object to use for the heuristic. */
8774
8775 int
8776 image_background_transparent (img, f, mask)
8777 struct image *img;
8778 struct frame *f;
8779 XImage *mask;
8780 {
8781 if (! img->background_transparent_valid)
8782 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8783 {
8784 #if 0 /* TODO: Image support. */
8785 if (img->mask)
8786 {
8787 int free_mask = !mask;
8788
8789 if (! mask)
8790 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8791 0, 0, img->width, img->height, ~0, ZPixmap);
8792
8793 img->background_transparent
8794 = !four_corners_best (mask, img->width, img->height);
8795
8796 if (free_mask)
8797 XDestroyImage (mask);
8798 }
8799 else
8800 #endif
8801 img->background_transparent = 0;
8802
8803 img->background_transparent_valid = 1;
8804 }
8805
8806 return img->background_transparent;
8807 }
8808
8809 \f
8810 /***********************************************************************
8811 Helper functions for X image types
8812 ***********************************************************************/
8813
8814 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8815 int, int));
8816 static void x_clear_image P_ ((struct frame *f, struct image *img));
8817 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8818 struct image *img,
8819 Lisp_Object color_name,
8820 unsigned long dflt));
8821
8822
8823 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8824 free the pixmap if any. MASK_P non-zero means clear the mask
8825 pixmap if any. COLORS_P non-zero means free colors allocated for
8826 the image, if any. */
8827
8828 static void
8829 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8830 struct frame *f;
8831 struct image *img;
8832 int pixmap_p, mask_p, colors_p;
8833 {
8834 if (pixmap_p && img->pixmap)
8835 {
8836 DeleteObject (img->pixmap);
8837 img->pixmap = NULL;
8838 img->background_valid = 0;
8839 }
8840
8841 if (mask_p && img->mask)
8842 {
8843 DeleteObject (img->mask);
8844 img->mask = NULL;
8845 img->background_transparent_valid = 0;
8846 }
8847
8848 if (colors_p && img->ncolors)
8849 {
8850 #if 0 /* TODO: color table support. */
8851 x_free_colors (f, img->colors, img->ncolors);
8852 #endif
8853 xfree (img->colors);
8854 img->colors = NULL;
8855 img->ncolors = 0;
8856 }
8857 }
8858
8859 /* Free X resources of image IMG which is used on frame F. */
8860
8861 static void
8862 x_clear_image (f, img)
8863 struct frame *f;
8864 struct image *img;
8865 {
8866 if (img->pixmap)
8867 {
8868 BLOCK_INPUT;
8869 DeleteObject (img->pixmap);
8870 img->pixmap = 0;
8871 UNBLOCK_INPUT;
8872 }
8873
8874 if (img->ncolors)
8875 {
8876 #if 0 /* TODO: color table support */
8877
8878 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8879
8880 /* If display has an immutable color map, freeing colors is not
8881 necessary and some servers don't allow it. So don't do it. */
8882 if (class != StaticColor
8883 && class != StaticGray
8884 && class != TrueColor)
8885 {
8886 Colormap cmap;
8887 BLOCK_INPUT;
8888 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8889 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8890 img->ncolors, 0);
8891 UNBLOCK_INPUT;
8892 }
8893 #endif
8894
8895 xfree (img->colors);
8896 img->colors = NULL;
8897 img->ncolors = 0;
8898 }
8899 }
8900
8901
8902 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8903 cannot be allocated, use DFLT. Add a newly allocated color to
8904 IMG->colors, so that it can be freed again. Value is the pixel
8905 color. */
8906
8907 static unsigned long
8908 x_alloc_image_color (f, img, color_name, dflt)
8909 struct frame *f;
8910 struct image *img;
8911 Lisp_Object color_name;
8912 unsigned long dflt;
8913 {
8914 XColor color;
8915 unsigned long result;
8916
8917 xassert (STRINGP (color_name));
8918
8919 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8920 {
8921 /* This isn't called frequently so we get away with simply
8922 reallocating the color vector to the needed size, here. */
8923 ++img->ncolors;
8924 img->colors =
8925 (unsigned long *) xrealloc (img->colors,
8926 img->ncolors * sizeof *img->colors);
8927 img->colors[img->ncolors - 1] = color.pixel;
8928 result = color.pixel;
8929 }
8930 else
8931 result = dflt;
8932 return result;
8933 }
8934
8935
8936 \f
8937 /***********************************************************************
8938 Image Cache
8939 ***********************************************************************/
8940
8941 static void cache_image P_ ((struct frame *f, struct image *img));
8942 static void postprocess_image P_ ((struct frame *, struct image *));
8943
8944
8945 /* Return a new, initialized image cache that is allocated from the
8946 heap. Call free_image_cache to free an image cache. */
8947
8948 struct image_cache *
8949 make_image_cache ()
8950 {
8951 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8952 int size;
8953
8954 bzero (c, sizeof *c);
8955 c->size = 50;
8956 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8957 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8958 c->buckets = (struct image **) xmalloc (size);
8959 bzero (c->buckets, size);
8960 return c;
8961 }
8962
8963
8964 /* Free image cache of frame F. Be aware that X frames share images
8965 caches. */
8966
8967 void
8968 free_image_cache (f)
8969 struct frame *f;
8970 {
8971 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8972 if (c)
8973 {
8974 int i;
8975
8976 /* Cache should not be referenced by any frame when freed. */
8977 xassert (c->refcount == 0);
8978
8979 for (i = 0; i < c->used; ++i)
8980 free_image (f, c->images[i]);
8981 xfree (c->images);
8982 xfree (c);
8983 xfree (c->buckets);
8984 FRAME_X_IMAGE_CACHE (f) = NULL;
8985 }
8986 }
8987
8988
8989 /* Clear image cache of frame F. FORCE_P non-zero means free all
8990 images. FORCE_P zero means clear only images that haven't been
8991 displayed for some time. Should be called from time to time to
8992 reduce the number of loaded images. If image-eviction-seconds is
8993 non-nil, this frees images in the cache which weren't displayed for
8994 at least that many seconds. */
8995
8996 void
8997 clear_image_cache (f, force_p)
8998 struct frame *f;
8999 int force_p;
9000 {
9001 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9002
9003 if (c && INTEGERP (Vimage_cache_eviction_delay))
9004 {
9005 EMACS_TIME t;
9006 unsigned long old;
9007 int i, nfreed;
9008
9009 EMACS_GET_TIME (t);
9010 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
9011
9012 /* Block input so that we won't be interrupted by a SIGIO
9013 while being in an inconsistent state. */
9014 BLOCK_INPUT;
9015
9016 for (i = nfreed = 0; i < c->used; ++i)
9017 {
9018 struct image *img = c->images[i];
9019 if (img != NULL
9020 && (force_p || (img->timestamp < old)))
9021 {
9022 free_image (f, img);
9023 ++nfreed;
9024 }
9025 }
9026
9027 /* We may be clearing the image cache because, for example,
9028 Emacs was iconified for a longer period of time. In that
9029 case, current matrices may still contain references to
9030 images freed above. So, clear these matrices. */
9031 if (nfreed)
9032 {
9033 Lisp_Object tail, frame;
9034
9035 FOR_EACH_FRAME (tail, frame)
9036 {
9037 struct frame *f = XFRAME (frame);
9038 if (FRAME_W32_P (f)
9039 && FRAME_X_IMAGE_CACHE (f) == c)
9040 clear_current_matrices (f);
9041 }
9042
9043 ++windows_or_buffers_changed;
9044 }
9045
9046 UNBLOCK_INPUT;
9047 }
9048 }
9049
9050
9051 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
9052 0, 1, 0,
9053 doc: /* Clear the image cache of FRAME.
9054 FRAME nil or omitted means use the selected frame.
9055 FRAME t means clear the image caches of all frames. */)
9056 (frame)
9057 Lisp_Object frame;
9058 {
9059 if (EQ (frame, Qt))
9060 {
9061 Lisp_Object tail;
9062
9063 FOR_EACH_FRAME (tail, frame)
9064 if (FRAME_W32_P (XFRAME (frame)))
9065 clear_image_cache (XFRAME (frame), 1);
9066 }
9067 else
9068 clear_image_cache (check_x_frame (frame), 1);
9069
9070 return Qnil;
9071 }
9072
9073
9074 /* Compute masks and transform image IMG on frame F, as specified
9075 by the image's specification, */
9076
9077 static void
9078 postprocess_image (f, img)
9079 struct frame *f;
9080 struct image *img;
9081 {
9082 #if 0 /* TODO: image support. */
9083 /* Manipulation of the image's mask. */
9084 if (img->pixmap)
9085 {
9086 Lisp_Object conversion, spec;
9087 Lisp_Object mask;
9088
9089 spec = img->spec;
9090
9091 /* `:heuristic-mask t'
9092 `:mask heuristic'
9093 means build a mask heuristically.
9094 `:heuristic-mask (R G B)'
9095 `:mask (heuristic (R G B))'
9096 means build a mask from color (R G B) in the
9097 image.
9098 `:mask nil'
9099 means remove a mask, if any. */
9100
9101 mask = image_spec_value (spec, QCheuristic_mask, NULL);
9102 if (!NILP (mask))
9103 x_build_heuristic_mask (f, img, mask);
9104 else
9105 {
9106 int found_p;
9107
9108 mask = image_spec_value (spec, QCmask, &found_p);
9109
9110 if (EQ (mask, Qheuristic))
9111 x_build_heuristic_mask (f, img, Qt);
9112 else if (CONSP (mask)
9113 && EQ (XCAR (mask), Qheuristic))
9114 {
9115 if (CONSP (XCDR (mask)))
9116 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9117 else
9118 x_build_heuristic_mask (f, img, XCDR (mask));
9119 }
9120 else if (NILP (mask) && found_p && img->mask)
9121 {
9122 DeleteObject (img->mask);
9123 img->mask = NULL;
9124 }
9125 }
9126
9127
9128 /* Should we apply an image transformation algorithm? */
9129 conversion = image_spec_value (spec, QCconversion, NULL);
9130 if (EQ (conversion, Qdisabled))
9131 x_disable_image (f, img);
9132 else if (EQ (conversion, Qlaplace))
9133 x_laplace (f, img);
9134 else if (EQ (conversion, Qemboss))
9135 x_emboss (f, img);
9136 else if (CONSP (conversion)
9137 && EQ (XCAR (conversion), Qedge_detection))
9138 {
9139 Lisp_Object tem;
9140 tem = XCDR (conversion);
9141 if (CONSP (tem))
9142 x_edge_detection (f, img,
9143 Fplist_get (tem, QCmatrix),
9144 Fplist_get (tem, QCcolor_adjustment));
9145 }
9146 }
9147 #endif
9148 }
9149
9150
9151 /* Return the id of image with Lisp specification SPEC on frame F.
9152 SPEC must be a valid Lisp image specification (see valid_image_p). */
9153
9154 int
9155 lookup_image (f, spec)
9156 struct frame *f;
9157 Lisp_Object spec;
9158 {
9159 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9160 struct image *img;
9161 int i;
9162 unsigned hash;
9163 struct gcpro gcpro1;
9164 EMACS_TIME now;
9165
9166 /* F must be a window-system frame, and SPEC must be a valid image
9167 specification. */
9168 xassert (FRAME_WINDOW_P (f));
9169 xassert (valid_image_p (spec));
9170
9171 GCPRO1 (spec);
9172
9173 /* Look up SPEC in the hash table of the image cache. */
9174 hash = sxhash (spec, 0);
9175 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9176
9177 for (img = c->buckets[i]; img; img = img->next)
9178 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9179 break;
9180
9181 /* If not found, create a new image and cache it. */
9182 if (img == NULL)
9183 {
9184 extern Lisp_Object Qpostscript;
9185
9186 BLOCK_INPUT;
9187 img = make_image (spec, hash);
9188 cache_image (f, img);
9189 img->load_failed_p = img->type->load (f, img) == 0;
9190
9191 /* If we can't load the image, and we don't have a width and
9192 height, use some arbitrary width and height so that we can
9193 draw a rectangle for it. */
9194 if (img->load_failed_p)
9195 {
9196 Lisp_Object value;
9197
9198 value = image_spec_value (spec, QCwidth, NULL);
9199 img->width = (INTEGERP (value)
9200 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9201 value = image_spec_value (spec, QCheight, NULL);
9202 img->height = (INTEGERP (value)
9203 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9204 }
9205 else
9206 {
9207 /* Handle image type independent image attributes
9208 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9209 `:background COLOR'. */
9210 Lisp_Object ascent, margin, relief, bg;
9211
9212 ascent = image_spec_value (spec, QCascent, NULL);
9213 if (INTEGERP (ascent))
9214 img->ascent = XFASTINT (ascent);
9215 else if (EQ (ascent, Qcenter))
9216 img->ascent = CENTERED_IMAGE_ASCENT;
9217
9218 margin = image_spec_value (spec, QCmargin, NULL);
9219 if (INTEGERP (margin) && XINT (margin) >= 0)
9220 img->vmargin = img->hmargin = XFASTINT (margin);
9221 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9222 && INTEGERP (XCDR (margin)))
9223 {
9224 if (XINT (XCAR (margin)) > 0)
9225 img->hmargin = XFASTINT (XCAR (margin));
9226 if (XINT (XCDR (margin)) > 0)
9227 img->vmargin = XFASTINT (XCDR (margin));
9228 }
9229
9230 relief = image_spec_value (spec, QCrelief, NULL);
9231 if (INTEGERP (relief))
9232 {
9233 img->relief = XINT (relief);
9234 img->hmargin += abs (img->relief);
9235 img->vmargin += abs (img->relief);
9236 }
9237
9238 if (! img->background_valid)
9239 {
9240 bg = image_spec_value (img->spec, QCbackground, NULL);
9241 if (!NILP (bg))
9242 {
9243 img->background
9244 = x_alloc_image_color (f, img, bg,
9245 FRAME_BACKGROUND_PIXEL (f));
9246 img->background_valid = 1;
9247 }
9248 }
9249
9250 /* Do image transformations and compute masks, unless we
9251 don't have the image yet. */
9252 if (!EQ (*img->type->type, Qpostscript))
9253 postprocess_image (f, img);
9254 }
9255
9256 UNBLOCK_INPUT;
9257 xassert (!interrupt_input_blocked);
9258 }
9259
9260 /* We're using IMG, so set its timestamp to `now'. */
9261 EMACS_GET_TIME (now);
9262 img->timestamp = EMACS_SECS (now);
9263
9264 UNGCPRO;
9265
9266 /* Value is the image id. */
9267 return img->id;
9268 }
9269
9270
9271 /* Cache image IMG in the image cache of frame F. */
9272
9273 static void
9274 cache_image (f, img)
9275 struct frame *f;
9276 struct image *img;
9277 {
9278 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9279 int i;
9280
9281 /* Find a free slot in c->images. */
9282 for (i = 0; i < c->used; ++i)
9283 if (c->images[i] == NULL)
9284 break;
9285
9286 /* If no free slot found, maybe enlarge c->images. */
9287 if (i == c->used && c->used == c->size)
9288 {
9289 c->size *= 2;
9290 c->images = (struct image **) xrealloc (c->images,
9291 c->size * sizeof *c->images);
9292 }
9293
9294 /* Add IMG to c->images, and assign IMG an id. */
9295 c->images[i] = img;
9296 img->id = i;
9297 if (i == c->used)
9298 ++c->used;
9299
9300 /* Add IMG to the cache's hash table. */
9301 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9302 img->next = c->buckets[i];
9303 if (img->next)
9304 img->next->prev = img;
9305 img->prev = NULL;
9306 c->buckets[i] = img;
9307 }
9308
9309
9310 /* Call FN on every image in the image cache of frame F. Used to mark
9311 Lisp Objects in the image cache. */
9312
9313 void
9314 forall_images_in_image_cache (f, fn)
9315 struct frame *f;
9316 void (*fn) P_ ((struct image *img));
9317 {
9318 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9319 {
9320 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9321 if (c)
9322 {
9323 int i;
9324 for (i = 0; i < c->used; ++i)
9325 if (c->images[i])
9326 fn (c->images[i]);
9327 }
9328 }
9329 }
9330
9331
9332 \f
9333 /***********************************************************************
9334 W32 support code
9335 ***********************************************************************/
9336
9337 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9338 XImage **, Pixmap *));
9339 static void x_destroy_x_image P_ ((XImage *));
9340 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9341
9342
9343 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9344 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9345 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
9346 via xmalloc. DEPTH of zero signifies a 24 bit image, otherwise
9347 DEPTH should indicate the bit depth of the image. Print error
9348 messages via image_error if an error occurs. Value is non-zero if
9349 successful. */
9350
9351 static int
9352 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9353 struct frame *f;
9354 int width, height, depth;
9355 XImage **ximg;
9356 Pixmap *pixmap;
9357 {
9358 BITMAPINFOHEADER *header;
9359 HDC hdc;
9360 int scanline_width_bits;
9361 int remainder;
9362 int palette_colors = 0;
9363
9364 if (depth == 0)
9365 depth = 24;
9366
9367 if (depth != 1 && depth != 4 && depth != 8
9368 && depth != 16 && depth != 24 && depth != 32)
9369 {
9370 image_error ("Invalid image bit depth specified", Qnil, Qnil);
9371 return 0;
9372 }
9373
9374 scanline_width_bits = width * depth;
9375 remainder = scanline_width_bits % 32;
9376
9377 if (remainder)
9378 scanline_width_bits += 32 - remainder;
9379
9380 /* Bitmaps with a depth less than 16 need a palette. */
9381 /* BITMAPINFO structure already contains the first RGBQUAD. */
9382 if (depth < 16)
9383 palette_colors = 1 << depth - 1;
9384
9385 *ximg = xmalloc (sizeof (XImage) + palette_colors * sizeof (RGBQUAD));
9386 if (*ximg == NULL)
9387 {
9388 image_error ("Unable to allocate memory for XImage", Qnil, Qnil);
9389 return 0;
9390 }
9391
9392 header = &((*ximg)->info.bmiHeader);
9393 bzero (&((*ximg)->info), sizeof (BITMAPINFO));
9394 header->biSize = sizeof (*header);
9395 header->biWidth = width;
9396 header->biHeight = -height; /* negative indicates a top-down bitmap. */
9397 header->biPlanes = 1;
9398 header->biBitCount = depth;
9399 header->biCompression = BI_RGB;
9400 header->biClrUsed = palette_colors;
9401
9402 hdc = get_frame_dc (f);
9403
9404 /* Create a DIBSection and raster array for the bitmap,
9405 and store its handle in *pixmap. */
9406 *pixmap = CreateDIBSection (hdc, &((*ximg)->info), DIB_RGB_COLORS,
9407 &((*ximg)->data), NULL, 0);
9408
9409 /* Realize display palette and garbage all frames. */
9410 release_frame_dc (f, hdc);
9411
9412 if (*pixmap == NULL)
9413 {
9414 DWORD err = GetLastError();
9415 Lisp_Object errcode;
9416 /* All system errors are < 10000, so the following is safe. */
9417 XSETINT (errcode, (int) err);
9418 image_error ("Unable to create bitmap, error code %d", errcode, Qnil);
9419 x_destroy_x_image (*ximg);
9420 return 0;
9421 }
9422
9423 return 1;
9424 }
9425
9426
9427 /* Destroy XImage XIMG. Free XIMG->data. */
9428
9429 static void
9430 x_destroy_x_image (ximg)
9431 XImage *ximg;
9432 {
9433 xassert (interrupt_input_blocked);
9434 if (ximg)
9435 {
9436 /* Data will be freed by DestroyObject. */
9437 ximg->data = NULL;
9438 xfree (ximg);
9439 }
9440 }
9441
9442
9443 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9444 are width and height of both the image and pixmap. */
9445
9446 static void
9447 x_put_x_image (f, ximg, pixmap, width, height)
9448 struct frame *f;
9449 XImage *ximg;
9450 Pixmap pixmap;
9451 {
9452
9453 #if TODO /* W32 specific image code. */
9454 GC gc;
9455
9456 xassert (interrupt_input_blocked);
9457 gc = XCreateGC (NULL, pixmap, 0, NULL);
9458 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9459 XFreeGC (NULL, gc);
9460 #endif
9461 }
9462
9463 \f
9464 /***********************************************************************
9465 File Handling
9466 ***********************************************************************/
9467
9468 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
9469 static char *slurp_file P_ ((char *, int *));
9470
9471
9472 /* Find image file FILE. Look in data-directory, then
9473 x-bitmap-file-path. Value is the full name of the file found, or
9474 nil if not found. */
9475
9476 static Lisp_Object
9477 x_find_image_file (file)
9478 Lisp_Object file;
9479 {
9480 Lisp_Object file_found, search_path;
9481 struct gcpro gcpro1, gcpro2;
9482 int fd;
9483
9484 file_found = Qnil;
9485 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9486 GCPRO2 (file_found, search_path);
9487
9488 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
9489 fd = openp (search_path, file, Qnil, &file_found, Qnil);
9490
9491 if (fd == -1)
9492 file_found = Qnil;
9493 else
9494 close (fd);
9495
9496 UNGCPRO;
9497 return file_found;
9498 }
9499
9500
9501 /* Read FILE into memory. Value is a pointer to a buffer allocated
9502 with xmalloc holding FILE's contents. Value is null if an error
9503 occurred. *SIZE is set to the size of the file. */
9504
9505 static char *
9506 slurp_file (file, size)
9507 char *file;
9508 int *size;
9509 {
9510 FILE *fp = NULL;
9511 char *buf = NULL;
9512 struct stat st;
9513
9514 if (stat (file, &st) == 0
9515 && (fp = fopen (file, "r")) != NULL
9516 && (buf = (char *) xmalloc (st.st_size),
9517 fread (buf, 1, st.st_size, fp) == st.st_size))
9518 {
9519 *size = st.st_size;
9520 fclose (fp);
9521 }
9522 else
9523 {
9524 if (fp)
9525 fclose (fp);
9526 if (buf)
9527 {
9528 xfree (buf);
9529 buf = NULL;
9530 }
9531 }
9532
9533 return buf;
9534 }
9535
9536
9537 \f
9538 /***********************************************************************
9539 XBM images
9540 ***********************************************************************/
9541
9542 static int xbm_scan P_ ((char **, char *, char *, int *));
9543 static int xbm_load P_ ((struct frame *f, struct image *img));
9544 static int xbm_load_image P_ ((struct frame *f, struct image *img,
9545 char *, char *));
9546 static int xbm_image_p P_ ((Lisp_Object object));
9547 static int xbm_read_bitmap_data P_ ((char *, char *, int *, int *,
9548 unsigned char **));
9549 static int xbm_file_p P_ ((Lisp_Object));
9550
9551
9552 /* Indices of image specification fields in xbm_format, below. */
9553
9554 enum xbm_keyword_index
9555 {
9556 XBM_TYPE,
9557 XBM_FILE,
9558 XBM_WIDTH,
9559 XBM_HEIGHT,
9560 XBM_DATA,
9561 XBM_FOREGROUND,
9562 XBM_BACKGROUND,
9563 XBM_ASCENT,
9564 XBM_MARGIN,
9565 XBM_RELIEF,
9566 XBM_ALGORITHM,
9567 XBM_HEURISTIC_MASK,
9568 XBM_MASK,
9569 XBM_LAST
9570 };
9571
9572 /* Vector of image_keyword structures describing the format
9573 of valid XBM image specifications. */
9574
9575 static struct image_keyword xbm_format[XBM_LAST] =
9576 {
9577 {":type", IMAGE_SYMBOL_VALUE, 1},
9578 {":file", IMAGE_STRING_VALUE, 0},
9579 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9580 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9581 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9582 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9583 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9584 {":ascent", IMAGE_ASCENT_VALUE, 0},
9585 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9586 {":relief", IMAGE_INTEGER_VALUE, 0},
9587 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9588 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9589 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9590 };
9591
9592 /* Structure describing the image type XBM. */
9593
9594 static struct image_type xbm_type =
9595 {
9596 &Qxbm,
9597 xbm_image_p,
9598 xbm_load,
9599 x_clear_image,
9600 NULL
9601 };
9602
9603 /* Tokens returned from xbm_scan. */
9604
9605 enum xbm_token
9606 {
9607 XBM_TK_IDENT = 256,
9608 XBM_TK_NUMBER
9609 };
9610
9611
9612 /* Return non-zero if OBJECT is a valid XBM-type image specification.
9613 A valid specification is a list starting with the symbol `image'
9614 The rest of the list is a property list which must contain an
9615 entry `:type xbm..
9616
9617 If the specification specifies a file to load, it must contain
9618 an entry `:file FILENAME' where FILENAME is a string.
9619
9620 If the specification is for a bitmap loaded from memory it must
9621 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9622 WIDTH and HEIGHT are integers > 0. DATA may be:
9623
9624 1. a string large enough to hold the bitmap data, i.e. it must
9625 have a size >= (WIDTH + 7) / 8 * HEIGHT
9626
9627 2. a bool-vector of size >= WIDTH * HEIGHT
9628
9629 3. a vector of strings or bool-vectors, one for each line of the
9630 bitmap.
9631
9632 4. A string containing an in-memory XBM file. WIDTH and HEIGHT
9633 may not be specified in this case because they are defined in the
9634 XBM file.
9635
9636 Both the file and data forms may contain the additional entries
9637 `:background COLOR' and `:foreground COLOR'. If not present,
9638 foreground and background of the frame on which the image is
9639 displayed is used. */
9640
9641 static int
9642 xbm_image_p (object)
9643 Lisp_Object object;
9644 {
9645 struct image_keyword kw[XBM_LAST];
9646
9647 bcopy (xbm_format, kw, sizeof kw);
9648 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9649 return 0;
9650
9651 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9652
9653 if (kw[XBM_FILE].count)
9654 {
9655 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9656 return 0;
9657 }
9658 else if (kw[XBM_DATA].count && xbm_file_p (kw[XBM_DATA].value))
9659 {
9660 /* In-memory XBM file. */
9661 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_FILE].count)
9662 return 0;
9663 }
9664 else
9665 {
9666 Lisp_Object data;
9667 int width, height;
9668
9669 /* Entries for `:width', `:height' and `:data' must be present. */
9670 if (!kw[XBM_WIDTH].count
9671 || !kw[XBM_HEIGHT].count
9672 || !kw[XBM_DATA].count)
9673 return 0;
9674
9675 data = kw[XBM_DATA].value;
9676 width = XFASTINT (kw[XBM_WIDTH].value);
9677 height = XFASTINT (kw[XBM_HEIGHT].value);
9678
9679 /* Check type of data, and width and height against contents of
9680 data. */
9681 if (VECTORP (data))
9682 {
9683 int i;
9684
9685 /* Number of elements of the vector must be >= height. */
9686 if (XVECTOR (data)->size < height)
9687 return 0;
9688
9689 /* Each string or bool-vector in data must be large enough
9690 for one line of the image. */
9691 for (i = 0; i < height; ++i)
9692 {
9693 Lisp_Object elt = XVECTOR (data)->contents[i];
9694
9695 if (STRINGP (elt))
9696 {
9697 if (XSTRING (elt)->size
9698 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9699 return 0;
9700 }
9701 else if (BOOL_VECTOR_P (elt))
9702 {
9703 if (XBOOL_VECTOR (elt)->size < width)
9704 return 0;
9705 }
9706 else
9707 return 0;
9708 }
9709 }
9710 else if (STRINGP (data))
9711 {
9712 if (XSTRING (data)->size
9713 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9714 return 0;
9715 }
9716 else if (BOOL_VECTOR_P (data))
9717 {
9718 if (XBOOL_VECTOR (data)->size < width * height)
9719 return 0;
9720 }
9721 else
9722 return 0;
9723 }
9724
9725 return 1;
9726 }
9727
9728
9729 /* Scan a bitmap file. FP is the stream to read from. Value is
9730 either an enumerator from enum xbm_token, or a character for a
9731 single-character token, or 0 at end of file. If scanning an
9732 identifier, store the lexeme of the identifier in SVAL. If
9733 scanning a number, store its value in *IVAL. */
9734
9735 static int
9736 xbm_scan (s, end, sval, ival)
9737 char **s, *end;
9738 char *sval;
9739 int *ival;
9740 {
9741 int c;
9742
9743 loop:
9744
9745 /* Skip white space. */
9746 while (*s < end && (c = *(*s)++, isspace (c)))
9747 ;
9748
9749 if (*s >= end)
9750 c = 0;
9751 else if (isdigit (c))
9752 {
9753 int value = 0, digit;
9754
9755 if (c == '0' && *s < end)
9756 {
9757 c = *(*s)++;
9758 if (c == 'x' || c == 'X')
9759 {
9760 while (*s < end)
9761 {
9762 c = *(*s)++;
9763 if (isdigit (c))
9764 digit = c - '0';
9765 else if (c >= 'a' && c <= 'f')
9766 digit = c - 'a' + 10;
9767 else if (c >= 'A' && c <= 'F')
9768 digit = c - 'A' + 10;
9769 else
9770 break;
9771 value = 16 * value + digit;
9772 }
9773 }
9774 else if (isdigit (c))
9775 {
9776 value = c - '0';
9777 while (*s < end
9778 && (c = *(*s)++, isdigit (c)))
9779 value = 8 * value + c - '0';
9780 }
9781 }
9782 else
9783 {
9784 value = c - '0';
9785 while (*s < end
9786 && (c = *(*s)++, isdigit (c)))
9787 value = 10 * value + c - '0';
9788 }
9789
9790 if (*s < end)
9791 *s = *s - 1;
9792 *ival = value;
9793 c = XBM_TK_NUMBER;
9794 }
9795 else if (isalpha (c) || c == '_')
9796 {
9797 *sval++ = c;
9798 while (*s < end
9799 && (c = *(*s)++, (isalnum (c) || c == '_')))
9800 *sval++ = c;
9801 *sval = 0;
9802 if (*s < end)
9803 *s = *s - 1;
9804 c = XBM_TK_IDENT;
9805 }
9806 else if (c == '/' && **s == '*')
9807 {
9808 /* C-style comment. */
9809 ++*s;
9810 while (**s && (**s != '*' || *(*s + 1) != '/'))
9811 ++*s;
9812 if (**s)
9813 {
9814 *s += 2;
9815 goto loop;
9816 }
9817 }
9818
9819 return c;
9820 }
9821
9822
9823 /* XBM bits seem to be backward within bytes compared with how
9824 Windows does things. */
9825 static unsigned char reflect_byte (unsigned char orig)
9826 {
9827 int i;
9828 unsigned char reflected = 0x00;
9829 for (i = 0; i < 8; i++)
9830 {
9831 if (orig & (0x01 << i))
9832 reflected |= 0x80 >> i;
9833 }
9834 return reflected;
9835 }
9836
9837
9838 /* Create a Windows bitmap from X bitmap data. */
9839 static HBITMAP
9840 w32_create_pixmap_from_bitmap_data (int width, int height, char *data)
9841 {
9842 int i, j, w1, w2;
9843 char *bits, *p;
9844 HBITMAP bmp;
9845
9846 w1 = (width + 7) / 8; /* nb of 8bits elt in X bitmap */
9847 w2 = ((width + 15) / 16) * 2; /* nb of 16bits elt in W32 bitmap */
9848 bits = (char *) xmalloc (height * w2);
9849 bzero (bits, height * w2);
9850 for (i = 0; i < height; i++)
9851 {
9852 p = bits + i*w2;
9853 for (j = 0; j < w1; j++)
9854 *p++ = reflect_byte(*data++);
9855 }
9856 bmp = CreateBitmap (width, height, 1, 1, bits);
9857 xfree (bits);
9858
9859 return bmp;
9860 }
9861
9862
9863 /* Replacement for XReadBitmapFileData which isn't available under old
9864 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9865 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9866 the image. Return in *DATA the bitmap data allocated with xmalloc.
9867 Value is non-zero if successful. DATA null means just test if
9868 CONTENTS looks like an in-memory XBM file. */
9869
9870 static int
9871 xbm_read_bitmap_data (contents, end, width, height, data)
9872 char *contents, *end;
9873 int *width, *height;
9874 unsigned char **data;
9875 {
9876 char *s = contents;
9877 char buffer[BUFSIZ];
9878 int padding_p = 0;
9879 int v10 = 0;
9880 int bytes_per_line, i, nbytes;
9881 unsigned char *p;
9882 int value;
9883 int LA1;
9884
9885 #define match() \
9886 LA1 = xbm_scan (&s, end, buffer, &value)
9887
9888 #define expect(TOKEN) \
9889 if (LA1 != (TOKEN)) \
9890 goto failure; \
9891 else \
9892 match ()
9893
9894 #define expect_ident(IDENT) \
9895 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9896 match (); \
9897 else \
9898 goto failure
9899
9900 *width = *height = -1;
9901 if (data)
9902 *data = NULL;
9903 LA1 = xbm_scan (&s, end, buffer, &value);
9904
9905 /* Parse defines for width, height and hot-spots. */
9906 while (LA1 == '#')
9907 {
9908 match ();
9909 expect_ident ("define");
9910 expect (XBM_TK_IDENT);
9911
9912 if (LA1 == XBM_TK_NUMBER);
9913 {
9914 char *p = strrchr (buffer, '_');
9915 p = p ? p + 1 : buffer;
9916 if (strcmp (p, "width") == 0)
9917 *width = value;
9918 else if (strcmp (p, "height") == 0)
9919 *height = value;
9920 }
9921 expect (XBM_TK_NUMBER);
9922 }
9923
9924 if (*width < 0 || *height < 0)
9925 goto failure;
9926 else if (data == NULL)
9927 goto success;
9928
9929 /* Parse bits. Must start with `static'. */
9930 expect_ident ("static");
9931 if (LA1 == XBM_TK_IDENT)
9932 {
9933 if (strcmp (buffer, "unsigned") == 0)
9934 {
9935 match ();
9936 expect_ident ("char");
9937 }
9938 else if (strcmp (buffer, "short") == 0)
9939 {
9940 match ();
9941 v10 = 1;
9942 if (*width % 16 && *width % 16 < 9)
9943 padding_p = 1;
9944 }
9945 else if (strcmp (buffer, "char") == 0)
9946 match ();
9947 else
9948 goto failure;
9949 }
9950 else
9951 goto failure;
9952
9953 expect (XBM_TK_IDENT);
9954 expect ('[');
9955 expect (']');
9956 expect ('=');
9957 expect ('{');
9958
9959 bytes_per_line = (*width + 7) / 8 + padding_p;
9960 nbytes = bytes_per_line * *height;
9961 p = *data = (char *) xmalloc (nbytes);
9962
9963 if (v10)
9964 {
9965 for (i = 0; i < nbytes; i += 2)
9966 {
9967 int val = value;
9968 expect (XBM_TK_NUMBER);
9969
9970 *p++ = val;
9971 if (!padding_p || ((i + 2) % bytes_per_line))
9972 *p++ = value >> 8;
9973
9974 if (LA1 == ',' || LA1 == '}')
9975 match ();
9976 else
9977 goto failure;
9978 }
9979 }
9980 else
9981 {
9982 for (i = 0; i < nbytes; ++i)
9983 {
9984 int val = value;
9985 expect (XBM_TK_NUMBER);
9986
9987 *p++ = val;
9988
9989 if (LA1 == ',' || LA1 == '}')
9990 match ();
9991 else
9992 goto failure;
9993 }
9994 }
9995
9996 success:
9997 return 1;
9998
9999 failure:
10000
10001 if (data && *data)
10002 {
10003 xfree (*data);
10004 *data = NULL;
10005 }
10006 return 0;
10007
10008 #undef match
10009 #undef expect
10010 #undef expect_ident
10011 }
10012
10013
10014 /* Load XBM image IMG which will be displayed on frame F from buffer
10015 CONTENTS. END is the end of the buffer. Value is non-zero if
10016 successful. */
10017
10018 static int
10019 xbm_load_image (f, img, contents, end)
10020 struct frame *f;
10021 struct image *img;
10022 char *contents, *end;
10023 {
10024 int rc;
10025 unsigned char *data;
10026 int success_p = 0;
10027
10028 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
10029 if (rc)
10030 {
10031 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10032 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10033 Lisp_Object value;
10034
10035 xassert (img->width > 0 && img->height > 0);
10036
10037 /* Get foreground and background colors, maybe allocate colors. */
10038 value = image_spec_value (img->spec, QCforeground, NULL);
10039 if (!NILP (value))
10040 foreground = x_alloc_image_color (f, img, value, foreground);
10041 value = image_spec_value (img->spec, QCbackground, NULL);
10042 if (!NILP (value))
10043 {
10044 background = x_alloc_image_color (f, img, value, background);
10045 img->background = background;
10046 img->background_valid = 1;
10047 }
10048 img->pixmap
10049 = w32_create_pixmap_from_bitmap_data (img->width, img->height, data);
10050
10051 xfree (data);
10052
10053 if (img->pixmap == 0)
10054 {
10055 x_clear_image (f, img);
10056 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
10057 }
10058 else
10059 success_p = 1;
10060 }
10061 else
10062 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10063
10064 return success_p;
10065 }
10066
10067
10068 /* Value is non-zero if DATA looks like an in-memory XBM file. */
10069
10070 static int
10071 xbm_file_p (data)
10072 Lisp_Object data;
10073 {
10074 int w, h;
10075 return (STRINGP (data)
10076 && xbm_read_bitmap_data (XSTRING (data)->data,
10077 (XSTRING (data)->data
10078 + STRING_BYTES (XSTRING (data))),
10079 &w, &h, NULL));
10080 }
10081
10082
10083 /* Fill image IMG which is used on frame F with pixmap data. Value is
10084 non-zero if successful. */
10085
10086 static int
10087 xbm_load (f, img)
10088 struct frame *f;
10089 struct image *img;
10090 {
10091 int success_p = 0;
10092 Lisp_Object file_name;
10093
10094 xassert (xbm_image_p (img->spec));
10095
10096 /* If IMG->spec specifies a file name, create a non-file spec from it. */
10097 file_name = image_spec_value (img->spec, QCfile, NULL);
10098 if (STRINGP (file_name))
10099 {
10100 Lisp_Object file;
10101 char *contents;
10102 int size;
10103 struct gcpro gcpro1;
10104
10105 file = x_find_image_file (file_name);
10106 GCPRO1 (file);
10107 if (!STRINGP (file))
10108 {
10109 image_error ("Cannot find image file `%s'", file_name, Qnil);
10110 UNGCPRO;
10111 return 0;
10112 }
10113
10114 contents = slurp_file (XSTRING (file)->data, &size);
10115 if (contents == NULL)
10116 {
10117 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
10118 UNGCPRO;
10119 return 0;
10120 }
10121
10122 success_p = xbm_load_image (f, img, contents, contents + size);
10123 UNGCPRO;
10124 }
10125 else
10126 {
10127 struct image_keyword fmt[XBM_LAST];
10128 Lisp_Object data;
10129 int depth;
10130 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
10131 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
10132 char *bits;
10133 int parsed_p;
10134 int in_memory_file_p = 0;
10135
10136 /* See if data looks like an in-memory XBM file. */
10137 data = image_spec_value (img->spec, QCdata, NULL);
10138 in_memory_file_p = xbm_file_p (data);
10139
10140 /* Parse the image specification. */
10141 bcopy (xbm_format, fmt, sizeof fmt);
10142 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
10143 xassert (parsed_p);
10144
10145 /* Get specified width, and height. */
10146 if (!in_memory_file_p)
10147 {
10148 img->width = XFASTINT (fmt[XBM_WIDTH].value);
10149 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
10150 xassert (img->width > 0 && img->height > 0);
10151 }
10152
10153 /* Get foreground and background colors, maybe allocate colors. */
10154 if (fmt[XBM_FOREGROUND].count
10155 && STRINGP (fmt[XBM_FOREGROUND].value))
10156 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
10157 foreground);
10158 if (fmt[XBM_BACKGROUND].count
10159 && STRINGP (fmt[XBM_BACKGROUND].value))
10160 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
10161 background);
10162
10163 if (in_memory_file_p)
10164 success_p = xbm_load_image (f, img, XSTRING (data)->data,
10165 (XSTRING (data)->data
10166 + STRING_BYTES (XSTRING (data))));
10167 else
10168 {
10169 if (VECTORP (data))
10170 {
10171 int i;
10172 char *p;
10173 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
10174
10175 p = bits = (char *) alloca (nbytes * img->height);
10176 for (i = 0; i < img->height; ++i, p += nbytes)
10177 {
10178 Lisp_Object line = XVECTOR (data)->contents[i];
10179 if (STRINGP (line))
10180 bcopy (XSTRING (line)->data, p, nbytes);
10181 else
10182 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10183 }
10184 }
10185 else if (STRINGP (data))
10186 bits = XSTRING (data)->data;
10187 else
10188 bits = XBOOL_VECTOR (data)->data;
10189
10190 /* Create the pixmap. */
10191 depth = one_w32_display_info.n_cbits;
10192 img->pixmap
10193 = w32_create_pixmap_from_bitmap_data (img->width, img->height,
10194 bits);
10195
10196 if (img->pixmap)
10197 success_p = 1;
10198 else
10199 {
10200 image_error ("Unable to create pixmap for XBM image `%s'",
10201 img->spec, Qnil);
10202 x_clear_image (f, img);
10203 }
10204 }
10205 }
10206
10207 return success_p;
10208 }
10209
10210
10211 \f
10212 /***********************************************************************
10213 XPM images
10214 ***********************************************************************/
10215
10216 #if HAVE_XPM
10217
10218 static int xpm_image_p P_ ((Lisp_Object object));
10219 static int xpm_load P_ ((struct frame *f, struct image *img));
10220 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10221
10222 #include "X11/xpm.h"
10223
10224 /* The symbol `xpm' identifying XPM-format images. */
10225
10226 Lisp_Object Qxpm;
10227
10228 /* Indices of image specification fields in xpm_format, below. */
10229
10230 enum xpm_keyword_index
10231 {
10232 XPM_TYPE,
10233 XPM_FILE,
10234 XPM_DATA,
10235 XPM_ASCENT,
10236 XPM_MARGIN,
10237 XPM_RELIEF,
10238 XPM_ALGORITHM,
10239 XPM_HEURISTIC_MASK,
10240 XPM_MASK,
10241 XPM_COLOR_SYMBOLS,
10242 XPM_BACKGROUND,
10243 XPM_LAST
10244 };
10245
10246 /* Vector of image_keyword structures describing the format
10247 of valid XPM image specifications. */
10248
10249 static struct image_keyword xpm_format[XPM_LAST] =
10250 {
10251 {":type", IMAGE_SYMBOL_VALUE, 1},
10252 {":file", IMAGE_STRING_VALUE, 0},
10253 {":data", IMAGE_STRING_VALUE, 0},
10254 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10255 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10256 {":relief", IMAGE_INTEGER_VALUE, 0},
10257 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10258 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10259 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10260 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10261 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10262 };
10263
10264 /* Structure describing the image type XBM. */
10265
10266 static struct image_type xpm_type =
10267 {
10268 &Qxpm,
10269 xpm_image_p,
10270 xpm_load,
10271 x_clear_image,
10272 NULL
10273 };
10274
10275
10276 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10277 for XPM images. Such a list must consist of conses whose car and
10278 cdr are strings. */
10279
10280 static int
10281 xpm_valid_color_symbols_p (color_symbols)
10282 Lisp_Object color_symbols;
10283 {
10284 while (CONSP (color_symbols))
10285 {
10286 Lisp_Object sym = XCAR (color_symbols);
10287 if (!CONSP (sym)
10288 || !STRINGP (XCAR (sym))
10289 || !STRINGP (XCDR (sym)))
10290 break;
10291 color_symbols = XCDR (color_symbols);
10292 }
10293
10294 return NILP (color_symbols);
10295 }
10296
10297
10298 /* Value is non-zero if OBJECT is a valid XPM image specification. */
10299
10300 static int
10301 xpm_image_p (object)
10302 Lisp_Object object;
10303 {
10304 struct image_keyword fmt[XPM_LAST];
10305 bcopy (xpm_format, fmt, sizeof fmt);
10306 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10307 /* Either `:file' or `:data' must be present. */
10308 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10309 /* Either no `:color-symbols' or it's a list of conses
10310 whose car and cdr are strings. */
10311 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10312 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10313 && (fmt[XPM_ASCENT].count == 0
10314 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10315 }
10316
10317
10318 /* Load image IMG which will be displayed on frame F. Value is
10319 non-zero if successful. */
10320
10321 static int
10322 xpm_load (f, img)
10323 struct frame *f;
10324 struct image *img;
10325 {
10326 int rc, i;
10327 XpmAttributes attrs;
10328 Lisp_Object specified_file, color_symbols;
10329
10330 /* Configure the XPM lib. Use the visual of frame F. Allocate
10331 close colors. Return colors allocated. */
10332 bzero (&attrs, sizeof attrs);
10333 attrs.visual = FRAME_X_VISUAL (f);
10334 attrs.colormap = FRAME_X_COLORMAP (f);
10335 attrs.valuemask |= XpmVisual;
10336 attrs.valuemask |= XpmColormap;
10337 attrs.valuemask |= XpmReturnAllocPixels;
10338 #ifdef XpmAllocCloseColors
10339 attrs.alloc_close_colors = 1;
10340 attrs.valuemask |= XpmAllocCloseColors;
10341 #else
10342 attrs.closeness = 600;
10343 attrs.valuemask |= XpmCloseness;
10344 #endif
10345
10346 /* If image specification contains symbolic color definitions, add
10347 these to `attrs'. */
10348 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10349 if (CONSP (color_symbols))
10350 {
10351 Lisp_Object tail;
10352 XpmColorSymbol *xpm_syms;
10353 int i, size;
10354
10355 attrs.valuemask |= XpmColorSymbols;
10356
10357 /* Count number of symbols. */
10358 attrs.numsymbols = 0;
10359 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10360 ++attrs.numsymbols;
10361
10362 /* Allocate an XpmColorSymbol array. */
10363 size = attrs.numsymbols * sizeof *xpm_syms;
10364 xpm_syms = (XpmColorSymbol *) alloca (size);
10365 bzero (xpm_syms, size);
10366 attrs.colorsymbols = xpm_syms;
10367
10368 /* Fill the color symbol array. */
10369 for (tail = color_symbols, i = 0;
10370 CONSP (tail);
10371 ++i, tail = XCDR (tail))
10372 {
10373 Lisp_Object name = XCAR (XCAR (tail));
10374 Lisp_Object color = XCDR (XCAR (tail));
10375 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10376 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10377 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10378 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10379 }
10380 }
10381
10382 /* Create a pixmap for the image, either from a file, or from a
10383 string buffer containing data in the same format as an XPM file. */
10384 BLOCK_INPUT;
10385 specified_file = image_spec_value (img->spec, QCfile, NULL);
10386 if (STRINGP (specified_file))
10387 {
10388 Lisp_Object file = x_find_image_file (specified_file);
10389 if (!STRINGP (file))
10390 {
10391 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10392 UNBLOCK_INPUT;
10393 return 0;
10394 }
10395
10396 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10397 XSTRING (file)->data, &img->pixmap, &img->mask,
10398 &attrs);
10399 }
10400 else
10401 {
10402 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10403 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10404 XSTRING (buffer)->data,
10405 &img->pixmap, &img->mask,
10406 &attrs);
10407 }
10408 UNBLOCK_INPUT;
10409
10410 if (rc == XpmSuccess)
10411 {
10412 /* Remember allocated colors. */
10413 img->ncolors = attrs.nalloc_pixels;
10414 img->colors = (unsigned long *) xmalloc (img->ncolors
10415 * sizeof *img->colors);
10416 for (i = 0; i < attrs.nalloc_pixels; ++i)
10417 img->colors[i] = attrs.alloc_pixels[i];
10418
10419 img->width = attrs.width;
10420 img->height = attrs.height;
10421 xassert (img->width > 0 && img->height > 0);
10422
10423 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10424 BLOCK_INPUT;
10425 XpmFreeAttributes (&attrs);
10426 UNBLOCK_INPUT;
10427 }
10428 else
10429 {
10430 switch (rc)
10431 {
10432 case XpmOpenFailed:
10433 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10434 break;
10435
10436 case XpmFileInvalid:
10437 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10438 break;
10439
10440 case XpmNoMemory:
10441 image_error ("Out of memory (%s)", img->spec, Qnil);
10442 break;
10443
10444 case XpmColorFailed:
10445 image_error ("Color allocation error (%s)", img->spec, Qnil);
10446 break;
10447
10448 default:
10449 image_error ("Unknown error (%s)", img->spec, Qnil);
10450 break;
10451 }
10452 }
10453
10454 return rc == XpmSuccess;
10455 }
10456
10457 #endif /* HAVE_XPM != 0 */
10458
10459 \f
10460 #if 0 /* TODO : Color tables on W32. */
10461 /***********************************************************************
10462 Color table
10463 ***********************************************************************/
10464
10465 /* An entry in the color table mapping an RGB color to a pixel color. */
10466
10467 struct ct_color
10468 {
10469 int r, g, b;
10470 unsigned long pixel;
10471
10472 /* Next in color table collision list. */
10473 struct ct_color *next;
10474 };
10475
10476 /* The bucket vector size to use. Must be prime. */
10477
10478 #define CT_SIZE 101
10479
10480 /* Value is a hash of the RGB color given by R, G, and B. */
10481
10482 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10483
10484 /* The color hash table. */
10485
10486 struct ct_color **ct_table;
10487
10488 /* Number of entries in the color table. */
10489
10490 int ct_colors_allocated;
10491
10492 /* Function prototypes. */
10493
10494 static void init_color_table P_ ((void));
10495 static void free_color_table P_ ((void));
10496 static unsigned long *colors_in_color_table P_ ((int *n));
10497 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10498 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10499
10500
10501 /* Initialize the color table. */
10502
10503 static void
10504 init_color_table ()
10505 {
10506 int size = CT_SIZE * sizeof (*ct_table);
10507 ct_table = (struct ct_color **) xmalloc (size);
10508 bzero (ct_table, size);
10509 ct_colors_allocated = 0;
10510 }
10511
10512
10513 /* Free memory associated with the color table. */
10514
10515 static void
10516 free_color_table ()
10517 {
10518 int i;
10519 struct ct_color *p, *next;
10520
10521 for (i = 0; i < CT_SIZE; ++i)
10522 for (p = ct_table[i]; p; p = next)
10523 {
10524 next = p->next;
10525 xfree (p);
10526 }
10527
10528 xfree (ct_table);
10529 ct_table = NULL;
10530 }
10531
10532
10533 /* Value is a pixel color for RGB color R, G, B on frame F. If an
10534 entry for that color already is in the color table, return the
10535 pixel color of that entry. Otherwise, allocate a new color for R,
10536 G, B, and make an entry in the color table. */
10537
10538 static unsigned long
10539 lookup_rgb_color (f, r, g, b)
10540 struct frame *f;
10541 int r, g, b;
10542 {
10543 unsigned hash = CT_HASH_RGB (r, g, b);
10544 int i = hash % CT_SIZE;
10545 struct ct_color *p;
10546
10547 for (p = ct_table[i]; p; p = p->next)
10548 if (p->r == r && p->g == g && p->b == b)
10549 break;
10550
10551 if (p == NULL)
10552 {
10553 COLORREF color;
10554 Colormap cmap;
10555 int rc;
10556
10557 color = PALETTERGB (r, g, b);
10558
10559 ++ct_colors_allocated;
10560
10561 p = (struct ct_color *) xmalloc (sizeof *p);
10562 p->r = r;
10563 p->g = g;
10564 p->b = b;
10565 p->pixel = color;
10566 p->next = ct_table[i];
10567 ct_table[i] = p;
10568 }
10569
10570 return p->pixel;
10571 }
10572
10573
10574 /* Look up pixel color PIXEL which is used on frame F in the color
10575 table. If not already present, allocate it. Value is PIXEL. */
10576
10577 static unsigned long
10578 lookup_pixel_color (f, pixel)
10579 struct frame *f;
10580 unsigned long pixel;
10581 {
10582 int i = pixel % CT_SIZE;
10583 struct ct_color *p;
10584
10585 for (p = ct_table[i]; p; p = p->next)
10586 if (p->pixel == pixel)
10587 break;
10588
10589 if (p == NULL)
10590 {
10591 XColor color;
10592 Colormap cmap;
10593 int rc;
10594
10595 BLOCK_INPUT;
10596
10597 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10598 color.pixel = pixel;
10599 XQueryColor (NULL, cmap, &color);
10600 rc = x_alloc_nearest_color (f, cmap, &color);
10601 UNBLOCK_INPUT;
10602
10603 if (rc)
10604 {
10605 ++ct_colors_allocated;
10606
10607 p = (struct ct_color *) xmalloc (sizeof *p);
10608 p->r = color.red;
10609 p->g = color.green;
10610 p->b = color.blue;
10611 p->pixel = pixel;
10612 p->next = ct_table[i];
10613 ct_table[i] = p;
10614 }
10615 else
10616 return FRAME_FOREGROUND_PIXEL (f);
10617 }
10618 return p->pixel;
10619 }
10620
10621
10622 /* Value is a vector of all pixel colors contained in the color table,
10623 allocated via xmalloc. Set *N to the number of colors. */
10624
10625 static unsigned long *
10626 colors_in_color_table (n)
10627 int *n;
10628 {
10629 int i, j;
10630 struct ct_color *p;
10631 unsigned long *colors;
10632
10633 if (ct_colors_allocated == 0)
10634 {
10635 *n = 0;
10636 colors = NULL;
10637 }
10638 else
10639 {
10640 colors = (unsigned long *) xmalloc (ct_colors_allocated
10641 * sizeof *colors);
10642 *n = ct_colors_allocated;
10643
10644 for (i = j = 0; i < CT_SIZE; ++i)
10645 for (p = ct_table[i]; p; p = p->next)
10646 colors[j++] = p->pixel;
10647 }
10648
10649 return colors;
10650 }
10651
10652 #endif /* TODO */
10653
10654 \f
10655 /***********************************************************************
10656 Algorithms
10657 ***********************************************************************/
10658 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10659 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10660 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10661 static void XPutPixel (XImage *, int, int, COLORREF);
10662
10663 /* Non-zero means draw a cross on images having `:conversion
10664 disabled'. */
10665
10666 int cross_disabled_images;
10667
10668 /* Edge detection matrices for different edge-detection
10669 strategies. */
10670
10671 static int emboss_matrix[9] = {
10672 /* x - 1 x x + 1 */
10673 2, -1, 0, /* y - 1 */
10674 -1, 0, 1, /* y */
10675 0, 1, -2 /* y + 1 */
10676 };
10677
10678 static int laplace_matrix[9] = {
10679 /* x - 1 x x + 1 */
10680 1, 0, 0, /* y - 1 */
10681 0, 0, 0, /* y */
10682 0, 0, -1 /* y + 1 */
10683 };
10684
10685 /* Value is the intensity of the color whose red/green/blue values
10686 are R, G, and B. */
10687
10688 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10689
10690
10691 /* On frame F, return an array of XColor structures describing image
10692 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10693 non-zero means also fill the red/green/blue members of the XColor
10694 structures. Value is a pointer to the array of XColors structures,
10695 allocated with xmalloc; it must be freed by the caller. */
10696
10697 static XColor *
10698 x_to_xcolors (f, img, rgb_p)
10699 struct frame *f;
10700 struct image *img;
10701 int rgb_p;
10702 {
10703 int x, y;
10704 XColor *colors, *p;
10705 XImage *ximg;
10706
10707 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10708 #if 0 /* TODO: implement image colors. */
10709 /* Get the X image IMG->pixmap. */
10710 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10711 0, 0, img->width, img->height, ~0, ZPixmap);
10712
10713 /* Fill the `pixel' members of the XColor array. I wished there
10714 were an easy and portable way to circumvent XGetPixel. */
10715 p = colors;
10716 for (y = 0; y < img->height; ++y)
10717 {
10718 XColor *row = p;
10719
10720 for (x = 0; x < img->width; ++x, ++p)
10721 p->pixel = XGetPixel (ximg, x, y);
10722
10723 if (rgb_p)
10724 x_query_colors (f, row, img->width);
10725 }
10726
10727 XDestroyImage (ximg);
10728 #endif
10729 return colors;
10730 }
10731
10732 /* Put a pixel of COLOR at position X, Y in XIMG. XIMG must have been
10733 created with CreateDIBSection, with the pointer to the bit values
10734 stored in ximg->data. */
10735
10736 static void XPutPixel (ximg, x, y, color)
10737 XImage * ximg;
10738 int x, y;
10739 COLORREF color;
10740 {
10741 int width = ximg->info.bmiHeader.biWidth;
10742 int height = ximg->info.bmiHeader.biHeight;
10743 int rowbytes = width * 3;
10744 unsigned char * pixel;
10745
10746 /* Don't support putting pixels in images with palettes. */
10747 xassert (ximg->info.bmiHeader.biBitCount == 24);
10748
10749 /* Ensure scanlines are aligned on 4 byte boundaries. */
10750 if (rowbytes % 4)
10751 rowbytes += 4 - (rowbytes % 4);
10752
10753 pixel = ximg->data + y * rowbytes + x * 3;
10754 *pixel = 255 - GetRValue (color);
10755 *(pixel + 1) = 255 - GetGValue (color);
10756 *(pixel + 2) = 255 - GetBValue (color);
10757 }
10758
10759
10760 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
10761 RGB members are set. F is the frame on which this all happens.
10762 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
10763
10764 static void
10765 x_from_xcolors (f, img, colors)
10766 struct frame *f;
10767 struct image *img;
10768 XColor *colors;
10769 {
10770 int x, y;
10771 XImage *oimg;
10772 Pixmap pixmap;
10773 XColor *p;
10774 #if 0 /* TODO: color tables. */
10775 init_color_table ();
10776 #endif
10777 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10778 &oimg, &pixmap);
10779 p = colors;
10780 for (y = 0; y < img->height; ++y)
10781 for (x = 0; x < img->width; ++x, ++p)
10782 {
10783 unsigned long pixel;
10784 #if 0 /* TODO: color tables. */
10785 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10786 #else
10787 pixel = PALETTERGB (p->red, p->green, p->blue);
10788 #endif
10789 XPutPixel (oimg, x, y, pixel);
10790 }
10791
10792 xfree (colors);
10793 x_clear_image_1 (f, img, 1, 0, 1);
10794
10795 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10796 x_destroy_x_image (oimg);
10797 img->pixmap = pixmap;
10798 #if 0 /* TODO: color tables. */
10799 img->colors = colors_in_color_table (&img->ncolors);
10800 free_color_table ();
10801 #endif
10802 }
10803
10804
10805 /* On frame F, perform edge-detection on image IMG.
10806
10807 MATRIX is a nine-element array specifying the transformation
10808 matrix. See emboss_matrix for an example.
10809
10810 COLOR_ADJUST is a color adjustment added to each pixel of the
10811 outgoing image. */
10812
10813 static void
10814 x_detect_edges (f, img, matrix, color_adjust)
10815 struct frame *f;
10816 struct image *img;
10817 int matrix[9], color_adjust;
10818 {
10819 XColor *colors = x_to_xcolors (f, img, 1);
10820 XColor *new, *p;
10821 int x, y, i, sum;
10822
10823 for (i = sum = 0; i < 9; ++i)
10824 sum += abs (matrix[i]);
10825
10826 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10827
10828 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10829
10830 for (y = 0; y < img->height; ++y)
10831 {
10832 p = COLOR (new, 0, y);
10833 p->red = p->green = p->blue = 0xffff/2;
10834 p = COLOR (new, img->width - 1, y);
10835 p->red = p->green = p->blue = 0xffff/2;
10836 }
10837
10838 for (x = 1; x < img->width - 1; ++x)
10839 {
10840 p = COLOR (new, x, 0);
10841 p->red = p->green = p->blue = 0xffff/2;
10842 p = COLOR (new, x, img->height - 1);
10843 p->red = p->green = p->blue = 0xffff/2;
10844 }
10845
10846 for (y = 1; y < img->height - 1; ++y)
10847 {
10848 p = COLOR (new, 1, y);
10849
10850 for (x = 1; x < img->width - 1; ++x, ++p)
10851 {
10852 int r, g, b, y1, x1;
10853
10854 r = g = b = i = 0;
10855 for (y1 = y - 1; y1 < y + 2; ++y1)
10856 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10857 if (matrix[i])
10858 {
10859 XColor *t = COLOR (colors, x1, y1);
10860 r += matrix[i] * t->red;
10861 g += matrix[i] * t->green;
10862 b += matrix[i] * t->blue;
10863 }
10864
10865 r = (r / sum + color_adjust) & 0xffff;
10866 g = (g / sum + color_adjust) & 0xffff;
10867 b = (b / sum + color_adjust) & 0xffff;
10868 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10869 }
10870 }
10871
10872 xfree (colors);
10873 x_from_xcolors (f, img, new);
10874
10875 #undef COLOR
10876 }
10877
10878
10879 /* Perform the pre-defined `emboss' edge-detection on image IMG
10880 on frame F. */
10881
10882 static void
10883 x_emboss (f, img)
10884 struct frame *f;
10885 struct image *img;
10886 {
10887 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10888 }
10889
10890
10891 /* Transform image IMG which is used on frame F with a Laplace
10892 edge-detection algorithm. The result is an image that can be used
10893 to draw disabled buttons, for example. */
10894
10895 static void
10896 x_laplace (f, img)
10897 struct frame *f;
10898 struct image *img;
10899 {
10900 x_detect_edges (f, img, laplace_matrix, 45000);
10901 }
10902
10903
10904 /* Perform edge-detection on image IMG on frame F, with specified
10905 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10906
10907 MATRIX must be either
10908
10909 - a list of at least 9 numbers in row-major form
10910 - a vector of at least 9 numbers
10911
10912 COLOR_ADJUST nil means use a default; otherwise it must be a
10913 number. */
10914
10915 static void
10916 x_edge_detection (f, img, matrix, color_adjust)
10917 struct frame *f;
10918 struct image *img;
10919 Lisp_Object matrix, color_adjust;
10920 {
10921 int i = 0;
10922 int trans[9];
10923
10924 if (CONSP (matrix))
10925 {
10926 for (i = 0;
10927 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10928 ++i, matrix = XCDR (matrix))
10929 trans[i] = XFLOATINT (XCAR (matrix));
10930 }
10931 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10932 {
10933 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10934 trans[i] = XFLOATINT (AREF (matrix, i));
10935 }
10936
10937 if (NILP (color_adjust))
10938 color_adjust = make_number (0xffff / 2);
10939
10940 if (i == 9 && NUMBERP (color_adjust))
10941 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10942 }
10943
10944
10945 /* Transform image IMG on frame F so that it looks disabled. */
10946
10947 static void
10948 x_disable_image (f, img)
10949 struct frame *f;
10950 struct image *img;
10951 {
10952 struct w32_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10953
10954 if (dpyinfo->n_planes * dpyinfo->n_cbits >= 2)
10955 {
10956 /* Color (or grayscale). Convert to gray, and equalize. Just
10957 drawing such images with a stipple can look very odd, so
10958 we're using this method instead. */
10959 XColor *colors = x_to_xcolors (f, img, 1);
10960 XColor *p, *end;
10961 const int h = 15000;
10962 const int l = 30000;
10963
10964 for (p = colors, end = colors + img->width * img->height;
10965 p < end;
10966 ++p)
10967 {
10968 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10969 int i2 = (0xffff - h - l) * i / 0xffff + l;
10970 p->red = p->green = p->blue = i2;
10971 }
10972
10973 x_from_xcolors (f, img, colors);
10974 }
10975
10976 /* Draw a cross over the disabled image, if we must or if we
10977 should. */
10978 if (dpyinfo->n_planes * dpyinfo->n_cbits < 2 || cross_disabled_images)
10979 {
10980 #if 0 /* TODO: full image support */
10981 Display *dpy = FRAME_X_DISPLAY (f);
10982 GC gc;
10983
10984 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10985 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10986 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10987 img->width - 1, img->height - 1);
10988 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10989 img->width - 1, 0);
10990 XFreeGC (dpy, gc);
10991
10992 if (img->mask)
10993 {
10994 gc = XCreateGC (dpy, img->mask, 0, NULL);
10995 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10996 XDrawLine (dpy, img->mask, gc, 0, 0,
10997 img->width - 1, img->height - 1);
10998 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10999 img->width - 1, 0);
11000 XFreeGC (dpy, gc);
11001 }
11002 #endif
11003 }
11004 }
11005
11006
11007 /* Build a mask for image IMG which is used on frame F. FILE is the
11008 name of an image file, for error messages. HOW determines how to
11009 determine the background color of IMG. If it is a list '(R G B)',
11010 with R, G, and B being integers >= 0, take that as the color of the
11011 background. Otherwise, determine the background color of IMG
11012 heuristically. Value is non-zero if successful. */
11013
11014 static int
11015 x_build_heuristic_mask (f, img, how)
11016 struct frame *f;
11017 struct image *img;
11018 Lisp_Object how;
11019 {
11020 #if 0 /* TODO: full image support. */
11021 Display *dpy = FRAME_W32_DISPLAY (f);
11022 XImage *ximg, *mask_img;
11023 int x, y, rc, use_img_background;
11024 unsigned long bg = 0;
11025
11026 if (img->mask)
11027 {
11028 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
11029 img->mask = None;
11030 img->background_transparent_valid = 0;
11031 }
11032
11033 /* Create an image and pixmap serving as mask. */
11034 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
11035 &mask_img, &img->mask);
11036 if (!rc)
11037 return 0;
11038
11039 /* Get the X image of IMG->pixmap. */
11040 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
11041 ~0, ZPixmap);
11042
11043 /* Determine the background color of ximg. If HOW is `(R G B)'
11044 take that as color. Otherwise, use the image's background color. */
11045 use_img_background = 1;
11046
11047 if (CONSP (how))
11048 {
11049 int rgb[3], i;
11050
11051 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
11052 {
11053 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
11054 how = XCDR (how);
11055 }
11056
11057 if (i == 3 && NILP (how))
11058 {
11059 char color_name[30];
11060 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
11061 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
11062 use_img_background = 0;
11063 }
11064 }
11065
11066 if (use_img_background)
11067 bg = four_corners_best (ximg, img->width, img->height);
11068
11069 /* Set all bits in mask_img to 1 whose color in ximg is different
11070 from the background color bg. */
11071 for (y = 0; y < img->height; ++y)
11072 for (x = 0; x < img->width; ++x)
11073 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
11074
11075 /* Fill in the background_transparent field while we have the mask handy. */
11076 image_background_transparent (img, f, mask_img);
11077
11078 /* Put mask_img into img->mask. */
11079 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11080 x_destroy_x_image (mask_img);
11081 XDestroyImage (ximg);
11082
11083 return 1;
11084 #else
11085 return 0;
11086 #endif
11087 }
11088
11089 \f
11090 /***********************************************************************
11091 PBM (mono, gray, color)
11092 ***********************************************************************/
11093
11094 static int pbm_image_p P_ ((Lisp_Object object));
11095 static int pbm_load P_ ((struct frame *f, struct image *img));
11096 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
11097
11098 /* The symbol `pbm' identifying images of this type. */
11099
11100 Lisp_Object Qpbm;
11101
11102 /* Indices of image specification fields in gs_format, below. */
11103
11104 enum pbm_keyword_index
11105 {
11106 PBM_TYPE,
11107 PBM_FILE,
11108 PBM_DATA,
11109 PBM_ASCENT,
11110 PBM_MARGIN,
11111 PBM_RELIEF,
11112 PBM_ALGORITHM,
11113 PBM_HEURISTIC_MASK,
11114 PBM_MASK,
11115 PBM_FOREGROUND,
11116 PBM_BACKGROUND,
11117 PBM_LAST
11118 };
11119
11120 /* Vector of image_keyword structures describing the format
11121 of valid user-defined image specifications. */
11122
11123 static struct image_keyword pbm_format[PBM_LAST] =
11124 {
11125 {":type", IMAGE_SYMBOL_VALUE, 1},
11126 {":file", IMAGE_STRING_VALUE, 0},
11127 {":data", IMAGE_STRING_VALUE, 0},
11128 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11129 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11130 {":relief", IMAGE_INTEGER_VALUE, 0},
11131 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11132 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11133 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11134 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
11135 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11136 };
11137
11138 /* Structure describing the image type `pbm'. */
11139
11140 static struct image_type pbm_type =
11141 {
11142 &Qpbm,
11143 pbm_image_p,
11144 pbm_load,
11145 x_clear_image,
11146 NULL
11147 };
11148
11149
11150 /* Return non-zero if OBJECT is a valid PBM image specification. */
11151
11152 static int
11153 pbm_image_p (object)
11154 Lisp_Object object;
11155 {
11156 struct image_keyword fmt[PBM_LAST];
11157
11158 bcopy (pbm_format, fmt, sizeof fmt);
11159
11160 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
11161 || (fmt[PBM_ASCENT].count
11162 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
11163 return 0;
11164
11165 /* Must specify either :data or :file. */
11166 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
11167 }
11168
11169
11170 /* Scan a decimal number from *S and return it. Advance *S while
11171 reading the number. END is the end of the string. Value is -1 at
11172 end of input. */
11173
11174 static int
11175 pbm_scan_number (s, end)
11176 unsigned char **s, *end;
11177 {
11178 int c, val = -1;
11179
11180 while (*s < end)
11181 {
11182 /* Skip white-space. */
11183 while (*s < end && (c = *(*s)++, isspace (c)))
11184 ;
11185
11186 if (c == '#')
11187 {
11188 /* Skip comment to end of line. */
11189 while (*s < end && (c = *(*s)++, c != '\n'))
11190 ;
11191 }
11192 else if (isdigit (c))
11193 {
11194 /* Read decimal number. */
11195 val = c - '0';
11196 while (*s < end && (c = *(*s)++, isdigit (c)))
11197 val = 10 * val + c - '0';
11198 break;
11199 }
11200 else
11201 break;
11202 }
11203
11204 return val;
11205 }
11206
11207
11208 /* Read FILE into memory. Value is a pointer to a buffer allocated
11209 with xmalloc holding FILE's contents. Value is null if an error
11210 occurred. *SIZE is set to the size of the file. */
11211
11212 static char *
11213 pbm_read_file (file, size)
11214 Lisp_Object file;
11215 int *size;
11216 {
11217 FILE *fp = NULL;
11218 char *buf = NULL;
11219 struct stat st;
11220
11221 if (stat (XSTRING (file)->data, &st) == 0
11222 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11223 && (buf = (char *) xmalloc (st.st_size),
11224 fread (buf, 1, st.st_size, fp) == st.st_size))
11225 {
11226 *size = st.st_size;
11227 fclose (fp);
11228 }
11229 else
11230 {
11231 if (fp)
11232 fclose (fp);
11233 if (buf)
11234 {
11235 xfree (buf);
11236 buf = NULL;
11237 }
11238 }
11239
11240 return buf;
11241 }
11242
11243
11244 /* Load PBM image IMG for use on frame F. */
11245
11246 static int
11247 pbm_load (f, img)
11248 struct frame *f;
11249 struct image *img;
11250 {
11251 int raw_p, x, y;
11252 int width, height, max_color_idx = 0;
11253 XImage *ximg;
11254 Lisp_Object file, specified_file;
11255 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11256 struct gcpro gcpro1;
11257 unsigned char *contents = NULL;
11258 unsigned char *end, *p;
11259 int size;
11260
11261 specified_file = image_spec_value (img->spec, QCfile, NULL);
11262 file = Qnil;
11263 GCPRO1 (file);
11264
11265 if (STRINGP (specified_file))
11266 {
11267 file = x_find_image_file (specified_file);
11268 if (!STRINGP (file))
11269 {
11270 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11271 UNGCPRO;
11272 return 0;
11273 }
11274
11275 contents = slurp_file (XSTRING (file)->data, &size);
11276 if (contents == NULL)
11277 {
11278 image_error ("Error reading `%s'", file, Qnil);
11279 UNGCPRO;
11280 return 0;
11281 }
11282
11283 p = contents;
11284 end = contents + size;
11285 }
11286 else
11287 {
11288 Lisp_Object data;
11289 data = image_spec_value (img->spec, QCdata, NULL);
11290 p = XSTRING (data)->data;
11291 end = p + STRING_BYTES (XSTRING (data));
11292 }
11293
11294 /* Check magic number. */
11295 if (end - p < 2 || *p++ != 'P')
11296 {
11297 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11298 error:
11299 xfree (contents);
11300 UNGCPRO;
11301 return 0;
11302 }
11303
11304 switch (*p++)
11305 {
11306 case '1':
11307 raw_p = 0, type = PBM_MONO;
11308 break;
11309
11310 case '2':
11311 raw_p = 0, type = PBM_GRAY;
11312 break;
11313
11314 case '3':
11315 raw_p = 0, type = PBM_COLOR;
11316 break;
11317
11318 case '4':
11319 raw_p = 1, type = PBM_MONO;
11320 break;
11321
11322 case '5':
11323 raw_p = 1, type = PBM_GRAY;
11324 break;
11325
11326 case '6':
11327 raw_p = 1, type = PBM_COLOR;
11328 break;
11329
11330 default:
11331 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11332 goto error;
11333 }
11334
11335 /* Read width, height, maximum color-component. Characters
11336 starting with `#' up to the end of a line are ignored. */
11337 width = pbm_scan_number (&p, end);
11338 height = pbm_scan_number (&p, end);
11339
11340 if (type != PBM_MONO)
11341 {
11342 max_color_idx = pbm_scan_number (&p, end);
11343 if (raw_p && max_color_idx > 255)
11344 max_color_idx = 255;
11345 }
11346
11347 if (width < 0
11348 || height < 0
11349 || (type != PBM_MONO && max_color_idx < 0))
11350 goto error;
11351
11352 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
11353 goto error;
11354
11355 #if 0 /* TODO: color tables. */
11356 /* Initialize the color hash table. */
11357 init_color_table ();
11358 #endif
11359
11360 if (type == PBM_MONO)
11361 {
11362 int c = 0, g;
11363 struct image_keyword fmt[PBM_LAST];
11364 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11365 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11366
11367 /* Parse the image specification. */
11368 bcopy (pbm_format, fmt, sizeof fmt);
11369 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11370
11371 /* Get foreground and background colors, maybe allocate colors. */
11372 if (fmt[PBM_FOREGROUND].count
11373 && STRINGP (fmt[PBM_FOREGROUND].value))
11374 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11375 if (fmt[PBM_BACKGROUND].count
11376 && STRINGP (fmt[PBM_BACKGROUND].value))
11377 {
11378 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11379 img->background = bg;
11380 img->background_valid = 1;
11381 }
11382
11383 for (y = 0; y < height; ++y)
11384 for (x = 0; x < width; ++x)
11385 {
11386 if (raw_p)
11387 {
11388 if ((x & 7) == 0)
11389 c = *p++;
11390 g = c & 0x80;
11391 c <<= 1;
11392 }
11393 else
11394 g = pbm_scan_number (&p, end);
11395
11396 XPutPixel (ximg, x, y, g ? fg : bg);
11397 }
11398 }
11399 else
11400 {
11401 for (y = 0; y < height; ++y)
11402 for (x = 0; x < width; ++x)
11403 {
11404 int r, g, b;
11405
11406 if (type == PBM_GRAY)
11407 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11408 else if (raw_p)
11409 {
11410 r = *p++;
11411 g = *p++;
11412 b = *p++;
11413 }
11414 else
11415 {
11416 r = pbm_scan_number (&p, end);
11417 g = pbm_scan_number (&p, end);
11418 b = pbm_scan_number (&p, end);
11419 }
11420
11421 if (r < 0 || g < 0 || b < 0)
11422 {
11423 x_destroy_x_image (ximg);
11424 image_error ("Invalid pixel value in image `%s'",
11425 img->spec, Qnil);
11426 goto error;
11427 }
11428
11429 /* RGB values are now in the range 0..max_color_idx.
11430 Scale this to the range 0..0xff supported by W32. */
11431 r = (int) ((double) r * 255 / max_color_idx);
11432 g = (int) ((double) g * 255 / max_color_idx);
11433 b = (int) ((double) b * 255 / max_color_idx);
11434 XPutPixel (ximg, x, y,
11435 #if 0 /* TODO: color tables. */
11436 lookup_rgb_color (f, r, g, b));
11437 #else
11438 PALETTERGB (r, g, b));
11439 #endif
11440 }
11441 }
11442
11443 #if 0 /* TODO: color tables. */
11444 /* Store in IMG->colors the colors allocated for the image, and
11445 free the color table. */
11446 img->colors = colors_in_color_table (&img->ncolors);
11447 free_color_table ();
11448 #endif
11449 /* Maybe fill in the background field while we have ximg handy. */
11450 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11451 IMAGE_BACKGROUND (img, f, ximg);
11452
11453 /* Put the image into a pixmap. */
11454 x_put_x_image (f, ximg, img->pixmap, width, height);
11455 x_destroy_x_image (ximg);
11456
11457 img->width = width;
11458 img->height = height;
11459
11460 UNGCPRO;
11461 xfree (contents);
11462 return 1;
11463 }
11464
11465 \f
11466 /***********************************************************************
11467 PNG
11468 ***********************************************************************/
11469
11470 #if HAVE_PNG
11471
11472 #include <png.h>
11473
11474 /* Function prototypes. */
11475
11476 static int png_image_p P_ ((Lisp_Object object));
11477 static int png_load P_ ((struct frame *f, struct image *img));
11478
11479 /* The symbol `png' identifying images of this type. */
11480
11481 Lisp_Object Qpng;
11482
11483 /* Indices of image specification fields in png_format, below. */
11484
11485 enum png_keyword_index
11486 {
11487 PNG_TYPE,
11488 PNG_DATA,
11489 PNG_FILE,
11490 PNG_ASCENT,
11491 PNG_MARGIN,
11492 PNG_RELIEF,
11493 PNG_ALGORITHM,
11494 PNG_HEURISTIC_MASK,
11495 PNG_MASK,
11496 PNG_BACKGROUND,
11497 PNG_LAST
11498 };
11499
11500 /* Vector of image_keyword structures describing the format
11501 of valid user-defined image specifications. */
11502
11503 static struct image_keyword png_format[PNG_LAST] =
11504 {
11505 {":type", IMAGE_SYMBOL_VALUE, 1},
11506 {":data", IMAGE_STRING_VALUE, 0},
11507 {":file", IMAGE_STRING_VALUE, 0},
11508 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11509 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11510 {":relief", IMAGE_INTEGER_VALUE, 0},
11511 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11512 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11513 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11514 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11515 };
11516
11517 /* Structure describing the image type `png'. */
11518
11519 static struct image_type png_type =
11520 {
11521 &Qpng,
11522 png_image_p,
11523 png_load,
11524 x_clear_image,
11525 NULL
11526 };
11527
11528
11529 /* Return non-zero if OBJECT is a valid PNG image specification. */
11530
11531 static int
11532 png_image_p (object)
11533 Lisp_Object object;
11534 {
11535 struct image_keyword fmt[PNG_LAST];
11536 bcopy (png_format, fmt, sizeof fmt);
11537
11538 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11539 || (fmt[PNG_ASCENT].count
11540 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11541 return 0;
11542
11543 /* Must specify either the :data or :file keyword. */
11544 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11545 }
11546
11547
11548 /* Error and warning handlers installed when the PNG library
11549 is initialized. */
11550
11551 static void
11552 my_png_error (png_ptr, msg)
11553 png_struct *png_ptr;
11554 char *msg;
11555 {
11556 xassert (png_ptr != NULL);
11557 image_error ("PNG error: %s", build_string (msg), Qnil);
11558 longjmp (png_ptr->jmpbuf, 1);
11559 }
11560
11561
11562 static void
11563 my_png_warning (png_ptr, msg)
11564 png_struct *png_ptr;
11565 char *msg;
11566 {
11567 xassert (png_ptr != NULL);
11568 image_error ("PNG warning: %s", build_string (msg), Qnil);
11569 }
11570
11571 /* Memory source for PNG decoding. */
11572
11573 struct png_memory_storage
11574 {
11575 unsigned char *bytes; /* The data */
11576 size_t len; /* How big is it? */
11577 int index; /* Where are we? */
11578 };
11579
11580
11581 /* Function set as reader function when reading PNG image from memory.
11582 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11583 bytes from the input to DATA. */
11584
11585 static void
11586 png_read_from_memory (png_ptr, data, length)
11587 png_structp png_ptr;
11588 png_bytep data;
11589 png_size_t length;
11590 {
11591 struct png_memory_storage *tbr
11592 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11593
11594 if (length > tbr->len - tbr->index)
11595 png_error (png_ptr, "Read error");
11596
11597 bcopy (tbr->bytes + tbr->index, data, length);
11598 tbr->index = tbr->index + length;
11599 }
11600
11601 /* Load PNG image IMG for use on frame F. Value is non-zero if
11602 successful. */
11603
11604 static int
11605 png_load (f, img)
11606 struct frame *f;
11607 struct image *img;
11608 {
11609 Lisp_Object file, specified_file;
11610 Lisp_Object specified_data;
11611 int x, y, i;
11612 XImage *ximg, *mask_img = NULL;
11613 struct gcpro gcpro1;
11614 png_struct *png_ptr = NULL;
11615 png_info *info_ptr = NULL, *end_info = NULL;
11616 FILE *volatile fp = NULL;
11617 png_byte sig[8];
11618 png_byte *volatile pixels = NULL;
11619 png_byte **volatile rows = NULL;
11620 png_uint_32 width, height;
11621 int bit_depth, color_type, interlace_type;
11622 png_byte channels;
11623 png_uint_32 row_bytes;
11624 int transparent_p;
11625 char *gamma_str;
11626 double screen_gamma, image_gamma;
11627 int intent;
11628 struct png_memory_storage tbr; /* Data to be read */
11629
11630 /* Find out what file to load. */
11631 specified_file = image_spec_value (img->spec, QCfile, NULL);
11632 specified_data = image_spec_value (img->spec, QCdata, NULL);
11633 file = Qnil;
11634 GCPRO1 (file);
11635
11636 if (NILP (specified_data))
11637 {
11638 file = x_find_image_file (specified_file);
11639 if (!STRINGP (file))
11640 {
11641 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11642 UNGCPRO;
11643 return 0;
11644 }
11645
11646 /* Open the image file. */
11647 fp = fopen (XSTRING (file)->data, "rb");
11648 if (!fp)
11649 {
11650 image_error ("Cannot open image file `%s'", file, Qnil);
11651 UNGCPRO;
11652 fclose (fp);
11653 return 0;
11654 }
11655
11656 /* Check PNG signature. */
11657 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11658 || !png_check_sig (sig, sizeof sig))
11659 {
11660 image_error ("Not a PNG file:` %s'", file, Qnil);
11661 UNGCPRO;
11662 fclose (fp);
11663 return 0;
11664 }
11665 }
11666 else
11667 {
11668 /* Read from memory. */
11669 tbr.bytes = XSTRING (specified_data)->data;
11670 tbr.len = STRING_BYTES (XSTRING (specified_data));
11671 tbr.index = 0;
11672
11673 /* Check PNG signature. */
11674 if (tbr.len < sizeof sig
11675 || !png_check_sig (tbr.bytes, sizeof sig))
11676 {
11677 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11678 UNGCPRO;
11679 return 0;
11680 }
11681
11682 /* Need to skip past the signature. */
11683 tbr.bytes += sizeof (sig);
11684 }
11685
11686 /* Initialize read and info structs for PNG lib. */
11687 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11688 my_png_error, my_png_warning);
11689 if (!png_ptr)
11690 {
11691 if (fp) fclose (fp);
11692 UNGCPRO;
11693 return 0;
11694 }
11695
11696 info_ptr = png_create_info_struct (png_ptr);
11697 if (!info_ptr)
11698 {
11699 png_destroy_read_struct (&png_ptr, NULL, NULL);
11700 if (fp) fclose (fp);
11701 UNGCPRO;
11702 return 0;
11703 }
11704
11705 end_info = png_create_info_struct (png_ptr);
11706 if (!end_info)
11707 {
11708 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11709 if (fp) fclose (fp);
11710 UNGCPRO;
11711 return 0;
11712 }
11713
11714 /* Set error jump-back. We come back here when the PNG library
11715 detects an error. */
11716 if (setjmp (png_ptr->jmpbuf))
11717 {
11718 error:
11719 if (png_ptr)
11720 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11721 xfree (pixels);
11722 xfree (rows);
11723 if (fp) fclose (fp);
11724 UNGCPRO;
11725 return 0;
11726 }
11727
11728 /* Read image info. */
11729 if (!NILP (specified_data))
11730 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11731 else
11732 png_init_io (png_ptr, fp);
11733
11734 png_set_sig_bytes (png_ptr, sizeof sig);
11735 png_read_info (png_ptr, info_ptr);
11736 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11737 &interlace_type, NULL, NULL);
11738
11739 /* If image contains simply transparency data, we prefer to
11740 construct a clipping mask. */
11741 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11742 transparent_p = 1;
11743 else
11744 transparent_p = 0;
11745
11746 /* This function is easier to write if we only have to handle
11747 one data format: RGB or RGBA with 8 bits per channel. Let's
11748 transform other formats into that format. */
11749
11750 /* Strip more than 8 bits per channel. */
11751 if (bit_depth == 16)
11752 png_set_strip_16 (png_ptr);
11753
11754 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11755 if available. */
11756 png_set_expand (png_ptr);
11757
11758 /* Convert grayscale images to RGB. */
11759 if (color_type == PNG_COLOR_TYPE_GRAY
11760 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11761 png_set_gray_to_rgb (png_ptr);
11762
11763 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11764 gamma_str = getenv ("SCREEN_GAMMA");
11765 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11766
11767 /* Tell the PNG lib to handle gamma correction for us. */
11768
11769 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11770 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11771 /* There is a special chunk in the image specifying the gamma. */
11772 png_set_sRGB (png_ptr, info_ptr, intent);
11773 else
11774 #endif
11775 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11776 /* Image contains gamma information. */
11777 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11778 else
11779 /* Use a default of 0.5 for the image gamma. */
11780 png_set_gamma (png_ptr, screen_gamma, 0.5);
11781
11782 /* Handle alpha channel by combining the image with a background
11783 color. Do this only if a real alpha channel is supplied. For
11784 simple transparency, we prefer a clipping mask. */
11785 if (!transparent_p)
11786 {
11787 png_color_16 *image_background;
11788 Lisp_Object specified_bg
11789 = image_spec_value (img->spec, QCbackground, NULL);
11790
11791
11792 if (STRINGP (specified_bg))
11793 /* The user specified `:background', use that. */
11794 {
11795 COLORREF color;
11796 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11797 {
11798 png_color_16 user_bg;
11799
11800 bzero (&user_bg, sizeof user_bg);
11801 user_bg.red = color.red;
11802 user_bg.green = color.green;
11803 user_bg.blue = color.blue;
11804
11805 png_set_background (png_ptr, &user_bg,
11806 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11807 }
11808 }
11809 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
11810 /* Image contains a background color with which to
11811 combine the image. */
11812 png_set_background (png_ptr, image_background,
11813 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11814 else
11815 {
11816 /* Image does not contain a background color with which
11817 to combine the image data via an alpha channel. Use
11818 the frame's background instead. */
11819 XColor color;
11820 Colormap cmap;
11821 png_color_16 frame_background;
11822
11823 cmap = FRAME_X_COLORMAP (f);
11824 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11825 x_query_color (f, &color);
11826
11827 bzero (&frame_background, sizeof frame_background);
11828 frame_background.red = color.red;
11829 frame_background.green = color.green;
11830 frame_background.blue = color.blue;
11831
11832 png_set_background (png_ptr, &frame_background,
11833 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11834 }
11835 }
11836
11837 /* Update info structure. */
11838 png_read_update_info (png_ptr, info_ptr);
11839
11840 /* Get number of channels. Valid values are 1 for grayscale images
11841 and images with a palette, 2 for grayscale images with transparency
11842 information (alpha channel), 3 for RGB images, and 4 for RGB
11843 images with alpha channel, i.e. RGBA. If conversions above were
11844 sufficient we should only have 3 or 4 channels here. */
11845 channels = png_get_channels (png_ptr, info_ptr);
11846 xassert (channels == 3 || channels == 4);
11847
11848 /* Number of bytes needed for one row of the image. */
11849 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11850
11851 /* Allocate memory for the image. */
11852 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11853 rows = (png_byte **) xmalloc (height * sizeof *rows);
11854 for (i = 0; i < height; ++i)
11855 rows[i] = pixels + i * row_bytes;
11856
11857 /* Read the entire image. */
11858 png_read_image (png_ptr, rows);
11859 png_read_end (png_ptr, info_ptr);
11860 if (fp)
11861 {
11862 fclose (fp);
11863 fp = NULL;
11864 }
11865
11866 /* Create the X image and pixmap. */
11867 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11868 &img->pixmap))
11869 goto error;
11870
11871 /* Create an image and pixmap serving as mask if the PNG image
11872 contains an alpha channel. */
11873 if (channels == 4
11874 && !transparent_p
11875 && !x_create_x_image_and_pixmap (f, width, height, 1,
11876 &mask_img, &img->mask))
11877 {
11878 x_destroy_x_image (ximg);
11879 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11880 img->pixmap = 0;
11881 goto error;
11882 }
11883
11884 /* Fill the X image and mask from PNG data. */
11885 init_color_table ();
11886
11887 for (y = 0; y < height; ++y)
11888 {
11889 png_byte *p = rows[y];
11890
11891 for (x = 0; x < width; ++x)
11892 {
11893 unsigned r, g, b;
11894
11895 r = *p++ << 8;
11896 g = *p++ << 8;
11897 b = *p++ << 8;
11898 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11899
11900 /* An alpha channel, aka mask channel, associates variable
11901 transparency with an image. Where other image formats
11902 support binary transparency---fully transparent or fully
11903 opaque---PNG allows up to 254 levels of partial transparency.
11904 The PNG library implements partial transparency by combining
11905 the image with a specified background color.
11906
11907 I'm not sure how to handle this here nicely: because the
11908 background on which the image is displayed may change, for
11909 real alpha channel support, it would be necessary to create
11910 a new image for each possible background.
11911
11912 What I'm doing now is that a mask is created if we have
11913 boolean transparency information. Otherwise I'm using
11914 the frame's background color to combine the image with. */
11915
11916 if (channels == 4)
11917 {
11918 if (mask_img)
11919 XPutPixel (mask_img, x, y, *p > 0);
11920 ++p;
11921 }
11922 }
11923 }
11924
11925 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11926 /* Set IMG's background color from the PNG image, unless the user
11927 overrode it. */
11928 {
11929 png_color_16 *bg;
11930 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11931 {
11932 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11933 img->background_valid = 1;
11934 }
11935 }
11936
11937 /* Remember colors allocated for this image. */
11938 img->colors = colors_in_color_table (&img->ncolors);
11939 free_color_table ();
11940
11941 /* Clean up. */
11942 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11943 xfree (rows);
11944 xfree (pixels);
11945
11946 img->width = width;
11947 img->height = height;
11948
11949 /* Maybe fill in the background field while we have ximg handy. */
11950 IMAGE_BACKGROUND (img, f, ximg);
11951
11952 /* Put the image into the pixmap, then free the X image and its buffer. */
11953 x_put_x_image (f, ximg, img->pixmap, width, height);
11954 x_destroy_x_image (ximg);
11955
11956 /* Same for the mask. */
11957 if (mask_img)
11958 {
11959 /* Fill in the background_transparent field while we have the mask
11960 handy. */
11961 image_background_transparent (img, f, mask_img);
11962
11963 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11964 x_destroy_x_image (mask_img);
11965 }
11966
11967 UNGCPRO;
11968 return 1;
11969 }
11970
11971 #endif /* HAVE_PNG != 0 */
11972
11973
11974 \f
11975 /***********************************************************************
11976 JPEG
11977 ***********************************************************************/
11978
11979 #if HAVE_JPEG
11980
11981 /* Work around a warning about HAVE_STDLIB_H being redefined in
11982 jconfig.h. */
11983 #ifdef HAVE_STDLIB_H
11984 #define HAVE_STDLIB_H_1
11985 #undef HAVE_STDLIB_H
11986 #endif /* HAVE_STLIB_H */
11987
11988 #include <jpeglib.h>
11989 #include <jerror.h>
11990 #include <setjmp.h>
11991
11992 #ifdef HAVE_STLIB_H_1
11993 #define HAVE_STDLIB_H 1
11994 #endif
11995
11996 static int jpeg_image_p P_ ((Lisp_Object object));
11997 static int jpeg_load P_ ((struct frame *f, struct image *img));
11998
11999 /* The symbol `jpeg' identifying images of this type. */
12000
12001 Lisp_Object Qjpeg;
12002
12003 /* Indices of image specification fields in gs_format, below. */
12004
12005 enum jpeg_keyword_index
12006 {
12007 JPEG_TYPE,
12008 JPEG_DATA,
12009 JPEG_FILE,
12010 JPEG_ASCENT,
12011 JPEG_MARGIN,
12012 JPEG_RELIEF,
12013 JPEG_ALGORITHM,
12014 JPEG_HEURISTIC_MASK,
12015 JPEG_MASK,
12016 JPEG_BACKGROUND,
12017 JPEG_LAST
12018 };
12019
12020 /* Vector of image_keyword structures describing the format
12021 of valid user-defined image specifications. */
12022
12023 static struct image_keyword jpeg_format[JPEG_LAST] =
12024 {
12025 {":type", IMAGE_SYMBOL_VALUE, 1},
12026 {":data", IMAGE_STRING_VALUE, 0},
12027 {":file", IMAGE_STRING_VALUE, 0},
12028 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12029 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12030 {":relief", IMAGE_INTEGER_VALUE, 0},
12031 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12032 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12033 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12034 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12035 };
12036
12037 /* Structure describing the image type `jpeg'. */
12038
12039 static struct image_type jpeg_type =
12040 {
12041 &Qjpeg,
12042 jpeg_image_p,
12043 jpeg_load,
12044 x_clear_image,
12045 NULL
12046 };
12047
12048
12049 /* Return non-zero if OBJECT is a valid JPEG image specification. */
12050
12051 static int
12052 jpeg_image_p (object)
12053 Lisp_Object object;
12054 {
12055 struct image_keyword fmt[JPEG_LAST];
12056
12057 bcopy (jpeg_format, fmt, sizeof fmt);
12058
12059 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
12060 || (fmt[JPEG_ASCENT].count
12061 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
12062 return 0;
12063
12064 /* Must specify either the :data or :file keyword. */
12065 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
12066 }
12067
12068
12069 struct my_jpeg_error_mgr
12070 {
12071 struct jpeg_error_mgr pub;
12072 jmp_buf setjmp_buffer;
12073 };
12074
12075 static void
12076 my_error_exit (cinfo)
12077 j_common_ptr cinfo;
12078 {
12079 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
12080 longjmp (mgr->setjmp_buffer, 1);
12081 }
12082
12083 /* Init source method for JPEG data source manager. Called by
12084 jpeg_read_header() before any data is actually read. See
12085 libjpeg.doc from the JPEG lib distribution. */
12086
12087 static void
12088 our_init_source (cinfo)
12089 j_decompress_ptr cinfo;
12090 {
12091 }
12092
12093
12094 /* Fill input buffer method for JPEG data source manager. Called
12095 whenever more data is needed. We read the whole image in one step,
12096 so this only adds a fake end of input marker at the end. */
12097
12098 static boolean
12099 our_fill_input_buffer (cinfo)
12100 j_decompress_ptr cinfo;
12101 {
12102 /* Insert a fake EOI marker. */
12103 struct jpeg_source_mgr *src = cinfo->src;
12104 static JOCTET buffer[2];
12105
12106 buffer[0] = (JOCTET) 0xFF;
12107 buffer[1] = (JOCTET) JPEG_EOI;
12108
12109 src->next_input_byte = buffer;
12110 src->bytes_in_buffer = 2;
12111 return TRUE;
12112 }
12113
12114
12115 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
12116 is the JPEG data source manager. */
12117
12118 static void
12119 our_skip_input_data (cinfo, num_bytes)
12120 j_decompress_ptr cinfo;
12121 long num_bytes;
12122 {
12123 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
12124
12125 if (src)
12126 {
12127 if (num_bytes > src->bytes_in_buffer)
12128 ERREXIT (cinfo, JERR_INPUT_EOF);
12129
12130 src->bytes_in_buffer -= num_bytes;
12131 src->next_input_byte += num_bytes;
12132 }
12133 }
12134
12135
12136 /* Method to terminate data source. Called by
12137 jpeg_finish_decompress() after all data has been processed. */
12138
12139 static void
12140 our_term_source (cinfo)
12141 j_decompress_ptr cinfo;
12142 {
12143 }
12144
12145
12146 /* Set up the JPEG lib for reading an image from DATA which contains
12147 LEN bytes. CINFO is the decompression info structure created for
12148 reading the image. */
12149
12150 static void
12151 jpeg_memory_src (cinfo, data, len)
12152 j_decompress_ptr cinfo;
12153 JOCTET *data;
12154 unsigned int len;
12155 {
12156 struct jpeg_source_mgr *src;
12157
12158 if (cinfo->src == NULL)
12159 {
12160 /* First time for this JPEG object? */
12161 cinfo->src = (struct jpeg_source_mgr *)
12162 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
12163 sizeof (struct jpeg_source_mgr));
12164 src = (struct jpeg_source_mgr *) cinfo->src;
12165 src->next_input_byte = data;
12166 }
12167
12168 src = (struct jpeg_source_mgr *) cinfo->src;
12169 src->init_source = our_init_source;
12170 src->fill_input_buffer = our_fill_input_buffer;
12171 src->skip_input_data = our_skip_input_data;
12172 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
12173 src->term_source = our_term_source;
12174 src->bytes_in_buffer = len;
12175 src->next_input_byte = data;
12176 }
12177
12178
12179 /* Load image IMG for use on frame F. Patterned after example.c
12180 from the JPEG lib. */
12181
12182 static int
12183 jpeg_load (f, img)
12184 struct frame *f;
12185 struct image *img;
12186 {
12187 struct jpeg_decompress_struct cinfo;
12188 struct my_jpeg_error_mgr mgr;
12189 Lisp_Object file, specified_file;
12190 Lisp_Object specified_data;
12191 FILE * volatile fp = NULL;
12192 JSAMPARRAY buffer;
12193 int row_stride, x, y;
12194 XImage *ximg = NULL;
12195 int rc;
12196 unsigned long *colors;
12197 int width, height;
12198 struct gcpro gcpro1;
12199
12200 /* Open the JPEG file. */
12201 specified_file = image_spec_value (img->spec, QCfile, NULL);
12202 specified_data = image_spec_value (img->spec, QCdata, NULL);
12203 file = Qnil;
12204 GCPRO1 (file);
12205
12206 if (NILP (specified_data))
12207 {
12208 file = x_find_image_file (specified_file);
12209 if (!STRINGP (file))
12210 {
12211 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12212 UNGCPRO;
12213 return 0;
12214 }
12215
12216 fp = fopen (XSTRING (file)->data, "r");
12217 if (fp == NULL)
12218 {
12219 image_error ("Cannot open `%s'", file, Qnil);
12220 UNGCPRO;
12221 return 0;
12222 }
12223 }
12224
12225 /* Customize libjpeg's error handling to call my_error_exit when an
12226 error is detected. This function will perform a longjmp. */
12227 cinfo.err = jpeg_std_error (&mgr.pub);
12228 mgr.pub.error_exit = my_error_exit;
12229
12230 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12231 {
12232 if (rc == 1)
12233 {
12234 /* Called from my_error_exit. Display a JPEG error. */
12235 char buffer[JMSG_LENGTH_MAX];
12236 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12237 image_error ("Error reading JPEG image `%s': %s", img->spec,
12238 build_string (buffer));
12239 }
12240
12241 /* Close the input file and destroy the JPEG object. */
12242 if (fp)
12243 fclose (fp);
12244 jpeg_destroy_decompress (&cinfo);
12245
12246 /* If we already have an XImage, free that. */
12247 x_destroy_x_image (ximg);
12248
12249 /* Free pixmap and colors. */
12250 x_clear_image (f, img);
12251
12252 UNGCPRO;
12253 return 0;
12254 }
12255
12256 /* Create the JPEG decompression object. Let it read from fp.
12257 Read the JPEG image header. */
12258 jpeg_create_decompress (&cinfo);
12259
12260 if (NILP (specified_data))
12261 jpeg_stdio_src (&cinfo, fp);
12262 else
12263 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12264 STRING_BYTES (XSTRING (specified_data)));
12265
12266 jpeg_read_header (&cinfo, TRUE);
12267
12268 /* Customize decompression so that color quantization will be used.
12269 Start decompression. */
12270 cinfo.quantize_colors = TRUE;
12271 jpeg_start_decompress (&cinfo);
12272 width = img->width = cinfo.output_width;
12273 height = img->height = cinfo.output_height;
12274
12275 /* Create X image and pixmap. */
12276 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12277 &img->pixmap))
12278 longjmp (mgr.setjmp_buffer, 2);
12279
12280 /* Allocate colors. When color quantization is used,
12281 cinfo.actual_number_of_colors has been set with the number of
12282 colors generated, and cinfo.colormap is a two-dimensional array
12283 of color indices in the range 0..cinfo.actual_number_of_colors.
12284 No more than 255 colors will be generated. */
12285 {
12286 int i, ir, ig, ib;
12287
12288 if (cinfo.out_color_components > 2)
12289 ir = 0, ig = 1, ib = 2;
12290 else if (cinfo.out_color_components > 1)
12291 ir = 0, ig = 1, ib = 0;
12292 else
12293 ir = 0, ig = 0, ib = 0;
12294
12295 /* Use the color table mechanism because it handles colors that
12296 cannot be allocated nicely. Such colors will be replaced with
12297 a default color, and we don't have to care about which colors
12298 can be freed safely, and which can't. */
12299 init_color_table ();
12300 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12301 * sizeof *colors);
12302
12303 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12304 {
12305 /* Multiply RGB values with 255 because X expects RGB values
12306 in the range 0..0xffff. */
12307 int r = cinfo.colormap[ir][i] << 8;
12308 int g = cinfo.colormap[ig][i] << 8;
12309 int b = cinfo.colormap[ib][i] << 8;
12310 colors[i] = lookup_rgb_color (f, r, g, b);
12311 }
12312
12313 /* Remember those colors actually allocated. */
12314 img->colors = colors_in_color_table (&img->ncolors);
12315 free_color_table ();
12316 }
12317
12318 /* Read pixels. */
12319 row_stride = width * cinfo.output_components;
12320 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12321 row_stride, 1);
12322 for (y = 0; y < height; ++y)
12323 {
12324 jpeg_read_scanlines (&cinfo, buffer, 1);
12325 for (x = 0; x < cinfo.output_width; ++x)
12326 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12327 }
12328
12329 /* Clean up. */
12330 jpeg_finish_decompress (&cinfo);
12331 jpeg_destroy_decompress (&cinfo);
12332 if (fp)
12333 fclose (fp);
12334
12335 /* Maybe fill in the background field while we have ximg handy. */
12336 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12337 IMAGE_BACKGROUND (img, f, ximg);
12338
12339 /* Put the image into the pixmap. */
12340 x_put_x_image (f, ximg, img->pixmap, width, height);
12341 x_destroy_x_image (ximg);
12342 UNBLOCK_INPUT;
12343 UNGCPRO;
12344 return 1;
12345 }
12346
12347 #endif /* HAVE_JPEG */
12348
12349
12350 \f
12351 /***********************************************************************
12352 TIFF
12353 ***********************************************************************/
12354
12355 #if HAVE_TIFF
12356
12357 #include <tiffio.h>
12358
12359 static int tiff_image_p P_ ((Lisp_Object object));
12360 static int tiff_load P_ ((struct frame *f, struct image *img));
12361
12362 /* The symbol `tiff' identifying images of this type. */
12363
12364 Lisp_Object Qtiff;
12365
12366 /* Indices of image specification fields in tiff_format, below. */
12367
12368 enum tiff_keyword_index
12369 {
12370 TIFF_TYPE,
12371 TIFF_DATA,
12372 TIFF_FILE,
12373 TIFF_ASCENT,
12374 TIFF_MARGIN,
12375 TIFF_RELIEF,
12376 TIFF_ALGORITHM,
12377 TIFF_HEURISTIC_MASK,
12378 TIFF_MASK,
12379 TIFF_BACKGROUND,
12380 TIFF_LAST
12381 };
12382
12383 /* Vector of image_keyword structures describing the format
12384 of valid user-defined image specifications. */
12385
12386 static struct image_keyword tiff_format[TIFF_LAST] =
12387 {
12388 {":type", IMAGE_SYMBOL_VALUE, 1},
12389 {":data", IMAGE_STRING_VALUE, 0},
12390 {":file", IMAGE_STRING_VALUE, 0},
12391 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12392 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12393 {":relief", IMAGE_INTEGER_VALUE, 0},
12394 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12395 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12396 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12397 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12398 };
12399
12400 /* Structure describing the image type `tiff'. */
12401
12402 static struct image_type tiff_type =
12403 {
12404 &Qtiff,
12405 tiff_image_p,
12406 tiff_load,
12407 x_clear_image,
12408 NULL
12409 };
12410
12411
12412 /* Return non-zero if OBJECT is a valid TIFF image specification. */
12413
12414 static int
12415 tiff_image_p (object)
12416 Lisp_Object object;
12417 {
12418 struct image_keyword fmt[TIFF_LAST];
12419 bcopy (tiff_format, fmt, sizeof fmt);
12420
12421 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12422 || (fmt[TIFF_ASCENT].count
12423 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12424 return 0;
12425
12426 /* Must specify either the :data or :file keyword. */
12427 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12428 }
12429
12430
12431 /* Reading from a memory buffer for TIFF images Based on the PNG
12432 memory source, but we have to provide a lot of extra functions.
12433 Blah.
12434
12435 We really only need to implement read and seek, but I am not
12436 convinced that the TIFF library is smart enough not to destroy
12437 itself if we only hand it the function pointers we need to
12438 override. */
12439
12440 typedef struct
12441 {
12442 unsigned char *bytes;
12443 size_t len;
12444 int index;
12445 }
12446 tiff_memory_source;
12447
12448 static size_t
12449 tiff_read_from_memory (data, buf, size)
12450 thandle_t data;
12451 tdata_t buf;
12452 tsize_t size;
12453 {
12454 tiff_memory_source *src = (tiff_memory_source *) data;
12455
12456 if (size > src->len - src->index)
12457 return (size_t) -1;
12458 bcopy (src->bytes + src->index, buf, size);
12459 src->index += size;
12460 return size;
12461 }
12462
12463 static size_t
12464 tiff_write_from_memory (data, buf, size)
12465 thandle_t data;
12466 tdata_t buf;
12467 tsize_t size;
12468 {
12469 return (size_t) -1;
12470 }
12471
12472 static toff_t
12473 tiff_seek_in_memory (data, off, whence)
12474 thandle_t data;
12475 toff_t off;
12476 int whence;
12477 {
12478 tiff_memory_source *src = (tiff_memory_source *) data;
12479 int idx;
12480
12481 switch (whence)
12482 {
12483 case SEEK_SET: /* Go from beginning of source. */
12484 idx = off;
12485 break;
12486
12487 case SEEK_END: /* Go from end of source. */
12488 idx = src->len + off;
12489 break;
12490
12491 case SEEK_CUR: /* Go from current position. */
12492 idx = src->index + off;
12493 break;
12494
12495 default: /* Invalid `whence'. */
12496 return -1;
12497 }
12498
12499 if (idx > src->len || idx < 0)
12500 return -1;
12501
12502 src->index = idx;
12503 return src->index;
12504 }
12505
12506 static int
12507 tiff_close_memory (data)
12508 thandle_t data;
12509 {
12510 /* NOOP */
12511 return 0;
12512 }
12513
12514 static int
12515 tiff_mmap_memory (data, pbase, psize)
12516 thandle_t data;
12517 tdata_t *pbase;
12518 toff_t *psize;
12519 {
12520 /* It is already _IN_ memory. */
12521 return 0;
12522 }
12523
12524 static void
12525 tiff_unmap_memory (data, base, size)
12526 thandle_t data;
12527 tdata_t base;
12528 toff_t size;
12529 {
12530 /* We don't need to do this. */
12531 }
12532
12533 static toff_t
12534 tiff_size_of_memory (data)
12535 thandle_t data;
12536 {
12537 return ((tiff_memory_source *) data)->len;
12538 }
12539
12540
12541 static void
12542 tiff_error_handler (title, format, ap)
12543 const char *title, *format;
12544 va_list ap;
12545 {
12546 char buf[512];
12547 int len;
12548
12549 len = sprintf (buf, "TIFF error: %s ", title);
12550 vsprintf (buf + len, format, ap);
12551 add_to_log (buf, Qnil, Qnil);
12552 }
12553
12554
12555 static void
12556 tiff_warning_handler (title, format, ap)
12557 const char *title, *format;
12558 va_list ap;
12559 {
12560 char buf[512];
12561 int len;
12562
12563 len = sprintf (buf, "TIFF warning: %s ", title);
12564 vsprintf (buf + len, format, ap);
12565 add_to_log (buf, Qnil, Qnil);
12566 }
12567
12568
12569 /* Load TIFF image IMG for use on frame F. Value is non-zero if
12570 successful. */
12571
12572 static int
12573 tiff_load (f, img)
12574 struct frame *f;
12575 struct image *img;
12576 {
12577 Lisp_Object file, specified_file;
12578 Lisp_Object specified_data;
12579 TIFF *tiff;
12580 int width, height, x, y;
12581 uint32 *buf;
12582 int rc;
12583 XImage *ximg;
12584 struct gcpro gcpro1;
12585 tiff_memory_source memsrc;
12586
12587 specified_file = image_spec_value (img->spec, QCfile, NULL);
12588 specified_data = image_spec_value (img->spec, QCdata, NULL);
12589 file = Qnil;
12590 GCPRO1 (file);
12591
12592 TIFFSetErrorHandler (tiff_error_handler);
12593 TIFFSetWarningHandler (tiff_warning_handler);
12594
12595 if (NILP (specified_data))
12596 {
12597 /* Read from a file */
12598 file = x_find_image_file (specified_file);
12599 if (!STRINGP (file))
12600 {
12601 image_error ("Cannot find image file `%s'", file, Qnil);
12602 UNGCPRO;
12603 return 0;
12604 }
12605
12606 /* Try to open the image file. */
12607 tiff = TIFFOpen (XSTRING (file)->data, "r");
12608 if (tiff == NULL)
12609 {
12610 image_error ("Cannot open `%s'", file, Qnil);
12611 UNGCPRO;
12612 return 0;
12613 }
12614 }
12615 else
12616 {
12617 /* Memory source! */
12618 memsrc.bytes = XSTRING (specified_data)->data;
12619 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12620 memsrc.index = 0;
12621
12622 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12623 (TIFFReadWriteProc) tiff_read_from_memory,
12624 (TIFFReadWriteProc) tiff_write_from_memory,
12625 tiff_seek_in_memory,
12626 tiff_close_memory,
12627 tiff_size_of_memory,
12628 tiff_mmap_memory,
12629 tiff_unmap_memory);
12630
12631 if (!tiff)
12632 {
12633 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12634 UNGCPRO;
12635 return 0;
12636 }
12637 }
12638
12639 /* Get width and height of the image, and allocate a raster buffer
12640 of width x height 32-bit values. */
12641 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12642 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12643 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12644
12645 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12646 TIFFClose (tiff);
12647 if (!rc)
12648 {
12649 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12650 xfree (buf);
12651 UNGCPRO;
12652 return 0;
12653 }
12654
12655 /* Create the X image and pixmap. */
12656 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12657 {
12658 xfree (buf);
12659 UNGCPRO;
12660 return 0;
12661 }
12662
12663 /* Initialize the color table. */
12664 init_color_table ();
12665
12666 /* Process the pixel raster. Origin is in the lower-left corner. */
12667 for (y = 0; y < height; ++y)
12668 {
12669 uint32 *row = buf + y * width;
12670
12671 for (x = 0; x < width; ++x)
12672 {
12673 uint32 abgr = row[x];
12674 int r = TIFFGetR (abgr) << 8;
12675 int g = TIFFGetG (abgr) << 8;
12676 int b = TIFFGetB (abgr) << 8;
12677 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12678 }
12679 }
12680
12681 /* Remember the colors allocated for the image. Free the color table. */
12682 img->colors = colors_in_color_table (&img->ncolors);
12683 free_color_table ();
12684
12685 img->width = width;
12686 img->height = height;
12687
12688 /* Maybe fill in the background field while we have ximg handy. */
12689 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12690 IMAGE_BACKGROUND (img, f, ximg);
12691
12692 /* Put the image into the pixmap, then free the X image and its buffer. */
12693 x_put_x_image (f, ximg, img->pixmap, width, height);
12694 x_destroy_x_image (ximg);
12695 xfree (buf);
12696
12697 UNGCPRO;
12698 return 1;
12699 }
12700
12701 #endif /* HAVE_TIFF != 0 */
12702
12703
12704 \f
12705 /***********************************************************************
12706 GIF
12707 ***********************************************************************/
12708
12709 #if HAVE_GIF
12710
12711 #include <gif_lib.h>
12712
12713 static int gif_image_p P_ ((Lisp_Object object));
12714 static int gif_load P_ ((struct frame *f, struct image *img));
12715
12716 /* The symbol `gif' identifying images of this type. */
12717
12718 Lisp_Object Qgif;
12719
12720 /* Indices of image specification fields in gif_format, below. */
12721
12722 enum gif_keyword_index
12723 {
12724 GIF_TYPE,
12725 GIF_DATA,
12726 GIF_FILE,
12727 GIF_ASCENT,
12728 GIF_MARGIN,
12729 GIF_RELIEF,
12730 GIF_ALGORITHM,
12731 GIF_HEURISTIC_MASK,
12732 GIF_MASK,
12733 GIF_IMAGE,
12734 GIF_BACKGROUND,
12735 GIF_LAST
12736 };
12737
12738 /* Vector of image_keyword structures describing the format
12739 of valid user-defined image specifications. */
12740
12741 static struct image_keyword gif_format[GIF_LAST] =
12742 {
12743 {":type", IMAGE_SYMBOL_VALUE, 1},
12744 {":data", IMAGE_STRING_VALUE, 0},
12745 {":file", IMAGE_STRING_VALUE, 0},
12746 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12747 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12748 {":relief", IMAGE_INTEGER_VALUE, 0},
12749 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12750 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12751 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12752 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12753 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12754 };
12755
12756 /* Structure describing the image type `gif'. */
12757
12758 static struct image_type gif_type =
12759 {
12760 &Qgif,
12761 gif_image_p,
12762 gif_load,
12763 x_clear_image,
12764 NULL
12765 };
12766
12767 /* Return non-zero if OBJECT is a valid GIF image specification. */
12768
12769 static int
12770 gif_image_p (object)
12771 Lisp_Object object;
12772 {
12773 struct image_keyword fmt[GIF_LAST];
12774 bcopy (gif_format, fmt, sizeof fmt);
12775
12776 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12777 || (fmt[GIF_ASCENT].count
12778 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12779 return 0;
12780
12781 /* Must specify either the :data or :file keyword. */
12782 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12783 }
12784
12785 /* Reading a GIF image from memory
12786 Based on the PNG memory stuff to a certain extent. */
12787
12788 typedef struct
12789 {
12790 unsigned char *bytes;
12791 size_t len;
12792 int index;
12793 }
12794 gif_memory_source;
12795
12796 /* Make the current memory source available to gif_read_from_memory.
12797 It's done this way because not all versions of libungif support
12798 a UserData field in the GifFileType structure. */
12799 static gif_memory_source *current_gif_memory_src;
12800
12801 static int
12802 gif_read_from_memory (file, buf, len)
12803 GifFileType *file;
12804 GifByteType *buf;
12805 int len;
12806 {
12807 gif_memory_source *src = current_gif_memory_src;
12808
12809 if (len > src->len - src->index)
12810 return -1;
12811
12812 bcopy (src->bytes + src->index, buf, len);
12813 src->index += len;
12814 return len;
12815 }
12816
12817
12818 /* Load GIF image IMG for use on frame F. Value is non-zero if
12819 successful. */
12820
12821 static int
12822 gif_load (f, img)
12823 struct frame *f;
12824 struct image *img;
12825 {
12826 Lisp_Object file, specified_file;
12827 Lisp_Object specified_data;
12828 int rc, width, height, x, y, i;
12829 XImage *ximg;
12830 ColorMapObject *gif_color_map;
12831 unsigned long pixel_colors[256];
12832 GifFileType *gif;
12833 struct gcpro gcpro1;
12834 Lisp_Object image;
12835 int ino, image_left, image_top, image_width, image_height;
12836 gif_memory_source memsrc;
12837 unsigned char *raster;
12838
12839 specified_file = image_spec_value (img->spec, QCfile, NULL);
12840 specified_data = image_spec_value (img->spec, QCdata, NULL);
12841 file = Qnil;
12842 GCPRO1 (file);
12843
12844 if (NILP (specified_data))
12845 {
12846 file = x_find_image_file (specified_file);
12847 if (!STRINGP (file))
12848 {
12849 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12850 UNGCPRO;
12851 return 0;
12852 }
12853
12854 /* Open the GIF file. */
12855 gif = DGifOpenFileName (XSTRING (file)->data);
12856 if (gif == NULL)
12857 {
12858 image_error ("Cannot open `%s'", file, Qnil);
12859 UNGCPRO;
12860 return 0;
12861 }
12862 }
12863 else
12864 {
12865 /* Read from memory! */
12866 current_gif_memory_src = &memsrc;
12867 memsrc.bytes = XSTRING (specified_data)->data;
12868 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12869 memsrc.index = 0;
12870
12871 gif = DGifOpen(&memsrc, gif_read_from_memory);
12872 if (!gif)
12873 {
12874 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12875 UNGCPRO;
12876 return 0;
12877 }
12878 }
12879
12880 /* Read entire contents. */
12881 rc = DGifSlurp (gif);
12882 if (rc == GIF_ERROR)
12883 {
12884 image_error ("Error reading `%s'", img->spec, Qnil);
12885 DGifCloseFile (gif);
12886 UNGCPRO;
12887 return 0;
12888 }
12889
12890 image = image_spec_value (img->spec, QCindex, NULL);
12891 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12892 if (ino >= gif->ImageCount)
12893 {
12894 image_error ("Invalid image number `%s' in image `%s'",
12895 image, img->spec);
12896 DGifCloseFile (gif);
12897 UNGCPRO;
12898 return 0;
12899 }
12900
12901 width = img->width = gif->SWidth;
12902 height = img->height = gif->SHeight;
12903
12904 /* Create the X image and pixmap. */
12905 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12906 {
12907 DGifCloseFile (gif);
12908 UNGCPRO;
12909 return 0;
12910 }
12911
12912 /* Allocate colors. */
12913 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12914 if (!gif_color_map)
12915 gif_color_map = gif->SColorMap;
12916 init_color_table ();
12917 bzero (pixel_colors, sizeof pixel_colors);
12918
12919 for (i = 0; i < gif_color_map->ColorCount; ++i)
12920 {
12921 int r = gif_color_map->Colors[i].Red << 8;
12922 int g = gif_color_map->Colors[i].Green << 8;
12923 int b = gif_color_map->Colors[i].Blue << 8;
12924 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12925 }
12926
12927 img->colors = colors_in_color_table (&img->ncolors);
12928 free_color_table ();
12929
12930 /* Clear the part of the screen image that are not covered by
12931 the image from the GIF file. Full animated GIF support
12932 requires more than can be done here (see the gif89 spec,
12933 disposal methods). Let's simply assume that the part
12934 not covered by a sub-image is in the frame's background color. */
12935 image_top = gif->SavedImages[ino].ImageDesc.Top;
12936 image_left = gif->SavedImages[ino].ImageDesc.Left;
12937 image_width = gif->SavedImages[ino].ImageDesc.Width;
12938 image_height = gif->SavedImages[ino].ImageDesc.Height;
12939
12940 for (y = 0; y < image_top; ++y)
12941 for (x = 0; x < width; ++x)
12942 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12943
12944 for (y = image_top + image_height; y < height; ++y)
12945 for (x = 0; x < width; ++x)
12946 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12947
12948 for (y = image_top; y < image_top + image_height; ++y)
12949 {
12950 for (x = 0; x < image_left; ++x)
12951 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12952 for (x = image_left + image_width; x < width; ++x)
12953 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12954 }
12955
12956 /* Read the GIF image into the X image. We use a local variable
12957 `raster' here because RasterBits below is a char *, and invites
12958 problems with bytes >= 0x80. */
12959 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12960
12961 if (gif->SavedImages[ino].ImageDesc.Interlace)
12962 {
12963 static int interlace_start[] = {0, 4, 2, 1};
12964 static int interlace_increment[] = {8, 8, 4, 2};
12965 int pass;
12966 int row = interlace_start[0];
12967
12968 pass = 0;
12969
12970 for (y = 0; y < image_height; y++)
12971 {
12972 if (row >= image_height)
12973 {
12974 row = interlace_start[++pass];
12975 while (row >= image_height)
12976 row = interlace_start[++pass];
12977 }
12978
12979 for (x = 0; x < image_width; x++)
12980 {
12981 int i = raster[(y * image_width) + x];
12982 XPutPixel (ximg, x + image_left, row + image_top,
12983 pixel_colors[i]);
12984 }
12985
12986 row += interlace_increment[pass];
12987 }
12988 }
12989 else
12990 {
12991 for (y = 0; y < image_height; ++y)
12992 for (x = 0; x < image_width; ++x)
12993 {
12994 int i = raster[y* image_width + x];
12995 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12996 }
12997 }
12998
12999 DGifCloseFile (gif);
13000
13001 /* Maybe fill in the background field while we have ximg handy. */
13002 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
13003 IMAGE_BACKGROUND (img, f, ximg);
13004
13005 /* Put the image into the pixmap, then free the X image and its buffer. */
13006 x_put_x_image (f, ximg, img->pixmap, width, height);
13007 x_destroy_x_image (ximg);
13008
13009 UNGCPRO;
13010 return 1;
13011 }
13012
13013 #endif /* HAVE_GIF != 0 */
13014
13015
13016 \f
13017 /***********************************************************************
13018 Ghostscript
13019 ***********************************************************************/
13020
13021 Lisp_Object Qpostscript;
13022
13023 #ifdef HAVE_GHOSTSCRIPT
13024 static int gs_image_p P_ ((Lisp_Object object));
13025 static int gs_load P_ ((struct frame *f, struct image *img));
13026 static void gs_clear_image P_ ((struct frame *f, struct image *img));
13027
13028 /* The symbol `postscript' identifying images of this type. */
13029
13030 /* Keyword symbols. */
13031
13032 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
13033
13034 /* Indices of image specification fields in gs_format, below. */
13035
13036 enum gs_keyword_index
13037 {
13038 GS_TYPE,
13039 GS_PT_WIDTH,
13040 GS_PT_HEIGHT,
13041 GS_FILE,
13042 GS_LOADER,
13043 GS_BOUNDING_BOX,
13044 GS_ASCENT,
13045 GS_MARGIN,
13046 GS_RELIEF,
13047 GS_ALGORITHM,
13048 GS_HEURISTIC_MASK,
13049 GS_MASK,
13050 GS_BACKGROUND,
13051 GS_LAST
13052 };
13053
13054 /* Vector of image_keyword structures describing the format
13055 of valid user-defined image specifications. */
13056
13057 static struct image_keyword gs_format[GS_LAST] =
13058 {
13059 {":type", IMAGE_SYMBOL_VALUE, 1},
13060 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13061 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
13062 {":file", IMAGE_STRING_VALUE, 1},
13063 {":loader", IMAGE_FUNCTION_VALUE, 0},
13064 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
13065 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
13066 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
13067 {":relief", IMAGE_INTEGER_VALUE, 0},
13068 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13069 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13070 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
13071 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
13072 };
13073
13074 /* Structure describing the image type `ghostscript'. */
13075
13076 static struct image_type gs_type =
13077 {
13078 &Qpostscript,
13079 gs_image_p,
13080 gs_load,
13081 gs_clear_image,
13082 NULL
13083 };
13084
13085
13086 /* Free X resources of Ghostscript image IMG which is used on frame F. */
13087
13088 static void
13089 gs_clear_image (f, img)
13090 struct frame *f;
13091 struct image *img;
13092 {
13093 /* IMG->data.ptr_val may contain a recorded colormap. */
13094 xfree (img->data.ptr_val);
13095 x_clear_image (f, img);
13096 }
13097
13098
13099 /* Return non-zero if OBJECT is a valid Ghostscript image
13100 specification. */
13101
13102 static int
13103 gs_image_p (object)
13104 Lisp_Object object;
13105 {
13106 struct image_keyword fmt[GS_LAST];
13107 Lisp_Object tem;
13108 int i;
13109
13110 bcopy (gs_format, fmt, sizeof fmt);
13111
13112 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
13113 || (fmt[GS_ASCENT].count
13114 && XFASTINT (fmt[GS_ASCENT].value) > 100))
13115 return 0;
13116
13117 /* Bounding box must be a list or vector containing 4 integers. */
13118 tem = fmt[GS_BOUNDING_BOX].value;
13119 if (CONSP (tem))
13120 {
13121 for (i = 0; i < 4; ++i, tem = XCDR (tem))
13122 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
13123 return 0;
13124 if (!NILP (tem))
13125 return 0;
13126 }
13127 else if (VECTORP (tem))
13128 {
13129 if (XVECTOR (tem)->size != 4)
13130 return 0;
13131 for (i = 0; i < 4; ++i)
13132 if (!INTEGERP (XVECTOR (tem)->contents[i]))
13133 return 0;
13134 }
13135 else
13136 return 0;
13137
13138 return 1;
13139 }
13140
13141
13142 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
13143 if successful. */
13144
13145 static int
13146 gs_load (f, img)
13147 struct frame *f;
13148 struct image *img;
13149 {
13150 char buffer[100];
13151 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
13152 struct gcpro gcpro1, gcpro2;
13153 Lisp_Object frame;
13154 double in_width, in_height;
13155 Lisp_Object pixel_colors = Qnil;
13156
13157 /* Compute pixel size of pixmap needed from the given size in the
13158 image specification. Sizes in the specification are in pt. 1 pt
13159 = 1/72 in, xdpi and ydpi are stored in the frame's X display
13160 info. */
13161 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
13162 in_width = XFASTINT (pt_width) / 72.0;
13163 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
13164 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
13165 in_height = XFASTINT (pt_height) / 72.0;
13166 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
13167
13168 /* Create the pixmap. */
13169 BLOCK_INPUT;
13170 xassert (img->pixmap == 0);
13171 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13172 img->width, img->height,
13173 one_w32_display_info.n_cbits);
13174 UNBLOCK_INPUT;
13175
13176 if (!img->pixmap)
13177 {
13178 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
13179 return 0;
13180 }
13181
13182 /* Call the loader to fill the pixmap. It returns a process object
13183 if successful. We do not record_unwind_protect here because
13184 other places in redisplay like calling window scroll functions
13185 don't either. Let the Lisp loader use `unwind-protect' instead. */
13186 GCPRO2 (window_and_pixmap_id, pixel_colors);
13187
13188 sprintf (buffer, "%lu %lu",
13189 (unsigned long) FRAME_W32_WINDOW (f),
13190 (unsigned long) img->pixmap);
13191 window_and_pixmap_id = build_string (buffer);
13192
13193 sprintf (buffer, "%lu %lu",
13194 FRAME_FOREGROUND_PIXEL (f),
13195 FRAME_BACKGROUND_PIXEL (f));
13196 pixel_colors = build_string (buffer);
13197
13198 XSETFRAME (frame, f);
13199 loader = image_spec_value (img->spec, QCloader, NULL);
13200 if (NILP (loader))
13201 loader = intern ("gs-load-image");
13202
13203 img->data.lisp_val = call6 (loader, frame, img->spec,
13204 make_number (img->width),
13205 make_number (img->height),
13206 window_and_pixmap_id,
13207 pixel_colors);
13208 UNGCPRO;
13209 return PROCESSP (img->data.lisp_val);
13210 }
13211
13212
13213 /* Kill the Ghostscript process that was started to fill PIXMAP on
13214 frame F. Called from XTread_socket when receiving an event
13215 telling Emacs that Ghostscript has finished drawing. */
13216
13217 void
13218 x_kill_gs_process (pixmap, f)
13219 Pixmap pixmap;
13220 struct frame *f;
13221 {
13222 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13223 int class, i;
13224 struct image *img;
13225
13226 /* Find the image containing PIXMAP. */
13227 for (i = 0; i < c->used; ++i)
13228 if (c->images[i]->pixmap == pixmap)
13229 break;
13230
13231 /* Should someone in between have cleared the image cache, for
13232 instance, give up. */
13233 if (i == c->used)
13234 return;
13235
13236 /* Kill the GS process. We should have found PIXMAP in the image
13237 cache and its image should contain a process object. */
13238 img = c->images[i];
13239 xassert (PROCESSP (img->data.lisp_val));
13240 Fkill_process (img->data.lisp_val, Qnil);
13241 img->data.lisp_val = Qnil;
13242
13243 /* On displays with a mutable colormap, figure out the colors
13244 allocated for the image by looking at the pixels of an XImage for
13245 img->pixmap. */
13246 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13247 if (class != StaticColor && class != StaticGray && class != TrueColor)
13248 {
13249 XImage *ximg;
13250
13251 BLOCK_INPUT;
13252
13253 /* Try to get an XImage for img->pixmep. */
13254 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13255 0, 0, img->width, img->height, ~0, ZPixmap);
13256 if (ximg)
13257 {
13258 int x, y;
13259
13260 /* Initialize the color table. */
13261 init_color_table ();
13262
13263 /* For each pixel of the image, look its color up in the
13264 color table. After having done so, the color table will
13265 contain an entry for each color used by the image. */
13266 for (y = 0; y < img->height; ++y)
13267 for (x = 0; x < img->width; ++x)
13268 {
13269 unsigned long pixel = XGetPixel (ximg, x, y);
13270 lookup_pixel_color (f, pixel);
13271 }
13272
13273 /* Record colors in the image. Free color table and XImage. */
13274 img->colors = colors_in_color_table (&img->ncolors);
13275 free_color_table ();
13276 XDestroyImage (ximg);
13277
13278 #if 0 /* This doesn't seem to be the case. If we free the colors
13279 here, we get a BadAccess later in x_clear_image when
13280 freeing the colors. */
13281 /* We have allocated colors once, but Ghostscript has also
13282 allocated colors on behalf of us. So, to get the
13283 reference counts right, free them once. */
13284 if (img->ncolors)
13285 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
13286 img->colors, img->ncolors, 0);
13287 #endif
13288 }
13289 else
13290 image_error ("Cannot get X image of `%s'; colors will not be freed",
13291 img->spec, Qnil);
13292
13293 UNBLOCK_INPUT;
13294 }
13295
13296 /* Now that we have the pixmap, compute mask and transform the
13297 image if requested. */
13298 BLOCK_INPUT;
13299 postprocess_image (f, img);
13300 UNBLOCK_INPUT;
13301 }
13302
13303 #endif /* HAVE_GHOSTSCRIPT */
13304
13305 \f
13306 /***********************************************************************
13307 Window properties
13308 ***********************************************************************/
13309
13310 DEFUN ("x-change-window-property", Fx_change_window_property,
13311 Sx_change_window_property, 2, 3, 0,
13312 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13313 PROP and VALUE must be strings. FRAME nil or omitted means use the
13314 selected frame. Value is VALUE. */)
13315 (prop, value, frame)
13316 Lisp_Object frame, prop, value;
13317 {
13318 #if 0 /* TODO : port window properties to W32 */
13319 struct frame *f = check_x_frame (frame);
13320 Atom prop_atom;
13321
13322 CHECK_STRING (prop);
13323 CHECK_STRING (value);
13324
13325 BLOCK_INPUT;
13326 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13327 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13328 prop_atom, XA_STRING, 8, PropModeReplace,
13329 XSTRING (value)->data, XSTRING (value)->size);
13330
13331 /* Make sure the property is set when we return. */
13332 XFlush (FRAME_W32_DISPLAY (f));
13333 UNBLOCK_INPUT;
13334
13335 #endif /* TODO */
13336
13337 return value;
13338 }
13339
13340
13341 DEFUN ("x-delete-window-property", Fx_delete_window_property,
13342 Sx_delete_window_property, 1, 2, 0,
13343 doc: /* Remove window property PROP from X window of FRAME.
13344 FRAME nil or omitted means use the selected frame. Value is PROP. */)
13345 (prop, frame)
13346 Lisp_Object prop, frame;
13347 {
13348 #if 0 /* TODO : port window properties to W32 */
13349
13350 struct frame *f = check_x_frame (frame);
13351 Atom prop_atom;
13352
13353 CHECK_STRING (prop);
13354 BLOCK_INPUT;
13355 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13356 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13357
13358 /* Make sure the property is removed when we return. */
13359 XFlush (FRAME_W32_DISPLAY (f));
13360 UNBLOCK_INPUT;
13361 #endif /* TODO */
13362
13363 return prop;
13364 }
13365
13366
13367 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13368 1, 2, 0,
13369 doc: /* Value is the value of window property PROP on FRAME.
13370 If FRAME is nil or omitted, use the selected frame. Value is nil
13371 if FRAME hasn't a property with name PROP or if PROP has no string
13372 value. */)
13373 (prop, frame)
13374 Lisp_Object prop, frame;
13375 {
13376 #if 0 /* TODO : port window properties to W32 */
13377
13378 struct frame *f = check_x_frame (frame);
13379 Atom prop_atom;
13380 int rc;
13381 Lisp_Object prop_value = Qnil;
13382 char *tmp_data = NULL;
13383 Atom actual_type;
13384 int actual_format;
13385 unsigned long actual_size, bytes_remaining;
13386
13387 CHECK_STRING (prop);
13388 BLOCK_INPUT;
13389 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13390 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13391 prop_atom, 0, 0, False, XA_STRING,
13392 &actual_type, &actual_format, &actual_size,
13393 &bytes_remaining, (unsigned char **) &tmp_data);
13394 if (rc == Success)
13395 {
13396 int size = bytes_remaining;
13397
13398 XFree (tmp_data);
13399 tmp_data = NULL;
13400
13401 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13402 prop_atom, 0, bytes_remaining,
13403 False, XA_STRING,
13404 &actual_type, &actual_format,
13405 &actual_size, &bytes_remaining,
13406 (unsigned char **) &tmp_data);
13407 if (rc == Success)
13408 prop_value = make_string (tmp_data, size);
13409
13410 XFree (tmp_data);
13411 }
13412
13413 UNBLOCK_INPUT;
13414
13415 return prop_value;
13416
13417 #endif /* TODO */
13418 return Qnil;
13419 }
13420
13421
13422 \f
13423 /***********************************************************************
13424 Busy cursor
13425 ***********************************************************************/
13426
13427 /* If non-null, an asynchronous timer that, when it expires, displays
13428 an hourglass cursor on all frames. */
13429
13430 static struct atimer *hourglass_atimer;
13431
13432 /* Non-zero means an hourglass cursor is currently shown. */
13433
13434 static int hourglass_shown_p;
13435
13436 /* Number of seconds to wait before displaying an hourglass cursor. */
13437
13438 static Lisp_Object Vhourglass_delay;
13439
13440 /* Default number of seconds to wait before displaying an hourglass
13441 cursor. */
13442
13443 #define DEFAULT_HOURGLASS_DELAY 1
13444
13445 /* Function prototypes. */
13446
13447 static void show_hourglass P_ ((struct atimer *));
13448 static void hide_hourglass P_ ((void));
13449
13450
13451 /* Cancel a currently active hourglass timer, and start a new one. */
13452
13453 void
13454 start_hourglass ()
13455 {
13456 #if 0 /* TODO: cursor shape changes. */
13457 EMACS_TIME delay;
13458 int secs, usecs = 0;
13459
13460 cancel_hourglass ();
13461
13462 if (INTEGERP (Vhourglass_delay)
13463 && XINT (Vhourglass_delay) > 0)
13464 secs = XFASTINT (Vhourglass_delay);
13465 else if (FLOATP (Vhourglass_delay)
13466 && XFLOAT_DATA (Vhourglass_delay) > 0)
13467 {
13468 Lisp_Object tem;
13469 tem = Ftruncate (Vhourglass_delay, Qnil);
13470 secs = XFASTINT (tem);
13471 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
13472 }
13473 else
13474 secs = DEFAULT_HOURGLASS_DELAY;
13475
13476 EMACS_SET_SECS_USECS (delay, secs, usecs);
13477 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13478 show_hourglass, NULL);
13479 #endif
13480 }
13481
13482
13483 /* Cancel the hourglass cursor timer if active, hide an hourglass
13484 cursor if shown. */
13485
13486 void
13487 cancel_hourglass ()
13488 {
13489 if (hourglass_atimer)
13490 {
13491 cancel_atimer (hourglass_atimer);
13492 hourglass_atimer = NULL;
13493 }
13494
13495 if (hourglass_shown_p)
13496 hide_hourglass ();
13497 }
13498
13499
13500 /* Timer function of hourglass_atimer. TIMER is equal to
13501 hourglass_atimer.
13502
13503 Display an hourglass cursor on all frames by mapping the frames'
13504 hourglass_window. Set the hourglass_p flag in the frames'
13505 output_data.x structure to indicate that an hourglass cursor is
13506 shown on the frames. */
13507
13508 static void
13509 show_hourglass (timer)
13510 struct atimer *timer;
13511 {
13512 #if 0 /* TODO: cursor shape changes. */
13513 /* The timer implementation will cancel this timer automatically
13514 after this function has run. Set hourglass_atimer to null
13515 so that we know the timer doesn't have to be canceled. */
13516 hourglass_atimer = NULL;
13517
13518 if (!hourglass_shown_p)
13519 {
13520 Lisp_Object rest, frame;
13521
13522 BLOCK_INPUT;
13523
13524 FOR_EACH_FRAME (rest, frame)
13525 if (FRAME_W32_P (XFRAME (frame)))
13526 {
13527 struct frame *f = XFRAME (frame);
13528
13529 f->output_data.w32->hourglass_p = 1;
13530
13531 if (!f->output_data.w32->hourglass_window)
13532 {
13533 unsigned long mask = CWCursor;
13534 XSetWindowAttributes attrs;
13535
13536 attrs.cursor = f->output_data.w32->hourglass_cursor;
13537
13538 f->output_data.w32->hourglass_window
13539 = XCreateWindow (FRAME_X_DISPLAY (f),
13540 FRAME_OUTER_WINDOW (f),
13541 0, 0, 32000, 32000, 0, 0,
13542 InputOnly,
13543 CopyFromParent,
13544 mask, &attrs);
13545 }
13546
13547 XMapRaised (FRAME_X_DISPLAY (f),
13548 f->output_data.w32->hourglass_window);
13549 XFlush (FRAME_X_DISPLAY (f));
13550 }
13551
13552 hourglass_shown_p = 1;
13553 UNBLOCK_INPUT;
13554 }
13555 #endif
13556 }
13557
13558
13559 /* Hide the hourglass cursor on all frames, if it is currently shown. */
13560
13561 static void
13562 hide_hourglass ()
13563 {
13564 #if 0 /* TODO: cursor shape changes. */
13565 if (hourglass_shown_p)
13566 {
13567 Lisp_Object rest, frame;
13568
13569 BLOCK_INPUT;
13570 FOR_EACH_FRAME (rest, frame)
13571 {
13572 struct frame *f = XFRAME (frame);
13573
13574 if (FRAME_W32_P (f)
13575 /* Watch out for newly created frames. */
13576 && f->output_data.x->hourglass_window)
13577 {
13578 XUnmapWindow (FRAME_X_DISPLAY (f),
13579 f->output_data.x->hourglass_window);
13580 /* Sync here because XTread_socket looks at the
13581 hourglass_p flag that is reset to zero below. */
13582 XSync (FRAME_X_DISPLAY (f), False);
13583 f->output_data.x->hourglass_p = 0;
13584 }
13585 }
13586
13587 hourglass_shown_p = 0;
13588 UNBLOCK_INPUT;
13589 }
13590 #endif
13591 }
13592
13593
13594 \f
13595 /***********************************************************************
13596 Tool tips
13597 ***********************************************************************/
13598
13599 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
13600 Lisp_Object, Lisp_Object));
13601 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13602 Lisp_Object, int, int, int *, int *));
13603
13604 /* The frame of a currently visible tooltip. */
13605
13606 Lisp_Object tip_frame;
13607
13608 /* If non-nil, a timer started that hides the last tooltip when it
13609 fires. */
13610
13611 Lisp_Object tip_timer;
13612 Window tip_window;
13613
13614 /* If non-nil, a vector of 3 elements containing the last args
13615 with which x-show-tip was called. See there. */
13616
13617 Lisp_Object last_show_tip_args;
13618
13619 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13620
13621 Lisp_Object Vx_max_tooltip_size;
13622
13623
13624 static Lisp_Object
13625 unwind_create_tip_frame (frame)
13626 Lisp_Object frame;
13627 {
13628 Lisp_Object deleted;
13629
13630 deleted = unwind_create_frame (frame);
13631 if (EQ (deleted, Qt))
13632 {
13633 tip_window = NULL;
13634 tip_frame = Qnil;
13635 }
13636
13637 return deleted;
13638 }
13639
13640
13641 /* Create a frame for a tooltip on the display described by DPYINFO.
13642 PARMS is a list of frame parameters. TEXT is the string to
13643 display in the tip frame. Value is the frame.
13644
13645 Note that functions called here, esp. x_default_parameter can
13646 signal errors, for instance when a specified color name is
13647 undefined. We have to make sure that we're in a consistent state
13648 when this happens. */
13649
13650 static Lisp_Object
13651 x_create_tip_frame (dpyinfo, parms, text)
13652 struct w32_display_info *dpyinfo;
13653 Lisp_Object parms, text;
13654 {
13655 struct frame *f;
13656 Lisp_Object frame, tem;
13657 Lisp_Object name;
13658 long window_prompting = 0;
13659 int width, height;
13660 int count = SPECPDL_INDEX ();
13661 struct gcpro gcpro1, gcpro2, gcpro3;
13662 struct kboard *kb;
13663 int face_change_count_before = face_change_count;
13664 Lisp_Object buffer;
13665 struct buffer *old_buffer;
13666
13667 check_w32 ();
13668
13669 /* Use this general default value to start with until we know if
13670 this frame has a specified name. */
13671 Vx_resource_name = Vinvocation_name;
13672
13673 #ifdef MULTI_KBOARD
13674 kb = dpyinfo->kboard;
13675 #else
13676 kb = &the_only_kboard;
13677 #endif
13678
13679 /* Get the name of the frame to use for resource lookup. */
13680 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13681 if (!STRINGP (name)
13682 && !EQ (name, Qunbound)
13683 && !NILP (name))
13684 error ("Invalid frame name--not a string or nil");
13685 Vx_resource_name = name;
13686
13687 frame = Qnil;
13688 GCPRO3 (parms, name, frame);
13689 /* Make a frame without minibuffer nor mode-line. */
13690 f = make_frame (0);
13691 f->wants_modeline = 0;
13692 XSETFRAME (frame, f);
13693
13694 buffer = Fget_buffer_create (build_string (" *tip*"));
13695 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13696 old_buffer = current_buffer;
13697 set_buffer_internal_1 (XBUFFER (buffer));
13698 current_buffer->truncate_lines = Qnil;
13699 Ferase_buffer ();
13700 Finsert (1, &text);
13701 set_buffer_internal_1 (old_buffer);
13702
13703 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
13704 record_unwind_protect (unwind_create_tip_frame, frame);
13705
13706 /* By setting the output method, we're essentially saying that
13707 the frame is live, as per FRAME_LIVE_P. If we get a signal
13708 from this point on, x_destroy_window might screw up reference
13709 counts etc. */
13710 f->output_method = output_w32;
13711 f->output_data.w32 =
13712 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13713 bzero (f->output_data.w32, sizeof (struct w32_output));
13714
13715 FRAME_FONTSET (f) = -1;
13716 f->icon_name = Qnil;
13717
13718 #if 0 /* GLYPH_DEBUG TODO: image support. */
13719 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13720 dpyinfo_refcount = dpyinfo->reference_count;
13721 #endif /* GLYPH_DEBUG */
13722 #ifdef MULTI_KBOARD
13723 FRAME_KBOARD (f) = kb;
13724 #endif
13725 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13726 f->output_data.w32->explicit_parent = 0;
13727
13728 /* Set the name; the functions to which we pass f expect the name to
13729 be set. */
13730 if (EQ (name, Qunbound) || NILP (name))
13731 {
13732 f->name = build_string (dpyinfo->w32_id_name);
13733 f->explicit_name = 0;
13734 }
13735 else
13736 {
13737 f->name = name;
13738 f->explicit_name = 1;
13739 /* use the frame's title when getting resources for this frame. */
13740 specbind (Qx_resource_name, name);
13741 }
13742
13743 /* Extract the window parameters from the supplied values
13744 that are needed to determine window geometry. */
13745 {
13746 Lisp_Object font;
13747
13748 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13749
13750 BLOCK_INPUT;
13751 /* First, try whatever font the caller has specified. */
13752 if (STRINGP (font))
13753 {
13754 tem = Fquery_fontset (font, Qnil);
13755 if (STRINGP (tem))
13756 font = x_new_fontset (f, XSTRING (tem)->data);
13757 else
13758 font = x_new_font (f, XSTRING (font)->data);
13759 }
13760
13761 /* Try out a font which we hope has bold and italic variations. */
13762 if (!STRINGP (font))
13763 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
13764 if (! STRINGP (font))
13765 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
13766 /* If those didn't work, look for something which will at least work. */
13767 if (! STRINGP (font))
13768 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
13769 UNBLOCK_INPUT;
13770 if (! STRINGP (font))
13771 font = build_string ("Fixedsys");
13772
13773 x_default_parameter (f, parms, Qfont, font,
13774 "font", "Font", RES_TYPE_STRING);
13775 }
13776
13777 x_default_parameter (f, parms, Qborder_width, make_number (2),
13778 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
13779 /* This defaults to 2 in order to match xterm. We recognize either
13780 internalBorderWidth or internalBorder (which is what xterm calls
13781 it). */
13782 if (NILP (Fassq (Qinternal_border_width, parms)))
13783 {
13784 Lisp_Object value;
13785
13786 value = w32_get_arg (parms, Qinternal_border_width,
13787 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13788 if (! EQ (value, Qunbound))
13789 parms = Fcons (Fcons (Qinternal_border_width, value),
13790 parms);
13791 }
13792 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
13793 "internalBorderWidth", "internalBorderWidth",
13794 RES_TYPE_NUMBER);
13795
13796 /* Also do the stuff which must be set before the window exists. */
13797 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13798 "foreground", "Foreground", RES_TYPE_STRING);
13799 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13800 "background", "Background", RES_TYPE_STRING);
13801 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13802 "pointerColor", "Foreground", RES_TYPE_STRING);
13803 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13804 "cursorColor", "Foreground", RES_TYPE_STRING);
13805 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13806 "borderColor", "BorderColor", RES_TYPE_STRING);
13807
13808 /* Init faces before x_default_parameter is called for scroll-bar
13809 parameters because that function calls x_set_scroll_bar_width,
13810 which calls change_frame_size, which calls Fset_window_buffer,
13811 which runs hooks, which call Fvertical_motion. At the end, we
13812 end up in init_iterator with a null face cache, which should not
13813 happen. */
13814 init_frame_faces (f);
13815
13816 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
13817 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13818
13819 window_prompting = x_figure_window_size (f, parms);
13820
13821 /* No fringes on tip frame. */
13822 f->output_data.w32->fringes_extra = 0;
13823 f->output_data.w32->fringe_cols = 0;
13824 f->output_data.w32->left_fringe_width = 0;
13825 f->output_data.w32->right_fringe_width = 0;
13826
13827 if (window_prompting & XNegative)
13828 {
13829 if (window_prompting & YNegative)
13830 f->output_data.w32->win_gravity = SouthEastGravity;
13831 else
13832 f->output_data.w32->win_gravity = NorthEastGravity;
13833 }
13834 else
13835 {
13836 if (window_prompting & YNegative)
13837 f->output_data.w32->win_gravity = SouthWestGravity;
13838 else
13839 f->output_data.w32->win_gravity = NorthWestGravity;
13840 }
13841
13842 f->output_data.w32->size_hint_flags = window_prompting;
13843
13844 BLOCK_INPUT;
13845 my_create_tip_window (f);
13846 UNBLOCK_INPUT;
13847
13848 x_make_gc (f);
13849
13850 x_default_parameter (f, parms, Qauto_raise, Qnil,
13851 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13852 x_default_parameter (f, parms, Qauto_lower, Qnil,
13853 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13854 x_default_parameter (f, parms, Qcursor_type, Qbox,
13855 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13856
13857 /* Dimensions, especially f->height, must be done via change_frame_size.
13858 Change will not be effected unless different from the current
13859 f->height. */
13860 width = f->width;
13861 height = f->height;
13862 f->height = 0;
13863 SET_FRAME_WIDTH (f, 0);
13864 change_frame_size (f, height, width, 1, 0, 0);
13865
13866 /* Set up faces after all frame parameters are known. This call
13867 also merges in face attributes specified for new frames.
13868
13869 Frame parameters may be changed if .Xdefaults contains
13870 specifications for the default font. For example, if there is an
13871 `Emacs.default.attributeBackground: pink', the `background-color'
13872 attribute of the frame get's set, which let's the internal border
13873 of the tooltip frame appear in pink. Prevent this. */
13874 {
13875 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13876
13877 /* Set tip_frame here, so that */
13878 tip_frame = frame;
13879 call1 (Qface_set_after_frame_default, frame);
13880
13881 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13882 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13883 Qnil));
13884 }
13885
13886 f->no_split = 1;
13887
13888 UNGCPRO;
13889
13890 /* It is now ok to make the frame official even if we get an error
13891 below. And the frame needs to be on Vframe_list or making it
13892 visible won't work. */
13893 Vframe_list = Fcons (frame, Vframe_list);
13894
13895 /* Now that the frame is official, it counts as a reference to
13896 its display. */
13897 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13898
13899 /* Setting attributes of faces of the tooltip frame from resources
13900 and similar will increment face_change_count, which leads to the
13901 clearing of all current matrices. Since this isn't necessary
13902 here, avoid it by resetting face_change_count to the value it
13903 had before we created the tip frame. */
13904 face_change_count = face_change_count_before;
13905
13906 /* Discard the unwind_protect. */
13907 return unbind_to (count, frame);
13908 }
13909
13910
13911 /* Compute where to display tip frame F. PARMS is the list of frame
13912 parameters for F. DX and DY are specified offsets from the current
13913 location of the mouse. WIDTH and HEIGHT are the width and height
13914 of the tooltip. Return coordinates relative to the root window of
13915 the display in *ROOT_X, and *ROOT_Y. */
13916
13917 static void
13918 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13919 struct frame *f;
13920 Lisp_Object parms, dx, dy;
13921 int width, height;
13922 int *root_x, *root_y;
13923 {
13924 Lisp_Object left, top;
13925
13926 /* User-specified position? */
13927 left = Fcdr (Fassq (Qleft, parms));
13928 top = Fcdr (Fassq (Qtop, parms));
13929
13930 /* Move the tooltip window where the mouse pointer is. Resize and
13931 show it. */
13932 if (!INTEGERP (left) || !INTEGERP (top))
13933 {
13934 POINT pt;
13935
13936 BLOCK_INPUT;
13937 GetCursorPos (&pt);
13938 *root_x = pt.x;
13939 *root_y = pt.y;
13940 UNBLOCK_INPUT;
13941 }
13942
13943 if (INTEGERP (top))
13944 *root_y = XINT (top);
13945 else if (*root_y + XINT (dy) - height < 0)
13946 *root_y -= XINT (dy);
13947 else
13948 {
13949 *root_y -= height;
13950 *root_y += XINT (dy);
13951 }
13952
13953 if (INTEGERP (left))
13954 *root_x = XINT (left);
13955 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13956 /* It fits to the right of the pointer. */
13957 *root_x += XINT (dx);
13958 else if (width + XINT (dx) <= *root_x)
13959 /* It fits to the left of the pointer. */
13960 *root_x -= width + XINT (dx);
13961 else
13962 /* Put it left justified on the screen -- it ought to fit that way. */
13963 *root_x = 0;
13964 }
13965
13966
13967 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13968 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13969 A tooltip window is a small window displaying a string.
13970
13971 FRAME nil or omitted means use the selected frame.
13972
13973 PARMS is an optional list of frame parameters which can be
13974 used to change the tooltip's appearance.
13975
13976 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13977 means use the default timeout of 5 seconds.
13978
13979 If the list of frame parameters PARAMS contains a `left' parameter,
13980 the tooltip is displayed at that x-position. Otherwise it is
13981 displayed at the mouse position, with offset DX added (default is 5 if
13982 DX isn't specified). Likewise for the y-position; if a `top' frame
13983 parameter is specified, it determines the y-position of the tooltip
13984 window, otherwise it is displayed at the mouse position, with offset
13985 DY added (default is -10).
13986
13987 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13988 Text larger than the specified size is clipped. */)
13989 (string, frame, parms, timeout, dx, dy)
13990 Lisp_Object string, frame, parms, timeout, dx, dy;
13991 {
13992 struct frame *f;
13993 struct window *w;
13994 int root_x, root_y;
13995 struct buffer *old_buffer;
13996 struct text_pos pos;
13997 int i, width, height;
13998 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13999 int old_windows_or_buffers_changed = windows_or_buffers_changed;
14000 int count = SPECPDL_INDEX ();
14001
14002 specbind (Qinhibit_redisplay, Qt);
14003
14004 GCPRO4 (string, parms, frame, timeout);
14005
14006 CHECK_STRING (string);
14007 f = check_x_frame (frame);
14008 if (NILP (timeout))
14009 timeout = make_number (5);
14010 else
14011 CHECK_NATNUM (timeout);
14012
14013 if (NILP (dx))
14014 dx = make_number (5);
14015 else
14016 CHECK_NUMBER (dx);
14017
14018 if (NILP (dy))
14019 dy = make_number (-10);
14020 else
14021 CHECK_NUMBER (dy);
14022
14023 if (NILP (last_show_tip_args))
14024 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
14025
14026 if (!NILP (tip_frame))
14027 {
14028 Lisp_Object last_string = AREF (last_show_tip_args, 0);
14029 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
14030 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
14031
14032 if (EQ (frame, last_frame)
14033 && !NILP (Fequal (last_string, string))
14034 && !NILP (Fequal (last_parms, parms)))
14035 {
14036 struct frame *f = XFRAME (tip_frame);
14037
14038 /* Only DX and DY have changed. */
14039 if (!NILP (tip_timer))
14040 {
14041 Lisp_Object timer = tip_timer;
14042 tip_timer = Qnil;
14043 call1 (Qcancel_timer, timer);
14044 }
14045
14046 BLOCK_INPUT;
14047 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
14048 PIXEL_HEIGHT (f), &root_x, &root_y);
14049
14050 /* Put tooltip in topmost group and in position. */
14051 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14052 root_x, root_y, 0, 0,
14053 SWP_NOSIZE | SWP_NOACTIVATE);
14054
14055 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14056 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14057 0, 0, 0, 0,
14058 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14059
14060 UNBLOCK_INPUT;
14061 goto start_timer;
14062 }
14063 }
14064
14065 /* Hide a previous tip, if any. */
14066 Fx_hide_tip ();
14067
14068 ASET (last_show_tip_args, 0, string);
14069 ASET (last_show_tip_args, 1, frame);
14070 ASET (last_show_tip_args, 2, parms);
14071
14072 /* Add default values to frame parameters. */
14073 if (NILP (Fassq (Qname, parms)))
14074 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
14075 if (NILP (Fassq (Qinternal_border_width, parms)))
14076 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
14077 if (NILP (Fassq (Qborder_width, parms)))
14078 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
14079 if (NILP (Fassq (Qborder_color, parms)))
14080 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
14081 if (NILP (Fassq (Qbackground_color, parms)))
14082 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
14083 parms);
14084
14085 /* Block input until the tip has been fully drawn, to avoid crashes
14086 when drawing tips in menus. */
14087 BLOCK_INPUT;
14088
14089 /* Create a frame for the tooltip, and record it in the global
14090 variable tip_frame. */
14091 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
14092 f = XFRAME (frame);
14093
14094 /* Set up the frame's root window. */
14095 w = XWINDOW (FRAME_ROOT_WINDOW (f));
14096 w->left = w->top = make_number (0);
14097
14098 if (CONSP (Vx_max_tooltip_size)
14099 && INTEGERP (XCAR (Vx_max_tooltip_size))
14100 && XINT (XCAR (Vx_max_tooltip_size)) > 0
14101 && INTEGERP (XCDR (Vx_max_tooltip_size))
14102 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
14103 {
14104 w->width = XCAR (Vx_max_tooltip_size);
14105 w->height = XCDR (Vx_max_tooltip_size);
14106 }
14107 else
14108 {
14109 w->width = make_number (80);
14110 w->height = make_number (40);
14111 }
14112
14113 f->window_width = XINT (w->width);
14114 adjust_glyphs (f);
14115 w->pseudo_window_p = 1;
14116
14117 /* Display the tooltip text in a temporary buffer. */
14118 old_buffer = current_buffer;
14119 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
14120 current_buffer->truncate_lines = Qnil;
14121 clear_glyph_matrix (w->desired_matrix);
14122 clear_glyph_matrix (w->current_matrix);
14123 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
14124 try_window (FRAME_ROOT_WINDOW (f), pos);
14125
14126 /* Compute width and height of the tooltip. */
14127 width = height = 0;
14128 for (i = 0; i < w->desired_matrix->nrows; ++i)
14129 {
14130 struct glyph_row *row = &w->desired_matrix->rows[i];
14131 struct glyph *last;
14132 int row_width;
14133
14134 /* Stop at the first empty row at the end. */
14135 if (!row->enabled_p || !row->displays_text_p)
14136 break;
14137
14138 /* Let the row go over the full width of the frame. */
14139 row->full_width_p = 1;
14140
14141 #ifdef TODO /* Investigate why some fonts need more width than is
14142 calculated for some tooltips. */
14143 /* There's a glyph at the end of rows that is use to place
14144 the cursor there. Don't include the width of this glyph. */
14145 if (row->used[TEXT_AREA])
14146 {
14147 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
14148 row_width = row->pixel_width - last->pixel_width;
14149 }
14150 else
14151 #endif
14152 row_width = row->pixel_width;
14153
14154 /* TODO: find why tips do not draw along baseline as instructed. */
14155 height += row->height;
14156 width = max (width, row_width);
14157 }
14158
14159 /* Add the frame's internal border to the width and height the X
14160 window should have. */
14161 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14162 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
14163
14164 /* Move the tooltip window where the mouse pointer is. Resize and
14165 show it. */
14166 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
14167
14168 {
14169 /* Adjust Window size to take border into account. */
14170 RECT rect;
14171 rect.left = rect.top = 0;
14172 rect.right = width;
14173 rect.bottom = height;
14174 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
14175 FRAME_EXTERNAL_MENU_BAR (f));
14176
14177 /* Position and size tooltip, and put it in the topmost group. */
14178 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
14179 root_x, root_y, rect.right - rect.left,
14180 rect.bottom - rect.top, SWP_NOACTIVATE);
14181
14182 /* Ensure tooltip is on top of other topmost windows (eg menus). */
14183 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
14184 0, 0, 0, 0,
14185 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
14186
14187 /* Let redisplay know that we have made the frame visible already. */
14188 f->async_visible = 1;
14189
14190 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
14191 }
14192
14193 /* Draw into the window. */
14194 w->must_be_updated_p = 1;
14195 update_single_window (w, 1);
14196
14197 UNBLOCK_INPUT;
14198
14199 /* Restore original current buffer. */
14200 set_buffer_internal_1 (old_buffer);
14201 windows_or_buffers_changed = old_windows_or_buffers_changed;
14202
14203 start_timer:
14204 /* Let the tip disappear after timeout seconds. */
14205 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
14206 intern ("x-hide-tip"));
14207
14208 UNGCPRO;
14209 return unbind_to (count, Qnil);
14210 }
14211
14212
14213 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
14214 doc: /* Hide the current tooltip window, if there is any.
14215 Value is t if tooltip was open, nil otherwise. */)
14216 ()
14217 {
14218 int count;
14219 Lisp_Object deleted, frame, timer;
14220 struct gcpro gcpro1, gcpro2;
14221
14222 /* Return quickly if nothing to do. */
14223 if (NILP (tip_timer) && NILP (tip_frame))
14224 return Qnil;
14225
14226 frame = tip_frame;
14227 timer = tip_timer;
14228 GCPRO2 (frame, timer);
14229 tip_frame = tip_timer = deleted = Qnil;
14230
14231 count = SPECPDL_INDEX ();
14232 specbind (Qinhibit_redisplay, Qt);
14233 specbind (Qinhibit_quit, Qt);
14234
14235 if (!NILP (timer))
14236 call1 (Qcancel_timer, timer);
14237
14238 if (FRAMEP (frame))
14239 {
14240 Fdelete_frame (frame, Qnil);
14241 deleted = Qt;
14242 }
14243
14244 UNGCPRO;
14245 return unbind_to (count, deleted);
14246 }
14247
14248
14249 \f
14250 /***********************************************************************
14251 File selection dialog
14252 ***********************************************************************/
14253 extern Lisp_Object Qfile_name_history;
14254
14255 /* Callback for altering the behaviour of the Open File dialog.
14256 Makes the Filename text field contain "Current Directory" and be
14257 read-only when "Directories" is selected in the filter. This
14258 allows us to work around the fact that the standard Open File
14259 dialog does not support directories. */
14260 UINT CALLBACK
14261 file_dialog_callback (hwnd, msg, wParam, lParam)
14262 HWND hwnd;
14263 UINT msg;
14264 WPARAM wParam;
14265 LPARAM lParam;
14266 {
14267 if (msg == WM_NOTIFY)
14268 {
14269 OFNOTIFY * notify = (OFNOTIFY *)lParam;
14270 /* Detect when the Filter dropdown is changed. */
14271 if (notify->hdr.code == CDN_TYPECHANGE)
14272 {
14273 HWND dialog = GetParent (hwnd);
14274 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
14275
14276 /* Directories is in index 2. */
14277 if (notify->lpOFN->nFilterIndex == 2)
14278 {
14279 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14280 "Current Directory");
14281 EnableWindow (edit_control, FALSE);
14282 }
14283 else
14284 {
14285 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
14286 "");
14287 EnableWindow (edit_control, TRUE);
14288 }
14289 }
14290 }
14291 return 0;
14292 }
14293
14294 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
14295 doc: /* Read file name, prompting with PROMPT in directory DIR.
14296 Use a file selection dialog.
14297 Select DEFAULT-FILENAME in the dialog's file selection box, if
14298 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
14299 (prompt, dir, default_filename, mustmatch)
14300 Lisp_Object prompt, dir, default_filename, mustmatch;
14301 {
14302 struct frame *f = SELECTED_FRAME ();
14303 Lisp_Object file = Qnil;
14304 int count = SPECPDL_INDEX ();
14305 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14306 char filename[MAX_PATH + 1];
14307 char init_dir[MAX_PATH + 1];
14308
14309 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
14310 CHECK_STRING (prompt);
14311 CHECK_STRING (dir);
14312
14313 /* Create the dialog with PROMPT as title, using DIR as initial
14314 directory and using "*" as pattern. */
14315 dir = Fexpand_file_name (dir, Qnil);
14316 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14317 init_dir[MAX_PATH] = '\0';
14318 unixtodos_filename (init_dir);
14319
14320 if (STRINGP (default_filename))
14321 {
14322 char *file_name_only;
14323 char *full_path_name = XSTRING (default_filename)->data;
14324
14325 unixtodos_filename (full_path_name);
14326
14327 file_name_only = strrchr (full_path_name, '\\');
14328 if (!file_name_only)
14329 file_name_only = full_path_name;
14330 else
14331 {
14332 file_name_only++;
14333 }
14334
14335 strncpy (filename, file_name_only, MAX_PATH);
14336 filename[MAX_PATH] = '\0';
14337 }
14338 else
14339 filename[0] = '\0';
14340
14341 {
14342 OPENFILENAME file_details;
14343
14344 /* Prevent redisplay. */
14345 specbind (Qinhibit_redisplay, Qt);
14346 BLOCK_INPUT;
14347
14348 bzero (&file_details, sizeof (file_details));
14349 file_details.lStructSize = sizeof (file_details);
14350 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14351 /* Undocumented Bug in Common File Dialog:
14352 If a filter is not specified, shell links are not resolved. */
14353 file_details.lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
14354 file_details.lpstrFile = filename;
14355 file_details.nMaxFile = sizeof (filename);
14356 file_details.lpstrInitialDir = init_dir;
14357 file_details.lpstrTitle = XSTRING (prompt)->data;
14358 file_details.Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
14359 | OFN_EXPLORER | OFN_ENABLEHOOK);
14360 if (!NILP (mustmatch))
14361 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14362
14363 file_details.lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
14364
14365 if (GetOpenFileName (&file_details))
14366 {
14367 dostounix_filename (filename);
14368 if (file_details.nFilterIndex == 2)
14369 {
14370 /* "Folder Only" selected - strip dummy file name. */
14371 char * last = strrchr (filename, '/');
14372 *last = '\0';
14373 }
14374
14375 file = DECODE_FILE(build_string (filename));
14376 }
14377 /* User cancelled the dialog without making a selection. */
14378 else if (!CommDlgExtendedError ())
14379 file = Qnil;
14380 /* An error occurred, fallback on reading from the mini-buffer. */
14381 else
14382 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14383 dir, mustmatch, dir, Qfile_name_history,
14384 default_filename, Qnil);
14385
14386 UNBLOCK_INPUT;
14387 file = unbind_to (count, file);
14388 }
14389
14390 UNGCPRO;
14391
14392 /* Make "Cancel" equivalent to C-g. */
14393 if (NILP (file))
14394 Fsignal (Qquit, Qnil);
14395
14396 return unbind_to (count, file);
14397 }
14398
14399
14400 \f
14401 /***********************************************************************
14402 w32 specialized functions
14403 ***********************************************************************/
14404
14405 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
14406 doc: /* Select a font using the W32 font dialog.
14407 Returns an X font string corresponding to the selection. */)
14408 (frame, include_proportional)
14409 Lisp_Object frame, include_proportional;
14410 {
14411 FRAME_PTR f = check_x_frame (frame);
14412 CHOOSEFONT cf;
14413 LOGFONT lf;
14414 TEXTMETRIC tm;
14415 HDC hdc;
14416 HANDLE oldobj;
14417 char buf[100];
14418
14419 bzero (&cf, sizeof (cf));
14420 bzero (&lf, sizeof (lf));
14421
14422 cf.lStructSize = sizeof (cf);
14423 cf.hwndOwner = FRAME_W32_WINDOW (f);
14424 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14425
14426 /* Unless include_proportional is non-nil, limit the selection to
14427 monospaced fonts. */
14428 if (NILP (include_proportional))
14429 cf.Flags |= CF_FIXEDPITCHONLY;
14430
14431 cf.lpLogFont = &lf;
14432
14433 /* Initialize as much of the font details as we can from the current
14434 default font. */
14435 hdc = GetDC (FRAME_W32_WINDOW (f));
14436 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14437 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14438 if (GetTextMetrics (hdc, &tm))
14439 {
14440 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14441 lf.lfWeight = tm.tmWeight;
14442 lf.lfItalic = tm.tmItalic;
14443 lf.lfUnderline = tm.tmUnderlined;
14444 lf.lfStrikeOut = tm.tmStruckOut;
14445 lf.lfCharSet = tm.tmCharSet;
14446 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14447 }
14448 SelectObject (hdc, oldobj);
14449 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
14450
14451 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
14452 return Qnil;
14453
14454 return build_string (buf);
14455 }
14456
14457 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14458 Sw32_send_sys_command, 1, 2, 0,
14459 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
14460 Some useful values for command are #xf030 to maximise frame (#xf020
14461 to minimize), #xf120 to restore frame to original size, and #xf100
14462 to activate the menubar for keyboard access. #xf140 activates the
14463 screen saver if defined.
14464
14465 If optional parameter FRAME is not specified, use selected frame. */)
14466 (command, frame)
14467 Lisp_Object command, frame;
14468 {
14469 FRAME_PTR f = check_x_frame (frame);
14470
14471 CHECK_NUMBER (command);
14472
14473 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
14474
14475 return Qnil;
14476 }
14477
14478 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
14479 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14480 This is a wrapper around the ShellExecute system function, which
14481 invokes the application registered to handle OPERATION for DOCUMENT.
14482 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14483 nil for the default action), and DOCUMENT is typically the name of a
14484 document file or URL, but can also be a program executable to run or
14485 a directory to open in the Windows Explorer.
14486
14487 If DOCUMENT is a program executable, PARAMETERS can be a string
14488 containing command line parameters, but otherwise should be nil.
14489
14490 SHOW-FLAG can be used to control whether the invoked application is hidden
14491 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14492 otherwise it is an integer representing a ShowWindow flag:
14493
14494 0 - start hidden
14495 1 - start normally
14496 3 - start maximized
14497 6 - start minimized */)
14498 (operation, document, parameters, show_flag)
14499 Lisp_Object operation, document, parameters, show_flag;
14500 {
14501 Lisp_Object current_dir;
14502
14503 CHECK_STRING (document);
14504
14505 /* Encode filename and current directory. */
14506 current_dir = ENCODE_FILE (current_buffer->directory);
14507 document = ENCODE_FILE (document);
14508 if ((int) ShellExecute (NULL,
14509 (STRINGP (operation) ?
14510 XSTRING (operation)->data : NULL),
14511 XSTRING (document)->data,
14512 (STRINGP (parameters) ?
14513 XSTRING (parameters)->data : NULL),
14514 XSTRING (current_dir)->data,
14515 (INTEGERP (show_flag) ?
14516 XINT (show_flag) : SW_SHOWDEFAULT))
14517 > 32)
14518 return Qt;
14519 error ("ShellExecute failed: %s", w32_strerror (0));
14520 }
14521
14522 /* Lookup virtual keycode from string representing the name of a
14523 non-ascii keystroke into the corresponding virtual key, using
14524 lispy_function_keys. */
14525 static int
14526 lookup_vk_code (char *key)
14527 {
14528 int i;
14529
14530 for (i = 0; i < 256; i++)
14531 if (lispy_function_keys[i] != 0
14532 && strcmp (lispy_function_keys[i], key) == 0)
14533 return i;
14534
14535 return -1;
14536 }
14537
14538 /* Convert a one-element vector style key sequence to a hot key
14539 definition. */
14540 static int
14541 w32_parse_hot_key (key)
14542 Lisp_Object key;
14543 {
14544 /* Copied from Fdefine_key and store_in_keymap. */
14545 register Lisp_Object c;
14546 int vk_code;
14547 int lisp_modifiers;
14548 int w32_modifiers;
14549 struct gcpro gcpro1;
14550
14551 CHECK_VECTOR (key);
14552
14553 if (XFASTINT (Flength (key)) != 1)
14554 return Qnil;
14555
14556 GCPRO1 (key);
14557
14558 c = Faref (key, make_number (0));
14559
14560 if (CONSP (c) && lucid_event_type_list_p (c))
14561 c = Fevent_convert_list (c);
14562
14563 UNGCPRO;
14564
14565 if (! INTEGERP (c) && ! SYMBOLP (c))
14566 error ("Key definition is invalid");
14567
14568 /* Work out the base key and the modifiers. */
14569 if (SYMBOLP (c))
14570 {
14571 c = parse_modifiers (c);
14572 lisp_modifiers = Fcar (Fcdr (c));
14573 c = Fcar (c);
14574 if (!SYMBOLP (c))
14575 abort ();
14576 vk_code = lookup_vk_code (XSTRING (SYMBOL_NAME (c))->data);
14577 }
14578 else if (INTEGERP (c))
14579 {
14580 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14581 /* Many ascii characters are their own virtual key code. */
14582 vk_code = XINT (c) & CHARACTERBITS;
14583 }
14584
14585 if (vk_code < 0 || vk_code > 255)
14586 return Qnil;
14587
14588 if ((lisp_modifiers & meta_modifier) != 0
14589 && !NILP (Vw32_alt_is_meta))
14590 lisp_modifiers |= alt_modifier;
14591
14592 /* Supply defs missing from mingw32. */
14593 #ifndef MOD_ALT
14594 #define MOD_ALT 0x0001
14595 #define MOD_CONTROL 0x0002
14596 #define MOD_SHIFT 0x0004
14597 #define MOD_WIN 0x0008
14598 #endif
14599
14600 /* Convert lisp modifiers to Windows hot-key form. */
14601 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14602 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14603 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14604 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14605
14606 return HOTKEY (vk_code, w32_modifiers);
14607 }
14608
14609 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14610 Sw32_register_hot_key, 1, 1, 0,
14611 doc: /* Register KEY as a hot-key combination.
14612 Certain key combinations like Alt-Tab are reserved for system use on
14613 Windows, and therefore are normally intercepted by the system. However,
14614 most of these key combinations can be received by registering them as
14615 hot-keys, overriding their special meaning.
14616
14617 KEY must be a one element key definition in vector form that would be
14618 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14619 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14620 is always interpreted as the Windows modifier keys.
14621
14622 The return value is the hotkey-id if registered, otherwise nil. */)
14623 (key)
14624 Lisp_Object key;
14625 {
14626 key = w32_parse_hot_key (key);
14627
14628 if (NILP (Fmemq (key, w32_grabbed_keys)))
14629 {
14630 /* Reuse an empty slot if possible. */
14631 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14632
14633 /* Safe to add new key to list, even if we have focus. */
14634 if (NILP (item))
14635 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14636 else
14637 XSETCAR (item, key);
14638
14639 /* Notify input thread about new hot-key definition, so that it
14640 takes effect without needing to switch focus. */
14641 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14642 (WPARAM) key, 0);
14643 }
14644
14645 return key;
14646 }
14647
14648 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14649 Sw32_unregister_hot_key, 1, 1, 0,
14650 doc: /* Unregister HOTKEY as a hot-key combination. */)
14651 (key)
14652 Lisp_Object key;
14653 {
14654 Lisp_Object item;
14655
14656 if (!INTEGERP (key))
14657 key = w32_parse_hot_key (key);
14658
14659 item = Fmemq (key, w32_grabbed_keys);
14660
14661 if (!NILP (item))
14662 {
14663 /* Notify input thread about hot-key definition being removed, so
14664 that it takes effect without needing focus switch. */
14665 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14666 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14667 {
14668 MSG msg;
14669 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14670 }
14671 return Qt;
14672 }
14673 return Qnil;
14674 }
14675
14676 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14677 Sw32_registered_hot_keys, 0, 0, 0,
14678 doc: /* Return list of registered hot-key IDs. */)
14679 ()
14680 {
14681 return Fcopy_sequence (w32_grabbed_keys);
14682 }
14683
14684 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14685 Sw32_reconstruct_hot_key, 1, 1, 0,
14686 doc: /* Convert hot-key ID to a lisp key combination. */)
14687 (hotkeyid)
14688 Lisp_Object hotkeyid;
14689 {
14690 int vk_code, w32_modifiers;
14691 Lisp_Object key;
14692
14693 CHECK_NUMBER (hotkeyid);
14694
14695 vk_code = HOTKEY_VK_CODE (hotkeyid);
14696 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14697
14698 if (lispy_function_keys[vk_code])
14699 key = intern (lispy_function_keys[vk_code]);
14700 else
14701 key = make_number (vk_code);
14702
14703 key = Fcons (key, Qnil);
14704 if (w32_modifiers & MOD_SHIFT)
14705 key = Fcons (Qshift, key);
14706 if (w32_modifiers & MOD_CONTROL)
14707 key = Fcons (Qctrl, key);
14708 if (w32_modifiers & MOD_ALT)
14709 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
14710 if (w32_modifiers & MOD_WIN)
14711 key = Fcons (Qhyper, key);
14712
14713 return key;
14714 }
14715
14716 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14717 Sw32_toggle_lock_key, 1, 2, 0,
14718 doc: /* Toggle the state of the lock key KEY.
14719 KEY can be `capslock', `kp-numlock', or `scroll'.
14720 If the optional parameter NEW-STATE is a number, then the state of KEY
14721 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
14722 (key, new_state)
14723 Lisp_Object key, new_state;
14724 {
14725 int vk_code;
14726
14727 if (EQ (key, intern ("capslock")))
14728 vk_code = VK_CAPITAL;
14729 else if (EQ (key, intern ("kp-numlock")))
14730 vk_code = VK_NUMLOCK;
14731 else if (EQ (key, intern ("scroll")))
14732 vk_code = VK_SCROLL;
14733 else
14734 return Qnil;
14735
14736 if (!dwWindowsThreadId)
14737 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14738
14739 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14740 (WPARAM) vk_code, (LPARAM) new_state))
14741 {
14742 MSG msg;
14743 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14744 return make_number (msg.wParam);
14745 }
14746 return Qnil;
14747 }
14748 \f
14749 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
14750 doc: /* Return storage information about the file system FILENAME is on.
14751 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14752 storage of the file system, FREE is the free storage, and AVAIL is the
14753 storage available to a non-superuser. All 3 numbers are in bytes.
14754 If the underlying system call fails, value is nil. */)
14755 (filename)
14756 Lisp_Object filename;
14757 {
14758 Lisp_Object encoded, value;
14759
14760 CHECK_STRING (filename);
14761 filename = Fexpand_file_name (filename, Qnil);
14762 encoded = ENCODE_FILE (filename);
14763
14764 value = Qnil;
14765
14766 /* Determining the required information on Windows turns out, sadly,
14767 to be more involved than one would hope. The original Win32 api
14768 call for this will return bogus information on some systems, but we
14769 must dynamically probe for the replacement api, since that was
14770 added rather late on. */
14771 {
14772 HMODULE hKernel = GetModuleHandle ("kernel32");
14773 BOOL (*pfn_GetDiskFreeSpaceEx)
14774 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14775 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14776
14777 /* On Windows, we may need to specify the root directory of the
14778 volume holding FILENAME. */
14779 char rootname[MAX_PATH];
14780 char *name = XSTRING (encoded)->data;
14781
14782 /* find the root name of the volume if given */
14783 if (isalpha (name[0]) && name[1] == ':')
14784 {
14785 rootname[0] = name[0];
14786 rootname[1] = name[1];
14787 rootname[2] = '\\';
14788 rootname[3] = 0;
14789 }
14790 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14791 {
14792 char *str = rootname;
14793 int slashes = 4;
14794 do
14795 {
14796 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14797 break;
14798 *str++ = *name++;
14799 }
14800 while ( *name );
14801
14802 *str++ = '\\';
14803 *str = 0;
14804 }
14805
14806 if (pfn_GetDiskFreeSpaceEx)
14807 {
14808 /* Unsigned large integers cannot be cast to double, so
14809 use signed ones instead. */
14810 LARGE_INTEGER availbytes;
14811 LARGE_INTEGER freebytes;
14812 LARGE_INTEGER totalbytes;
14813
14814 if (pfn_GetDiskFreeSpaceEx(rootname,
14815 (ULARGE_INTEGER *)&availbytes,
14816 (ULARGE_INTEGER *)&totalbytes,
14817 (ULARGE_INTEGER *)&freebytes))
14818 value = list3 (make_float ((double) totalbytes.QuadPart),
14819 make_float ((double) freebytes.QuadPart),
14820 make_float ((double) availbytes.QuadPart));
14821 }
14822 else
14823 {
14824 DWORD sectors_per_cluster;
14825 DWORD bytes_per_sector;
14826 DWORD free_clusters;
14827 DWORD total_clusters;
14828
14829 if (GetDiskFreeSpace(rootname,
14830 &sectors_per_cluster,
14831 &bytes_per_sector,
14832 &free_clusters,
14833 &total_clusters))
14834 value = list3 (make_float ((double) total_clusters
14835 * sectors_per_cluster * bytes_per_sector),
14836 make_float ((double) free_clusters
14837 * sectors_per_cluster * bytes_per_sector),
14838 make_float ((double) free_clusters
14839 * sectors_per_cluster * bytes_per_sector));
14840 }
14841 }
14842
14843 return value;
14844 }
14845 \f
14846 /***********************************************************************
14847 Initialization
14848 ***********************************************************************/
14849
14850 void
14851 syms_of_w32fns ()
14852 {
14853 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14854
14855 /* This is zero if not using MS-Windows. */
14856 w32_in_use = 0;
14857
14858 /* TrackMouseEvent not available in all versions of Windows, so must load
14859 it dynamically. Do it once, here, instead of every time it is used. */
14860 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14861 track_mouse_window = NULL;
14862
14863 w32_visible_system_caret_hwnd = NULL;
14864
14865 Qauto_raise = intern ("auto-raise");
14866 staticpro (&Qauto_raise);
14867 Qauto_lower = intern ("auto-lower");
14868 staticpro (&Qauto_lower);
14869 Qbar = intern ("bar");
14870 staticpro (&Qbar);
14871 Qhbar = intern ("hbar");
14872 staticpro (&Qhbar);
14873 Qborder_color = intern ("border-color");
14874 staticpro (&Qborder_color);
14875 Qborder_width = intern ("border-width");
14876 staticpro (&Qborder_width);
14877 Qbox = intern ("box");
14878 staticpro (&Qbox);
14879 Qcursor_color = intern ("cursor-color");
14880 staticpro (&Qcursor_color);
14881 Qcursor_type = intern ("cursor-type");
14882 staticpro (&Qcursor_type);
14883 Qgeometry = intern ("geometry");
14884 staticpro (&Qgeometry);
14885 Qicon_left = intern ("icon-left");
14886 staticpro (&Qicon_left);
14887 Qicon_top = intern ("icon-top");
14888 staticpro (&Qicon_top);
14889 Qicon_type = intern ("icon-type");
14890 staticpro (&Qicon_type);
14891 Qicon_name = intern ("icon-name");
14892 staticpro (&Qicon_name);
14893 Qinternal_border_width = intern ("internal-border-width");
14894 staticpro (&Qinternal_border_width);
14895 Qleft = intern ("left");
14896 staticpro (&Qleft);
14897 Qright = intern ("right");
14898 staticpro (&Qright);
14899 Qmouse_color = intern ("mouse-color");
14900 staticpro (&Qmouse_color);
14901 Qnone = intern ("none");
14902 staticpro (&Qnone);
14903 Qparent_id = intern ("parent-id");
14904 staticpro (&Qparent_id);
14905 Qscroll_bar_width = intern ("scroll-bar-width");
14906 staticpro (&Qscroll_bar_width);
14907 Qsuppress_icon = intern ("suppress-icon");
14908 staticpro (&Qsuppress_icon);
14909 Qundefined_color = intern ("undefined-color");
14910 staticpro (&Qundefined_color);
14911 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14912 staticpro (&Qvertical_scroll_bars);
14913 Qvisibility = intern ("visibility");
14914 staticpro (&Qvisibility);
14915 Qwindow_id = intern ("window-id");
14916 staticpro (&Qwindow_id);
14917 Qx_frame_parameter = intern ("x-frame-parameter");
14918 staticpro (&Qx_frame_parameter);
14919 Qx_resource_name = intern ("x-resource-name");
14920 staticpro (&Qx_resource_name);
14921 Quser_position = intern ("user-position");
14922 staticpro (&Quser_position);
14923 Quser_size = intern ("user-size");
14924 staticpro (&Quser_size);
14925 Qscreen_gamma = intern ("screen-gamma");
14926 staticpro (&Qscreen_gamma);
14927 Qline_spacing = intern ("line-spacing");
14928 staticpro (&Qline_spacing);
14929 Qcenter = intern ("center");
14930 staticpro (&Qcenter);
14931 Qcancel_timer = intern ("cancel-timer");
14932 staticpro (&Qcancel_timer);
14933 Qfullscreen = intern ("fullscreen");
14934 staticpro (&Qfullscreen);
14935 Qfullwidth = intern ("fullwidth");
14936 staticpro (&Qfullwidth);
14937 Qfullheight = intern ("fullheight");
14938 staticpro (&Qfullheight);
14939 Qfullboth = intern ("fullboth");
14940 staticpro (&Qfullboth);
14941
14942 Qhyper = intern ("hyper");
14943 staticpro (&Qhyper);
14944 Qsuper = intern ("super");
14945 staticpro (&Qsuper);
14946 Qmeta = intern ("meta");
14947 staticpro (&Qmeta);
14948 Qalt = intern ("alt");
14949 staticpro (&Qalt);
14950 Qctrl = intern ("ctrl");
14951 staticpro (&Qctrl);
14952 Qcontrol = intern ("control");
14953 staticpro (&Qcontrol);
14954 Qshift = intern ("shift");
14955 staticpro (&Qshift);
14956 /* This is the end of symbol initialization. */
14957
14958 /* Text property `display' should be nonsticky by default. */
14959 Vtext_property_default_nonsticky
14960 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14961
14962
14963 Qlaplace = intern ("laplace");
14964 staticpro (&Qlaplace);
14965 Qemboss = intern ("emboss");
14966 staticpro (&Qemboss);
14967 Qedge_detection = intern ("edge-detection");
14968 staticpro (&Qedge_detection);
14969 Qheuristic = intern ("heuristic");
14970 staticpro (&Qheuristic);
14971 QCmatrix = intern (":matrix");
14972 staticpro (&QCmatrix);
14973 QCcolor_adjustment = intern (":color-adjustment");
14974 staticpro (&QCcolor_adjustment);
14975 QCmask = intern (":mask");
14976 staticpro (&QCmask);
14977
14978 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14979 staticpro (&Qface_set_after_frame_default);
14980
14981 Fput (Qundefined_color, Qerror_conditions,
14982 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14983 Fput (Qundefined_color, Qerror_message,
14984 build_string ("Undefined color"));
14985
14986 staticpro (&w32_grabbed_keys);
14987 w32_grabbed_keys = Qnil;
14988
14989 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14990 doc: /* An array of color name mappings for windows. */);
14991 Vw32_color_map = Qnil;
14992
14993 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14994 doc: /* Non-nil if alt key presses are passed on to Windows.
14995 When non-nil, for example, alt pressed and released and then space will
14996 open the System menu. When nil, Emacs silently swallows alt key events. */);
14997 Vw32_pass_alt_to_system = Qnil;
14998
14999 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
15000 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
15001 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
15002 Vw32_alt_is_meta = Qt;
15003
15004 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
15005 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
15006 XSETINT (Vw32_quit_key, 0);
15007
15008 DEFVAR_LISP ("w32-pass-lwindow-to-system",
15009 &Vw32_pass_lwindow_to_system,
15010 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
15011 When non-nil, the Start menu is opened by tapping the key. */);
15012 Vw32_pass_lwindow_to_system = Qt;
15013
15014 DEFVAR_LISP ("w32-pass-rwindow-to-system",
15015 &Vw32_pass_rwindow_to_system,
15016 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
15017 When non-nil, the Start menu is opened by tapping the key. */);
15018 Vw32_pass_rwindow_to_system = Qt;
15019
15020 DEFVAR_INT ("w32-phantom-key-code",
15021 &Vw32_phantom_key_code,
15022 doc: /* Virtual key code used to generate \"phantom\" key presses.
15023 Value is a number between 0 and 255.
15024
15025 Phantom key presses are generated in order to stop the system from
15026 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
15027 `w32-pass-rwindow-to-system' is nil. */);
15028 /* Although 255 is technically not a valid key code, it works and
15029 means that this hack won't interfere with any real key code. */
15030 Vw32_phantom_key_code = 255;
15031
15032 DEFVAR_LISP ("w32-enable-num-lock",
15033 &Vw32_enable_num_lock,
15034 doc: /* Non-nil if Num Lock should act normally.
15035 Set to nil to see Num Lock as the key `kp-numlock'. */);
15036 Vw32_enable_num_lock = Qt;
15037
15038 DEFVAR_LISP ("w32-enable-caps-lock",
15039 &Vw32_enable_caps_lock,
15040 doc: /* Non-nil if Caps Lock should act normally.
15041 Set to nil to see Caps Lock as the key `capslock'. */);
15042 Vw32_enable_caps_lock = Qt;
15043
15044 DEFVAR_LISP ("w32-scroll-lock-modifier",
15045 &Vw32_scroll_lock_modifier,
15046 doc: /* Modifier to use for the Scroll Lock on state.
15047 The value can be hyper, super, meta, alt, control or shift for the
15048 respective modifier, or nil to see Scroll Lock as the key `scroll'.
15049 Any other value will cause the key to be ignored. */);
15050 Vw32_scroll_lock_modifier = Qt;
15051
15052 DEFVAR_LISP ("w32-lwindow-modifier",
15053 &Vw32_lwindow_modifier,
15054 doc: /* Modifier to use for the left \"Windows\" key.
15055 The value can be hyper, super, meta, alt, control or shift for the
15056 respective modifier, or nil to appear as the key `lwindow'.
15057 Any other value will cause the key to be ignored. */);
15058 Vw32_lwindow_modifier = Qnil;
15059
15060 DEFVAR_LISP ("w32-rwindow-modifier",
15061 &Vw32_rwindow_modifier,
15062 doc: /* Modifier to use for the right \"Windows\" key.
15063 The value can be hyper, super, meta, alt, control or shift for the
15064 respective modifier, or nil to appear as the key `rwindow'.
15065 Any other value will cause the key to be ignored. */);
15066 Vw32_rwindow_modifier = Qnil;
15067
15068 DEFVAR_LISP ("w32-apps-modifier",
15069 &Vw32_apps_modifier,
15070 doc: /* Modifier to use for the \"Apps\" key.
15071 The value can be hyper, super, meta, alt, control or shift for the
15072 respective modifier, or nil to appear as the key `apps'.
15073 Any other value will cause the key to be ignored. */);
15074 Vw32_apps_modifier = Qnil;
15075
15076 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
15077 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
15078 w32_enable_synthesized_fonts = 0;
15079
15080 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
15081 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
15082 Vw32_enable_palette = Qt;
15083
15084 DEFVAR_INT ("w32-mouse-button-tolerance",
15085 &Vw32_mouse_button_tolerance,
15086 doc: /* Analogue of double click interval for faking middle mouse events.
15087 The value is the minimum time in milliseconds that must elapse between
15088 left/right button down events before they are considered distinct events.
15089 If both mouse buttons are depressed within this interval, a middle mouse
15090 button down event is generated instead. */);
15091 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
15092
15093 DEFVAR_INT ("w32-mouse-move-interval",
15094 &Vw32_mouse_move_interval,
15095 doc: /* Minimum interval between mouse move events.
15096 The value is the minimum time in milliseconds that must elapse between
15097 successive mouse move (or scroll bar drag) events before they are
15098 reported as lisp events. */);
15099 XSETINT (Vw32_mouse_move_interval, 0);
15100
15101 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
15102 &w32_pass_extra_mouse_buttons_to_system,
15103 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
15104 Recent versions of Windows support mice with up to five buttons.
15105 Since most applications don't support these extra buttons, most mouse
15106 drivers will allow you to map them to functions at the system level.
15107 If this variable is non-nil, Emacs will pass them on, allowing the
15108 system to handle them. */);
15109 w32_pass_extra_mouse_buttons_to_system = 0;
15110
15111 init_x_parm_symbols ();
15112
15113 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
15114 doc: /* List of directories to search for bitmap files for w32. */);
15115 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
15116
15117 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
15118 doc: /* The shape of the pointer when over text.
15119 Changing the value does not affect existing frames
15120 unless you set the mouse color. */);
15121 Vx_pointer_shape = Qnil;
15122
15123 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
15124 doc: /* The name Emacs uses to look up resources; for internal use only.
15125 `x-get-resource' uses this as the first component of the instance name
15126 when requesting resource values.
15127 Emacs initially sets `x-resource-name' to the name under which Emacs
15128 was invoked, or to the value specified with the `-name' or `-rn'
15129 switches, if present. */);
15130 Vx_resource_name = Qnil;
15131
15132 Vx_nontext_pointer_shape = Qnil;
15133
15134 Vx_mode_pointer_shape = Qnil;
15135
15136 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
15137 doc: /* The shape of the pointer when Emacs is busy.
15138 This variable takes effect when you create a new frame
15139 or when you set the mouse color. */);
15140 Vx_hourglass_pointer_shape = Qnil;
15141
15142 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
15143 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
15144 display_hourglass_p = 1;
15145
15146 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
15147 doc: /* *Seconds to wait before displaying an hourglass pointer.
15148 Value must be an integer or float. */);
15149 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
15150
15151 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
15152 &Vx_sensitive_text_pointer_shape,
15153 doc: /* The shape of the pointer when over mouse-sensitive text.
15154 This variable takes effect when you create a new frame
15155 or when you set the mouse color. */);
15156 Vx_sensitive_text_pointer_shape = Qnil;
15157
15158 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
15159 &Vx_window_horizontal_drag_shape,
15160 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
15161 This variable takes effect when you create a new frame
15162 or when you set the mouse color. */);
15163 Vx_window_horizontal_drag_shape = Qnil;
15164
15165 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
15166 doc: /* A string indicating the foreground color of the cursor box. */);
15167 Vx_cursor_fore_pixel = Qnil;
15168
15169 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
15170 doc: /* Maximum size for tooltips.
15171 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
15172 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
15173
15174 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
15175 doc: /* Non-nil if no window manager is in use.
15176 Emacs doesn't try to figure this out; this is always nil
15177 unless you set it to something else. */);
15178 /* We don't have any way to find this out, so set it to nil
15179 and maybe the user would like to set it to t. */
15180 Vx_no_window_manager = Qnil;
15181
15182 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
15183 &Vx_pixel_size_width_font_regexp,
15184 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
15185
15186 Since Emacs gets width of a font matching with this regexp from
15187 PIXEL_SIZE field of the name, font finding mechanism gets faster for
15188 such a font. This is especially effective for such large fonts as
15189 Chinese, Japanese, and Korean. */);
15190 Vx_pixel_size_width_font_regexp = Qnil;
15191
15192 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
15193 doc: /* Time after which cached images are removed from the cache.
15194 When an image has not been displayed this many seconds, remove it
15195 from the image cache. Value must be an integer or nil with nil
15196 meaning don't clear the cache. */);
15197 Vimage_cache_eviction_delay = make_number (30 * 60);
15198
15199 DEFVAR_LISP ("w32-bdf-filename-alist",
15200 &Vw32_bdf_filename_alist,
15201 doc: /* List of bdf fonts and their corresponding filenames. */);
15202 Vw32_bdf_filename_alist = Qnil;
15203
15204 DEFVAR_BOOL ("w32-strict-fontnames",
15205 &w32_strict_fontnames,
15206 doc: /* Non-nil means only use fonts that are exact matches for those requested.
15207 Default is nil, which allows old fontnames that are not XLFD compliant,
15208 and allows third-party CJK display to work by specifying false charset
15209 fields to trick Emacs into translating to Big5, SJIS etc.
15210 Setting this to t will prevent wrong fonts being selected when
15211 fontsets are automatically created. */);
15212 w32_strict_fontnames = 0;
15213
15214 DEFVAR_BOOL ("w32-strict-painting",
15215 &w32_strict_painting,
15216 doc: /* Non-nil means use strict rules for repainting frames.
15217 Set this to nil to get the old behaviour for repainting; this should
15218 only be necessary if the default setting causes problems. */);
15219 w32_strict_painting = 1;
15220
15221 DEFVAR_LISP ("w32-charset-info-alist",
15222 &Vw32_charset_info_alist,
15223 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
15224 Each entry should be of the form:
15225
15226 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
15227
15228 where CHARSET_NAME is a string used in font names to identify the charset,
15229 WINDOWS_CHARSET is a symbol that can be one of:
15230 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
15231 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
15232 w32-charset-chinesebig5,
15233 #ifdef JOHAB_CHARSET
15234 w32-charset-johab, w32-charset-hebrew,
15235 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
15236 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
15237 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
15238 #endif
15239 #ifdef UNICODE_CHARSET
15240 w32-charset-unicode,
15241 #endif
15242 or w32-charset-oem.
15243 CODEPAGE should be an integer specifying the codepage that should be used
15244 to display the character set, t to do no translation and output as Unicode,
15245 or nil to do no translation and output as 8 bit (or multibyte on far-east
15246 versions of Windows) characters. */);
15247 Vw32_charset_info_alist = Qnil;
15248
15249 staticpro (&Qw32_charset_ansi);
15250 Qw32_charset_ansi = intern ("w32-charset-ansi");
15251 staticpro (&Qw32_charset_symbol);
15252 Qw32_charset_symbol = intern ("w32-charset-symbol");
15253 staticpro (&Qw32_charset_shiftjis);
15254 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
15255 staticpro (&Qw32_charset_hangeul);
15256 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
15257 staticpro (&Qw32_charset_chinesebig5);
15258 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15259 staticpro (&Qw32_charset_gb2312);
15260 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15261 staticpro (&Qw32_charset_oem);
15262 Qw32_charset_oem = intern ("w32-charset-oem");
15263
15264 #ifdef JOHAB_CHARSET
15265 {
15266 static int w32_extra_charsets_defined = 1;
15267 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15268 doc: /* Internal variable. */);
15269
15270 staticpro (&Qw32_charset_johab);
15271 Qw32_charset_johab = intern ("w32-charset-johab");
15272 staticpro (&Qw32_charset_easteurope);
15273 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15274 staticpro (&Qw32_charset_turkish);
15275 Qw32_charset_turkish = intern ("w32-charset-turkish");
15276 staticpro (&Qw32_charset_baltic);
15277 Qw32_charset_baltic = intern ("w32-charset-baltic");
15278 staticpro (&Qw32_charset_russian);
15279 Qw32_charset_russian = intern ("w32-charset-russian");
15280 staticpro (&Qw32_charset_arabic);
15281 Qw32_charset_arabic = intern ("w32-charset-arabic");
15282 staticpro (&Qw32_charset_greek);
15283 Qw32_charset_greek = intern ("w32-charset-greek");
15284 staticpro (&Qw32_charset_hebrew);
15285 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
15286 staticpro (&Qw32_charset_vietnamese);
15287 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
15288 staticpro (&Qw32_charset_thai);
15289 Qw32_charset_thai = intern ("w32-charset-thai");
15290 staticpro (&Qw32_charset_mac);
15291 Qw32_charset_mac = intern ("w32-charset-mac");
15292 }
15293 #endif
15294
15295 #ifdef UNICODE_CHARSET
15296 {
15297 static int w32_unicode_charset_defined = 1;
15298 DEFVAR_BOOL ("w32-unicode-charset-defined",
15299 &w32_unicode_charset_defined,
15300 doc: /* Internal variable. */);
15301
15302 staticpro (&Qw32_charset_unicode);
15303 Qw32_charset_unicode = intern ("w32-charset-unicode");
15304 #endif
15305
15306 defsubr (&Sx_get_resource);
15307 #if 0 /* TODO: Port to W32 */
15308 defsubr (&Sx_change_window_property);
15309 defsubr (&Sx_delete_window_property);
15310 defsubr (&Sx_window_property);
15311 #endif
15312 defsubr (&Sxw_display_color_p);
15313 defsubr (&Sx_display_grayscale_p);
15314 defsubr (&Sxw_color_defined_p);
15315 defsubr (&Sxw_color_values);
15316 defsubr (&Sx_server_max_request_size);
15317 defsubr (&Sx_server_vendor);
15318 defsubr (&Sx_server_version);
15319 defsubr (&Sx_display_pixel_width);
15320 defsubr (&Sx_display_pixel_height);
15321 defsubr (&Sx_display_mm_width);
15322 defsubr (&Sx_display_mm_height);
15323 defsubr (&Sx_display_screens);
15324 defsubr (&Sx_display_planes);
15325 defsubr (&Sx_display_color_cells);
15326 defsubr (&Sx_display_visual_class);
15327 defsubr (&Sx_display_backing_store);
15328 defsubr (&Sx_display_save_under);
15329 defsubr (&Sx_parse_geometry);
15330 defsubr (&Sx_create_frame);
15331 defsubr (&Sx_open_connection);
15332 defsubr (&Sx_close_connection);
15333 defsubr (&Sx_display_list);
15334 defsubr (&Sx_synchronize);
15335
15336 /* W32 specific functions */
15337
15338 defsubr (&Sw32_focus_frame);
15339 defsubr (&Sw32_select_font);
15340 defsubr (&Sw32_define_rgb_color);
15341 defsubr (&Sw32_default_color_map);
15342 defsubr (&Sw32_load_color_file);
15343 defsubr (&Sw32_send_sys_command);
15344 defsubr (&Sw32_shell_execute);
15345 defsubr (&Sw32_register_hot_key);
15346 defsubr (&Sw32_unregister_hot_key);
15347 defsubr (&Sw32_registered_hot_keys);
15348 defsubr (&Sw32_reconstruct_hot_key);
15349 defsubr (&Sw32_toggle_lock_key);
15350 defsubr (&Sw32_find_bdf_fonts);
15351
15352 defsubr (&Sfile_system_info);
15353
15354 /* Setting callback functions for fontset handler. */
15355 get_font_info_func = w32_get_font_info;
15356
15357 #if 0 /* This function pointer doesn't seem to be used anywhere.
15358 And the pointer assigned has the wrong type, anyway. */
15359 list_fonts_func = w32_list_fonts;
15360 #endif
15361
15362 load_font_func = w32_load_font;
15363 find_ccl_program_func = w32_find_ccl_program;
15364 query_font_func = w32_query_font;
15365 set_frame_fontset_func = x_set_font;
15366 check_window_system_func = check_w32;
15367
15368 /* Images. */
15369 Qxbm = intern ("xbm");
15370 staticpro (&Qxbm);
15371 QCconversion = intern (":conversion");
15372 staticpro (&QCconversion);
15373 QCheuristic_mask = intern (":heuristic-mask");
15374 staticpro (&QCheuristic_mask);
15375 QCcolor_symbols = intern (":color-symbols");
15376 staticpro (&QCcolor_symbols);
15377 QCascent = intern (":ascent");
15378 staticpro (&QCascent);
15379 QCmargin = intern (":margin");
15380 staticpro (&QCmargin);
15381 QCrelief = intern (":relief");
15382 staticpro (&QCrelief);
15383 Qpostscript = intern ("postscript");
15384 staticpro (&Qpostscript);
15385 #if 0 /* TODO: These need entries at top of file. */
15386 QCloader = intern (":loader");
15387 staticpro (&QCloader);
15388 QCbounding_box = intern (":bounding-box");
15389 staticpro (&QCbounding_box);
15390 QCpt_width = intern (":pt-width");
15391 staticpro (&QCpt_width);
15392 QCpt_height = intern (":pt-height");
15393 staticpro (&QCpt_height);
15394 #endif
15395 QCindex = intern (":index");
15396 staticpro (&QCindex);
15397 Qpbm = intern ("pbm");
15398 staticpro (&Qpbm);
15399
15400 #if HAVE_XPM
15401 Qxpm = intern ("xpm");
15402 staticpro (&Qxpm);
15403 #endif
15404
15405 #if HAVE_JPEG
15406 Qjpeg = intern ("jpeg");
15407 staticpro (&Qjpeg);
15408 #endif
15409
15410 #if HAVE_TIFF
15411 Qtiff = intern ("tiff");
15412 staticpro (&Qtiff);
15413 #endif
15414
15415 #if HAVE_GIF
15416 Qgif = intern ("gif");
15417 staticpro (&Qgif);
15418 #endif
15419
15420 #if HAVE_PNG
15421 Qpng = intern ("png");
15422 staticpro (&Qpng);
15423 #endif
15424
15425 defsubr (&Sclear_image_cache);
15426 defsubr (&Simage_size);
15427 defsubr (&Simage_mask_p);
15428
15429 #if GLYPH_DEBUG
15430 defsubr (&Simagep);
15431 defsubr (&Slookup_image);
15432 #endif
15433
15434 hourglass_atimer = NULL;
15435 hourglass_shown_p = 0;
15436 defsubr (&Sx_show_tip);
15437 defsubr (&Sx_hide_tip);
15438 tip_timer = Qnil;
15439 staticpro (&tip_timer);
15440 tip_frame = Qnil;
15441 staticpro (&tip_frame);
15442
15443 last_show_tip_args = Qnil;
15444 staticpro (&last_show_tip_args);
15445
15446 defsubr (&Sx_file_dialog);
15447 }
15448
15449
15450 void
15451 init_xfns ()
15452 {
15453 image_types = NULL;
15454 Vimage_types = Qnil;
15455
15456 define_image_type (&pbm_type);
15457 define_image_type (&xbm_type);
15458 #if 0 /* TODO : Image support for W32 */
15459 define_image_type (&gs_type);
15460 #endif
15461
15462 #if HAVE_XPM
15463 define_image_type (&xpm_type);
15464 #endif
15465
15466 #if HAVE_JPEG
15467 define_image_type (&jpeg_type);
15468 #endif
15469
15470 #if HAVE_TIFF
15471 define_image_type (&tiff_type);
15472 #endif
15473
15474 #if HAVE_GIF
15475 define_image_type (&gif_type);
15476 #endif
15477
15478 #if HAVE_PNG
15479 define_image_type (&png_type);
15480 #endif
15481 }
15482
15483 #undef abort
15484
15485 void
15486 w32_abort()
15487 {
15488 int button;
15489 button = MessageBox (NULL,
15490 "A fatal error has occurred!\n\n"
15491 "Select Abort to exit, Retry to debug, Ignore to continue",
15492 "Emacs Abort Dialog",
15493 MB_ICONEXCLAMATION | MB_TASKMODAL
15494 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15495 switch (button)
15496 {
15497 case IDRETRY:
15498 DebugBreak ();
15499 break;
15500 case IDIGNORE:
15501 break;
15502 case IDABORT:
15503 default:
15504 abort ();
15505 break;
15506 }
15507 }
15508
15509 /* For convenience when debugging. */
15510 int
15511 w32_last_error()
15512 {
15513 return GetLastError ();
15514 }