(w32_to_all_x_charsets): Return correct type in startup case.
[bpt/emacs.git] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 92, 93, 94, 95, 1996, 1997, 1998, 1999, 2000, 2001
3 Free Software Foundation, Inc.
4
5 This file is part of GNU Emacs.
6
7 GNU Emacs is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2, or (at your option)
10 any later version.
11
12 GNU Emacs is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GNU Emacs; see the file COPYING. If not, write to
19 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA. */
21
22 /* Added by Kevin Gallo */
23
24 #include <config.h>
25
26 #include <signal.h>
27 #include <stdio.h>
28 #include <limits.h>
29 #include <errno.h>
30
31 #include "lisp.h"
32 #include "charset.h"
33 #include "dispextern.h"
34 #include "w32term.h"
35 #include "keyboard.h"
36 #include "frame.h"
37 #include "window.h"
38 #include "buffer.h"
39 #include "fontset.h"
40 #include "intervals.h"
41 #include "blockinput.h"
42 #include "epaths.h"
43 #include "w32heap.h"
44 #include "termhooks.h"
45 #include "coding.h"
46 #include "ccl.h"
47 #include "systime.h"
48
49 #include "bitmaps/gray.xbm"
50
51 #include <commdlg.h>
52 #include <shellapi.h>
53 #include <ctype.h>
54
55 extern void free_frame_menubar ();
56 extern void x_compute_fringe_widths P_ ((struct frame *, int));
57 extern double atof ();
58 extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
59 extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
60 extern void w32_free_menu_strings P_ ((HWND));
61
62 extern int quit_char;
63
64 /* A definition of XColor for non-X frames. */
65 #ifndef HAVE_X_WINDOWS
66 typedef struct {
67 unsigned long pixel;
68 unsigned short red, green, blue;
69 char flags;
70 char pad;
71 } XColor;
72 #endif
73
74 extern char *lispy_function_keys[];
75
76 /* The gray bitmap `bitmaps/gray'. This is done because w32term.c uses
77 it, and including `bitmaps/gray' more than once is a problem when
78 config.h defines `static' as an empty replacement string. */
79
80 int gray_bitmap_width = gray_width;
81 int gray_bitmap_height = gray_height;
82 unsigned char *gray_bitmap_bits = gray_bits;
83
84 /* The colormap for converting color names to RGB values */
85 Lisp_Object Vw32_color_map;
86
87 /* Non nil if alt key presses are passed on to Windows. */
88 Lisp_Object Vw32_pass_alt_to_system;
89
90 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
91 to alt_modifier. */
92 Lisp_Object Vw32_alt_is_meta;
93
94 /* If non-zero, the windows virtual key code for an alternative quit key. */
95 Lisp_Object Vw32_quit_key;
96
97 /* Non nil if left window key events are passed on to Windows (this only
98 affects whether "tapping" the key opens the Start menu). */
99 Lisp_Object Vw32_pass_lwindow_to_system;
100
101 /* Non nil if right window key events are passed on to Windows (this
102 only affects whether "tapping" the key opens the Start menu). */
103 Lisp_Object Vw32_pass_rwindow_to_system;
104
105 /* Virtual key code used to generate "phantom" key presses in order
106 to stop system from acting on Windows key events. */
107 Lisp_Object Vw32_phantom_key_code;
108
109 /* Modifier associated with the left "Windows" key, or nil to act as a
110 normal key. */
111 Lisp_Object Vw32_lwindow_modifier;
112
113 /* Modifier associated with the right "Windows" key, or nil to act as a
114 normal key. */
115 Lisp_Object Vw32_rwindow_modifier;
116
117 /* Modifier associated with the "Apps" key, or nil to act as a normal
118 key. */
119 Lisp_Object Vw32_apps_modifier;
120
121 /* Value is nil if Num Lock acts as a function key. */
122 Lisp_Object Vw32_enable_num_lock;
123
124 /* Value is nil if Caps Lock acts as a function key. */
125 Lisp_Object Vw32_enable_caps_lock;
126
127 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
128 Lisp_Object Vw32_scroll_lock_modifier;
129
130 /* Switch to control whether we inhibit requests for synthesized bold
131 and italic versions of fonts. */
132 int w32_enable_synthesized_fonts;
133
134 /* Enable palette management. */
135 Lisp_Object Vw32_enable_palette;
136
137 /* Control how close left/right button down events must be to
138 be converted to a middle button down event. */
139 Lisp_Object Vw32_mouse_button_tolerance;
140
141 /* Minimum interval between mouse movement (and scroll bar drag)
142 events that are passed on to the event loop. */
143 Lisp_Object Vw32_mouse_move_interval;
144
145 /* Flag to indicate if XBUTTON events should be passed on to Windows. */
146 int w32_pass_extra_mouse_buttons_to_system;
147
148 /* The name we're using in resource queries. */
149 Lisp_Object Vx_resource_name;
150
151 /* Non nil if no window manager is in use. */
152 Lisp_Object Vx_no_window_manager;
153
154 /* Non-zero means we're allowed to display a hourglass pointer. */
155
156 int display_hourglass_p;
157
158 /* The background and shape of the mouse pointer, and shape when not
159 over text or in the modeline. */
160
161 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
162 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
163
164 /* The shape when over mouse-sensitive text. */
165
166 Lisp_Object Vx_sensitive_text_pointer_shape;
167
168 /* Color of chars displayed in cursor box. */
169
170 Lisp_Object Vx_cursor_fore_pixel;
171
172 /* Nonzero if using Windows. */
173
174 static int w32_in_use;
175
176 /* Search path for bitmap files. */
177
178 Lisp_Object Vx_bitmap_file_path;
179
180 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
181
182 Lisp_Object Vx_pixel_size_width_font_regexp;
183
184 /* Alist of bdf fonts and the files that define them. */
185 Lisp_Object Vw32_bdf_filename_alist;
186
187 /* A flag to control whether fonts are matched strictly or not. */
188 int w32_strict_fontnames;
189
190 /* A flag to control whether we should only repaint if GetUpdateRect
191 indicates there is an update region. */
192 int w32_strict_painting;
193
194 /* Associative list linking character set strings to Windows codepages. */
195 Lisp_Object Vw32_charset_info_alist;
196
197 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
198 #ifndef VIETNAMESE_CHARSET
199 #define VIETNAMESE_CHARSET 163
200 #endif
201
202 Lisp_Object Qauto_raise;
203 Lisp_Object Qauto_lower;
204 Lisp_Object Qbar;
205 Lisp_Object Qborder_color;
206 Lisp_Object Qborder_width;
207 Lisp_Object Qbox;
208 Lisp_Object Qcursor_color;
209 Lisp_Object Qcursor_type;
210 Lisp_Object Qgeometry;
211 Lisp_Object Qicon_left;
212 Lisp_Object Qicon_top;
213 Lisp_Object Qicon_type;
214 Lisp_Object Qicon_name;
215 Lisp_Object Qinternal_border_width;
216 Lisp_Object Qleft;
217 Lisp_Object Qright;
218 Lisp_Object Qmouse_color;
219 Lisp_Object Qnone;
220 Lisp_Object Qparent_id;
221 Lisp_Object Qscroll_bar_width;
222 Lisp_Object Qsuppress_icon;
223 Lisp_Object Qundefined_color;
224 Lisp_Object Qvertical_scroll_bars;
225 Lisp_Object Qvisibility;
226 Lisp_Object Qwindow_id;
227 Lisp_Object Qx_frame_parameter;
228 Lisp_Object Qx_resource_name;
229 Lisp_Object Quser_position;
230 Lisp_Object Quser_size;
231 Lisp_Object Qscreen_gamma;
232 Lisp_Object Qline_spacing;
233 Lisp_Object Qcenter;
234 Lisp_Object Qcancel_timer;
235 Lisp_Object Qhyper;
236 Lisp_Object Qsuper;
237 Lisp_Object Qmeta;
238 Lisp_Object Qalt;
239 Lisp_Object Qctrl;
240 Lisp_Object Qcontrol;
241 Lisp_Object Qshift;
242
243 Lisp_Object Qw32_charset_ansi;
244 Lisp_Object Qw32_charset_default;
245 Lisp_Object Qw32_charset_symbol;
246 Lisp_Object Qw32_charset_shiftjis;
247 Lisp_Object Qw32_charset_hangeul;
248 Lisp_Object Qw32_charset_gb2312;
249 Lisp_Object Qw32_charset_chinesebig5;
250 Lisp_Object Qw32_charset_oem;
251
252 #ifndef JOHAB_CHARSET
253 #define JOHAB_CHARSET 130
254 #endif
255 #ifdef JOHAB_CHARSET
256 Lisp_Object Qw32_charset_easteurope;
257 Lisp_Object Qw32_charset_turkish;
258 Lisp_Object Qw32_charset_baltic;
259 Lisp_Object Qw32_charset_russian;
260 Lisp_Object Qw32_charset_arabic;
261 Lisp_Object Qw32_charset_greek;
262 Lisp_Object Qw32_charset_hebrew;
263 Lisp_Object Qw32_charset_vietnamese;
264 Lisp_Object Qw32_charset_thai;
265 Lisp_Object Qw32_charset_johab;
266 Lisp_Object Qw32_charset_mac;
267 #endif
268
269 #ifdef UNICODE_CHARSET
270 Lisp_Object Qw32_charset_unicode;
271 #endif
272
273 Lisp_Object Qfullscreen;
274 Lisp_Object Qfullwidth;
275 Lisp_Object Qfullheight;
276 Lisp_Object Qfullboth;
277
278 extern Lisp_Object Qtop;
279 extern Lisp_Object Qdisplay;
280 extern Lisp_Object Qtool_bar_lines;
281
282 /* State variables for emulating a three button mouse. */
283 #define LMOUSE 1
284 #define MMOUSE 2
285 #define RMOUSE 4
286
287 static int button_state = 0;
288 static W32Msg saved_mouse_button_msg;
289 static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
290 static W32Msg saved_mouse_move_msg;
291 static unsigned mouse_move_timer = 0;
292
293 /* Window that is tracking the mouse. */
294 static HWND track_mouse_window;
295 FARPROC track_mouse_event_fn;
296
297 /* W95 mousewheel handler */
298 unsigned int msh_mousewheel = 0;
299
300 /* Timers */
301 #define MOUSE_BUTTON_ID 1
302 #define MOUSE_MOVE_ID 2
303 #define MENU_FREE_ID 3
304 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
305 is received. */
306 #define MENU_FREE_DELAY 1000
307 static unsigned menu_free_timer = 0;
308
309 /* The below are defined in frame.c. */
310
311 extern Lisp_Object Qheight, Qminibuffer, Qname, Qonly, Qwidth;
312 extern Lisp_Object Qunsplittable, Qmenu_bar_lines, Qbuffer_predicate, Qtitle;
313 extern Lisp_Object Qtool_bar_lines;
314
315 extern Lisp_Object Vwindow_system_version;
316
317 Lisp_Object Qface_set_after_frame_default;
318
319 #ifdef GLYPH_DEBUG
320 int image_cache_refcount, dpyinfo_refcount;
321 #endif
322
323
324 /* From w32term.c. */
325 extern Lisp_Object Vw32_num_mouse_buttons;
326 extern Lisp_Object Vw32_recognize_altgr;
327
328 extern HWND w32_system_caret_hwnd;
329
330 extern int w32_system_caret_height;
331 extern int w32_system_caret_x;
332 extern int w32_system_caret_y;
333 extern int w32_use_visible_system_caret;
334
335 static HWND w32_visible_system_caret_hwnd;
336
337 \f
338 /* Error if we are not connected to MS-Windows. */
339 void
340 check_w32 ()
341 {
342 if (! w32_in_use)
343 error ("MS-Windows not in use or not initialized");
344 }
345
346 /* Nonzero if we can use mouse menus.
347 You should not call this unless HAVE_MENUS is defined. */
348
349 int
350 have_menus_p ()
351 {
352 return w32_in_use;
353 }
354
355 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
356 and checking validity for W32. */
357
358 FRAME_PTR
359 check_x_frame (frame)
360 Lisp_Object frame;
361 {
362 FRAME_PTR f;
363
364 if (NILP (frame))
365 frame = selected_frame;
366 CHECK_LIVE_FRAME (frame);
367 f = XFRAME (frame);
368 if (! FRAME_W32_P (f))
369 error ("non-w32 frame used");
370 return f;
371 }
372
373 /* Let the user specify an display with a frame.
374 nil stands for the selected frame--or, if that is not a w32 frame,
375 the first display on the list. */
376
377 static struct w32_display_info *
378 check_x_display_info (frame)
379 Lisp_Object frame;
380 {
381 if (NILP (frame))
382 {
383 struct frame *sf = XFRAME (selected_frame);
384
385 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
386 return FRAME_W32_DISPLAY_INFO (sf);
387 else
388 return &one_w32_display_info;
389 }
390 else if (STRINGP (frame))
391 return x_display_info_for_name (frame);
392 else
393 {
394 FRAME_PTR f;
395
396 CHECK_LIVE_FRAME (frame);
397 f = XFRAME (frame);
398 if (! FRAME_W32_P (f))
399 error ("non-w32 frame used");
400 return FRAME_W32_DISPLAY_INFO (f);
401 }
402 }
403 \f
404 /* Return the Emacs frame-object corresponding to an w32 window.
405 It could be the frame's main window or an icon window. */
406
407 /* This function can be called during GC, so use GC_xxx type test macros. */
408
409 struct frame *
410 x_window_to_frame (dpyinfo, wdesc)
411 struct w32_display_info *dpyinfo;
412 HWND wdesc;
413 {
414 Lisp_Object tail, frame;
415 struct frame *f;
416
417 for (tail = Vframe_list; GC_CONSP (tail); tail = XCDR (tail))
418 {
419 frame = XCAR (tail);
420 if (!GC_FRAMEP (frame))
421 continue;
422 f = XFRAME (frame);
423 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
424 continue;
425 if (f->output_data.w32->hourglass_window == wdesc)
426 return f;
427
428 if (FRAME_W32_WINDOW (f) == wdesc)
429 return f;
430 }
431 return 0;
432 }
433
434 \f
435
436 /* Code to deal with bitmaps. Bitmaps are referenced by their bitmap
437 id, which is just an int that this section returns. Bitmaps are
438 reference counted so they can be shared among frames.
439
440 Bitmap indices are guaranteed to be > 0, so a negative number can
441 be used to indicate no bitmap.
442
443 If you use x_create_bitmap_from_data, then you must keep track of
444 the bitmaps yourself. That is, creating a bitmap from the same
445 data more than once will not be caught. */
446
447
448 /* Functions to access the contents of a bitmap, given an id. */
449
450 int
451 x_bitmap_height (f, id)
452 FRAME_PTR f;
453 int id;
454 {
455 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].height;
456 }
457
458 int
459 x_bitmap_width (f, id)
460 FRAME_PTR f;
461 int id;
462 {
463 return FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].width;
464 }
465
466 int
467 x_bitmap_pixmap (f, id)
468 FRAME_PTR f;
469 int id;
470 {
471 return (int) FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].pixmap;
472 }
473
474
475 /* Allocate a new bitmap record. Returns index of new record. */
476
477 static int
478 x_allocate_bitmap_record (f)
479 FRAME_PTR f;
480 {
481 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
482 int i;
483
484 if (dpyinfo->bitmaps == NULL)
485 {
486 dpyinfo->bitmaps_size = 10;
487 dpyinfo->bitmaps
488 = (struct w32_bitmap_record *) xmalloc (dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
489 dpyinfo->bitmaps_last = 1;
490 return 1;
491 }
492
493 if (dpyinfo->bitmaps_last < dpyinfo->bitmaps_size)
494 return ++dpyinfo->bitmaps_last;
495
496 for (i = 0; i < dpyinfo->bitmaps_size; ++i)
497 if (dpyinfo->bitmaps[i].refcount == 0)
498 return i + 1;
499
500 dpyinfo->bitmaps_size *= 2;
501 dpyinfo->bitmaps
502 = (struct w32_bitmap_record *) xrealloc (dpyinfo->bitmaps,
503 dpyinfo->bitmaps_size * sizeof (struct w32_bitmap_record));
504 return ++dpyinfo->bitmaps_last;
505 }
506
507 /* Add one reference to the reference count of the bitmap with id ID. */
508
509 void
510 x_reference_bitmap (f, id)
511 FRAME_PTR f;
512 int id;
513 {
514 ++FRAME_W32_DISPLAY_INFO (f)->bitmaps[id - 1].refcount;
515 }
516
517 /* Create a bitmap for frame F from a HEIGHT x WIDTH array of bits at BITS. */
518
519 int
520 x_create_bitmap_from_data (f, bits, width, height)
521 struct frame *f;
522 char *bits;
523 unsigned int width, height;
524 {
525 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
526 Pixmap bitmap;
527 int id;
528
529 bitmap = CreateBitmap (width, height,
530 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_planes,
531 FRAME_W32_DISPLAY_INFO (XFRAME (frame))->n_cbits,
532 bits);
533
534 if (! bitmap)
535 return -1;
536
537 id = x_allocate_bitmap_record (f);
538 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
539 dpyinfo->bitmaps[id - 1].file = NULL;
540 dpyinfo->bitmaps[id - 1].hinst = NULL;
541 dpyinfo->bitmaps[id - 1].refcount = 1;
542 dpyinfo->bitmaps[id - 1].depth = 1;
543 dpyinfo->bitmaps[id - 1].height = height;
544 dpyinfo->bitmaps[id - 1].width = width;
545
546 return id;
547 }
548
549 /* Create bitmap from file FILE for frame F. */
550
551 int
552 x_create_bitmap_from_file (f, file)
553 struct frame *f;
554 Lisp_Object file;
555 {
556 return -1;
557 #if 0 /* TODO : bitmap support */
558 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
559 unsigned int width, height;
560 HBITMAP bitmap;
561 int xhot, yhot, result, id;
562 Lisp_Object found;
563 int fd;
564 char *filename;
565 HINSTANCE hinst;
566
567 /* Look for an existing bitmap with the same name. */
568 for (id = 0; id < dpyinfo->bitmaps_last; ++id)
569 {
570 if (dpyinfo->bitmaps[id].refcount
571 && dpyinfo->bitmaps[id].file
572 && !strcmp (dpyinfo->bitmaps[id].file, (char *) XSTRING (file)->data))
573 {
574 ++dpyinfo->bitmaps[id].refcount;
575 return id + 1;
576 }
577 }
578
579 /* Search bitmap-file-path for the file, if appropriate. */
580 fd = openp (Vx_bitmap_file_path, file, Qnil, &found, 0);
581 if (fd < 0)
582 return -1;
583 emacs_close (fd);
584
585 filename = (char *) XSTRING (found)->data;
586
587 hinst = LoadLibraryEx (filename, NULL, LOAD_LIBRARY_AS_DATAFILE);
588
589 if (hinst == NULL)
590 return -1;
591
592
593 result = XReadBitmapFile (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
594 filename, &width, &height, &bitmap, &xhot, &yhot);
595 if (result != BitmapSuccess)
596 return -1;
597
598 id = x_allocate_bitmap_record (f);
599 dpyinfo->bitmaps[id - 1].pixmap = bitmap;
600 dpyinfo->bitmaps[id - 1].refcount = 1;
601 dpyinfo->bitmaps[id - 1].file = (char *) xmalloc (XSTRING (file)->size + 1);
602 dpyinfo->bitmaps[id - 1].depth = 1;
603 dpyinfo->bitmaps[id - 1].height = height;
604 dpyinfo->bitmaps[id - 1].width = width;
605 strcpy (dpyinfo->bitmaps[id - 1].file, XSTRING (file)->data);
606
607 return id;
608 #endif /* TODO */
609 }
610
611 /* Remove reference to bitmap with id number ID. */
612
613 void
614 x_destroy_bitmap (f, id)
615 FRAME_PTR f;
616 int id;
617 {
618 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
619
620 if (id > 0)
621 {
622 --dpyinfo->bitmaps[id - 1].refcount;
623 if (dpyinfo->bitmaps[id - 1].refcount == 0)
624 {
625 BLOCK_INPUT;
626 DeleteObject (dpyinfo->bitmaps[id - 1].pixmap);
627 if (dpyinfo->bitmaps[id - 1].file)
628 {
629 xfree (dpyinfo->bitmaps[id - 1].file);
630 dpyinfo->bitmaps[id - 1].file = NULL;
631 }
632 UNBLOCK_INPUT;
633 }
634 }
635 }
636
637 /* Free all the bitmaps for the display specified by DPYINFO. */
638
639 static void
640 x_destroy_all_bitmaps (dpyinfo)
641 struct w32_display_info *dpyinfo;
642 {
643 int i;
644 for (i = 0; i < dpyinfo->bitmaps_last; i++)
645 if (dpyinfo->bitmaps[i].refcount > 0)
646 {
647 DeleteObject (dpyinfo->bitmaps[i].pixmap);
648 if (dpyinfo->bitmaps[i].file)
649 xfree (dpyinfo->bitmaps[i].file);
650 }
651 dpyinfo->bitmaps_last = 0;
652 }
653 \f
654 /* Connect the frame-parameter names for W32 frames
655 to the ways of passing the parameter values to the window system.
656
657 The name of a parameter, as a Lisp symbol,
658 has an `x-frame-parameter' property which is an integer in Lisp
659 but can be interpreted as an `enum x_frame_parm' in C. */
660
661 enum x_frame_parm
662 {
663 X_PARM_FOREGROUND_COLOR,
664 X_PARM_BACKGROUND_COLOR,
665 X_PARM_MOUSE_COLOR,
666 X_PARM_CURSOR_COLOR,
667 X_PARM_BORDER_COLOR,
668 X_PARM_ICON_TYPE,
669 X_PARM_FONT,
670 X_PARM_BORDER_WIDTH,
671 X_PARM_INTERNAL_BORDER_WIDTH,
672 X_PARM_NAME,
673 X_PARM_AUTORAISE,
674 X_PARM_AUTOLOWER,
675 X_PARM_VERT_SCROLL_BAR,
676 X_PARM_VISIBILITY,
677 X_PARM_MENU_BAR_LINES
678 };
679
680
681 struct x_frame_parm_table
682 {
683 char *name;
684 void (*setter) P_ ((struct frame *, Lisp_Object, Lisp_Object));
685 };
686
687 BOOL my_show_window P_ ((struct frame *, HWND, int));
688 void my_set_window_pos P_ ((HWND, HWND, int, int, int, int, UINT));
689 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
690 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
691 static void x_change_window_heights P_ ((Lisp_Object, int));
692 /* TODO: Native Input Method support; see x_create_im. */
693 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
694 static void x_set_line_spacing P_ ((struct frame *, Lisp_Object, Lisp_Object));
695 static void x_set_fullscreen P_ ((struct frame *, Lisp_Object, Lisp_Object));
696 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
697 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
698 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
699 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
700 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
701 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
702 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
703 void x_set_font P_ ((struct frame *, Lisp_Object, Lisp_Object));
704 static void x_set_fringe_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
705 void x_set_border_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
706 void x_set_internal_border_width P_ ((struct frame *, Lisp_Object,
707 Lisp_Object));
708 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
709 void x_set_autoraise P_ ((struct frame *, Lisp_Object, Lisp_Object));
710 void x_set_autolower P_ ((struct frame *, Lisp_Object, Lisp_Object));
711 void x_set_vertical_scroll_bars P_ ((struct frame *, Lisp_Object,
712 Lisp_Object));
713 void x_set_visibility P_ ((struct frame *, Lisp_Object, Lisp_Object));
714 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
715 void x_set_scroll_bar_width P_ ((struct frame *, Lisp_Object, Lisp_Object));
716 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
717 void x_set_unsplittable P_ ((struct frame *, Lisp_Object, Lisp_Object));
718 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
719 static void x_set_screen_gamma P_ ((struct frame *, Lisp_Object, Lisp_Object));
720 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
721 Lisp_Object));
722
723 static struct x_frame_parm_table x_frame_parms[] =
724 {
725 {"auto-raise", x_set_autoraise},
726 {"auto-lower", x_set_autolower},
727 {"background-color", x_set_background_color},
728 {"border-color", x_set_border_color},
729 {"border-width", x_set_border_width},
730 {"cursor-color", x_set_cursor_color},
731 {"cursor-type", x_set_cursor_type},
732 {"font", x_set_font},
733 {"foreground-color", x_set_foreground_color},
734 {"icon-name", x_set_icon_name},
735 {"icon-type", x_set_icon_type},
736 {"internal-border-width", x_set_internal_border_width},
737 {"menu-bar-lines", x_set_menu_bar_lines},
738 {"mouse-color", x_set_mouse_color},
739 {"name", x_explicitly_set_name},
740 {"scroll-bar-width", x_set_scroll_bar_width},
741 {"title", x_set_title},
742 {"unsplittable", x_set_unsplittable},
743 {"vertical-scroll-bars", x_set_vertical_scroll_bars},
744 {"visibility", x_set_visibility},
745 {"tool-bar-lines", x_set_tool_bar_lines},
746 {"screen-gamma", x_set_screen_gamma},
747 {"line-spacing", x_set_line_spacing},
748 {"left-fringe", x_set_fringe_width},
749 {"right-fringe", x_set_fringe_width},
750 {"fullscreen", x_set_fullscreen},
751 };
752
753 /* Attach the `x-frame-parameter' properties to
754 the Lisp symbol names of parameters relevant to W32. */
755
756 void
757 init_x_parm_symbols ()
758 {
759 int i;
760
761 for (i = 0; i < sizeof (x_frame_parms) / sizeof (x_frame_parms[0]); i++)
762 Fput (intern (x_frame_parms[i].name), Qx_frame_parameter,
763 make_number (i));
764 }
765 \f
766 /* Really try to move where we want to be in case of fullscreen. Some WMs
767 moves the window where we tell them. Some (mwm, twm) moves the outer
768 window manager window there instead.
769 Try to compensate for those WM here. */
770 static void
771 x_fullscreen_move (f, new_top, new_left)
772 struct frame *f;
773 int new_top;
774 int new_left;
775 {
776 if (new_top != f->output_data.w32->top_pos
777 || new_left != f->output_data.w32->left_pos)
778 {
779 int move_x = new_left;
780 int move_y = new_top;
781
782 f->output_data.w32->want_fullscreen |= FULLSCREEN_MOVE_WAIT;
783 x_set_offset (f, move_x, move_y, 1);
784 }
785 }
786
787 /* Change the parameters of frame F as specified by ALIST.
788 If a parameter is not specially recognized, do nothing;
789 otherwise call the `x_set_...' function for that parameter. */
790
791 void
792 x_set_frame_parameters (f, alist)
793 FRAME_PTR f;
794 Lisp_Object alist;
795 {
796 Lisp_Object tail;
797
798 /* If both of these parameters are present, it's more efficient to
799 set them both at once. So we wait until we've looked at the
800 entire list before we set them. */
801 int width, height;
802
803 /* Same here. */
804 Lisp_Object left, top;
805
806 /* Same with these. */
807 Lisp_Object icon_left, icon_top;
808
809 /* Record in these vectors all the parms specified. */
810 Lisp_Object *parms;
811 Lisp_Object *values;
812 int i, p;
813 int left_no_change = 0, top_no_change = 0;
814 int icon_left_no_change = 0, icon_top_no_change = 0;
815 int fullscreen_is_being_set = 0;
816
817 struct gcpro gcpro1, gcpro2;
818
819 i = 0;
820 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
821 i++;
822
823 parms = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
824 values = (Lisp_Object *) alloca (i * sizeof (Lisp_Object));
825
826 /* Extract parm names and values into those vectors. */
827
828 i = 0;
829 for (tail = alist; CONSP (tail); tail = Fcdr (tail))
830 {
831 Lisp_Object elt;
832
833 elt = Fcar (tail);
834 parms[i] = Fcar (elt);
835 values[i] = Fcdr (elt);
836 i++;
837 }
838 /* TAIL and ALIST are not used again below here. */
839 alist = tail = Qnil;
840
841 GCPRO2 (*parms, *values);
842 gcpro1.nvars = i;
843 gcpro2.nvars = i;
844
845 /* There is no need to gcpro LEFT, TOP, ICON_LEFT, or ICON_TOP,
846 because their values appear in VALUES and strings are not valid. */
847 top = left = Qunbound;
848 icon_left = icon_top = Qunbound;
849
850 /* Provide default values for HEIGHT and WIDTH. */
851 if (FRAME_NEW_WIDTH (f))
852 width = FRAME_NEW_WIDTH (f);
853 else
854 width = FRAME_WIDTH (f);
855
856 if (FRAME_NEW_HEIGHT (f))
857 height = FRAME_NEW_HEIGHT (f);
858 else
859 height = FRAME_HEIGHT (f);
860
861 /* Process foreground_color and background_color before anything else.
862 They are independent of other properties, but other properties (e.g.,
863 cursor_color) are dependent upon them. */
864 /* Process default font as well, since fringe widths depends on it. */
865 for (p = 0; p < i; p++)
866 {
867 Lisp_Object prop, val;
868
869 prop = parms[p];
870 val = values[p];
871 if (EQ (prop, Qforeground_color)
872 || EQ (prop, Qbackground_color)
873 || EQ (prop, Qfont)
874 || EQ (prop, Qfullscreen))
875 {
876 register Lisp_Object param_index, old_value;
877
878 old_value = get_frame_param (f, prop);
879 fullscreen_is_being_set |= EQ (prop, Qfullscreen);
880
881 if (NILP (Fequal (val, old_value)))
882 {
883 store_frame_param (f, prop, val);
884
885 param_index = Fget (prop, Qx_frame_parameter);
886 if (NATNUMP (param_index)
887 && (XFASTINT (param_index)
888 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
889 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
890 }
891 }
892 }
893
894 /* Now process them in reverse of specified order. */
895 for (i--; i >= 0; i--)
896 {
897 Lisp_Object prop, val;
898
899 prop = parms[i];
900 val = values[i];
901
902 if (EQ (prop, Qwidth) && NUMBERP (val))
903 width = XFASTINT (val);
904 else if (EQ (prop, Qheight) && NUMBERP (val))
905 height = XFASTINT (val);
906 else if (EQ (prop, Qtop))
907 top = val;
908 else if (EQ (prop, Qleft))
909 left = val;
910 else if (EQ (prop, Qicon_top))
911 icon_top = val;
912 else if (EQ (prop, Qicon_left))
913 icon_left = val;
914 else if (EQ (prop, Qforeground_color)
915 || EQ (prop, Qbackground_color)
916 || EQ (prop, Qfont)
917 || EQ (prop, Qfullscreen))
918 /* Processed above. */
919 continue;
920 else
921 {
922 register Lisp_Object param_index, old_value;
923
924 old_value = get_frame_param (f, prop);
925
926 store_frame_param (f, prop, val);
927
928 param_index = Fget (prop, Qx_frame_parameter);
929 if (NATNUMP (param_index)
930 && (XFASTINT (param_index)
931 < sizeof (x_frame_parms)/sizeof (x_frame_parms[0])))
932 (*x_frame_parms[XINT (param_index)].setter)(f, val, old_value);
933 }
934 }
935
936 /* Don't die if just one of these was set. */
937 if (EQ (left, Qunbound))
938 {
939 left_no_change = 1;
940 if (f->output_data.w32->left_pos < 0)
941 left = Fcons (Qplus, Fcons (make_number (f->output_data.w32->left_pos), Qnil));
942 else
943 XSETINT (left, f->output_data.w32->left_pos);
944 }
945 if (EQ (top, Qunbound))
946 {
947 top_no_change = 1;
948 if (f->output_data.w32->top_pos < 0)
949 top = Fcons (Qplus, Fcons (make_number (f->output_data.w32->top_pos), Qnil));
950 else
951 XSETINT (top, f->output_data.w32->top_pos);
952 }
953
954 /* If one of the icon positions was not set, preserve or default it. */
955 if (EQ (icon_left, Qunbound) || ! INTEGERP (icon_left))
956 {
957 icon_left_no_change = 1;
958 icon_left = Fcdr (Fassq (Qicon_left, f->param_alist));
959 if (NILP (icon_left))
960 XSETINT (icon_left, 0);
961 }
962 if (EQ (icon_top, Qunbound) || ! INTEGERP (icon_top))
963 {
964 icon_top_no_change = 1;
965 icon_top = Fcdr (Fassq (Qicon_top, f->param_alist));
966 if (NILP (icon_top))
967 XSETINT (icon_top, 0);
968 }
969
970 if (FRAME_VISIBLE_P (f) && fullscreen_is_being_set)
971 {
972 /* If the frame is visible already and the fullscreen parameter is
973 being set, it is too late to set WM manager hints to specify
974 size and position.
975 Here we first get the width, height and position that applies to
976 fullscreen. We then move the frame to the appropriate
977 position. Resize of the frame is taken care of in the code after
978 this if-statement. */
979 int new_left, new_top;
980
981 x_fullscreen_adjust (f, &width, &height, &new_top, &new_left);
982 x_fullscreen_move (f, new_top, new_left);
983 }
984
985 /* Don't set these parameters unless they've been explicitly
986 specified. The window might be mapped or resized while we're in
987 this function, and we don't want to override that unless the lisp
988 code has asked for it.
989
990 Don't set these parameters unless they actually differ from the
991 window's current parameters; the window may not actually exist
992 yet. */
993 {
994 Lisp_Object frame;
995
996 check_frame_size (f, &height, &width);
997
998 XSETFRAME (frame, f);
999
1000 if (width != FRAME_WIDTH (f)
1001 || height != FRAME_HEIGHT (f)
1002 || FRAME_NEW_HEIGHT (f) || FRAME_NEW_WIDTH (f))
1003 Fset_frame_size (frame, make_number (width), make_number (height));
1004
1005 if ((!NILP (left) || !NILP (top))
1006 && ! (left_no_change && top_no_change)
1007 && ! (NUMBERP (left) && XINT (left) == f->output_data.w32->left_pos
1008 && NUMBERP (top) && XINT (top) == f->output_data.w32->top_pos))
1009 {
1010 int leftpos = 0;
1011 int toppos = 0;
1012
1013 /* Record the signs. */
1014 f->output_data.w32->size_hint_flags &= ~ (XNegative | YNegative);
1015 if (EQ (left, Qminus))
1016 f->output_data.w32->size_hint_flags |= XNegative;
1017 else if (INTEGERP (left))
1018 {
1019 leftpos = XINT (left);
1020 if (leftpos < 0)
1021 f->output_data.w32->size_hint_flags |= XNegative;
1022 }
1023 else if (CONSP (left) && EQ (XCAR (left), Qminus)
1024 && CONSP (XCDR (left))
1025 && INTEGERP (XCAR (XCDR (left))))
1026 {
1027 leftpos = - XINT (XCAR (XCDR (left)));
1028 f->output_data.w32->size_hint_flags |= XNegative;
1029 }
1030 else if (CONSP (left) && EQ (XCAR (left), Qplus)
1031 && CONSP (XCDR (left))
1032 && INTEGERP (XCAR (XCDR (left))))
1033 {
1034 leftpos = XINT (XCAR (XCDR (left)));
1035 }
1036
1037 if (EQ (top, Qminus))
1038 f->output_data.w32->size_hint_flags |= YNegative;
1039 else if (INTEGERP (top))
1040 {
1041 toppos = XINT (top);
1042 if (toppos < 0)
1043 f->output_data.w32->size_hint_flags |= YNegative;
1044 }
1045 else if (CONSP (top) && EQ (XCAR (top), Qminus)
1046 && CONSP (XCDR (top))
1047 && INTEGERP (XCAR (XCDR (top))))
1048 {
1049 toppos = - XINT (XCAR (XCDR (top)));
1050 f->output_data.w32->size_hint_flags |= YNegative;
1051 }
1052 else if (CONSP (top) && EQ (XCAR (top), Qplus)
1053 && CONSP (XCDR (top))
1054 && INTEGERP (XCAR (XCDR (top))))
1055 {
1056 toppos = XINT (XCAR (XCDR (top)));
1057 }
1058
1059
1060 /* Store the numeric value of the position. */
1061 f->output_data.w32->top_pos = toppos;
1062 f->output_data.w32->left_pos = leftpos;
1063
1064 f->output_data.w32->win_gravity = NorthWestGravity;
1065
1066 /* Actually set that position, and convert to absolute. */
1067 x_set_offset (f, leftpos, toppos, -1);
1068 }
1069
1070 if ((!NILP (icon_left) || !NILP (icon_top))
1071 && ! (icon_left_no_change && icon_top_no_change))
1072 x_wm_set_icon_position (f, XINT (icon_left), XINT (icon_top));
1073 }
1074
1075 UNGCPRO;
1076 }
1077
1078 /* Store the screen positions of frame F into XPTR and YPTR.
1079 These are the positions of the containing window manager window,
1080 not Emacs's own window. */
1081
1082 void
1083 x_real_positions (f, xptr, yptr)
1084 FRAME_PTR f;
1085 int *xptr, *yptr;
1086 {
1087 POINT pt;
1088 RECT rect;
1089
1090 GetClientRect(FRAME_W32_WINDOW(f), &rect);
1091 AdjustWindowRect(&rect, f->output_data.w32->dwStyle, FRAME_EXTERNAL_MENU_BAR(f));
1092
1093 pt.x = rect.left;
1094 pt.y = rect.top;
1095
1096 ClientToScreen (FRAME_W32_WINDOW(f), &pt);
1097
1098 /* Remember x_pixels_diff and y_pixels_diff. */
1099 f->output_data.w32->x_pixels_diff = pt.x - rect.left;
1100 f->output_data.w32->y_pixels_diff = pt.y - rect.top;
1101
1102 *xptr = pt.x;
1103 *yptr = pt.y;
1104 }
1105
1106 /* Insert a description of internally-recorded parameters of frame X
1107 into the parameter alist *ALISTPTR that is to be given to the user.
1108 Only parameters that are specific to W32
1109 and whose values are not correctly recorded in the frame's
1110 param_alist need to be considered here. */
1111
1112 void
1113 x_report_frame_params (f, alistptr)
1114 struct frame *f;
1115 Lisp_Object *alistptr;
1116 {
1117 char buf[16];
1118 Lisp_Object tem;
1119
1120 /* Represent negative positions (off the top or left screen edge)
1121 in a way that Fmodify_frame_parameters will understand correctly. */
1122 XSETINT (tem, f->output_data.w32->left_pos);
1123 if (f->output_data.w32->left_pos >= 0)
1124 store_in_alist (alistptr, Qleft, tem);
1125 else
1126 store_in_alist (alistptr, Qleft, Fcons (Qplus, Fcons (tem, Qnil)));
1127
1128 XSETINT (tem, f->output_data.w32->top_pos);
1129 if (f->output_data.w32->top_pos >= 0)
1130 store_in_alist (alistptr, Qtop, tem);
1131 else
1132 store_in_alist (alistptr, Qtop, Fcons (Qplus, Fcons (tem, Qnil)));
1133
1134 store_in_alist (alistptr, Qborder_width,
1135 make_number (f->output_data.w32->border_width));
1136 store_in_alist (alistptr, Qinternal_border_width,
1137 make_number (f->output_data.w32->internal_border_width));
1138 store_in_alist (alistptr, Qleft_fringe,
1139 make_number (f->output_data.w32->left_fringe_width));
1140 store_in_alist (alistptr, Qright_fringe,
1141 make_number (f->output_data.w32->right_fringe_width));
1142 store_in_alist (alistptr, Qscroll_bar_width,
1143 make_number (FRAME_HAS_VERTICAL_SCROLL_BARS (f)
1144 ? FRAME_SCROLL_BAR_PIXEL_WIDTH(f)
1145 : 0));
1146 sprintf (buf, "%ld", (long) FRAME_W32_WINDOW (f));
1147 store_in_alist (alistptr, Qwindow_id,
1148 build_string (buf));
1149 store_in_alist (alistptr, Qicon_name, f->icon_name);
1150 FRAME_SAMPLE_VISIBILITY (f);
1151 store_in_alist (alistptr, Qvisibility,
1152 (FRAME_VISIBLE_P (f) ? Qt
1153 : FRAME_ICONIFIED_P (f) ? Qicon : Qnil));
1154 store_in_alist (alistptr, Qdisplay,
1155 XCAR (FRAME_W32_DISPLAY_INFO (f)->name_list_element));
1156 }
1157 \f
1158
1159 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
1160 Sw32_define_rgb_color, 4, 4, 0,
1161 doc: /* Convert RGB numbers to a windows color reference and associate with NAME.
1162 This adds or updates a named color to w32-color-map, making it
1163 available for use. The original entry's RGB ref is returned, or nil
1164 if the entry is new. */)
1165 (red, green, blue, name)
1166 Lisp_Object red, green, blue, name;
1167 {
1168 Lisp_Object rgb;
1169 Lisp_Object oldrgb = Qnil;
1170 Lisp_Object entry;
1171
1172 CHECK_NUMBER (red);
1173 CHECK_NUMBER (green);
1174 CHECK_NUMBER (blue);
1175 CHECK_STRING (name);
1176
1177 XSET (rgb, Lisp_Int, RGB(XUINT (red), XUINT (green), XUINT (blue)));
1178
1179 BLOCK_INPUT;
1180
1181 /* replace existing entry in w32-color-map or add new entry. */
1182 entry = Fassoc (name, Vw32_color_map);
1183 if (NILP (entry))
1184 {
1185 entry = Fcons (name, rgb);
1186 Vw32_color_map = Fcons (entry, Vw32_color_map);
1187 }
1188 else
1189 {
1190 oldrgb = Fcdr (entry);
1191 Fsetcdr (entry, rgb);
1192 }
1193
1194 UNBLOCK_INPUT;
1195
1196 return (oldrgb);
1197 }
1198
1199 DEFUN ("w32-load-color-file", Fw32_load_color_file,
1200 Sw32_load_color_file, 1, 1, 0,
1201 doc: /* Create an alist of color entries from an external file.
1202 Assign this value to w32-color-map to replace the existing color map.
1203
1204 The file should define one named RGB color per line like so:
1205 R G B name
1206 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
1207 (filename)
1208 Lisp_Object filename;
1209 {
1210 FILE *fp;
1211 Lisp_Object cmap = Qnil;
1212 Lisp_Object abspath;
1213
1214 CHECK_STRING (filename);
1215 abspath = Fexpand_file_name (filename, Qnil);
1216
1217 fp = fopen (XSTRING (filename)->data, "rt");
1218 if (fp)
1219 {
1220 char buf[512];
1221 int red, green, blue;
1222 int num;
1223
1224 BLOCK_INPUT;
1225
1226 while (fgets (buf, sizeof (buf), fp) != NULL) {
1227 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
1228 {
1229 char *name = buf + num;
1230 num = strlen (name) - 1;
1231 if (name[num] == '\n')
1232 name[num] = 0;
1233 cmap = Fcons (Fcons (build_string (name),
1234 make_number (RGB (red, green, blue))),
1235 cmap);
1236 }
1237 }
1238 fclose (fp);
1239
1240 UNBLOCK_INPUT;
1241 }
1242
1243 return cmap;
1244 }
1245
1246 /* The default colors for the w32 color map */
1247 typedef struct colormap_t
1248 {
1249 char *name;
1250 COLORREF colorref;
1251 } colormap_t;
1252
1253 colormap_t w32_color_map[] =
1254 {
1255 {"snow" , PALETTERGB (255,250,250)},
1256 {"ghost white" , PALETTERGB (248,248,255)},
1257 {"GhostWhite" , PALETTERGB (248,248,255)},
1258 {"white smoke" , PALETTERGB (245,245,245)},
1259 {"WhiteSmoke" , PALETTERGB (245,245,245)},
1260 {"gainsboro" , PALETTERGB (220,220,220)},
1261 {"floral white" , PALETTERGB (255,250,240)},
1262 {"FloralWhite" , PALETTERGB (255,250,240)},
1263 {"old lace" , PALETTERGB (253,245,230)},
1264 {"OldLace" , PALETTERGB (253,245,230)},
1265 {"linen" , PALETTERGB (250,240,230)},
1266 {"antique white" , PALETTERGB (250,235,215)},
1267 {"AntiqueWhite" , PALETTERGB (250,235,215)},
1268 {"papaya whip" , PALETTERGB (255,239,213)},
1269 {"PapayaWhip" , PALETTERGB (255,239,213)},
1270 {"blanched almond" , PALETTERGB (255,235,205)},
1271 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
1272 {"bisque" , PALETTERGB (255,228,196)},
1273 {"peach puff" , PALETTERGB (255,218,185)},
1274 {"PeachPuff" , PALETTERGB (255,218,185)},
1275 {"navajo white" , PALETTERGB (255,222,173)},
1276 {"NavajoWhite" , PALETTERGB (255,222,173)},
1277 {"moccasin" , PALETTERGB (255,228,181)},
1278 {"cornsilk" , PALETTERGB (255,248,220)},
1279 {"ivory" , PALETTERGB (255,255,240)},
1280 {"lemon chiffon" , PALETTERGB (255,250,205)},
1281 {"LemonChiffon" , PALETTERGB (255,250,205)},
1282 {"seashell" , PALETTERGB (255,245,238)},
1283 {"honeydew" , PALETTERGB (240,255,240)},
1284 {"mint cream" , PALETTERGB (245,255,250)},
1285 {"MintCream" , PALETTERGB (245,255,250)},
1286 {"azure" , PALETTERGB (240,255,255)},
1287 {"alice blue" , PALETTERGB (240,248,255)},
1288 {"AliceBlue" , PALETTERGB (240,248,255)},
1289 {"lavender" , PALETTERGB (230,230,250)},
1290 {"lavender blush" , PALETTERGB (255,240,245)},
1291 {"LavenderBlush" , PALETTERGB (255,240,245)},
1292 {"misty rose" , PALETTERGB (255,228,225)},
1293 {"MistyRose" , PALETTERGB (255,228,225)},
1294 {"white" , PALETTERGB (255,255,255)},
1295 {"black" , PALETTERGB ( 0, 0, 0)},
1296 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
1297 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
1298 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
1299 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
1300 {"dim gray" , PALETTERGB (105,105,105)},
1301 {"DimGray" , PALETTERGB (105,105,105)},
1302 {"dim grey" , PALETTERGB (105,105,105)},
1303 {"DimGrey" , PALETTERGB (105,105,105)},
1304 {"slate gray" , PALETTERGB (112,128,144)},
1305 {"SlateGray" , PALETTERGB (112,128,144)},
1306 {"slate grey" , PALETTERGB (112,128,144)},
1307 {"SlateGrey" , PALETTERGB (112,128,144)},
1308 {"light slate gray" , PALETTERGB (119,136,153)},
1309 {"LightSlateGray" , PALETTERGB (119,136,153)},
1310 {"light slate grey" , PALETTERGB (119,136,153)},
1311 {"LightSlateGrey" , PALETTERGB (119,136,153)},
1312 {"gray" , PALETTERGB (190,190,190)},
1313 {"grey" , PALETTERGB (190,190,190)},
1314 {"light grey" , PALETTERGB (211,211,211)},
1315 {"LightGrey" , PALETTERGB (211,211,211)},
1316 {"light gray" , PALETTERGB (211,211,211)},
1317 {"LightGray" , PALETTERGB (211,211,211)},
1318 {"midnight blue" , PALETTERGB ( 25, 25,112)},
1319 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
1320 {"navy" , PALETTERGB ( 0, 0,128)},
1321 {"navy blue" , PALETTERGB ( 0, 0,128)},
1322 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
1323 {"cornflower blue" , PALETTERGB (100,149,237)},
1324 {"CornflowerBlue" , PALETTERGB (100,149,237)},
1325 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
1326 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
1327 {"slate blue" , PALETTERGB (106, 90,205)},
1328 {"SlateBlue" , PALETTERGB (106, 90,205)},
1329 {"medium slate blue" , PALETTERGB (123,104,238)},
1330 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
1331 {"light slate blue" , PALETTERGB (132,112,255)},
1332 {"LightSlateBlue" , PALETTERGB (132,112,255)},
1333 {"medium blue" , PALETTERGB ( 0, 0,205)},
1334 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
1335 {"royal blue" , PALETTERGB ( 65,105,225)},
1336 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
1337 {"blue" , PALETTERGB ( 0, 0,255)},
1338 {"dodger blue" , PALETTERGB ( 30,144,255)},
1339 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
1340 {"deep sky blue" , PALETTERGB ( 0,191,255)},
1341 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
1342 {"sky blue" , PALETTERGB (135,206,235)},
1343 {"SkyBlue" , PALETTERGB (135,206,235)},
1344 {"light sky blue" , PALETTERGB (135,206,250)},
1345 {"LightSkyBlue" , PALETTERGB (135,206,250)},
1346 {"steel blue" , PALETTERGB ( 70,130,180)},
1347 {"SteelBlue" , PALETTERGB ( 70,130,180)},
1348 {"light steel blue" , PALETTERGB (176,196,222)},
1349 {"LightSteelBlue" , PALETTERGB (176,196,222)},
1350 {"light blue" , PALETTERGB (173,216,230)},
1351 {"LightBlue" , PALETTERGB (173,216,230)},
1352 {"powder blue" , PALETTERGB (176,224,230)},
1353 {"PowderBlue" , PALETTERGB (176,224,230)},
1354 {"pale turquoise" , PALETTERGB (175,238,238)},
1355 {"PaleTurquoise" , PALETTERGB (175,238,238)},
1356 {"dark turquoise" , PALETTERGB ( 0,206,209)},
1357 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
1358 {"medium turquoise" , PALETTERGB ( 72,209,204)},
1359 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
1360 {"turquoise" , PALETTERGB ( 64,224,208)},
1361 {"cyan" , PALETTERGB ( 0,255,255)},
1362 {"light cyan" , PALETTERGB (224,255,255)},
1363 {"LightCyan" , PALETTERGB (224,255,255)},
1364 {"cadet blue" , PALETTERGB ( 95,158,160)},
1365 {"CadetBlue" , PALETTERGB ( 95,158,160)},
1366 {"medium aquamarine" , PALETTERGB (102,205,170)},
1367 {"MediumAquamarine" , PALETTERGB (102,205,170)},
1368 {"aquamarine" , PALETTERGB (127,255,212)},
1369 {"dark green" , PALETTERGB ( 0,100, 0)},
1370 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
1371 {"dark olive green" , PALETTERGB ( 85,107, 47)},
1372 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
1373 {"dark sea green" , PALETTERGB (143,188,143)},
1374 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
1375 {"sea green" , PALETTERGB ( 46,139, 87)},
1376 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
1377 {"medium sea green" , PALETTERGB ( 60,179,113)},
1378 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
1379 {"light sea green" , PALETTERGB ( 32,178,170)},
1380 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
1381 {"pale green" , PALETTERGB (152,251,152)},
1382 {"PaleGreen" , PALETTERGB (152,251,152)},
1383 {"spring green" , PALETTERGB ( 0,255,127)},
1384 {"SpringGreen" , PALETTERGB ( 0,255,127)},
1385 {"lawn green" , PALETTERGB (124,252, 0)},
1386 {"LawnGreen" , PALETTERGB (124,252, 0)},
1387 {"green" , PALETTERGB ( 0,255, 0)},
1388 {"chartreuse" , PALETTERGB (127,255, 0)},
1389 {"medium spring green" , PALETTERGB ( 0,250,154)},
1390 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
1391 {"green yellow" , PALETTERGB (173,255, 47)},
1392 {"GreenYellow" , PALETTERGB (173,255, 47)},
1393 {"lime green" , PALETTERGB ( 50,205, 50)},
1394 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
1395 {"yellow green" , PALETTERGB (154,205, 50)},
1396 {"YellowGreen" , PALETTERGB (154,205, 50)},
1397 {"forest green" , PALETTERGB ( 34,139, 34)},
1398 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
1399 {"olive drab" , PALETTERGB (107,142, 35)},
1400 {"OliveDrab" , PALETTERGB (107,142, 35)},
1401 {"dark khaki" , PALETTERGB (189,183,107)},
1402 {"DarkKhaki" , PALETTERGB (189,183,107)},
1403 {"khaki" , PALETTERGB (240,230,140)},
1404 {"pale goldenrod" , PALETTERGB (238,232,170)},
1405 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
1406 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
1407 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
1408 {"light yellow" , PALETTERGB (255,255,224)},
1409 {"LightYellow" , PALETTERGB (255,255,224)},
1410 {"yellow" , PALETTERGB (255,255, 0)},
1411 {"gold" , PALETTERGB (255,215, 0)},
1412 {"light goldenrod" , PALETTERGB (238,221,130)},
1413 {"LightGoldenrod" , PALETTERGB (238,221,130)},
1414 {"goldenrod" , PALETTERGB (218,165, 32)},
1415 {"dark goldenrod" , PALETTERGB (184,134, 11)},
1416 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
1417 {"rosy brown" , PALETTERGB (188,143,143)},
1418 {"RosyBrown" , PALETTERGB (188,143,143)},
1419 {"indian red" , PALETTERGB (205, 92, 92)},
1420 {"IndianRed" , PALETTERGB (205, 92, 92)},
1421 {"saddle brown" , PALETTERGB (139, 69, 19)},
1422 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
1423 {"sienna" , PALETTERGB (160, 82, 45)},
1424 {"peru" , PALETTERGB (205,133, 63)},
1425 {"burlywood" , PALETTERGB (222,184,135)},
1426 {"beige" , PALETTERGB (245,245,220)},
1427 {"wheat" , PALETTERGB (245,222,179)},
1428 {"sandy brown" , PALETTERGB (244,164, 96)},
1429 {"SandyBrown" , PALETTERGB (244,164, 96)},
1430 {"tan" , PALETTERGB (210,180,140)},
1431 {"chocolate" , PALETTERGB (210,105, 30)},
1432 {"firebrick" , PALETTERGB (178,34, 34)},
1433 {"brown" , PALETTERGB (165,42, 42)},
1434 {"dark salmon" , PALETTERGB (233,150,122)},
1435 {"DarkSalmon" , PALETTERGB (233,150,122)},
1436 {"salmon" , PALETTERGB (250,128,114)},
1437 {"light salmon" , PALETTERGB (255,160,122)},
1438 {"LightSalmon" , PALETTERGB (255,160,122)},
1439 {"orange" , PALETTERGB (255,165, 0)},
1440 {"dark orange" , PALETTERGB (255,140, 0)},
1441 {"DarkOrange" , PALETTERGB (255,140, 0)},
1442 {"coral" , PALETTERGB (255,127, 80)},
1443 {"light coral" , PALETTERGB (240,128,128)},
1444 {"LightCoral" , PALETTERGB (240,128,128)},
1445 {"tomato" , PALETTERGB (255, 99, 71)},
1446 {"orange red" , PALETTERGB (255, 69, 0)},
1447 {"OrangeRed" , PALETTERGB (255, 69, 0)},
1448 {"red" , PALETTERGB (255, 0, 0)},
1449 {"hot pink" , PALETTERGB (255,105,180)},
1450 {"HotPink" , PALETTERGB (255,105,180)},
1451 {"deep pink" , PALETTERGB (255, 20,147)},
1452 {"DeepPink" , PALETTERGB (255, 20,147)},
1453 {"pink" , PALETTERGB (255,192,203)},
1454 {"light pink" , PALETTERGB (255,182,193)},
1455 {"LightPink" , PALETTERGB (255,182,193)},
1456 {"pale violet red" , PALETTERGB (219,112,147)},
1457 {"PaleVioletRed" , PALETTERGB (219,112,147)},
1458 {"maroon" , PALETTERGB (176, 48, 96)},
1459 {"medium violet red" , PALETTERGB (199, 21,133)},
1460 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
1461 {"violet red" , PALETTERGB (208, 32,144)},
1462 {"VioletRed" , PALETTERGB (208, 32,144)},
1463 {"magenta" , PALETTERGB (255, 0,255)},
1464 {"violet" , PALETTERGB (238,130,238)},
1465 {"plum" , PALETTERGB (221,160,221)},
1466 {"orchid" , PALETTERGB (218,112,214)},
1467 {"medium orchid" , PALETTERGB (186, 85,211)},
1468 {"MediumOrchid" , PALETTERGB (186, 85,211)},
1469 {"dark orchid" , PALETTERGB (153, 50,204)},
1470 {"DarkOrchid" , PALETTERGB (153, 50,204)},
1471 {"dark violet" , PALETTERGB (148, 0,211)},
1472 {"DarkViolet" , PALETTERGB (148, 0,211)},
1473 {"blue violet" , PALETTERGB (138, 43,226)},
1474 {"BlueViolet" , PALETTERGB (138, 43,226)},
1475 {"purple" , PALETTERGB (160, 32,240)},
1476 {"medium purple" , PALETTERGB (147,112,219)},
1477 {"MediumPurple" , PALETTERGB (147,112,219)},
1478 {"thistle" , PALETTERGB (216,191,216)},
1479 {"gray0" , PALETTERGB ( 0, 0, 0)},
1480 {"grey0" , PALETTERGB ( 0, 0, 0)},
1481 {"dark grey" , PALETTERGB (169,169,169)},
1482 {"DarkGrey" , PALETTERGB (169,169,169)},
1483 {"dark gray" , PALETTERGB (169,169,169)},
1484 {"DarkGray" , PALETTERGB (169,169,169)},
1485 {"dark blue" , PALETTERGB ( 0, 0,139)},
1486 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
1487 {"dark cyan" , PALETTERGB ( 0,139,139)},
1488 {"DarkCyan" , PALETTERGB ( 0,139,139)},
1489 {"dark magenta" , PALETTERGB (139, 0,139)},
1490 {"DarkMagenta" , PALETTERGB (139, 0,139)},
1491 {"dark red" , PALETTERGB (139, 0, 0)},
1492 {"DarkRed" , PALETTERGB (139, 0, 0)},
1493 {"light green" , PALETTERGB (144,238,144)},
1494 {"LightGreen" , PALETTERGB (144,238,144)},
1495 };
1496
1497 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
1498 0, 0, 0, doc: /* Return the default color map. */)
1499 ()
1500 {
1501 int i;
1502 colormap_t *pc = w32_color_map;
1503 Lisp_Object cmap;
1504
1505 BLOCK_INPUT;
1506
1507 cmap = Qnil;
1508
1509 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
1510 pc++, i++)
1511 cmap = Fcons (Fcons (build_string (pc->name),
1512 make_number (pc->colorref)),
1513 cmap);
1514
1515 UNBLOCK_INPUT;
1516
1517 return (cmap);
1518 }
1519
1520 Lisp_Object
1521 w32_to_x_color (rgb)
1522 Lisp_Object rgb;
1523 {
1524 Lisp_Object color;
1525
1526 CHECK_NUMBER (rgb);
1527
1528 BLOCK_INPUT;
1529
1530 color = Frassq (rgb, Vw32_color_map);
1531
1532 UNBLOCK_INPUT;
1533
1534 if (!NILP (color))
1535 return (Fcar (color));
1536 else
1537 return Qnil;
1538 }
1539
1540 COLORREF
1541 w32_color_map_lookup (colorname)
1542 char *colorname;
1543 {
1544 Lisp_Object tail, ret = Qnil;
1545
1546 BLOCK_INPUT;
1547
1548 for (tail = Vw32_color_map; !NILP (tail); tail = Fcdr (tail))
1549 {
1550 register Lisp_Object elt, tem;
1551
1552 elt = Fcar (tail);
1553 if (!CONSP (elt)) continue;
1554
1555 tem = Fcar (elt);
1556
1557 if (lstrcmpi (XSTRING (tem)->data, colorname) == 0)
1558 {
1559 ret = XUINT (Fcdr (elt));
1560 break;
1561 }
1562
1563 QUIT;
1564 }
1565
1566
1567 UNBLOCK_INPUT;
1568
1569 return ret;
1570 }
1571
1572 COLORREF
1573 x_to_w32_color (colorname)
1574 char * colorname;
1575 {
1576 register Lisp_Object ret = Qnil;
1577
1578 BLOCK_INPUT;
1579
1580 if (colorname[0] == '#')
1581 {
1582 /* Could be an old-style RGB Device specification. */
1583 char *color;
1584 int size;
1585 color = colorname + 1;
1586
1587 size = strlen(color);
1588 if (size == 3 || size == 6 || size == 9 || size == 12)
1589 {
1590 UINT colorval;
1591 int i, pos;
1592 pos = 0;
1593 size /= 3;
1594 colorval = 0;
1595
1596 for (i = 0; i < 3; i++)
1597 {
1598 char *end;
1599 char t;
1600 unsigned long value;
1601
1602 /* The check for 'x' in the following conditional takes into
1603 account the fact that strtol allows a "0x" in front of
1604 our numbers, and we don't. */
1605 if (!isxdigit(color[0]) || color[1] == 'x')
1606 break;
1607 t = color[size];
1608 color[size] = '\0';
1609 value = strtoul(color, &end, 16);
1610 color[size] = t;
1611 if (errno == ERANGE || end - color != size)
1612 break;
1613 switch (size)
1614 {
1615 case 1:
1616 value = value * 0x10;
1617 break;
1618 case 2:
1619 break;
1620 case 3:
1621 value /= 0x10;
1622 break;
1623 case 4:
1624 value /= 0x100;
1625 break;
1626 }
1627 colorval |= (value << pos);
1628 pos += 0x8;
1629 if (i == 2)
1630 {
1631 UNBLOCK_INPUT;
1632 return (colorval);
1633 }
1634 color = end;
1635 }
1636 }
1637 }
1638 else if (strnicmp(colorname, "rgb:", 4) == 0)
1639 {
1640 char *color;
1641 UINT colorval;
1642 int i, pos;
1643 pos = 0;
1644
1645 colorval = 0;
1646 color = colorname + 4;
1647 for (i = 0; i < 3; i++)
1648 {
1649 char *end;
1650 unsigned long value;
1651
1652 /* The check for 'x' in the following conditional takes into
1653 account the fact that strtol allows a "0x" in front of
1654 our numbers, and we don't. */
1655 if (!isxdigit(color[0]) || color[1] == 'x')
1656 break;
1657 value = strtoul(color, &end, 16);
1658 if (errno == ERANGE)
1659 break;
1660 switch (end - color)
1661 {
1662 case 1:
1663 value = value * 0x10 + value;
1664 break;
1665 case 2:
1666 break;
1667 case 3:
1668 value /= 0x10;
1669 break;
1670 case 4:
1671 value /= 0x100;
1672 break;
1673 default:
1674 value = ULONG_MAX;
1675 }
1676 if (value == ULONG_MAX)
1677 break;
1678 colorval |= (value << pos);
1679 pos += 0x8;
1680 if (i == 2)
1681 {
1682 if (*end != '\0')
1683 break;
1684 UNBLOCK_INPUT;
1685 return (colorval);
1686 }
1687 if (*end != '/')
1688 break;
1689 color = end + 1;
1690 }
1691 }
1692 else if (strnicmp(colorname, "rgbi:", 5) == 0)
1693 {
1694 /* This is an RGB Intensity specification. */
1695 char *color;
1696 UINT colorval;
1697 int i, pos;
1698 pos = 0;
1699
1700 colorval = 0;
1701 color = colorname + 5;
1702 for (i = 0; i < 3; i++)
1703 {
1704 char *end;
1705 double value;
1706 UINT val;
1707
1708 value = strtod(color, &end);
1709 if (errno == ERANGE)
1710 break;
1711 if (value < 0.0 || value > 1.0)
1712 break;
1713 val = (UINT)(0x100 * value);
1714 /* We used 0x100 instead of 0xFF to give an continuous
1715 range between 0.0 and 1.0 inclusive. The next statement
1716 fixes the 1.0 case. */
1717 if (val == 0x100)
1718 val = 0xFF;
1719 colorval |= (val << pos);
1720 pos += 0x8;
1721 if (i == 2)
1722 {
1723 if (*end != '\0')
1724 break;
1725 UNBLOCK_INPUT;
1726 return (colorval);
1727 }
1728 if (*end != '/')
1729 break;
1730 color = end + 1;
1731 }
1732 }
1733 /* I am not going to attempt to handle any of the CIE color schemes
1734 or TekHVC, since I don't know the algorithms for conversion to
1735 RGB. */
1736
1737 /* If we fail to lookup the color name in w32_color_map, then check the
1738 colorname to see if it can be crudely approximated: If the X color
1739 ends in a number (e.g., "darkseagreen2"), strip the number and
1740 return the result of looking up the base color name. */
1741 ret = w32_color_map_lookup (colorname);
1742 if (NILP (ret))
1743 {
1744 int len = strlen (colorname);
1745
1746 if (isdigit (colorname[len - 1]))
1747 {
1748 char *ptr, *approx = alloca (len + 1);
1749
1750 strcpy (approx, colorname);
1751 ptr = &approx[len - 1];
1752 while (ptr > approx && isdigit (*ptr))
1753 *ptr-- = '\0';
1754
1755 ret = w32_color_map_lookup (approx);
1756 }
1757 }
1758
1759 UNBLOCK_INPUT;
1760 return ret;
1761 }
1762
1763
1764 void
1765 w32_regenerate_palette (FRAME_PTR f)
1766 {
1767 struct w32_palette_entry * list;
1768 LOGPALETTE * log_palette;
1769 HPALETTE new_palette;
1770 int i;
1771
1772 /* don't bother trying to create palette if not supported */
1773 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1774 return;
1775
1776 log_palette = (LOGPALETTE *)
1777 alloca (sizeof (LOGPALETTE) +
1778 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1779 log_palette->palVersion = 0x300;
1780 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1781
1782 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1783 for (i = 0;
1784 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1785 i++, list = list->next)
1786 log_palette->palPalEntry[i] = list->entry;
1787
1788 new_palette = CreatePalette (log_palette);
1789
1790 enter_crit ();
1791
1792 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1793 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1794 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1795
1796 /* Realize display palette and garbage all frames. */
1797 release_frame_dc (f, get_frame_dc (f));
1798
1799 leave_crit ();
1800 }
1801
1802 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1803 #define SET_W32_COLOR(pe, color) \
1804 do \
1805 { \
1806 pe.peRed = GetRValue (color); \
1807 pe.peGreen = GetGValue (color); \
1808 pe.peBlue = GetBValue (color); \
1809 pe.peFlags = 0; \
1810 } while (0)
1811
1812 #if 0
1813 /* Keep these around in case we ever want to track color usage. */
1814 void
1815 w32_map_color (FRAME_PTR f, COLORREF color)
1816 {
1817 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1818
1819 if (NILP (Vw32_enable_palette))
1820 return;
1821
1822 /* check if color is already mapped */
1823 while (list)
1824 {
1825 if (W32_COLOR (list->entry) == color)
1826 {
1827 ++list->refcount;
1828 return;
1829 }
1830 list = list->next;
1831 }
1832
1833 /* not already mapped, so add to list and recreate Windows palette */
1834 list = (struct w32_palette_entry *)
1835 xmalloc (sizeof (struct w32_palette_entry));
1836 SET_W32_COLOR (list->entry, color);
1837 list->refcount = 1;
1838 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1839 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1840 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1841
1842 /* set flag that palette must be regenerated */
1843 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1844 }
1845
1846 void
1847 w32_unmap_color (FRAME_PTR f, COLORREF color)
1848 {
1849 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1850 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1851
1852 if (NILP (Vw32_enable_palette))
1853 return;
1854
1855 /* check if color is already mapped */
1856 while (list)
1857 {
1858 if (W32_COLOR (list->entry) == color)
1859 {
1860 if (--list->refcount == 0)
1861 {
1862 *prev = list->next;
1863 xfree (list);
1864 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1865 break;
1866 }
1867 else
1868 return;
1869 }
1870 prev = &list->next;
1871 list = list->next;
1872 }
1873
1874 /* set flag that palette must be regenerated */
1875 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1876 }
1877 #endif
1878
1879
1880 /* Gamma-correct COLOR on frame F. */
1881
1882 void
1883 gamma_correct (f, color)
1884 struct frame *f;
1885 COLORREF *color;
1886 {
1887 if (f->gamma)
1888 {
1889 *color = PALETTERGB (
1890 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1891 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1892 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1893 }
1894 }
1895
1896
1897 /* Decide if color named COLOR is valid for the display associated with
1898 the selected frame; if so, return the rgb values in COLOR_DEF.
1899 If ALLOC is nonzero, allocate a new colormap cell. */
1900
1901 int
1902 w32_defined_color (f, color, color_def, alloc)
1903 FRAME_PTR f;
1904 char *color;
1905 XColor *color_def;
1906 int alloc;
1907 {
1908 register Lisp_Object tem;
1909 COLORREF w32_color_ref;
1910
1911 tem = x_to_w32_color (color);
1912
1913 if (!NILP (tem))
1914 {
1915 if (f)
1916 {
1917 /* Apply gamma correction. */
1918 w32_color_ref = XUINT (tem);
1919 gamma_correct (f, &w32_color_ref);
1920 XSETINT (tem, w32_color_ref);
1921 }
1922
1923 /* Map this color to the palette if it is enabled. */
1924 if (!NILP (Vw32_enable_palette))
1925 {
1926 struct w32_palette_entry * entry =
1927 one_w32_display_info.color_list;
1928 struct w32_palette_entry ** prev =
1929 &one_w32_display_info.color_list;
1930
1931 /* check if color is already mapped */
1932 while (entry)
1933 {
1934 if (W32_COLOR (entry->entry) == XUINT (tem))
1935 break;
1936 prev = &entry->next;
1937 entry = entry->next;
1938 }
1939
1940 if (entry == NULL && alloc)
1941 {
1942 /* not already mapped, so add to list */
1943 entry = (struct w32_palette_entry *)
1944 xmalloc (sizeof (struct w32_palette_entry));
1945 SET_W32_COLOR (entry->entry, XUINT (tem));
1946 entry->next = NULL;
1947 *prev = entry;
1948 one_w32_display_info.num_colors++;
1949
1950 /* set flag that palette must be regenerated */
1951 one_w32_display_info.regen_palette = TRUE;
1952 }
1953 }
1954 /* Ensure COLORREF value is snapped to nearest color in (default)
1955 palette by simulating the PALETTERGB macro. This works whether
1956 or not the display device has a palette. */
1957 w32_color_ref = XUINT (tem) | 0x2000000;
1958
1959 color_def->pixel = w32_color_ref;
1960 color_def->red = GetRValue (w32_color_ref);
1961 color_def->green = GetGValue (w32_color_ref);
1962 color_def->blue = GetBValue (w32_color_ref);
1963
1964 return 1;
1965 }
1966 else
1967 {
1968 return 0;
1969 }
1970 }
1971
1972 /* Given a string ARG naming a color, compute a pixel value from it
1973 suitable for screen F.
1974 If F is not a color screen, return DEF (default) regardless of what
1975 ARG says. */
1976
1977 int
1978 x_decode_color (f, arg, def)
1979 FRAME_PTR f;
1980 Lisp_Object arg;
1981 int def;
1982 {
1983 XColor cdef;
1984
1985 CHECK_STRING (arg);
1986
1987 if (strcmp (XSTRING (arg)->data, "black") == 0)
1988 return BLACK_PIX_DEFAULT (f);
1989 else if (strcmp (XSTRING (arg)->data, "white") == 0)
1990 return WHITE_PIX_DEFAULT (f);
1991
1992 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1993 return def;
1994
1995 /* w32_defined_color is responsible for coping with failures
1996 by looking for a near-miss. */
1997 if (w32_defined_color (f, XSTRING (arg)->data, &cdef, 1))
1998 return cdef.pixel;
1999
2000 /* defined_color failed; return an ultimate default. */
2001 return def;
2002 }
2003 \f
2004 /* Change the `line-spacing' frame parameter of frame F. OLD_VALUE is
2005 the previous value of that parameter, NEW_VALUE is the new value. */
2006
2007 static void
2008 x_set_line_spacing (f, new_value, old_value)
2009 struct frame *f;
2010 Lisp_Object new_value, old_value;
2011 {
2012 if (NILP (new_value))
2013 f->extra_line_spacing = 0;
2014 else if (NATNUMP (new_value))
2015 f->extra_line_spacing = XFASTINT (new_value);
2016 else
2017 Fsignal (Qerror, Fcons (build_string ("Invalid line-spacing"),
2018 Fcons (new_value, Qnil)));
2019 if (FRAME_VISIBLE_P (f))
2020 redraw_frame (f);
2021 }
2022
2023
2024 /* Change the `fullscreen' frame parameter of frame F. OLD_VALUE is
2025 the previous value of that parameter, NEW_VALUE is the new value. */
2026
2027 static void
2028 x_set_fullscreen (f, new_value, old_value)
2029 struct frame *f;
2030 Lisp_Object new_value, old_value;
2031 {
2032 if (NILP (new_value))
2033 f->output_data.w32->want_fullscreen = FULLSCREEN_NONE;
2034 else if (EQ (new_value, Qfullboth))
2035 f->output_data.w32->want_fullscreen = FULLSCREEN_BOTH;
2036 else if (EQ (new_value, Qfullwidth))
2037 f->output_data.w32->want_fullscreen = FULLSCREEN_WIDTH;
2038 else if (EQ (new_value, Qfullheight))
2039 f->output_data.w32->want_fullscreen = FULLSCREEN_HEIGHT;
2040 }
2041
2042
2043 /* Change the `screen-gamma' frame parameter of frame F. OLD_VALUE is
2044 the previous value of that parameter, NEW_VALUE is the new value. */
2045
2046 static void
2047 x_set_screen_gamma (f, new_value, old_value)
2048 struct frame *f;
2049 Lisp_Object new_value, old_value;
2050 {
2051 if (NILP (new_value))
2052 f->gamma = 0;
2053 else if (NUMBERP (new_value) && XFLOATINT (new_value) > 0)
2054 /* The value 0.4545 is the normal viewing gamma. */
2055 f->gamma = 1.0 / (0.4545 * XFLOATINT (new_value));
2056 else
2057 Fsignal (Qerror, Fcons (build_string ("Invalid screen-gamma"),
2058 Fcons (new_value, Qnil)));
2059
2060 clear_face_cache (0);
2061 }
2062
2063
2064 /* Functions called only from `x_set_frame_param'
2065 to set individual parameters.
2066
2067 If FRAME_W32_WINDOW (f) is 0,
2068 the frame is being created and its window does not exist yet.
2069 In that case, just record the parameter's new value
2070 in the standard place; do not attempt to change the window. */
2071
2072 void
2073 x_set_foreground_color (f, arg, oldval)
2074 struct frame *f;
2075 Lisp_Object arg, oldval;
2076 {
2077 struct w32_output *x = f->output_data.w32;
2078 PIX_TYPE fg, old_fg;
2079
2080 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2081 old_fg = FRAME_FOREGROUND_PIXEL (f);
2082 FRAME_FOREGROUND_PIXEL (f) = fg;
2083
2084 if (FRAME_W32_WINDOW (f) != 0)
2085 {
2086 if (x->cursor_pixel == old_fg)
2087 x->cursor_pixel = fg;
2088
2089 update_face_from_frame_parameter (f, Qforeground_color, arg);
2090 if (FRAME_VISIBLE_P (f))
2091 redraw_frame (f);
2092 }
2093 }
2094
2095 void
2096 x_set_background_color (f, arg, oldval)
2097 struct frame *f;
2098 Lisp_Object arg, oldval;
2099 {
2100 FRAME_BACKGROUND_PIXEL (f)
2101 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
2102
2103 if (FRAME_W32_WINDOW (f) != 0)
2104 {
2105 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
2106 FRAME_BACKGROUND_PIXEL (f));
2107
2108 update_face_from_frame_parameter (f, Qbackground_color, arg);
2109
2110 if (FRAME_VISIBLE_P (f))
2111 redraw_frame (f);
2112 }
2113 }
2114
2115 void
2116 x_set_mouse_color (f, arg, oldval)
2117 struct frame *f;
2118 Lisp_Object arg, oldval;
2119 {
2120 Cursor cursor, nontext_cursor, mode_cursor, cross_cursor;
2121 int count;
2122 int mask_color;
2123
2124 if (!EQ (Qnil, arg))
2125 f->output_data.w32->mouse_pixel
2126 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2127 mask_color = FRAME_BACKGROUND_PIXEL (f);
2128
2129 /* Don't let pointers be invisible. */
2130 if (mask_color == f->output_data.w32->mouse_pixel
2131 && mask_color == FRAME_BACKGROUND_PIXEL (f))
2132 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
2133
2134 #if 0 /* TODO : cursor changes */
2135 BLOCK_INPUT;
2136
2137 /* It's not okay to crash if the user selects a screwy cursor. */
2138 count = x_catch_errors (FRAME_W32_DISPLAY (f));
2139
2140 if (!EQ (Qnil, Vx_pointer_shape))
2141 {
2142 CHECK_NUMBER (Vx_pointer_shape);
2143 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
2144 }
2145 else
2146 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2147 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
2148
2149 if (!EQ (Qnil, Vx_nontext_pointer_shape))
2150 {
2151 CHECK_NUMBER (Vx_nontext_pointer_shape);
2152 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2153 XINT (Vx_nontext_pointer_shape));
2154 }
2155 else
2156 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
2157 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2158
2159 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
2160 {
2161 CHECK_NUMBER (Vx_hourglass_pointer_shape);
2162 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2163 XINT (Vx_hourglass_pointer_shape));
2164 }
2165 else
2166 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
2167 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
2168
2169 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
2170 if (!EQ (Qnil, Vx_mode_pointer_shape))
2171 {
2172 CHECK_NUMBER (Vx_mode_pointer_shape);
2173 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2174 XINT (Vx_mode_pointer_shape));
2175 }
2176 else
2177 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
2178 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
2179
2180 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
2181 {
2182 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
2183 cross_cursor
2184 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
2185 XINT (Vx_sensitive_text_pointer_shape));
2186 }
2187 else
2188 cross_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
2189
2190 if (!NILP (Vx_window_horizontal_drag_shape))
2191 {
2192 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
2193 horizontal_drag_cursor
2194 = XCreateFontCursor (FRAME_X_DISPLAY (f),
2195 XINT (Vx_window_horizontal_drag_shape));
2196 }
2197 else
2198 horizontal_drag_cursor
2199 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
2200
2201 /* Check and report errors with the above calls. */
2202 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
2203 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
2204
2205 {
2206 XColor fore_color, back_color;
2207
2208 fore_color.pixel = f->output_data.w32->mouse_pixel;
2209 back_color.pixel = mask_color;
2210 XQueryColor (FRAME_W32_DISPLAY (f),
2211 DefaultColormap (FRAME_W32_DISPLAY (f),
2212 DefaultScreen (FRAME_W32_DISPLAY (f))),
2213 &fore_color);
2214 XQueryColor (FRAME_W32_DISPLAY (f),
2215 DefaultColormap (FRAME_W32_DISPLAY (f),
2216 DefaultScreen (FRAME_W32_DISPLAY (f))),
2217 &back_color);
2218 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
2219 &fore_color, &back_color);
2220 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
2221 &fore_color, &back_color);
2222 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
2223 &fore_color, &back_color);
2224 XRecolorCursor (FRAME_W32_DISPLAY (f), cross_cursor,
2225 &fore_color, &back_color);
2226 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
2227 &fore_color, &back_color);
2228 }
2229
2230 if (FRAME_W32_WINDOW (f) != 0)
2231 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
2232
2233 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
2234 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
2235 f->output_data.w32->text_cursor = cursor;
2236
2237 if (nontext_cursor != f->output_data.w32->nontext_cursor
2238 && f->output_data.w32->nontext_cursor != 0)
2239 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
2240 f->output_data.w32->nontext_cursor = nontext_cursor;
2241
2242 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
2243 && f->output_data.w32->hourglass_cursor != 0)
2244 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
2245 f->output_data.w32->hourglass_cursor = hourglass_cursor;
2246
2247 if (mode_cursor != f->output_data.w32->modeline_cursor
2248 && f->output_data.w32->modeline_cursor != 0)
2249 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
2250 f->output_data.w32->modeline_cursor = mode_cursor;
2251
2252 if (cross_cursor != f->output_data.w32->cross_cursor
2253 && f->output_data.w32->cross_cursor != 0)
2254 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->cross_cursor);
2255 f->output_data.w32->cross_cursor = cross_cursor;
2256
2257 XFlush (FRAME_W32_DISPLAY (f));
2258 UNBLOCK_INPUT;
2259
2260 update_face_from_frame_parameter (f, Qmouse_color, arg);
2261 #endif /* TODO */
2262 }
2263
2264 /* Defined in w32term.c. */
2265 void x_update_cursor (struct frame *f, int on_p);
2266
2267 void
2268 x_set_cursor_color (f, arg, oldval)
2269 struct frame *f;
2270 Lisp_Object arg, oldval;
2271 {
2272 unsigned long fore_pixel, pixel;
2273
2274 if (!NILP (Vx_cursor_fore_pixel))
2275 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
2276 WHITE_PIX_DEFAULT (f));
2277 else
2278 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2279
2280 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2281
2282 /* Make sure that the cursor color differs from the background color. */
2283 if (pixel == FRAME_BACKGROUND_PIXEL (f))
2284 {
2285 pixel = f->output_data.w32->mouse_pixel;
2286 if (pixel == fore_pixel)
2287 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
2288 }
2289
2290 FRAME_FOREGROUND_PIXEL (f) = fore_pixel;
2291 f->output_data.w32->cursor_pixel = pixel;
2292
2293 if (FRAME_W32_WINDOW (f) != 0)
2294 {
2295 if (FRAME_VISIBLE_P (f))
2296 {
2297 x_update_cursor (f, 0);
2298 x_update_cursor (f, 1);
2299 }
2300 }
2301
2302 update_face_from_frame_parameter (f, Qcursor_color, arg);
2303 }
2304
2305 /* Set the border-color of frame F to pixel value PIX.
2306 Note that this does not fully take effect if done before
2307 F has an window. */
2308 void
2309 x_set_border_pixel (f, pix)
2310 struct frame *f;
2311 int pix;
2312 {
2313 f->output_data.w32->border_pixel = pix;
2314
2315 if (FRAME_W32_WINDOW (f) != 0 && f->output_data.w32->border_width > 0)
2316 {
2317 if (FRAME_VISIBLE_P (f))
2318 redraw_frame (f);
2319 }
2320 }
2321
2322 /* Set the border-color of frame F to value described by ARG.
2323 ARG can be a string naming a color.
2324 The border-color is used for the border that is drawn by the server.
2325 Note that this does not fully take effect if done before
2326 F has a window; it must be redone when the window is created. */
2327
2328 void
2329 x_set_border_color (f, arg, oldval)
2330 struct frame *f;
2331 Lisp_Object arg, oldval;
2332 {
2333 int pix;
2334
2335 CHECK_STRING (arg);
2336 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
2337 x_set_border_pixel (f, pix);
2338 update_face_from_frame_parameter (f, Qborder_color, arg);
2339 }
2340
2341 /* Value is the internal representation of the specified cursor type
2342 ARG. If type is BAR_CURSOR, return in *WIDTH the specified width
2343 of the bar cursor. */
2344
2345 enum text_cursor_kinds
2346 x_specified_cursor_type (arg, width)
2347 Lisp_Object arg;
2348 int *width;
2349 {
2350 enum text_cursor_kinds type;
2351
2352 if (EQ (arg, Qbar))
2353 {
2354 type = BAR_CURSOR;
2355 *width = 2;
2356 }
2357 else if (CONSP (arg)
2358 && EQ (XCAR (arg), Qbar)
2359 && INTEGERP (XCDR (arg))
2360 && XINT (XCDR (arg)) >= 0)
2361 {
2362 type = BAR_CURSOR;
2363 *width = XINT (XCDR (arg));
2364 }
2365 else if (NILP (arg))
2366 type = NO_CURSOR;
2367 else
2368 /* Treat anything unknown as "box cursor".
2369 It was bad to signal an error; people have trouble fixing
2370 .Xdefaults with Emacs, when it has something bad in it. */
2371 type = FILLED_BOX_CURSOR;
2372
2373 return type;
2374 }
2375
2376 void
2377 x_set_cursor_type (f, arg, oldval)
2378 FRAME_PTR f;
2379 Lisp_Object arg, oldval;
2380 {
2381 int width;
2382
2383 FRAME_DESIRED_CURSOR (f) = x_specified_cursor_type (arg, &width);
2384 f->output_data.w32->cursor_width = width;
2385
2386 /* Make sure the cursor gets redrawn. This is overkill, but how
2387 often do people change cursor types? */
2388 update_mode_lines++;
2389 }
2390 \f
2391 void
2392 x_set_icon_type (f, arg, oldval)
2393 struct frame *f;
2394 Lisp_Object arg, oldval;
2395 {
2396 int result;
2397
2398 if (NILP (arg) && NILP (oldval))
2399 return;
2400
2401 if (STRINGP (arg) && STRINGP (oldval)
2402 && EQ (Fstring_equal (oldval, arg), Qt))
2403 return;
2404
2405 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
2406 return;
2407
2408 BLOCK_INPUT;
2409
2410 result = x_bitmap_icon (f, arg);
2411 if (result)
2412 {
2413 UNBLOCK_INPUT;
2414 error ("No icon window available");
2415 }
2416
2417 UNBLOCK_INPUT;
2418 }
2419
2420 /* Return non-nil if frame F wants a bitmap icon. */
2421
2422 Lisp_Object
2423 x_icon_type (f)
2424 FRAME_PTR f;
2425 {
2426 Lisp_Object tem;
2427
2428 tem = assq_no_quit (Qicon_type, f->param_alist);
2429 if (CONSP (tem))
2430 return XCDR (tem);
2431 else
2432 return Qnil;
2433 }
2434
2435 void
2436 x_set_icon_name (f, arg, oldval)
2437 struct frame *f;
2438 Lisp_Object arg, oldval;
2439 {
2440 if (STRINGP (arg))
2441 {
2442 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
2443 return;
2444 }
2445 else if (!STRINGP (oldval) && EQ (oldval, Qnil) == EQ (arg, Qnil))
2446 return;
2447
2448 f->icon_name = arg;
2449
2450 #if 0
2451 if (f->output_data.w32->icon_bitmap != 0)
2452 return;
2453
2454 BLOCK_INPUT;
2455
2456 result = x_text_icon (f,
2457 (char *) XSTRING ((!NILP (f->icon_name)
2458 ? f->icon_name
2459 : !NILP (f->title)
2460 ? f->title
2461 : f->name))->data);
2462
2463 if (result)
2464 {
2465 UNBLOCK_INPUT;
2466 error ("No icon window available");
2467 }
2468
2469 /* If the window was unmapped (and its icon was mapped),
2470 the new icon is not mapped, so map the window in its stead. */
2471 if (FRAME_VISIBLE_P (f))
2472 {
2473 #ifdef USE_X_TOOLKIT
2474 XtPopup (f->output_data.w32->widget, XtGrabNone);
2475 #endif
2476 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
2477 }
2478
2479 XFlush (FRAME_W32_DISPLAY (f));
2480 UNBLOCK_INPUT;
2481 #endif
2482 }
2483
2484 extern Lisp_Object x_new_font ();
2485 extern Lisp_Object x_new_fontset();
2486
2487 void
2488 x_set_font (f, arg, oldval)
2489 struct frame *f;
2490 Lisp_Object arg, oldval;
2491 {
2492 Lisp_Object result;
2493 Lisp_Object fontset_name;
2494 Lisp_Object frame;
2495 int old_fontset = FRAME_FONTSET(f);
2496
2497 CHECK_STRING (arg);
2498
2499 fontset_name = Fquery_fontset (arg, Qnil);
2500
2501 BLOCK_INPUT;
2502 result = (STRINGP (fontset_name)
2503 ? x_new_fontset (f, XSTRING (fontset_name)->data)
2504 : x_new_font (f, XSTRING (arg)->data));
2505 UNBLOCK_INPUT;
2506
2507 if (EQ (result, Qnil))
2508 error ("Font `%s' is not defined", XSTRING (arg)->data);
2509 else if (EQ (result, Qt))
2510 error ("The characters of the given font have varying widths");
2511 else if (STRINGP (result))
2512 {
2513 if (STRINGP (fontset_name))
2514 {
2515 /* Fontset names are built from ASCII font names, so the
2516 names may be equal despite there was a change. */
2517 if (old_fontset == FRAME_FONTSET (f))
2518 return;
2519 }
2520 else if (!NILP (Fequal (result, oldval)))
2521 return;
2522
2523 store_frame_param (f, Qfont, result);
2524 recompute_basic_faces (f);
2525 }
2526 else
2527 abort ();
2528
2529 do_pending_window_change (0);
2530
2531 /* Don't call `face-set-after-frame-default' when faces haven't been
2532 initialized yet. This is the case when called from
2533 Fx_create_frame. In that case, the X widget or window doesn't
2534 exist either, and we can end up in x_report_frame_params with a
2535 null widget which gives a segfault. */
2536 if (FRAME_FACE_CACHE (f))
2537 {
2538 XSETFRAME (frame, f);
2539 call1 (Qface_set_after_frame_default, frame);
2540 }
2541 }
2542
2543 static void
2544 x_set_fringe_width (f, new_value, old_value)
2545 struct frame *f;
2546 Lisp_Object new_value, old_value;
2547 {
2548 x_compute_fringe_widths (f, 1);
2549 }
2550
2551 void
2552 x_set_border_width (f, arg, oldval)
2553 struct frame *f;
2554 Lisp_Object arg, oldval;
2555 {
2556 CHECK_NUMBER (arg);
2557
2558 if (XINT (arg) == f->output_data.w32->border_width)
2559 return;
2560
2561 if (FRAME_W32_WINDOW (f) != 0)
2562 error ("Cannot change the border width of a window");
2563
2564 f->output_data.w32->border_width = XINT (arg);
2565 }
2566
2567 void
2568 x_set_internal_border_width (f, arg, oldval)
2569 struct frame *f;
2570 Lisp_Object arg, oldval;
2571 {
2572 int old = f->output_data.w32->internal_border_width;
2573
2574 CHECK_NUMBER (arg);
2575 f->output_data.w32->internal_border_width = XINT (arg);
2576 if (f->output_data.w32->internal_border_width < 0)
2577 f->output_data.w32->internal_border_width = 0;
2578
2579 if (f->output_data.w32->internal_border_width == old)
2580 return;
2581
2582 if (FRAME_W32_WINDOW (f) != 0)
2583 {
2584 x_set_window_size (f, 0, f->width, f->height);
2585 SET_FRAME_GARBAGED (f);
2586 do_pending_window_change (0);
2587 }
2588 else
2589 SET_FRAME_GARBAGED (f);
2590 }
2591
2592 void
2593 x_set_visibility (f, value, oldval)
2594 struct frame *f;
2595 Lisp_Object value, oldval;
2596 {
2597 Lisp_Object frame;
2598 XSETFRAME (frame, f);
2599
2600 if (NILP (value))
2601 Fmake_frame_invisible (frame, Qt);
2602 else if (EQ (value, Qicon))
2603 Ficonify_frame (frame);
2604 else
2605 Fmake_frame_visible (frame);
2606 }
2607
2608 \f
2609 /* Change window heights in windows rooted in WINDOW by N lines. */
2610
2611 static void
2612 x_change_window_heights (window, n)
2613 Lisp_Object window;
2614 int n;
2615 {
2616 struct window *w = XWINDOW (window);
2617
2618 XSETFASTINT (w->top, XFASTINT (w->top) + n);
2619 XSETFASTINT (w->height, XFASTINT (w->height) - n);
2620
2621 if (INTEGERP (w->orig_top))
2622 XSETFASTINT (w->orig_top, XFASTINT (w->orig_top) + n);
2623 if (INTEGERP (w->orig_height))
2624 XSETFASTINT (w->orig_height, XFASTINT (w->orig_height) - n);
2625
2626 /* Handle just the top child in a vertical split. */
2627 if (!NILP (w->vchild))
2628 x_change_window_heights (w->vchild, n);
2629
2630 /* Adjust all children in a horizontal split. */
2631 for (window = w->hchild; !NILP (window); window = w->next)
2632 {
2633 w = XWINDOW (window);
2634 x_change_window_heights (window, n);
2635 }
2636 }
2637
2638 void
2639 x_set_menu_bar_lines (f, value, oldval)
2640 struct frame *f;
2641 Lisp_Object value, oldval;
2642 {
2643 int nlines;
2644 int olines = FRAME_MENU_BAR_LINES (f);
2645
2646 /* Right now, menu bars don't work properly in minibuf-only frames;
2647 most of the commands try to apply themselves to the minibuffer
2648 frame itself, and get an error because you can't switch buffers
2649 in or split the minibuffer window. */
2650 if (FRAME_MINIBUF_ONLY_P (f))
2651 return;
2652
2653 if (INTEGERP (value))
2654 nlines = XINT (value);
2655 else
2656 nlines = 0;
2657
2658 FRAME_MENU_BAR_LINES (f) = 0;
2659 if (nlines)
2660 FRAME_EXTERNAL_MENU_BAR (f) = 1;
2661 else
2662 {
2663 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
2664 free_frame_menubar (f);
2665 FRAME_EXTERNAL_MENU_BAR (f) = 0;
2666
2667 /* Adjust the frame size so that the client (text) dimensions
2668 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
2669 set correctly. */
2670 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2671 do_pending_window_change (0);
2672 }
2673 adjust_glyphs (f);
2674 }
2675
2676
2677 /* Set the number of lines used for the tool bar of frame F to VALUE.
2678 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
2679 is the old number of tool bar lines. This function changes the
2680 height of all windows on frame F to match the new tool bar height.
2681 The frame's height doesn't change. */
2682
2683 void
2684 x_set_tool_bar_lines (f, value, oldval)
2685 struct frame *f;
2686 Lisp_Object value, oldval;
2687 {
2688 int delta, nlines, root_height;
2689 Lisp_Object root_window;
2690
2691 /* Treat tool bars like menu bars. */
2692 if (FRAME_MINIBUF_ONLY_P (f))
2693 return;
2694
2695 /* Use VALUE only if an integer >= 0. */
2696 if (INTEGERP (value) && XINT (value) >= 0)
2697 nlines = XFASTINT (value);
2698 else
2699 nlines = 0;
2700
2701 /* Make sure we redisplay all windows in this frame. */
2702 ++windows_or_buffers_changed;
2703
2704 delta = nlines - FRAME_TOOL_BAR_LINES (f);
2705
2706 /* Don't resize the tool-bar to more than we have room for. */
2707 root_window = FRAME_ROOT_WINDOW (f);
2708 root_height = XINT (XWINDOW (root_window)->height);
2709 if (root_height - delta < 1)
2710 {
2711 delta = root_height - 1;
2712 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
2713 }
2714
2715 FRAME_TOOL_BAR_LINES (f) = nlines;
2716 x_change_window_heights (root_window, delta);
2717 adjust_glyphs (f);
2718
2719 /* We also have to make sure that the internal border at the top of
2720 the frame, below the menu bar or tool bar, is redrawn when the
2721 tool bar disappears. This is so because the internal border is
2722 below the tool bar if one is displayed, but is below the menu bar
2723 if there isn't a tool bar. The tool bar draws into the area
2724 below the menu bar. */
2725 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
2726 {
2727 updating_frame = f;
2728 clear_frame ();
2729 clear_current_matrices (f);
2730 updating_frame = NULL;
2731 }
2732
2733 /* If the tool bar gets smaller, the internal border below it
2734 has to be cleared. It was formerly part of the display
2735 of the larger tool bar, and updating windows won't clear it. */
2736 if (delta < 0)
2737 {
2738 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
2739 int width = PIXEL_WIDTH (f);
2740 int y = nlines * CANON_Y_UNIT (f);
2741
2742 BLOCK_INPUT;
2743 {
2744 HDC hdc = get_frame_dc (f);
2745 w32_clear_area (f, hdc, 0, y, width, height);
2746 release_frame_dc (f, hdc);
2747 }
2748 UNBLOCK_INPUT;
2749
2750 if (WINDOWP (f->tool_bar_window))
2751 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
2752 }
2753 }
2754
2755
2756 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
2757 w32_id_name.
2758
2759 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2760 name; if NAME is a string, set F's name to NAME and set
2761 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2762
2763 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2764 suggesting a new name, which lisp code should override; if
2765 F->explicit_name is set, ignore the new name; otherwise, set it. */
2766
2767 void
2768 x_set_name (f, name, explicit)
2769 struct frame *f;
2770 Lisp_Object name;
2771 int explicit;
2772 {
2773 /* Make sure that requests from lisp code override requests from
2774 Emacs redisplay code. */
2775 if (explicit)
2776 {
2777 /* If we're switching from explicit to implicit, we had better
2778 update the mode lines and thereby update the title. */
2779 if (f->explicit_name && NILP (name))
2780 update_mode_lines = 1;
2781
2782 f->explicit_name = ! NILP (name);
2783 }
2784 else if (f->explicit_name)
2785 return;
2786
2787 /* If NAME is nil, set the name to the w32_id_name. */
2788 if (NILP (name))
2789 {
2790 /* Check for no change needed in this very common case
2791 before we do any consing. */
2792 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
2793 XSTRING (f->name)->data))
2794 return;
2795 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
2796 }
2797 else
2798 CHECK_STRING (name);
2799
2800 /* Don't change the name if it's already NAME. */
2801 if (! NILP (Fstring_equal (name, f->name)))
2802 return;
2803
2804 f->name = name;
2805
2806 /* For setting the frame title, the title parameter should override
2807 the name parameter. */
2808 if (! NILP (f->title))
2809 name = f->title;
2810
2811 if (FRAME_W32_WINDOW (f))
2812 {
2813 if (STRING_MULTIBYTE (name))
2814 name = ENCODE_SYSTEM (name);
2815
2816 BLOCK_INPUT;
2817 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2818 UNBLOCK_INPUT;
2819 }
2820 }
2821
2822 /* This function should be called when the user's lisp code has
2823 specified a name for the frame; the name will override any set by the
2824 redisplay code. */
2825 void
2826 x_explicitly_set_name (f, arg, oldval)
2827 FRAME_PTR f;
2828 Lisp_Object arg, oldval;
2829 {
2830 x_set_name (f, arg, 1);
2831 }
2832
2833 /* This function should be called by Emacs redisplay code to set the
2834 name; names set this way will never override names set by the user's
2835 lisp code. */
2836 void
2837 x_implicitly_set_name (f, arg, oldval)
2838 FRAME_PTR f;
2839 Lisp_Object arg, oldval;
2840 {
2841 x_set_name (f, arg, 0);
2842 }
2843 \f
2844 /* Change the title of frame F to NAME.
2845 If NAME is nil, use the frame name as the title.
2846
2847 If EXPLICIT is non-zero, that indicates that lisp code is setting the
2848 name; if NAME is a string, set F's name to NAME and set
2849 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
2850
2851 If EXPLICIT is zero, that indicates that Emacs redisplay code is
2852 suggesting a new name, which lisp code should override; if
2853 F->explicit_name is set, ignore the new name; otherwise, set it. */
2854
2855 void
2856 x_set_title (f, name, old_name)
2857 struct frame *f;
2858 Lisp_Object name, old_name;
2859 {
2860 /* Don't change the title if it's already NAME. */
2861 if (EQ (name, f->title))
2862 return;
2863
2864 update_mode_lines = 1;
2865
2866 f->title = name;
2867
2868 if (NILP (name))
2869 name = f->name;
2870
2871 if (FRAME_W32_WINDOW (f))
2872 {
2873 if (STRING_MULTIBYTE (name))
2874 name = ENCODE_SYSTEM (name);
2875
2876 BLOCK_INPUT;
2877 SetWindowText(FRAME_W32_WINDOW (f), XSTRING (name)->data);
2878 UNBLOCK_INPUT;
2879 }
2880 }
2881 \f
2882 void
2883 x_set_autoraise (f, arg, oldval)
2884 struct frame *f;
2885 Lisp_Object arg, oldval;
2886 {
2887 f->auto_raise = !EQ (Qnil, arg);
2888 }
2889
2890 void
2891 x_set_autolower (f, arg, oldval)
2892 struct frame *f;
2893 Lisp_Object arg, oldval;
2894 {
2895 f->auto_lower = !EQ (Qnil, arg);
2896 }
2897
2898 void
2899 x_set_unsplittable (f, arg, oldval)
2900 struct frame *f;
2901 Lisp_Object arg, oldval;
2902 {
2903 f->no_split = !NILP (arg);
2904 }
2905
2906 void
2907 x_set_vertical_scroll_bars (f, arg, oldval)
2908 struct frame *f;
2909 Lisp_Object arg, oldval;
2910 {
2911 if ((EQ (arg, Qleft) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_RIGHT (f))
2912 || (EQ (arg, Qright) && FRAME_HAS_VERTICAL_SCROLL_BARS_ON_LEFT (f))
2913 || (NILP (arg) && FRAME_HAS_VERTICAL_SCROLL_BARS (f))
2914 || (!NILP (arg) && ! FRAME_HAS_VERTICAL_SCROLL_BARS (f)))
2915 {
2916 FRAME_VERTICAL_SCROLL_BAR_TYPE (f) = NILP (arg) ?
2917 vertical_scroll_bar_none :
2918 /* Put scroll bars on the right by default, as is conventional
2919 on MS-Windows. */
2920 EQ (Qleft, arg)
2921 ? vertical_scroll_bar_left
2922 : vertical_scroll_bar_right;
2923
2924 /* We set this parameter before creating the window for the
2925 frame, so we can get the geometry right from the start.
2926 However, if the window hasn't been created yet, we shouldn't
2927 call x_set_window_size. */
2928 if (FRAME_W32_WINDOW (f))
2929 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2930 do_pending_window_change (0);
2931 }
2932 }
2933
2934 void
2935 x_set_scroll_bar_width (f, arg, oldval)
2936 struct frame *f;
2937 Lisp_Object arg, oldval;
2938 {
2939 int wid = FONT_WIDTH (f->output_data.w32->font);
2940
2941 if (NILP (arg))
2942 {
2943 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2944 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f) +
2945 wid - 1) / wid;
2946 if (FRAME_W32_WINDOW (f))
2947 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2948 do_pending_window_change (0);
2949 }
2950 else if (INTEGERP (arg) && XINT (arg) > 0
2951 && XFASTINT (arg) != FRAME_SCROLL_BAR_PIXEL_WIDTH (f))
2952 {
2953 FRAME_SCROLL_BAR_PIXEL_WIDTH (f) = XFASTINT (arg);
2954 FRAME_SCROLL_BAR_COLS (f) = (FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
2955 + wid-1) / wid;
2956 if (FRAME_W32_WINDOW (f))
2957 x_set_window_size (f, 0, FRAME_WIDTH (f), FRAME_HEIGHT (f));
2958 do_pending_window_change (0);
2959 }
2960 change_frame_size (f, 0, FRAME_WIDTH (f), 0, 0, 0);
2961 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.hpos = 0;
2962 XWINDOW (FRAME_SELECTED_WINDOW (f))->cursor.x = 0;
2963 }
2964 \f
2965 /* Subroutines of creating an frame. */
2966
2967 /* Make sure that Vx_resource_name is set to a reasonable value.
2968 Fix it up, or set it to `emacs' if it is too hopeless. */
2969
2970 static void
2971 validate_x_resource_name ()
2972 {
2973 int len = 0;
2974 /* Number of valid characters in the resource name. */
2975 int good_count = 0;
2976 /* Number of invalid characters in the resource name. */
2977 int bad_count = 0;
2978 Lisp_Object new;
2979 int i;
2980
2981 if (STRINGP (Vx_resource_name))
2982 {
2983 unsigned char *p = XSTRING (Vx_resource_name)->data;
2984 int i;
2985
2986 len = STRING_BYTES (XSTRING (Vx_resource_name));
2987
2988 /* Only letters, digits, - and _ are valid in resource names.
2989 Count the valid characters and count the invalid ones. */
2990 for (i = 0; i < len; i++)
2991 {
2992 int c = p[i];
2993 if (! ((c >= 'a' && c <= 'z')
2994 || (c >= 'A' && c <= 'Z')
2995 || (c >= '0' && c <= '9')
2996 || c == '-' || c == '_'))
2997 bad_count++;
2998 else
2999 good_count++;
3000 }
3001 }
3002 else
3003 /* Not a string => completely invalid. */
3004 bad_count = 5, good_count = 0;
3005
3006 /* If name is valid already, return. */
3007 if (bad_count == 0)
3008 return;
3009
3010 /* If name is entirely invalid, or nearly so, use `emacs'. */
3011 if (good_count == 0
3012 || (good_count == 1 && bad_count > 0))
3013 {
3014 Vx_resource_name = build_string ("emacs");
3015 return;
3016 }
3017
3018 /* Name is partly valid. Copy it and replace the invalid characters
3019 with underscores. */
3020
3021 Vx_resource_name = new = Fcopy_sequence (Vx_resource_name);
3022
3023 for (i = 0; i < len; i++)
3024 {
3025 int c = XSTRING (new)->data[i];
3026 if (! ((c >= 'a' && c <= 'z')
3027 || (c >= 'A' && c <= 'Z')
3028 || (c >= '0' && c <= '9')
3029 || c == '-' || c == '_'))
3030 XSTRING (new)->data[i] = '_';
3031 }
3032 }
3033
3034
3035 extern char *x_get_string_resource ();
3036
3037 DEFUN ("x-get-resource", Fx_get_resource, Sx_get_resource, 2, 4, 0,
3038 doc: /* Return the value of ATTRIBUTE, of class CLASS, from the X defaults database.
3039 This uses `INSTANCE.ATTRIBUTE' as the key and `Emacs.CLASS' as the
3040 class, where INSTANCE is the name under which Emacs was invoked, or
3041 the name specified by the `-name' or `-rn' command-line arguments.
3042
3043 The optional arguments COMPONENT and SUBCLASS add to the key and the
3044 class, respectively. You must specify both of them or neither.
3045 If you specify them, the key is `INSTANCE.COMPONENT.ATTRIBUTE'
3046 and the class is `Emacs.CLASS.SUBCLASS'. */)
3047 (attribute, class, component, subclass)
3048 Lisp_Object attribute, class, component, subclass;
3049 {
3050 register char *value;
3051 char *name_key;
3052 char *class_key;
3053
3054 CHECK_STRING (attribute);
3055 CHECK_STRING (class);
3056
3057 if (!NILP (component))
3058 CHECK_STRING (component);
3059 if (!NILP (subclass))
3060 CHECK_STRING (subclass);
3061 if (NILP (component) != NILP (subclass))
3062 error ("x-get-resource: must specify both COMPONENT and SUBCLASS or neither");
3063
3064 validate_x_resource_name ();
3065
3066 /* Allocate space for the components, the dots which separate them,
3067 and the final '\0'. Make them big enough for the worst case. */
3068 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vx_resource_name))
3069 + (STRINGP (component)
3070 ? STRING_BYTES (XSTRING (component)) : 0)
3071 + STRING_BYTES (XSTRING (attribute))
3072 + 3);
3073
3074 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3075 + STRING_BYTES (XSTRING (class))
3076 + (STRINGP (subclass)
3077 ? STRING_BYTES (XSTRING (subclass)) : 0)
3078 + 3);
3079
3080 /* Start with emacs.FRAMENAME for the name (the specific one)
3081 and with `Emacs' for the class key (the general one). */
3082 strcpy (name_key, XSTRING (Vx_resource_name)->data);
3083 strcpy (class_key, EMACS_CLASS);
3084
3085 strcat (class_key, ".");
3086 strcat (class_key, XSTRING (class)->data);
3087
3088 if (!NILP (component))
3089 {
3090 strcat (class_key, ".");
3091 strcat (class_key, XSTRING (subclass)->data);
3092
3093 strcat (name_key, ".");
3094 strcat (name_key, XSTRING (component)->data);
3095 }
3096
3097 strcat (name_key, ".");
3098 strcat (name_key, XSTRING (attribute)->data);
3099
3100 value = x_get_string_resource (Qnil,
3101 name_key, class_key);
3102
3103 if (value != (char *) 0)
3104 return build_string (value);
3105 else
3106 return Qnil;
3107 }
3108
3109 /* Used when C code wants a resource value. */
3110
3111 char *
3112 x_get_resource_string (attribute, class)
3113 char *attribute, *class;
3114 {
3115 char *name_key;
3116 char *class_key;
3117 struct frame *sf = SELECTED_FRAME ();
3118
3119 /* Allocate space for the components, the dots which separate them,
3120 and the final '\0'. */
3121 name_key = (char *) alloca (STRING_BYTES (XSTRING (Vinvocation_name))
3122 + strlen (attribute) + 2);
3123 class_key = (char *) alloca ((sizeof (EMACS_CLASS) - 1)
3124 + strlen (class) + 2);
3125
3126 sprintf (name_key, "%s.%s",
3127 XSTRING (Vinvocation_name)->data,
3128 attribute);
3129 sprintf (class_key, "%s.%s", EMACS_CLASS, class);
3130
3131 return x_get_string_resource (sf, name_key, class_key);
3132 }
3133
3134 /* Types we might convert a resource string into. */
3135 enum resource_types
3136 {
3137 RES_TYPE_NUMBER,
3138 RES_TYPE_FLOAT,
3139 RES_TYPE_BOOLEAN,
3140 RES_TYPE_STRING,
3141 RES_TYPE_SYMBOL
3142 };
3143
3144 /* Return the value of parameter PARAM.
3145
3146 First search ALIST, then Vdefault_frame_alist, then the X defaults
3147 database, using ATTRIBUTE as the attribute name and CLASS as its class.
3148
3149 Convert the resource to the type specified by desired_type.
3150
3151 If no default is specified, return Qunbound. If you call
3152 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
3153 and don't let it get stored in any Lisp-visible variables! */
3154
3155 static Lisp_Object
3156 w32_get_arg (alist, param, attribute, class, type)
3157 Lisp_Object alist, param;
3158 char *attribute;
3159 char *class;
3160 enum resource_types type;
3161 {
3162 register Lisp_Object tem;
3163
3164 tem = Fassq (param, alist);
3165 if (EQ (tem, Qnil))
3166 tem = Fassq (param, Vdefault_frame_alist);
3167 if (EQ (tem, Qnil))
3168 {
3169
3170 if (attribute)
3171 {
3172 tem = Fx_get_resource (build_string (attribute),
3173 build_string (class),
3174 Qnil, Qnil);
3175
3176 if (NILP (tem))
3177 return Qunbound;
3178
3179 switch (type)
3180 {
3181 case RES_TYPE_NUMBER:
3182 return make_number (atoi (XSTRING (tem)->data));
3183
3184 case RES_TYPE_FLOAT:
3185 return make_float (atof (XSTRING (tem)->data));
3186
3187 case RES_TYPE_BOOLEAN:
3188 tem = Fdowncase (tem);
3189 if (!strcmp (XSTRING (tem)->data, "on")
3190 || !strcmp (XSTRING (tem)->data, "true"))
3191 return Qt;
3192 else
3193 return Qnil;
3194
3195 case RES_TYPE_STRING:
3196 return tem;
3197
3198 case RES_TYPE_SYMBOL:
3199 /* As a special case, we map the values `true' and `on'
3200 to Qt, and `false' and `off' to Qnil. */
3201 {
3202 Lisp_Object lower;
3203 lower = Fdowncase (tem);
3204 if (!strcmp (XSTRING (lower)->data, "on")
3205 || !strcmp (XSTRING (lower)->data, "true"))
3206 return Qt;
3207 else if (!strcmp (XSTRING (lower)->data, "off")
3208 || !strcmp (XSTRING (lower)->data, "false"))
3209 return Qnil;
3210 else
3211 return Fintern (tem, Qnil);
3212 }
3213
3214 default:
3215 abort ();
3216 }
3217 }
3218 else
3219 return Qunbound;
3220 }
3221 return Fcdr (tem);
3222 }
3223
3224 /* Record in frame F the specified or default value according to ALIST
3225 of the parameter named PROP (a Lisp symbol).
3226 If no value is specified for PROP, look for an X default for XPROP
3227 on the frame named NAME.
3228 If that is not found either, use the value DEFLT. */
3229
3230 static Lisp_Object
3231 x_default_parameter (f, alist, prop, deflt, xprop, xclass, type)
3232 struct frame *f;
3233 Lisp_Object alist;
3234 Lisp_Object prop;
3235 Lisp_Object deflt;
3236 char *xprop;
3237 char *xclass;
3238 enum resource_types type;
3239 {
3240 Lisp_Object tem;
3241
3242 tem = w32_get_arg (alist, prop, xprop, xclass, type);
3243 if (EQ (tem, Qunbound))
3244 tem = deflt;
3245 x_set_frame_parameters (f, Fcons (Fcons (prop, tem), Qnil));
3246 return tem;
3247 }
3248 \f
3249 DEFUN ("x-parse-geometry", Fx_parse_geometry, Sx_parse_geometry, 1, 1, 0,
3250 doc: /* Parse an X-style geometry string STRING.
3251 Returns an alist of the form ((top . TOP), (left . LEFT) ... ).
3252 The properties returned may include `top', `left', `height', and `width'.
3253 The value of `left' or `top' may be an integer,
3254 or a list (+ N) meaning N pixels relative to top/left corner,
3255 or a list (- N) meaning -N pixels relative to bottom/right corner. */)
3256 (string)
3257 Lisp_Object string;
3258 {
3259 int geometry, x, y;
3260 unsigned int width, height;
3261 Lisp_Object result;
3262
3263 CHECK_STRING (string);
3264
3265 geometry = XParseGeometry ((char *) XSTRING (string)->data,
3266 &x, &y, &width, &height);
3267
3268 result = Qnil;
3269 if (geometry & XValue)
3270 {
3271 Lisp_Object element;
3272
3273 if (x >= 0 && (geometry & XNegative))
3274 element = Fcons (Qleft, Fcons (Qminus, Fcons (make_number (-x), Qnil)));
3275 else if (x < 0 && ! (geometry & XNegative))
3276 element = Fcons (Qleft, Fcons (Qplus, Fcons (make_number (x), Qnil)));
3277 else
3278 element = Fcons (Qleft, make_number (x));
3279 result = Fcons (element, result);
3280 }
3281
3282 if (geometry & YValue)
3283 {
3284 Lisp_Object element;
3285
3286 if (y >= 0 && (geometry & YNegative))
3287 element = Fcons (Qtop, Fcons (Qminus, Fcons (make_number (-y), Qnil)));
3288 else if (y < 0 && ! (geometry & YNegative))
3289 element = Fcons (Qtop, Fcons (Qplus, Fcons (make_number (y), Qnil)));
3290 else
3291 element = Fcons (Qtop, make_number (y));
3292 result = Fcons (element, result);
3293 }
3294
3295 if (geometry & WidthValue)
3296 result = Fcons (Fcons (Qwidth, make_number (width)), result);
3297 if (geometry & HeightValue)
3298 result = Fcons (Fcons (Qheight, make_number (height)), result);
3299
3300 return result;
3301 }
3302
3303 /* Calculate the desired size and position of this window,
3304 and return the flags saying which aspects were specified.
3305
3306 This function does not make the coordinates positive. */
3307
3308 #define DEFAULT_ROWS 40
3309 #define DEFAULT_COLS 80
3310
3311 static int
3312 x_figure_window_size (f, parms)
3313 struct frame *f;
3314 Lisp_Object parms;
3315 {
3316 register Lisp_Object tem0, tem1, tem2;
3317 long window_prompting = 0;
3318
3319 /* Default values if we fall through.
3320 Actually, if that happens we should get
3321 window manager prompting. */
3322 SET_FRAME_WIDTH (f, DEFAULT_COLS);
3323 f->height = DEFAULT_ROWS;
3324 /* Window managers expect that if program-specified
3325 positions are not (0,0), they're intentional, not defaults. */
3326 f->output_data.w32->top_pos = 0;
3327 f->output_data.w32->left_pos = 0;
3328
3329 /* Ensure that old new_width and new_height will not override the
3330 values set here. */
3331 FRAME_NEW_WIDTH (f) = 0;
3332 FRAME_NEW_HEIGHT (f) = 0;
3333
3334 tem0 = w32_get_arg (parms, Qheight, 0, 0, RES_TYPE_NUMBER);
3335 tem1 = w32_get_arg (parms, Qwidth, 0, 0, RES_TYPE_NUMBER);
3336 tem2 = w32_get_arg (parms, Quser_size, 0, 0, RES_TYPE_NUMBER);
3337 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3338 {
3339 if (!EQ (tem0, Qunbound))
3340 {
3341 CHECK_NUMBER (tem0);
3342 f->height = XINT (tem0);
3343 }
3344 if (!EQ (tem1, Qunbound))
3345 {
3346 CHECK_NUMBER (tem1);
3347 SET_FRAME_WIDTH (f, XINT (tem1));
3348 }
3349 if (!NILP (tem2) && !EQ (tem2, Qunbound))
3350 window_prompting |= USSize;
3351 else
3352 window_prompting |= PSize;
3353 }
3354
3355 f->output_data.w32->vertical_scroll_bar_extra
3356 = (!FRAME_HAS_VERTICAL_SCROLL_BARS (f)
3357 ? 0
3358 : FRAME_SCROLL_BAR_PIXEL_WIDTH (f) > 0
3359 ? FRAME_SCROLL_BAR_PIXEL_WIDTH (f)
3360 : (FRAME_SCROLL_BAR_COLS (f) * FONT_WIDTH (f->output_data.w32->font)));
3361
3362 x_compute_fringe_widths (f, 0);
3363
3364 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3365 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3366
3367 tem0 = w32_get_arg (parms, Qtop, 0, 0, RES_TYPE_NUMBER);
3368 tem1 = w32_get_arg (parms, Qleft, 0, 0, RES_TYPE_NUMBER);
3369 tem2 = w32_get_arg (parms, Quser_position, 0, 0, RES_TYPE_NUMBER);
3370 if (! EQ (tem0, Qunbound) || ! EQ (tem1, Qunbound))
3371 {
3372 if (EQ (tem0, Qminus))
3373 {
3374 f->output_data.w32->top_pos = 0;
3375 window_prompting |= YNegative;
3376 }
3377 else if (CONSP (tem0) && EQ (XCAR (tem0), Qminus)
3378 && CONSP (XCDR (tem0))
3379 && INTEGERP (XCAR (XCDR (tem0))))
3380 {
3381 f->output_data.w32->top_pos = - XINT (XCAR (XCDR (tem0)));
3382 window_prompting |= YNegative;
3383 }
3384 else if (CONSP (tem0) && EQ (XCAR (tem0), Qplus)
3385 && CONSP (XCDR (tem0))
3386 && INTEGERP (XCAR (XCDR (tem0))))
3387 {
3388 f->output_data.w32->top_pos = XINT (XCAR (XCDR (tem0)));
3389 }
3390 else if (EQ (tem0, Qunbound))
3391 f->output_data.w32->top_pos = 0;
3392 else
3393 {
3394 CHECK_NUMBER (tem0);
3395 f->output_data.w32->top_pos = XINT (tem0);
3396 if (f->output_data.w32->top_pos < 0)
3397 window_prompting |= YNegative;
3398 }
3399
3400 if (EQ (tem1, Qminus))
3401 {
3402 f->output_data.w32->left_pos = 0;
3403 window_prompting |= XNegative;
3404 }
3405 else if (CONSP (tem1) && EQ (XCAR (tem1), Qminus)
3406 && CONSP (XCDR (tem1))
3407 && INTEGERP (XCAR (XCDR (tem1))))
3408 {
3409 f->output_data.w32->left_pos = - XINT (XCAR (XCDR (tem1)));
3410 window_prompting |= XNegative;
3411 }
3412 else if (CONSP (tem1) && EQ (XCAR (tem1), Qplus)
3413 && CONSP (XCDR (tem1))
3414 && INTEGERP (XCAR (XCDR (tem1))))
3415 {
3416 f->output_data.w32->left_pos = XINT (XCAR (XCDR (tem1)));
3417 }
3418 else if (EQ (tem1, Qunbound))
3419 f->output_data.w32->left_pos = 0;
3420 else
3421 {
3422 CHECK_NUMBER (tem1);
3423 f->output_data.w32->left_pos = XINT (tem1);
3424 if (f->output_data.w32->left_pos < 0)
3425 window_prompting |= XNegative;
3426 }
3427
3428 if (!NILP (tem2) && ! EQ (tem2, Qunbound))
3429 window_prompting |= USPosition;
3430 else
3431 window_prompting |= PPosition;
3432 }
3433
3434 if (f->output_data.w32->want_fullscreen != FULLSCREEN_NONE)
3435 {
3436 int left, top;
3437 int width, height;
3438
3439 /* It takes both for some WM:s to place it where we want */
3440 window_prompting = USPosition | PPosition;
3441 x_fullscreen_adjust (f, &width, &height, &top, &left);
3442 f->width = width;
3443 f->height = height;
3444 f->output_data.w32->pixel_width = CHAR_TO_PIXEL_WIDTH (f, f->width);
3445 f->output_data.w32->pixel_height = CHAR_TO_PIXEL_HEIGHT (f, f->height);
3446 f->output_data.w32->left_pos = left;
3447 f->output_data.w32->top_pos = top;
3448 }
3449
3450 return window_prompting;
3451 }
3452
3453 \f
3454
3455 extern LRESULT CALLBACK w32_wnd_proc ();
3456
3457 BOOL
3458 w32_init_class (hinst)
3459 HINSTANCE hinst;
3460 {
3461 WNDCLASS wc;
3462
3463 wc.style = CS_HREDRAW | CS_VREDRAW;
3464 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
3465 wc.cbClsExtra = 0;
3466 wc.cbWndExtra = WND_EXTRA_BYTES;
3467 wc.hInstance = hinst;
3468 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
3469 wc.hCursor = LoadCursor (NULL, IDC_ARROW);
3470 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
3471 wc.lpszMenuName = NULL;
3472 wc.lpszClassName = EMACS_CLASS;
3473
3474 return (RegisterClass (&wc));
3475 }
3476
3477 HWND
3478 w32_createscrollbar (f, bar)
3479 struct frame *f;
3480 struct scroll_bar * bar;
3481 {
3482 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
3483 /* Position and size of scroll bar. */
3484 XINT(bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
3485 XINT(bar->top),
3486 XINT(bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
3487 XINT(bar->height),
3488 FRAME_W32_WINDOW (f),
3489 NULL,
3490 hinst,
3491 NULL));
3492 }
3493
3494 void
3495 w32_createwindow (f)
3496 struct frame *f;
3497 {
3498 HWND hwnd;
3499 RECT rect;
3500
3501 rect.left = rect.top = 0;
3502 rect.right = PIXEL_WIDTH (f);
3503 rect.bottom = PIXEL_HEIGHT (f);
3504
3505 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3506 FRAME_EXTERNAL_MENU_BAR (f));
3507
3508 /* Do first time app init */
3509
3510 if (!hprevinst)
3511 {
3512 w32_init_class (hinst);
3513 }
3514
3515 FRAME_W32_WINDOW (f) = hwnd
3516 = CreateWindow (EMACS_CLASS,
3517 f->namebuf,
3518 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
3519 f->output_data.w32->left_pos,
3520 f->output_data.w32->top_pos,
3521 rect.right - rect.left,
3522 rect.bottom - rect.top,
3523 NULL,
3524 NULL,
3525 hinst,
3526 NULL);
3527
3528 if (hwnd)
3529 {
3530 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
3531 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
3532 SetWindowLong (hwnd, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
3533 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->output_data.w32->vertical_scroll_bar_extra);
3534 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3535
3536 /* Enable drag-n-drop. */
3537 DragAcceptFiles (hwnd, TRUE);
3538
3539 /* Do this to discard the default setting specified by our parent. */
3540 ShowWindow (hwnd, SW_HIDE);
3541 }
3542 }
3543
3544 void
3545 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
3546 W32Msg * wmsg;
3547 HWND hwnd;
3548 UINT msg;
3549 WPARAM wParam;
3550 LPARAM lParam;
3551 {
3552 wmsg->msg.hwnd = hwnd;
3553 wmsg->msg.message = msg;
3554 wmsg->msg.wParam = wParam;
3555 wmsg->msg.lParam = lParam;
3556 wmsg->msg.time = GetMessageTime ();
3557
3558 post_msg (wmsg);
3559 }
3560
3561 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
3562 between left and right keys as advertised. We test for this
3563 support dynamically, and set a flag when the support is absent. If
3564 absent, we keep track of the left and right control and alt keys
3565 ourselves. This is particularly necessary on keyboards that rely
3566 upon the AltGr key, which is represented as having the left control
3567 and right alt keys pressed. For these keyboards, we need to know
3568 when the left alt key has been pressed in addition to the AltGr key
3569 so that we can properly support M-AltGr-key sequences (such as M-@
3570 on Swedish keyboards). */
3571
3572 #define EMACS_LCONTROL 0
3573 #define EMACS_RCONTROL 1
3574 #define EMACS_LMENU 2
3575 #define EMACS_RMENU 3
3576
3577 static int modifiers[4];
3578 static int modifiers_recorded;
3579 static int modifier_key_support_tested;
3580
3581 static void
3582 test_modifier_support (unsigned int wparam)
3583 {
3584 unsigned int l, r;
3585
3586 if (wparam != VK_CONTROL && wparam != VK_MENU)
3587 return;
3588 if (wparam == VK_CONTROL)
3589 {
3590 l = VK_LCONTROL;
3591 r = VK_RCONTROL;
3592 }
3593 else
3594 {
3595 l = VK_LMENU;
3596 r = VK_RMENU;
3597 }
3598 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
3599 modifiers_recorded = 1;
3600 else
3601 modifiers_recorded = 0;
3602 modifier_key_support_tested = 1;
3603 }
3604
3605 static void
3606 record_keydown (unsigned int wparam, unsigned int lparam)
3607 {
3608 int i;
3609
3610 if (!modifier_key_support_tested)
3611 test_modifier_support (wparam);
3612
3613 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3614 return;
3615
3616 if (wparam == VK_CONTROL)
3617 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3618 else
3619 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3620
3621 modifiers[i] = 1;
3622 }
3623
3624 static void
3625 record_keyup (unsigned int wparam, unsigned int lparam)
3626 {
3627 int i;
3628
3629 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
3630 return;
3631
3632 if (wparam == VK_CONTROL)
3633 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
3634 else
3635 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
3636
3637 modifiers[i] = 0;
3638 }
3639
3640 /* Emacs can lose focus while a modifier key has been pressed. When
3641 it regains focus, be conservative and clear all modifiers since
3642 we cannot reconstruct the left and right modifier state. */
3643 static void
3644 reset_modifiers ()
3645 {
3646 SHORT ctrl, alt;
3647
3648 if (GetFocus () == NULL)
3649 /* Emacs doesn't have keyboard focus. Do nothing. */
3650 return;
3651
3652 ctrl = GetAsyncKeyState (VK_CONTROL);
3653 alt = GetAsyncKeyState (VK_MENU);
3654
3655 if (!(ctrl & 0x08000))
3656 /* Clear any recorded control modifier state. */
3657 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3658
3659 if (!(alt & 0x08000))
3660 /* Clear any recorded alt modifier state. */
3661 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3662
3663 /* Update the state of all modifier keys, because modifiers used in
3664 hot-key combinations can get stuck on if Emacs loses focus as a
3665 result of a hot-key being pressed. */
3666 {
3667 BYTE keystate[256];
3668
3669 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
3670
3671 GetKeyboardState (keystate);
3672 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
3673 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
3674 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
3675 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
3676 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
3677 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
3678 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
3679 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
3680 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
3681 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
3682 SetKeyboardState (keystate);
3683 }
3684 }
3685
3686 /* Synchronize modifier state with what is reported with the current
3687 keystroke. Even if we cannot distinguish between left and right
3688 modifier keys, we know that, if no modifiers are set, then neither
3689 the left or right modifier should be set. */
3690 static void
3691 sync_modifiers ()
3692 {
3693 if (!modifiers_recorded)
3694 return;
3695
3696 if (!(GetKeyState (VK_CONTROL) & 0x8000))
3697 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
3698
3699 if (!(GetKeyState (VK_MENU) & 0x8000))
3700 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
3701 }
3702
3703 static int
3704 modifier_set (int vkey)
3705 {
3706 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
3707 return (GetKeyState (vkey) & 0x1);
3708 if (!modifiers_recorded)
3709 return (GetKeyState (vkey) & 0x8000);
3710
3711 switch (vkey)
3712 {
3713 case VK_LCONTROL:
3714 return modifiers[EMACS_LCONTROL];
3715 case VK_RCONTROL:
3716 return modifiers[EMACS_RCONTROL];
3717 case VK_LMENU:
3718 return modifiers[EMACS_LMENU];
3719 case VK_RMENU:
3720 return modifiers[EMACS_RMENU];
3721 }
3722 return (GetKeyState (vkey) & 0x8000);
3723 }
3724
3725 /* Convert between the modifier bits W32 uses and the modifier bits
3726 Emacs uses. */
3727
3728 unsigned int
3729 w32_key_to_modifier (int key)
3730 {
3731 Lisp_Object key_mapping;
3732
3733 switch (key)
3734 {
3735 case VK_LWIN:
3736 key_mapping = Vw32_lwindow_modifier;
3737 break;
3738 case VK_RWIN:
3739 key_mapping = Vw32_rwindow_modifier;
3740 break;
3741 case VK_APPS:
3742 key_mapping = Vw32_apps_modifier;
3743 break;
3744 case VK_SCROLL:
3745 key_mapping = Vw32_scroll_lock_modifier;
3746 break;
3747 default:
3748 key_mapping = Qnil;
3749 }
3750
3751 /* NB. This code runs in the input thread, asychronously to the lisp
3752 thread, so we must be careful to ensure access to lisp data is
3753 thread-safe. The following code is safe because the modifier
3754 variable values are updated atomically from lisp and symbols are
3755 not relocated by GC. Also, we don't have to worry about seeing GC
3756 markbits here. */
3757 if (EQ (key_mapping, Qhyper))
3758 return hyper_modifier;
3759 if (EQ (key_mapping, Qsuper))
3760 return super_modifier;
3761 if (EQ (key_mapping, Qmeta))
3762 return meta_modifier;
3763 if (EQ (key_mapping, Qalt))
3764 return alt_modifier;
3765 if (EQ (key_mapping, Qctrl))
3766 return ctrl_modifier;
3767 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
3768 return ctrl_modifier;
3769 if (EQ (key_mapping, Qshift))
3770 return shift_modifier;
3771
3772 /* Don't generate any modifier if not explicitly requested. */
3773 return 0;
3774 }
3775
3776 unsigned int
3777 w32_get_modifiers ()
3778 {
3779 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
3780 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
3781 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
3782 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
3783 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
3784 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
3785 (modifier_set (VK_MENU) ?
3786 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
3787 }
3788
3789 /* We map the VK_* modifiers into console modifier constants
3790 so that we can use the same routines to handle both console
3791 and window input. */
3792
3793 static int
3794 construct_console_modifiers ()
3795 {
3796 int mods;
3797
3798 mods = 0;
3799 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
3800 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
3801 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
3802 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
3803 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
3804 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
3805 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
3806 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
3807 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
3808 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
3809 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
3810
3811 return mods;
3812 }
3813
3814 static int
3815 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
3816 {
3817 int mods;
3818
3819 /* Convert to emacs modifiers. */
3820 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
3821
3822 return mods;
3823 }
3824
3825 unsigned int
3826 map_keypad_keys (unsigned int virt_key, unsigned int extended)
3827 {
3828 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
3829 return virt_key;
3830
3831 if (virt_key == VK_RETURN)
3832 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
3833
3834 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
3835 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
3836
3837 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
3838 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
3839
3840 if (virt_key == VK_CLEAR)
3841 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
3842
3843 return virt_key;
3844 }
3845
3846 /* List of special key combinations which w32 would normally capture,
3847 but emacs should grab instead. Not directly visible to lisp, to
3848 simplify synchronization. Each item is an integer encoding a virtual
3849 key code and modifier combination to capture. */
3850 Lisp_Object w32_grabbed_keys;
3851
3852 #define HOTKEY(vk,mods) make_number (((vk) & 255) | ((mods) << 8))
3853 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
3854 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
3855 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
3856
3857 /* Register hot-keys for reserved key combinations when Emacs has
3858 keyboard focus, since this is the only way Emacs can receive key
3859 combinations like Alt-Tab which are used by the system. */
3860
3861 static void
3862 register_hot_keys (hwnd)
3863 HWND hwnd;
3864 {
3865 Lisp_Object keylist;
3866
3867 /* Use GC_CONSP, since we are called asynchronously. */
3868 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3869 {
3870 Lisp_Object key = XCAR (keylist);
3871
3872 /* Deleted entries get set to nil. */
3873 if (!INTEGERP (key))
3874 continue;
3875
3876 RegisterHotKey (hwnd, HOTKEY_ID (key),
3877 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
3878 }
3879 }
3880
3881 static void
3882 unregister_hot_keys (hwnd)
3883 HWND hwnd;
3884 {
3885 Lisp_Object keylist;
3886
3887 /* Use GC_CONSP, since we are called asynchronously. */
3888 for (keylist = w32_grabbed_keys; GC_CONSP (keylist); keylist = XCDR (keylist))
3889 {
3890 Lisp_Object key = XCAR (keylist);
3891
3892 if (!INTEGERP (key))
3893 continue;
3894
3895 UnregisterHotKey (hwnd, HOTKEY_ID (key));
3896 }
3897 }
3898
3899 /* Main message dispatch loop. */
3900
3901 static void
3902 w32_msg_pump (deferred_msg * msg_buf)
3903 {
3904 MSG msg;
3905 int result;
3906 HWND focus_window;
3907
3908 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
3909
3910 while (GetMessage (&msg, NULL, 0, 0))
3911 {
3912 if (msg.hwnd == NULL)
3913 {
3914 switch (msg.message)
3915 {
3916 case WM_NULL:
3917 /* Produced by complete_deferred_msg; just ignore. */
3918 break;
3919 case WM_EMACS_CREATEWINDOW:
3920 w32_createwindow ((struct frame *) msg.wParam);
3921 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3922 abort ();
3923 break;
3924 case WM_EMACS_SETLOCALE:
3925 SetThreadLocale (msg.wParam);
3926 /* Reply is not expected. */
3927 break;
3928 case WM_EMACS_SETKEYBOARDLAYOUT:
3929 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
3930 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3931 result, 0))
3932 abort ();
3933 break;
3934 case WM_EMACS_REGISTER_HOT_KEY:
3935 focus_window = GetFocus ();
3936 if (focus_window != NULL)
3937 RegisterHotKey (focus_window,
3938 HOTKEY_ID (msg.wParam),
3939 HOTKEY_MODIFIERS (msg.wParam),
3940 HOTKEY_VK_CODE (msg.wParam));
3941 /* Reply is not expected. */
3942 break;
3943 case WM_EMACS_UNREGISTER_HOT_KEY:
3944 focus_window = GetFocus ();
3945 if (focus_window != NULL)
3946 UnregisterHotKey (focus_window, HOTKEY_ID (msg.wParam));
3947 /* Mark item as erased. NB: this code must be
3948 thread-safe. The next line is okay because the cons
3949 cell is never made into garbage and is not relocated by
3950 GC. */
3951 XSETCAR ((Lisp_Object) msg.lParam, Qnil);
3952 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
3953 abort ();
3954 break;
3955 case WM_EMACS_TOGGLE_LOCK_KEY:
3956 {
3957 int vk_code = (int) msg.wParam;
3958 int cur_state = (GetKeyState (vk_code) & 1);
3959 Lisp_Object new_state = (Lisp_Object) msg.lParam;
3960
3961 /* NB: This code must be thread-safe. It is safe to
3962 call NILP because symbols are not relocated by GC,
3963 and pointer here is not touched by GC (so the markbit
3964 can't be set). Numbers are safe because they are
3965 immediate values. */
3966 if (NILP (new_state)
3967 || (NUMBERP (new_state)
3968 && ((XUINT (new_state)) & 1) != cur_state))
3969 {
3970 one_w32_display_info.faked_key = vk_code;
3971
3972 keybd_event ((BYTE) vk_code,
3973 (BYTE) MapVirtualKey (vk_code, 0),
3974 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3975 keybd_event ((BYTE) vk_code,
3976 (BYTE) MapVirtualKey (vk_code, 0),
3977 KEYEVENTF_EXTENDEDKEY | 0, 0);
3978 keybd_event ((BYTE) vk_code,
3979 (BYTE) MapVirtualKey (vk_code, 0),
3980 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3981 cur_state = !cur_state;
3982 }
3983 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
3984 cur_state, 0))
3985 abort ();
3986 }
3987 break;
3988 default:
3989 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
3990 }
3991 }
3992 else
3993 {
3994 DispatchMessage (&msg);
3995 }
3996
3997 /* Exit nested loop when our deferred message has completed. */
3998 if (msg_buf->completed)
3999 break;
4000 }
4001 }
4002
4003 deferred_msg * deferred_msg_head;
4004
4005 static deferred_msg *
4006 find_deferred_msg (HWND hwnd, UINT msg)
4007 {
4008 deferred_msg * item;
4009
4010 /* Don't actually need synchronization for read access, since
4011 modification of single pointer is always atomic. */
4012 /* enter_crit (); */
4013
4014 for (item = deferred_msg_head; item != NULL; item = item->next)
4015 if (item->w32msg.msg.hwnd == hwnd
4016 && item->w32msg.msg.message == msg)
4017 break;
4018
4019 /* leave_crit (); */
4020
4021 return item;
4022 }
4023
4024 static LRESULT
4025 send_deferred_msg (deferred_msg * msg_buf,
4026 HWND hwnd,
4027 UINT msg,
4028 WPARAM wParam,
4029 LPARAM lParam)
4030 {
4031 /* Only input thread can send deferred messages. */
4032 if (GetCurrentThreadId () != dwWindowsThreadId)
4033 abort ();
4034
4035 /* It is an error to send a message that is already deferred. */
4036 if (find_deferred_msg (hwnd, msg) != NULL)
4037 abort ();
4038
4039 /* Enforced synchronization is not needed because this is the only
4040 function that alters deferred_msg_head, and the following critical
4041 section is guaranteed to only be serially reentered (since only the
4042 input thread can call us). */
4043
4044 /* enter_crit (); */
4045
4046 msg_buf->completed = 0;
4047 msg_buf->next = deferred_msg_head;
4048 deferred_msg_head = msg_buf;
4049 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
4050
4051 /* leave_crit (); */
4052
4053 /* Start a new nested message loop to process other messages until
4054 this one is completed. */
4055 w32_msg_pump (msg_buf);
4056
4057 deferred_msg_head = msg_buf->next;
4058
4059 return msg_buf->result;
4060 }
4061
4062 void
4063 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
4064 {
4065 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
4066
4067 if (msg_buf == NULL)
4068 /* Message may have been cancelled, so don't abort(). */
4069 return;
4070
4071 msg_buf->result = result;
4072 msg_buf->completed = 1;
4073
4074 /* Ensure input thread is woken so it notices the completion. */
4075 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4076 }
4077
4078 void
4079 cancel_all_deferred_msgs ()
4080 {
4081 deferred_msg * item;
4082
4083 /* Don't actually need synchronization for read access, since
4084 modification of single pointer is always atomic. */
4085 /* enter_crit (); */
4086
4087 for (item = deferred_msg_head; item != NULL; item = item->next)
4088 {
4089 item->result = 0;
4090 item->completed = 1;
4091 }
4092
4093 /* leave_crit (); */
4094
4095 /* Ensure input thread is woken so it notices the completion. */
4096 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
4097 }
4098
4099 DWORD
4100 w32_msg_worker (dw)
4101 DWORD dw;
4102 {
4103 MSG msg;
4104 deferred_msg dummy_buf;
4105
4106 /* Ensure our message queue is created */
4107
4108 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
4109
4110 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
4111 abort ();
4112
4113 memset (&dummy_buf, 0, sizeof (dummy_buf));
4114 dummy_buf.w32msg.msg.hwnd = NULL;
4115 dummy_buf.w32msg.msg.message = WM_NULL;
4116
4117 /* This is the inital message loop which should only exit when the
4118 application quits. */
4119 w32_msg_pump (&dummy_buf);
4120
4121 return 0;
4122 }
4123
4124 static void
4125 post_character_message (hwnd, msg, wParam, lParam, modifiers)
4126 HWND hwnd;
4127 UINT msg;
4128 WPARAM wParam;
4129 LPARAM lParam;
4130 DWORD modifiers;
4131
4132 {
4133 W32Msg wmsg;
4134
4135 wmsg.dwModifiers = modifiers;
4136
4137 /* Detect quit_char and set quit-flag directly. Note that we
4138 still need to post a message to ensure the main thread will be
4139 woken up if blocked in sys_select(), but we do NOT want to post
4140 the quit_char message itself (because it will usually be as if
4141 the user had typed quit_char twice). Instead, we post a dummy
4142 message that has no particular effect. */
4143 {
4144 int c = wParam;
4145 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
4146 c = make_ctrl_char (c) & 0377;
4147 if (c == quit_char
4148 || (wmsg.dwModifiers == 0 &&
4149 XFASTINT (Vw32_quit_key) && wParam == XFASTINT (Vw32_quit_key)))
4150 {
4151 Vquit_flag = Qt;
4152
4153 /* The choice of message is somewhat arbitrary, as long as
4154 the main thread handler just ignores it. */
4155 msg = WM_NULL;
4156
4157 /* Interrupt any blocking system calls. */
4158 signal_quit ();
4159
4160 /* As a safety precaution, forcibly complete any deferred
4161 messages. This is a kludge, but I don't see any particularly
4162 clean way to handle the situation where a deferred message is
4163 "dropped" in the lisp thread, and will thus never be
4164 completed, eg. by the user trying to activate the menubar
4165 when the lisp thread is busy, and then typing C-g when the
4166 menubar doesn't open promptly (with the result that the
4167 menubar never responds at all because the deferred
4168 WM_INITMENU message is never completed). Another problem
4169 situation is when the lisp thread calls SendMessage (to send
4170 a window manager command) when a message has been deferred;
4171 the lisp thread gets blocked indefinitely waiting for the
4172 deferred message to be completed, which itself is waiting for
4173 the lisp thread to respond.
4174
4175 Note that we don't want to block the input thread waiting for
4176 a reponse from the lisp thread (although that would at least
4177 solve the deadlock problem above), because we want to be able
4178 to receive C-g to interrupt the lisp thread. */
4179 cancel_all_deferred_msgs ();
4180 }
4181 }
4182
4183 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4184 }
4185
4186 /* Main window procedure */
4187
4188 LRESULT CALLBACK
4189 w32_wnd_proc (hwnd, msg, wParam, lParam)
4190 HWND hwnd;
4191 UINT msg;
4192 WPARAM wParam;
4193 LPARAM lParam;
4194 {
4195 struct frame *f;
4196 struct w32_display_info *dpyinfo = &one_w32_display_info;
4197 W32Msg wmsg;
4198 int windows_translate;
4199 int key;
4200
4201 /* Note that it is okay to call x_window_to_frame, even though we are
4202 not running in the main lisp thread, because frame deletion
4203 requires the lisp thread to synchronize with this thread. Thus, if
4204 a frame struct is returned, it can be used without concern that the
4205 lisp thread might make it disappear while we are using it.
4206
4207 NB. Walking the frame list in this thread is safe (as long as
4208 writes of Lisp_Object slots are atomic, which they are on Windows).
4209 Although delete-frame can destructively modify the frame list while
4210 we are walking it, a garbage collection cannot occur until after
4211 delete-frame has synchronized with this thread.
4212
4213 It is also safe to use functions that make GDI calls, such as
4214 w32_clear_rect, because these functions must obtain a DC handle
4215 from the frame struct using get_frame_dc which is thread-aware. */
4216
4217 switch (msg)
4218 {
4219 case WM_ERASEBKGND:
4220 f = x_window_to_frame (dpyinfo, hwnd);
4221 if (f)
4222 {
4223 HDC hdc = get_frame_dc (f);
4224 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
4225 w32_clear_rect (f, hdc, &wmsg.rect);
4226 release_frame_dc (f, hdc);
4227
4228 #if defined (W32_DEBUG_DISPLAY)
4229 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
4230 f,
4231 wmsg.rect.left, wmsg.rect.top,
4232 wmsg.rect.right, wmsg.rect.bottom));
4233 #endif /* W32_DEBUG_DISPLAY */
4234 }
4235 return 1;
4236 case WM_PALETTECHANGED:
4237 /* ignore our own changes */
4238 if ((HWND)wParam != hwnd)
4239 {
4240 f = x_window_to_frame (dpyinfo, hwnd);
4241 if (f)
4242 /* get_frame_dc will realize our palette and force all
4243 frames to be redrawn if needed. */
4244 release_frame_dc (f, get_frame_dc (f));
4245 }
4246 return 0;
4247 case WM_PAINT:
4248 {
4249 PAINTSTRUCT paintStruct;
4250 RECT update_rect;
4251 bzero (&update_rect, sizeof (update_rect));
4252
4253 f = x_window_to_frame (dpyinfo, hwnd);
4254 if (f == 0)
4255 {
4256 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
4257 return 0;
4258 }
4259
4260 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
4261 fails. Apparently this can happen under some
4262 circumstances. */
4263 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
4264 {
4265 enter_crit ();
4266 BeginPaint (hwnd, &paintStruct);
4267
4268 /* The rectangles returned by GetUpdateRect and BeginPaint
4269 do not always match. Play it safe by assuming both areas
4270 are invalid. */
4271 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
4272
4273 #if defined (W32_DEBUG_DISPLAY)
4274 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
4275 f,
4276 wmsg.rect.left, wmsg.rect.top,
4277 wmsg.rect.right, wmsg.rect.bottom));
4278 DebPrint ((" [update region is %d,%d-%d,%d]\n",
4279 update_rect.left, update_rect.top,
4280 update_rect.right, update_rect.bottom));
4281 #endif
4282 EndPaint (hwnd, &paintStruct);
4283 leave_crit ();
4284
4285 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4286
4287 return 0;
4288 }
4289
4290 /* If GetUpdateRect returns 0 (meaning there is no update
4291 region), assume the whole window needs to be repainted. */
4292 GetClientRect(hwnd, &wmsg.rect);
4293 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4294 return 0;
4295 }
4296
4297 case WM_INPUTLANGCHANGE:
4298 /* Inform lisp thread of keyboard layout changes. */
4299 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4300
4301 /* Clear dead keys in the keyboard state; for simplicity only
4302 preserve modifier key states. */
4303 {
4304 int i;
4305 BYTE keystate[256];
4306
4307 GetKeyboardState (keystate);
4308 for (i = 0; i < 256; i++)
4309 if (1
4310 && i != VK_SHIFT
4311 && i != VK_LSHIFT
4312 && i != VK_RSHIFT
4313 && i != VK_CAPITAL
4314 && i != VK_NUMLOCK
4315 && i != VK_SCROLL
4316 && i != VK_CONTROL
4317 && i != VK_LCONTROL
4318 && i != VK_RCONTROL
4319 && i != VK_MENU
4320 && i != VK_LMENU
4321 && i != VK_RMENU
4322 && i != VK_LWIN
4323 && i != VK_RWIN)
4324 keystate[i] = 0;
4325 SetKeyboardState (keystate);
4326 }
4327 goto dflt;
4328
4329 case WM_HOTKEY:
4330 /* Synchronize hot keys with normal input. */
4331 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
4332 return (0);
4333
4334 case WM_KEYUP:
4335 case WM_SYSKEYUP:
4336 record_keyup (wParam, lParam);
4337 goto dflt;
4338
4339 case WM_KEYDOWN:
4340 case WM_SYSKEYDOWN:
4341 /* Ignore keystrokes we fake ourself; see below. */
4342 if (dpyinfo->faked_key == wParam)
4343 {
4344 dpyinfo->faked_key = 0;
4345 /* Make sure TranslateMessage sees them though (as long as
4346 they don't produce WM_CHAR messages). This ensures that
4347 indicator lights are toggled promptly on Windows 9x, for
4348 example. */
4349 if (lispy_function_keys[wParam] != 0)
4350 {
4351 windows_translate = 1;
4352 goto translate;
4353 }
4354 return 0;
4355 }
4356
4357 /* Synchronize modifiers with current keystroke. */
4358 sync_modifiers ();
4359 record_keydown (wParam, lParam);
4360 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
4361
4362 windows_translate = 0;
4363
4364 switch (wParam)
4365 {
4366 case VK_LWIN:
4367 if (NILP (Vw32_pass_lwindow_to_system))
4368 {
4369 /* Prevent system from acting on keyup (which opens the
4370 Start menu if no other key was pressed) by simulating a
4371 press of Space which we will ignore. */
4372 if (GetAsyncKeyState (wParam) & 1)
4373 {
4374 if (NUMBERP (Vw32_phantom_key_code))
4375 key = XUINT (Vw32_phantom_key_code) & 255;
4376 else
4377 key = VK_SPACE;
4378 dpyinfo->faked_key = key;
4379 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4380 }
4381 }
4382 if (!NILP (Vw32_lwindow_modifier))
4383 return 0;
4384 break;
4385 case VK_RWIN:
4386 if (NILP (Vw32_pass_rwindow_to_system))
4387 {
4388 if (GetAsyncKeyState (wParam) & 1)
4389 {
4390 if (NUMBERP (Vw32_phantom_key_code))
4391 key = XUINT (Vw32_phantom_key_code) & 255;
4392 else
4393 key = VK_SPACE;
4394 dpyinfo->faked_key = key;
4395 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
4396 }
4397 }
4398 if (!NILP (Vw32_rwindow_modifier))
4399 return 0;
4400 break;
4401 case VK_APPS:
4402 if (!NILP (Vw32_apps_modifier))
4403 return 0;
4404 break;
4405 case VK_MENU:
4406 if (NILP (Vw32_pass_alt_to_system))
4407 /* Prevent DefWindowProc from activating the menu bar if an
4408 Alt key is pressed and released by itself. */
4409 return 0;
4410 windows_translate = 1;
4411 break;
4412 case VK_CAPITAL:
4413 /* Decide whether to treat as modifier or function key. */
4414 if (NILP (Vw32_enable_caps_lock))
4415 goto disable_lock_key;
4416 windows_translate = 1;
4417 break;
4418 case VK_NUMLOCK:
4419 /* Decide whether to treat as modifier or function key. */
4420 if (NILP (Vw32_enable_num_lock))
4421 goto disable_lock_key;
4422 windows_translate = 1;
4423 break;
4424 case VK_SCROLL:
4425 /* Decide whether to treat as modifier or function key. */
4426 if (NILP (Vw32_scroll_lock_modifier))
4427 goto disable_lock_key;
4428 windows_translate = 1;
4429 break;
4430 disable_lock_key:
4431 /* Ensure the appropriate lock key state (and indicator light)
4432 remains in the same state. We do this by faking another
4433 press of the relevant key. Apparently, this really is the
4434 only way to toggle the state of the indicator lights. */
4435 dpyinfo->faked_key = wParam;
4436 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4437 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4438 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4439 KEYEVENTF_EXTENDEDKEY | 0, 0);
4440 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
4441 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
4442 /* Ensure indicator lights are updated promptly on Windows 9x
4443 (TranslateMessage apparently does this), after forwarding
4444 input event. */
4445 post_character_message (hwnd, msg, wParam, lParam,
4446 w32_get_key_modifiers (wParam, lParam));
4447 windows_translate = 1;
4448 break;
4449 case VK_CONTROL:
4450 case VK_SHIFT:
4451 case VK_PROCESSKEY: /* Generated by IME. */
4452 windows_translate = 1;
4453 break;
4454 case VK_CANCEL:
4455 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
4456 which is confusing for purposes of key binding; convert
4457 VK_CANCEL events into VK_PAUSE events. */
4458 wParam = VK_PAUSE;
4459 break;
4460 case VK_PAUSE:
4461 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
4462 for purposes of key binding; convert these back into
4463 VK_NUMLOCK events, at least when we want to see NumLock key
4464 presses. (Note that there is never any possibility that
4465 VK_PAUSE with Ctrl really is C-Pause as per above.) */
4466 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
4467 wParam = VK_NUMLOCK;
4468 break;
4469 default:
4470 /* If not defined as a function key, change it to a WM_CHAR message. */
4471 if (lispy_function_keys[wParam] == 0)
4472 {
4473 DWORD modifiers = construct_console_modifiers ();
4474
4475 if (!NILP (Vw32_recognize_altgr)
4476 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
4477 {
4478 /* Always let TranslateMessage handle AltGr key chords;
4479 for some reason, ToAscii doesn't always process AltGr
4480 chords correctly. */
4481 windows_translate = 1;
4482 }
4483 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
4484 {
4485 /* Handle key chords including any modifiers other
4486 than shift directly, in order to preserve as much
4487 modifier information as possible. */
4488 if ('A' <= wParam && wParam <= 'Z')
4489 {
4490 /* Don't translate modified alphabetic keystrokes,
4491 so the user doesn't need to constantly switch
4492 layout to type control or meta keystrokes when
4493 the normal layout translates alphabetic
4494 characters to non-ascii characters. */
4495 if (!modifier_set (VK_SHIFT))
4496 wParam += ('a' - 'A');
4497 msg = WM_CHAR;
4498 }
4499 else
4500 {
4501 /* Try to handle other keystrokes by determining the
4502 base character (ie. translating the base key plus
4503 shift modifier). */
4504 int add;
4505 int isdead = 0;
4506 KEY_EVENT_RECORD key;
4507
4508 key.bKeyDown = TRUE;
4509 key.wRepeatCount = 1;
4510 key.wVirtualKeyCode = wParam;
4511 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
4512 key.uChar.AsciiChar = 0;
4513 key.dwControlKeyState = modifiers;
4514
4515 add = w32_kbd_patch_key (&key);
4516 /* 0 means an unrecognised keycode, negative means
4517 dead key. Ignore both. */
4518 while (--add >= 0)
4519 {
4520 /* Forward asciified character sequence. */
4521 post_character_message
4522 (hwnd, WM_CHAR, key.uChar.AsciiChar, lParam,
4523 w32_get_key_modifiers (wParam, lParam));
4524 w32_kbd_patch_key (&key);
4525 }
4526 return 0;
4527 }
4528 }
4529 else
4530 {
4531 /* Let TranslateMessage handle everything else. */
4532 windows_translate = 1;
4533 }
4534 }
4535 }
4536
4537 translate:
4538 if (windows_translate)
4539 {
4540 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
4541
4542 windows_msg.time = GetMessageTime ();
4543 TranslateMessage (&windows_msg);
4544 goto dflt;
4545 }
4546
4547 /* Fall through */
4548
4549 case WM_SYSCHAR:
4550 case WM_CHAR:
4551 post_character_message (hwnd, msg, wParam, lParam,
4552 w32_get_key_modifiers (wParam, lParam));
4553 break;
4554
4555 /* Simulate middle mouse button events when left and right buttons
4556 are used together, but only if user has two button mouse. */
4557 case WM_LBUTTONDOWN:
4558 case WM_RBUTTONDOWN:
4559 if (XINT (Vw32_num_mouse_buttons) > 2)
4560 goto handle_plain_button;
4561
4562 {
4563 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
4564 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
4565
4566 if (button_state & this)
4567 return 0;
4568
4569 if (button_state == 0)
4570 SetCapture (hwnd);
4571
4572 button_state |= this;
4573
4574 if (button_state & other)
4575 {
4576 if (mouse_button_timer)
4577 {
4578 KillTimer (hwnd, mouse_button_timer);
4579 mouse_button_timer = 0;
4580
4581 /* Generate middle mouse event instead. */
4582 msg = WM_MBUTTONDOWN;
4583 button_state |= MMOUSE;
4584 }
4585 else if (button_state & MMOUSE)
4586 {
4587 /* Ignore button event if we've already generated a
4588 middle mouse down event. This happens if the
4589 user releases and press one of the two buttons
4590 after we've faked a middle mouse event. */
4591 return 0;
4592 }
4593 else
4594 {
4595 /* Flush out saved message. */
4596 post_msg (&saved_mouse_button_msg);
4597 }
4598 wmsg.dwModifiers = w32_get_modifiers ();
4599 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4600
4601 /* Clear message buffer. */
4602 saved_mouse_button_msg.msg.hwnd = 0;
4603 }
4604 else
4605 {
4606 /* Hold onto message for now. */
4607 mouse_button_timer =
4608 SetTimer (hwnd, MOUSE_BUTTON_ID,
4609 XINT (Vw32_mouse_button_tolerance), NULL);
4610 saved_mouse_button_msg.msg.hwnd = hwnd;
4611 saved_mouse_button_msg.msg.message = msg;
4612 saved_mouse_button_msg.msg.wParam = wParam;
4613 saved_mouse_button_msg.msg.lParam = lParam;
4614 saved_mouse_button_msg.msg.time = GetMessageTime ();
4615 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
4616 }
4617 }
4618 return 0;
4619
4620 case WM_LBUTTONUP:
4621 case WM_RBUTTONUP:
4622 if (XINT (Vw32_num_mouse_buttons) > 2)
4623 goto handle_plain_button;
4624
4625 {
4626 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
4627 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
4628
4629 if ((button_state & this) == 0)
4630 return 0;
4631
4632 button_state &= ~this;
4633
4634 if (button_state & MMOUSE)
4635 {
4636 /* Only generate event when second button is released. */
4637 if ((button_state & other) == 0)
4638 {
4639 msg = WM_MBUTTONUP;
4640 button_state &= ~MMOUSE;
4641
4642 if (button_state) abort ();
4643 }
4644 else
4645 return 0;
4646 }
4647 else
4648 {
4649 /* Flush out saved message if necessary. */
4650 if (saved_mouse_button_msg.msg.hwnd)
4651 {
4652 post_msg (&saved_mouse_button_msg);
4653 }
4654 }
4655 wmsg.dwModifiers = w32_get_modifiers ();
4656 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4657
4658 /* Always clear message buffer and cancel timer. */
4659 saved_mouse_button_msg.msg.hwnd = 0;
4660 KillTimer (hwnd, mouse_button_timer);
4661 mouse_button_timer = 0;
4662
4663 if (button_state == 0)
4664 ReleaseCapture ();
4665 }
4666 return 0;
4667
4668 case WM_XBUTTONDOWN:
4669 case WM_XBUTTONUP:
4670 if (w32_pass_extra_mouse_buttons_to_system)
4671 goto dflt;
4672 /* else fall through and process them. */
4673 case WM_MBUTTONDOWN:
4674 case WM_MBUTTONUP:
4675 handle_plain_button:
4676 {
4677 BOOL up;
4678 int button;
4679
4680 if (parse_button (msg, HIWORD (wParam), &button, &up))
4681 {
4682 if (up) ReleaseCapture ();
4683 else SetCapture (hwnd);
4684 button = (button == 0) ? LMOUSE :
4685 ((button == 1) ? MMOUSE : RMOUSE);
4686 if (up)
4687 button_state &= ~button;
4688 else
4689 button_state |= button;
4690 }
4691 }
4692
4693 wmsg.dwModifiers = w32_get_modifiers ();
4694 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4695
4696 /* Need to return true for XBUTTON messages, false for others,
4697 to indicate that we processed the message. */
4698 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
4699
4700 case WM_MOUSEMOVE:
4701 /* If the mouse has just moved into the frame, start tracking
4702 it, so we will be notified when it leaves the frame. Mouse
4703 tracking only works under W98 and NT4 and later. On earlier
4704 versions, there is no way of telling when the mouse leaves the
4705 frame, so we just have to put up with help-echo and mouse
4706 highlighting remaining while the frame is not active. */
4707 if (track_mouse_event_fn && !track_mouse_window)
4708 {
4709 TRACKMOUSEEVENT tme;
4710 tme.cbSize = sizeof (tme);
4711 tme.dwFlags = TME_LEAVE;
4712 tme.hwndTrack = hwnd;
4713
4714 track_mouse_event_fn (&tme);
4715 track_mouse_window = hwnd;
4716 }
4717 case WM_VSCROLL:
4718 if (XINT (Vw32_mouse_move_interval) <= 0
4719 || (msg == WM_MOUSEMOVE && button_state == 0))
4720 {
4721 wmsg.dwModifiers = w32_get_modifiers ();
4722 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4723 return 0;
4724 }
4725
4726 /* Hang onto mouse move and scroll messages for a bit, to avoid
4727 sending such events to Emacs faster than it can process them.
4728 If we get more events before the timer from the first message
4729 expires, we just replace the first message. */
4730
4731 if (saved_mouse_move_msg.msg.hwnd == 0)
4732 mouse_move_timer =
4733 SetTimer (hwnd, MOUSE_MOVE_ID,
4734 XINT (Vw32_mouse_move_interval), NULL);
4735
4736 /* Hold onto message for now. */
4737 saved_mouse_move_msg.msg.hwnd = hwnd;
4738 saved_mouse_move_msg.msg.message = msg;
4739 saved_mouse_move_msg.msg.wParam = wParam;
4740 saved_mouse_move_msg.msg.lParam = lParam;
4741 saved_mouse_move_msg.msg.time = GetMessageTime ();
4742 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
4743
4744 return 0;
4745
4746 case WM_MOUSEWHEEL:
4747 wmsg.dwModifiers = w32_get_modifiers ();
4748 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4749 return 0;
4750
4751 case WM_DROPFILES:
4752 wmsg.dwModifiers = w32_get_modifiers ();
4753 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4754 return 0;
4755
4756 case WM_TIMER:
4757 /* Flush out saved messages if necessary. */
4758 if (wParam == mouse_button_timer)
4759 {
4760 if (saved_mouse_button_msg.msg.hwnd)
4761 {
4762 post_msg (&saved_mouse_button_msg);
4763 saved_mouse_button_msg.msg.hwnd = 0;
4764 }
4765 KillTimer (hwnd, mouse_button_timer);
4766 mouse_button_timer = 0;
4767 }
4768 else if (wParam == mouse_move_timer)
4769 {
4770 if (saved_mouse_move_msg.msg.hwnd)
4771 {
4772 post_msg (&saved_mouse_move_msg);
4773 saved_mouse_move_msg.msg.hwnd = 0;
4774 }
4775 KillTimer (hwnd, mouse_move_timer);
4776 mouse_move_timer = 0;
4777 }
4778 else if (wParam == menu_free_timer)
4779 {
4780 KillTimer (hwnd, menu_free_timer);
4781 menu_free_timer = 0;
4782 f = x_window_to_frame (dpyinfo, hwnd);
4783 if (!f->output_data.w32->menu_command_in_progress)
4784 {
4785 /* Free memory used by owner-drawn and help-echo strings. */
4786 w32_free_menu_strings (hwnd);
4787 f->output_data.w32->menubar_active = 0;
4788 }
4789 }
4790 return 0;
4791
4792 case WM_NCACTIVATE:
4793 /* Windows doesn't send us focus messages when putting up and
4794 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
4795 The only indication we get that something happened is receiving
4796 this message afterwards. So this is a good time to reset our
4797 keyboard modifiers' state. */
4798 reset_modifiers ();
4799 goto dflt;
4800
4801 case WM_INITMENU:
4802 button_state = 0;
4803 ReleaseCapture ();
4804 /* We must ensure menu bar is fully constructed and up to date
4805 before allowing user interaction with it. To achieve this
4806 we send this message to the lisp thread and wait for a
4807 reply (whose value is not actually needed) to indicate that
4808 the menu bar is now ready for use, so we can now return.
4809
4810 To remain responsive in the meantime, we enter a nested message
4811 loop that can process all other messages.
4812
4813 However, we skip all this if the message results from calling
4814 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
4815 thread a message because it is blocked on us at this point. We
4816 set menubar_active before calling TrackPopupMenu to indicate
4817 this (there is no possibility of confusion with real menubar
4818 being active). */
4819
4820 f = x_window_to_frame (dpyinfo, hwnd);
4821 if (f
4822 && (f->output_data.w32->menubar_active
4823 /* We can receive this message even in the absence of a
4824 menubar (ie. when the system menu is activated) - in this
4825 case we do NOT want to forward the message, otherwise it
4826 will cause the menubar to suddenly appear when the user
4827 had requested it to be turned off! */
4828 || f->output_data.w32->menubar_widget == NULL))
4829 return 0;
4830
4831 {
4832 deferred_msg msg_buf;
4833
4834 /* Detect if message has already been deferred; in this case
4835 we cannot return any sensible value to ignore this. */
4836 if (find_deferred_msg (hwnd, msg) != NULL)
4837 abort ();
4838
4839 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
4840 }
4841
4842 case WM_EXITMENULOOP:
4843 f = x_window_to_frame (dpyinfo, hwnd);
4844
4845 /* If a menu command is not already in progress, check again
4846 after a short delay, since Windows often (always?) sends the
4847 WM_EXITMENULOOP before the corresponding WM_COMMAND message. */
4848 if (f && !f->output_data.w32->menu_command_in_progress)
4849 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
4850 goto dflt;
4851
4852 case WM_MENUSELECT:
4853 /* Direct handling of help_echo in menus. Should be safe now
4854 that we generate the help_echo by placing a help event in the
4855 keyboard buffer. */
4856 {
4857 HMENU menu = (HMENU) lParam;
4858 UINT menu_item = (UINT) LOWORD (wParam);
4859 UINT flags = (UINT) HIWORD (wParam);
4860
4861 w32_menu_display_help (hwnd, menu, menu_item, flags);
4862 }
4863 return 0;
4864
4865 case WM_MEASUREITEM:
4866 f = x_window_to_frame (dpyinfo, hwnd);
4867 if (f)
4868 {
4869 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
4870
4871 if (pMis->CtlType == ODT_MENU)
4872 {
4873 /* Work out dimensions for popup menu titles. */
4874 char * title = (char *) pMis->itemData;
4875 HDC hdc = GetDC (hwnd);
4876 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4877 LOGFONT menu_logfont;
4878 HFONT old_font;
4879 SIZE size;
4880
4881 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4882 menu_logfont.lfWeight = FW_BOLD;
4883 menu_font = CreateFontIndirect (&menu_logfont);
4884 old_font = SelectObject (hdc, menu_font);
4885
4886 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
4887 if (title)
4888 {
4889 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
4890 pMis->itemWidth = size.cx;
4891 if (pMis->itemHeight < size.cy)
4892 pMis->itemHeight = size.cy;
4893 }
4894 else
4895 pMis->itemWidth = 0;
4896
4897 SelectObject (hdc, old_font);
4898 DeleteObject (menu_font);
4899 ReleaseDC (hwnd, hdc);
4900 return TRUE;
4901 }
4902 }
4903 return 0;
4904
4905 case WM_DRAWITEM:
4906 f = x_window_to_frame (dpyinfo, hwnd);
4907 if (f)
4908 {
4909 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
4910
4911 if (pDis->CtlType == ODT_MENU)
4912 {
4913 /* Draw popup menu title. */
4914 char * title = (char *) pDis->itemData;
4915 if (title)
4916 {
4917 HDC hdc = pDis->hDC;
4918 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
4919 LOGFONT menu_logfont;
4920 HFONT old_font;
4921
4922 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
4923 menu_logfont.lfWeight = FW_BOLD;
4924 menu_font = CreateFontIndirect (&menu_logfont);
4925 old_font = SelectObject (hdc, menu_font);
4926
4927 /* Always draw title as if not selected. */
4928 ExtTextOut (hdc,
4929 pDis->rcItem.left
4930 + GetSystemMetrics (SM_CXMENUCHECK),
4931 pDis->rcItem.top,
4932 ETO_OPAQUE, &pDis->rcItem,
4933 title, strlen (title), NULL);
4934
4935 SelectObject (hdc, old_font);
4936 DeleteObject (menu_font);
4937 }
4938 return TRUE;
4939 }
4940 }
4941 return 0;
4942
4943 #if 0
4944 /* Still not right - can't distinguish between clicks in the
4945 client area of the frame from clicks forwarded from the scroll
4946 bars - may have to hook WM_NCHITTEST to remember the mouse
4947 position and then check if it is in the client area ourselves. */
4948 case WM_MOUSEACTIVATE:
4949 /* Discard the mouse click that activates a frame, allowing the
4950 user to click anywhere without changing point (or worse!).
4951 Don't eat mouse clicks on scrollbars though!! */
4952 if (LOWORD (lParam) == HTCLIENT )
4953 return MA_ACTIVATEANDEAT;
4954 goto dflt;
4955 #endif
4956
4957 case WM_MOUSELEAVE:
4958 /* No longer tracking mouse. */
4959 track_mouse_window = NULL;
4960
4961 case WM_ACTIVATEAPP:
4962 case WM_ACTIVATE:
4963 case WM_WINDOWPOSCHANGED:
4964 case WM_SHOWWINDOW:
4965 /* Inform lisp thread that a frame might have just been obscured
4966 or exposed, so should recheck visibility of all frames. */
4967 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4968 goto dflt;
4969
4970 case WM_SETFOCUS:
4971 dpyinfo->faked_key = 0;
4972 reset_modifiers ();
4973 register_hot_keys (hwnd);
4974 goto command;
4975 case WM_KILLFOCUS:
4976 unregister_hot_keys (hwnd);
4977 button_state = 0;
4978 ReleaseCapture ();
4979 /* Relinquish the system caret. */
4980 if (w32_system_caret_hwnd)
4981 {
4982 w32_visible_system_caret_hwnd = NULL;
4983 w32_system_caret_hwnd = NULL;
4984 DestroyCaret ();
4985 }
4986 goto command;
4987 case WM_COMMAND:
4988 f = x_window_to_frame (dpyinfo, hwnd);
4989 if (f && HIWORD (wParam) == 0)
4990 {
4991 f->output_data.w32->menu_command_in_progress = 1;
4992 if (menu_free_timer)
4993 {
4994 KillTimer (hwnd, menu_free_timer);
4995 menu_free_timer = 0;
4996 }
4997 }
4998 case WM_MOVE:
4999 case WM_SIZE:
5000 command:
5001 wmsg.dwModifiers = w32_get_modifiers ();
5002 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5003 goto dflt;
5004
5005 case WM_CLOSE:
5006 wmsg.dwModifiers = w32_get_modifiers ();
5007 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5008 return 0;
5009
5010 case WM_WINDOWPOSCHANGING:
5011 /* Don't restrict the sizing of tip frames. */
5012 if (hwnd == tip_window)
5013 return 0;
5014 {
5015 WINDOWPLACEMENT wp;
5016 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
5017
5018 wp.length = sizeof (WINDOWPLACEMENT);
5019 GetWindowPlacement (hwnd, &wp);
5020
5021 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
5022 {
5023 RECT rect;
5024 int wdiff;
5025 int hdiff;
5026 DWORD font_width;
5027 DWORD line_height;
5028 DWORD internal_border;
5029 DWORD scrollbar_extra;
5030 RECT wr;
5031
5032 wp.length = sizeof(wp);
5033 GetWindowRect (hwnd, &wr);
5034
5035 enter_crit ();
5036
5037 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
5038 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
5039 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
5040 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
5041
5042 leave_crit ();
5043
5044 memset (&rect, 0, sizeof (rect));
5045 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
5046 GetMenu (hwnd) != NULL);
5047
5048 /* Force width and height of client area to be exact
5049 multiples of the character cell dimensions. */
5050 wdiff = (lppos->cx - (rect.right - rect.left)
5051 - 2 * internal_border - scrollbar_extra)
5052 % font_width;
5053 hdiff = (lppos->cy - (rect.bottom - rect.top)
5054 - 2 * internal_border)
5055 % line_height;
5056
5057 if (wdiff || hdiff)
5058 {
5059 /* For right/bottom sizing we can just fix the sizes.
5060 However for top/left sizing we will need to fix the X
5061 and Y positions as well. */
5062
5063 lppos->cx -= wdiff;
5064 lppos->cy -= hdiff;
5065
5066 if (wp.showCmd != SW_SHOWMAXIMIZED
5067 && (lppos->flags & SWP_NOMOVE) == 0)
5068 {
5069 if (lppos->x != wr.left || lppos->y != wr.top)
5070 {
5071 lppos->x += wdiff;
5072 lppos->y += hdiff;
5073 }
5074 else
5075 {
5076 lppos->flags |= SWP_NOMOVE;
5077 }
5078 }
5079
5080 return 0;
5081 }
5082 }
5083 }
5084
5085 goto dflt;
5086
5087 case WM_GETMINMAXINFO:
5088 /* Hack to correct bug that allows Emacs frames to be resized
5089 below the Minimum Tracking Size. */
5090 ((LPMINMAXINFO) lParam)->ptMinTrackSize.y++;
5091 /* Hack to allow resizing the Emacs frame above the screen size.
5092 Note that Windows 9x limits coordinates to 16-bits. */
5093 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
5094 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
5095 return 0;
5096
5097 case WM_EMACS_CREATESCROLLBAR:
5098 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
5099 (struct scroll_bar *) lParam);
5100
5101 case WM_EMACS_SHOWWINDOW:
5102 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
5103
5104 case WM_EMACS_SETFOREGROUND:
5105 {
5106 HWND foreground_window;
5107 DWORD foreground_thread, retval;
5108
5109 /* On NT 5.0, and apparently Windows 98, it is necessary to
5110 attach to the thread that currently has focus in order to
5111 pull the focus away from it. */
5112 foreground_window = GetForegroundWindow ();
5113 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
5114 if (!foreground_window
5115 || foreground_thread == GetCurrentThreadId ()
5116 || !AttachThreadInput (GetCurrentThreadId (),
5117 foreground_thread, TRUE))
5118 foreground_thread = 0;
5119
5120 retval = SetForegroundWindow ((HWND) wParam);
5121
5122 /* Detach from the previous foreground thread. */
5123 if (foreground_thread)
5124 AttachThreadInput (GetCurrentThreadId (),
5125 foreground_thread, FALSE);
5126
5127 return retval;
5128 }
5129
5130 case WM_EMACS_SETWINDOWPOS:
5131 {
5132 WINDOWPOS * pos = (WINDOWPOS *) wParam;
5133 return SetWindowPos (hwnd, pos->hwndInsertAfter,
5134 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
5135 }
5136
5137 case WM_EMACS_DESTROYWINDOW:
5138 DragAcceptFiles ((HWND) wParam, FALSE);
5139 return DestroyWindow ((HWND) wParam);
5140
5141 case WM_EMACS_HIDE_CARET:
5142 return HideCaret (hwnd);
5143
5144 case WM_EMACS_SHOW_CARET:
5145 return ShowCaret (hwnd);
5146
5147 case WM_EMACS_DESTROY_CARET:
5148 w32_system_caret_hwnd = NULL;
5149 w32_visible_system_caret_hwnd = NULL;
5150 return DestroyCaret ();
5151
5152 case WM_EMACS_TRACK_CARET:
5153 /* If there is currently no system caret, create one. */
5154 if (w32_system_caret_hwnd == NULL)
5155 {
5156 /* Use the default caret width, and avoid changing it
5157 unneccesarily, as it confuses screen reader software. */
5158 w32_system_caret_hwnd = hwnd;
5159 CreateCaret (hwnd, NULL, 0,
5160 w32_system_caret_height);
5161 }
5162
5163 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
5164 return 0;
5165 /* Ensure visible caret gets turned on when requested. */
5166 else if (w32_use_visible_system_caret
5167 && w32_visible_system_caret_hwnd != hwnd)
5168 {
5169 w32_visible_system_caret_hwnd = hwnd;
5170 return ShowCaret (hwnd);
5171 }
5172 /* Ensure visible caret gets turned off when requested. */
5173 else if (!w32_use_visible_system_caret
5174 && w32_visible_system_caret_hwnd)
5175 {
5176 w32_visible_system_caret_hwnd = NULL;
5177 return HideCaret (hwnd);
5178 }
5179 else
5180 return 1;
5181
5182 case WM_EMACS_TRACKPOPUPMENU:
5183 {
5184 UINT flags;
5185 POINT *pos;
5186 int retval;
5187 pos = (POINT *)lParam;
5188 flags = TPM_CENTERALIGN;
5189 if (button_state & LMOUSE)
5190 flags |= TPM_LEFTBUTTON;
5191 else if (button_state & RMOUSE)
5192 flags |= TPM_RIGHTBUTTON;
5193
5194 /* Remember we did a SetCapture on the initial mouse down event,
5195 so for safety, we make sure the capture is cancelled now. */
5196 ReleaseCapture ();
5197 button_state = 0;
5198
5199 /* Use menubar_active to indicate that WM_INITMENU is from
5200 TrackPopupMenu below, and should be ignored. */
5201 f = x_window_to_frame (dpyinfo, hwnd);
5202 if (f)
5203 f->output_data.w32->menubar_active = 1;
5204
5205 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
5206 0, hwnd, NULL))
5207 {
5208 MSG amsg;
5209 /* Eat any mouse messages during popupmenu */
5210 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
5211 PM_REMOVE));
5212 /* Get the menu selection, if any */
5213 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
5214 {
5215 retval = LOWORD (amsg.wParam);
5216 }
5217 else
5218 {
5219 retval = 0;
5220 }
5221 }
5222 else
5223 {
5224 retval = -1;
5225 }
5226
5227 return retval;
5228 }
5229
5230 default:
5231 /* Check for messages registered at runtime. */
5232 if (msg == msh_mousewheel)
5233 {
5234 wmsg.dwModifiers = w32_get_modifiers ();
5235 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
5236 return 0;
5237 }
5238
5239 dflt:
5240 return DefWindowProc (hwnd, msg, wParam, lParam);
5241 }
5242
5243
5244 /* The most common default return code for handled messages is 0. */
5245 return 0;
5246 }
5247
5248 void
5249 my_create_window (f)
5250 struct frame * f;
5251 {
5252 MSG msg;
5253
5254 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
5255 abort ();
5256 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
5257 }
5258
5259
5260 /* Create a tooltip window. Unlike my_create_window, we do not do this
5261 indirectly via the Window thread, as we do not need to process Window
5262 messages for the tooltip. Creating tooltips indirectly also creates
5263 deadlocks when tooltips are created for menu items. */
5264 void
5265 my_create_tip_window (f)
5266 struct frame *f;
5267 {
5268 RECT rect;
5269
5270 rect.left = rect.top = 0;
5271 rect.right = PIXEL_WIDTH (f);
5272 rect.bottom = PIXEL_HEIGHT (f);
5273
5274 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5275 FRAME_EXTERNAL_MENU_BAR (f));
5276
5277 tip_window = FRAME_W32_WINDOW (f)
5278 = CreateWindow (EMACS_CLASS,
5279 f->namebuf,
5280 f->output_data.w32->dwStyle,
5281 f->output_data.w32->left_pos,
5282 f->output_data.w32->top_pos,
5283 rect.right - rect.left,
5284 rect.bottom - rect.top,
5285 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
5286 NULL,
5287 hinst,
5288 NULL);
5289
5290 if (tip_window)
5291 {
5292 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FONT_WIDTH (f->output_data.w32->font));
5293 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, f->output_data.w32->line_height);
5294 SetWindowLong (tip_window, WND_BORDER_INDEX, f->output_data.w32->internal_border_width);
5295 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
5296
5297 /* Tip frames have no scrollbars. */
5298 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
5299
5300 /* Do this to discard the default setting specified by our parent. */
5301 ShowWindow (tip_window, SW_HIDE);
5302 }
5303 }
5304
5305
5306 /* Create and set up the w32 window for frame F. */
5307
5308 static void
5309 w32_window (f, window_prompting, minibuffer_only)
5310 struct frame *f;
5311 long window_prompting;
5312 int minibuffer_only;
5313 {
5314 BLOCK_INPUT;
5315
5316 /* Use the resource name as the top-level window name
5317 for looking up resources. Make a non-Lisp copy
5318 for the window manager, so GC relocation won't bother it.
5319
5320 Elsewhere we specify the window name for the window manager. */
5321
5322 {
5323 char *str = (char *) XSTRING (Vx_resource_name)->data;
5324 f->namebuf = (char *) xmalloc (strlen (str) + 1);
5325 strcpy (f->namebuf, str);
5326 }
5327
5328 my_create_window (f);
5329
5330 validate_x_resource_name ();
5331
5332 /* x_set_name normally ignores requests to set the name if the
5333 requested name is the same as the current name. This is the one
5334 place where that assumption isn't correct; f->name is set, but
5335 the server hasn't been told. */
5336 {
5337 Lisp_Object name;
5338 int explicit = f->explicit_name;
5339
5340 f->explicit_name = 0;
5341 name = f->name;
5342 f->name = Qnil;
5343 x_set_name (f, name, explicit);
5344 }
5345
5346 UNBLOCK_INPUT;
5347
5348 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
5349 initialize_frame_menubar (f);
5350
5351 if (FRAME_W32_WINDOW (f) == 0)
5352 error ("Unable to create window");
5353 }
5354
5355 /* Handle the icon stuff for this window. Perhaps later we might
5356 want an x_set_icon_position which can be called interactively as
5357 well. */
5358
5359 static void
5360 x_icon (f, parms)
5361 struct frame *f;
5362 Lisp_Object parms;
5363 {
5364 Lisp_Object icon_x, icon_y;
5365
5366 /* Set the position of the icon. Note that Windows 95 groups all
5367 icons in the tray. */
5368 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
5369 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
5370 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
5371 {
5372 CHECK_NUMBER (icon_x);
5373 CHECK_NUMBER (icon_y);
5374 }
5375 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
5376 error ("Both left and top icon corners of icon must be specified");
5377
5378 BLOCK_INPUT;
5379
5380 if (! EQ (icon_x, Qunbound))
5381 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
5382
5383 #if 0 /* TODO */
5384 /* Start up iconic or window? */
5385 x_wm_set_window_state
5386 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
5387 ? IconicState
5388 : NormalState));
5389
5390 x_text_icon (f, (char *) XSTRING ((!NILP (f->icon_name)
5391 ? f->icon_name
5392 : f->name))->data);
5393 #endif
5394
5395 UNBLOCK_INPUT;
5396 }
5397
5398
5399 static void
5400 x_make_gc (f)
5401 struct frame *f;
5402 {
5403 XGCValues gc_values;
5404
5405 BLOCK_INPUT;
5406
5407 /* Create the GC's of this frame.
5408 Note that many default values are used. */
5409
5410 /* Normal video */
5411 gc_values.font = f->output_data.w32->font;
5412
5413 /* Cursor has cursor-color background, background-color foreground. */
5414 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
5415 gc_values.background = f->output_data.w32->cursor_pixel;
5416 f->output_data.w32->cursor_gc
5417 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
5418 (GCFont | GCForeground | GCBackground),
5419 &gc_values);
5420
5421 /* Reliefs. */
5422 f->output_data.w32->white_relief.gc = 0;
5423 f->output_data.w32->black_relief.gc = 0;
5424
5425 UNBLOCK_INPUT;
5426 }
5427
5428
5429 /* Handler for signals raised during x_create_frame and
5430 x_create_top_frame. FRAME is the frame which is partially
5431 constructed. */
5432
5433 static Lisp_Object
5434 unwind_create_frame (frame)
5435 Lisp_Object frame;
5436 {
5437 struct frame *f = XFRAME (frame);
5438
5439 /* If frame is ``official'', nothing to do. */
5440 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
5441 {
5442 #ifdef GLYPH_DEBUG
5443 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5444 #endif
5445
5446 x_free_frame_resources (f);
5447
5448 /* Check that reference counts are indeed correct. */
5449 xassert (dpyinfo->reference_count == dpyinfo_refcount);
5450 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
5451
5452 return Qt;
5453 }
5454
5455 return Qnil;
5456 }
5457
5458
5459 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
5460 1, 1, 0,
5461 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
5462 Returns an Emacs frame object.
5463 ALIST is an alist of frame parameters.
5464 If the parameters specify that the frame should not have a minibuffer,
5465 and do not specify a specific minibuffer window to use,
5466 then `default-minibuffer-frame' must be a frame whose minibuffer can
5467 be shared by the new frame.
5468
5469 This function is an internal primitive--use `make-frame' instead. */)
5470 (parms)
5471 Lisp_Object parms;
5472 {
5473 struct frame *f;
5474 Lisp_Object frame, tem;
5475 Lisp_Object name;
5476 int minibuffer_only = 0;
5477 long window_prompting = 0;
5478 int width, height;
5479 int count = BINDING_STACK_SIZE ();
5480 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5481 Lisp_Object display;
5482 struct w32_display_info *dpyinfo = NULL;
5483 Lisp_Object parent;
5484 struct kboard *kb;
5485
5486 check_w32 ();
5487
5488 /* Use this general default value to start with
5489 until we know if this frame has a specified name. */
5490 Vx_resource_name = Vinvocation_name;
5491
5492 display = w32_get_arg (parms, Qdisplay, 0, 0, RES_TYPE_STRING);
5493 if (EQ (display, Qunbound))
5494 display = Qnil;
5495 dpyinfo = check_x_display_info (display);
5496 #ifdef MULTI_KBOARD
5497 kb = dpyinfo->kboard;
5498 #else
5499 kb = &the_only_kboard;
5500 #endif
5501
5502 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
5503 if (!STRINGP (name)
5504 && ! EQ (name, Qunbound)
5505 && ! NILP (name))
5506 error ("Invalid frame name--not a string or nil");
5507
5508 if (STRINGP (name))
5509 Vx_resource_name = name;
5510
5511 /* See if parent window is specified. */
5512 parent = w32_get_arg (parms, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
5513 if (EQ (parent, Qunbound))
5514 parent = Qnil;
5515 if (! NILP (parent))
5516 CHECK_NUMBER (parent);
5517
5518 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
5519 /* No need to protect DISPLAY because that's not used after passing
5520 it to make_frame_without_minibuffer. */
5521 frame = Qnil;
5522 GCPRO4 (parms, parent, name, frame);
5523 tem = w32_get_arg (parms, Qminibuffer, "minibuffer", "Minibuffer",
5524 RES_TYPE_SYMBOL);
5525 if (EQ (tem, Qnone) || NILP (tem))
5526 f = make_frame_without_minibuffer (Qnil, kb, display);
5527 else if (EQ (tem, Qonly))
5528 {
5529 f = make_minibuffer_frame ();
5530 minibuffer_only = 1;
5531 }
5532 else if (WINDOWP (tem))
5533 f = make_frame_without_minibuffer (tem, kb, display);
5534 else
5535 f = make_frame (1);
5536
5537 XSETFRAME (frame, f);
5538
5539 /* Note that Windows does support scroll bars. */
5540 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
5541 /* By default, make scrollbars the system standard width. */
5542 f->scroll_bar_pixel_width = GetSystemMetrics (SM_CXVSCROLL);
5543
5544 f->output_method = output_w32;
5545 f->output_data.w32 =
5546 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5547 bzero (f->output_data.w32, sizeof (struct w32_output));
5548 FRAME_FONTSET (f) = -1;
5549 record_unwind_protect (unwind_create_frame, frame);
5550
5551 f->icon_name
5552 = w32_get_arg (parms, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
5553 if (! STRINGP (f->icon_name))
5554 f->icon_name = Qnil;
5555
5556 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
5557 #ifdef MULTI_KBOARD
5558 FRAME_KBOARD (f) = kb;
5559 #endif
5560
5561 /* Specify the parent under which to make this window. */
5562
5563 if (!NILP (parent))
5564 {
5565 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
5566 f->output_data.w32->explicit_parent = 1;
5567 }
5568 else
5569 {
5570 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5571 f->output_data.w32->explicit_parent = 0;
5572 }
5573
5574 /* Set the name; the functions to which we pass f expect the name to
5575 be set. */
5576 if (EQ (name, Qunbound) || NILP (name))
5577 {
5578 f->name = build_string (dpyinfo->w32_id_name);
5579 f->explicit_name = 0;
5580 }
5581 else
5582 {
5583 f->name = name;
5584 f->explicit_name = 1;
5585 /* use the frame's title when getting resources for this frame. */
5586 specbind (Qx_resource_name, name);
5587 }
5588
5589 /* Extract the window parameters from the supplied values
5590 that are needed to determine window geometry. */
5591 {
5592 Lisp_Object font;
5593
5594 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
5595
5596 BLOCK_INPUT;
5597 /* First, try whatever font the caller has specified. */
5598 if (STRINGP (font))
5599 {
5600 tem = Fquery_fontset (font, Qnil);
5601 if (STRINGP (tem))
5602 font = x_new_fontset (f, XSTRING (tem)->data);
5603 else
5604 font = x_new_font (f, XSTRING (font)->data);
5605 }
5606 /* Try out a font which we hope has bold and italic variations. */
5607 if (!STRINGP (font))
5608 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
5609 if (! STRINGP (font))
5610 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
5611 /* If those didn't work, look for something which will at least work. */
5612 if (! STRINGP (font))
5613 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
5614 UNBLOCK_INPUT;
5615 if (! STRINGP (font))
5616 font = build_string ("Fixedsys");
5617
5618 x_default_parameter (f, parms, Qfont, font,
5619 "font", "Font", RES_TYPE_STRING);
5620 }
5621
5622 x_default_parameter (f, parms, Qborder_width, make_number (2),
5623 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5624 /* This defaults to 2 in order to match xterm. We recognize either
5625 internalBorderWidth or internalBorder (which is what xterm calls
5626 it). */
5627 if (NILP (Fassq (Qinternal_border_width, parms)))
5628 {
5629 Lisp_Object value;
5630
5631 value = w32_get_arg (parms, Qinternal_border_width,
5632 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
5633 if (! EQ (value, Qunbound))
5634 parms = Fcons (Fcons (Qinternal_border_width, value),
5635 parms);
5636 }
5637 /* Default internalBorderWidth to 0 on Windows to match other programs. */
5638 x_default_parameter (f, parms, Qinternal_border_width, make_number (0),
5639 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
5640 x_default_parameter (f, parms, Qvertical_scroll_bars, Qright,
5641 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
5642
5643 /* Also do the stuff which must be set before the window exists. */
5644 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5645 "foreground", "Foreground", RES_TYPE_STRING);
5646 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5647 "background", "Background", RES_TYPE_STRING);
5648 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5649 "pointerColor", "Foreground", RES_TYPE_STRING);
5650 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5651 "cursorColor", "Foreground", RES_TYPE_STRING);
5652 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5653 "borderColor", "BorderColor", RES_TYPE_STRING);
5654 x_default_parameter (f, parms, Qscreen_gamma, Qnil,
5655 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
5656 x_default_parameter (f, parms, Qline_spacing, Qnil,
5657 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
5658 x_default_parameter (f, parms, Qleft_fringe, Qnil,
5659 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
5660 x_default_parameter (f, parms, Qright_fringe, Qnil,
5661 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
5662
5663
5664 /* Init faces before x_default_parameter is called for scroll-bar
5665 parameters because that function calls x_set_scroll_bar_width,
5666 which calls change_frame_size, which calls Fset_window_buffer,
5667 which runs hooks, which call Fvertical_motion. At the end, we
5668 end up in init_iterator with a null face cache, which should not
5669 happen. */
5670 init_frame_faces (f);
5671
5672 x_default_parameter (f, parms, Qmenu_bar_lines, make_number (1),
5673 "menuBar", "MenuBar", RES_TYPE_NUMBER);
5674 x_default_parameter (f, parms, Qtool_bar_lines, make_number (0),
5675 "toolBar", "ToolBar", RES_TYPE_NUMBER);
5676 x_default_parameter (f, parms, Qbuffer_predicate, Qnil,
5677 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
5678 x_default_parameter (f, parms, Qtitle, Qnil,
5679 "title", "Title", RES_TYPE_STRING);
5680 x_default_parameter (f, parms, Qfullscreen, Qnil,
5681 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
5682
5683 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
5684 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5685
5686 /* Add the tool-bar height to the initial frame height so that the
5687 user gets a text display area of the size he specified with -g or
5688 via .Xdefaults. Later changes of the tool-bar height don't
5689 change the frame size. This is done so that users can create
5690 tall Emacs frames without having to guess how tall the tool-bar
5691 will get. */
5692 if (FRAME_TOOL_BAR_LINES (f))
5693 {
5694 int margin, relief, bar_height;
5695
5696 relief = (tool_bar_button_relief >= 0
5697 ? tool_bar_button_relief
5698 : DEFAULT_TOOL_BAR_BUTTON_RELIEF);
5699
5700 if (INTEGERP (Vtool_bar_button_margin)
5701 && XINT (Vtool_bar_button_margin) > 0)
5702 margin = XFASTINT (Vtool_bar_button_margin);
5703 else if (CONSP (Vtool_bar_button_margin)
5704 && INTEGERP (XCDR (Vtool_bar_button_margin))
5705 && XINT (XCDR (Vtool_bar_button_margin)) > 0)
5706 margin = XFASTINT (XCDR (Vtool_bar_button_margin));
5707 else
5708 margin = 0;
5709
5710 bar_height = DEFAULT_TOOL_BAR_IMAGE_HEIGHT + 2 * margin + 2 * relief;
5711 f->height += (bar_height + CANON_Y_UNIT (f) - 1) / CANON_Y_UNIT (f);
5712 }
5713
5714 window_prompting = x_figure_window_size (f, parms);
5715
5716 if (window_prompting & XNegative)
5717 {
5718 if (window_prompting & YNegative)
5719 f->output_data.w32->win_gravity = SouthEastGravity;
5720 else
5721 f->output_data.w32->win_gravity = NorthEastGravity;
5722 }
5723 else
5724 {
5725 if (window_prompting & YNegative)
5726 f->output_data.w32->win_gravity = SouthWestGravity;
5727 else
5728 f->output_data.w32->win_gravity = NorthWestGravity;
5729 }
5730
5731 f->output_data.w32->size_hint_flags = window_prompting;
5732
5733 tem = w32_get_arg (parms, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
5734 f->no_split = minibuffer_only || EQ (tem, Qt);
5735
5736 w32_window (f, window_prompting, minibuffer_only);
5737 x_icon (f, parms);
5738
5739 x_make_gc (f);
5740
5741 /* Now consider the frame official. */
5742 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5743 Vframe_list = Fcons (frame, Vframe_list);
5744
5745 /* We need to do this after creating the window, so that the
5746 icon-creation functions can say whose icon they're describing. */
5747 x_default_parameter (f, parms, Qicon_type, Qnil,
5748 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
5749
5750 x_default_parameter (f, parms, Qauto_raise, Qnil,
5751 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5752 x_default_parameter (f, parms, Qauto_lower, Qnil,
5753 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5754 x_default_parameter (f, parms, Qcursor_type, Qbox,
5755 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5756 x_default_parameter (f, parms, Qscroll_bar_width, Qnil,
5757 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
5758
5759 /* Dimensions, especially f->height, must be done via change_frame_size.
5760 Change will not be effected unless different from the current
5761 f->height. */
5762 width = f->width;
5763 height = f->height;
5764
5765 f->height = 0;
5766 SET_FRAME_WIDTH (f, 0);
5767 change_frame_size (f, height, width, 1, 0, 0);
5768
5769 /* Tell the server what size and position, etc, we want, and how
5770 badly we want them. This should be done after we have the menu
5771 bar so that its size can be taken into account. */
5772 BLOCK_INPUT;
5773 x_wm_set_size_hint (f, window_prompting, 0);
5774 UNBLOCK_INPUT;
5775
5776 /* Avoid a bug that causes the new frame to never become visible if
5777 an echo area message is displayed during the following call1. */
5778 specbind(Qredisplay_dont_pause, Qt);
5779
5780 /* Set up faces after all frame parameters are known. This call
5781 also merges in face attributes specified for new frames. If we
5782 don't do this, the `menu' face for instance won't have the right
5783 colors, and the menu bar won't appear in the specified colors for
5784 new frames. */
5785 call1 (Qface_set_after_frame_default, frame);
5786
5787 /* Make the window appear on the frame and enable display, unless
5788 the caller says not to. However, with explicit parent, Emacs
5789 cannot control visibility, so don't try. */
5790 if (! f->output_data.w32->explicit_parent)
5791 {
5792 Lisp_Object visibility;
5793
5794 visibility = w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
5795 if (EQ (visibility, Qunbound))
5796 visibility = Qt;
5797
5798 if (EQ (visibility, Qicon))
5799 x_iconify_frame (f);
5800 else if (! NILP (visibility))
5801 x_make_frame_visible (f);
5802 else
5803 /* Must have been Qnil. */
5804 ;
5805 }
5806 UNGCPRO;
5807
5808 /* Make sure windows on this frame appear in calls to next-window
5809 and similar functions. */
5810 Vwindow_list = Qnil;
5811
5812 return unbind_to (count, frame);
5813 }
5814
5815 /* FRAME is used only to get a handle on the X display. We don't pass the
5816 display info directly because we're called from frame.c, which doesn't
5817 know about that structure. */
5818 Lisp_Object
5819 x_get_focus_frame (frame)
5820 struct frame *frame;
5821 {
5822 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
5823 Lisp_Object xfocus;
5824 if (! dpyinfo->w32_focus_frame)
5825 return Qnil;
5826
5827 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
5828 return xfocus;
5829 }
5830
5831 DEFUN ("w32-focus-frame", Fw32_focus_frame, Sw32_focus_frame, 1, 1, 0,
5832 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
5833 (frame)
5834 Lisp_Object frame;
5835 {
5836 x_focus_on_frame (check_x_frame (frame));
5837 return Qnil;
5838 }
5839
5840 \f
5841 /* Return the charset portion of a font name. */
5842 char * xlfd_charset_of_font (char * fontname)
5843 {
5844 char *charset, *encoding;
5845
5846 encoding = strrchr(fontname, '-');
5847 if (!encoding || encoding == fontname)
5848 return NULL;
5849
5850 for (charset = encoding - 1; charset >= fontname; charset--)
5851 if (*charset == '-')
5852 break;
5853
5854 if (charset == fontname || strcmp(charset, "-*-*") == 0)
5855 return NULL;
5856
5857 return charset + 1;
5858 }
5859
5860 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
5861 int size, char* filename);
5862 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
5863 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
5864 char * charset);
5865 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
5866
5867 static struct font_info *
5868 w32_load_system_font (f,fontname,size)
5869 struct frame *f;
5870 char * fontname;
5871 int size;
5872 {
5873 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
5874 Lisp_Object font_names;
5875
5876 /* Get a list of all the fonts that match this name. Once we
5877 have a list of matching fonts, we compare them against the fonts
5878 we already have loaded by comparing names. */
5879 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
5880
5881 if (!NILP (font_names))
5882 {
5883 Lisp_Object tail;
5884 int i;
5885
5886 /* First check if any are already loaded, as that is cheaper
5887 than loading another one. */
5888 for (i = 0; i < dpyinfo->n_fonts; i++)
5889 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
5890 if (dpyinfo->font_table[i].name
5891 && (!strcmp (dpyinfo->font_table[i].name,
5892 XSTRING (XCAR (tail))->data)
5893 || !strcmp (dpyinfo->font_table[i].full_name,
5894 XSTRING (XCAR (tail))->data)))
5895 return (dpyinfo->font_table + i);
5896
5897 fontname = (char *) XSTRING (XCAR (font_names))->data;
5898 }
5899 else if (w32_strict_fontnames)
5900 {
5901 /* If EnumFontFamiliesEx was available, we got a full list of
5902 fonts back so stop now to avoid the possibility of loading a
5903 random font. If we had to fall back to EnumFontFamilies, the
5904 list is incomplete, so continue whether the font we want was
5905 listed or not. */
5906 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
5907 FARPROC enum_font_families_ex
5908 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
5909 if (enum_font_families_ex)
5910 return NULL;
5911 }
5912
5913 /* Load the font and add it to the table. */
5914 {
5915 char *full_name, *encoding, *charset;
5916 XFontStruct *font;
5917 struct font_info *fontp;
5918 LOGFONT lf;
5919 BOOL ok;
5920 int codepage;
5921 int i;
5922
5923 if (!fontname || !x_to_w32_font (fontname, &lf))
5924 return (NULL);
5925
5926 if (!*lf.lfFaceName)
5927 /* If no name was specified for the font, we get a random font
5928 from CreateFontIndirect - this is not particularly
5929 desirable, especially since CreateFontIndirect does not
5930 fill out the missing name in lf, so we never know what we
5931 ended up with. */
5932 return NULL;
5933
5934 /* Specify anti-aliasing to prevent Cleartype fonts being used,
5935 since those fonts leave garbage behind. */
5936 lf.lfQuality = ANTIALIASED_QUALITY;
5937
5938 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
5939 bzero (font, sizeof (*font));
5940
5941 /* Set bdf to NULL to indicate that this is a Windows font. */
5942 font->bdf = NULL;
5943
5944 BLOCK_INPUT;
5945
5946 font->hfont = CreateFontIndirect (&lf);
5947
5948 if (font->hfont == NULL)
5949 {
5950 ok = FALSE;
5951 }
5952 else
5953 {
5954 HDC hdc;
5955 HANDLE oldobj;
5956
5957 codepage = w32_codepage_for_font (fontname);
5958
5959 hdc = GetDC (dpyinfo->root_window);
5960 oldobj = SelectObject (hdc, font->hfont);
5961
5962 ok = GetTextMetrics (hdc, &font->tm);
5963 if (codepage == CP_UNICODE)
5964 font->double_byte_p = 1;
5965 else
5966 {
5967 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
5968 don't report themselves as double byte fonts, when
5969 patently they are. So instead of trusting
5970 GetFontLanguageInfo, we check the properties of the
5971 codepage directly, since that is ultimately what we are
5972 working from anyway. */
5973 /* font->double_byte_p = GetFontLanguageInfo(hdc) & GCP_DBCS; */
5974 CPINFO cpi = {0};
5975 GetCPInfo (codepage, &cpi);
5976 font->double_byte_p = cpi.MaxCharSize > 1;
5977 }
5978
5979 SelectObject (hdc, oldobj);
5980 ReleaseDC (dpyinfo->root_window, hdc);
5981 /* Fill out details in lf according to the font that was
5982 actually loaded. */
5983 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
5984 lf.lfWidth = font->tm.tmAveCharWidth;
5985 lf.lfWeight = font->tm.tmWeight;
5986 lf.lfItalic = font->tm.tmItalic;
5987 lf.lfCharSet = font->tm.tmCharSet;
5988 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
5989 ? VARIABLE_PITCH : FIXED_PITCH);
5990 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
5991 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
5992
5993 w32_cache_char_metrics (font);
5994 }
5995
5996 UNBLOCK_INPUT;
5997
5998 if (!ok)
5999 {
6000 w32_unload_font (dpyinfo, font);
6001 return (NULL);
6002 }
6003
6004 /* Find a free slot in the font table. */
6005 for (i = 0; i < dpyinfo->n_fonts; ++i)
6006 if (dpyinfo->font_table[i].name == NULL)
6007 break;
6008
6009 /* If no free slot found, maybe enlarge the font table. */
6010 if (i == dpyinfo->n_fonts
6011 && dpyinfo->n_fonts == dpyinfo->font_table_size)
6012 {
6013 int sz;
6014 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
6015 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
6016 dpyinfo->font_table
6017 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
6018 }
6019
6020 fontp = dpyinfo->font_table + i;
6021 if (i == dpyinfo->n_fonts)
6022 ++dpyinfo->n_fonts;
6023
6024 /* Now fill in the slots of *FONTP. */
6025 BLOCK_INPUT;
6026 fontp->font = font;
6027 fontp->font_idx = i;
6028 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
6029 bcopy (fontname, fontp->name, strlen (fontname) + 1);
6030
6031 charset = xlfd_charset_of_font (fontname);
6032
6033 /* Cache the W32 codepage for a font. This makes w32_encode_char
6034 (called for every glyph during redisplay) much faster. */
6035 fontp->codepage = codepage;
6036
6037 /* Work out the font's full name. */
6038 full_name = (char *)xmalloc (100);
6039 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
6040 fontp->full_name = full_name;
6041 else
6042 {
6043 /* If all else fails - just use the name we used to load it. */
6044 xfree (full_name);
6045 fontp->full_name = fontp->name;
6046 }
6047
6048 fontp->size = FONT_WIDTH (font);
6049 fontp->height = FONT_HEIGHT (font);
6050
6051 /* The slot `encoding' specifies how to map a character
6052 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
6053 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
6054 (0:0x20..0x7F, 1:0xA0..0xFF,
6055 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
6056 2:0xA020..0xFF7F). For the moment, we don't know which charset
6057 uses this font. So, we set information in fontp->encoding[1]
6058 which is never used by any charset. If mapping can't be
6059 decided, set FONT_ENCODING_NOT_DECIDED. */
6060
6061 /* SJIS fonts need to be set to type 4, all others seem to work as
6062 type FONT_ENCODING_NOT_DECIDED. */
6063 encoding = strrchr (fontp->name, '-');
6064 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
6065 fontp->encoding[1] = 4;
6066 else
6067 fontp->encoding[1] = FONT_ENCODING_NOT_DECIDED;
6068
6069 /* The following three values are set to 0 under W32, which is
6070 what they get set to if XGetFontProperty fails under X. */
6071 fontp->baseline_offset = 0;
6072 fontp->relative_compose = 0;
6073 fontp->default_ascent = 0;
6074
6075 /* Set global flag fonts_changed_p to non-zero if the font loaded
6076 has a character with a smaller width than any other character
6077 before, or if the font loaded has a smaller height than any
6078 other font loaded before. If this happens, it will make a
6079 glyph matrix reallocation necessary. */
6080 fonts_changed_p |= x_compute_min_glyph_bounds (f);
6081 UNBLOCK_INPUT;
6082 return fontp;
6083 }
6084 }
6085
6086 /* Load font named FONTNAME of size SIZE for frame F, and return a
6087 pointer to the structure font_info while allocating it dynamically.
6088 If loading fails, return NULL. */
6089 struct font_info *
6090 w32_load_font (f,fontname,size)
6091 struct frame *f;
6092 char * fontname;
6093 int size;
6094 {
6095 Lisp_Object bdf_fonts;
6096 struct font_info *retval = NULL;
6097
6098 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
6099
6100 while (!retval && CONSP (bdf_fonts))
6101 {
6102 char *bdf_name, *bdf_file;
6103 Lisp_Object bdf_pair;
6104
6105 bdf_name = XSTRING (XCAR (bdf_fonts))->data;
6106 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
6107 bdf_file = XSTRING (XCDR (bdf_pair))->data;
6108
6109 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
6110
6111 bdf_fonts = XCDR (bdf_fonts);
6112 }
6113
6114 if (retval)
6115 return retval;
6116
6117 return w32_load_system_font(f, fontname, size);
6118 }
6119
6120
6121 void
6122 w32_unload_font (dpyinfo, font)
6123 struct w32_display_info *dpyinfo;
6124 XFontStruct * font;
6125 {
6126 if (font)
6127 {
6128 if (font->per_char) xfree (font->per_char);
6129 if (font->bdf) w32_free_bdf_font (font->bdf);
6130
6131 if (font->hfont) DeleteObject(font->hfont);
6132 xfree (font);
6133 }
6134 }
6135
6136 /* The font conversion stuff between x and w32 */
6137
6138 /* X font string is as follows (from faces.el)
6139 * (let ((- "[-?]")
6140 * (foundry "[^-]+")
6141 * (family "[^-]+")
6142 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
6143 * (weight\? "\\([^-]*\\)") ; 1
6144 * (slant "\\([ior]\\)") ; 2
6145 * (slant\? "\\([^-]?\\)") ; 2
6146 * (swidth "\\([^-]*\\)") ; 3
6147 * (adstyle "[^-]*") ; 4
6148 * (pixelsize "[0-9]+")
6149 * (pointsize "[0-9][0-9]+")
6150 * (resx "[0-9][0-9]+")
6151 * (resy "[0-9][0-9]+")
6152 * (spacing "[cmp?*]")
6153 * (avgwidth "[0-9]+")
6154 * (registry "[^-]+")
6155 * (encoding "[^-]+")
6156 * )
6157 */
6158
6159 static LONG
6160 x_to_w32_weight (lpw)
6161 char * lpw;
6162 {
6163 if (!lpw) return (FW_DONTCARE);
6164
6165 if (stricmp (lpw,"heavy") == 0) return FW_HEAVY;
6166 else if (stricmp (lpw,"extrabold") == 0) return FW_EXTRABOLD;
6167 else if (stricmp (lpw,"bold") == 0) return FW_BOLD;
6168 else if (stricmp (lpw,"demibold") == 0) return FW_SEMIBOLD;
6169 else if (stricmp (lpw,"semibold") == 0) return FW_SEMIBOLD;
6170 else if (stricmp (lpw,"medium") == 0) return FW_MEDIUM;
6171 else if (stricmp (lpw,"normal") == 0) return FW_NORMAL;
6172 else if (stricmp (lpw,"light") == 0) return FW_LIGHT;
6173 else if (stricmp (lpw,"extralight") == 0) return FW_EXTRALIGHT;
6174 else if (stricmp (lpw,"thin") == 0) return FW_THIN;
6175 else
6176 return FW_DONTCARE;
6177 }
6178
6179
6180 static char *
6181 w32_to_x_weight (fnweight)
6182 int fnweight;
6183 {
6184 if (fnweight >= FW_HEAVY) return "heavy";
6185 if (fnweight >= FW_EXTRABOLD) return "extrabold";
6186 if (fnweight >= FW_BOLD) return "bold";
6187 if (fnweight >= FW_SEMIBOLD) return "demibold";
6188 if (fnweight >= FW_MEDIUM) return "medium";
6189 if (fnweight >= FW_NORMAL) return "normal";
6190 if (fnweight >= FW_LIGHT) return "light";
6191 if (fnweight >= FW_EXTRALIGHT) return "extralight";
6192 if (fnweight >= FW_THIN) return "thin";
6193 else
6194 return "*";
6195 }
6196
6197 static LONG
6198 x_to_w32_charset (lpcs)
6199 char * lpcs;
6200 {
6201 Lisp_Object this_entry, w32_charset;
6202 char *charset;
6203 int len = strlen (lpcs);
6204
6205 /* Support "*-#nnn" format for unknown charsets. */
6206 if (strncmp (lpcs, "*-#", 3) == 0)
6207 return atoi (lpcs + 3);
6208
6209 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
6210 charset = alloca (len + 1);
6211 strcpy (charset, lpcs);
6212 lpcs = strchr (charset, '*');
6213 if (lpcs)
6214 *lpcs = 0;
6215
6216 /* Look through w32-charset-info-alist for the character set.
6217 Format of each entry is
6218 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6219 */
6220 this_entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6221
6222 if (NILP(this_entry))
6223 {
6224 /* At startup, we want iso8859-1 fonts to come up properly. */
6225 if (stricmp(charset, "iso8859-1") == 0)
6226 return ANSI_CHARSET;
6227 else
6228 return DEFAULT_CHARSET;
6229 }
6230
6231 w32_charset = Fcar (Fcdr (this_entry));
6232
6233 /* Translate Lisp symbol to number. */
6234 if (w32_charset == Qw32_charset_ansi)
6235 return ANSI_CHARSET;
6236 if (w32_charset == Qw32_charset_symbol)
6237 return SYMBOL_CHARSET;
6238 if (w32_charset == Qw32_charset_shiftjis)
6239 return SHIFTJIS_CHARSET;
6240 if (w32_charset == Qw32_charset_hangeul)
6241 return HANGEUL_CHARSET;
6242 if (w32_charset == Qw32_charset_chinesebig5)
6243 return CHINESEBIG5_CHARSET;
6244 if (w32_charset == Qw32_charset_gb2312)
6245 return GB2312_CHARSET;
6246 if (w32_charset == Qw32_charset_oem)
6247 return OEM_CHARSET;
6248 #ifdef JOHAB_CHARSET
6249 if (w32_charset == Qw32_charset_johab)
6250 return JOHAB_CHARSET;
6251 if (w32_charset == Qw32_charset_easteurope)
6252 return EASTEUROPE_CHARSET;
6253 if (w32_charset == Qw32_charset_turkish)
6254 return TURKISH_CHARSET;
6255 if (w32_charset == Qw32_charset_baltic)
6256 return BALTIC_CHARSET;
6257 if (w32_charset == Qw32_charset_russian)
6258 return RUSSIAN_CHARSET;
6259 if (w32_charset == Qw32_charset_arabic)
6260 return ARABIC_CHARSET;
6261 if (w32_charset == Qw32_charset_greek)
6262 return GREEK_CHARSET;
6263 if (w32_charset == Qw32_charset_hebrew)
6264 return HEBREW_CHARSET;
6265 if (w32_charset == Qw32_charset_vietnamese)
6266 return VIETNAMESE_CHARSET;
6267 if (w32_charset == Qw32_charset_thai)
6268 return THAI_CHARSET;
6269 if (w32_charset == Qw32_charset_mac)
6270 return MAC_CHARSET;
6271 #endif /* JOHAB_CHARSET */
6272 #ifdef UNICODE_CHARSET
6273 if (w32_charset == Qw32_charset_unicode)
6274 return UNICODE_CHARSET;
6275 #endif
6276
6277 return DEFAULT_CHARSET;
6278 }
6279
6280
6281 static char *
6282 w32_to_x_charset (fncharset)
6283 int fncharset;
6284 {
6285 static char buf[32];
6286 Lisp_Object charset_type;
6287
6288 switch (fncharset)
6289 {
6290 case ANSI_CHARSET:
6291 /* Handle startup case of w32-charset-info-alist not
6292 being set up yet. */
6293 if (NILP(Vw32_charset_info_alist))
6294 return "iso8859-1";
6295 charset_type = Qw32_charset_ansi;
6296 break;
6297 case DEFAULT_CHARSET:
6298 charset_type = Qw32_charset_default;
6299 break;
6300 case SYMBOL_CHARSET:
6301 charset_type = Qw32_charset_symbol;
6302 break;
6303 case SHIFTJIS_CHARSET:
6304 charset_type = Qw32_charset_shiftjis;
6305 break;
6306 case HANGEUL_CHARSET:
6307 charset_type = Qw32_charset_hangeul;
6308 break;
6309 case GB2312_CHARSET:
6310 charset_type = Qw32_charset_gb2312;
6311 break;
6312 case CHINESEBIG5_CHARSET:
6313 charset_type = Qw32_charset_chinesebig5;
6314 break;
6315 case OEM_CHARSET:
6316 charset_type = Qw32_charset_oem;
6317 break;
6318
6319 /* More recent versions of Windows (95 and NT4.0) define more
6320 character sets. */
6321 #ifdef EASTEUROPE_CHARSET
6322 case EASTEUROPE_CHARSET:
6323 charset_type = Qw32_charset_easteurope;
6324 break;
6325 case TURKISH_CHARSET:
6326 charset_type = Qw32_charset_turkish;
6327 break;
6328 case BALTIC_CHARSET:
6329 charset_type = Qw32_charset_baltic;
6330 break;
6331 case RUSSIAN_CHARSET:
6332 charset_type = Qw32_charset_russian;
6333 break;
6334 case ARABIC_CHARSET:
6335 charset_type = Qw32_charset_arabic;
6336 break;
6337 case GREEK_CHARSET:
6338 charset_type = Qw32_charset_greek;
6339 break;
6340 case HEBREW_CHARSET:
6341 charset_type = Qw32_charset_hebrew;
6342 break;
6343 case VIETNAMESE_CHARSET:
6344 charset_type = Qw32_charset_vietnamese;
6345 break;
6346 case THAI_CHARSET:
6347 charset_type = Qw32_charset_thai;
6348 break;
6349 case MAC_CHARSET:
6350 charset_type = Qw32_charset_mac;
6351 break;
6352 case JOHAB_CHARSET:
6353 charset_type = Qw32_charset_johab;
6354 break;
6355 #endif
6356
6357 #ifdef UNICODE_CHARSET
6358 case UNICODE_CHARSET:
6359 charset_type = Qw32_charset_unicode;
6360 break;
6361 #endif
6362 default:
6363 /* Encode numerical value of unknown charset. */
6364 sprintf (buf, "*-#%u", fncharset);
6365 return buf;
6366 }
6367
6368 {
6369 Lisp_Object rest;
6370 char * best_match = NULL;
6371
6372 /* Look through w32-charset-info-alist for the character set.
6373 Prefer ISO codepages, and prefer lower numbers in the ISO
6374 range. Only return charsets for codepages which are installed.
6375
6376 Format of each entry is
6377 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6378 */
6379 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6380 {
6381 char * x_charset;
6382 Lisp_Object w32_charset;
6383 Lisp_Object codepage;
6384
6385 Lisp_Object this_entry = XCAR (rest);
6386
6387 /* Skip invalid entries in alist. */
6388 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6389 || !CONSP (XCDR (this_entry))
6390 || !SYMBOLP (XCAR (XCDR (this_entry))))
6391 continue;
6392
6393 x_charset = XSTRING (XCAR (this_entry))->data;
6394 w32_charset = XCAR (XCDR (this_entry));
6395 codepage = XCDR (XCDR (this_entry));
6396
6397 /* Look for Same charset and a valid codepage (or non-int
6398 which means ignore). */
6399 if (w32_charset == charset_type
6400 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6401 || IsValidCodePage (XINT (codepage))))
6402 {
6403 /* If we don't have a match already, then this is the
6404 best. */
6405 if (!best_match)
6406 best_match = x_charset;
6407 /* If this is an ISO codepage, and the best so far isn't,
6408 then this is better. */
6409 else if (strnicmp (best_match, "iso", 3) != 0
6410 && strnicmp (x_charset, "iso", 3) == 0)
6411 best_match = x_charset;
6412 /* If both are ISO8859 codepages, choose the one with the
6413 lowest number in the encoding field. */
6414 else if (strnicmp (best_match, "iso8859-", 8) == 0
6415 && strnicmp (x_charset, "iso8859-", 8) == 0)
6416 {
6417 int best_enc = atoi (best_match + 8);
6418 int this_enc = atoi (x_charset + 8);
6419 if (this_enc > 0 && this_enc < best_enc)
6420 best_match = x_charset;
6421 }
6422 }
6423 }
6424
6425 /* If no match, encode the numeric value. */
6426 if (!best_match)
6427 {
6428 sprintf (buf, "*-#%u", fncharset);
6429 return buf;
6430 }
6431
6432 strncpy(buf, best_match, 31);
6433 buf[31] = '\0';
6434 return buf;
6435 }
6436 }
6437
6438
6439 /* Return all the X charsets that map to a font. */
6440 static Lisp_Object
6441 w32_to_all_x_charsets (fncharset)
6442 int fncharset;
6443 {
6444 static char buf[32];
6445 Lisp_Object charset_type;
6446 Lisp_Object retval = Qnil;
6447
6448 switch (fncharset)
6449 {
6450 case ANSI_CHARSET:
6451 /* Handle startup case of w32-charset-info-alist not
6452 being set up yet. */
6453 if (NILP(Vw32_charset_info_alist))
6454 return Fcons (build_string ("iso8859-1"), Qnil);
6455
6456 charset_type = Qw32_charset_ansi;
6457 break;
6458 case DEFAULT_CHARSET:
6459 charset_type = Qw32_charset_default;
6460 break;
6461 case SYMBOL_CHARSET:
6462 charset_type = Qw32_charset_symbol;
6463 break;
6464 case SHIFTJIS_CHARSET:
6465 charset_type = Qw32_charset_shiftjis;
6466 break;
6467 case HANGEUL_CHARSET:
6468 charset_type = Qw32_charset_hangeul;
6469 break;
6470 case GB2312_CHARSET:
6471 charset_type = Qw32_charset_gb2312;
6472 break;
6473 case CHINESEBIG5_CHARSET:
6474 charset_type = Qw32_charset_chinesebig5;
6475 break;
6476 case OEM_CHARSET:
6477 charset_type = Qw32_charset_oem;
6478 break;
6479
6480 /* More recent versions of Windows (95 and NT4.0) define more
6481 character sets. */
6482 #ifdef EASTEUROPE_CHARSET
6483 case EASTEUROPE_CHARSET:
6484 charset_type = Qw32_charset_easteurope;
6485 break;
6486 case TURKISH_CHARSET:
6487 charset_type = Qw32_charset_turkish;
6488 break;
6489 case BALTIC_CHARSET:
6490 charset_type = Qw32_charset_baltic;
6491 break;
6492 case RUSSIAN_CHARSET:
6493 charset_type = Qw32_charset_russian;
6494 break;
6495 case ARABIC_CHARSET:
6496 charset_type = Qw32_charset_arabic;
6497 break;
6498 case GREEK_CHARSET:
6499 charset_type = Qw32_charset_greek;
6500 break;
6501 case HEBREW_CHARSET:
6502 charset_type = Qw32_charset_hebrew;
6503 break;
6504 case VIETNAMESE_CHARSET:
6505 charset_type = Qw32_charset_vietnamese;
6506 break;
6507 case THAI_CHARSET:
6508 charset_type = Qw32_charset_thai;
6509 break;
6510 case MAC_CHARSET:
6511 charset_type = Qw32_charset_mac;
6512 break;
6513 case JOHAB_CHARSET:
6514 charset_type = Qw32_charset_johab;
6515 break;
6516 #endif
6517
6518 #ifdef UNICODE_CHARSET
6519 case UNICODE_CHARSET:
6520 charset_type = Qw32_charset_unicode;
6521 break;
6522 #endif
6523 default:
6524 /* Encode numerical value of unknown charset. */
6525 sprintf (buf, "*-#%u", fncharset);
6526 return Fcons (build_string (buf), Qnil);
6527 }
6528
6529 {
6530 Lisp_Object rest;
6531 /* Look through w32-charset-info-alist for the character set.
6532 Only return charsets for codepages which are installed.
6533
6534 Format of each entry in Vw32_charset_info_alist is
6535 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
6536 */
6537 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
6538 {
6539 Lisp_Object x_charset;
6540 Lisp_Object w32_charset;
6541 Lisp_Object codepage;
6542
6543 Lisp_Object this_entry = XCAR (rest);
6544
6545 /* Skip invalid entries in alist. */
6546 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
6547 || !CONSP (XCDR (this_entry))
6548 || !SYMBOLP (XCAR (XCDR (this_entry))))
6549 continue;
6550
6551 x_charset = XCAR (this_entry);
6552 w32_charset = XCAR (XCDR (this_entry));
6553 codepage = XCDR (XCDR (this_entry));
6554
6555 /* Look for Same charset and a valid codepage (or non-int
6556 which means ignore). */
6557 if (w32_charset == charset_type
6558 && (!INTEGERP (codepage) || codepage == CP_DEFAULT
6559 || IsValidCodePage (XINT (codepage))))
6560 {
6561 retval = Fcons (x_charset, retval);
6562 }
6563 }
6564
6565 /* If no match, encode the numeric value. */
6566 if (NILP (retval))
6567 {
6568 sprintf (buf, "*-#%u", fncharset);
6569 return Fcons (build_string (buf), Qnil);
6570 }
6571
6572 return retval;
6573 }
6574 }
6575
6576 /* Get the Windows codepage corresponding to the specified font. The
6577 charset info in the font name is used to look up
6578 w32-charset-to-codepage-alist. */
6579 int
6580 w32_codepage_for_font (char *fontname)
6581 {
6582 Lisp_Object codepage, entry;
6583 char *charset_str, *charset, *end;
6584
6585 if (NILP (Vw32_charset_info_alist))
6586 return CP_DEFAULT;
6587
6588 /* Extract charset part of font string. */
6589 charset = xlfd_charset_of_font (fontname);
6590
6591 if (!charset)
6592 return CP_UNKNOWN;
6593
6594 charset_str = (char *) alloca (strlen (charset) + 1);
6595 strcpy (charset_str, charset);
6596
6597 #if 0
6598 /* Remove leading "*-". */
6599 if (strncmp ("*-", charset_str, 2) == 0)
6600 charset = charset_str + 2;
6601 else
6602 #endif
6603 charset = charset_str;
6604
6605 /* Stop match at wildcard (including preceding '-'). */
6606 if (end = strchr (charset, '*'))
6607 {
6608 if (end > charset && *(end-1) == '-')
6609 end--;
6610 *end = '\0';
6611 }
6612
6613 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
6614 if (NILP (entry))
6615 return CP_UNKNOWN;
6616
6617 codepage = Fcdr (Fcdr (entry));
6618
6619 if (NILP (codepage))
6620 return CP_8BIT;
6621 else if (XFASTINT (codepage) == XFASTINT (Qt))
6622 return CP_UNICODE;
6623 else if (INTEGERP (codepage))
6624 return XINT (codepage);
6625 else
6626 return CP_UNKNOWN;
6627 }
6628
6629
6630 static BOOL
6631 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
6632 LOGFONT * lplogfont;
6633 char * lpxstr;
6634 int len;
6635 char * specific_charset;
6636 {
6637 char* fonttype;
6638 char *fontname;
6639 char height_pixels[8];
6640 char height_dpi[8];
6641 char width_pixels[8];
6642 char *fontname_dash;
6643 int display_resy = one_w32_display_info.resy;
6644 int display_resx = one_w32_display_info.resx;
6645 int bufsz;
6646 struct coding_system coding;
6647
6648 if (!lpxstr) abort ();
6649
6650 if (!lplogfont)
6651 return FALSE;
6652
6653 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
6654 fonttype = "raster";
6655 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
6656 fonttype = "outline";
6657 else
6658 fonttype = "unknown";
6659
6660 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
6661 &coding);
6662 coding.src_multibyte = 0;
6663 coding.dst_multibyte = 1;
6664 coding.mode |= CODING_MODE_LAST_BLOCK;
6665 bufsz = decoding_buffer_size (&coding, LF_FACESIZE);
6666
6667 fontname = alloca(sizeof(*fontname) * bufsz);
6668 decode_coding (&coding, lplogfont->lfFaceName, fontname,
6669 strlen(lplogfont->lfFaceName), bufsz - 1);
6670 *(fontname + coding.produced) = '\0';
6671
6672 /* Replace dashes with underscores so the dashes are not
6673 misinterpreted. */
6674 fontname_dash = fontname;
6675 while (fontname_dash = strchr (fontname_dash, '-'))
6676 *fontname_dash = '_';
6677
6678 if (lplogfont->lfHeight)
6679 {
6680 sprintf (height_pixels, "%u", abs (lplogfont->lfHeight));
6681 sprintf (height_dpi, "%u",
6682 abs (lplogfont->lfHeight) * 720 / display_resy);
6683 }
6684 else
6685 {
6686 strcpy (height_pixels, "*");
6687 strcpy (height_dpi, "*");
6688 }
6689 if (lplogfont->lfWidth)
6690 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
6691 else
6692 strcpy (width_pixels, "*");
6693
6694 _snprintf (lpxstr, len - 1,
6695 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
6696 fonttype, /* foundry */
6697 fontname, /* family */
6698 w32_to_x_weight (lplogfont->lfWeight), /* weight */
6699 lplogfont->lfItalic?'i':'r', /* slant */
6700 /* setwidth name */
6701 /* add style name */
6702 height_pixels, /* pixel size */
6703 height_dpi, /* point size */
6704 display_resx, /* resx */
6705 display_resy, /* resy */
6706 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
6707 ? 'p' : 'c', /* spacing */
6708 width_pixels, /* avg width */
6709 specific_charset ? specific_charset
6710 : w32_to_x_charset (lplogfont->lfCharSet)
6711 /* charset registry and encoding */
6712 );
6713
6714 lpxstr[len - 1] = 0; /* just to be sure */
6715 return (TRUE);
6716 }
6717
6718 static BOOL
6719 x_to_w32_font (lpxstr, lplogfont)
6720 char * lpxstr;
6721 LOGFONT * lplogfont;
6722 {
6723 struct coding_system coding;
6724
6725 if (!lplogfont) return (FALSE);
6726
6727 memset (lplogfont, 0, sizeof (*lplogfont));
6728
6729 /* Set default value for each field. */
6730 #if 1
6731 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
6732 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
6733 lplogfont->lfQuality = DEFAULT_QUALITY;
6734 #else
6735 /* go for maximum quality */
6736 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
6737 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
6738 lplogfont->lfQuality = PROOF_QUALITY;
6739 #endif
6740
6741 lplogfont->lfCharSet = DEFAULT_CHARSET;
6742 lplogfont->lfWeight = FW_DONTCARE;
6743 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
6744
6745 if (!lpxstr)
6746 return FALSE;
6747
6748 /* Provide a simple escape mechanism for specifying Windows font names
6749 * directly -- if font spec does not beginning with '-', assume this
6750 * format:
6751 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
6752 */
6753
6754 if (*lpxstr == '-')
6755 {
6756 int fields, tem;
6757 char name[50], weight[20], slant, pitch, pixels[10], height[10],
6758 width[10], resy[10], remainder[50];
6759 char * encoding;
6760 int dpi = one_w32_display_info.resy;
6761
6762 fields = sscanf (lpxstr,
6763 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
6764 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
6765 if (fields == EOF)
6766 return (FALSE);
6767
6768 /* In the general case when wildcards cover more than one field,
6769 we don't know which field is which, so don't fill any in.
6770 However, we need to cope with this particular form, which is
6771 generated by font_list_1 (invoked by try_font_list):
6772 "-raster-6x10-*-gb2312*-*"
6773 and make sure to correctly parse the charset field. */
6774 if (fields == 3)
6775 {
6776 fields = sscanf (lpxstr,
6777 "-%*[^-]-%49[^-]-*-%49s",
6778 name, remainder);
6779 }
6780 else if (fields < 9)
6781 {
6782 fields = 0;
6783 remainder[0] = 0;
6784 }
6785
6786 if (fields > 0 && name[0] != '*')
6787 {
6788 int bufsize;
6789 unsigned char *buf;
6790
6791 setup_coding_system
6792 (Fcheck_coding_system (Vlocale_coding_system), &coding);
6793 coding.src_multibyte = 1;
6794 coding.dst_multibyte = 1;
6795 bufsize = encoding_buffer_size (&coding, strlen (name));
6796 buf = (unsigned char *) alloca (bufsize);
6797 coding.mode |= CODING_MODE_LAST_BLOCK;
6798 encode_coding (&coding, name, buf, strlen (name), bufsize);
6799 if (coding.produced >= LF_FACESIZE)
6800 coding.produced = LF_FACESIZE - 1;
6801 buf[coding.produced] = 0;
6802 strcpy (lplogfont->lfFaceName, buf);
6803 }
6804 else
6805 {
6806 lplogfont->lfFaceName[0] = '\0';
6807 }
6808
6809 fields--;
6810
6811 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6812
6813 fields--;
6814
6815 lplogfont->lfItalic = (fields > 0 && slant == 'i');
6816
6817 fields--;
6818
6819 if (fields > 0 && pixels[0] != '*')
6820 lplogfont->lfHeight = atoi (pixels);
6821
6822 fields--;
6823 fields--;
6824 if (fields > 0 && resy[0] != '*')
6825 {
6826 tem = atoi (resy);
6827 if (tem > 0) dpi = tem;
6828 }
6829
6830 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
6831 lplogfont->lfHeight = atoi (height) * dpi / 720;
6832
6833 if (fields > 0)
6834 lplogfont->lfPitchAndFamily =
6835 (fields > 0 && pitch == 'p') ? VARIABLE_PITCH : FIXED_PITCH;
6836
6837 fields--;
6838
6839 if (fields > 0 && width[0] != '*')
6840 lplogfont->lfWidth = atoi (width) / 10;
6841
6842 fields--;
6843
6844 /* Strip the trailing '-' if present. (it shouldn't be, as it
6845 fails the test against xlfd-tight-regexp in fontset.el). */
6846 {
6847 int len = strlen (remainder);
6848 if (len > 0 && remainder[len-1] == '-')
6849 remainder[len-1] = 0;
6850 }
6851 encoding = remainder;
6852 #if 0
6853 if (strncmp (encoding, "*-", 2) == 0)
6854 encoding += 2;
6855 #endif
6856 lplogfont->lfCharSet = x_to_w32_charset (encoding);
6857 }
6858 else
6859 {
6860 int fields;
6861 char name[100], height[10], width[10], weight[20];
6862
6863 fields = sscanf (lpxstr,
6864 "%99[^:]:%9[^:]:%9[^:]:%19s",
6865 name, height, width, weight);
6866
6867 if (fields == EOF) return (FALSE);
6868
6869 if (fields > 0)
6870 {
6871 strncpy (lplogfont->lfFaceName,name, LF_FACESIZE);
6872 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
6873 }
6874 else
6875 {
6876 lplogfont->lfFaceName[0] = 0;
6877 }
6878
6879 fields--;
6880
6881 if (fields > 0)
6882 lplogfont->lfHeight = atoi (height);
6883
6884 fields--;
6885
6886 if (fields > 0)
6887 lplogfont->lfWidth = atoi (width);
6888
6889 fields--;
6890
6891 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
6892 }
6893
6894 /* This makes TrueType fonts work better. */
6895 lplogfont->lfHeight = - abs (lplogfont->lfHeight);
6896
6897 return (TRUE);
6898 }
6899
6900 /* Strip the pixel height and point height from the given xlfd, and
6901 return the pixel height. If no pixel height is specified, calculate
6902 one from the point height, or if that isn't defined either, return
6903 0 (which usually signifies a scalable font).
6904 */
6905 static int
6906 xlfd_strip_height (char *fontname)
6907 {
6908 int pixel_height, field_number;
6909 char *read_from, *write_to;
6910
6911 xassert (fontname);
6912
6913 pixel_height = field_number = 0;
6914 write_to = NULL;
6915
6916 /* Look for height fields. */
6917 for (read_from = fontname; *read_from; read_from++)
6918 {
6919 if (*read_from == '-')
6920 {
6921 field_number++;
6922 if (field_number == 7) /* Pixel height. */
6923 {
6924 read_from++;
6925 write_to = read_from;
6926
6927 /* Find end of field. */
6928 for (;*read_from && *read_from != '-'; read_from++)
6929 ;
6930
6931 /* Split the fontname at end of field. */
6932 if (*read_from)
6933 {
6934 *read_from = '\0';
6935 read_from++;
6936 }
6937 pixel_height = atoi (write_to);
6938 /* Blank out field. */
6939 if (read_from > write_to)
6940 {
6941 *write_to = '-';
6942 write_to++;
6943 }
6944 /* If the pixel height field is at the end (partial xlfd),
6945 return now. */
6946 else
6947 return pixel_height;
6948
6949 /* If we got a pixel height, the point height can be
6950 ignored. Just blank it out and break now. */
6951 if (pixel_height)
6952 {
6953 /* Find end of point size field. */
6954 for (; *read_from && *read_from != '-'; read_from++)
6955 ;
6956
6957 if (*read_from)
6958 read_from++;
6959
6960 /* Blank out the point size field. */
6961 if (read_from > write_to)
6962 {
6963 *write_to = '-';
6964 write_to++;
6965 }
6966 else
6967 return pixel_height;
6968
6969 break;
6970 }
6971 /* If the point height is already blank, break now. */
6972 if (*read_from == '-')
6973 {
6974 read_from++;
6975 break;
6976 }
6977 }
6978 else if (field_number == 8)
6979 {
6980 /* If we didn't get a pixel height, try to get the point
6981 height and convert that. */
6982 int point_size;
6983 char *point_size_start = read_from++;
6984
6985 /* Find end of field. */
6986 for (; *read_from && *read_from != '-'; read_from++)
6987 ;
6988
6989 if (*read_from)
6990 {
6991 *read_from = '\0';
6992 read_from++;
6993 }
6994
6995 point_size = atoi (point_size_start);
6996
6997 /* Convert to pixel height. */
6998 pixel_height = point_size
6999 * one_w32_display_info.height_in / 720;
7000
7001 /* Blank out this field and break. */
7002 *write_to = '-';
7003 write_to++;
7004 break;
7005 }
7006 }
7007 }
7008
7009 /* Shift the rest of the font spec into place. */
7010 if (write_to && read_from > write_to)
7011 {
7012 for (; *read_from; read_from++, write_to++)
7013 *write_to = *read_from;
7014 *write_to = '\0';
7015 }
7016
7017 return pixel_height;
7018 }
7019
7020 /* Assume parameter 1 is fully qualified, no wildcards. */
7021 static BOOL
7022 w32_font_match (fontname, pattern)
7023 char * fontname;
7024 char * pattern;
7025 {
7026 char *regex = alloca (strlen (pattern) * 2 + 3);
7027 char *font_name_copy = alloca (strlen (fontname) + 1);
7028 char *ptr;
7029
7030 /* Copy fontname so we can modify it during comparison. */
7031 strcpy (font_name_copy, fontname);
7032
7033 ptr = regex;
7034 *ptr++ = '^';
7035
7036 /* Turn pattern into a regexp and do a regexp match. */
7037 for (; *pattern; pattern++)
7038 {
7039 if (*pattern == '?')
7040 *ptr++ = '.';
7041 else if (*pattern == '*')
7042 {
7043 *ptr++ = '.';
7044 *ptr++ = '*';
7045 }
7046 else
7047 *ptr++ = *pattern;
7048 }
7049 *ptr = '$';
7050 *(ptr + 1) = '\0';
7051
7052 /* Strip out font heights and compare them seperately, since
7053 rounding error can cause mismatches. This also allows a
7054 comparison between a font that declares only a pixel height and a
7055 pattern that declares the point height.
7056 */
7057 {
7058 int font_height, pattern_height;
7059
7060 font_height = xlfd_strip_height (font_name_copy);
7061 pattern_height = xlfd_strip_height (regex);
7062
7063 /* Compare now, and don't bother doing expensive regexp matching
7064 if the heights differ. */
7065 if (font_height && pattern_height && (font_height != pattern_height))
7066 return FALSE;
7067 }
7068
7069 return (fast_c_string_match_ignore_case (build_string (regex),
7070 font_name_copy) >= 0);
7071 }
7072
7073 /* Callback functions, and a structure holding info they need, for
7074 listing system fonts on W32. We need one set of functions to do the
7075 job properly, but these don't work on NT 3.51 and earlier, so we
7076 have a second set which don't handle character sets properly to
7077 fall back on.
7078
7079 In both cases, there are two passes made. The first pass gets one
7080 font from each family, the second pass lists all the fonts from
7081 each family. */
7082
7083 typedef struct enumfont_t
7084 {
7085 HDC hdc;
7086 int numFonts;
7087 LOGFONT logfont;
7088 XFontStruct *size_ref;
7089 Lisp_Object *pattern;
7090 Lisp_Object list;
7091 Lisp_Object *tail;
7092 } enumfont_t;
7093
7094
7095 static void
7096 enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
7097
7098
7099 static int CALLBACK
7100 enum_font_cb2 (lplf, lptm, FontType, lpef)
7101 ENUMLOGFONT * lplf;
7102 NEWTEXTMETRIC * lptm;
7103 int FontType;
7104 enumfont_t * lpef;
7105 {
7106 /* Ignore struck out and underlined versions of fonts. */
7107 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
7108 return 1;
7109
7110 /* Only return fonts with names starting with @ if they were
7111 explicitly specified, since Microsoft uses an initial @ to
7112 denote fonts for vertical writing, without providing a more
7113 convenient way of identifying them. */
7114 if (lplf->elfLogFont.lfFaceName[0] == '@'
7115 && lpef->logfont.lfFaceName[0] != '@')
7116 return 1;
7117
7118 /* Check that the character set matches if it was specified */
7119 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
7120 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
7121 return 1;
7122
7123 {
7124 char buf[100];
7125 Lisp_Object width = Qnil;
7126 Lisp_Object charset_list = Qnil;
7127 char *charset = NULL;
7128
7129 /* Truetype fonts do not report their true metrics until loaded */
7130 if (FontType != RASTER_FONTTYPE)
7131 {
7132 if (!NILP (*(lpef->pattern)))
7133 {
7134 /* Scalable fonts are as big as you want them to be. */
7135 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
7136 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
7137 width = make_number (lpef->logfont.lfWidth);
7138 }
7139 else
7140 {
7141 lplf->elfLogFont.lfHeight = 0;
7142 lplf->elfLogFont.lfWidth = 0;
7143 }
7144 }
7145
7146 /* Make sure the height used here is the same as everywhere
7147 else (ie character height, not cell height). */
7148 if (lplf->elfLogFont.lfHeight > 0)
7149 {
7150 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
7151 if (FontType == RASTER_FONTTYPE)
7152 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
7153 else
7154 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
7155 }
7156
7157 if (!NILP (*(lpef->pattern)))
7158 {
7159 charset = xlfd_charset_of_font (XSTRING(*(lpef->pattern))->data);
7160
7161 /* We already checked charsets above, but DEFAULT_CHARSET
7162 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
7163 if (charset
7164 && strncmp (charset, "*-*", 3) != 0
7165 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
7166 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET)) != 0)
7167 return 1;
7168 }
7169
7170 if (charset)
7171 charset_list = Fcons (build_string (charset), Qnil);
7172 else
7173 charset_list = w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet);
7174
7175 /* Loop through the charsets. */
7176 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
7177 {
7178 Lisp_Object this_charset = Fcar (charset_list);
7179 charset = XSTRING (this_charset)->data;
7180
7181 /* List bold and italic variations if w32-enable-synthesized-fonts
7182 is non-nil and this is a plain font. */
7183 if (w32_enable_synthesized_fonts
7184 && lplf->elfLogFont.lfWeight == FW_NORMAL
7185 && lplf->elfLogFont.lfItalic == FALSE)
7186 {
7187 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7188 charset, width);
7189 /* bold. */
7190 lplf->elfLogFont.lfWeight = FW_BOLD;
7191 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7192 charset, width);
7193 /* bold italic. */
7194 lplf->elfLogFont.lfItalic = TRUE;
7195 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7196 charset, width);
7197 /* italic. */
7198 lplf->elfLogFont.lfWeight = FW_NORMAL;
7199 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7200 charset, width);
7201 }
7202 else
7203 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
7204 charset, width);
7205 }
7206 }
7207
7208 return 1;
7209 }
7210
7211 static void
7212 enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
7213 enumfont_t * lpef;
7214 LOGFONT * logfont;
7215 char * match_charset;
7216 Lisp_Object width;
7217 {
7218 char buf[100];
7219
7220 if (!w32_to_x_font (logfont, buf, 100, match_charset))
7221 return;
7222
7223 if (NILP (*(lpef->pattern))
7224 || w32_font_match (buf, XSTRING (*(lpef->pattern))->data))
7225 {
7226 /* Check if we already listed this font. This may happen if
7227 w32_enable_synthesized_fonts is non-nil, and there are real
7228 bold and italic versions of the font. */
7229 Lisp_Object font_name = build_string (buf);
7230 if (NILP (Fmember (font_name, lpef->list)))
7231 {
7232 *lpef->tail = Fcons (Fcons (build_string (buf), width), Qnil);
7233 lpef->tail = &(XCDR (*lpef->tail));
7234 lpef->numFonts++;
7235 }
7236 }
7237 }
7238
7239
7240 static int CALLBACK
7241 enum_font_cb1 (lplf, lptm, FontType, lpef)
7242 ENUMLOGFONT * lplf;
7243 NEWTEXTMETRIC * lptm;
7244 int FontType;
7245 enumfont_t * lpef;
7246 {
7247 return EnumFontFamilies (lpef->hdc,
7248 lplf->elfLogFont.lfFaceName,
7249 (FONTENUMPROC) enum_font_cb2,
7250 (LPARAM) lpef);
7251 }
7252
7253
7254 static int CALLBACK
7255 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
7256 ENUMLOGFONTEX * lplf;
7257 NEWTEXTMETRICEX * lptm;
7258 int font_type;
7259 enumfont_t * lpef;
7260 {
7261 /* We are not interested in the extra info we get back from the 'Ex
7262 version - only the fact that we get character set variations
7263 enumerated seperately. */
7264 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
7265 font_type, lpef);
7266 }
7267
7268 static int CALLBACK
7269 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
7270 ENUMLOGFONTEX * lplf;
7271 NEWTEXTMETRICEX * lptm;
7272 int font_type;
7273 enumfont_t * lpef;
7274 {
7275 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7276 FARPROC enum_font_families_ex
7277 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7278 /* We don't really expect EnumFontFamiliesEx to disappear once we
7279 get here, so don't bother handling it gracefully. */
7280 if (enum_font_families_ex == NULL)
7281 error ("gdi32.dll has disappeared!");
7282 return enum_font_families_ex (lpef->hdc,
7283 &lplf->elfLogFont,
7284 (FONTENUMPROC) enum_fontex_cb2,
7285 (LPARAM) lpef, 0);
7286 }
7287
7288 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
7289 and xterm.c in Emacs 20.3) */
7290
7291 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
7292 {
7293 char *fontname, *ptnstr;
7294 Lisp_Object list, tem, newlist = Qnil;
7295 int n_fonts = 0;
7296
7297 list = Vw32_bdf_filename_alist;
7298 ptnstr = XSTRING (pattern)->data;
7299
7300 for ( ; CONSP (list); list = XCDR (list))
7301 {
7302 tem = XCAR (list);
7303 if (CONSP (tem))
7304 fontname = XSTRING (XCAR (tem))->data;
7305 else if (STRINGP (tem))
7306 fontname = XSTRING (tem)->data;
7307 else
7308 continue;
7309
7310 if (w32_font_match (fontname, ptnstr))
7311 {
7312 newlist = Fcons (XCAR (tem), newlist);
7313 n_fonts++;
7314 if (n_fonts >= max_names)
7315 break;
7316 }
7317 }
7318
7319 return newlist;
7320 }
7321
7322
7323 /* Return a list of names of available fonts matching PATTERN on frame
7324 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
7325 to be listed. Frame F NULL means we have not yet created any
7326 frame, which means we can't get proper size info, as we don't have
7327 a device context to use for GetTextMetrics.
7328 MAXNAMES sets a limit on how many fonts to match. */
7329
7330 Lisp_Object
7331 w32_list_fonts (f, pattern, size, maxnames)
7332 struct frame *f;
7333 Lisp_Object pattern;
7334 int size;
7335 int maxnames;
7336 {
7337 Lisp_Object patterns, key = Qnil, tem, tpat;
7338 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
7339 struct w32_display_info *dpyinfo = &one_w32_display_info;
7340 int n_fonts = 0;
7341
7342 patterns = Fassoc (pattern, Valternate_fontname_alist);
7343 if (NILP (patterns))
7344 patterns = Fcons (pattern, Qnil);
7345
7346 for (; CONSP (patterns); patterns = XCDR (patterns))
7347 {
7348 enumfont_t ef;
7349 int codepage;
7350
7351 tpat = XCAR (patterns);
7352
7353 if (!STRINGP (tpat))
7354 continue;
7355
7356 /* Avoid expensive EnumFontFamilies functions if we are not
7357 going to be able to output one of these anyway. */
7358 codepage = w32_codepage_for_font (XSTRING (tpat)->data);
7359 if (codepage != CP_8BIT && codepage != CP_UNICODE
7360 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
7361 && !IsValidCodePage(codepage))
7362 continue;
7363
7364 /* See if we cached the result for this particular query.
7365 The cache is an alist of the form:
7366 ((PATTERN (FONTNAME . WIDTH) ...) ...)
7367 */
7368 if (tem = XCDR (dpyinfo->name_list_element),
7369 !NILP (list = Fassoc (tpat, tem)))
7370 {
7371 list = Fcdr_safe (list);
7372 /* We have a cached list. Don't have to get the list again. */
7373 goto label_cached;
7374 }
7375
7376 BLOCK_INPUT;
7377 /* At first, put PATTERN in the cache. */
7378 list = Qnil;
7379 ef.pattern = &tpat;
7380 ef.list = list;
7381 ef.tail = &list;
7382 ef.numFonts = 0;
7383
7384 /* Use EnumFontFamiliesEx where it is available, as it knows
7385 about character sets. Fall back to EnumFontFamilies for
7386 older versions of NT that don't support the 'Ex function. */
7387 x_to_w32_font (XSTRING (tpat)->data, &ef.logfont);
7388 {
7389 LOGFONT font_match_pattern;
7390 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
7391 FARPROC enum_font_families_ex
7392 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
7393
7394 /* We do our own pattern matching so we can handle wildcards. */
7395 font_match_pattern.lfFaceName[0] = 0;
7396 font_match_pattern.lfPitchAndFamily = 0;
7397 /* We can use the charset, because if it is a wildcard it will
7398 be DEFAULT_CHARSET anyway. */
7399 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
7400
7401 ef.hdc = GetDC (dpyinfo->root_window);
7402
7403 if (enum_font_families_ex)
7404 enum_font_families_ex (ef.hdc,
7405 &font_match_pattern,
7406 (FONTENUMPROC) enum_fontex_cb1,
7407 (LPARAM) &ef, 0);
7408 else
7409 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
7410 (LPARAM)&ef);
7411
7412 ReleaseDC (dpyinfo->root_window, ef.hdc);
7413 }
7414
7415 UNBLOCK_INPUT;
7416
7417 /* Make a list of the fonts we got back.
7418 Store that in the font cache for the display. */
7419 XSETCDR (dpyinfo->name_list_element,
7420 Fcons (Fcons (tpat, list),
7421 XCDR (dpyinfo->name_list_element)));
7422
7423 label_cached:
7424 if (NILP (list)) continue; /* Try the remaining alternatives. */
7425
7426 newlist = second_best = Qnil;
7427
7428 /* Make a list of the fonts that have the right width. */
7429 for (; CONSP (list); list = XCDR (list))
7430 {
7431 int found_size;
7432 tem = XCAR (list);
7433
7434 if (!CONSP (tem))
7435 continue;
7436 if (NILP (XCAR (tem)))
7437 continue;
7438 if (!size)
7439 {
7440 newlist = Fcons (XCAR (tem), newlist);
7441 n_fonts++;
7442 if (n_fonts >= maxnames)
7443 break;
7444 else
7445 continue;
7446 }
7447 if (!INTEGERP (XCDR (tem)))
7448 {
7449 /* Since we don't yet know the size of the font, we must
7450 load it and try GetTextMetrics. */
7451 W32FontStruct thisinfo;
7452 LOGFONT lf;
7453 HDC hdc;
7454 HANDLE oldobj;
7455
7456 if (!x_to_w32_font (XSTRING (XCAR (tem))->data, &lf))
7457 continue;
7458
7459 BLOCK_INPUT;
7460 thisinfo.bdf = NULL;
7461 thisinfo.hfont = CreateFontIndirect (&lf);
7462 if (thisinfo.hfont == NULL)
7463 continue;
7464
7465 hdc = GetDC (dpyinfo->root_window);
7466 oldobj = SelectObject (hdc, thisinfo.hfont);
7467 if (GetTextMetrics (hdc, &thisinfo.tm))
7468 XSETCDR (tem, make_number (FONT_WIDTH (&thisinfo)));
7469 else
7470 XSETCDR (tem, make_number (0));
7471 SelectObject (hdc, oldobj);
7472 ReleaseDC (dpyinfo->root_window, hdc);
7473 DeleteObject(thisinfo.hfont);
7474 UNBLOCK_INPUT;
7475 }
7476 found_size = XINT (XCDR (tem));
7477 if (found_size == size)
7478 {
7479 newlist = Fcons (XCAR (tem), newlist);
7480 n_fonts++;
7481 if (n_fonts >= maxnames)
7482 break;
7483 }
7484 /* keep track of the closest matching size in case
7485 no exact match is found. */
7486 else if (found_size > 0)
7487 {
7488 if (NILP (second_best))
7489 second_best = tem;
7490
7491 else if (found_size < size)
7492 {
7493 if (XINT (XCDR (second_best)) > size
7494 || XINT (XCDR (second_best)) < found_size)
7495 second_best = tem;
7496 }
7497 else
7498 {
7499 if (XINT (XCDR (second_best)) > size
7500 && XINT (XCDR (second_best)) >
7501 found_size)
7502 second_best = tem;
7503 }
7504 }
7505 }
7506
7507 if (!NILP (newlist))
7508 break;
7509 else if (!NILP (second_best))
7510 {
7511 newlist = Fcons (XCAR (second_best), Qnil);
7512 break;
7513 }
7514 }
7515
7516 /* Include any bdf fonts. */
7517 if (n_fonts < maxnames)
7518 {
7519 Lisp_Object combined[2];
7520 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
7521 combined[1] = newlist;
7522 newlist = Fnconc(2, combined);
7523 }
7524
7525 return newlist;
7526 }
7527
7528
7529 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
7530 struct font_info *
7531 w32_get_font_info (f, font_idx)
7532 FRAME_PTR f;
7533 int font_idx;
7534 {
7535 return (FRAME_W32_FONT_TABLE (f) + font_idx);
7536 }
7537
7538
7539 struct font_info*
7540 w32_query_font (struct frame *f, char *fontname)
7541 {
7542 int i;
7543 struct font_info *pfi;
7544
7545 pfi = FRAME_W32_FONT_TABLE (f);
7546
7547 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
7548 {
7549 if (strcmp(pfi->name, fontname) == 0) return pfi;
7550 }
7551
7552 return NULL;
7553 }
7554
7555 /* Find a CCL program for a font specified by FONTP, and set the member
7556 `encoder' of the structure. */
7557
7558 void
7559 w32_find_ccl_program (fontp)
7560 struct font_info *fontp;
7561 {
7562 Lisp_Object list, elt;
7563
7564 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
7565 {
7566 elt = XCAR (list);
7567 if (CONSP (elt)
7568 && STRINGP (XCAR (elt))
7569 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
7570 >= 0))
7571 break;
7572 }
7573 if (! NILP (list))
7574 {
7575 struct ccl_program *ccl
7576 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
7577
7578 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
7579 xfree (ccl);
7580 else
7581 fontp->font_encoder = ccl;
7582 }
7583 }
7584
7585 \f
7586 /* Find BDF files in a specified directory. (use GCPRO when calling,
7587 as this calls lisp to get a directory listing). */
7588 static Lisp_Object
7589 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
7590 {
7591 Lisp_Object filelist, list = Qnil;
7592 char fontname[100];
7593
7594 if (!STRINGP(directory))
7595 return Qnil;
7596
7597 filelist = Fdirectory_files (directory, Qt,
7598 build_string (".*\\.[bB][dD][fF]"), Qt);
7599
7600 for ( ; CONSP(filelist); filelist = XCDR (filelist))
7601 {
7602 Lisp_Object filename = XCAR (filelist);
7603 if (w32_BDF_to_x_font (XSTRING (filename)->data, fontname, 100))
7604 store_in_alist (&list, build_string (fontname), filename);
7605 }
7606 return list;
7607 }
7608
7609 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
7610 1, 1, 0,
7611 doc: /* Return a list of BDF fonts in DIR.
7612 The list is suitable for appending to w32-bdf-filename-alist. Fonts
7613 which do not contain an xlfd description will not be included in the
7614 list. DIR may be a list of directories. */)
7615 (directory)
7616 Lisp_Object directory;
7617 {
7618 Lisp_Object list = Qnil;
7619 struct gcpro gcpro1, gcpro2;
7620
7621 if (!CONSP (directory))
7622 return w32_find_bdf_fonts_in_dir (directory);
7623
7624 for ( ; CONSP (directory); directory = XCDR (directory))
7625 {
7626 Lisp_Object pair[2];
7627 pair[0] = list;
7628 pair[1] = Qnil;
7629 GCPRO2 (directory, list);
7630 pair[1] = w32_find_bdf_fonts_in_dir( XCAR (directory) );
7631 list = Fnconc( 2, pair );
7632 UNGCPRO;
7633 }
7634 return list;
7635 }
7636
7637 \f
7638 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
7639 doc: /* Internal function called by `color-defined-p', which see. */)
7640 (color, frame)
7641 Lisp_Object color, frame;
7642 {
7643 XColor foo;
7644 FRAME_PTR f = check_x_frame (frame);
7645
7646 CHECK_STRING (color);
7647
7648 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7649 return Qt;
7650 else
7651 return Qnil;
7652 }
7653
7654 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
7655 doc: /* Internal function called by `color-values', which see. */)
7656 (color, frame)
7657 Lisp_Object color, frame;
7658 {
7659 XColor foo;
7660 FRAME_PTR f = check_x_frame (frame);
7661
7662 CHECK_STRING (color);
7663
7664 if (w32_defined_color (f, XSTRING (color)->data, &foo, 0))
7665 {
7666 Lisp_Object rgb[3];
7667
7668 rgb[0] = make_number ((GetRValue (foo.pixel) << 8)
7669 | GetRValue (foo.pixel));
7670 rgb[1] = make_number ((GetGValue (foo.pixel) << 8)
7671 | GetGValue (foo.pixel));
7672 rgb[2] = make_number ((GetBValue (foo.pixel) << 8)
7673 | GetBValue (foo.pixel));
7674 return Flist (3, rgb);
7675 }
7676 else
7677 return Qnil;
7678 }
7679
7680 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
7681 doc: /* Internal function called by `display-color-p', which see. */)
7682 (display)
7683 Lisp_Object display;
7684 {
7685 struct w32_display_info *dpyinfo = check_x_display_info (display);
7686
7687 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
7688 return Qnil;
7689
7690 return Qt;
7691 }
7692
7693 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
7694 Sx_display_grayscale_p, 0, 1, 0,
7695 doc: /* Return t if the X display supports shades of gray.
7696 Note that color displays do support shades of gray.
7697 The optional argument DISPLAY specifies which display to ask about.
7698 DISPLAY should be either a frame or a display name (a string).
7699 If omitted or nil, that stands for the selected frame's display. */)
7700 (display)
7701 Lisp_Object display;
7702 {
7703 struct w32_display_info *dpyinfo = check_x_display_info (display);
7704
7705 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
7706 return Qnil;
7707
7708 return Qt;
7709 }
7710
7711 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
7712 Sx_display_pixel_width, 0, 1, 0,
7713 doc: /* Returns the width in pixels of DISPLAY.
7714 The optional argument DISPLAY specifies which display to ask about.
7715 DISPLAY should be either a frame or a display name (a string).
7716 If omitted or nil, that stands for the selected frame's display. */)
7717 (display)
7718 Lisp_Object display;
7719 {
7720 struct w32_display_info *dpyinfo = check_x_display_info (display);
7721
7722 return make_number (dpyinfo->width);
7723 }
7724
7725 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
7726 Sx_display_pixel_height, 0, 1, 0,
7727 doc: /* Returns the height in pixels of DISPLAY.
7728 The optional argument DISPLAY specifies which display to ask about.
7729 DISPLAY should be either a frame or a display name (a string).
7730 If omitted or nil, that stands for the selected frame's display. */)
7731 (display)
7732 Lisp_Object display;
7733 {
7734 struct w32_display_info *dpyinfo = check_x_display_info (display);
7735
7736 return make_number (dpyinfo->height);
7737 }
7738
7739 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
7740 0, 1, 0,
7741 doc: /* Returns the number of bitplanes of DISPLAY.
7742 The optional argument DISPLAY specifies which display to ask about.
7743 DISPLAY should be either a frame or a display name (a string).
7744 If omitted or nil, that stands for the selected frame's display. */)
7745 (display)
7746 Lisp_Object display;
7747 {
7748 struct w32_display_info *dpyinfo = check_x_display_info (display);
7749
7750 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
7751 }
7752
7753 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
7754 0, 1, 0,
7755 doc: /* Returns the number of color cells of DISPLAY.
7756 The optional argument DISPLAY specifies which display to ask about.
7757 DISPLAY should be either a frame or a display name (a string).
7758 If omitted or nil, that stands for the selected frame's display. */)
7759 (display)
7760 Lisp_Object display;
7761 {
7762 struct w32_display_info *dpyinfo = check_x_display_info (display);
7763 HDC hdc;
7764 int cap;
7765
7766 hdc = GetDC (dpyinfo->root_window);
7767 if (dpyinfo->has_palette)
7768 cap = GetDeviceCaps (hdc,SIZEPALETTE);
7769 else
7770 cap = GetDeviceCaps (hdc,NUMCOLORS);
7771
7772 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
7773 and because probably is more meaningful on Windows anyway */
7774 if (cap < 0)
7775 cap = 1 << min(dpyinfo->n_planes * dpyinfo->n_cbits, 24);
7776
7777 ReleaseDC (dpyinfo->root_window, hdc);
7778
7779 return make_number (cap);
7780 }
7781
7782 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
7783 Sx_server_max_request_size,
7784 0, 1, 0,
7785 doc: /* Returns the maximum request size of the server of DISPLAY.
7786 The optional argument DISPLAY specifies which display to ask about.
7787 DISPLAY should be either a frame or a display name (a string).
7788 If omitted or nil, that stands for the selected frame's display. */)
7789 (display)
7790 Lisp_Object display;
7791 {
7792 struct w32_display_info *dpyinfo = check_x_display_info (display);
7793
7794 return make_number (1);
7795 }
7796
7797 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
7798 doc: /* Returns the vendor ID string of the W32 system (Microsoft).
7799 The optional argument DISPLAY specifies which display to ask about.
7800 DISPLAY should be either a frame or a display name (a string).
7801 If omitted or nil, that stands for the selected frame's display. */)
7802 (display)
7803 Lisp_Object display;
7804 {
7805 return build_string ("Microsoft Corp.");
7806 }
7807
7808 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
7809 doc: /* Returns the version numbers of the server of DISPLAY.
7810 The value is a list of three integers: the major and minor
7811 version numbers, and the vendor-specific release
7812 number. See also the function `x-server-vendor'.
7813
7814 The optional argument DISPLAY specifies which display to ask about.
7815 DISPLAY should be either a frame or a display name (a string).
7816 If omitted or nil, that stands for the selected frame's display. */)
7817 (display)
7818 Lisp_Object display;
7819 {
7820 return Fcons (make_number (w32_major_version),
7821 Fcons (make_number (w32_minor_version),
7822 Fcons (make_number (w32_build_number), Qnil)));
7823 }
7824
7825 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
7826 doc: /* Returns the number of screens on the server of DISPLAY.
7827 The optional argument DISPLAY specifies which display to ask about.
7828 DISPLAY should be either a frame or a display name (a string).
7829 If omitted or nil, that stands for the selected frame's display. */)
7830 (display)
7831 Lisp_Object display;
7832 {
7833 return make_number (1);
7834 }
7835
7836 DEFUN ("x-display-mm-height", Fx_display_mm_height,
7837 Sx_display_mm_height, 0, 1, 0,
7838 doc: /* Returns the height in millimeters of DISPLAY.
7839 The optional argument DISPLAY specifies which display to ask about.
7840 DISPLAY should be either a frame or a display name (a string).
7841 If omitted or nil, that stands for the selected frame's display. */)
7842 (display)
7843 Lisp_Object display;
7844 {
7845 struct w32_display_info *dpyinfo = check_x_display_info (display);
7846 HDC hdc;
7847 int cap;
7848
7849 hdc = GetDC (dpyinfo->root_window);
7850
7851 cap = GetDeviceCaps (hdc, VERTSIZE);
7852
7853 ReleaseDC (dpyinfo->root_window, hdc);
7854
7855 return make_number (cap);
7856 }
7857
7858 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
7859 doc: /* Returns the width in millimeters of DISPLAY.
7860 The optional argument DISPLAY specifies which display to ask about.
7861 DISPLAY should be either a frame or a display name (a string).
7862 If omitted or nil, that stands for the selected frame's display. */)
7863 (display)
7864 Lisp_Object display;
7865 {
7866 struct w32_display_info *dpyinfo = check_x_display_info (display);
7867
7868 HDC hdc;
7869 int cap;
7870
7871 hdc = GetDC (dpyinfo->root_window);
7872
7873 cap = GetDeviceCaps (hdc, HORZSIZE);
7874
7875 ReleaseDC (dpyinfo->root_window, hdc);
7876
7877 return make_number (cap);
7878 }
7879
7880 DEFUN ("x-display-backing-store", Fx_display_backing_store,
7881 Sx_display_backing_store, 0, 1, 0,
7882 doc: /* Returns an indication of whether DISPLAY does backing store.
7883 The value may be `always', `when-mapped', or `not-useful'.
7884 The optional argument DISPLAY specifies which display to ask about.
7885 DISPLAY should be either a frame or a display name (a string).
7886 If omitted or nil, that stands for the selected frame's display. */)
7887 (display)
7888 Lisp_Object display;
7889 {
7890 return intern ("not-useful");
7891 }
7892
7893 DEFUN ("x-display-visual-class", Fx_display_visual_class,
7894 Sx_display_visual_class, 0, 1, 0,
7895 doc: /* Returns the visual class of DISPLAY.
7896 The value is one of the symbols `static-gray', `gray-scale',
7897 `static-color', `pseudo-color', `true-color', or `direct-color'.
7898
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 Lisp_Object result = Qnil;
7907
7908 if (dpyinfo->has_palette)
7909 result = intern ("pseudo-color");
7910 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
7911 result = intern ("static-grey");
7912 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
7913 result = intern ("static-color");
7914 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
7915 result = intern ("true-color");
7916
7917 return result;
7918 }
7919
7920 DEFUN ("x-display-save-under", Fx_display_save_under,
7921 Sx_display_save_under, 0, 1, 0,
7922 doc: /* Returns t if DISPLAY supports the save-under feature.
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 Qnil;
7930 }
7931 \f
7932 int
7933 x_pixel_width (f)
7934 register struct frame *f;
7935 {
7936 return PIXEL_WIDTH (f);
7937 }
7938
7939 int
7940 x_pixel_height (f)
7941 register struct frame *f;
7942 {
7943 return PIXEL_HEIGHT (f);
7944 }
7945
7946 int
7947 x_char_width (f)
7948 register struct frame *f;
7949 {
7950 return FONT_WIDTH (f->output_data.w32->font);
7951 }
7952
7953 int
7954 x_char_height (f)
7955 register struct frame *f;
7956 {
7957 return f->output_data.w32->line_height;
7958 }
7959
7960 int
7961 x_screen_planes (f)
7962 register struct frame *f;
7963 {
7964 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
7965 }
7966 \f
7967 /* Return the display structure for the display named NAME.
7968 Open a new connection if necessary. */
7969
7970 struct w32_display_info *
7971 x_display_info_for_name (name)
7972 Lisp_Object name;
7973 {
7974 Lisp_Object names;
7975 struct w32_display_info *dpyinfo;
7976
7977 CHECK_STRING (name);
7978
7979 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
7980 dpyinfo;
7981 dpyinfo = dpyinfo->next, names = XCDR (names))
7982 {
7983 Lisp_Object tem;
7984 tem = Fstring_equal (XCAR (XCAR (names)), name);
7985 if (!NILP (tem))
7986 return dpyinfo;
7987 }
7988
7989 /* Use this general default value to start with. */
7990 Vx_resource_name = Vinvocation_name;
7991
7992 validate_x_resource_name ();
7993
7994 dpyinfo = w32_term_init (name, (unsigned char *)0,
7995 (char *) XSTRING (Vx_resource_name)->data);
7996
7997 if (dpyinfo == 0)
7998 error ("Cannot connect to server %s", XSTRING (name)->data);
7999
8000 w32_in_use = 1;
8001 XSETFASTINT (Vwindow_system_version, 3);
8002
8003 return dpyinfo;
8004 }
8005
8006 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
8007 1, 3, 0, doc: /* Open a connection to a server.
8008 DISPLAY is the name of the display to connect to.
8009 Optional second arg XRM-STRING is a string of resources in xrdb format.
8010 If the optional third arg MUST-SUCCEED is non-nil,
8011 terminate Emacs if we can't open the connection. */)
8012 (display, xrm_string, must_succeed)
8013 Lisp_Object display, xrm_string, must_succeed;
8014 {
8015 unsigned char *xrm_option;
8016 struct w32_display_info *dpyinfo;
8017
8018 /* If initialization has already been done, return now to avoid
8019 overwriting critical parts of one_w32_display_info. */
8020 if (w32_in_use)
8021 return Qnil;
8022
8023 CHECK_STRING (display);
8024 if (! NILP (xrm_string))
8025 CHECK_STRING (xrm_string);
8026
8027 if (! EQ (Vwindow_system, intern ("w32")))
8028 error ("Not using Microsoft Windows");
8029
8030 /* Allow color mapping to be defined externally; first look in user's
8031 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
8032 {
8033 Lisp_Object color_file;
8034 struct gcpro gcpro1;
8035
8036 color_file = build_string("~/rgb.txt");
8037
8038 GCPRO1 (color_file);
8039
8040 if (NILP (Ffile_readable_p (color_file)))
8041 color_file =
8042 Fexpand_file_name (build_string ("rgb.txt"),
8043 Fsymbol_value (intern ("data-directory")));
8044
8045 Vw32_color_map = Fw32_load_color_file (color_file);
8046
8047 UNGCPRO;
8048 }
8049 if (NILP (Vw32_color_map))
8050 Vw32_color_map = Fw32_default_color_map ();
8051
8052 if (! NILP (xrm_string))
8053 xrm_option = (unsigned char *) XSTRING (xrm_string)->data;
8054 else
8055 xrm_option = (unsigned char *) 0;
8056
8057 /* Use this general default value to start with. */
8058 /* First remove .exe suffix from invocation-name - it looks ugly. */
8059 {
8060 char basename[ MAX_PATH ], *str;
8061
8062 strcpy (basename, XSTRING (Vinvocation_name)->data);
8063 str = strrchr (basename, '.');
8064 if (str) *str = 0;
8065 Vinvocation_name = build_string (basename);
8066 }
8067 Vx_resource_name = Vinvocation_name;
8068
8069 validate_x_resource_name ();
8070
8071 /* This is what opens the connection and sets x_current_display.
8072 This also initializes many symbols, such as those used for input. */
8073 dpyinfo = w32_term_init (display, xrm_option,
8074 (char *) XSTRING (Vx_resource_name)->data);
8075
8076 if (dpyinfo == 0)
8077 {
8078 if (!NILP (must_succeed))
8079 fatal ("Cannot connect to server %s.\n",
8080 XSTRING (display)->data);
8081 else
8082 error ("Cannot connect to server %s", XSTRING (display)->data);
8083 }
8084
8085 w32_in_use = 1;
8086
8087 XSETFASTINT (Vwindow_system_version, 3);
8088 return Qnil;
8089 }
8090
8091 DEFUN ("x-close-connection", Fx_close_connection,
8092 Sx_close_connection, 1, 1, 0,
8093 doc: /* Close the connection to DISPLAY's server.
8094 For DISPLAY, specify either a frame or a display name (a string).
8095 If DISPLAY is nil, that stands for the selected frame's display. */)
8096 (display)
8097 Lisp_Object display;
8098 {
8099 struct w32_display_info *dpyinfo = check_x_display_info (display);
8100 int i;
8101
8102 if (dpyinfo->reference_count > 0)
8103 error ("Display still has frames on it");
8104
8105 BLOCK_INPUT;
8106 /* Free the fonts in the font table. */
8107 for (i = 0; i < dpyinfo->n_fonts; i++)
8108 if (dpyinfo->font_table[i].name)
8109 {
8110 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
8111 xfree (dpyinfo->font_table[i].full_name);
8112 xfree (dpyinfo->font_table[i].name);
8113 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
8114 }
8115 x_destroy_all_bitmaps (dpyinfo);
8116
8117 x_delete_display (dpyinfo);
8118 UNBLOCK_INPUT;
8119
8120 return Qnil;
8121 }
8122
8123 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
8124 doc: /* Return the list of display names that Emacs has connections to. */)
8125 ()
8126 {
8127 Lisp_Object tail, result;
8128
8129 result = Qnil;
8130 for (tail = w32_display_name_list; ! NILP (tail); tail = XCDR (tail))
8131 result = Fcons (XCAR (XCAR (tail)), result);
8132
8133 return result;
8134 }
8135
8136 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
8137 doc: /* This is a noop on W32 systems. */)
8138 (on, display)
8139 Lisp_Object display, on;
8140 {
8141 return Qnil;
8142 }
8143
8144 \f
8145 \f
8146 /***********************************************************************
8147 Image types
8148 ***********************************************************************/
8149
8150 /* Value is the number of elements of vector VECTOR. */
8151
8152 #define DIM(VECTOR) (sizeof (VECTOR) / sizeof *(VECTOR))
8153
8154 /* List of supported image types. Use define_image_type to add new
8155 types. Use lookup_image_type to find a type for a given symbol. */
8156
8157 static struct image_type *image_types;
8158
8159 /* The symbol `image' which is the car of the lists used to represent
8160 images in Lisp. */
8161
8162 extern Lisp_Object Qimage;
8163
8164 /* The symbol `xbm' which is used as the type symbol for XBM images. */
8165
8166 Lisp_Object Qxbm;
8167
8168 /* Keywords. */
8169
8170 extern Lisp_Object QCwidth, QCheight, QCforeground, QCbackground, QCfile;
8171 extern Lisp_Object QCdata;
8172 Lisp_Object QCtype, QCascent, QCmargin, QCrelief;
8173 Lisp_Object QCconversion, QCcolor_symbols, QCheuristic_mask;
8174 Lisp_Object QCindex, QCmatrix, QCcolor_adjustment, QCmask;
8175
8176 /* Other symbols. */
8177
8178 Lisp_Object Qlaplace, Qemboss, Qedge_detection, Qheuristic;
8179
8180 /* Time in seconds after which images should be removed from the cache
8181 if not displayed. */
8182
8183 Lisp_Object Vimage_cache_eviction_delay;
8184
8185 /* Function prototypes. */
8186
8187 static void define_image_type P_ ((struct image_type *type));
8188 static struct image_type *lookup_image_type P_ ((Lisp_Object symbol));
8189 static void image_error P_ ((char *format, Lisp_Object, Lisp_Object));
8190 static void x_laplace P_ ((struct frame *, struct image *));
8191 static void x_emboss P_ ((struct frame *, struct image *));
8192 static int x_build_heuristic_mask P_ ((struct frame *, struct image *,
8193 Lisp_Object));
8194
8195
8196 /* Define a new image type from TYPE. This adds a copy of TYPE to
8197 image_types and adds the symbol *TYPE->type to Vimage_types. */
8198
8199 static void
8200 define_image_type (type)
8201 struct image_type *type;
8202 {
8203 /* Make a copy of TYPE to avoid a bus error in a dumped Emacs.
8204 The initialized data segment is read-only. */
8205 struct image_type *p = (struct image_type *) xmalloc (sizeof *p);
8206 bcopy (type, p, sizeof *p);
8207 p->next = image_types;
8208 image_types = p;
8209 Vimage_types = Fcons (*p->type, Vimage_types);
8210 }
8211
8212
8213 /* Look up image type SYMBOL, and return a pointer to its image_type
8214 structure. Value is null if SYMBOL is not a known image type. */
8215
8216 static INLINE struct image_type *
8217 lookup_image_type (symbol)
8218 Lisp_Object symbol;
8219 {
8220 struct image_type *type;
8221
8222 for (type = image_types; type; type = type->next)
8223 if (EQ (symbol, *type->type))
8224 break;
8225
8226 return type;
8227 }
8228
8229
8230 /* Value is non-zero if OBJECT is a valid Lisp image specification. A
8231 valid image specification is a list whose car is the symbol
8232 `image', and whose rest is a property list. The property list must
8233 contain a value for key `:type'. That value must be the name of a
8234 supported image type. The rest of the property list depends on the
8235 image type. */
8236
8237 int
8238 valid_image_p (object)
8239 Lisp_Object object;
8240 {
8241 int valid_p = 0;
8242
8243 if (CONSP (object) && EQ (XCAR (object), Qimage))
8244 {
8245 Lisp_Object tem;
8246
8247 for (tem = XCDR (object); CONSP (tem); tem = XCDR (tem))
8248 if (EQ (XCAR (tem), QCtype))
8249 {
8250 tem = XCDR (tem);
8251 if (CONSP (tem) && SYMBOLP (XCAR (tem)))
8252 {
8253 struct image_type *type;
8254 type = lookup_image_type (XCAR (tem));
8255 if (type)
8256 valid_p = type->valid_p (object);
8257 }
8258
8259 break;
8260 }
8261 }
8262
8263 return valid_p;
8264 }
8265
8266
8267 /* Log error message with format string FORMAT and argument ARG.
8268 Signaling an error, e.g. when an image cannot be loaded, is not a
8269 good idea because this would interrupt redisplay, and the error
8270 message display would lead to another redisplay. This function
8271 therefore simply displays a message. */
8272
8273 static void
8274 image_error (format, arg1, arg2)
8275 char *format;
8276 Lisp_Object arg1, arg2;
8277 {
8278 add_to_log (format, arg1, arg2);
8279 }
8280
8281
8282 \f
8283 /***********************************************************************
8284 Image specifications
8285 ***********************************************************************/
8286
8287 enum image_value_type
8288 {
8289 IMAGE_DONT_CHECK_VALUE_TYPE,
8290 IMAGE_STRING_VALUE,
8291 IMAGE_STRING_OR_NIL_VALUE,
8292 IMAGE_SYMBOL_VALUE,
8293 IMAGE_POSITIVE_INTEGER_VALUE,
8294 IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR,
8295 IMAGE_NON_NEGATIVE_INTEGER_VALUE,
8296 IMAGE_ASCENT_VALUE,
8297 IMAGE_INTEGER_VALUE,
8298 IMAGE_FUNCTION_VALUE,
8299 IMAGE_NUMBER_VALUE,
8300 IMAGE_BOOL_VALUE
8301 };
8302
8303 /* Structure used when parsing image specifications. */
8304
8305 struct image_keyword
8306 {
8307 /* Name of keyword. */
8308 char *name;
8309
8310 /* The type of value allowed. */
8311 enum image_value_type type;
8312
8313 /* Non-zero means key must be present. */
8314 int mandatory_p;
8315
8316 /* Used to recognize duplicate keywords in a property list. */
8317 int count;
8318
8319 /* The value that was found. */
8320 Lisp_Object value;
8321 };
8322
8323
8324 static int parse_image_spec P_ ((Lisp_Object, struct image_keyword *,
8325 int, Lisp_Object));
8326 static Lisp_Object image_spec_value P_ ((Lisp_Object, Lisp_Object, int *));
8327
8328
8329 /* Parse image spec SPEC according to KEYWORDS. A valid image spec
8330 has the format (image KEYWORD VALUE ...). One of the keyword/
8331 value pairs must be `:type TYPE'. KEYWORDS is a vector of
8332 image_keywords structures of size NKEYWORDS describing other
8333 allowed keyword/value pairs. Value is non-zero if SPEC is valid. */
8334
8335 static int
8336 parse_image_spec (spec, keywords, nkeywords, type)
8337 Lisp_Object spec;
8338 struct image_keyword *keywords;
8339 int nkeywords;
8340 Lisp_Object type;
8341 {
8342 int i;
8343 Lisp_Object plist;
8344
8345 if (!CONSP (spec) || !EQ (XCAR (spec), Qimage))
8346 return 0;
8347
8348 plist = XCDR (spec);
8349 while (CONSP (plist))
8350 {
8351 Lisp_Object key, value;
8352
8353 /* First element of a pair must be a symbol. */
8354 key = XCAR (plist);
8355 plist = XCDR (plist);
8356 if (!SYMBOLP (key))
8357 return 0;
8358
8359 /* There must follow a value. */
8360 if (!CONSP (plist))
8361 return 0;
8362 value = XCAR (plist);
8363 plist = XCDR (plist);
8364
8365 /* Find key in KEYWORDS. Error if not found. */
8366 for (i = 0; i < nkeywords; ++i)
8367 if (strcmp (keywords[i].name, XSYMBOL (key)->name->data) == 0)
8368 break;
8369
8370 if (i == nkeywords)
8371 continue;
8372
8373 /* Record that we recognized the keyword. If a keywords
8374 was found more than once, it's an error. */
8375 keywords[i].value = value;
8376 ++keywords[i].count;
8377
8378 if (keywords[i].count > 1)
8379 return 0;
8380
8381 /* Check type of value against allowed type. */
8382 switch (keywords[i].type)
8383 {
8384 case IMAGE_STRING_VALUE:
8385 if (!STRINGP (value))
8386 return 0;
8387 break;
8388
8389 case IMAGE_STRING_OR_NIL_VALUE:
8390 if (!STRINGP (value) && !NILP (value))
8391 return 0;
8392 break;
8393
8394 case IMAGE_SYMBOL_VALUE:
8395 if (!SYMBOLP (value))
8396 return 0;
8397 break;
8398
8399 case IMAGE_POSITIVE_INTEGER_VALUE:
8400 if (!INTEGERP (value) || XINT (value) <= 0)
8401 return 0;
8402 break;
8403
8404 case IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR:
8405 if (INTEGERP (value) && XINT (value) >= 0)
8406 break;
8407 if (CONSP (value)
8408 && INTEGERP (XCAR (value)) && INTEGERP (XCDR (value))
8409 && XINT (XCAR (value)) >= 0 && XINT (XCDR (value)) >= 0)
8410 break;
8411 return 0;
8412
8413 case IMAGE_ASCENT_VALUE:
8414 if (SYMBOLP (value) && EQ (value, Qcenter))
8415 break;
8416 else if (INTEGERP (value)
8417 && XINT (value) >= 0
8418 && XINT (value) <= 100)
8419 break;
8420 return 0;
8421
8422 case IMAGE_NON_NEGATIVE_INTEGER_VALUE:
8423 if (!INTEGERP (value) || XINT (value) < 0)
8424 return 0;
8425 break;
8426
8427 case IMAGE_DONT_CHECK_VALUE_TYPE:
8428 break;
8429
8430 case IMAGE_FUNCTION_VALUE:
8431 value = indirect_function (value);
8432 if (SUBRP (value)
8433 || COMPILEDP (value)
8434 || (CONSP (value) && EQ (XCAR (value), Qlambda)))
8435 break;
8436 return 0;
8437
8438 case IMAGE_NUMBER_VALUE:
8439 if (!INTEGERP (value) && !FLOATP (value))
8440 return 0;
8441 break;
8442
8443 case IMAGE_INTEGER_VALUE:
8444 if (!INTEGERP (value))
8445 return 0;
8446 break;
8447
8448 case IMAGE_BOOL_VALUE:
8449 if (!NILP (value) && !EQ (value, Qt))
8450 return 0;
8451 break;
8452
8453 default:
8454 abort ();
8455 break;
8456 }
8457
8458 if (EQ (key, QCtype) && !EQ (type, value))
8459 return 0;
8460 }
8461
8462 /* Check that all mandatory fields are present. */
8463 for (i = 0; i < nkeywords; ++i)
8464 if (keywords[i].mandatory_p && keywords[i].count == 0)
8465 return 0;
8466
8467 return NILP (plist);
8468 }
8469
8470
8471 /* Return the value of KEY in image specification SPEC. Value is nil
8472 if KEY is not present in SPEC. if FOUND is not null, set *FOUND
8473 to 1 if KEY was found in SPEC, set it to 0 otherwise. */
8474
8475 static Lisp_Object
8476 image_spec_value (spec, key, found)
8477 Lisp_Object spec, key;
8478 int *found;
8479 {
8480 Lisp_Object tail;
8481
8482 xassert (valid_image_p (spec));
8483
8484 for (tail = XCDR (spec);
8485 CONSP (tail) && CONSP (XCDR (tail));
8486 tail = XCDR (XCDR (tail)))
8487 {
8488 if (EQ (XCAR (tail), key))
8489 {
8490 if (found)
8491 *found = 1;
8492 return XCAR (XCDR (tail));
8493 }
8494 }
8495
8496 if (found)
8497 *found = 0;
8498 return Qnil;
8499 }
8500
8501
8502
8503 \f
8504 /***********************************************************************
8505 Image type independent image structures
8506 ***********************************************************************/
8507
8508 static struct image *make_image P_ ((Lisp_Object spec, unsigned hash));
8509 static void free_image P_ ((struct frame *f, struct image *img));
8510
8511
8512 /* Allocate and return a new image structure for image specification
8513 SPEC. SPEC has a hash value of HASH. */
8514
8515 static struct image *
8516 make_image (spec, hash)
8517 Lisp_Object spec;
8518 unsigned hash;
8519 {
8520 struct image *img = (struct image *) xmalloc (sizeof *img);
8521
8522 xassert (valid_image_p (spec));
8523 bzero (img, sizeof *img);
8524 img->type = lookup_image_type (image_spec_value (spec, QCtype, NULL));
8525 xassert (img->type != NULL);
8526 img->spec = spec;
8527 img->data.lisp_val = Qnil;
8528 img->ascent = DEFAULT_IMAGE_ASCENT;
8529 img->hash = hash;
8530 return img;
8531 }
8532
8533
8534 /* Free image IMG which was used on frame F, including its resources. */
8535
8536 static void
8537 free_image (f, img)
8538 struct frame *f;
8539 struct image *img;
8540 {
8541 if (img)
8542 {
8543 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8544
8545 /* Remove IMG from the hash table of its cache. */
8546 if (img->prev)
8547 img->prev->next = img->next;
8548 else
8549 c->buckets[img->hash % IMAGE_CACHE_BUCKETS_SIZE] = img->next;
8550
8551 if (img->next)
8552 img->next->prev = img->prev;
8553
8554 c->images[img->id] = NULL;
8555
8556 /* Free resources, then free IMG. */
8557 img->type->free (f, img);
8558 xfree (img);
8559 }
8560 }
8561
8562
8563 /* Prepare image IMG for display on frame F. Must be called before
8564 drawing an image. */
8565
8566 void
8567 prepare_image_for_display (f, img)
8568 struct frame *f;
8569 struct image *img;
8570 {
8571 EMACS_TIME t;
8572
8573 /* We're about to display IMG, so set its timestamp to `now'. */
8574 EMACS_GET_TIME (t);
8575 img->timestamp = EMACS_SECS (t);
8576
8577 /* If IMG doesn't have a pixmap yet, load it now, using the image
8578 type dependent loader function. */
8579 if (img->pixmap == 0 && !img->load_failed_p)
8580 img->load_failed_p = img->type->load (f, img) == 0;
8581 }
8582
8583
8584 /* Value is the number of pixels for the ascent of image IMG when
8585 drawn in face FACE. */
8586
8587 int
8588 image_ascent (img, face)
8589 struct image *img;
8590 struct face *face;
8591 {
8592 int height = img->height + img->vmargin;
8593 int ascent;
8594
8595 if (img->ascent == CENTERED_IMAGE_ASCENT)
8596 {
8597 if (face->font)
8598 ascent = height / 2 - (FONT_DESCENT(face->font)
8599 - FONT_BASE(face->font)) / 2;
8600 else
8601 ascent = height / 2;
8602 }
8603 else
8604 ascent = height * img->ascent / 100.0;
8605
8606 return ascent;
8607 }
8608
8609
8610 \f
8611 /* Image background colors. */
8612
8613 static unsigned long
8614 four_corners_best (ximg, width, height)
8615 XImage *ximg;
8616 unsigned long width, height;
8617 {
8618 #if 0 /* TODO: Image support. */
8619 unsigned long corners[4], best;
8620 int i, best_count;
8621
8622 /* Get the colors at the corners of ximg. */
8623 corners[0] = XGetPixel (ximg, 0, 0);
8624 corners[1] = XGetPixel (ximg, width - 1, 0);
8625 corners[2] = XGetPixel (ximg, width - 1, height - 1);
8626 corners[3] = XGetPixel (ximg, 0, height - 1);
8627
8628 /* Choose the most frequently found color as background. */
8629 for (i = best_count = 0; i < 4; ++i)
8630 {
8631 int j, n;
8632
8633 for (j = n = 0; j < 4; ++j)
8634 if (corners[i] == corners[j])
8635 ++n;
8636
8637 if (n > best_count)
8638 best = corners[i], best_count = n;
8639 }
8640
8641 return best;
8642 #else
8643 return 0;
8644 #endif
8645 }
8646
8647 /* Return the `background' field of IMG. If IMG doesn't have one yet,
8648 it is guessed heuristically. If non-zero, XIMG is an existing XImage
8649 object to use for the heuristic. */
8650
8651 unsigned long
8652 image_background (img, f, ximg)
8653 struct image *img;
8654 struct frame *f;
8655 XImage *ximg;
8656 {
8657 if (! img->background_valid)
8658 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8659 {
8660 #if 0 /* TODO: Image support. */
8661 int free_ximg = !ximg;
8662
8663 if (! ximg)
8664 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
8665 0, 0, img->width, img->height, ~0, ZPixmap);
8666
8667 img->background = four_corners_best (ximg, img->width, img->height);
8668
8669 if (free_ximg)
8670 XDestroyImage (ximg);
8671
8672 img->background_valid = 1;
8673 #endif
8674 }
8675
8676 return img->background;
8677 }
8678
8679 /* Return the `background_transparent' field of IMG. If IMG doesn't
8680 have one yet, it is guessed heuristically. If non-zero, MASK is an
8681 existing XImage object to use for the heuristic. */
8682
8683 int
8684 image_background_transparent (img, f, mask)
8685 struct image *img;
8686 struct frame *f;
8687 XImage *mask;
8688 {
8689 if (! img->background_transparent_valid)
8690 /* IMG doesn't have a background yet, try to guess a reasonable value. */
8691 {
8692 #if 0 /* TODO: Image support. */
8693 if (img->mask)
8694 {
8695 int free_mask = !mask;
8696
8697 if (! mask)
8698 mask = XGetImage (FRAME_X_DISPLAY (f), img->mask,
8699 0, 0, img->width, img->height, ~0, ZPixmap);
8700
8701 img->background_transparent
8702 = !four_corners_best (mask, img->width, img->height);
8703
8704 if (free_mask)
8705 XDestroyImage (mask);
8706 }
8707 else
8708 #endif
8709 img->background_transparent = 0;
8710
8711 img->background_transparent_valid = 1;
8712 }
8713
8714 return img->background_transparent;
8715 }
8716
8717 \f
8718 /***********************************************************************
8719 Helper functions for X image types
8720 ***********************************************************************/
8721
8722 static void x_clear_image_1 P_ ((struct frame *, struct image *, int,
8723 int, int));
8724 static void x_clear_image P_ ((struct frame *f, struct image *img));
8725 static unsigned long x_alloc_image_color P_ ((struct frame *f,
8726 struct image *img,
8727 Lisp_Object color_name,
8728 unsigned long dflt));
8729
8730
8731 /* Clear X resources of image IMG on frame F. PIXMAP_P non-zero means
8732 free the pixmap if any. MASK_P non-zero means clear the mask
8733 pixmap if any. COLORS_P non-zero means free colors allocated for
8734 the image, if any. */
8735
8736 static void
8737 x_clear_image_1 (f, img, pixmap_p, mask_p, colors_p)
8738 struct frame *f;
8739 struct image *img;
8740 int pixmap_p, mask_p, colors_p;
8741 {
8742 #if 0 /* TODO: W32 image support */
8743 if (pixmap_p && img->pixmap)
8744 {
8745 XFreePixmap (FRAME_X_DISPLAY (f), img->pixmap);
8746 img->pixmap = None;
8747 img->background_valid = 0;
8748 }
8749
8750 if (mask_p && img->mask)
8751 {
8752 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
8753 img->mask = None;
8754 img->background_transparent_valid = 0;
8755 }
8756
8757 if (colors_p && img->ncolors)
8758 {
8759 x_free_colors (f, img->colors, img->ncolors);
8760 xfree (img->colors);
8761 img->colors = NULL;
8762 img->ncolors = 0;
8763 }
8764 #endif
8765 }
8766
8767 /* Free X resources of image IMG which is used on frame F. */
8768
8769 static void
8770 x_clear_image (f, img)
8771 struct frame *f;
8772 struct image *img;
8773 {
8774 #if 0 /* TODO: W32 image support */
8775
8776 if (img->pixmap)
8777 {
8778 BLOCK_INPUT;
8779 XFreePixmap (NULL, img->pixmap);
8780 img->pixmap = 0;
8781 UNBLOCK_INPUT;
8782 }
8783
8784 if (img->ncolors)
8785 {
8786 int class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
8787
8788 /* If display has an immutable color map, freeing colors is not
8789 necessary and some servers don't allow it. So don't do it. */
8790 if (class != StaticColor
8791 && class != StaticGray
8792 && class != TrueColor)
8793 {
8794 Colormap cmap;
8795 BLOCK_INPUT;
8796 cmap = DefaultColormapOfScreen (FRAME_W32_DISPLAY_INFO (f)->screen);
8797 XFreeColors (FRAME_W32_DISPLAY (f), cmap, img->colors,
8798 img->ncolors, 0);
8799 UNBLOCK_INPUT;
8800 }
8801
8802 xfree (img->colors);
8803 img->colors = NULL;
8804 img->ncolors = 0;
8805 }
8806 #endif
8807 }
8808
8809
8810 /* Allocate color COLOR_NAME for image IMG on frame F. If color
8811 cannot be allocated, use DFLT. Add a newly allocated color to
8812 IMG->colors, so that it can be freed again. Value is the pixel
8813 color. */
8814
8815 static unsigned long
8816 x_alloc_image_color (f, img, color_name, dflt)
8817 struct frame *f;
8818 struct image *img;
8819 Lisp_Object color_name;
8820 unsigned long dflt;
8821 {
8822 #if 0 /* TODO: allocing colors. */
8823 XColor color;
8824 unsigned long result;
8825
8826 xassert (STRINGP (color_name));
8827
8828 if (w32_defined_color (f, XSTRING (color_name)->data, &color, 1))
8829 {
8830 /* This isn't called frequently so we get away with simply
8831 reallocating the color vector to the needed size, here. */
8832 ++img->ncolors;
8833 img->colors =
8834 (unsigned long *) xrealloc (img->colors,
8835 img->ncolors * sizeof *img->colors);
8836 img->colors[img->ncolors - 1] = color.pixel;
8837 result = color.pixel;
8838 }
8839 else
8840 result = dflt;
8841 return result;
8842 #endif
8843 return 0;
8844 }
8845
8846
8847 \f
8848 /***********************************************************************
8849 Image Cache
8850 ***********************************************************************/
8851
8852 static void cache_image P_ ((struct frame *f, struct image *img));
8853 static void postprocess_image P_ ((struct frame *, struct image *));
8854
8855
8856 /* Return a new, initialized image cache that is allocated from the
8857 heap. Call free_image_cache to free an image cache. */
8858
8859 struct image_cache *
8860 make_image_cache ()
8861 {
8862 struct image_cache *c = (struct image_cache *) xmalloc (sizeof *c);
8863 int size;
8864
8865 bzero (c, sizeof *c);
8866 c->size = 50;
8867 c->images = (struct image **) xmalloc (c->size * sizeof *c->images);
8868 size = IMAGE_CACHE_BUCKETS_SIZE * sizeof *c->buckets;
8869 c->buckets = (struct image **) xmalloc (size);
8870 bzero (c->buckets, size);
8871 return c;
8872 }
8873
8874
8875 /* Free image cache of frame F. Be aware that X frames share images
8876 caches. */
8877
8878 void
8879 free_image_cache (f)
8880 struct frame *f;
8881 {
8882 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8883 if (c)
8884 {
8885 int i;
8886
8887 /* Cache should not be referenced by any frame when freed. */
8888 xassert (c->refcount == 0);
8889
8890 for (i = 0; i < c->used; ++i)
8891 free_image (f, c->images[i]);
8892 xfree (c->images);
8893 xfree (c);
8894 xfree (c->buckets);
8895 FRAME_X_IMAGE_CACHE (f) = NULL;
8896 }
8897 }
8898
8899
8900 /* Clear image cache of frame F. FORCE_P non-zero means free all
8901 images. FORCE_P zero means clear only images that haven't been
8902 displayed for some time. Should be called from time to time to
8903 reduce the number of loaded images. If image-eviction-seconds is
8904 non-nil, this frees images in the cache which weren't displayed for
8905 at least that many seconds. */
8906
8907 void
8908 clear_image_cache (f, force_p)
8909 struct frame *f;
8910 int force_p;
8911 {
8912 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
8913
8914 if (c && INTEGERP (Vimage_cache_eviction_delay))
8915 {
8916 EMACS_TIME t;
8917 unsigned long old;
8918 int i, any_freed_p = 0;
8919
8920 EMACS_GET_TIME (t);
8921 old = EMACS_SECS (t) - XFASTINT (Vimage_cache_eviction_delay);
8922
8923 for (i = 0; i < c->used; ++i)
8924 {
8925 struct image *img = c->images[i];
8926 if (img != NULL
8927 && (force_p
8928 || (img->timestamp > old)))
8929 {
8930 free_image (f, img);
8931 any_freed_p = 1;
8932 }
8933 }
8934
8935 /* We may be clearing the image cache because, for example,
8936 Emacs was iconified for a longer period of time. In that
8937 case, current matrices may still contain references to
8938 images freed above. So, clear these matrices. */
8939 if (any_freed_p)
8940 {
8941 clear_current_matrices (f);
8942 ++windows_or_buffers_changed;
8943 }
8944 }
8945 }
8946
8947
8948 DEFUN ("clear-image-cache", Fclear_image_cache, Sclear_image_cache,
8949 0, 1, 0,
8950 doc: /* Clear the image cache of FRAME.
8951 FRAME nil or omitted means use the selected frame.
8952 FRAME t means clear the image caches of all frames. */)
8953 (frame)
8954 Lisp_Object frame;
8955 {
8956 if (EQ (frame, Qt))
8957 {
8958 Lisp_Object tail;
8959
8960 FOR_EACH_FRAME (tail, frame)
8961 if (FRAME_W32_P (XFRAME (frame)))
8962 clear_image_cache (XFRAME (frame), 1);
8963 }
8964 else
8965 clear_image_cache (check_x_frame (frame), 1);
8966
8967 return Qnil;
8968 }
8969
8970
8971 /* Compute masks and transform image IMG on frame F, as specified
8972 by the image's specification, */
8973
8974 static void
8975 postprocess_image (f, img)
8976 struct frame *f;
8977 struct image *img;
8978 {
8979 #if 0 /* TODO: image support. */
8980 /* Manipulation of the image's mask. */
8981 if (img->pixmap)
8982 {
8983 Lisp_Object conversion, spec;
8984 Lisp_Object mask;
8985
8986 spec = img->spec;
8987
8988 /* `:heuristic-mask t'
8989 `:mask heuristic'
8990 means build a mask heuristically.
8991 `:heuristic-mask (R G B)'
8992 `:mask (heuristic (R G B))'
8993 means build a mask from color (R G B) in the
8994 image.
8995 `:mask nil'
8996 means remove a mask, if any. */
8997
8998 mask = image_spec_value (spec, QCheuristic_mask, NULL);
8999 if (!NILP (mask))
9000 x_build_heuristic_mask (f, img, mask);
9001 else
9002 {
9003 int found_p;
9004
9005 mask = image_spec_value (spec, QCmask, &found_p);
9006
9007 if (EQ (mask, Qheuristic))
9008 x_build_heuristic_mask (f, img, Qt);
9009 else if (CONSP (mask)
9010 && EQ (XCAR (mask), Qheuristic))
9011 {
9012 if (CONSP (XCDR (mask)))
9013 x_build_heuristic_mask (f, img, XCAR (XCDR (mask)));
9014 else
9015 x_build_heuristic_mask (f, img, XCDR (mask));
9016 }
9017 else if (NILP (mask) && found_p && img->mask)
9018 {
9019 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
9020 img->mask = NULL;
9021 }
9022 }
9023
9024
9025 /* Should we apply an image transformation algorithm? */
9026 conversion = image_spec_value (spec, QCconversion, NULL);
9027 if (EQ (conversion, Qdisabled))
9028 x_disable_image (f, img);
9029 else if (EQ (conversion, Qlaplace))
9030 x_laplace (f, img);
9031 else if (EQ (conversion, Qemboss))
9032 x_emboss (f, img);
9033 else if (CONSP (conversion)
9034 && EQ (XCAR (conversion), Qedge_detection))
9035 {
9036 Lisp_Object tem;
9037 tem = XCDR (conversion);
9038 if (CONSP (tem))
9039 x_edge_detection (f, img,
9040 Fplist_get (tem, QCmatrix),
9041 Fplist_get (tem, QCcolor_adjustment));
9042 }
9043 }
9044 #endif
9045 }
9046
9047
9048 /* Return the id of image with Lisp specification SPEC on frame F.
9049 SPEC must be a valid Lisp image specification (see valid_image_p). */
9050
9051 int
9052 lookup_image (f, spec)
9053 struct frame *f;
9054 Lisp_Object spec;
9055 {
9056 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9057 struct image *img;
9058 int i;
9059 unsigned hash;
9060 struct gcpro gcpro1;
9061 EMACS_TIME now;
9062
9063 /* F must be a window-system frame, and SPEC must be a valid image
9064 specification. */
9065 xassert (FRAME_WINDOW_P (f));
9066 xassert (valid_image_p (spec));
9067
9068 GCPRO1 (spec);
9069
9070 /* Look up SPEC in the hash table of the image cache. */
9071 hash = sxhash (spec, 0);
9072 i = hash % IMAGE_CACHE_BUCKETS_SIZE;
9073
9074 for (img = c->buckets[i]; img; img = img->next)
9075 if (img->hash == hash && !NILP (Fequal (img->spec, spec)))
9076 break;
9077
9078 /* If not found, create a new image and cache it. */
9079 if (img == NULL)
9080 {
9081 extern Lisp_Object Qpostscript;
9082
9083 BLOCK_INPUT;
9084 img = make_image (spec, hash);
9085 cache_image (f, img);
9086 img->load_failed_p = img->type->load (f, img) == 0;
9087
9088 /* If we can't load the image, and we don't have a width and
9089 height, use some arbitrary width and height so that we can
9090 draw a rectangle for it. */
9091 if (img->load_failed_p)
9092 {
9093 Lisp_Object value;
9094
9095 value = image_spec_value (spec, QCwidth, NULL);
9096 img->width = (INTEGERP (value)
9097 ? XFASTINT (value) : DEFAULT_IMAGE_WIDTH);
9098 value = image_spec_value (spec, QCheight, NULL);
9099 img->height = (INTEGERP (value)
9100 ? XFASTINT (value) : DEFAULT_IMAGE_HEIGHT);
9101 }
9102 else
9103 {
9104 /* Handle image type independent image attributes
9105 `:ascent PERCENT', `:margin MARGIN', `:relief RELIEF',
9106 `:background COLOR'. */
9107 Lisp_Object ascent, margin, relief, bg;
9108
9109 ascent = image_spec_value (spec, QCascent, NULL);
9110 if (INTEGERP (ascent))
9111 img->ascent = XFASTINT (ascent);
9112 else if (EQ (ascent, Qcenter))
9113 img->ascent = CENTERED_IMAGE_ASCENT;
9114
9115 margin = image_spec_value (spec, QCmargin, NULL);
9116 if (INTEGERP (margin) && XINT (margin) >= 0)
9117 img->vmargin = img->hmargin = XFASTINT (margin);
9118 else if (CONSP (margin) && INTEGERP (XCAR (margin))
9119 && INTEGERP (XCDR (margin)))
9120 {
9121 if (XINT (XCAR (margin)) > 0)
9122 img->hmargin = XFASTINT (XCAR (margin));
9123 if (XINT (XCDR (margin)) > 0)
9124 img->vmargin = XFASTINT (XCDR (margin));
9125 }
9126
9127 relief = image_spec_value (spec, QCrelief, NULL);
9128 if (INTEGERP (relief))
9129 {
9130 img->relief = XINT (relief);
9131 img->hmargin += abs (img->relief);
9132 img->vmargin += abs (img->relief);
9133 }
9134
9135 if (! img->background_valid)
9136 {
9137 bg = image_spec_value (img->spec, QCbackground, NULL);
9138 if (!NILP (bg))
9139 {
9140 img->background
9141 = x_alloc_image_color (f, img, bg,
9142 FRAME_BACKGROUND_PIXEL (f));
9143 img->background_valid = 1;
9144 }
9145 }
9146
9147 /* Do image transformations and compute masks, unless we
9148 don't have the image yet. */
9149 if (!EQ (*img->type->type, Qpostscript))
9150 postprocess_image (f, img);
9151 }
9152
9153 UNBLOCK_INPUT;
9154 xassert (!interrupt_input_blocked);
9155 }
9156
9157 /* We're using IMG, so set its timestamp to `now'. */
9158 EMACS_GET_TIME (now);
9159 img->timestamp = EMACS_SECS (now);
9160
9161 UNGCPRO;
9162
9163 /* Value is the image id. */
9164 return img->id;
9165 }
9166
9167
9168 /* Cache image IMG in the image cache of frame F. */
9169
9170 static void
9171 cache_image (f, img)
9172 struct frame *f;
9173 struct image *img;
9174 {
9175 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9176 int i;
9177
9178 /* Find a free slot in c->images. */
9179 for (i = 0; i < c->used; ++i)
9180 if (c->images[i] == NULL)
9181 break;
9182
9183 /* If no free slot found, maybe enlarge c->images. */
9184 if (i == c->used && c->used == c->size)
9185 {
9186 c->size *= 2;
9187 c->images = (struct image **) xrealloc (c->images,
9188 c->size * sizeof *c->images);
9189 }
9190
9191 /* Add IMG to c->images, and assign IMG an id. */
9192 c->images[i] = img;
9193 img->id = i;
9194 if (i == c->used)
9195 ++c->used;
9196
9197 /* Add IMG to the cache's hash table. */
9198 i = img->hash % IMAGE_CACHE_BUCKETS_SIZE;
9199 img->next = c->buckets[i];
9200 if (img->next)
9201 img->next->prev = img;
9202 img->prev = NULL;
9203 c->buckets[i] = img;
9204 }
9205
9206
9207 /* Call FN on every image in the image cache of frame F. Used to mark
9208 Lisp Objects in the image cache. */
9209
9210 void
9211 forall_images_in_image_cache (f, fn)
9212 struct frame *f;
9213 void (*fn) P_ ((struct image *img));
9214 {
9215 if (FRAME_LIVE_P (f) && FRAME_W32_P (f))
9216 {
9217 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
9218 if (c)
9219 {
9220 int i;
9221 for (i = 0; i < c->used; ++i)
9222 if (c->images[i])
9223 fn (c->images[i]);
9224 }
9225 }
9226 }
9227
9228
9229 \f
9230 /***********************************************************************
9231 W32 support code
9232 ***********************************************************************/
9233
9234 #if 0 /* TODO: W32 specific image code. */
9235
9236 static int x_create_x_image_and_pixmap P_ ((struct frame *, int, int, int,
9237 XImage **, Pixmap *));
9238 static void x_destroy_x_image P_ ((XImage *));
9239 static void x_put_x_image P_ ((struct frame *, XImage *, Pixmap, int, int));
9240
9241
9242 /* Create an XImage and a pixmap of size WIDTH x HEIGHT for use on
9243 frame F. Set *XIMG and *PIXMAP to the XImage and Pixmap created.
9244 Set (*XIMG)->data to a raster of WIDTH x HEIGHT pixels allocated
9245 via xmalloc. Print error messages via image_error if an error
9246 occurs. Value is non-zero if successful. */
9247
9248 static int
9249 x_create_x_image_and_pixmap (f, width, height, depth, ximg, pixmap)
9250 struct frame *f;
9251 int width, height, depth;
9252 XImage **ximg;
9253 Pixmap *pixmap;
9254 {
9255 #if 0 /* TODO: Image support for W32 */
9256 Display *display = FRAME_W32_DISPLAY (f);
9257 Screen *screen = FRAME_X_SCREEN (f);
9258 Window window = FRAME_W32_WINDOW (f);
9259
9260 xassert (interrupt_input_blocked);
9261
9262 if (depth <= 0)
9263 depth = one_w32_display_info.n_cbits;
9264 *ximg = XCreateImage (display, DefaultVisualOfScreen (screen),
9265 depth, ZPixmap, 0, NULL, width, height,
9266 depth > 16 ? 32 : depth > 8 ? 16 : 8, 0);
9267 if (*ximg == NULL)
9268 {
9269 image_error ("Unable to allocate X image", Qnil, Qnil);
9270 return 0;
9271 }
9272
9273 /* Allocate image raster. */
9274 (*ximg)->data = (char *) xmalloc ((*ximg)->bytes_per_line * height);
9275
9276 /* Allocate a pixmap of the same size. */
9277 *pixmap = XCreatePixmap (display, window, width, height, depth);
9278 if (*pixmap == 0)
9279 {
9280 x_destroy_x_image (*ximg);
9281 *ximg = NULL;
9282 image_error ("Unable to create X pixmap", Qnil, Qnil);
9283 return 0;
9284 }
9285 #endif
9286 return 1;
9287 }
9288
9289
9290 /* Destroy XImage XIMG. Free XIMG->data. */
9291
9292 static void
9293 x_destroy_x_image (ximg)
9294 XImage *ximg;
9295 {
9296 xassert (interrupt_input_blocked);
9297 if (ximg)
9298 {
9299 xfree (ximg->data);
9300 ximg->data = NULL;
9301 XDestroyImage (ximg);
9302 }
9303 }
9304
9305
9306 /* Put XImage XIMG into pixmap PIXMAP on frame F. WIDTH and HEIGHT
9307 are width and height of both the image and pixmap. */
9308
9309 static void
9310 x_put_x_image (f, ximg, pixmap, width, height)
9311 struct frame *f;
9312 XImage *ximg;
9313 Pixmap pixmap;
9314 {
9315 GC gc;
9316
9317 xassert (interrupt_input_blocked);
9318 gc = XCreateGC (NULL, pixmap, 0, NULL);
9319 XPutImage (NULL, pixmap, gc, ximg, 0, 0, 0, 0, width, height);
9320 XFreeGC (NULL, gc);
9321 }
9322
9323 #endif
9324
9325 \f
9326 /***********************************************************************
9327 File Handling
9328 ***********************************************************************/
9329
9330 static Lisp_Object x_find_image_file P_ ((Lisp_Object));
9331 static char *slurp_file P_ ((char *, int *));
9332
9333
9334 /* Find image file FILE. Look in data-directory, then
9335 x-bitmap-file-path. Value is the full name of the file found, or
9336 nil if not found. */
9337
9338 static Lisp_Object
9339 x_find_image_file (file)
9340 Lisp_Object file;
9341 {
9342 Lisp_Object file_found, search_path;
9343 struct gcpro gcpro1, gcpro2;
9344 int fd;
9345
9346 file_found = Qnil;
9347 search_path = Fcons (Vdata_directory, Vx_bitmap_file_path);
9348 GCPRO2 (file_found, search_path);
9349
9350 /* Try to find FILE in data-directory, then x-bitmap-file-path. */
9351 fd = openp (search_path, file, Qnil, &file_found, 0);
9352
9353 if (fd == -1)
9354 file_found = Qnil;
9355 else
9356 close (fd);
9357
9358 UNGCPRO;
9359 return file_found;
9360 }
9361
9362
9363 /* Read FILE into memory. Value is a pointer to a buffer allocated
9364 with xmalloc holding FILE's contents. Value is null if an error
9365 occurred. *SIZE is set to the size of the file. */
9366
9367 static char *
9368 slurp_file (file, size)
9369 char *file;
9370 int *size;
9371 {
9372 FILE *fp = NULL;
9373 char *buf = NULL;
9374 struct stat st;
9375
9376 if (stat (file, &st) == 0
9377 && (fp = fopen (file, "r")) != NULL
9378 && (buf = (char *) xmalloc (st.st_size),
9379 fread (buf, 1, st.st_size, fp) == st.st_size))
9380 {
9381 *size = st.st_size;
9382 fclose (fp);
9383 }
9384 else
9385 {
9386 if (fp)
9387 fclose (fp);
9388 if (buf)
9389 {
9390 xfree (buf);
9391 buf = NULL;
9392 }
9393 }
9394
9395 return buf;
9396 }
9397
9398
9399 \f
9400 /***********************************************************************
9401 XBM images
9402 ***********************************************************************/
9403
9404 static int xbm_load P_ ((struct frame *f, struct image *img));
9405 static int xbm_load_image_from_file P_ ((struct frame *f, struct image *img,
9406 Lisp_Object file));
9407 static int xbm_image_p P_ ((Lisp_Object object));
9408 static int xbm_read_bitmap_file_data P_ ((char *, int *, int *,
9409 unsigned char **));
9410
9411
9412 /* Indices of image specification fields in xbm_format, below. */
9413
9414 enum xbm_keyword_index
9415 {
9416 XBM_TYPE,
9417 XBM_FILE,
9418 XBM_WIDTH,
9419 XBM_HEIGHT,
9420 XBM_DATA,
9421 XBM_FOREGROUND,
9422 XBM_BACKGROUND,
9423 XBM_ASCENT,
9424 XBM_MARGIN,
9425 XBM_RELIEF,
9426 XBM_ALGORITHM,
9427 XBM_HEURISTIC_MASK,
9428 XBM_MASK,
9429 XBM_LAST
9430 };
9431
9432 /* Vector of image_keyword structures describing the format
9433 of valid XBM image specifications. */
9434
9435 static struct image_keyword xbm_format[XBM_LAST] =
9436 {
9437 {":type", IMAGE_SYMBOL_VALUE, 1},
9438 {":file", IMAGE_STRING_VALUE, 0},
9439 {":width", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9440 {":height", IMAGE_POSITIVE_INTEGER_VALUE, 0},
9441 {":data", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9442 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
9443 {":background", IMAGE_STRING_OR_NIL_VALUE, 0},
9444 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
9445 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
9446 {":relief", IMAGE_INTEGER_VALUE, 0},
9447 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
9448 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0}
9449 };
9450
9451 /* Structure describing the image type XBM. */
9452
9453 static struct image_type xbm_type =
9454 {
9455 &Qxbm,
9456 xbm_image_p,
9457 xbm_load,
9458 x_clear_image,
9459 NULL
9460 };
9461
9462 /* Tokens returned from xbm_scan. */
9463
9464 enum xbm_token
9465 {
9466 XBM_TK_IDENT = 256,
9467 XBM_TK_NUMBER
9468 };
9469
9470
9471 /* Return non-zero if OBJECT is a valid XBM-type image specification.
9472 A valid specification is a list starting with the symbol `image'
9473 The rest of the list is a property list which must contain an
9474 entry `:type xbm..
9475
9476 If the specification specifies a file to load, it must contain
9477 an entry `:file FILENAME' where FILENAME is a string.
9478
9479 If the specification is for a bitmap loaded from memory it must
9480 contain `:width WIDTH', `:height HEIGHT', and `:data DATA', where
9481 WIDTH and HEIGHT are integers > 0. DATA may be:
9482
9483 1. a string large enough to hold the bitmap data, i.e. it must
9484 have a size >= (WIDTH + 7) / 8 * HEIGHT
9485
9486 2. a bool-vector of size >= WIDTH * HEIGHT
9487
9488 3. a vector of strings or bool-vectors, one for each line of the
9489 bitmap.
9490
9491 Both the file and data forms may contain the additional entries
9492 `:background COLOR' and `:foreground COLOR'. If not present,
9493 foreground and background of the frame on which the image is
9494 displayed, is used. */
9495
9496 static int
9497 xbm_image_p (object)
9498 Lisp_Object object;
9499 {
9500 struct image_keyword kw[XBM_LAST];
9501
9502 bcopy (xbm_format, kw, sizeof kw);
9503 if (!parse_image_spec (object, kw, XBM_LAST, Qxbm))
9504 return 0;
9505
9506 xassert (EQ (kw[XBM_TYPE].value, Qxbm));
9507
9508 if (kw[XBM_FILE].count)
9509 {
9510 if (kw[XBM_WIDTH].count || kw[XBM_HEIGHT].count || kw[XBM_DATA].count)
9511 return 0;
9512 }
9513 else
9514 {
9515 Lisp_Object data;
9516 int width, height;
9517
9518 /* Entries for `:width', `:height' and `:data' must be present. */
9519 if (!kw[XBM_WIDTH].count
9520 || !kw[XBM_HEIGHT].count
9521 || !kw[XBM_DATA].count)
9522 return 0;
9523
9524 data = kw[XBM_DATA].value;
9525 width = XFASTINT (kw[XBM_WIDTH].value);
9526 height = XFASTINT (kw[XBM_HEIGHT].value);
9527
9528 /* Check type of data, and width and height against contents of
9529 data. */
9530 if (VECTORP (data))
9531 {
9532 int i;
9533
9534 /* Number of elements of the vector must be >= height. */
9535 if (XVECTOR (data)->size < height)
9536 return 0;
9537
9538 /* Each string or bool-vector in data must be large enough
9539 for one line of the image. */
9540 for (i = 0; i < height; ++i)
9541 {
9542 Lisp_Object elt = XVECTOR (data)->contents[i];
9543
9544 if (STRINGP (elt))
9545 {
9546 if (XSTRING (elt)->size
9547 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR)
9548 return 0;
9549 }
9550 else if (BOOL_VECTOR_P (elt))
9551 {
9552 if (XBOOL_VECTOR (elt)->size < width)
9553 return 0;
9554 }
9555 else
9556 return 0;
9557 }
9558 }
9559 else if (STRINGP (data))
9560 {
9561 if (XSTRING (data)->size
9562 < (width + BITS_PER_CHAR - 1) / BITS_PER_CHAR * height)
9563 return 0;
9564 }
9565 else if (BOOL_VECTOR_P (data))
9566 {
9567 if (XBOOL_VECTOR (data)->size < width * height)
9568 return 0;
9569 }
9570 else
9571 return 0;
9572 }
9573
9574 /* Baseline must be a value between 0 and 100 (a percentage). */
9575 if (kw[XBM_ASCENT].count
9576 && XFASTINT (kw[XBM_ASCENT].value) > 100)
9577 return 0;
9578
9579 return 1;
9580 }
9581
9582
9583 /* Scan a bitmap file. FP is the stream to read from. Value is
9584 either an enumerator from enum xbm_token, or a character for a
9585 single-character token, or 0 at end of file. If scanning an
9586 identifier, store the lexeme of the identifier in SVAL. If
9587 scanning a number, store its value in *IVAL. */
9588
9589 static int
9590 xbm_scan (s, end, sval, ival)
9591 char **s, *end;
9592 char *sval;
9593 int *ival;
9594 {
9595 int c;
9596
9597 loop:
9598
9599 /* Skip white space. */
9600 while (*s < end &&(c = *(*s)++, isspace (c)))
9601 ;
9602
9603 if (*s >= end)
9604 c = 0;
9605 else if (isdigit (c))
9606 {
9607 int value = 0, digit;
9608
9609 if (c == '0' && *s < end)
9610 {
9611 c = *(*s)++;
9612 if (c == 'x' || c == 'X')
9613 {
9614 while (*s < end)
9615 {
9616 c = *(*s)++;
9617 if (isdigit (c))
9618 digit = c - '0';
9619 else if (c >= 'a' && c <= 'f')
9620 digit = c - 'a' + 10;
9621 else if (c >= 'A' && c <= 'F')
9622 digit = c - 'A' + 10;
9623 else
9624 break;
9625 value = 16 * value + digit;
9626 }
9627 }
9628 else if (isdigit (c))
9629 {
9630 value = c - '0';
9631 while (*s < end
9632 && (c = *(*s)++, isdigit (c)))
9633 value = 8 * value + c - '0';
9634 }
9635 }
9636 else
9637 {
9638 value = c - '0';
9639 while (*s < end
9640 && (c = *(*s)++, isdigit (c)))
9641 value = 10 * value + c - '0';
9642 }
9643
9644 if (*s < end)
9645 *s = *s - 1;
9646 *ival = value;
9647 c = XBM_TK_NUMBER;
9648 }
9649 else if (isalpha (c) || c == '_')
9650 {
9651 *sval++ = c;
9652 while (*s < end
9653 && (c = *(*s)++, (isalnum (c) || c == '_')))
9654 *sval++ = c;
9655 *sval = 0;
9656 if (*s < end)
9657 *s = *s - 1;
9658 c = XBM_TK_IDENT;
9659 }
9660 else if (c == '/' && **s == '*')
9661 {
9662 /* C-style comment. */
9663 ++*s;
9664 while (**s && (**s != '*' || *(*s + 1) != '/'))
9665 ++*s;
9666 if (**s)
9667 {
9668 *s += 2;
9669 goto loop;
9670 }
9671 }
9672
9673 return c;
9674 }
9675
9676
9677 /* Replacement for XReadBitmapFileData which isn't available under old
9678 X versions. CONTENTS is a pointer to a buffer to parse; END is the
9679 buffer's end. Set *WIDTH and *HEIGHT to the width and height of
9680 the image. Return in *DATA the bitmap data allocated with xmalloc.
9681 Value is non-zero if successful. DATA null means just test if
9682 CONTENTS looks like an in-memory XBM file. */
9683
9684 static int
9685 xbm_read_bitmap_data (contents, end, width, height, data)
9686 char *contents, *end;
9687 int *width, *height;
9688 unsigned char **data;
9689 {
9690 char *s = contents;
9691 char buffer[BUFSIZ];
9692 int padding_p = 0;
9693 int v10 = 0;
9694 int bytes_per_line, i, nbytes;
9695 unsigned char *p;
9696 int value;
9697 int LA1;
9698
9699 #define match() \
9700 LA1 = xbm_scan (contents, end, buffer, &value)
9701
9702 #define expect(TOKEN) \
9703 if (LA1 != (TOKEN)) \
9704 goto failure; \
9705 else \
9706 match ()
9707
9708 #define expect_ident(IDENT) \
9709 if (LA1 == XBM_TK_IDENT && strcmp (buffer, (IDENT)) == 0) \
9710 match (); \
9711 else \
9712 goto failure
9713
9714 *width = *height = -1;
9715 if (data)
9716 *data = NULL;
9717 LA1 = xbm_scan (&s, end, buffer, &value);
9718
9719 /* Parse defines for width, height and hot-spots. */
9720 while (LA1 == '#')
9721 {
9722 match ();
9723 expect_ident ("define");
9724 expect (XBM_TK_IDENT);
9725
9726 if (LA1 == XBM_TK_NUMBER);
9727 {
9728 char *p = strrchr (buffer, '_');
9729 p = p ? p + 1 : buffer;
9730 if (strcmp (p, "width") == 0)
9731 *width = value;
9732 else if (strcmp (p, "height") == 0)
9733 *height = value;
9734 }
9735 expect (XBM_TK_NUMBER);
9736 }
9737
9738 if (*width < 0 || *height < 0)
9739 goto failure;
9740 else if (data == NULL)
9741 goto success;
9742
9743 /* Parse bits. Must start with `static'. */
9744 expect_ident ("static");
9745 if (LA1 == XBM_TK_IDENT)
9746 {
9747 if (strcmp (buffer, "unsigned") == 0)
9748 {
9749 match ();
9750 expect_ident ("char");
9751 }
9752 else if (strcmp (buffer, "short") == 0)
9753 {
9754 match ();
9755 v10 = 1;
9756 if (*width % 16 && *width % 16 < 9)
9757 padding_p = 1;
9758 }
9759 else if (strcmp (buffer, "char") == 0)
9760 match ();
9761 else
9762 goto failure;
9763 }
9764 else
9765 goto failure;
9766
9767 expect (XBM_TK_IDENT);
9768 expect ('[');
9769 expect (']');
9770 expect ('=');
9771 expect ('{');
9772
9773 bytes_per_line = (*width + 7) / 8 + padding_p;
9774 nbytes = bytes_per_line * *height;
9775 p = *data = (char *) xmalloc (nbytes);
9776
9777 if (v10)
9778 {
9779
9780 for (i = 0; i < nbytes; i += 2)
9781 {
9782 int val = value;
9783 expect (XBM_TK_NUMBER);
9784
9785 *p++ = val;
9786 if (!padding_p || ((i + 2) % bytes_per_line))
9787 *p++ = value >> 8;
9788
9789 if (LA1 == ',' || LA1 == '}')
9790 match ();
9791 else
9792 goto failure;
9793 }
9794 }
9795 else
9796 {
9797 for (i = 0; i < nbytes; ++i)
9798 {
9799 int val = value;
9800 expect (XBM_TK_NUMBER);
9801
9802 *p++ = val;
9803
9804 if (LA1 == ',' || LA1 == '}')
9805 match ();
9806 else
9807 goto failure;
9808 }
9809 }
9810
9811 success:
9812 return 1;
9813
9814 failure:
9815
9816 if (data && *data)
9817 {
9818 xfree (*data);
9819 *data = NULL;
9820 }
9821 return 0;
9822
9823 #undef match
9824 #undef expect
9825 #undef expect_ident
9826 }
9827
9828
9829 /* Load XBM image IMG which will be displayed on frame F from buffer
9830 CONTENTS. END is the end of the buffer. Value is non-zero if
9831 successful. */
9832
9833 static int
9834 xbm_load_image (f, img, contents, end)
9835 struct frame *f;
9836 struct image *img;
9837 char *contents, *end;
9838 {
9839 int rc;
9840 unsigned char *data;
9841 int success_p = 0;
9842
9843 rc = xbm_read_bitmap_data (contents, end, &img->width, &img->height, &data);
9844 if (rc)
9845 {
9846 int depth = one_w32_display_info.n_cbits;
9847 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9848 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9849 Lisp_Object value;
9850
9851 xassert (img->width > 0 && img->height > 0);
9852
9853 /* Get foreground and background colors, maybe allocate colors. */
9854 value = image_spec_value (img->spec, QCforeground, NULL);
9855 if (!NILP (value))
9856 foreground = x_alloc_image_color (f, img, value, foreground);
9857 value = image_spec_value (img->spec, QCbackground, NULL);
9858 if (!NILP (value))
9859 {
9860 background = x_alloc_image_color (f, img, value, background);
9861 img->background = background;
9862 img->background_valid = 1;
9863 }
9864
9865 #if 0 /* TODO : Port image display to W32 */
9866 img->pixmap
9867 = XCreatePixmapFromBitmapData (FRAME_W32_DISPLAY (f),
9868 FRAME_W32_WINDOW (f),
9869 data,
9870 img->width, img->height,
9871 foreground, background,
9872 depth);
9873 #endif
9874 xfree (data);
9875
9876 if (img->pixmap == 0)
9877 {
9878 x_clear_image (f, img);
9879 image_error ("Unable to create X pixmap for `%s'", img->spec, Qnil);
9880 }
9881 else
9882 success_p = 1;
9883 }
9884 else
9885 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9886
9887 return success_p;
9888 }
9889
9890
9891 /* Value is non-zero if DATA looks like an in-memory XBM file. */
9892
9893 static int
9894 xbm_file_p (data)
9895 Lisp_Object data;
9896 {
9897 int w, h;
9898 return (STRINGP (data)
9899 && xbm_read_bitmap_data (XSTRING (data)->data,
9900 (XSTRING (data)->data
9901 + STRING_BYTES (XSTRING (data))),
9902 &w, &h, NULL));
9903 }
9904
9905
9906 /* Fill image IMG which is used on frame F with pixmap data. Value is
9907 non-zero if successful. */
9908
9909 static int
9910 xbm_load (f, img)
9911 struct frame *f;
9912 struct image *img;
9913 {
9914 int success_p = 0;
9915 Lisp_Object file_name;
9916
9917 xassert (xbm_image_p (img->spec));
9918
9919 /* If IMG->spec specifies a file name, create a non-file spec from it. */
9920 file_name = image_spec_value (img->spec, QCfile, NULL);
9921 if (STRINGP (file_name))
9922 {
9923 Lisp_Object file;
9924 char *contents;
9925 int size;
9926 struct gcpro gcpro1;
9927
9928 file = x_find_image_file (file_name);
9929 GCPRO1 (file);
9930 if (!STRINGP (file))
9931 {
9932 image_error ("Cannot find image file `%s'", file_name, Qnil);
9933 UNGCPRO;
9934 return 0;
9935 }
9936
9937 contents = slurp_file (XSTRING (file)->data, &size);
9938 if (contents == NULL)
9939 {
9940 image_error ("Error loading XBM image `%s'", img->spec, Qnil);
9941 UNGCPRO;
9942 return 0;
9943 }
9944
9945 success_p = xbm_load_image (f, img, contents, contents + size);
9946 UNGCPRO;
9947 }
9948 else
9949 {
9950 struct image_keyword fmt[XBM_LAST];
9951 Lisp_Object data;
9952 int depth;
9953 unsigned long foreground = FRAME_FOREGROUND_PIXEL (f);
9954 unsigned long background = FRAME_BACKGROUND_PIXEL (f);
9955 char *bits;
9956 int parsed_p;
9957 int in_memory_file_p = 0;
9958
9959 /* See if data looks like an in-memory XBM file. */
9960 data = image_spec_value (img->spec, QCdata, NULL);
9961 in_memory_file_p = xbm_file_p (data);
9962
9963 /* Parse the list specification. */
9964 bcopy (xbm_format, fmt, sizeof fmt);
9965 parsed_p = parse_image_spec (img->spec, fmt, XBM_LAST, Qxbm);
9966 xassert (parsed_p);
9967
9968 /* Get specified width, and height. */
9969 if (!in_memory_file_p)
9970 {
9971 img->width = XFASTINT (fmt[XBM_WIDTH].value);
9972 img->height = XFASTINT (fmt[XBM_HEIGHT].value);
9973 xassert (img->width > 0 && img->height > 0);
9974 }
9975 /* Get foreground and background colors, maybe allocate colors. */
9976 if (fmt[XBM_FOREGROUND].count
9977 && STRINGP (fmt[XBM_FOREGROUND].value))
9978 foreground = x_alloc_image_color (f, img, fmt[XBM_FOREGROUND].value,
9979 foreground);
9980 if (fmt[XBM_BACKGROUND].count
9981 && STRINGP (fmt[XBM_BACKGROUND].value))
9982 background = x_alloc_image_color (f, img, fmt[XBM_BACKGROUND].value,
9983 background);
9984
9985 if (in_memory_file_p)
9986 success_p = xbm_load_image (f, img, XSTRING (data)->data,
9987 (XSTRING (data)->data
9988 + STRING_BYTES (XSTRING (data))));
9989 else
9990 {
9991 if (VECTORP (data))
9992 {
9993 int i;
9994 char *p;
9995 int nbytes = (img->width + BITS_PER_CHAR - 1) / BITS_PER_CHAR;
9996
9997 p = bits = (char *) alloca (nbytes * img->height);
9998 for (i = 0; i < img->height; ++i, p += nbytes)
9999 {
10000 Lisp_Object line = XVECTOR (data)->contents[i];
10001 if (STRINGP (line))
10002 bcopy (XSTRING (line)->data, p, nbytes);
10003 else
10004 bcopy (XBOOL_VECTOR (line)->data, p, nbytes);
10005 }
10006 }
10007 else if (STRINGP (data))
10008 bits = XSTRING (data)->data;
10009 else
10010 bits = XBOOL_VECTOR (data)->data;
10011 #ifdef TODO /* image support. */
10012 /* Create the pixmap. */
10013 depth = one_w32_display_info.n_cbits;
10014 img->pixmap
10015 = XCreatePixmapFromBitmapData (FRAME_X_DISPLAY (f),
10016 FRAME_X_WINDOW (f),
10017 bits,
10018 img->width, img->height,
10019 foreground, background,
10020 depth);
10021 #endif
10022 if (img->pixmap)
10023 success_p = 1;
10024 else
10025 {
10026 image_error ("Unable to create pixmap for XBM image `%s'",
10027 img->spec, Qnil);
10028 x_clear_image (f, img);
10029 }
10030 }
10031 }
10032
10033 return success_p;
10034 }
10035
10036
10037 \f
10038 /***********************************************************************
10039 XPM images
10040 ***********************************************************************/
10041
10042 #if HAVE_XPM
10043
10044 static int xpm_image_p P_ ((Lisp_Object object));
10045 static int xpm_load P_ ((struct frame *f, struct image *img));
10046 static int xpm_valid_color_symbols_p P_ ((Lisp_Object));
10047
10048 #include "X11/xpm.h"
10049
10050 /* The symbol `xpm' identifying XPM-format images. */
10051
10052 Lisp_Object Qxpm;
10053
10054 /* Indices of image specification fields in xpm_format, below. */
10055
10056 enum xpm_keyword_index
10057 {
10058 XPM_TYPE,
10059 XPM_FILE,
10060 XPM_DATA,
10061 XPM_ASCENT,
10062 XPM_MARGIN,
10063 XPM_RELIEF,
10064 XPM_ALGORITHM,
10065 XPM_HEURISTIC_MASK,
10066 XPM_MASK,
10067 XPM_COLOR_SYMBOLS,
10068 XPM_BACKGROUND,
10069 XPM_LAST
10070 };
10071
10072 /* Vector of image_keyword structures describing the format
10073 of valid XPM image specifications. */
10074
10075 static struct image_keyword xpm_format[XPM_LAST] =
10076 {
10077 {":type", IMAGE_SYMBOL_VALUE, 1},
10078 {":file", IMAGE_STRING_VALUE, 0},
10079 {":data", IMAGE_STRING_VALUE, 0},
10080 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10081 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10082 {":relief", IMAGE_INTEGER_VALUE, 0},
10083 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10084 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10085 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10086 {":color-symbols", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10087 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10088 };
10089
10090 /* Structure describing the image type XBM. */
10091
10092 static struct image_type xpm_type =
10093 {
10094 &Qxpm,
10095 xpm_image_p,
10096 xpm_load,
10097 x_clear_image,
10098 NULL
10099 };
10100
10101
10102 /* Value is non-zero if COLOR_SYMBOLS is a valid color symbols list
10103 for XPM images. Such a list must consist of conses whose car and
10104 cdr are strings. */
10105
10106 static int
10107 xpm_valid_color_symbols_p (color_symbols)
10108 Lisp_Object color_symbols;
10109 {
10110 while (CONSP (color_symbols))
10111 {
10112 Lisp_Object sym = XCAR (color_symbols);
10113 if (!CONSP (sym)
10114 || !STRINGP (XCAR (sym))
10115 || !STRINGP (XCDR (sym)))
10116 break;
10117 color_symbols = XCDR (color_symbols);
10118 }
10119
10120 return NILP (color_symbols);
10121 }
10122
10123
10124 /* Value is non-zero if OBJECT is a valid XPM image specification. */
10125
10126 static int
10127 xpm_image_p (object)
10128 Lisp_Object object;
10129 {
10130 struct image_keyword fmt[XPM_LAST];
10131 bcopy (xpm_format, fmt, sizeof fmt);
10132 return (parse_image_spec (object, fmt, XPM_LAST, Qxpm)
10133 /* Either `:file' or `:data' must be present. */
10134 && fmt[XPM_FILE].count + fmt[XPM_DATA].count == 1
10135 /* Either no `:color-symbols' or it's a list of conses
10136 whose car and cdr are strings. */
10137 && (fmt[XPM_COLOR_SYMBOLS].count == 0
10138 || xpm_valid_color_symbols_p (fmt[XPM_COLOR_SYMBOLS].value))
10139 && (fmt[XPM_ASCENT].count == 0
10140 || XFASTINT (fmt[XPM_ASCENT].value) < 100));
10141 }
10142
10143
10144 /* Load image IMG which will be displayed on frame F. Value is
10145 non-zero if successful. */
10146
10147 static int
10148 xpm_load (f, img)
10149 struct frame *f;
10150 struct image *img;
10151 {
10152 int rc, i;
10153 XpmAttributes attrs;
10154 Lisp_Object specified_file, color_symbols;
10155
10156 /* Configure the XPM lib. Use the visual of frame F. Allocate
10157 close colors. Return colors allocated. */
10158 bzero (&attrs, sizeof attrs);
10159 attrs.visual = FRAME_X_VISUAL (f);
10160 attrs.colormap = FRAME_X_COLORMAP (f);
10161 attrs.valuemask |= XpmVisual;
10162 attrs.valuemask |= XpmColormap;
10163 attrs.valuemask |= XpmReturnAllocPixels;
10164 #ifdef XpmAllocCloseColors
10165 attrs.alloc_close_colors = 1;
10166 attrs.valuemask |= XpmAllocCloseColors;
10167 #else
10168 attrs.closeness = 600;
10169 attrs.valuemask |= XpmCloseness;
10170 #endif
10171
10172 /* If image specification contains symbolic color definitions, add
10173 these to `attrs'. */
10174 color_symbols = image_spec_value (img->spec, QCcolor_symbols, NULL);
10175 if (CONSP (color_symbols))
10176 {
10177 Lisp_Object tail;
10178 XpmColorSymbol *xpm_syms;
10179 int i, size;
10180
10181 attrs.valuemask |= XpmColorSymbols;
10182
10183 /* Count number of symbols. */
10184 attrs.numsymbols = 0;
10185 for (tail = color_symbols; CONSP (tail); tail = XCDR (tail))
10186 ++attrs.numsymbols;
10187
10188 /* Allocate an XpmColorSymbol array. */
10189 size = attrs.numsymbols * sizeof *xpm_syms;
10190 xpm_syms = (XpmColorSymbol *) alloca (size);
10191 bzero (xpm_syms, size);
10192 attrs.colorsymbols = xpm_syms;
10193
10194 /* Fill the color symbol array. */
10195 for (tail = color_symbols, i = 0;
10196 CONSP (tail);
10197 ++i, tail = XCDR (tail))
10198 {
10199 Lisp_Object name = XCAR (XCAR (tail));
10200 Lisp_Object color = XCDR (XCAR (tail));
10201 xpm_syms[i].name = (char *) alloca (XSTRING (name)->size + 1);
10202 strcpy (xpm_syms[i].name, XSTRING (name)->data);
10203 xpm_syms[i].value = (char *) alloca (XSTRING (color)->size + 1);
10204 strcpy (xpm_syms[i].value, XSTRING (color)->data);
10205 }
10206 }
10207
10208 /* Create a pixmap for the image, either from a file, or from a
10209 string buffer containing data in the same format as an XPM file. */
10210 BLOCK_INPUT;
10211 specified_file = image_spec_value (img->spec, QCfile, NULL);
10212 if (STRINGP (specified_file))
10213 {
10214 Lisp_Object file = x_find_image_file (specified_file);
10215 if (!STRINGP (file))
10216 {
10217 image_error ("Cannot find image file `%s'", specified_file, Qnil);
10218 UNBLOCK_INPUT;
10219 return 0;
10220 }
10221
10222 rc = XpmReadFileToPixmap (NULL, FRAME_W32_WINDOW (f),
10223 XSTRING (file)->data, &img->pixmap, &img->mask,
10224 &attrs);
10225 }
10226 else
10227 {
10228 Lisp_Object buffer = image_spec_value (img->spec, QCdata, NULL);
10229 rc = XpmCreatePixmapFromBuffer (NULL, FRAME_W32_WINDOW (f),
10230 XSTRING (buffer)->data,
10231 &img->pixmap, &img->mask,
10232 &attrs);
10233 }
10234 UNBLOCK_INPUT;
10235
10236 if (rc == XpmSuccess)
10237 {
10238 /* Remember allocated colors. */
10239 img->ncolors = attrs.nalloc_pixels;
10240 img->colors = (unsigned long *) xmalloc (img->ncolors
10241 * sizeof *img->colors);
10242 for (i = 0; i < attrs.nalloc_pixels; ++i)
10243 img->colors[i] = attrs.alloc_pixels[i];
10244
10245 img->width = attrs.width;
10246 img->height = attrs.height;
10247 xassert (img->width > 0 && img->height > 0);
10248
10249 /* The call to XpmFreeAttributes below frees attrs.alloc_pixels. */
10250 BLOCK_INPUT;
10251 XpmFreeAttributes (&attrs);
10252 UNBLOCK_INPUT;
10253 }
10254 else
10255 {
10256 switch (rc)
10257 {
10258 case XpmOpenFailed:
10259 image_error ("Error opening XPM file (%s)", img->spec, Qnil);
10260 break;
10261
10262 case XpmFileInvalid:
10263 image_error ("Invalid XPM file (%s)", img->spec, Qnil);
10264 break;
10265
10266 case XpmNoMemory:
10267 image_error ("Out of memory (%s)", img->spec, Qnil);
10268 break;
10269
10270 case XpmColorFailed:
10271 image_error ("Color allocation error (%s)", img->spec, Qnil);
10272 break;
10273
10274 default:
10275 image_error ("Unknown error (%s)", img->spec, Qnil);
10276 break;
10277 }
10278 }
10279
10280 return rc == XpmSuccess;
10281 }
10282
10283 #endif /* HAVE_XPM != 0 */
10284
10285 \f
10286 #if 0 /* TODO : Color tables on W32. */
10287 /***********************************************************************
10288 Color table
10289 ***********************************************************************/
10290
10291 /* An entry in the color table mapping an RGB color to a pixel color. */
10292
10293 struct ct_color
10294 {
10295 int r, g, b;
10296 unsigned long pixel;
10297
10298 /* Next in color table collision list. */
10299 struct ct_color *next;
10300 };
10301
10302 /* The bucket vector size to use. Must be prime. */
10303
10304 #define CT_SIZE 101
10305
10306 /* Value is a hash of the RGB color given by R, G, and B. */
10307
10308 #define CT_HASH_RGB(R, G, B) (((R) << 16) ^ ((G) << 8) ^ (B))
10309
10310 /* The color hash table. */
10311
10312 struct ct_color **ct_table;
10313
10314 /* Number of entries in the color table. */
10315
10316 int ct_colors_allocated;
10317
10318 /* Function prototypes. */
10319
10320 static void init_color_table P_ ((void));
10321 static void free_color_table P_ ((void));
10322 static unsigned long *colors_in_color_table P_ ((int *n));
10323 static unsigned long lookup_rgb_color P_ ((struct frame *f, int r, int g, int b));
10324 static unsigned long lookup_pixel_color P_ ((struct frame *f, unsigned long p));
10325
10326
10327 /* Initialize the color table. */
10328
10329 static void
10330 init_color_table ()
10331 {
10332 int size = CT_SIZE * sizeof (*ct_table);
10333 ct_table = (struct ct_color **) xmalloc (size);
10334 bzero (ct_table, size);
10335 ct_colors_allocated = 0;
10336 }
10337
10338
10339 /* Free memory associated with the color table. */
10340
10341 static void
10342 free_color_table ()
10343 {
10344 int i;
10345 struct ct_color *p, *next;
10346
10347 for (i = 0; i < CT_SIZE; ++i)
10348 for (p = ct_table[i]; p; p = next)
10349 {
10350 next = p->next;
10351 xfree (p);
10352 }
10353
10354 xfree (ct_table);
10355 ct_table = NULL;
10356 }
10357
10358
10359 /* Value is a pixel color for RGB color R, G, B on frame F. If an
10360 entry for that color already is in the color table, return the
10361 pixel color of that entry. Otherwise, allocate a new color for R,
10362 G, B, and make an entry in the color table. */
10363
10364 static unsigned long
10365 lookup_rgb_color (f, r, g, b)
10366 struct frame *f;
10367 int r, g, b;
10368 {
10369 unsigned hash = CT_HASH_RGB (r, g, b);
10370 int i = hash % CT_SIZE;
10371 struct ct_color *p;
10372
10373 for (p = ct_table[i]; p; p = p->next)
10374 if (p->r == r && p->g == g && p->b == b)
10375 break;
10376
10377 if (p == NULL)
10378 {
10379 COLORREF color;
10380 Colormap cmap;
10381 int rc;
10382
10383 color = PALETTERGB (r, g, b);
10384
10385 ++ct_colors_allocated;
10386
10387 p = (struct ct_color *) xmalloc (sizeof *p);
10388 p->r = r;
10389 p->g = g;
10390 p->b = b;
10391 p->pixel = color;
10392 p->next = ct_table[i];
10393 ct_table[i] = p;
10394 }
10395
10396 return p->pixel;
10397 }
10398
10399
10400 /* Look up pixel color PIXEL which is used on frame F in the color
10401 table. If not already present, allocate it. Value is PIXEL. */
10402
10403 static unsigned long
10404 lookup_pixel_color (f, pixel)
10405 struct frame *f;
10406 unsigned long pixel;
10407 {
10408 int i = pixel % CT_SIZE;
10409 struct ct_color *p;
10410
10411 for (p = ct_table[i]; p; p = p->next)
10412 if (p->pixel == pixel)
10413 break;
10414
10415 if (p == NULL)
10416 {
10417 XColor color;
10418 Colormap cmap;
10419 int rc;
10420
10421 BLOCK_INPUT;
10422
10423 cmap = DefaultColormapOfScreen (FRAME_X_SCREEN (f));
10424 color.pixel = pixel;
10425 XQueryColor (NULL, cmap, &color);
10426 rc = x_alloc_nearest_color (f, cmap, &color);
10427 UNBLOCK_INPUT;
10428
10429 if (rc)
10430 {
10431 ++ct_colors_allocated;
10432
10433 p = (struct ct_color *) xmalloc (sizeof *p);
10434 p->r = color.red;
10435 p->g = color.green;
10436 p->b = color.blue;
10437 p->pixel = pixel;
10438 p->next = ct_table[i];
10439 ct_table[i] = p;
10440 }
10441 else
10442 return FRAME_FOREGROUND_PIXEL (f);
10443 }
10444 return p->pixel;
10445 }
10446
10447
10448 /* Value is a vector of all pixel colors contained in the color table,
10449 allocated via xmalloc. Set *N to the number of colors. */
10450
10451 static unsigned long *
10452 colors_in_color_table (n)
10453 int *n;
10454 {
10455 int i, j;
10456 struct ct_color *p;
10457 unsigned long *colors;
10458
10459 if (ct_colors_allocated == 0)
10460 {
10461 *n = 0;
10462 colors = NULL;
10463 }
10464 else
10465 {
10466 colors = (unsigned long *) xmalloc (ct_colors_allocated
10467 * sizeof *colors);
10468 *n = ct_colors_allocated;
10469
10470 for (i = j = 0; i < CT_SIZE; ++i)
10471 for (p = ct_table[i]; p; p = p->next)
10472 colors[j++] = p->pixel;
10473 }
10474
10475 return colors;
10476 }
10477
10478 #endif /* TODO */
10479
10480 \f
10481 /***********************************************************************
10482 Algorithms
10483 ***********************************************************************/
10484 #if 0 /* TODO: image support. */
10485 static XColor *x_to_xcolors P_ ((struct frame *, struct image *, int));
10486 static void x_from_xcolors P_ ((struct frame *, struct image *, XColor *));
10487 static void x_detect_edges P_ ((struct frame *, struct image *, int[9], int));
10488
10489 /* Non-zero means draw a cross on images having `:conversion
10490 disabled'. */
10491
10492 int cross_disabled_images;
10493
10494 /* Edge detection matrices for different edge-detection
10495 strategies. */
10496
10497 static int emboss_matrix[9] = {
10498 /* x - 1 x x + 1 */
10499 2, -1, 0, /* y - 1 */
10500 -1, 0, 1, /* y */
10501 0, 1, -2 /* y + 1 */
10502 };
10503
10504 static int laplace_matrix[9] = {
10505 /* x - 1 x x + 1 */
10506 1, 0, 0, /* y - 1 */
10507 0, 0, 0, /* y */
10508 0, 0, -1 /* y + 1 */
10509 };
10510
10511 /* Value is the intensity of the color whose red/green/blue values
10512 are R, G, and B. */
10513
10514 #define COLOR_INTENSITY(R, G, B) ((2 * (R) + 3 * (G) + (B)) / 6)
10515
10516
10517 /* On frame F, return an array of XColor structures describing image
10518 IMG->pixmap. Each XColor structure has its pixel color set. RGB_P
10519 non-zero means also fill the red/green/blue members of the XColor
10520 structures. Value is a pointer to the array of XColors structures,
10521 allocated with xmalloc; it must be freed by the caller. */
10522
10523 static XColor *
10524 x_to_xcolors (f, img, rgb_p)
10525 struct frame *f;
10526 struct image *img;
10527 int rgb_p;
10528 {
10529 int x, y;
10530 XColor *colors, *p;
10531 XImage *ximg;
10532
10533 colors = (XColor *) xmalloc (img->width * img->height * sizeof *colors);
10534
10535 /* Get the X image IMG->pixmap. */
10536 ximg = XGetImage (FRAME_X_DISPLAY (f), img->pixmap,
10537 0, 0, img->width, img->height, ~0, ZPixmap);
10538
10539 /* Fill the `pixel' members of the XColor array. I wished there
10540 were an easy and portable way to circumvent XGetPixel. */
10541 p = colors;
10542 for (y = 0; y < img->height; ++y)
10543 {
10544 XColor *row = p;
10545
10546 for (x = 0; x < img->width; ++x, ++p)
10547 p->pixel = XGetPixel (ximg, x, y);
10548
10549 if (rgb_p)
10550 x_query_colors (f, row, img->width);
10551 }
10552
10553 XDestroyImage (ximg);
10554 return colors;
10555 }
10556
10557
10558 /* Create IMG->pixmap from an array COLORS of XColor structures, whose
10559 RGB members are set. F is the frame on which this all happens.
10560 COLORS will be freed; an existing IMG->pixmap will be freed, too. */
10561
10562 static void
10563 x_from_xcolors (f, img, colors)
10564 struct frame *f;
10565 struct image *img;
10566 XColor *colors;
10567 {
10568 int x, y;
10569 XImage *oimg;
10570 Pixmap pixmap;
10571 XColor *p;
10572
10573 init_color_table ();
10574
10575 x_create_x_image_and_pixmap (f, img->width, img->height, 0,
10576 &oimg, &pixmap);
10577 p = colors;
10578 for (y = 0; y < img->height; ++y)
10579 for (x = 0; x < img->width; ++x, ++p)
10580 {
10581 unsigned long pixel;
10582 pixel = lookup_rgb_color (f, p->red, p->green, p->blue);
10583 XPutPixel (oimg, x, y, pixel);
10584 }
10585
10586 xfree (colors);
10587 x_clear_image_1 (f, img, 1, 0, 1);
10588
10589 x_put_x_image (f, oimg, pixmap, img->width, img->height);
10590 x_destroy_x_image (oimg);
10591 img->pixmap = pixmap;
10592 img->colors = colors_in_color_table (&img->ncolors);
10593 free_color_table ();
10594 }
10595
10596
10597 /* On frame F, perform edge-detection on image IMG.
10598
10599 MATRIX is a nine-element array specifying the transformation
10600 matrix. See emboss_matrix for an example.
10601
10602 COLOR_ADJUST is a color adjustment added to each pixel of the
10603 outgoing image. */
10604
10605 static void
10606 x_detect_edges (f, img, matrix, color_adjust)
10607 struct frame *f;
10608 struct image *img;
10609 int matrix[9], color_adjust;
10610 {
10611 XColor *colors = x_to_xcolors (f, img, 1);
10612 XColor *new, *p;
10613 int x, y, i, sum;
10614
10615 for (i = sum = 0; i < 9; ++i)
10616 sum += abs (matrix[i]);
10617
10618 #define COLOR(A, X, Y) ((A) + (Y) * img->width + (X))
10619
10620 new = (XColor *) xmalloc (img->width * img->height * sizeof *new);
10621
10622 for (y = 0; y < img->height; ++y)
10623 {
10624 p = COLOR (new, 0, y);
10625 p->red = p->green = p->blue = 0xffff/2;
10626 p = COLOR (new, img->width - 1, y);
10627 p->red = p->green = p->blue = 0xffff/2;
10628 }
10629
10630 for (x = 1; x < img->width - 1; ++x)
10631 {
10632 p = COLOR (new, x, 0);
10633 p->red = p->green = p->blue = 0xffff/2;
10634 p = COLOR (new, x, img->height - 1);
10635 p->red = p->green = p->blue = 0xffff/2;
10636 }
10637
10638 for (y = 1; y < img->height - 1; ++y)
10639 {
10640 p = COLOR (new, 1, y);
10641
10642 for (x = 1; x < img->width - 1; ++x, ++p)
10643 {
10644 int r, g, b, y1, x1;
10645
10646 r = g = b = i = 0;
10647 for (y1 = y - 1; y1 < y + 2; ++y1)
10648 for (x1 = x - 1; x1 < x + 2; ++x1, ++i)
10649 if (matrix[i])
10650 {
10651 XColor *t = COLOR (colors, x1, y1);
10652 r += matrix[i] * t->red;
10653 g += matrix[i] * t->green;
10654 b += matrix[i] * t->blue;
10655 }
10656
10657 r = (r / sum + color_adjust) & 0xffff;
10658 g = (g / sum + color_adjust) & 0xffff;
10659 b = (b / sum + color_adjust) & 0xffff;
10660 p->red = p->green = p->blue = COLOR_INTENSITY (r, g, b);
10661 }
10662 }
10663
10664 xfree (colors);
10665 x_from_xcolors (f, img, new);
10666
10667 #undef COLOR
10668 }
10669
10670
10671 /* Perform the pre-defined `emboss' edge-detection on image IMG
10672 on frame F. */
10673
10674 static void
10675 x_emboss (f, img)
10676 struct frame *f;
10677 struct image *img;
10678 {
10679 x_detect_edges (f, img, emboss_matrix, 0xffff / 2);
10680 }
10681
10682
10683 /* Transform image IMG which is used on frame F with a Laplace
10684 edge-detection algorithm. The result is an image that can be used
10685 to draw disabled buttons, for example. */
10686
10687 static void
10688 x_laplace (f, img)
10689 struct frame *f;
10690 struct image *img;
10691 {
10692 x_detect_edges (f, img, laplace_matrix, 45000);
10693 }
10694
10695
10696 /* Perform edge-detection on image IMG on frame F, with specified
10697 transformation matrix MATRIX and color-adjustment COLOR_ADJUST.
10698
10699 MATRIX must be either
10700
10701 - a list of at least 9 numbers in row-major form
10702 - a vector of at least 9 numbers
10703
10704 COLOR_ADJUST nil means use a default; otherwise it must be a
10705 number. */
10706
10707 static void
10708 x_edge_detection (f, img, matrix, color_adjust)
10709 struct frame *f;
10710 struct image *img;
10711 Lisp_Object matrix, color_adjust;
10712 {
10713 int i = 0;
10714 int trans[9];
10715
10716 if (CONSP (matrix))
10717 {
10718 for (i = 0;
10719 i < 9 && CONSP (matrix) && NUMBERP (XCAR (matrix));
10720 ++i, matrix = XCDR (matrix))
10721 trans[i] = XFLOATINT (XCAR (matrix));
10722 }
10723 else if (VECTORP (matrix) && ASIZE (matrix) >= 9)
10724 {
10725 for (i = 0; i < 9 && NUMBERP (AREF (matrix, i)); ++i)
10726 trans[i] = XFLOATINT (AREF (matrix, i));
10727 }
10728
10729 if (NILP (color_adjust))
10730 color_adjust = make_number (0xffff / 2);
10731
10732 if (i == 9 && NUMBERP (color_adjust))
10733 x_detect_edges (f, img, trans, (int) XFLOATINT (color_adjust));
10734 }
10735
10736
10737 /* Transform image IMG on frame F so that it looks disabled. */
10738
10739 static void
10740 x_disable_image (f, img)
10741 struct frame *f;
10742 struct image *img;
10743 {
10744 struct x_display_info *dpyinfo = FRAME_X_DISPLAY_INFO (f);
10745
10746 if (dpyinfo->n_planes >= 2)
10747 {
10748 /* Color (or grayscale). Convert to gray, and equalize. Just
10749 drawing such images with a stipple can look very odd, so
10750 we're using this method instead. */
10751 XColor *colors = x_to_xcolors (f, img, 1);
10752 XColor *p, *end;
10753 const int h = 15000;
10754 const int l = 30000;
10755
10756 for (p = colors, end = colors + img->width * img->height;
10757 p < end;
10758 ++p)
10759 {
10760 int i = COLOR_INTENSITY (p->red, p->green, p->blue);
10761 int i2 = (0xffff - h - l) * i / 0xffff + l;
10762 p->red = p->green = p->blue = i2;
10763 }
10764
10765 x_from_xcolors (f, img, colors);
10766 }
10767
10768 /* Draw a cross over the disabled image, if we must or if we
10769 should. */
10770 if (dpyinfo->n_planes < 2 || cross_disabled_images)
10771 {
10772 Display *dpy = FRAME_X_DISPLAY (f);
10773 GC gc;
10774
10775 gc = XCreateGC (dpy, img->pixmap, 0, NULL);
10776 XSetForeground (dpy, gc, BLACK_PIX_DEFAULT (f));
10777 XDrawLine (dpy, img->pixmap, gc, 0, 0,
10778 img->width - 1, img->height - 1);
10779 XDrawLine (dpy, img->pixmap, gc, 0, img->height - 1,
10780 img->width - 1, 0);
10781 XFreeGC (dpy, gc);
10782
10783 if (img->mask)
10784 {
10785 gc = XCreateGC (dpy, img->mask, 0, NULL);
10786 XSetForeground (dpy, gc, WHITE_PIX_DEFAULT (f));
10787 XDrawLine (dpy, img->mask, gc, 0, 0,
10788 img->width - 1, img->height - 1);
10789 XDrawLine (dpy, img->mask, gc, 0, img->height - 1,
10790 img->width - 1, 0);
10791 XFreeGC (dpy, gc);
10792 }
10793 }
10794 }
10795
10796
10797 /* Build a mask for image IMG which is used on frame F. FILE is the
10798 name of an image file, for error messages. HOW determines how to
10799 determine the background color of IMG. If it is a list '(R G B)',
10800 with R, G, and B being integers >= 0, take that as the color of the
10801 background. Otherwise, determine the background color of IMG
10802 heuristically. Value is non-zero if successful. */
10803
10804 static int
10805 x_build_heuristic_mask (f, img, how)
10806 struct frame *f;
10807 struct image *img;
10808 Lisp_Object how;
10809 {
10810 Display *dpy = FRAME_W32_DISPLAY (f);
10811 XImage *ximg, *mask_img;
10812 int x, y, rc, use_img_background;
10813 unsigned long bg = 0;
10814
10815 if (img->mask)
10816 {
10817 XFreePixmap (FRAME_X_DISPLAY (f), img->mask);
10818 img->mask = None;
10819 img->background_transparent_valid = 0;
10820 }
10821
10822 /* Create an image and pixmap serving as mask. */
10823 rc = x_create_x_image_and_pixmap (f, img->width, img->height, 1,
10824 &mask_img, &img->mask);
10825 if (!rc)
10826 return 0;
10827
10828 /* Get the X image of IMG->pixmap. */
10829 ximg = XGetImage (dpy, img->pixmap, 0, 0, img->width, img->height,
10830 ~0, ZPixmap);
10831
10832 /* Determine the background color of ximg. If HOW is `(R G B)'
10833 take that as color. Otherwise, use the image's background color. */
10834 use_img_background = 1;
10835
10836 if (CONSP (how))
10837 {
10838 int rgb[3], i;
10839
10840 for (i = 0; i < 3 && CONSP (how) && NATNUMP (XCAR (how)); ++i)
10841 {
10842 rgb[i] = XFASTINT (XCAR (how)) & 0xffff;
10843 how = XCDR (how);
10844 }
10845
10846 if (i == 3 && NILP (how))
10847 {
10848 char color_name[30];
10849 sprintf (color_name, "#%04x%04x%04x", rgb[0], rgb[1], rgb[2]);
10850 bg = x_alloc_image_color (f, img, build_string (color_name), 0);
10851 use_img_background = 0;
10852 }
10853 }
10854
10855 if (use_img_background)
10856 bg = four_corners_best (ximg, img->width, img->height);
10857
10858 /* Set all bits in mask_img to 1 whose color in ximg is different
10859 from the background color bg. */
10860 for (y = 0; y < img->height; ++y)
10861 for (x = 0; x < img->width; ++x)
10862 XPutPixel (mask_img, x, y, XGetPixel (ximg, x, y) != bg);
10863
10864 /* Fill in the background_transparent field while we have the mask handy. */
10865 image_background_transparent (img, f, mask_img);
10866
10867 /* Put mask_img into img->mask. */
10868 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
10869 x_destroy_x_image (mask_img);
10870 XDestroyImage (ximg);
10871
10872 return 1;
10873 }
10874 #endif /* TODO */
10875
10876 \f
10877 /***********************************************************************
10878 PBM (mono, gray, color)
10879 ***********************************************************************/
10880 #ifdef HAVE_PBM
10881
10882 static int pbm_image_p P_ ((Lisp_Object object));
10883 static int pbm_load P_ ((struct frame *f, struct image *img));
10884 static int pbm_scan_number P_ ((unsigned char **, unsigned char *));
10885
10886 /* The symbol `pbm' identifying images of this type. */
10887
10888 Lisp_Object Qpbm;
10889
10890 /* Indices of image specification fields in gs_format, below. */
10891
10892 enum pbm_keyword_index
10893 {
10894 PBM_TYPE,
10895 PBM_FILE,
10896 PBM_DATA,
10897 PBM_ASCENT,
10898 PBM_MARGIN,
10899 PBM_RELIEF,
10900 PBM_ALGORITHM,
10901 PBM_HEURISTIC_MASK,
10902 PBM_MASK,
10903 PBM_FOREGROUND,
10904 PBM_BACKGROUND,
10905 PBM_LAST
10906 };
10907
10908 /* Vector of image_keyword structures describing the format
10909 of valid user-defined image specifications. */
10910
10911 static struct image_keyword pbm_format[PBM_LAST] =
10912 {
10913 {":type", IMAGE_SYMBOL_VALUE, 1},
10914 {":file", IMAGE_STRING_VALUE, 0},
10915 {":data", IMAGE_STRING_VALUE, 0},
10916 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
10917 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
10918 {":relief", IMAGE_INTEGER_VALUE, 0},
10919 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10920 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10921 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
10922 {":foreground", IMAGE_STRING_OR_NIL_VALUE, 0},
10923 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
10924 };
10925
10926 /* Structure describing the image type `pbm'. */
10927
10928 static struct image_type pbm_type =
10929 {
10930 &Qpbm,
10931 pbm_image_p,
10932 pbm_load,
10933 x_clear_image,
10934 NULL
10935 };
10936
10937
10938 /* Return non-zero if OBJECT is a valid PBM image specification. */
10939
10940 static int
10941 pbm_image_p (object)
10942 Lisp_Object object;
10943 {
10944 struct image_keyword fmt[PBM_LAST];
10945
10946 bcopy (pbm_format, fmt, sizeof fmt);
10947
10948 if (!parse_image_spec (object, fmt, PBM_LAST, Qpbm)
10949 || (fmt[PBM_ASCENT].count
10950 && XFASTINT (fmt[PBM_ASCENT].value) > 100))
10951 return 0;
10952
10953 /* Must specify either :data or :file. */
10954 return fmt[PBM_DATA].count + fmt[PBM_FILE].count == 1;
10955 }
10956
10957
10958 /* Scan a decimal number from *S and return it. Advance *S while
10959 reading the number. END is the end of the string. Value is -1 at
10960 end of input. */
10961
10962 static int
10963 pbm_scan_number (s, end)
10964 unsigned char **s, *end;
10965 {
10966 int c, val = -1;
10967
10968 while (*s < end)
10969 {
10970 /* Skip white-space. */
10971 while (*s < end && (c = *(*s)++, isspace (c)))
10972 ;
10973
10974 if (c == '#')
10975 {
10976 /* Skip comment to end of line. */
10977 while (*s < end && (c = *(*s)++, c != '\n'))
10978 ;
10979 }
10980 else if (isdigit (c))
10981 {
10982 /* Read decimal number. */
10983 val = c - '0';
10984 while (*s < end && (c = *(*s)++, isdigit (c)))
10985 val = 10 * val + c - '0';
10986 break;
10987 }
10988 else
10989 break;
10990 }
10991
10992 return val;
10993 }
10994
10995
10996 /* Read FILE into memory. Value is a pointer to a buffer allocated
10997 with xmalloc holding FILE's contents. Value is null if an error
10998 occured. *SIZE is set to the size of the file. */
10999
11000 static char *
11001 pbm_read_file (file, size)
11002 Lisp_Object file;
11003 int *size;
11004 {
11005 FILE *fp = NULL;
11006 char *buf = NULL;
11007 struct stat st;
11008
11009 if (stat (XSTRING (file)->data, &st) == 0
11010 && (fp = fopen (XSTRING (file)->data, "r")) != NULL
11011 && (buf = (char *) xmalloc (st.st_size),
11012 fread (buf, 1, st.st_size, fp) == st.st_size))
11013 {
11014 *size = st.st_size;
11015 fclose (fp);
11016 }
11017 else
11018 {
11019 if (fp)
11020 fclose (fp);
11021 if (buf)
11022 {
11023 xfree (buf);
11024 buf = NULL;
11025 }
11026 }
11027
11028 return buf;
11029 }
11030
11031
11032 /* Load PBM image IMG for use on frame F. */
11033
11034 static int
11035 pbm_load (f, img)
11036 struct frame *f;
11037 struct image *img;
11038 {
11039 int raw_p, x, y;
11040 int width, height, max_color_idx = 0;
11041 XImage *ximg;
11042 Lisp_Object file, specified_file;
11043 enum {PBM_MONO, PBM_GRAY, PBM_COLOR} type;
11044 struct gcpro gcpro1;
11045 unsigned char *contents = NULL;
11046 unsigned char *end, *p;
11047 int size;
11048
11049 specified_file = image_spec_value (img->spec, QCfile, NULL);
11050 file = Qnil;
11051 GCPRO1 (file);
11052
11053 if (STRINGP (specified_file))
11054 {
11055 file = x_find_image_file (specified_file);
11056 if (!STRINGP (file))
11057 {
11058 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11059 UNGCPRO;
11060 return 0;
11061 }
11062
11063 contents = slurp_file (XSTRING (file)->data, &size);
11064 if (contents == NULL)
11065 {
11066 image_error ("Error reading `%s'", file, Qnil);
11067 UNGCPRO;
11068 return 0;
11069 }
11070
11071 p = contents;
11072 end = contents + size;
11073 }
11074 else
11075 {
11076 Lisp_Object data;
11077 data = image_spec_value (img->spec, QCdata, NULL);
11078 p = XSTRING (data)->data;
11079 end = p + STRING_BYTES (XSTRING (data));
11080 }
11081
11082 /* Check magic number. */
11083 if (end - p < 2 || *p++ != 'P')
11084 {
11085 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11086 error:
11087 xfree (contents);
11088 UNGCPRO;
11089 return 0;
11090 }
11091
11092 switch (*p++)
11093 {
11094 case '1':
11095 raw_p = 0, type = PBM_MONO;
11096 break;
11097
11098 case '2':
11099 raw_p = 0, type = PBM_GRAY;
11100 break;
11101
11102 case '3':
11103 raw_p = 0, type = PBM_COLOR;
11104 break;
11105
11106 case '4':
11107 raw_p = 1, type = PBM_MONO;
11108 break;
11109
11110 case '5':
11111 raw_p = 1, type = PBM_GRAY;
11112 break;
11113
11114 case '6':
11115 raw_p = 1, type = PBM_COLOR;
11116 break;
11117
11118 default:
11119 image_error ("Not a PBM image: `%s'", img->spec, Qnil);
11120 goto error;
11121 }
11122
11123 /* Read width, height, maximum color-component. Characters
11124 starting with `#' up to the end of a line are ignored. */
11125 width = pbm_scan_number (&p, end);
11126 height = pbm_scan_number (&p, end);
11127
11128 if (type != PBM_MONO)
11129 {
11130 max_color_idx = pbm_scan_number (&p, end);
11131 if (raw_p && max_color_idx > 255)
11132 max_color_idx = 255;
11133 }
11134
11135 if (width < 0
11136 || height < 0
11137 || (type != PBM_MONO && max_color_idx < 0))
11138 goto error;
11139
11140 if (!x_create_x_image_and_pixmap (f, width, height, 0,
11141 &ximg, &img->pixmap))
11142 goto error;
11143
11144 /* Initialize the color hash table. */
11145 init_color_table ();
11146
11147 if (type == PBM_MONO)
11148 {
11149 int c = 0, g;
11150 struct image_keyword fmt[PBM_LAST];
11151 unsigned long fg = FRAME_FOREGROUND_PIXEL (f);
11152 unsigned long bg = FRAME_BACKGROUND_PIXEL (f);
11153
11154 /* Parse the image specification. */
11155 bcopy (pbm_format, fmt, sizeof fmt);
11156 parse_image_spec (img->spec, fmt, PBM_LAST, Qpbm);
11157
11158 /* Get foreground and background colors, maybe allocate colors. */
11159 if (fmt[PBM_FOREGROUND].count
11160 && STRINGP (fmt[PBM_FOREGROUND].value))
11161 fg = x_alloc_image_color (f, img, fmt[PBM_FOREGROUND].value, fg);
11162 if (fmt[PBM_BACKGROUND].count
11163 && STRINGP (fmt[PBM_BACKGROUND].value))
11164 {
11165 bg = x_alloc_image_color (f, img, fmt[PBM_BACKGROUND].value, bg);
11166 img->background = bg;
11167 img->background_valid = 1;
11168 }
11169
11170 for (y = 0; y < height; ++y)
11171 for (x = 0; x < width; ++x)
11172 {
11173 if (raw_p)
11174 {
11175 if ((x & 7) == 0)
11176 c = *p++;
11177 g = c & 0x80;
11178 c <<= 1;
11179 }
11180 else
11181 g = pbm_scan_number (&p, end);
11182
11183 XPutPixel (ximg, x, y, g ? fg : bg);
11184 }
11185 }
11186 else
11187 {
11188 for (y = 0; y < height; ++y)
11189 for (x = 0; x < width; ++x)
11190 {
11191 int r, g, b;
11192
11193 if (type == PBM_GRAY)
11194 r = g = b = raw_p ? *p++ : pbm_scan_number (&p, end);
11195 else if (raw_p)
11196 {
11197 r = *p++;
11198 g = *p++;
11199 b = *p++;
11200 }
11201 else
11202 {
11203 r = pbm_scan_number (&p, end);
11204 g = pbm_scan_number (&p, end);
11205 b = pbm_scan_number (&p, end);
11206 }
11207
11208 if (r < 0 || g < 0 || b < 0)
11209 {
11210 xfree (ximg->data);
11211 ximg->data = NULL;
11212 XDestroyImage (ximg);
11213 image_error ("Invalid pixel value in image `%s'",
11214 img->spec, Qnil);
11215 goto error;
11216 }
11217
11218 /* RGB values are now in the range 0..max_color_idx.
11219 Scale this to the range 0..0xffff supported by X. */
11220 r = (double) r * 65535 / max_color_idx;
11221 g = (double) g * 65535 / max_color_idx;
11222 b = (double) b * 65535 / max_color_idx;
11223 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11224 }
11225 }
11226
11227 /* Store in IMG->colors the colors allocated for the image, and
11228 free the color table. */
11229 img->colors = colors_in_color_table (&img->ncolors);
11230 free_color_table ();
11231
11232 /* Maybe fill in the background field while we have ximg handy. */
11233 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11234 IMAGE_BACKGROUND (img, f, ximg);
11235
11236 /* Put the image into a pixmap. */
11237 x_put_x_image (f, ximg, img->pixmap, width, height);
11238 x_destroy_x_image (ximg);
11239
11240 img->width = width;
11241 img->height = height;
11242
11243 UNGCPRO;
11244 xfree (contents);
11245 return 1;
11246 }
11247 #endif /* HAVE_PBM */
11248
11249 \f
11250 /***********************************************************************
11251 PNG
11252 ***********************************************************************/
11253
11254 #if HAVE_PNG
11255
11256 #include <png.h>
11257
11258 /* Function prototypes. */
11259
11260 static int png_image_p P_ ((Lisp_Object object));
11261 static int png_load P_ ((struct frame *f, struct image *img));
11262
11263 /* The symbol `png' identifying images of this type. */
11264
11265 Lisp_Object Qpng;
11266
11267 /* Indices of image specification fields in png_format, below. */
11268
11269 enum png_keyword_index
11270 {
11271 PNG_TYPE,
11272 PNG_DATA,
11273 PNG_FILE,
11274 PNG_ASCENT,
11275 PNG_MARGIN,
11276 PNG_RELIEF,
11277 PNG_ALGORITHM,
11278 PNG_HEURISTIC_MASK,
11279 PNG_MASK,
11280 PNG_BACKGROUND,
11281 PNG_LAST
11282 };
11283
11284 /* Vector of image_keyword structures describing the format
11285 of valid user-defined image specifications. */
11286
11287 static struct image_keyword png_format[PNG_LAST] =
11288 {
11289 {":type", IMAGE_SYMBOL_VALUE, 1},
11290 {":data", IMAGE_STRING_VALUE, 0},
11291 {":file", IMAGE_STRING_VALUE, 0},
11292 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11293 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11294 {":relief", IMAGE_INTEGER_VALUE, 0},
11295 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11296 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11297 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11298 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11299 };
11300
11301 /* Structure describing the image type `png'. */
11302
11303 static struct image_type png_type =
11304 {
11305 &Qpng,
11306 png_image_p,
11307 png_load,
11308 x_clear_image,
11309 NULL
11310 };
11311
11312
11313 /* Return non-zero if OBJECT is a valid PNG image specification. */
11314
11315 static int
11316 png_image_p (object)
11317 Lisp_Object object;
11318 {
11319 struct image_keyword fmt[PNG_LAST];
11320 bcopy (png_format, fmt, sizeof fmt);
11321
11322 if (!parse_image_spec (object, fmt, PNG_LAST, Qpng)
11323 || (fmt[PNG_ASCENT].count
11324 && XFASTINT (fmt[PNG_ASCENT].value) > 100))
11325 return 0;
11326
11327 /* Must specify either the :data or :file keyword. */
11328 return fmt[PNG_FILE].count + fmt[PNG_DATA].count == 1;
11329 }
11330
11331
11332 /* Error and warning handlers installed when the PNG library
11333 is initialized. */
11334
11335 static void
11336 my_png_error (png_ptr, msg)
11337 png_struct *png_ptr;
11338 char *msg;
11339 {
11340 xassert (png_ptr != NULL);
11341 image_error ("PNG error: %s", build_string (msg), Qnil);
11342 longjmp (png_ptr->jmpbuf, 1);
11343 }
11344
11345
11346 static void
11347 my_png_warning (png_ptr, msg)
11348 png_struct *png_ptr;
11349 char *msg;
11350 {
11351 xassert (png_ptr != NULL);
11352 image_error ("PNG warning: %s", build_string (msg), Qnil);
11353 }
11354
11355 /* Memory source for PNG decoding. */
11356
11357 struct png_memory_storage
11358 {
11359 unsigned char *bytes; /* The data */
11360 size_t len; /* How big is it? */
11361 int index; /* Where are we? */
11362 };
11363
11364
11365 /* Function set as reader function when reading PNG image from memory.
11366 PNG_PTR is a pointer to the PNG control structure. Copy LENGTH
11367 bytes from the input to DATA. */
11368
11369 static void
11370 png_read_from_memory (png_ptr, data, length)
11371 png_structp png_ptr;
11372 png_bytep data;
11373 png_size_t length;
11374 {
11375 struct png_memory_storage *tbr
11376 = (struct png_memory_storage *) png_get_io_ptr (png_ptr);
11377
11378 if (length > tbr->len - tbr->index)
11379 png_error (png_ptr, "Read error");
11380
11381 bcopy (tbr->bytes + tbr->index, data, length);
11382 tbr->index = tbr->index + length;
11383 }
11384
11385 /* Load PNG image IMG for use on frame F. Value is non-zero if
11386 successful. */
11387
11388 static int
11389 png_load (f, img)
11390 struct frame *f;
11391 struct image *img;
11392 {
11393 Lisp_Object file, specified_file;
11394 Lisp_Object specified_data;
11395 int x, y, i;
11396 XImage *ximg, *mask_img = NULL;
11397 struct gcpro gcpro1;
11398 png_struct *png_ptr = NULL;
11399 png_info *info_ptr = NULL, *end_info = NULL;
11400 FILE *volatile fp = NULL;
11401 png_byte sig[8];
11402 png_byte *volatile pixels = NULL;
11403 png_byte **volatile rows = NULL;
11404 png_uint_32 width, height;
11405 int bit_depth, color_type, interlace_type;
11406 png_byte channels;
11407 png_uint_32 row_bytes;
11408 int transparent_p;
11409 char *gamma_str;
11410 double screen_gamma, image_gamma;
11411 int intent;
11412 struct png_memory_storage tbr; /* Data to be read */
11413
11414 /* Find out what file to load. */
11415 specified_file = image_spec_value (img->spec, QCfile, NULL);
11416 specified_data = image_spec_value (img->spec, QCdata, NULL);
11417 file = Qnil;
11418 GCPRO1 (file);
11419
11420 if (NILP (specified_data))
11421 {
11422 file = x_find_image_file (specified_file);
11423 if (!STRINGP (file))
11424 {
11425 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11426 UNGCPRO;
11427 return 0;
11428 }
11429
11430 /* Open the image file. */
11431 fp = fopen (XSTRING (file)->data, "rb");
11432 if (!fp)
11433 {
11434 image_error ("Cannot open image file `%s'", file, Qnil);
11435 UNGCPRO;
11436 fclose (fp);
11437 return 0;
11438 }
11439
11440 /* Check PNG signature. */
11441 if (fread (sig, 1, sizeof sig, fp) != sizeof sig
11442 || !png_check_sig (sig, sizeof sig))
11443 {
11444 image_error ("Not a PNG file:` %s'", file, Qnil);
11445 UNGCPRO;
11446 fclose (fp);
11447 return 0;
11448 }
11449 }
11450 else
11451 {
11452 /* Read from memory. */
11453 tbr.bytes = XSTRING (specified_data)->data;
11454 tbr.len = STRING_BYTES (XSTRING (specified_data));
11455 tbr.index = 0;
11456
11457 /* Check PNG signature. */
11458 if (tbr.len < sizeof sig
11459 || !png_check_sig (tbr.bytes, sizeof sig))
11460 {
11461 image_error ("Not a PNG image: `%s'", img->spec, Qnil);
11462 UNGCPRO;
11463 return 0;
11464 }
11465
11466 /* Need to skip past the signature. */
11467 tbr.bytes += sizeof (sig);
11468 }
11469
11470 /* Initialize read and info structs for PNG lib. */
11471 png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL,
11472 my_png_error, my_png_warning);
11473 if (!png_ptr)
11474 {
11475 if (fp) fclose (fp);
11476 UNGCPRO;
11477 return 0;
11478 }
11479
11480 info_ptr = png_create_info_struct (png_ptr);
11481 if (!info_ptr)
11482 {
11483 png_destroy_read_struct (&png_ptr, NULL, NULL);
11484 if (fp) fclose (fp);
11485 UNGCPRO;
11486 return 0;
11487 }
11488
11489 end_info = png_create_info_struct (png_ptr);
11490 if (!end_info)
11491 {
11492 png_destroy_read_struct (&png_ptr, &info_ptr, NULL);
11493 if (fp) fclose (fp);
11494 UNGCPRO;
11495 return 0;
11496 }
11497
11498 /* Set error jump-back. We come back here when the PNG library
11499 detects an error. */
11500 if (setjmp (png_ptr->jmpbuf))
11501 {
11502 error:
11503 if (png_ptr)
11504 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11505 xfree (pixels);
11506 xfree (rows);
11507 if (fp) fclose (fp);
11508 UNGCPRO;
11509 return 0;
11510 }
11511
11512 /* Read image info. */
11513 if (!NILP (specified_data))
11514 png_set_read_fn (png_ptr, (void *) &tbr, png_read_from_memory);
11515 else
11516 png_init_io (png_ptr, fp);
11517
11518 png_set_sig_bytes (png_ptr, sizeof sig);
11519 png_read_info (png_ptr, info_ptr);
11520 png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type,
11521 &interlace_type, NULL, NULL);
11522
11523 /* If image contains simply transparency data, we prefer to
11524 construct a clipping mask. */
11525 if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS))
11526 transparent_p = 1;
11527 else
11528 transparent_p = 0;
11529
11530 /* This function is easier to write if we only have to handle
11531 one data format: RGB or RGBA with 8 bits per channel. Let's
11532 transform other formats into that format. */
11533
11534 /* Strip more than 8 bits per channel. */
11535 if (bit_depth == 16)
11536 png_set_strip_16 (png_ptr);
11537
11538 /* Expand data to 24 bit RGB, or 8 bit grayscale, with alpha channel
11539 if available. */
11540 png_set_expand (png_ptr);
11541
11542 /* Convert grayscale images to RGB. */
11543 if (color_type == PNG_COLOR_TYPE_GRAY
11544 || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
11545 png_set_gray_to_rgb (png_ptr);
11546
11547 /* The value 2.2 is a guess for PC monitors from PNG example.c. */
11548 gamma_str = getenv ("SCREEN_GAMMA");
11549 screen_gamma = gamma_str ? atof (gamma_str) : 2.2;
11550
11551 /* Tell the PNG lib to handle gamma correction for us. */
11552
11553 #if defined(PNG_READ_sRGB_SUPPORTED) || defined(PNG_WRITE_sRGB_SUPPORTED)
11554 if (png_get_sRGB (png_ptr, info_ptr, &intent))
11555 /* There is a special chunk in the image specifying the gamma. */
11556 png_set_sRGB (png_ptr, info_ptr, intent);
11557 else
11558 #endif
11559 if (png_get_gAMA (png_ptr, info_ptr, &image_gamma))
11560 /* Image contains gamma information. */
11561 png_set_gamma (png_ptr, screen_gamma, image_gamma);
11562 else
11563 /* Use a default of 0.5 for the image gamma. */
11564 png_set_gamma (png_ptr, screen_gamma, 0.5);
11565
11566 /* Handle alpha channel by combining the image with a background
11567 color. Do this only if a real alpha channel is supplied. For
11568 simple transparency, we prefer a clipping mask. */
11569 if (!transparent_p)
11570 {
11571 png_color_16 *image_background;
11572 Lisp_Object specified_bg
11573 = image_spec_value (img->spec, QCbackground, NULL);
11574
11575
11576 if (STRINGP (specified_bg))
11577 /* The user specified `:background', use that. */
11578 {
11579 COLORREF color;
11580 if (w32_defined_color (f, XSTRING (specified_bg)->data, &color, 0))
11581 {
11582 png_color_16 user_bg;
11583
11584 bzero (&user_bg, sizeof user_bg);
11585 user_bg.red = color.red;
11586 user_bg.green = color.green;
11587 user_bg.blue = color.blue;
11588
11589 png_set_background (png_ptr, &user_bg,
11590 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11591 }
11592 }
11593 else if (png_get_bKGD (png_ptr, info_ptr, &image_background))
11594 /* Image contains a background color with which to
11595 combine the image. */
11596 png_set_background (png_ptr, image_background,
11597 PNG_BACKGROUND_GAMMA_FILE, 1, 1.0);
11598 else
11599 {
11600 /* Image does not contain a background color with which
11601 to combine the image data via an alpha channel. Use
11602 the frame's background instead. */
11603 XColor color;
11604 Colormap cmap;
11605 png_color_16 frame_background;
11606
11607 cmap = FRAME_X_COLORMAP (f);
11608 color.pixel = FRAME_BACKGROUND_PIXEL (f);
11609 x_query_color (f, &color);
11610
11611 bzero (&frame_background, sizeof frame_background);
11612 frame_background.red = color.red;
11613 frame_background.green = color.green;
11614 frame_background.blue = color.blue;
11615
11616 png_set_background (png_ptr, &frame_background,
11617 PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0);
11618 }
11619 }
11620
11621 /* Update info structure. */
11622 png_read_update_info (png_ptr, info_ptr);
11623
11624 /* Get number of channels. Valid values are 1 for grayscale images
11625 and images with a palette, 2 for grayscale images with transparency
11626 information (alpha channel), 3 for RGB images, and 4 for RGB
11627 images with alpha channel, i.e. RGBA. If conversions above were
11628 sufficient we should only have 3 or 4 channels here. */
11629 channels = png_get_channels (png_ptr, info_ptr);
11630 xassert (channels == 3 || channels == 4);
11631
11632 /* Number of bytes needed for one row of the image. */
11633 row_bytes = png_get_rowbytes (png_ptr, info_ptr);
11634
11635 /* Allocate memory for the image. */
11636 pixels = (png_byte *) xmalloc (row_bytes * height * sizeof *pixels);
11637 rows = (png_byte **) xmalloc (height * sizeof *rows);
11638 for (i = 0; i < height; ++i)
11639 rows[i] = pixels + i * row_bytes;
11640
11641 /* Read the entire image. */
11642 png_read_image (png_ptr, rows);
11643 png_read_end (png_ptr, info_ptr);
11644 if (fp)
11645 {
11646 fclose (fp);
11647 fp = NULL;
11648 }
11649
11650 /* Create the X image and pixmap. */
11651 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
11652 &img->pixmap))
11653 goto error;
11654
11655 /* Create an image and pixmap serving as mask if the PNG image
11656 contains an alpha channel. */
11657 if (channels == 4
11658 && !transparent_p
11659 && !x_create_x_image_and_pixmap (f, width, height, 1,
11660 &mask_img, &img->mask))
11661 {
11662 x_destroy_x_image (ximg);
11663 XFreePixmap (FRAME_W32_DISPLAY (f), img->pixmap);
11664 img->pixmap = 0;
11665 goto error;
11666 }
11667
11668 /* Fill the X image and mask from PNG data. */
11669 init_color_table ();
11670
11671 for (y = 0; y < height; ++y)
11672 {
11673 png_byte *p = rows[y];
11674
11675 for (x = 0; x < width; ++x)
11676 {
11677 unsigned r, g, b;
11678
11679 r = *p++ << 8;
11680 g = *p++ << 8;
11681 b = *p++ << 8;
11682 XPutPixel (ximg, x, y, lookup_rgb_color (f, r, g, b));
11683
11684 /* An alpha channel, aka mask channel, associates variable
11685 transparency with an image. Where other image formats
11686 support binary transparency---fully transparent or fully
11687 opaque---PNG allows up to 254 levels of partial transparency.
11688 The PNG library implements partial transparency by combining
11689 the image with a specified background color.
11690
11691 I'm not sure how to handle this here nicely: because the
11692 background on which the image is displayed may change, for
11693 real alpha channel support, it would be necessary to create
11694 a new image for each possible background.
11695
11696 What I'm doing now is that a mask is created if we have
11697 boolean transparency information. Otherwise I'm using
11698 the frame's background color to combine the image with. */
11699
11700 if (channels == 4)
11701 {
11702 if (mask_img)
11703 XPutPixel (mask_img, x, y, *p > 0);
11704 ++p;
11705 }
11706 }
11707 }
11708
11709 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
11710 /* Set IMG's background color from the PNG image, unless the user
11711 overrode it. */
11712 {
11713 png_color_16 *bg;
11714 if (png_get_bKGD (png_ptr, info_ptr, &bg))
11715 {
11716 img->background = lookup_rgb_color (f, bg->red, bg->green, bg->blue);
11717 img->background_valid = 1;
11718 }
11719 }
11720
11721 /* Remember colors allocated for this image. */
11722 img->colors = colors_in_color_table (&img->ncolors);
11723 free_color_table ();
11724
11725 /* Clean up. */
11726 png_destroy_read_struct (&png_ptr, &info_ptr, &end_info);
11727 xfree (rows);
11728 xfree (pixels);
11729
11730 img->width = width;
11731 img->height = height;
11732
11733 /* Maybe fill in the background field while we have ximg handy. */
11734 IMAGE_BACKGROUND (img, f, ximg);
11735
11736 /* Put the image into the pixmap, then free the X image and its buffer. */
11737 x_put_x_image (f, ximg, img->pixmap, width, height);
11738 x_destroy_x_image (ximg);
11739
11740 /* Same for the mask. */
11741 if (mask_img)
11742 {
11743 /* Fill in the background_transparent field while we have the mask
11744 handy. */
11745 image_background_transparent (img, f, mask_img);
11746
11747 x_put_x_image (f, mask_img, img->mask, img->width, img->height);
11748 x_destroy_x_image (mask_img);
11749 }
11750
11751 UNGCPRO;
11752 return 1;
11753 }
11754
11755 #endif /* HAVE_PNG != 0 */
11756
11757
11758 \f
11759 /***********************************************************************
11760 JPEG
11761 ***********************************************************************/
11762
11763 #if HAVE_JPEG
11764
11765 /* Work around a warning about HAVE_STDLIB_H being redefined in
11766 jconfig.h. */
11767 #ifdef HAVE_STDLIB_H
11768 #define HAVE_STDLIB_H_1
11769 #undef HAVE_STDLIB_H
11770 #endif /* HAVE_STLIB_H */
11771
11772 #include <jpeglib.h>
11773 #include <jerror.h>
11774 #include <setjmp.h>
11775
11776 #ifdef HAVE_STLIB_H_1
11777 #define HAVE_STDLIB_H 1
11778 #endif
11779
11780 static int jpeg_image_p P_ ((Lisp_Object object));
11781 static int jpeg_load P_ ((struct frame *f, struct image *img));
11782
11783 /* The symbol `jpeg' identifying images of this type. */
11784
11785 Lisp_Object Qjpeg;
11786
11787 /* Indices of image specification fields in gs_format, below. */
11788
11789 enum jpeg_keyword_index
11790 {
11791 JPEG_TYPE,
11792 JPEG_DATA,
11793 JPEG_FILE,
11794 JPEG_ASCENT,
11795 JPEG_MARGIN,
11796 JPEG_RELIEF,
11797 JPEG_ALGORITHM,
11798 JPEG_HEURISTIC_MASK,
11799 JPEG_MASK,
11800 JPEG_BACKGROUND,
11801 JPEG_LAST
11802 };
11803
11804 /* Vector of image_keyword structures describing the format
11805 of valid user-defined image specifications. */
11806
11807 static struct image_keyword jpeg_format[JPEG_LAST] =
11808 {
11809 {":type", IMAGE_SYMBOL_VALUE, 1},
11810 {":data", IMAGE_STRING_VALUE, 0},
11811 {":file", IMAGE_STRING_VALUE, 0},
11812 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
11813 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
11814 {":relief", IMAGE_INTEGER_VALUE, 0},
11815 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11816 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11817 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
11818 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
11819 };
11820
11821 /* Structure describing the image type `jpeg'. */
11822
11823 static struct image_type jpeg_type =
11824 {
11825 &Qjpeg,
11826 jpeg_image_p,
11827 jpeg_load,
11828 x_clear_image,
11829 NULL
11830 };
11831
11832
11833 /* Return non-zero if OBJECT is a valid JPEG image specification. */
11834
11835 static int
11836 jpeg_image_p (object)
11837 Lisp_Object object;
11838 {
11839 struct image_keyword fmt[JPEG_LAST];
11840
11841 bcopy (jpeg_format, fmt, sizeof fmt);
11842
11843 if (!parse_image_spec (object, fmt, JPEG_LAST, Qjpeg)
11844 || (fmt[JPEG_ASCENT].count
11845 && XFASTINT (fmt[JPEG_ASCENT].value) > 100))
11846 return 0;
11847
11848 /* Must specify either the :data or :file keyword. */
11849 return fmt[JPEG_FILE].count + fmt[JPEG_DATA].count == 1;
11850 }
11851
11852
11853 struct my_jpeg_error_mgr
11854 {
11855 struct jpeg_error_mgr pub;
11856 jmp_buf setjmp_buffer;
11857 };
11858
11859 static void
11860 my_error_exit (cinfo)
11861 j_common_ptr cinfo;
11862 {
11863 struct my_jpeg_error_mgr *mgr = (struct my_jpeg_error_mgr *) cinfo->err;
11864 longjmp (mgr->setjmp_buffer, 1);
11865 }
11866
11867 /* Init source method for JPEG data source manager. Called by
11868 jpeg_read_header() before any data is actually read. See
11869 libjpeg.doc from the JPEG lib distribution. */
11870
11871 static void
11872 our_init_source (cinfo)
11873 j_decompress_ptr cinfo;
11874 {
11875 }
11876
11877
11878 /* Fill input buffer method for JPEG data source manager. Called
11879 whenever more data is needed. We read the whole image in one step,
11880 so this only adds a fake end of input marker at the end. */
11881
11882 static boolean
11883 our_fill_input_buffer (cinfo)
11884 j_decompress_ptr cinfo;
11885 {
11886 /* Insert a fake EOI marker. */
11887 struct jpeg_source_mgr *src = cinfo->src;
11888 static JOCTET buffer[2];
11889
11890 buffer[0] = (JOCTET) 0xFF;
11891 buffer[1] = (JOCTET) JPEG_EOI;
11892
11893 src->next_input_byte = buffer;
11894 src->bytes_in_buffer = 2;
11895 return TRUE;
11896 }
11897
11898
11899 /* Method to skip over NUM_BYTES bytes in the image data. CINFO->src
11900 is the JPEG data source manager. */
11901
11902 static void
11903 our_skip_input_data (cinfo, num_bytes)
11904 j_decompress_ptr cinfo;
11905 long num_bytes;
11906 {
11907 struct jpeg_source_mgr *src = (struct jpeg_source_mgr *) cinfo->src;
11908
11909 if (src)
11910 {
11911 if (num_bytes > src->bytes_in_buffer)
11912 ERREXIT (cinfo, JERR_INPUT_EOF);
11913
11914 src->bytes_in_buffer -= num_bytes;
11915 src->next_input_byte += num_bytes;
11916 }
11917 }
11918
11919
11920 /* Method to terminate data source. Called by
11921 jpeg_finish_decompress() after all data has been processed. */
11922
11923 static void
11924 our_term_source (cinfo)
11925 j_decompress_ptr cinfo;
11926 {
11927 }
11928
11929
11930 /* Set up the JPEG lib for reading an image from DATA which contains
11931 LEN bytes. CINFO is the decompression info structure created for
11932 reading the image. */
11933
11934 static void
11935 jpeg_memory_src (cinfo, data, len)
11936 j_decompress_ptr cinfo;
11937 JOCTET *data;
11938 unsigned int len;
11939 {
11940 struct jpeg_source_mgr *src;
11941
11942 if (cinfo->src == NULL)
11943 {
11944 /* First time for this JPEG object? */
11945 cinfo->src = (struct jpeg_source_mgr *)
11946 (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT,
11947 sizeof (struct jpeg_source_mgr));
11948 src = (struct jpeg_source_mgr *) cinfo->src;
11949 src->next_input_byte = data;
11950 }
11951
11952 src = (struct jpeg_source_mgr *) cinfo->src;
11953 src->init_source = our_init_source;
11954 src->fill_input_buffer = our_fill_input_buffer;
11955 src->skip_input_data = our_skip_input_data;
11956 src->resync_to_restart = jpeg_resync_to_restart; /* Use default method. */
11957 src->term_source = our_term_source;
11958 src->bytes_in_buffer = len;
11959 src->next_input_byte = data;
11960 }
11961
11962
11963 /* Load image IMG for use on frame F. Patterned after example.c
11964 from the JPEG lib. */
11965
11966 static int
11967 jpeg_load (f, img)
11968 struct frame *f;
11969 struct image *img;
11970 {
11971 struct jpeg_decompress_struct cinfo;
11972 struct my_jpeg_error_mgr mgr;
11973 Lisp_Object file, specified_file;
11974 Lisp_Object specified_data;
11975 FILE * volatile fp = NULL;
11976 JSAMPARRAY buffer;
11977 int row_stride, x, y;
11978 XImage *ximg = NULL;
11979 int rc;
11980 unsigned long *colors;
11981 int width, height;
11982 struct gcpro gcpro1;
11983
11984 /* Open the JPEG file. */
11985 specified_file = image_spec_value (img->spec, QCfile, NULL);
11986 specified_data = image_spec_value (img->spec, QCdata, NULL);
11987 file = Qnil;
11988 GCPRO1 (file);
11989
11990 if (NILP (specified_data))
11991 {
11992 file = x_find_image_file (specified_file);
11993 if (!STRINGP (file))
11994 {
11995 image_error ("Cannot find image file `%s'", specified_file, Qnil);
11996 UNGCPRO;
11997 return 0;
11998 }
11999
12000 fp = fopen (XSTRING (file)->data, "r");
12001 if (fp == NULL)
12002 {
12003 image_error ("Cannot open `%s'", file, Qnil);
12004 UNGCPRO;
12005 return 0;
12006 }
12007 }
12008
12009 /* Customize libjpeg's error handling to call my_error_exit when an
12010 error is detected. This function will perform a longjmp. */
12011 cinfo.err = jpeg_std_error (&mgr.pub);
12012 mgr.pub.error_exit = my_error_exit;
12013
12014 if ((rc = setjmp (mgr.setjmp_buffer)) != 0)
12015 {
12016 if (rc == 1)
12017 {
12018 /* Called from my_error_exit. Display a JPEG error. */
12019 char buffer[JMSG_LENGTH_MAX];
12020 cinfo.err->format_message ((j_common_ptr) &cinfo, buffer);
12021 image_error ("Error reading JPEG image `%s': %s", img->spec,
12022 build_string (buffer));
12023 }
12024
12025 /* Close the input file and destroy the JPEG object. */
12026 if (fp)
12027 fclose (fp);
12028 jpeg_destroy_decompress (&cinfo);
12029
12030 /* If we already have an XImage, free that. */
12031 x_destroy_x_image (ximg);
12032
12033 /* Free pixmap and colors. */
12034 x_clear_image (f, img);
12035
12036 UNGCPRO;
12037 return 0;
12038 }
12039
12040 /* Create the JPEG decompression object. Let it read from fp.
12041 Read the JPEG image header. */
12042 jpeg_create_decompress (&cinfo);
12043
12044 if (NILP (specified_data))
12045 jpeg_stdio_src (&cinfo, fp);
12046 else
12047 jpeg_memory_src (&cinfo, XSTRING (specified_data)->data,
12048 STRING_BYTES (XSTRING (specified_data)));
12049
12050 jpeg_read_header (&cinfo, TRUE);
12051
12052 /* Customize decompression so that color quantization will be used.
12053 Start decompression. */
12054 cinfo.quantize_colors = TRUE;
12055 jpeg_start_decompress (&cinfo);
12056 width = img->width = cinfo.output_width;
12057 height = img->height = cinfo.output_height;
12058
12059 /* Create X image and pixmap. */
12060 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg,
12061 &img->pixmap))
12062 longjmp (mgr.setjmp_buffer, 2);
12063
12064 /* Allocate colors. When color quantization is used,
12065 cinfo.actual_number_of_colors has been set with the number of
12066 colors generated, and cinfo.colormap is a two-dimensional array
12067 of color indices in the range 0..cinfo.actual_number_of_colors.
12068 No more than 255 colors will be generated. */
12069 {
12070 int i, ir, ig, ib;
12071
12072 if (cinfo.out_color_components > 2)
12073 ir = 0, ig = 1, ib = 2;
12074 else if (cinfo.out_color_components > 1)
12075 ir = 0, ig = 1, ib = 0;
12076 else
12077 ir = 0, ig = 0, ib = 0;
12078
12079 /* Use the color table mechanism because it handles colors that
12080 cannot be allocated nicely. Such colors will be replaced with
12081 a default color, and we don't have to care about which colors
12082 can be freed safely, and which can't. */
12083 init_color_table ();
12084 colors = (unsigned long *) alloca (cinfo.actual_number_of_colors
12085 * sizeof *colors);
12086
12087 for (i = 0; i < cinfo.actual_number_of_colors; ++i)
12088 {
12089 /* Multiply RGB values with 255 because X expects RGB values
12090 in the range 0..0xffff. */
12091 int r = cinfo.colormap[ir][i] << 8;
12092 int g = cinfo.colormap[ig][i] << 8;
12093 int b = cinfo.colormap[ib][i] << 8;
12094 colors[i] = lookup_rgb_color (f, r, g, b);
12095 }
12096
12097 /* Remember those colors actually allocated. */
12098 img->colors = colors_in_color_table (&img->ncolors);
12099 free_color_table ();
12100 }
12101
12102 /* Read pixels. */
12103 row_stride = width * cinfo.output_components;
12104 buffer = cinfo.mem->alloc_sarray ((j_common_ptr) &cinfo, JPOOL_IMAGE,
12105 row_stride, 1);
12106 for (y = 0; y < height; ++y)
12107 {
12108 jpeg_read_scanlines (&cinfo, buffer, 1);
12109 for (x = 0; x < cinfo.output_width; ++x)
12110 XPutPixel (ximg, x, y, colors[buffer[0][x]]);
12111 }
12112
12113 /* Clean up. */
12114 jpeg_finish_decompress (&cinfo);
12115 jpeg_destroy_decompress (&cinfo);
12116 if (fp)
12117 fclose (fp);
12118
12119 /* Maybe fill in the background field while we have ximg handy. */
12120 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12121 IMAGE_BACKGROUND (img, f, ximg);
12122
12123 /* Put the image into the pixmap. */
12124 x_put_x_image (f, ximg, img->pixmap, width, height);
12125 x_destroy_x_image (ximg);
12126 UNBLOCK_INPUT;
12127 UNGCPRO;
12128 return 1;
12129 }
12130
12131 #endif /* HAVE_JPEG */
12132
12133
12134 \f
12135 /***********************************************************************
12136 TIFF
12137 ***********************************************************************/
12138
12139 #if HAVE_TIFF
12140
12141 #include <tiffio.h>
12142
12143 static int tiff_image_p P_ ((Lisp_Object object));
12144 static int tiff_load P_ ((struct frame *f, struct image *img));
12145
12146 /* The symbol `tiff' identifying images of this type. */
12147
12148 Lisp_Object Qtiff;
12149
12150 /* Indices of image specification fields in tiff_format, below. */
12151
12152 enum tiff_keyword_index
12153 {
12154 TIFF_TYPE,
12155 TIFF_DATA,
12156 TIFF_FILE,
12157 TIFF_ASCENT,
12158 TIFF_MARGIN,
12159 TIFF_RELIEF,
12160 TIFF_ALGORITHM,
12161 TIFF_HEURISTIC_MASK,
12162 TIFF_MASK,
12163 TIFF_BACKGROUND,
12164 TIFF_LAST
12165 };
12166
12167 /* Vector of image_keyword structures describing the format
12168 of valid user-defined image specifications. */
12169
12170 static struct image_keyword tiff_format[TIFF_LAST] =
12171 {
12172 {":type", IMAGE_SYMBOL_VALUE, 1},
12173 {":data", IMAGE_STRING_VALUE, 0},
12174 {":file", IMAGE_STRING_VALUE, 0},
12175 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12176 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12177 {":relief", IMAGE_INTEGER_VALUE, 0},
12178 {":conversions", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12179 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12180 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12181 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12182 };
12183
12184 /* Structure describing the image type `tiff'. */
12185
12186 static struct image_type tiff_type =
12187 {
12188 &Qtiff,
12189 tiff_image_p,
12190 tiff_load,
12191 x_clear_image,
12192 NULL
12193 };
12194
12195
12196 /* Return non-zero if OBJECT is a valid TIFF image specification. */
12197
12198 static int
12199 tiff_image_p (object)
12200 Lisp_Object object;
12201 {
12202 struct image_keyword fmt[TIFF_LAST];
12203 bcopy (tiff_format, fmt, sizeof fmt);
12204
12205 if (!parse_image_spec (object, fmt, TIFF_LAST, Qtiff)
12206 || (fmt[TIFF_ASCENT].count
12207 && XFASTINT (fmt[TIFF_ASCENT].value) > 100))
12208 return 0;
12209
12210 /* Must specify either the :data or :file keyword. */
12211 return fmt[TIFF_FILE].count + fmt[TIFF_DATA].count == 1;
12212 }
12213
12214
12215 /* Reading from a memory buffer for TIFF images Based on the PNG
12216 memory source, but we have to provide a lot of extra functions.
12217 Blah.
12218
12219 We really only need to implement read and seek, but I am not
12220 convinced that the TIFF library is smart enough not to destroy
12221 itself if we only hand it the function pointers we need to
12222 override. */
12223
12224 typedef struct
12225 {
12226 unsigned char *bytes;
12227 size_t len;
12228 int index;
12229 }
12230 tiff_memory_source;
12231
12232 static size_t
12233 tiff_read_from_memory (data, buf, size)
12234 thandle_t data;
12235 tdata_t buf;
12236 tsize_t size;
12237 {
12238 tiff_memory_source *src = (tiff_memory_source *) data;
12239
12240 if (size > src->len - src->index)
12241 return (size_t) -1;
12242 bcopy (src->bytes + src->index, buf, size);
12243 src->index += size;
12244 return size;
12245 }
12246
12247 static size_t
12248 tiff_write_from_memory (data, buf, size)
12249 thandle_t data;
12250 tdata_t buf;
12251 tsize_t size;
12252 {
12253 return (size_t) -1;
12254 }
12255
12256 static toff_t
12257 tiff_seek_in_memory (data, off, whence)
12258 thandle_t data;
12259 toff_t off;
12260 int whence;
12261 {
12262 tiff_memory_source *src = (tiff_memory_source *) data;
12263 int idx;
12264
12265 switch (whence)
12266 {
12267 case SEEK_SET: /* Go from beginning of source. */
12268 idx = off;
12269 break;
12270
12271 case SEEK_END: /* Go from end of source. */
12272 idx = src->len + off;
12273 break;
12274
12275 case SEEK_CUR: /* Go from current position. */
12276 idx = src->index + off;
12277 break;
12278
12279 default: /* Invalid `whence'. */
12280 return -1;
12281 }
12282
12283 if (idx > src->len || idx < 0)
12284 return -1;
12285
12286 src->index = idx;
12287 return src->index;
12288 }
12289
12290 static int
12291 tiff_close_memory (data)
12292 thandle_t data;
12293 {
12294 /* NOOP */
12295 return 0;
12296 }
12297
12298 static int
12299 tiff_mmap_memory (data, pbase, psize)
12300 thandle_t data;
12301 tdata_t *pbase;
12302 toff_t *psize;
12303 {
12304 /* It is already _IN_ memory. */
12305 return 0;
12306 }
12307
12308 static void
12309 tiff_unmap_memory (data, base, size)
12310 thandle_t data;
12311 tdata_t base;
12312 toff_t size;
12313 {
12314 /* We don't need to do this. */
12315 }
12316
12317 static toff_t
12318 tiff_size_of_memory (data)
12319 thandle_t data;
12320 {
12321 return ((tiff_memory_source *) data)->len;
12322 }
12323
12324
12325 static void
12326 tiff_error_handler (title, format, ap)
12327 const char *title, *format;
12328 va_list ap;
12329 {
12330 char buf[512];
12331 int len;
12332
12333 len = sprintf (buf, "TIFF error: %s ", title);
12334 vsprintf (buf + len, format, ap);
12335 add_to_log (buf, Qnil, Qnil);
12336 }
12337
12338
12339 static void
12340 tiff_warning_handler (title, format, ap)
12341 const char *title, *format;
12342 va_list ap;
12343 {
12344 char buf[512];
12345 int len;
12346
12347 len = sprintf (buf, "TIFF warning: %s ", title);
12348 vsprintf (buf + len, format, ap);
12349 add_to_log (buf, Qnil, Qnil);
12350 }
12351
12352
12353 /* Load TIFF image IMG for use on frame F. Value is non-zero if
12354 successful. */
12355
12356 static int
12357 tiff_load (f, img)
12358 struct frame *f;
12359 struct image *img;
12360 {
12361 Lisp_Object file, specified_file;
12362 Lisp_Object specified_data;
12363 TIFF *tiff;
12364 int width, height, x, y;
12365 uint32 *buf;
12366 int rc;
12367 XImage *ximg;
12368 struct gcpro gcpro1;
12369 tiff_memory_source memsrc;
12370
12371 specified_file = image_spec_value (img->spec, QCfile, NULL);
12372 specified_data = image_spec_value (img->spec, QCdata, NULL);
12373 file = Qnil;
12374 GCPRO1 (file);
12375
12376 TIFFSetErrorHandler (tiff_error_handler);
12377 TIFFSetWarningHandler (tiff_warning_handler);
12378
12379 if (NILP (specified_data))
12380 {
12381 /* Read from a file */
12382 file = x_find_image_file (specified_file);
12383 if (!STRINGP (file))
12384 {
12385 image_error ("Cannot find image file `%s'", file, Qnil);
12386 UNGCPRO;
12387 return 0;
12388 }
12389
12390 /* Try to open the image file. */
12391 tiff = TIFFOpen (XSTRING (file)->data, "r");
12392 if (tiff == NULL)
12393 {
12394 image_error ("Cannot open `%s'", file, Qnil);
12395 UNGCPRO;
12396 return 0;
12397 }
12398 }
12399 else
12400 {
12401 /* Memory source! */
12402 memsrc.bytes = XSTRING (specified_data)->data;
12403 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12404 memsrc.index = 0;
12405
12406 tiff = TIFFClientOpen ("memory_source", "r", &memsrc,
12407 (TIFFReadWriteProc) tiff_read_from_memory,
12408 (TIFFReadWriteProc) tiff_write_from_memory,
12409 tiff_seek_in_memory,
12410 tiff_close_memory,
12411 tiff_size_of_memory,
12412 tiff_mmap_memory,
12413 tiff_unmap_memory);
12414
12415 if (!tiff)
12416 {
12417 image_error ("Cannot open memory source for `%s'", img->spec, Qnil);
12418 UNGCPRO;
12419 return 0;
12420 }
12421 }
12422
12423 /* Get width and height of the image, and allocate a raster buffer
12424 of width x height 32-bit values. */
12425 TIFFGetField (tiff, TIFFTAG_IMAGEWIDTH, &width);
12426 TIFFGetField (tiff, TIFFTAG_IMAGELENGTH, &height);
12427 buf = (uint32 *) xmalloc (width * height * sizeof *buf);
12428
12429 rc = TIFFReadRGBAImage (tiff, width, height, buf, 0);
12430 TIFFClose (tiff);
12431 if (!rc)
12432 {
12433 image_error ("Error reading TIFF image `%s'", img->spec, Qnil);
12434 xfree (buf);
12435 UNGCPRO;
12436 return 0;
12437 }
12438
12439 /* Create the X image and pixmap. */
12440 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12441 {
12442 xfree (buf);
12443 UNGCPRO;
12444 return 0;
12445 }
12446
12447 /* Initialize the color table. */
12448 init_color_table ();
12449
12450 /* Process the pixel raster. Origin is in the lower-left corner. */
12451 for (y = 0; y < height; ++y)
12452 {
12453 uint32 *row = buf + y * width;
12454
12455 for (x = 0; x < width; ++x)
12456 {
12457 uint32 abgr = row[x];
12458 int r = TIFFGetR (abgr) << 8;
12459 int g = TIFFGetG (abgr) << 8;
12460 int b = TIFFGetB (abgr) << 8;
12461 XPutPixel (ximg, x, height - 1 - y, lookup_rgb_color (f, r, g, b));
12462 }
12463 }
12464
12465 /* Remember the colors allocated for the image. Free the color table. */
12466 img->colors = colors_in_color_table (&img->ncolors);
12467 free_color_table ();
12468
12469 img->width = width;
12470 img->height = height;
12471
12472 /* Maybe fill in the background field while we have ximg handy. */
12473 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12474 IMAGE_BACKGROUND (img, f, ximg);
12475
12476 /* Put the image into the pixmap, then free the X image and its buffer. */
12477 x_put_x_image (f, ximg, img->pixmap, width, height);
12478 x_destroy_x_image (ximg);
12479 xfree (buf);
12480
12481 UNGCPRO;
12482 return 1;
12483 }
12484
12485 #endif /* HAVE_TIFF != 0 */
12486
12487
12488 \f
12489 /***********************************************************************
12490 GIF
12491 ***********************************************************************/
12492
12493 #if HAVE_GIF
12494
12495 #include <gif_lib.h>
12496
12497 static int gif_image_p P_ ((Lisp_Object object));
12498 static int gif_load P_ ((struct frame *f, struct image *img));
12499
12500 /* The symbol `gif' identifying images of this type. */
12501
12502 Lisp_Object Qgif;
12503
12504 /* Indices of image specification fields in gif_format, below. */
12505
12506 enum gif_keyword_index
12507 {
12508 GIF_TYPE,
12509 GIF_DATA,
12510 GIF_FILE,
12511 GIF_ASCENT,
12512 GIF_MARGIN,
12513 GIF_RELIEF,
12514 GIF_ALGORITHM,
12515 GIF_HEURISTIC_MASK,
12516 GIF_MASK,
12517 GIF_IMAGE,
12518 GIF_BACKGROUND,
12519 GIF_LAST
12520 };
12521
12522 /* Vector of image_keyword structures describing the format
12523 of valid user-defined image specifications. */
12524
12525 static struct image_keyword gif_format[GIF_LAST] =
12526 {
12527 {":type", IMAGE_SYMBOL_VALUE, 1},
12528 {":data", IMAGE_STRING_VALUE, 0},
12529 {":file", IMAGE_STRING_VALUE, 0},
12530 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12531 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12532 {":relief", IMAGE_INTEGER_VALUE, 0},
12533 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12534 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12535 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12536 {":image", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12537 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12538 };
12539
12540 /* Structure describing the image type `gif'. */
12541
12542 static struct image_type gif_type =
12543 {
12544 &Qgif,
12545 gif_image_p,
12546 gif_load,
12547 x_clear_image,
12548 NULL
12549 };
12550
12551 /* Return non-zero if OBJECT is a valid GIF image specification. */
12552
12553 static int
12554 gif_image_p (object)
12555 Lisp_Object object;
12556 {
12557 struct image_keyword fmt[GIF_LAST];
12558 bcopy (gif_format, fmt, sizeof fmt);
12559
12560 if (!parse_image_spec (object, fmt, GIF_LAST, Qgif)
12561 || (fmt[GIF_ASCENT].count
12562 && XFASTINT (fmt[GIF_ASCENT].value) > 100))
12563 return 0;
12564
12565 /* Must specify either the :data or :file keyword. */
12566 return fmt[GIF_FILE].count + fmt[GIF_DATA].count == 1;
12567 }
12568
12569 /* Reading a GIF image from memory
12570 Based on the PNG memory stuff to a certain extent. */
12571
12572 typedef struct
12573 {
12574 unsigned char *bytes;
12575 size_t len;
12576 int index;
12577 }
12578 gif_memory_source;
12579
12580 /* Make the current memory source available to gif_read_from_memory.
12581 It's done this way because not all versions of libungif support
12582 a UserData field in the GifFileType structure. */
12583 static gif_memory_source *current_gif_memory_src;
12584
12585 static int
12586 gif_read_from_memory (file, buf, len)
12587 GifFileType *file;
12588 GifByteType *buf;
12589 int len;
12590 {
12591 gif_memory_source *src = current_gif_memory_src;
12592
12593 if (len > src->len - src->index)
12594 return -1;
12595
12596 bcopy (src->bytes + src->index, buf, len);
12597 src->index += len;
12598 return len;
12599 }
12600
12601
12602 /* Load GIF image IMG for use on frame F. Value is non-zero if
12603 successful. */
12604
12605 static int
12606 gif_load (f, img)
12607 struct frame *f;
12608 struct image *img;
12609 {
12610 Lisp_Object file, specified_file;
12611 Lisp_Object specified_data;
12612 int rc, width, height, x, y, i;
12613 XImage *ximg;
12614 ColorMapObject *gif_color_map;
12615 unsigned long pixel_colors[256];
12616 GifFileType *gif;
12617 struct gcpro gcpro1;
12618 Lisp_Object image;
12619 int ino, image_left, image_top, image_width, image_height;
12620 gif_memory_source memsrc;
12621 unsigned char *raster;
12622
12623 specified_file = image_spec_value (img->spec, QCfile, NULL);
12624 specified_data = image_spec_value (img->spec, QCdata, NULL);
12625 file = Qnil;
12626 GCPRO1 (file);
12627
12628 if (NILP (specified_data))
12629 {
12630 file = x_find_image_file (specified_file);
12631 if (!STRINGP (file))
12632 {
12633 image_error ("Cannot find image file `%s'", specified_file, Qnil);
12634 UNGCPRO;
12635 return 0;
12636 }
12637
12638 /* Open the GIF file. */
12639 gif = DGifOpenFileName (XSTRING (file)->data);
12640 if (gif == NULL)
12641 {
12642 image_error ("Cannot open `%s'", file, Qnil);
12643 UNGCPRO;
12644 return 0;
12645 }
12646 }
12647 else
12648 {
12649 /* Read from memory! */
12650 current_gif_memory_src = &memsrc;
12651 memsrc.bytes = XSTRING (specified_data)->data;
12652 memsrc.len = STRING_BYTES (XSTRING (specified_data));
12653 memsrc.index = 0;
12654
12655 gif = DGifOpen(&memsrc, gif_read_from_memory);
12656 if (!gif)
12657 {
12658 image_error ("Cannot open memory source `%s'", img->spec, Qnil);
12659 UNGCPRO;
12660 return 0;
12661 }
12662 }
12663
12664 /* Read entire contents. */
12665 rc = DGifSlurp (gif);
12666 if (rc == GIF_ERROR)
12667 {
12668 image_error ("Error reading `%s'", img->spec, Qnil);
12669 DGifCloseFile (gif);
12670 UNGCPRO;
12671 return 0;
12672 }
12673
12674 image = image_spec_value (img->spec, QCindex, NULL);
12675 ino = INTEGERP (image) ? XFASTINT (image) : 0;
12676 if (ino >= gif->ImageCount)
12677 {
12678 image_error ("Invalid image number `%s' in image `%s'",
12679 image, img->spec);
12680 DGifCloseFile (gif);
12681 UNGCPRO;
12682 return 0;
12683 }
12684
12685 width = img->width = gif->SWidth;
12686 height = img->height = gif->SHeight;
12687
12688 /* Create the X image and pixmap. */
12689 if (!x_create_x_image_and_pixmap (f, width, height, 0, &ximg, &img->pixmap))
12690 {
12691 DGifCloseFile (gif);
12692 UNGCPRO;
12693 return 0;
12694 }
12695
12696 /* Allocate colors. */
12697 gif_color_map = gif->SavedImages[ino].ImageDesc.ColorMap;
12698 if (!gif_color_map)
12699 gif_color_map = gif->SColorMap;
12700 init_color_table ();
12701 bzero (pixel_colors, sizeof pixel_colors);
12702
12703 for (i = 0; i < gif_color_map->ColorCount; ++i)
12704 {
12705 int r = gif_color_map->Colors[i].Red << 8;
12706 int g = gif_color_map->Colors[i].Green << 8;
12707 int b = gif_color_map->Colors[i].Blue << 8;
12708 pixel_colors[i] = lookup_rgb_color (f, r, g, b);
12709 }
12710
12711 img->colors = colors_in_color_table (&img->ncolors);
12712 free_color_table ();
12713
12714 /* Clear the part of the screen image that are not covered by
12715 the image from the GIF file. Full animated GIF support
12716 requires more than can be done here (see the gif89 spec,
12717 disposal methods). Let's simply assume that the part
12718 not covered by a sub-image is in the frame's background color. */
12719 image_top = gif->SavedImages[ino].ImageDesc.Top;
12720 image_left = gif->SavedImages[ino].ImageDesc.Left;
12721 image_width = gif->SavedImages[ino].ImageDesc.Width;
12722 image_height = gif->SavedImages[ino].ImageDesc.Height;
12723
12724 for (y = 0; y < image_top; ++y)
12725 for (x = 0; x < width; ++x)
12726 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12727
12728 for (y = image_top + image_height; y < height; ++y)
12729 for (x = 0; x < width; ++x)
12730 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12731
12732 for (y = image_top; y < image_top + image_height; ++y)
12733 {
12734 for (x = 0; x < image_left; ++x)
12735 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12736 for (x = image_left + image_width; x < width; ++x)
12737 XPutPixel (ximg, x, y, FRAME_BACKGROUND_PIXEL (f));
12738 }
12739
12740 /* Read the GIF image into the X image. We use a local variable
12741 `raster' here because RasterBits below is a char *, and invites
12742 problems with bytes >= 0x80. */
12743 raster = (unsigned char *) gif->SavedImages[ino].RasterBits;
12744
12745 if (gif->SavedImages[ino].ImageDesc.Interlace)
12746 {
12747 static int interlace_start[] = {0, 4, 2, 1};
12748 static int interlace_increment[] = {8, 8, 4, 2};
12749 int pass;
12750 int row = interlace_start[0];
12751
12752 pass = 0;
12753
12754 for (y = 0; y < image_height; y++)
12755 {
12756 if (row >= image_height)
12757 {
12758 row = interlace_start[++pass];
12759 while (row >= image_height)
12760 row = interlace_start[++pass];
12761 }
12762
12763 for (x = 0; x < image_width; x++)
12764 {
12765 int i = raster[(y * image_width) + x];
12766 XPutPixel (ximg, x + image_left, row + image_top,
12767 pixel_colors[i]);
12768 }
12769
12770 row += interlace_increment[pass];
12771 }
12772 }
12773 else
12774 {
12775 for (y = 0; y < image_height; ++y)
12776 for (x = 0; x < image_width; ++x)
12777 {
12778 int i = raster[y* image_width + x];
12779 XPutPixel (ximg, x + image_left, y + image_top, pixel_colors[i]);
12780 }
12781 }
12782
12783 DGifCloseFile (gif);
12784
12785 /* Maybe fill in the background field while we have ximg handy. */
12786 if (NILP (image_spec_value (img->spec, QCbackground, NULL)))
12787 IMAGE_BACKGROUND (img, f, ximg);
12788
12789 /* Put the image into the pixmap, then free the X image and its buffer. */
12790 x_put_x_image (f, ximg, img->pixmap, width, height);
12791 x_destroy_x_image (ximg);
12792
12793 UNGCPRO;
12794 return 1;
12795 }
12796
12797 #endif /* HAVE_GIF != 0 */
12798
12799
12800 \f
12801 /***********************************************************************
12802 Ghostscript
12803 ***********************************************************************/
12804
12805 Lisp_Object Qpostscript;
12806
12807 #ifdef HAVE_GHOSTSCRIPT
12808 static int gs_image_p P_ ((Lisp_Object object));
12809 static int gs_load P_ ((struct frame *f, struct image *img));
12810 static void gs_clear_image P_ ((struct frame *f, struct image *img));
12811
12812 /* The symbol `postscript' identifying images of this type. */
12813
12814 /* Keyword symbols. */
12815
12816 Lisp_Object QCloader, QCbounding_box, QCpt_width, QCpt_height;
12817
12818 /* Indices of image specification fields in gs_format, below. */
12819
12820 enum gs_keyword_index
12821 {
12822 GS_TYPE,
12823 GS_PT_WIDTH,
12824 GS_PT_HEIGHT,
12825 GS_FILE,
12826 GS_LOADER,
12827 GS_BOUNDING_BOX,
12828 GS_ASCENT,
12829 GS_MARGIN,
12830 GS_RELIEF,
12831 GS_ALGORITHM,
12832 GS_HEURISTIC_MASK,
12833 GS_MASK,
12834 GS_BACKGROUND,
12835 GS_LAST
12836 };
12837
12838 /* Vector of image_keyword structures describing the format
12839 of valid user-defined image specifications. */
12840
12841 static struct image_keyword gs_format[GS_LAST] =
12842 {
12843 {":type", IMAGE_SYMBOL_VALUE, 1},
12844 {":pt-width", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12845 {":pt-height", IMAGE_POSITIVE_INTEGER_VALUE, 1},
12846 {":file", IMAGE_STRING_VALUE, 1},
12847 {":loader", IMAGE_FUNCTION_VALUE, 0},
12848 {":bounding-box", IMAGE_DONT_CHECK_VALUE_TYPE, 1},
12849 {":ascent", IMAGE_NON_NEGATIVE_INTEGER_VALUE, 0},
12850 {":margin", IMAGE_POSITIVE_INTEGER_VALUE_OR_PAIR, 0},
12851 {":relief", IMAGE_INTEGER_VALUE, 0},
12852 {":conversion", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12853 {":heuristic-mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12854 {":mask", IMAGE_DONT_CHECK_VALUE_TYPE, 0},
12855 {":background", IMAGE_STRING_OR_NIL_VALUE, 0}
12856 };
12857
12858 /* Structure describing the image type `ghostscript'. */
12859
12860 static struct image_type gs_type =
12861 {
12862 &Qpostscript,
12863 gs_image_p,
12864 gs_load,
12865 gs_clear_image,
12866 NULL
12867 };
12868
12869
12870 /* Free X resources of Ghostscript image IMG which is used on frame F. */
12871
12872 static void
12873 gs_clear_image (f, img)
12874 struct frame *f;
12875 struct image *img;
12876 {
12877 /* IMG->data.ptr_val may contain a recorded colormap. */
12878 xfree (img->data.ptr_val);
12879 x_clear_image (f, img);
12880 }
12881
12882
12883 /* Return non-zero if OBJECT is a valid Ghostscript image
12884 specification. */
12885
12886 static int
12887 gs_image_p (object)
12888 Lisp_Object object;
12889 {
12890 struct image_keyword fmt[GS_LAST];
12891 Lisp_Object tem;
12892 int i;
12893
12894 bcopy (gs_format, fmt, sizeof fmt);
12895
12896 if (!parse_image_spec (object, fmt, GS_LAST, Qpostscript)
12897 || (fmt[GS_ASCENT].count
12898 && XFASTINT (fmt[GS_ASCENT].value) > 100))
12899 return 0;
12900
12901 /* Bounding box must be a list or vector containing 4 integers. */
12902 tem = fmt[GS_BOUNDING_BOX].value;
12903 if (CONSP (tem))
12904 {
12905 for (i = 0; i < 4; ++i, tem = XCDR (tem))
12906 if (!CONSP (tem) || !INTEGERP (XCAR (tem)))
12907 return 0;
12908 if (!NILP (tem))
12909 return 0;
12910 }
12911 else if (VECTORP (tem))
12912 {
12913 if (XVECTOR (tem)->size != 4)
12914 return 0;
12915 for (i = 0; i < 4; ++i)
12916 if (!INTEGERP (XVECTOR (tem)->contents[i]))
12917 return 0;
12918 }
12919 else
12920 return 0;
12921
12922 return 1;
12923 }
12924
12925
12926 /* Load Ghostscript image IMG for use on frame F. Value is non-zero
12927 if successful. */
12928
12929 static int
12930 gs_load (f, img)
12931 struct frame *f;
12932 struct image *img;
12933 {
12934 char buffer[100];
12935 Lisp_Object window_and_pixmap_id = Qnil, loader, pt_height, pt_width;
12936 struct gcpro gcpro1, gcpro2;
12937 Lisp_Object frame;
12938 double in_width, in_height;
12939 Lisp_Object pixel_colors = Qnil;
12940
12941 /* Compute pixel size of pixmap needed from the given size in the
12942 image specification. Sizes in the specification are in pt. 1 pt
12943 = 1/72 in, xdpi and ydpi are stored in the frame's X display
12944 info. */
12945 pt_width = image_spec_value (img->spec, QCpt_width, NULL);
12946 in_width = XFASTINT (pt_width) / 72.0;
12947 img->width = in_width * FRAME_W32_DISPLAY_INFO (f)->resx;
12948 pt_height = image_spec_value (img->spec, QCpt_height, NULL);
12949 in_height = XFASTINT (pt_height) / 72.0;
12950 img->height = in_height * FRAME_W32_DISPLAY_INFO (f)->resy;
12951
12952 /* Create the pixmap. */
12953 BLOCK_INPUT;
12954 xassert (img->pixmap == 0);
12955 img->pixmap = XCreatePixmap (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
12956 img->width, img->height,
12957 one_w32_display_info.n_cbits);
12958 UNBLOCK_INPUT;
12959
12960 if (!img->pixmap)
12961 {
12962 image_error ("Unable to create pixmap for `%s'", img->spec, Qnil);
12963 return 0;
12964 }
12965
12966 /* Call the loader to fill the pixmap. It returns a process object
12967 if successful. We do not record_unwind_protect here because
12968 other places in redisplay like calling window scroll functions
12969 don't either. Let the Lisp loader use `unwind-protect' instead. */
12970 GCPRO2 (window_and_pixmap_id, pixel_colors);
12971
12972 sprintf (buffer, "%lu %lu",
12973 (unsigned long) FRAME_W32_WINDOW (f),
12974 (unsigned long) img->pixmap);
12975 window_and_pixmap_id = build_string (buffer);
12976
12977 sprintf (buffer, "%lu %lu",
12978 FRAME_FOREGROUND_PIXEL (f),
12979 FRAME_BACKGROUND_PIXEL (f));
12980 pixel_colors = build_string (buffer);
12981
12982 XSETFRAME (frame, f);
12983 loader = image_spec_value (img->spec, QCloader, NULL);
12984 if (NILP (loader))
12985 loader = intern ("gs-load-image");
12986
12987 img->data.lisp_val = call6 (loader, frame, img->spec,
12988 make_number (img->width),
12989 make_number (img->height),
12990 window_and_pixmap_id,
12991 pixel_colors);
12992 UNGCPRO;
12993 return PROCESSP (img->data.lisp_val);
12994 }
12995
12996
12997 /* Kill the Ghostscript process that was started to fill PIXMAP on
12998 frame F. Called from XTread_socket when receiving an event
12999 telling Emacs that Ghostscript has finished drawing. */
13000
13001 void
13002 x_kill_gs_process (pixmap, f)
13003 Pixmap pixmap;
13004 struct frame *f;
13005 {
13006 struct image_cache *c = FRAME_X_IMAGE_CACHE (f);
13007 int class, i;
13008 struct image *img;
13009
13010 /* Find the image containing PIXMAP. */
13011 for (i = 0; i < c->used; ++i)
13012 if (c->images[i]->pixmap == pixmap)
13013 break;
13014
13015 /* Should someone in between have cleared the image cache, for
13016 instance, give up. */
13017 if (i == c->used)
13018 return;
13019
13020 /* Kill the GS process. We should have found PIXMAP in the image
13021 cache and its image should contain a process object. */
13022 img = c->images[i];
13023 xassert (PROCESSP (img->data.lisp_val));
13024 Fkill_process (img->data.lisp_val, Qnil);
13025 img->data.lisp_val = Qnil;
13026
13027 /* On displays with a mutable colormap, figure out the colors
13028 allocated for the image by looking at the pixels of an XImage for
13029 img->pixmap. */
13030 class = FRAME_W32_DISPLAY_INFO (f)->visual->class;
13031 if (class != StaticColor && class != StaticGray && class != TrueColor)
13032 {
13033 XImage *ximg;
13034
13035 BLOCK_INPUT;
13036
13037 /* Try to get an XImage for img->pixmep. */
13038 ximg = XGetImage (FRAME_W32_DISPLAY (f), img->pixmap,
13039 0, 0, img->width, img->height, ~0, ZPixmap);
13040 if (ximg)
13041 {
13042 int x, y;
13043
13044 /* Initialize the color table. */
13045 init_color_table ();
13046
13047 /* For each pixel of the image, look its color up in the
13048 color table. After having done so, the color table will
13049 contain an entry for each color used by the image. */
13050 for (y = 0; y < img->height; ++y)
13051 for (x = 0; x < img->width; ++x)
13052 {
13053 unsigned long pixel = XGetPixel (ximg, x, y);
13054 lookup_pixel_color (f, pixel);
13055 }
13056
13057 /* Record colors in the image. Free color table and XImage. */
13058 img->colors = colors_in_color_table (&img->ncolors);
13059 free_color_table ();
13060 XDestroyImage (ximg);
13061
13062 #if 0 /* This doesn't seem to be the case. If we free the colors
13063 here, we get a BadAccess later in x_clear_image when
13064 freeing the colors. */
13065 /* We have allocated colors once, but Ghostscript has also
13066 allocated colors on behalf of us. So, to get the
13067 reference counts right, free them once. */
13068 if (img->ncolors)
13069 x_free_colors (FRAME_W32_DISPLAY (f), cmap,
13070 img->colors, img->ncolors, 0);
13071 #endif
13072 }
13073 else
13074 image_error ("Cannot get X image of `%s'; colors will not be freed",
13075 img->spec, Qnil);
13076
13077 UNBLOCK_INPUT;
13078 }
13079
13080 /* Now that we have the pixmap, compute mask and transform the
13081 image if requested. */
13082 BLOCK_INPUT;
13083 postprocess_image (f, img);
13084 UNBLOCK_INPUT;
13085 }
13086
13087 #endif /* HAVE_GHOSTSCRIPT */
13088
13089 \f
13090 /***********************************************************************
13091 Window properties
13092 ***********************************************************************/
13093
13094 DEFUN ("x-change-window-property", Fx_change_window_property,
13095 Sx_change_window_property, 2, 3, 0,
13096 doc: /* Change window property PROP to VALUE on the X window of FRAME.
13097 PROP and VALUE must be strings. FRAME nil or omitted means use the
13098 selected frame. Value is VALUE. */)
13099 (prop, value, frame)
13100 Lisp_Object frame, prop, value;
13101 {
13102 #if 0 /* TODO : port window properties to W32 */
13103 struct frame *f = check_x_frame (frame);
13104 Atom prop_atom;
13105
13106 CHECK_STRING (prop);
13107 CHECK_STRING (value);
13108
13109 BLOCK_INPUT;
13110 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13111 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13112 prop_atom, XA_STRING, 8, PropModeReplace,
13113 XSTRING (value)->data, XSTRING (value)->size);
13114
13115 /* Make sure the property is set when we return. */
13116 XFlush (FRAME_W32_DISPLAY (f));
13117 UNBLOCK_INPUT;
13118
13119 #endif /* TODO */
13120
13121 return value;
13122 }
13123
13124
13125 DEFUN ("x-delete-window-property", Fx_delete_window_property,
13126 Sx_delete_window_property, 1, 2, 0,
13127 doc: /* Remove window property PROP from X window of FRAME.
13128 FRAME nil or omitted means use the selected frame. Value is PROP. */)
13129 (prop, frame)
13130 Lisp_Object prop, frame;
13131 {
13132 #if 0 /* TODO : port window properties to W32 */
13133
13134 struct frame *f = check_x_frame (frame);
13135 Atom prop_atom;
13136
13137 CHECK_STRING (prop);
13138 BLOCK_INPUT;
13139 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13140 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
13141
13142 /* Make sure the property is removed when we return. */
13143 XFlush (FRAME_W32_DISPLAY (f));
13144 UNBLOCK_INPUT;
13145 #endif /* TODO */
13146
13147 return prop;
13148 }
13149
13150
13151 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
13152 1, 2, 0,
13153 doc: /* Value is the value of window property PROP on FRAME.
13154 If FRAME is nil or omitted, use the selected frame. Value is nil
13155 if FRAME hasn't a property with name PROP or if PROP has no string
13156 value. */)
13157 (prop, frame)
13158 Lisp_Object prop, frame;
13159 {
13160 #if 0 /* TODO : port window properties to W32 */
13161
13162 struct frame *f = check_x_frame (frame);
13163 Atom prop_atom;
13164 int rc;
13165 Lisp_Object prop_value = Qnil;
13166 char *tmp_data = NULL;
13167 Atom actual_type;
13168 int actual_format;
13169 unsigned long actual_size, bytes_remaining;
13170
13171 CHECK_STRING (prop);
13172 BLOCK_INPUT;
13173 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), XSTRING (prop)->data, False);
13174 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13175 prop_atom, 0, 0, False, XA_STRING,
13176 &actual_type, &actual_format, &actual_size,
13177 &bytes_remaining, (unsigned char **) &tmp_data);
13178 if (rc == Success)
13179 {
13180 int size = bytes_remaining;
13181
13182 XFree (tmp_data);
13183 tmp_data = NULL;
13184
13185 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
13186 prop_atom, 0, bytes_remaining,
13187 False, XA_STRING,
13188 &actual_type, &actual_format,
13189 &actual_size, &bytes_remaining,
13190 (unsigned char **) &tmp_data);
13191 if (rc == Success)
13192 prop_value = make_string (tmp_data, size);
13193
13194 XFree (tmp_data);
13195 }
13196
13197 UNBLOCK_INPUT;
13198
13199 return prop_value;
13200
13201 #endif /* TODO */
13202 return Qnil;
13203 }
13204
13205
13206 \f
13207 /***********************************************************************
13208 Busy cursor
13209 ***********************************************************************/
13210
13211 /* If non-null, an asynchronous timer that, when it expires, displays
13212 an hourglass cursor on all frames. */
13213
13214 static struct atimer *hourglass_atimer;
13215
13216 /* Non-zero means an hourglass cursor is currently shown. */
13217
13218 static int hourglass_shown_p;
13219
13220 /* Number of seconds to wait before displaying an hourglass cursor. */
13221
13222 static Lisp_Object Vhourglass_delay;
13223
13224 /* Default number of seconds to wait before displaying an hourglass
13225 cursor. */
13226
13227 #define DEFAULT_HOURGLASS_DELAY 1
13228
13229 /* Function prototypes. */
13230
13231 static void show_hourglass P_ ((struct atimer *));
13232 static void hide_hourglass P_ ((void));
13233
13234
13235 /* Cancel a currently active hourglass timer, and start a new one. */
13236
13237 void
13238 start_hourglass ()
13239 {
13240 #if 0 /* TODO: cursor shape changes. */
13241 EMACS_TIME delay;
13242 int secs, usecs = 0;
13243
13244 cancel_hourglass ();
13245
13246 if (INTEGERP (Vhourglass_delay)
13247 && XINT (Vhourglass_delay) > 0)
13248 secs = XFASTINT (Vhourglass_delay);
13249 else if (FLOATP (Vhourglass_delay)
13250 && XFLOAT_DATA (Vhourglass_delay) > 0)
13251 {
13252 Lisp_Object tem;
13253 tem = Ftruncate (Vhourglass_delay, Qnil);
13254 secs = XFASTINT (tem);
13255 usecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000000;
13256 }
13257 else
13258 secs = DEFAULT_HOURGLASS_DELAY;
13259
13260 EMACS_SET_SECS_USECS (delay, secs, usecs);
13261 hourglass_atimer = start_atimer (ATIMER_RELATIVE, delay,
13262 show_hourglass, NULL);
13263 #endif
13264 }
13265
13266
13267 /* Cancel the hourglass cursor timer if active, hide an hourglass
13268 cursor if shown. */
13269
13270 void
13271 cancel_hourglass ()
13272 {
13273 if (hourglass_atimer)
13274 {
13275 cancel_atimer (hourglass_atimer);
13276 hourglass_atimer = NULL;
13277 }
13278
13279 if (hourglass_shown_p)
13280 hide_hourglass ();
13281 }
13282
13283
13284 /* Timer function of hourglass_atimer. TIMER is equal to
13285 hourglass_atimer.
13286
13287 Display an hourglass cursor on all frames by mapping the frames'
13288 hourglass_window. Set the hourglass_p flag in the frames'
13289 output_data.x structure to indicate that an hourglass cursor is
13290 shown on the frames. */
13291
13292 static void
13293 show_hourglass (timer)
13294 struct atimer *timer;
13295 {
13296 #if 0 /* TODO: cursor shape changes. */
13297 /* The timer implementation will cancel this timer automatically
13298 after this function has run. Set hourglass_atimer to null
13299 so that we know the timer doesn't have to be canceled. */
13300 hourglass_atimer = NULL;
13301
13302 if (!hourglass_shown_p)
13303 {
13304 Lisp_Object rest, frame;
13305
13306 BLOCK_INPUT;
13307
13308 FOR_EACH_FRAME (rest, frame)
13309 if (FRAME_W32_P (XFRAME (frame)))
13310 {
13311 struct frame *f = XFRAME (frame);
13312
13313 f->output_data.w32->hourglass_p = 1;
13314
13315 if (!f->output_data.w32->hourglass_window)
13316 {
13317 unsigned long mask = CWCursor;
13318 XSetWindowAttributes attrs;
13319
13320 attrs.cursor = f->output_data.w32->hourglass_cursor;
13321
13322 f->output_data.w32->hourglass_window
13323 = XCreateWindow (FRAME_X_DISPLAY (f),
13324 FRAME_OUTER_WINDOW (f),
13325 0, 0, 32000, 32000, 0, 0,
13326 InputOnly,
13327 CopyFromParent,
13328 mask, &attrs);
13329 }
13330
13331 XMapRaised (FRAME_X_DISPLAY (f),
13332 f->output_data.w32->hourglass_window);
13333 XFlush (FRAME_X_DISPLAY (f));
13334 }
13335
13336 hourglass_shown_p = 1;
13337 UNBLOCK_INPUT;
13338 }
13339 #endif
13340 }
13341
13342
13343 /* Hide the hourglass cursor on all frames, if it is currently shown. */
13344
13345 static void
13346 hide_hourglass ()
13347 {
13348 #if 0 /* TODO: cursor shape changes. */
13349 if (hourglass_shown_p)
13350 {
13351 Lisp_Object rest, frame;
13352
13353 BLOCK_INPUT;
13354 FOR_EACH_FRAME (rest, frame)
13355 {
13356 struct frame *f = XFRAME (frame);
13357
13358 if (FRAME_W32_P (f)
13359 /* Watch out for newly created frames. */
13360 && f->output_data.x->hourglass_window)
13361 {
13362 XUnmapWindow (FRAME_X_DISPLAY (f),
13363 f->output_data.x->hourglass_window);
13364 /* Sync here because XTread_socket looks at the
13365 hourglass_p flag that is reset to zero below. */
13366 XSync (FRAME_X_DISPLAY (f), False);
13367 f->output_data.x->hourglass_p = 0;
13368 }
13369 }
13370
13371 hourglass_shown_p = 0;
13372 UNBLOCK_INPUT;
13373 }
13374 #endif
13375 }
13376
13377
13378 \f
13379 /***********************************************************************
13380 Tool tips
13381 ***********************************************************************/
13382
13383 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
13384 Lisp_Object, Lisp_Object));
13385 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
13386 Lisp_Object, int, int, int *, int *));
13387
13388 /* The frame of a currently visible tooltip. */
13389
13390 Lisp_Object tip_frame;
13391
13392 /* If non-nil, a timer started that hides the last tooltip when it
13393 fires. */
13394
13395 Lisp_Object tip_timer;
13396 Window tip_window;
13397
13398 /* If non-nil, a vector of 3 elements containing the last args
13399 with which x-show-tip was called. See there. */
13400
13401 Lisp_Object last_show_tip_args;
13402
13403 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
13404
13405 Lisp_Object Vx_max_tooltip_size;
13406
13407
13408 static Lisp_Object
13409 unwind_create_tip_frame (frame)
13410 Lisp_Object frame;
13411 {
13412 Lisp_Object deleted;
13413
13414 deleted = unwind_create_frame (frame);
13415 if (EQ (deleted, Qt))
13416 {
13417 tip_window = NULL;
13418 tip_frame = Qnil;
13419 }
13420
13421 return deleted;
13422 }
13423
13424
13425 /* Create a frame for a tooltip on the display described by DPYINFO.
13426 PARMS is a list of frame parameters. TEXT is the string to
13427 display in the tip frame. Value is the frame.
13428
13429 Note that functions called here, esp. x_default_parameter can
13430 signal errors, for instance when a specified color name is
13431 undefined. We have to make sure that we're in a consistent state
13432 when this happens. */
13433
13434 static Lisp_Object
13435 x_create_tip_frame (dpyinfo, parms, text)
13436 struct w32_display_info *dpyinfo;
13437 Lisp_Object parms, text;
13438 {
13439 struct frame *f;
13440 Lisp_Object frame, tem;
13441 Lisp_Object name;
13442 long window_prompting = 0;
13443 int width, height;
13444 int count = BINDING_STACK_SIZE ();
13445 struct gcpro gcpro1, gcpro2, gcpro3;
13446 struct kboard *kb;
13447 int face_change_count_before = face_change_count;
13448 Lisp_Object buffer;
13449 struct buffer *old_buffer;
13450
13451 check_w32 ();
13452
13453 /* Use this general default value to start with until we know if
13454 this frame has a specified name. */
13455 Vx_resource_name = Vinvocation_name;
13456
13457 #ifdef MULTI_KBOARD
13458 kb = dpyinfo->kboard;
13459 #else
13460 kb = &the_only_kboard;
13461 #endif
13462
13463 /* Get the name of the frame to use for resource lookup. */
13464 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
13465 if (!STRINGP (name)
13466 && !EQ (name, Qunbound)
13467 && !NILP (name))
13468 error ("Invalid frame name--not a string or nil");
13469 Vx_resource_name = name;
13470
13471 frame = Qnil;
13472 GCPRO3 (parms, name, frame);
13473 /* Make a frame without minibuffer nor mode-line. */
13474 f = make_frame (0);
13475 f->wants_modeline = 0;
13476 XSETFRAME (frame, f);
13477
13478 buffer = Fget_buffer_create (build_string (" *tip*"));
13479 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer);
13480 old_buffer = current_buffer;
13481 set_buffer_internal_1 (XBUFFER (buffer));
13482 current_buffer->truncate_lines = Qnil;
13483 Ferase_buffer ();
13484 Finsert (1, &text);
13485 set_buffer_internal_1 (old_buffer);
13486
13487 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
13488 record_unwind_protect (unwind_create_tip_frame, frame);
13489
13490 /* By setting the output method, we're essentially saying that
13491 the frame is live, as per FRAME_LIVE_P. If we get a signal
13492 from this point on, x_destroy_window might screw up reference
13493 counts etc. */
13494 f->output_method = output_w32;
13495 f->output_data.w32 =
13496 (struct w32_output *) xmalloc (sizeof (struct w32_output));
13497 bzero (f->output_data.w32, sizeof (struct w32_output));
13498
13499 FRAME_FONTSET (f) = -1;
13500 f->icon_name = Qnil;
13501
13502 #if 0 /* GLYPH_DEBUG TODO: image support. */
13503 image_cache_refcount = FRAME_X_IMAGE_CACHE (f)->refcount;
13504 dpyinfo_refcount = dpyinfo->reference_count;
13505 #endif /* GLYPH_DEBUG */
13506 #ifdef MULTI_KBOARD
13507 FRAME_KBOARD (f) = kb;
13508 #endif
13509 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13510 f->output_data.w32->explicit_parent = 0;
13511
13512 /* Set the name; the functions to which we pass f expect the name to
13513 be set. */
13514 if (EQ (name, Qunbound) || NILP (name))
13515 {
13516 f->name = build_string (dpyinfo->w32_id_name);
13517 f->explicit_name = 0;
13518 }
13519 else
13520 {
13521 f->name = name;
13522 f->explicit_name = 1;
13523 /* use the frame's title when getting resources for this frame. */
13524 specbind (Qx_resource_name, name);
13525 }
13526
13527 /* Extract the window parameters from the supplied values
13528 that are needed to determine window geometry. */
13529 {
13530 Lisp_Object font;
13531
13532 font = w32_get_arg (parms, Qfont, "font", "Font", RES_TYPE_STRING);
13533
13534 BLOCK_INPUT;
13535 /* First, try whatever font the caller has specified. */
13536 if (STRINGP (font))
13537 {
13538 tem = Fquery_fontset (font, Qnil);
13539 if (STRINGP (tem))
13540 font = x_new_fontset (f, XSTRING (tem)->data);
13541 else
13542 font = x_new_font (f, XSTRING (font)->data);
13543 }
13544
13545 /* Try out a font which we hope has bold and italic variations. */
13546 if (!STRINGP (font))
13547 font = x_new_font (f, "-*-Courier New-normal-r-*-*-*-100-*-*-c-*-iso8859-1");
13548 if (! STRINGP (font))
13549 font = x_new_font (f, "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1");
13550 /* If those didn't work, look for something which will at least work. */
13551 if (! STRINGP (font))
13552 font = x_new_font (f, "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1");
13553 UNBLOCK_INPUT;
13554 if (! STRINGP (font))
13555 font = build_string ("Fixedsys");
13556
13557 x_default_parameter (f, parms, Qfont, font,
13558 "font", "Font", RES_TYPE_STRING);
13559 }
13560
13561 x_default_parameter (f, parms, Qborder_width, make_number (2),
13562 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
13563 /* This defaults to 2 in order to match xterm. We recognize either
13564 internalBorderWidth or internalBorder (which is what xterm calls
13565 it). */
13566 if (NILP (Fassq (Qinternal_border_width, parms)))
13567 {
13568 Lisp_Object value;
13569
13570 value = w32_get_arg (parms, Qinternal_border_width,
13571 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
13572 if (! EQ (value, Qunbound))
13573 parms = Fcons (Fcons (Qinternal_border_width, value),
13574 parms);
13575 }
13576 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
13577 "internalBorderWidth", "internalBorderWidth",
13578 RES_TYPE_NUMBER);
13579
13580 /* Also do the stuff which must be set before the window exists. */
13581 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
13582 "foreground", "Foreground", RES_TYPE_STRING);
13583 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
13584 "background", "Background", RES_TYPE_STRING);
13585 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
13586 "pointerColor", "Foreground", RES_TYPE_STRING);
13587 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
13588 "cursorColor", "Foreground", RES_TYPE_STRING);
13589 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
13590 "borderColor", "BorderColor", RES_TYPE_STRING);
13591
13592 /* Init faces before x_default_parameter is called for scroll-bar
13593 parameters because that function calls x_set_scroll_bar_width,
13594 which calls change_frame_size, which calls Fset_window_buffer,
13595 which runs hooks, which call Fvertical_motion. At the end, we
13596 end up in init_iterator with a null face cache, which should not
13597 happen. */
13598 init_frame_faces (f);
13599
13600 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
13601 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
13602
13603 window_prompting = x_figure_window_size (f, parms);
13604
13605 /* No fringes on tip frame. */
13606 f->output_data.w32->fringes_extra = 0;
13607 f->output_data.w32->fringe_cols = 0;
13608 f->output_data.w32->left_fringe_width = 0;
13609 f->output_data.w32->right_fringe_width = 0;
13610
13611 if (window_prompting & XNegative)
13612 {
13613 if (window_prompting & YNegative)
13614 f->output_data.w32->win_gravity = SouthEastGravity;
13615 else
13616 f->output_data.w32->win_gravity = NorthEastGravity;
13617 }
13618 else
13619 {
13620 if (window_prompting & YNegative)
13621 f->output_data.w32->win_gravity = SouthWestGravity;
13622 else
13623 f->output_data.w32->win_gravity = NorthWestGravity;
13624 }
13625
13626 f->output_data.w32->size_hint_flags = window_prompting;
13627
13628 BLOCK_INPUT;
13629 my_create_tip_window (f);
13630 UNBLOCK_INPUT;
13631
13632 x_make_gc (f);
13633
13634 x_default_parameter (f, parms, Qauto_raise, Qnil,
13635 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13636 x_default_parameter (f, parms, Qauto_lower, Qnil,
13637 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
13638 x_default_parameter (f, parms, Qcursor_type, Qbox,
13639 "cursorType", "CursorType", RES_TYPE_SYMBOL);
13640
13641 /* Dimensions, especially f->height, must be done via change_frame_size.
13642 Change will not be effected unless different from the current
13643 f->height. */
13644 width = f->width;
13645 height = f->height;
13646 f->height = 0;
13647 SET_FRAME_WIDTH (f, 0);
13648 change_frame_size (f, height, width, 1, 0, 0);
13649
13650 /* Set up faces after all frame parameters are known. This call
13651 also merges in face attributes specified for new frames.
13652
13653 Frame parameters may be changed if .Xdefaults contains
13654 specifications for the default font. For example, if there is an
13655 `Emacs.default.attributeBackground: pink', the `background-color'
13656 attribute of the frame get's set, which let's the internal border
13657 of the tooltip frame appear in pink. Prevent this. */
13658 {
13659 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
13660
13661 /* Set tip_frame here, so that */
13662 tip_frame = frame;
13663 call1 (Qface_set_after_frame_default, frame);
13664
13665 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
13666 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
13667 Qnil));
13668 }
13669
13670 f->no_split = 1;
13671
13672 UNGCPRO;
13673
13674 /* It is now ok to make the frame official even if we get an error
13675 below. And the frame needs to be on Vframe_list or making it
13676 visible won't work. */
13677 Vframe_list = Fcons (frame, Vframe_list);
13678
13679 /* Now that the frame is official, it counts as a reference to
13680 its display. */
13681 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
13682
13683 /* Setting attributes of faces of the tooltip frame from resources
13684 and similar will increment face_change_count, which leads to the
13685 clearing of all current matrices. Since this isn't necessary
13686 here, avoid it by resetting face_change_count to the value it
13687 had before we created the tip frame. */
13688 face_change_count = face_change_count_before;
13689
13690 /* Discard the unwind_protect. */
13691 return unbind_to (count, frame);
13692 }
13693
13694
13695 /* Compute where to display tip frame F. PARMS is the list of frame
13696 parameters for F. DX and DY are specified offsets from the current
13697 location of the mouse. WIDTH and HEIGHT are the width and height
13698 of the tooltip. Return coordinates relative to the root window of
13699 the display in *ROOT_X, and *ROOT_Y. */
13700
13701 static void
13702 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
13703 struct frame *f;
13704 Lisp_Object parms, dx, dy;
13705 int width, height;
13706 int *root_x, *root_y;
13707 {
13708 Lisp_Object left, top;
13709
13710 /* User-specified position? */
13711 left = Fcdr (Fassq (Qleft, parms));
13712 top = Fcdr (Fassq (Qtop, parms));
13713
13714 /* Move the tooltip window where the mouse pointer is. Resize and
13715 show it. */
13716 if (!INTEGERP (left) || !INTEGERP (top))
13717 {
13718 POINT pt;
13719
13720 BLOCK_INPUT;
13721 GetCursorPos (&pt);
13722 *root_x = pt.x;
13723 *root_y = pt.y;
13724 UNBLOCK_INPUT;
13725 }
13726
13727 if (INTEGERP (top))
13728 *root_y = XINT (top);
13729 else if (*root_y + XINT (dy) - height < 0)
13730 *root_y -= XINT (dy);
13731 else
13732 {
13733 *root_y -= height;
13734 *root_y += XINT (dy);
13735 }
13736
13737 if (INTEGERP (left))
13738 *root_x = XINT (left);
13739 else if (*root_x + XINT (dx) + width <= FRAME_W32_DISPLAY_INFO (f)->width)
13740 /* It fits to the right of the pointer. */
13741 *root_x += XINT (dx);
13742 else if (width + XINT (dx) <= *root_x)
13743 /* It fits to the left of the pointer. */
13744 *root_x -= width + XINT (dx);
13745 else
13746 /* Put it left justified on the screen -- it ought to fit that way. */
13747 *root_x = 0;
13748 }
13749
13750
13751 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
13752 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
13753 A tooltip window is a small window displaying a string.
13754
13755 FRAME nil or omitted means use the selected frame.
13756
13757 PARMS is an optional list of frame parameters which can be
13758 used to change the tooltip's appearance.
13759
13760 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
13761 means use the default timeout of 5 seconds.
13762
13763 If the list of frame parameters PARAMS contains a `left' parameter,
13764 the tooltip is displayed at that x-position. Otherwise it is
13765 displayed at the mouse position, with offset DX added (default is 5 if
13766 DX isn't specified). Likewise for the y-position; if a `top' frame
13767 parameter is specified, it determines the y-position of the tooltip
13768 window, otherwise it is displayed at the mouse position, with offset
13769 DY added (default is -10).
13770
13771 A tooltip's maximum size is specified by `x-max-tooltip-size'.
13772 Text larger than the specified size is clipped. */)
13773 (string, frame, parms, timeout, dx, dy)
13774 Lisp_Object string, frame, parms, timeout, dx, dy;
13775 {
13776 struct frame *f;
13777 struct window *w;
13778 int root_x, root_y;
13779 struct buffer *old_buffer;
13780 struct text_pos pos;
13781 int i, width, height;
13782 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
13783 int old_windows_or_buffers_changed = windows_or_buffers_changed;
13784 int count = BINDING_STACK_SIZE ();
13785
13786 specbind (Qinhibit_redisplay, Qt);
13787
13788 GCPRO4 (string, parms, frame, timeout);
13789
13790 CHECK_STRING (string);
13791 f = check_x_frame (frame);
13792 if (NILP (timeout))
13793 timeout = make_number (5);
13794 else
13795 CHECK_NATNUM (timeout);
13796
13797 if (NILP (dx))
13798 dx = make_number (5);
13799 else
13800 CHECK_NUMBER (dx);
13801
13802 if (NILP (dy))
13803 dy = make_number (-10);
13804 else
13805 CHECK_NUMBER (dy);
13806
13807 if (NILP (last_show_tip_args))
13808 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
13809
13810 if (!NILP (tip_frame))
13811 {
13812 Lisp_Object last_string = AREF (last_show_tip_args, 0);
13813 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
13814 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
13815
13816 if (EQ (frame, last_frame)
13817 && !NILP (Fequal (last_string, string))
13818 && !NILP (Fequal (last_parms, parms)))
13819 {
13820 struct frame *f = XFRAME (tip_frame);
13821
13822 /* Only DX and DY have changed. */
13823 if (!NILP (tip_timer))
13824 {
13825 Lisp_Object timer = tip_timer;
13826 tip_timer = Qnil;
13827 call1 (Qcancel_timer, timer);
13828 }
13829
13830 BLOCK_INPUT;
13831 compute_tip_xy (f, parms, dx, dy, PIXEL_WIDTH (f),
13832 PIXEL_HEIGHT (f), &root_x, &root_y);
13833
13834 /* Put tooltip in topmost group and in position. */
13835 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13836 root_x, root_y, 0, 0,
13837 SWP_NOSIZE | SWP_NOACTIVATE);
13838
13839 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13840 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13841 0, 0, 0, 0,
13842 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13843
13844 UNBLOCK_INPUT;
13845 goto start_timer;
13846 }
13847 }
13848
13849 /* Hide a previous tip, if any. */
13850 Fx_hide_tip ();
13851
13852 ASET (last_show_tip_args, 0, string);
13853 ASET (last_show_tip_args, 1, frame);
13854 ASET (last_show_tip_args, 2, parms);
13855
13856 /* Add default values to frame parameters. */
13857 if (NILP (Fassq (Qname, parms)))
13858 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
13859 if (NILP (Fassq (Qinternal_border_width, parms)))
13860 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
13861 if (NILP (Fassq (Qborder_width, parms)))
13862 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
13863 if (NILP (Fassq (Qborder_color, parms)))
13864 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
13865 if (NILP (Fassq (Qbackground_color, parms)))
13866 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
13867 parms);
13868
13869 /* Block input until the tip has been fully drawn, to avoid crashes
13870 when drawing tips in menus. */
13871 BLOCK_INPUT;
13872
13873 /* Create a frame for the tooltip, and record it in the global
13874 variable tip_frame. */
13875 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
13876 f = XFRAME (frame);
13877
13878 /* Set up the frame's root window. */
13879 w = XWINDOW (FRAME_ROOT_WINDOW (f));
13880 w->left = w->top = make_number (0);
13881
13882 if (CONSP (Vx_max_tooltip_size)
13883 && INTEGERP (XCAR (Vx_max_tooltip_size))
13884 && XINT (XCAR (Vx_max_tooltip_size)) > 0
13885 && INTEGERP (XCDR (Vx_max_tooltip_size))
13886 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
13887 {
13888 w->width = XCAR (Vx_max_tooltip_size);
13889 w->height = XCDR (Vx_max_tooltip_size);
13890 }
13891 else
13892 {
13893 w->width = make_number (80);
13894 w->height = make_number (40);
13895 }
13896
13897 f->window_width = XINT (w->width);
13898 adjust_glyphs (f);
13899 w->pseudo_window_p = 1;
13900
13901 /* Display the tooltip text in a temporary buffer. */
13902 old_buffer = current_buffer;
13903 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
13904 current_buffer->truncate_lines = Qnil;
13905 clear_glyph_matrix (w->desired_matrix);
13906 clear_glyph_matrix (w->current_matrix);
13907 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
13908 try_window (FRAME_ROOT_WINDOW (f), pos);
13909
13910 /* Compute width and height of the tooltip. */
13911 width = height = 0;
13912 for (i = 0; i < w->desired_matrix->nrows; ++i)
13913 {
13914 struct glyph_row *row = &w->desired_matrix->rows[i];
13915 struct glyph *last;
13916 int row_width;
13917
13918 /* Stop at the first empty row at the end. */
13919 if (!row->enabled_p || !row->displays_text_p)
13920 break;
13921
13922 /* Let the row go over the full width of the frame. */
13923 row->full_width_p = 1;
13924
13925 #ifdef TODO /* Investigate why some fonts need more width than is
13926 calculated for some tooltips. */
13927 /* There's a glyph at the end of rows that is use to place
13928 the cursor there. Don't include the width of this glyph. */
13929 if (row->used[TEXT_AREA])
13930 {
13931 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
13932 row_width = row->pixel_width - last->pixel_width;
13933 }
13934 else
13935 #endif
13936 row_width = row->pixel_width;
13937
13938 /* TODO: find why tips do not draw along baseline as instructed. */
13939 height += row->height;
13940 width = max (width, row_width);
13941 }
13942
13943 /* Add the frame's internal border to the width and height the X
13944 window should have. */
13945 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13946 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
13947
13948 /* Move the tooltip window where the mouse pointer is. Resize and
13949 show it. */
13950 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
13951
13952 {
13953 /* Adjust Window size to take border into account. */
13954 RECT rect;
13955 rect.left = rect.top = 0;
13956 rect.right = width;
13957 rect.bottom = height;
13958 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
13959 FRAME_EXTERNAL_MENU_BAR (f));
13960
13961 /* Position and size tooltip, and put it in the topmost group. */
13962 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
13963 root_x, root_y, rect.right - rect.left,
13964 rect.bottom - rect.top, SWP_NOACTIVATE);
13965
13966 /* Ensure tooltip is on top of other topmost windows (eg menus). */
13967 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
13968 0, 0, 0, 0,
13969 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
13970
13971 /* Let redisplay know that we have made the frame visible already. */
13972 f->async_visible = 1;
13973
13974 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
13975 }
13976
13977 /* Draw into the window. */
13978 w->must_be_updated_p = 1;
13979 update_single_window (w, 1);
13980
13981 UNBLOCK_INPUT;
13982
13983 /* Restore original current buffer. */
13984 set_buffer_internal_1 (old_buffer);
13985 windows_or_buffers_changed = old_windows_or_buffers_changed;
13986
13987 start_timer:
13988 /* Let the tip disappear after timeout seconds. */
13989 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
13990 intern ("x-hide-tip"));
13991
13992 UNGCPRO;
13993 return unbind_to (count, Qnil);
13994 }
13995
13996
13997 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
13998 doc: /* Hide the current tooltip window, if there is any.
13999 Value is t if tooltip was open, nil otherwise. */)
14000 ()
14001 {
14002 int count;
14003 Lisp_Object deleted, frame, timer;
14004 struct gcpro gcpro1, gcpro2;
14005
14006 /* Return quickly if nothing to do. */
14007 if (NILP (tip_timer) && NILP (tip_frame))
14008 return Qnil;
14009
14010 frame = tip_frame;
14011 timer = tip_timer;
14012 GCPRO2 (frame, timer);
14013 tip_frame = tip_timer = deleted = Qnil;
14014
14015 count = BINDING_STACK_SIZE ();
14016 specbind (Qinhibit_redisplay, Qt);
14017 specbind (Qinhibit_quit, Qt);
14018
14019 if (!NILP (timer))
14020 call1 (Qcancel_timer, timer);
14021
14022 if (FRAMEP (frame))
14023 {
14024 Fdelete_frame (frame, Qnil);
14025 deleted = Qt;
14026 }
14027
14028 UNGCPRO;
14029 return unbind_to (count, deleted);
14030 }
14031
14032
14033 \f
14034 /***********************************************************************
14035 File selection dialog
14036 ***********************************************************************/
14037
14038 extern Lisp_Object Qfile_name_history;
14039
14040 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 4, 0,
14041 doc: /* Read file name, prompting with PROMPT in directory DIR.
14042 Use a file selection dialog.
14043 Select DEFAULT-FILENAME in the dialog's file selection box, if
14044 specified. Ensure that file exists if MUSTMATCH is non-nil. */)
14045 (prompt, dir, default_filename, mustmatch)
14046 Lisp_Object prompt, dir, default_filename, mustmatch;
14047 {
14048 struct frame *f = SELECTED_FRAME ();
14049 Lisp_Object file = Qnil;
14050 int count = specpdl_ptr - specpdl;
14051 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5;
14052 char filename[MAX_PATH + 1];
14053 char init_dir[MAX_PATH + 1];
14054 int use_dialog_p = 1;
14055
14056 GCPRO5 (prompt, dir, default_filename, mustmatch, file);
14057 CHECK_STRING (prompt);
14058 CHECK_STRING (dir);
14059
14060 /* Create the dialog with PROMPT as title, using DIR as initial
14061 directory and using "*" as pattern. */
14062 dir = Fexpand_file_name (dir, Qnil);
14063 strncpy (init_dir, XSTRING (dir)->data, MAX_PATH);
14064 init_dir[MAX_PATH] = '\0';
14065 unixtodos_filename (init_dir);
14066
14067 if (STRINGP (default_filename))
14068 {
14069 char *file_name_only;
14070 char *full_path_name = XSTRING (default_filename)->data;
14071
14072 unixtodos_filename (full_path_name);
14073
14074 file_name_only = strrchr (full_path_name, '\\');
14075 if (!file_name_only)
14076 file_name_only = full_path_name;
14077 else
14078 {
14079 file_name_only++;
14080
14081 /* If default_file_name is a directory, don't use the open
14082 file dialog, as it does not support selecting
14083 directories. */
14084 if (!(*file_name_only))
14085 use_dialog_p = 0;
14086 }
14087
14088 strncpy (filename, file_name_only, MAX_PATH);
14089 filename[MAX_PATH] = '\0';
14090 }
14091 else
14092 filename[0] = '\0';
14093
14094 if (use_dialog_p)
14095 {
14096 OPENFILENAME file_details;
14097
14098 /* Prevent redisplay. */
14099 specbind (Qinhibit_redisplay, Qt);
14100 BLOCK_INPUT;
14101
14102 bzero (&file_details, sizeof (file_details));
14103 file_details.lStructSize = sizeof (file_details);
14104 file_details.hwndOwner = FRAME_W32_WINDOW (f);
14105 /* Undocumented Bug in Common File Dialog:
14106 If a filter is not specified, shell links are not resolved. */
14107 file_details.lpstrFilter = "ALL Files (*.*)\0*.*\0\0";
14108 file_details.lpstrFile = filename;
14109 file_details.nMaxFile = sizeof (filename);
14110 file_details.lpstrInitialDir = init_dir;
14111 file_details.lpstrTitle = XSTRING (prompt)->data;
14112 file_details.Flags = OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
14113
14114 if (!NILP (mustmatch))
14115 file_details.Flags |= OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST;
14116
14117 if (GetOpenFileName (&file_details))
14118 {
14119 dostounix_filename (filename);
14120 file = build_string (filename);
14121 }
14122 else
14123 file = Qnil;
14124
14125 UNBLOCK_INPUT;
14126 file = unbind_to (count, file);
14127 }
14128 /* Open File dialog will not allow folders to be selected, so resort
14129 to minibuffer completing reads for directories. */
14130 else
14131 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
14132 dir, mustmatch, dir, Qfile_name_history,
14133 default_filename, Qnil);
14134
14135 UNGCPRO;
14136
14137 /* Make "Cancel" equivalent to C-g. */
14138 if (NILP (file))
14139 Fsignal (Qquit, Qnil);
14140
14141 return unbind_to (count, file);
14142 }
14143
14144
14145 \f
14146 /***********************************************************************
14147 w32 specialized functions
14148 ***********************************************************************/
14149
14150 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
14151 doc: /* Select a font using the W32 font dialog.
14152 Returns an X font string corresponding to the selection. */)
14153 (frame, include_proportional)
14154 Lisp_Object frame, include_proportional;
14155 {
14156 FRAME_PTR f = check_x_frame (frame);
14157 CHOOSEFONT cf;
14158 LOGFONT lf;
14159 TEXTMETRIC tm;
14160 HDC hdc;
14161 HANDLE oldobj;
14162 char buf[100];
14163
14164 bzero (&cf, sizeof (cf));
14165 bzero (&lf, sizeof (lf));
14166
14167 cf.lStructSize = sizeof (cf);
14168 cf.hwndOwner = FRAME_W32_WINDOW (f);
14169 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
14170
14171 /* Unless include_proportional is non-nil, limit the selection to
14172 monospaced fonts. */
14173 if (NILP (include_proportional))
14174 cf.Flags |= CF_FIXEDPITCHONLY;
14175
14176 cf.lpLogFont = &lf;
14177
14178 /* Initialize as much of the font details as we can from the current
14179 default font. */
14180 hdc = GetDC (FRAME_W32_WINDOW (f));
14181 oldobj = SelectObject (hdc, FRAME_FONT (f)->hfont);
14182 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
14183 if (GetTextMetrics (hdc, &tm))
14184 {
14185 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
14186 lf.lfWeight = tm.tmWeight;
14187 lf.lfItalic = tm.tmItalic;
14188 lf.lfUnderline = tm.tmUnderlined;
14189 lf.lfStrikeOut = tm.tmStruckOut;
14190 lf.lfCharSet = tm.tmCharSet;
14191 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
14192 }
14193 SelectObject (hdc, oldobj);
14194 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
14195
14196 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
14197 return Qnil;
14198
14199 return build_string (buf);
14200 }
14201
14202 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
14203 Sw32_send_sys_command, 1, 2, 0,
14204 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
14205 Some useful values for command are #xf030 to maximise frame (#xf020
14206 to minimize), #xf120 to restore frame to original size, and #xf100
14207 to activate the menubar for keyboard access. #xf140 activates the
14208 screen saver if defined.
14209
14210 If optional parameter FRAME is not specified, use selected frame. */)
14211 (command, frame)
14212 Lisp_Object command, frame;
14213 {
14214 FRAME_PTR f = check_x_frame (frame);
14215
14216 CHECK_NUMBER (command);
14217
14218 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
14219
14220 return Qnil;
14221 }
14222
14223 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
14224 doc: /* Get Windows to perform OPERATION on DOCUMENT.
14225 This is a wrapper around the ShellExecute system function, which
14226 invokes the application registered to handle OPERATION for DOCUMENT.
14227 OPERATION is typically \"open\", \"print\" or \"explore\" (but can be
14228 nil for the default action), and DOCUMENT is typically the name of a
14229 document file or URL, but can also be a program executable to run or
14230 a directory to open in the Windows Explorer.
14231
14232 If DOCUMENT is a program executable, PARAMETERS can be a string
14233 containing command line parameters, but otherwise should be nil.
14234
14235 SHOW-FLAG can be used to control whether the invoked application is hidden
14236 or minimized. If SHOW-FLAG is nil, the application is displayed normally,
14237 otherwise it is an integer representing a ShowWindow flag:
14238
14239 0 - start hidden
14240 1 - start normally
14241 3 - start maximized
14242 6 - start minimized */)
14243 (operation, document, parameters, show_flag)
14244 Lisp_Object operation, document, parameters, show_flag;
14245 {
14246 Lisp_Object current_dir;
14247
14248 CHECK_STRING (document);
14249
14250 /* Encode filename and current directory. */
14251 current_dir = ENCODE_FILE (current_buffer->directory);
14252 document = ENCODE_FILE (document);
14253 if ((int) ShellExecute (NULL,
14254 (STRINGP (operation) ?
14255 XSTRING (operation)->data : NULL),
14256 XSTRING (document)->data,
14257 (STRINGP (parameters) ?
14258 XSTRING (parameters)->data : NULL),
14259 XSTRING (current_dir)->data,
14260 (INTEGERP (show_flag) ?
14261 XINT (show_flag) : SW_SHOWDEFAULT))
14262 > 32)
14263 return Qt;
14264 error ("ShellExecute failed: %s", w32_strerror (0));
14265 }
14266
14267 /* Lookup virtual keycode from string representing the name of a
14268 non-ascii keystroke into the corresponding virtual key, using
14269 lispy_function_keys. */
14270 static int
14271 lookup_vk_code (char *key)
14272 {
14273 int i;
14274
14275 for (i = 0; i < 256; i++)
14276 if (lispy_function_keys[i] != 0
14277 && strcmp (lispy_function_keys[i], key) == 0)
14278 return i;
14279
14280 return -1;
14281 }
14282
14283 /* Convert a one-element vector style key sequence to a hot key
14284 definition. */
14285 static int
14286 w32_parse_hot_key (key)
14287 Lisp_Object key;
14288 {
14289 /* Copied from Fdefine_key and store_in_keymap. */
14290 register Lisp_Object c;
14291 int vk_code;
14292 int lisp_modifiers;
14293 int w32_modifiers;
14294 struct gcpro gcpro1;
14295
14296 CHECK_VECTOR (key);
14297
14298 if (XFASTINT (Flength (key)) != 1)
14299 return Qnil;
14300
14301 GCPRO1 (key);
14302
14303 c = Faref (key, make_number (0));
14304
14305 if (CONSP (c) && lucid_event_type_list_p (c))
14306 c = Fevent_convert_list (c);
14307
14308 UNGCPRO;
14309
14310 if (! INTEGERP (c) && ! SYMBOLP (c))
14311 error ("Key definition is invalid");
14312
14313 /* Work out the base key and the modifiers. */
14314 if (SYMBOLP (c))
14315 {
14316 c = parse_modifiers (c);
14317 lisp_modifiers = Fcar (Fcdr (c));
14318 c = Fcar (c);
14319 if (!SYMBOLP (c))
14320 abort ();
14321 vk_code = lookup_vk_code (XSYMBOL (c)->name->data);
14322 }
14323 else if (INTEGERP (c))
14324 {
14325 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
14326 /* Many ascii characters are their own virtual key code. */
14327 vk_code = XINT (c) & CHARACTERBITS;
14328 }
14329
14330 if (vk_code < 0 || vk_code > 255)
14331 return Qnil;
14332
14333 if ((lisp_modifiers & meta_modifier) != 0
14334 && !NILP (Vw32_alt_is_meta))
14335 lisp_modifiers |= alt_modifier;
14336
14337 /* Supply defs missing from mingw32. */
14338 #ifndef MOD_ALT
14339 #define MOD_ALT 0x0001
14340 #define MOD_CONTROL 0x0002
14341 #define MOD_SHIFT 0x0004
14342 #define MOD_WIN 0x0008
14343 #endif
14344
14345 /* Convert lisp modifiers to Windows hot-key form. */
14346 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
14347 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
14348 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
14349 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
14350
14351 return HOTKEY (vk_code, w32_modifiers);
14352 }
14353
14354 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
14355 Sw32_register_hot_key, 1, 1, 0,
14356 doc: /* Register KEY as a hot-key combination.
14357 Certain key combinations like Alt-Tab are reserved for system use on
14358 Windows, and therefore are normally intercepted by the system. However,
14359 most of these key combinations can be received by registering them as
14360 hot-keys, overriding their special meaning.
14361
14362 KEY must be a one element key definition in vector form that would be
14363 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
14364 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
14365 is always interpreted as the Windows modifier keys.
14366
14367 The return value is the hotkey-id if registered, otherwise nil. */)
14368 (key)
14369 Lisp_Object key;
14370 {
14371 key = w32_parse_hot_key (key);
14372
14373 if (NILP (Fmemq (key, w32_grabbed_keys)))
14374 {
14375 /* Reuse an empty slot if possible. */
14376 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
14377
14378 /* Safe to add new key to list, even if we have focus. */
14379 if (NILP (item))
14380 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
14381 else
14382 XSETCAR (item, key);
14383
14384 /* Notify input thread about new hot-key definition, so that it
14385 takes effect without needing to switch focus. */
14386 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
14387 (WPARAM) key, 0);
14388 }
14389
14390 return key;
14391 }
14392
14393 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
14394 Sw32_unregister_hot_key, 1, 1, 0,
14395 doc: /* Unregister HOTKEY as a hot-key combination. */)
14396 (key)
14397 Lisp_Object key;
14398 {
14399 Lisp_Object item;
14400
14401 if (!INTEGERP (key))
14402 key = w32_parse_hot_key (key);
14403
14404 item = Fmemq (key, w32_grabbed_keys);
14405
14406 if (!NILP (item))
14407 {
14408 /* Notify input thread about hot-key definition being removed, so
14409 that it takes effect without needing focus switch. */
14410 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
14411 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
14412 {
14413 MSG msg;
14414 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14415 }
14416 return Qt;
14417 }
14418 return Qnil;
14419 }
14420
14421 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
14422 Sw32_registered_hot_keys, 0, 0, 0,
14423 doc: /* Return list of registered hot-key IDs. */)
14424 ()
14425 {
14426 return Fcopy_sequence (w32_grabbed_keys);
14427 }
14428
14429 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
14430 Sw32_reconstruct_hot_key, 1, 1, 0,
14431 doc: /* Convert hot-key ID to a lisp key combination. */)
14432 (hotkeyid)
14433 Lisp_Object hotkeyid;
14434 {
14435 int vk_code, w32_modifiers;
14436 Lisp_Object key;
14437
14438 CHECK_NUMBER (hotkeyid);
14439
14440 vk_code = HOTKEY_VK_CODE (hotkeyid);
14441 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
14442
14443 if (lispy_function_keys[vk_code])
14444 key = intern (lispy_function_keys[vk_code]);
14445 else
14446 key = make_number (vk_code);
14447
14448 key = Fcons (key, Qnil);
14449 if (w32_modifiers & MOD_SHIFT)
14450 key = Fcons (Qshift, key);
14451 if (w32_modifiers & MOD_CONTROL)
14452 key = Fcons (Qctrl, key);
14453 if (w32_modifiers & MOD_ALT)
14454 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
14455 if (w32_modifiers & MOD_WIN)
14456 key = Fcons (Qhyper, key);
14457
14458 return key;
14459 }
14460
14461 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
14462 Sw32_toggle_lock_key, 1, 2, 0,
14463 doc: /* Toggle the state of the lock key KEY.
14464 KEY can be `capslock', `kp-numlock', or `scroll'.
14465 If the optional parameter NEW-STATE is a number, then the state of KEY
14466 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
14467 (key, new_state)
14468 Lisp_Object key, new_state;
14469 {
14470 int vk_code;
14471
14472 if (EQ (key, intern ("capslock")))
14473 vk_code = VK_CAPITAL;
14474 else if (EQ (key, intern ("kp-numlock")))
14475 vk_code = VK_NUMLOCK;
14476 else if (EQ (key, intern ("scroll")))
14477 vk_code = VK_SCROLL;
14478 else
14479 return Qnil;
14480
14481 if (!dwWindowsThreadId)
14482 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
14483
14484 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
14485 (WPARAM) vk_code, (LPARAM) new_state))
14486 {
14487 MSG msg;
14488 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
14489 return make_number (msg.wParam);
14490 }
14491 return Qnil;
14492 }
14493 \f
14494 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
14495 doc: /* Return storage information about the file system FILENAME is on.
14496 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
14497 storage of the file system, FREE is the free storage, and AVAIL is the
14498 storage available to a non-superuser. All 3 numbers are in bytes.
14499 If the underlying system call fails, value is nil. */)
14500 (filename)
14501 Lisp_Object filename;
14502 {
14503 Lisp_Object encoded, value;
14504
14505 CHECK_STRING (filename);
14506 filename = Fexpand_file_name (filename, Qnil);
14507 encoded = ENCODE_FILE (filename);
14508
14509 value = Qnil;
14510
14511 /* Determining the required information on Windows turns out, sadly,
14512 to be more involved than one would hope. The original Win32 api
14513 call for this will return bogus information on some systems, but we
14514 must dynamically probe for the replacement api, since that was
14515 added rather late on. */
14516 {
14517 HMODULE hKernel = GetModuleHandle ("kernel32");
14518 BOOL (*pfn_GetDiskFreeSpaceEx)
14519 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
14520 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
14521
14522 /* On Windows, we may need to specify the root directory of the
14523 volume holding FILENAME. */
14524 char rootname[MAX_PATH];
14525 char *name = XSTRING (encoded)->data;
14526
14527 /* find the root name of the volume if given */
14528 if (isalpha (name[0]) && name[1] == ':')
14529 {
14530 rootname[0] = name[0];
14531 rootname[1] = name[1];
14532 rootname[2] = '\\';
14533 rootname[3] = 0;
14534 }
14535 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
14536 {
14537 char *str = rootname;
14538 int slashes = 4;
14539 do
14540 {
14541 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
14542 break;
14543 *str++ = *name++;
14544 }
14545 while ( *name );
14546
14547 *str++ = '\\';
14548 *str = 0;
14549 }
14550
14551 if (pfn_GetDiskFreeSpaceEx)
14552 {
14553 LARGE_INTEGER availbytes;
14554 LARGE_INTEGER freebytes;
14555 LARGE_INTEGER totalbytes;
14556
14557 if (pfn_GetDiskFreeSpaceEx(rootname,
14558 &availbytes,
14559 &totalbytes,
14560 &freebytes))
14561 value = list3 (make_float ((double) totalbytes.QuadPart),
14562 make_float ((double) freebytes.QuadPart),
14563 make_float ((double) availbytes.QuadPart));
14564 }
14565 else
14566 {
14567 DWORD sectors_per_cluster;
14568 DWORD bytes_per_sector;
14569 DWORD free_clusters;
14570 DWORD total_clusters;
14571
14572 if (GetDiskFreeSpace(rootname,
14573 &sectors_per_cluster,
14574 &bytes_per_sector,
14575 &free_clusters,
14576 &total_clusters))
14577 value = list3 (make_float ((double) total_clusters
14578 * sectors_per_cluster * bytes_per_sector),
14579 make_float ((double) free_clusters
14580 * sectors_per_cluster * bytes_per_sector),
14581 make_float ((double) free_clusters
14582 * sectors_per_cluster * bytes_per_sector));
14583 }
14584 }
14585
14586 return value;
14587 }
14588 \f
14589 /***********************************************************************
14590 Initialization
14591 ***********************************************************************/
14592
14593 void
14594 syms_of_w32fns ()
14595 {
14596 HMODULE user32_lib = GetModuleHandle ("user32.dll");
14597
14598 /* This is zero if not using MS-Windows. */
14599 w32_in_use = 0;
14600
14601 /* TrackMouseEvent not available in all versions of Windows, so must load
14602 it dynamically. Do it once, here, instead of every time it is used. */
14603 track_mouse_event_fn = GetProcAddress (user32_lib, "TrackMouseEvent");
14604 track_mouse_window = NULL;
14605
14606 w32_visible_system_caret_hwnd = NULL;
14607
14608 Qauto_raise = intern ("auto-raise");
14609 staticpro (&Qauto_raise);
14610 Qauto_lower = intern ("auto-lower");
14611 staticpro (&Qauto_lower);
14612 Qbar = intern ("bar");
14613 staticpro (&Qbar);
14614 Qborder_color = intern ("border-color");
14615 staticpro (&Qborder_color);
14616 Qborder_width = intern ("border-width");
14617 staticpro (&Qborder_width);
14618 Qbox = intern ("box");
14619 staticpro (&Qbox);
14620 Qcursor_color = intern ("cursor-color");
14621 staticpro (&Qcursor_color);
14622 Qcursor_type = intern ("cursor-type");
14623 staticpro (&Qcursor_type);
14624 Qgeometry = intern ("geometry");
14625 staticpro (&Qgeometry);
14626 Qicon_left = intern ("icon-left");
14627 staticpro (&Qicon_left);
14628 Qicon_top = intern ("icon-top");
14629 staticpro (&Qicon_top);
14630 Qicon_type = intern ("icon-type");
14631 staticpro (&Qicon_type);
14632 Qicon_name = intern ("icon-name");
14633 staticpro (&Qicon_name);
14634 Qinternal_border_width = intern ("internal-border-width");
14635 staticpro (&Qinternal_border_width);
14636 Qleft = intern ("left");
14637 staticpro (&Qleft);
14638 Qright = intern ("right");
14639 staticpro (&Qright);
14640 Qmouse_color = intern ("mouse-color");
14641 staticpro (&Qmouse_color);
14642 Qnone = intern ("none");
14643 staticpro (&Qnone);
14644 Qparent_id = intern ("parent-id");
14645 staticpro (&Qparent_id);
14646 Qscroll_bar_width = intern ("scroll-bar-width");
14647 staticpro (&Qscroll_bar_width);
14648 Qsuppress_icon = intern ("suppress-icon");
14649 staticpro (&Qsuppress_icon);
14650 Qundefined_color = intern ("undefined-color");
14651 staticpro (&Qundefined_color);
14652 Qvertical_scroll_bars = intern ("vertical-scroll-bars");
14653 staticpro (&Qvertical_scroll_bars);
14654 Qvisibility = intern ("visibility");
14655 staticpro (&Qvisibility);
14656 Qwindow_id = intern ("window-id");
14657 staticpro (&Qwindow_id);
14658 Qx_frame_parameter = intern ("x-frame-parameter");
14659 staticpro (&Qx_frame_parameter);
14660 Qx_resource_name = intern ("x-resource-name");
14661 staticpro (&Qx_resource_name);
14662 Quser_position = intern ("user-position");
14663 staticpro (&Quser_position);
14664 Quser_size = intern ("user-size");
14665 staticpro (&Quser_size);
14666 Qscreen_gamma = intern ("screen-gamma");
14667 staticpro (&Qscreen_gamma);
14668 Qline_spacing = intern ("line-spacing");
14669 staticpro (&Qline_spacing);
14670 Qcenter = intern ("center");
14671 staticpro (&Qcenter);
14672 Qcancel_timer = intern ("cancel-timer");
14673 staticpro (&Qcancel_timer);
14674 Qfullscreen = intern ("fullscreen");
14675 staticpro (&Qfullscreen);
14676 Qfullwidth = intern ("fullwidth");
14677 staticpro (&Qfullwidth);
14678 Qfullheight = intern ("fullheight");
14679 staticpro (&Qfullheight);
14680 Qfullboth = intern ("fullboth");
14681 staticpro (&Qfullboth);
14682
14683 Qhyper = intern ("hyper");
14684 staticpro (&Qhyper);
14685 Qsuper = intern ("super");
14686 staticpro (&Qsuper);
14687 Qmeta = intern ("meta");
14688 staticpro (&Qmeta);
14689 Qalt = intern ("alt");
14690 staticpro (&Qalt);
14691 Qctrl = intern ("ctrl");
14692 staticpro (&Qctrl);
14693 Qcontrol = intern ("control");
14694 staticpro (&Qcontrol);
14695 Qshift = intern ("shift");
14696 staticpro (&Qshift);
14697 /* This is the end of symbol initialization. */
14698
14699 /* Text property `display' should be nonsticky by default. */
14700 Vtext_property_default_nonsticky
14701 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
14702
14703
14704 Qlaplace = intern ("laplace");
14705 staticpro (&Qlaplace);
14706 Qemboss = intern ("emboss");
14707 staticpro (&Qemboss);
14708 Qedge_detection = intern ("edge-detection");
14709 staticpro (&Qedge_detection);
14710 Qheuristic = intern ("heuristic");
14711 staticpro (&Qheuristic);
14712 QCmatrix = intern (":matrix");
14713 staticpro (&QCmatrix);
14714 QCcolor_adjustment = intern (":color-adjustment");
14715 staticpro (&QCcolor_adjustment);
14716 QCmask = intern (":mask");
14717 staticpro (&QCmask);
14718
14719 Qface_set_after_frame_default = intern ("face-set-after-frame-default");
14720 staticpro (&Qface_set_after_frame_default);
14721
14722 Fput (Qundefined_color, Qerror_conditions,
14723 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
14724 Fput (Qundefined_color, Qerror_message,
14725 build_string ("Undefined color"));
14726
14727 staticpro (&w32_grabbed_keys);
14728 w32_grabbed_keys = Qnil;
14729
14730 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
14731 doc: /* An array of color name mappings for windows. */);
14732 Vw32_color_map = Qnil;
14733
14734 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
14735 doc: /* Non-nil if alt key presses are passed on to Windows.
14736 When non-nil, for example, alt pressed and released and then space will
14737 open the System menu. When nil, Emacs silently swallows alt key events. */);
14738 Vw32_pass_alt_to_system = Qnil;
14739
14740 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
14741 doc: /* Non-nil if the alt key is to be considered the same as the meta key.
14742 When nil, Emacs will translate the alt key to the Alt modifier, and not Meta. */);
14743 Vw32_alt_is_meta = Qt;
14744
14745 DEFVAR_INT ("w32-quit-key", &Vw32_quit_key,
14746 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
14747 XSETINT (Vw32_quit_key, 0);
14748
14749 DEFVAR_LISP ("w32-pass-lwindow-to-system",
14750 &Vw32_pass_lwindow_to_system,
14751 doc: /* Non-nil if the left \"Windows\" key is passed on to Windows.
14752 When non-nil, the Start menu is opened by tapping the key. */);
14753 Vw32_pass_lwindow_to_system = Qt;
14754
14755 DEFVAR_LISP ("w32-pass-rwindow-to-system",
14756 &Vw32_pass_rwindow_to_system,
14757 doc: /* Non-nil if the right \"Windows\" key is passed on to Windows.
14758 When non-nil, the Start menu is opened by tapping the key. */);
14759 Vw32_pass_rwindow_to_system = Qt;
14760
14761 DEFVAR_INT ("w32-phantom-key-code",
14762 &Vw32_phantom_key_code,
14763 doc: /* Virtual key code used to generate \"phantom\" key presses.
14764 Value is a number between 0 and 255.
14765
14766 Phantom key presses are generated in order to stop the system from
14767 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
14768 `w32-pass-rwindow-to-system' is nil. */);
14769 /* Although 255 is technically not a valid key code, it works and
14770 means that this hack won't interfere with any real key code. */
14771 Vw32_phantom_key_code = 255;
14772
14773 DEFVAR_LISP ("w32-enable-num-lock",
14774 &Vw32_enable_num_lock,
14775 doc: /* Non-nil if Num Lock should act normally.
14776 Set to nil to see Num Lock as the key `kp-numlock'. */);
14777 Vw32_enable_num_lock = Qt;
14778
14779 DEFVAR_LISP ("w32-enable-caps-lock",
14780 &Vw32_enable_caps_lock,
14781 doc: /* Non-nil if Caps Lock should act normally.
14782 Set to nil to see Caps Lock as the key `capslock'. */);
14783 Vw32_enable_caps_lock = Qt;
14784
14785 DEFVAR_LISP ("w32-scroll-lock-modifier",
14786 &Vw32_scroll_lock_modifier,
14787 doc: /* Modifier to use for the Scroll Lock on state.
14788 The value can be hyper, super, meta, alt, control or shift for the
14789 respective modifier, or nil to see Scroll Lock as the key `scroll'.
14790 Any other value will cause the key to be ignored. */);
14791 Vw32_scroll_lock_modifier = Qt;
14792
14793 DEFVAR_LISP ("w32-lwindow-modifier",
14794 &Vw32_lwindow_modifier,
14795 doc: /* Modifier to use for the left \"Windows\" key.
14796 The value can be hyper, super, meta, alt, control or shift for the
14797 respective modifier, or nil to appear as the key `lwindow'.
14798 Any other value will cause the key to be ignored. */);
14799 Vw32_lwindow_modifier = Qnil;
14800
14801 DEFVAR_LISP ("w32-rwindow-modifier",
14802 &Vw32_rwindow_modifier,
14803 doc: /* Modifier to use for the right \"Windows\" key.
14804 The value can be hyper, super, meta, alt, control or shift for the
14805 respective modifier, or nil to appear as the key `rwindow'.
14806 Any other value will cause the key to be ignored. */);
14807 Vw32_rwindow_modifier = Qnil;
14808
14809 DEFVAR_LISP ("w32-apps-modifier",
14810 &Vw32_apps_modifier,
14811 doc: /* Modifier to use for the \"Apps\" key.
14812 The value can be hyper, super, meta, alt, control or shift for the
14813 respective modifier, or nil to appear as the key `apps'.
14814 Any other value will cause the key to be ignored. */);
14815 Vw32_apps_modifier = Qnil;
14816
14817 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
14818 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
14819 w32_enable_synthesized_fonts = 0;
14820
14821 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
14822 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
14823 Vw32_enable_palette = Qt;
14824
14825 DEFVAR_INT ("w32-mouse-button-tolerance",
14826 &Vw32_mouse_button_tolerance,
14827 doc: /* Analogue of double click interval for faking middle mouse events.
14828 The value is the minimum time in milliseconds that must elapse between
14829 left/right button down events before they are considered distinct events.
14830 If both mouse buttons are depressed within this interval, a middle mouse
14831 button down event is generated instead. */);
14832 XSETINT (Vw32_mouse_button_tolerance, GetDoubleClickTime () / 2);
14833
14834 DEFVAR_INT ("w32-mouse-move-interval",
14835 &Vw32_mouse_move_interval,
14836 doc: /* Minimum interval between mouse move events.
14837 The value is the minimum time in milliseconds that must elapse between
14838 successive mouse move (or scroll bar drag) events before they are
14839 reported as lisp events. */);
14840 XSETINT (Vw32_mouse_move_interval, 0);
14841
14842 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
14843 &w32_pass_extra_mouse_buttons_to_system,
14844 doc: /* Non-nil if the fourth and fifth mouse buttons are passed to Windows.
14845 Recent versions of Windows support mice with up to five buttons.
14846 Since most applications don't support these extra buttons, most mouse
14847 drivers will allow you to map them to functions at the system level.
14848 If this variable is non-nil, Emacs will pass them on, allowing the
14849 system to handle them. */);
14850 w32_pass_extra_mouse_buttons_to_system = 0;
14851
14852 init_x_parm_symbols ();
14853
14854 DEFVAR_LISP ("x-bitmap-file-path", &Vx_bitmap_file_path,
14855 doc: /* List of directories to search for bitmap files for w32. */);
14856 Vx_bitmap_file_path = decode_env_path ((char *) 0, "PATH");
14857
14858 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
14859 doc: /* The shape of the pointer when over text.
14860 Changing the value does not affect existing frames
14861 unless you set the mouse color. */);
14862 Vx_pointer_shape = Qnil;
14863
14864 DEFVAR_LISP ("x-resource-name", &Vx_resource_name,
14865 doc: /* The name Emacs uses to look up resources; for internal use only.
14866 `x-get-resource' uses this as the first component of the instance name
14867 when requesting resource values.
14868 Emacs initially sets `x-resource-name' to the name under which Emacs
14869 was invoked, or to the value specified with the `-name' or `-rn'
14870 switches, if present. */);
14871 Vx_resource_name = Qnil;
14872
14873 Vx_nontext_pointer_shape = Qnil;
14874
14875 Vx_mode_pointer_shape = Qnil;
14876
14877 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
14878 doc: /* The shape of the pointer when Emacs is busy.
14879 This variable takes effect when you create a new frame
14880 or when you set the mouse color. */);
14881 Vx_hourglass_pointer_shape = Qnil;
14882
14883 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
14884 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
14885 display_hourglass_p = 1;
14886
14887 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
14888 doc: /* *Seconds to wait before displaying an hourglass pointer.
14889 Value must be an integer or float. */);
14890 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
14891
14892 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
14893 &Vx_sensitive_text_pointer_shape,
14894 doc: /* The shape of the pointer when over mouse-sensitive text.
14895 This variable takes effect when you create a new frame
14896 or when you set the mouse color. */);
14897 Vx_sensitive_text_pointer_shape = Qnil;
14898
14899 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
14900 &Vx_window_horizontal_drag_shape,
14901 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
14902 This variable takes effect when you create a new frame
14903 or when you set the mouse color. */);
14904 Vx_window_horizontal_drag_shape = Qnil;
14905
14906 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
14907 doc: /* A string indicating the foreground color of the cursor box. */);
14908 Vx_cursor_fore_pixel = Qnil;
14909
14910 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
14911 doc: /* Maximum size for tooltips.
14912 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
14913 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
14914
14915 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
14916 doc: /* Non-nil if no window manager is in use.
14917 Emacs doesn't try to figure this out; this is always nil
14918 unless you set it to something else. */);
14919 /* We don't have any way to find this out, so set it to nil
14920 and maybe the user would like to set it to t. */
14921 Vx_no_window_manager = Qnil;
14922
14923 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
14924 &Vx_pixel_size_width_font_regexp,
14925 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
14926
14927 Since Emacs gets width of a font matching with this regexp from
14928 PIXEL_SIZE field of the name, font finding mechanism gets faster for
14929 such a font. This is especially effective for such large fonts as
14930 Chinese, Japanese, and Korean. */);
14931 Vx_pixel_size_width_font_regexp = Qnil;
14932
14933 DEFVAR_LISP ("image-cache-eviction-delay", &Vimage_cache_eviction_delay,
14934 doc: /* Time after which cached images are removed from the cache.
14935 When an image has not been displayed this many seconds, remove it
14936 from the image cache. Value must be an integer or nil with nil
14937 meaning don't clear the cache. */);
14938 Vimage_cache_eviction_delay = make_number (30 * 60);
14939
14940 DEFVAR_LISP ("w32-bdf-filename-alist",
14941 &Vw32_bdf_filename_alist,
14942 doc: /* List of bdf fonts and their corresponding filenames. */);
14943 Vw32_bdf_filename_alist = Qnil;
14944
14945 DEFVAR_BOOL ("w32-strict-fontnames",
14946 &w32_strict_fontnames,
14947 doc: /* Non-nil means only use fonts that are exact matches for those requested.
14948 Default is nil, which allows old fontnames that are not XLFD compliant,
14949 and allows third-party CJK display to work by specifying false charset
14950 fields to trick Emacs into translating to Big5, SJIS etc.
14951 Setting this to t will prevent wrong fonts being selected when
14952 fontsets are automatically created. */);
14953 w32_strict_fontnames = 0;
14954
14955 DEFVAR_BOOL ("w32-strict-painting",
14956 &w32_strict_painting,
14957 doc: /* Non-nil means use strict rules for repainting frames.
14958 Set this to nil to get the old behaviour for repainting; this should
14959 only be necessary if the default setting causes problems. */);
14960 w32_strict_painting = 1;
14961
14962 DEFVAR_LISP ("w32-charset-info-alist",
14963 &Vw32_charset_info_alist,
14964 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
14965 Each entry should be of the form:
14966
14967 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
14968
14969 where CHARSET_NAME is a string used in font names to identify the charset,
14970 WINDOWS_CHARSET is a symbol that can be one of:
14971 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
14972 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
14973 w32-charset-chinesebig5,
14974 #ifdef JOHAB_CHARSET
14975 w32-charset-johab, w32-charset-hebrew,
14976 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
14977 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
14978 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
14979 #endif
14980 #ifdef UNICODE_CHARSET
14981 w32-charset-unicode,
14982 #endif
14983 or w32-charset-oem.
14984 CODEPAGE should be an integer specifying the codepage that should be used
14985 to display the character set, t to do no translation and output as Unicode,
14986 or nil to do no translation and output as 8 bit (or multibyte on far-east
14987 versions of Windows) characters. */);
14988 Vw32_charset_info_alist = Qnil;
14989
14990 staticpro (&Qw32_charset_ansi);
14991 Qw32_charset_ansi = intern ("w32-charset-ansi");
14992 staticpro (&Qw32_charset_symbol);
14993 Qw32_charset_symbol = intern ("w32-charset-symbol");
14994 staticpro (&Qw32_charset_shiftjis);
14995 Qw32_charset_shiftjis = intern ("w32-charset-shiftjis");
14996 staticpro (&Qw32_charset_hangeul);
14997 Qw32_charset_hangeul = intern ("w32-charset-hangeul");
14998 staticpro (&Qw32_charset_chinesebig5);
14999 Qw32_charset_chinesebig5 = intern ("w32-charset-chinesebig5");
15000 staticpro (&Qw32_charset_gb2312);
15001 Qw32_charset_gb2312 = intern ("w32-charset-gb2312");
15002 staticpro (&Qw32_charset_oem);
15003 Qw32_charset_oem = intern ("w32-charset-oem");
15004
15005 #ifdef JOHAB_CHARSET
15006 {
15007 static int w32_extra_charsets_defined = 1;
15008 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
15009 doc: /* Internal variable. */);
15010
15011 staticpro (&Qw32_charset_johab);
15012 Qw32_charset_johab = intern ("w32-charset-johab");
15013 staticpro (&Qw32_charset_easteurope);
15014 Qw32_charset_easteurope = intern ("w32-charset-easteurope");
15015 staticpro (&Qw32_charset_turkish);
15016 Qw32_charset_turkish = intern ("w32-charset-turkish");
15017 staticpro (&Qw32_charset_baltic);
15018 Qw32_charset_baltic = intern ("w32-charset-baltic");
15019 staticpro (&Qw32_charset_russian);
15020 Qw32_charset_russian = intern ("w32-charset-russian");
15021 staticpro (&Qw32_charset_arabic);
15022 Qw32_charset_arabic = intern ("w32-charset-arabic");
15023 staticpro (&Qw32_charset_greek);
15024 Qw32_charset_greek = intern ("w32-charset-greek");
15025 staticpro (&Qw32_charset_hebrew);
15026 Qw32_charset_hebrew = intern ("w32-charset-hebrew");
15027 staticpro (&Qw32_charset_vietnamese);
15028 Qw32_charset_vietnamese = intern ("w32-charset-vietnamese");
15029 staticpro (&Qw32_charset_thai);
15030 Qw32_charset_thai = intern ("w32-charset-thai");
15031 staticpro (&Qw32_charset_mac);
15032 Qw32_charset_mac = intern ("w32-charset-mac");
15033 }
15034 #endif
15035
15036 #ifdef UNICODE_CHARSET
15037 {
15038 static int w32_unicode_charset_defined = 1;
15039 DEFVAR_BOOL ("w32-unicode-charset-defined",
15040 &w32_unicode_charset_defined,
15041 doc: /* Internal variable. */);
15042
15043 staticpro (&Qw32_charset_unicode);
15044 Qw32_charset_unicode = intern ("w32-charset-unicode");
15045 #endif
15046
15047 defsubr (&Sx_get_resource);
15048 #if 0 /* TODO: Port to W32 */
15049 defsubr (&Sx_change_window_property);
15050 defsubr (&Sx_delete_window_property);
15051 defsubr (&Sx_window_property);
15052 #endif
15053 defsubr (&Sxw_display_color_p);
15054 defsubr (&Sx_display_grayscale_p);
15055 defsubr (&Sxw_color_defined_p);
15056 defsubr (&Sxw_color_values);
15057 defsubr (&Sx_server_max_request_size);
15058 defsubr (&Sx_server_vendor);
15059 defsubr (&Sx_server_version);
15060 defsubr (&Sx_display_pixel_width);
15061 defsubr (&Sx_display_pixel_height);
15062 defsubr (&Sx_display_mm_width);
15063 defsubr (&Sx_display_mm_height);
15064 defsubr (&Sx_display_screens);
15065 defsubr (&Sx_display_planes);
15066 defsubr (&Sx_display_color_cells);
15067 defsubr (&Sx_display_visual_class);
15068 defsubr (&Sx_display_backing_store);
15069 defsubr (&Sx_display_save_under);
15070 defsubr (&Sx_parse_geometry);
15071 defsubr (&Sx_create_frame);
15072 defsubr (&Sx_open_connection);
15073 defsubr (&Sx_close_connection);
15074 defsubr (&Sx_display_list);
15075 defsubr (&Sx_synchronize);
15076
15077 /* W32 specific functions */
15078
15079 defsubr (&Sw32_focus_frame);
15080 defsubr (&Sw32_select_font);
15081 defsubr (&Sw32_define_rgb_color);
15082 defsubr (&Sw32_default_color_map);
15083 defsubr (&Sw32_load_color_file);
15084 defsubr (&Sw32_send_sys_command);
15085 defsubr (&Sw32_shell_execute);
15086 defsubr (&Sw32_register_hot_key);
15087 defsubr (&Sw32_unregister_hot_key);
15088 defsubr (&Sw32_registered_hot_keys);
15089 defsubr (&Sw32_reconstruct_hot_key);
15090 defsubr (&Sw32_toggle_lock_key);
15091 defsubr (&Sw32_find_bdf_fonts);
15092
15093 defsubr (&Sfile_system_info);
15094
15095 /* Setting callback functions for fontset handler. */
15096 get_font_info_func = w32_get_font_info;
15097
15098 #if 0 /* This function pointer doesn't seem to be used anywhere.
15099 And the pointer assigned has the wrong type, anyway. */
15100 list_fonts_func = w32_list_fonts;
15101 #endif
15102
15103 load_font_func = w32_load_font;
15104 find_ccl_program_func = w32_find_ccl_program;
15105 query_font_func = w32_query_font;
15106 set_frame_fontset_func = x_set_font;
15107 check_window_system_func = check_w32;
15108
15109 #if 0 /* TODO Image support for W32 */
15110 /* Images. */
15111 Qxbm = intern ("xbm");
15112 staticpro (&Qxbm);
15113 QCtype = intern (":type");
15114 staticpro (&QCtype);
15115 QCconversion = intern (":conversion");
15116 staticpro (&QCconversion);
15117 QCheuristic_mask = intern (":heuristic-mask");
15118 staticpro (&QCheuristic_mask);
15119 QCcolor_symbols = intern (":color-symbols");
15120 staticpro (&QCcolor_symbols);
15121 QCascent = intern (":ascent");
15122 staticpro (&QCascent);
15123 QCmargin = intern (":margin");
15124 staticpro (&QCmargin);
15125 QCrelief = intern (":relief");
15126 staticpro (&QCrelief);
15127 Qpostscript = intern ("postscript");
15128 staticpro (&Qpostscript);
15129 QCloader = intern (":loader");
15130 staticpro (&QCloader);
15131 QCbounding_box = intern (":bounding-box");
15132 staticpro (&QCbounding_box);
15133 QCpt_width = intern (":pt-width");
15134 staticpro (&QCpt_width);
15135 QCpt_height = intern (":pt-height");
15136 staticpro (&QCpt_height);
15137 QCindex = intern (":index");
15138 staticpro (&QCindex);
15139 Qpbm = intern ("pbm");
15140 staticpro (&Qpbm);
15141
15142 #if HAVE_XPM
15143 Qxpm = intern ("xpm");
15144 staticpro (&Qxpm);
15145 #endif
15146
15147 #if HAVE_JPEG
15148 Qjpeg = intern ("jpeg");
15149 staticpro (&Qjpeg);
15150 #endif
15151
15152 #if HAVE_TIFF
15153 Qtiff = intern ("tiff");
15154 staticpro (&Qtiff);
15155 #endif
15156
15157 #if HAVE_GIF
15158 Qgif = intern ("gif");
15159 staticpro (&Qgif);
15160 #endif
15161
15162 #if HAVE_PNG
15163 Qpng = intern ("png");
15164 staticpro (&Qpng);
15165 #endif
15166
15167 defsubr (&Sclear_image_cache);
15168
15169 #if GLYPH_DEBUG
15170 defsubr (&Simagep);
15171 defsubr (&Slookup_image);
15172 #endif
15173 #endif /* TODO */
15174
15175 hourglass_atimer = NULL;
15176 hourglass_shown_p = 0;
15177 defsubr (&Sx_show_tip);
15178 defsubr (&Sx_hide_tip);
15179 tip_timer = Qnil;
15180 staticpro (&tip_timer);
15181 tip_frame = Qnil;
15182 staticpro (&tip_frame);
15183
15184 last_show_tip_args = Qnil;
15185 staticpro (&last_show_tip_args);
15186
15187 defsubr (&Sx_file_dialog);
15188 }
15189
15190
15191 void
15192 init_xfns ()
15193 {
15194 image_types = NULL;
15195 Vimage_types = Qnil;
15196
15197 #if 0 /* TODO : Image support for W32 */
15198 define_image_type (&xbm_type);
15199 define_image_type (&gs_type);
15200 define_image_type (&pbm_type);
15201
15202 #if HAVE_XPM
15203 define_image_type (&xpm_type);
15204 #endif
15205
15206 #if HAVE_JPEG
15207 define_image_type (&jpeg_type);
15208 #endif
15209
15210 #if HAVE_TIFF
15211 define_image_type (&tiff_type);
15212 #endif
15213
15214 #if HAVE_GIF
15215 define_image_type (&gif_type);
15216 #endif
15217
15218 #if HAVE_PNG
15219 define_image_type (&png_type);
15220 #endif
15221 #endif /* TODO */
15222 }
15223
15224 #undef abort
15225
15226 void
15227 w32_abort()
15228 {
15229 int button;
15230 button = MessageBox (NULL,
15231 "A fatal error has occurred!\n\n"
15232 "Select Abort to exit, Retry to debug, Ignore to continue",
15233 "Emacs Abort Dialog",
15234 MB_ICONEXCLAMATION | MB_TASKMODAL
15235 | MB_SETFOREGROUND | MB_ABORTRETRYIGNORE);
15236 switch (button)
15237 {
15238 case IDRETRY:
15239 DebugBreak ();
15240 break;
15241 case IDIGNORE:
15242 break;
15243 case IDABORT:
15244 default:
15245 abort ();
15246 break;
15247 }
15248 }
15249
15250 /* For convenience when debugging. */
15251 int
15252 w32_last_error()
15253 {
15254 return GetLastError ();
15255 }