Make "xfree (NULL)" a no-op; remove useless if-before-xfree.
[bpt/emacs.git] / src / w32fns.c
1 /* Graphical user interface functions for the Microsoft W32 API.
2 Copyright (C) 1989, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
3 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
4 Free Software Foundation, Inc.
5
6 This file is part of GNU Emacs.
7
8 GNU Emacs is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 GNU Emacs is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */
20
21 /* Added by Kevin Gallo */
22
23 #include <config.h>
24
25 #include <signal.h>
26 #include <stdio.h>
27 #include <limits.h>
28 #include <errno.h>
29 #include <math.h>
30
31 #include "lisp.h"
32 #include "w32term.h"
33 #include "frame.h"
34 #include "window.h"
35 #include "buffer.h"
36 #include "intervals.h"
37 #include "dispextern.h"
38 #include "keyboard.h"
39 #include "blockinput.h"
40 #include "epaths.h"
41 #include "character.h"
42 #include "charset.h"
43 #include "coding.h"
44 #include "ccl.h"
45 #include "fontset.h"
46 #include "systime.h"
47 #include "termhooks.h"
48 #include "w32heap.h"
49
50 #include "bitmaps/gray.xbm"
51
52 #include <commctrl.h>
53 #include <commdlg.h>
54 #include <shellapi.h>
55 #include <ctype.h>
56 #include <winspool.h>
57 #include <objbase.h>
58
59 #include <dlgs.h>
60 #include <imm.h>
61 #define FILE_NAME_TEXT_FIELD edt1
62
63 #include "font.h"
64 #include "w32font.h"
65
66 void syms_of_w32fns ();
67 void globals_of_w32fns ();
68
69 extern void free_frame_menubar ();
70 extern double atof ();
71 extern int w32_console_toggle_lock_key P_ ((int, Lisp_Object));
72 extern void w32_menu_display_help P_ ((HWND, HMENU, UINT, UINT));
73 extern void w32_free_menu_strings P_ ((HWND));
74 #if OLD_FONT
75 extern XCharStruct *w32_per_char_metric P_ ((XFontStruct *, wchar_t *, int));
76 #endif
77
78 extern int quit_char;
79
80 extern char *lispy_function_keys[];
81
82 /* The colormap for converting color names to RGB values */
83 Lisp_Object Vw32_color_map;
84
85 /* Non nil if alt key presses are passed on to Windows. */
86 Lisp_Object Vw32_pass_alt_to_system;
87
88 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
89 to alt_modifier. */
90 Lisp_Object Vw32_alt_is_meta;
91
92 /* If non-zero, the windows virtual key code for an alternative quit key. */
93 int w32_quit_key;
94
95 /* Non nil if left window key events are passed on to Windows (this only
96 affects whether "tapping" the key opens the Start menu). */
97 Lisp_Object Vw32_pass_lwindow_to_system;
98
99 /* Non nil if right window key events are passed on to Windows (this
100 only affects whether "tapping" the key opens the Start menu). */
101 Lisp_Object Vw32_pass_rwindow_to_system;
102
103 /* Virtual key code used to generate "phantom" key presses in order
104 to stop system from acting on Windows key events. */
105 Lisp_Object Vw32_phantom_key_code;
106
107 /* Modifier associated with the left "Windows" key, or nil to act as a
108 normal key. */
109 Lisp_Object Vw32_lwindow_modifier;
110
111 /* Modifier associated with the right "Windows" key, or nil to act as a
112 normal key. */
113 Lisp_Object Vw32_rwindow_modifier;
114
115 /* Modifier associated with the "Apps" key, or nil to act as a normal
116 key. */
117 Lisp_Object Vw32_apps_modifier;
118
119 /* Value is nil if Num Lock acts as a function key. */
120 Lisp_Object Vw32_enable_num_lock;
121
122 /* Value is nil if Caps Lock acts as a function key. */
123 Lisp_Object Vw32_enable_caps_lock;
124
125 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
126 Lisp_Object Vw32_scroll_lock_modifier;
127
128 /* Switch to control whether we inhibit requests for synthesized bold
129 and italic versions of fonts. */
130 int w32_enable_synthesized_fonts;
131
132 /* Enable palette management. */
133 Lisp_Object Vw32_enable_palette;
134
135 /* Control how close left/right button down events must be to
136 be converted to a middle button down event. */
137 int w32_mouse_button_tolerance;
138
139 /* Minimum interval between mouse movement (and scroll bar drag)
140 events that are passed on to the event loop. */
141 int w32_mouse_move_interval;
142
143 /* Flag to indicate if XBUTTON events should be passed on to Windows. */
144 static int w32_pass_extra_mouse_buttons_to_system;
145
146 /* Flag to indicate if media keys should be passed on to Windows. */
147 static int w32_pass_multimedia_buttons_to_system;
148
149 /* Non nil if no window manager is in use. */
150 Lisp_Object Vx_no_window_manager;
151
152 /* Non-zero means we're allowed to display a hourglass pointer. */
153
154 int display_hourglass_p;
155
156 /* If non-zero, a w32 timer that, when it expires, displays an
157 hourglass cursor on all frames. */
158 static unsigned hourglass_timer = 0;
159 static HWND hourglass_hwnd = NULL;
160
161 /* The background and shape of the mouse pointer, and shape when not
162 over text or in the modeline. */
163
164 Lisp_Object Vx_pointer_shape, Vx_nontext_pointer_shape, Vx_mode_pointer_shape;
165 Lisp_Object Vx_hourglass_pointer_shape, Vx_window_horizontal_drag_shape;
166
167 /* The shape when over mouse-sensitive text. */
168
169 Lisp_Object Vx_sensitive_text_pointer_shape;
170
171 #ifndef IDC_HAND
172 #define IDC_HAND MAKEINTRESOURCE(32649)
173 #endif
174
175 /* Color of chars displayed in cursor box. */
176
177 Lisp_Object Vx_cursor_fore_pixel;
178
179 /* Nonzero if using Windows. */
180
181 static int w32_in_use;
182
183 /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'. */
184
185 Lisp_Object Vx_pixel_size_width_font_regexp;
186
187 /* Alist of bdf fonts and the files that define them. */
188 Lisp_Object Vw32_bdf_filename_alist;
189
190 /* A flag to control whether fonts are matched strictly or not. */
191 static int w32_strict_fontnames;
192
193 /* A flag to control whether we should only repaint if GetUpdateRect
194 indicates there is an update region. */
195 static int w32_strict_painting;
196
197 /* Associative list linking character set strings to Windows codepages. */
198 static Lisp_Object Vw32_charset_info_alist;
199
200 /* VIETNAMESE_CHARSET is not defined in some versions of MSVC. */
201 #ifndef VIETNAMESE_CHARSET
202 #define VIETNAMESE_CHARSET 163
203 #endif
204
205 Lisp_Object Qnone;
206 Lisp_Object Qsuppress_icon;
207 Lisp_Object Qundefined_color;
208 Lisp_Object Qcancel_timer;
209 Lisp_Object Qhyper;
210 Lisp_Object Qsuper;
211 Lisp_Object Qmeta;
212 Lisp_Object Qalt;
213 Lisp_Object Qctrl;
214 Lisp_Object Qcontrol;
215 Lisp_Object Qshift;
216
217 Lisp_Object Qw32_charset_ansi;
218 Lisp_Object Qw32_charset_default;
219 Lisp_Object Qw32_charset_symbol;
220 Lisp_Object Qw32_charset_shiftjis;
221 Lisp_Object Qw32_charset_hangeul;
222 Lisp_Object Qw32_charset_gb2312;
223 Lisp_Object Qw32_charset_chinesebig5;
224 Lisp_Object Qw32_charset_oem;
225
226 #ifndef JOHAB_CHARSET
227 #define JOHAB_CHARSET 130
228 #endif
229 #ifdef JOHAB_CHARSET
230 Lisp_Object Qw32_charset_easteurope;
231 Lisp_Object Qw32_charset_turkish;
232 Lisp_Object Qw32_charset_baltic;
233 Lisp_Object Qw32_charset_russian;
234 Lisp_Object Qw32_charset_arabic;
235 Lisp_Object Qw32_charset_greek;
236 Lisp_Object Qw32_charset_hebrew;
237 Lisp_Object Qw32_charset_vietnamese;
238 Lisp_Object Qw32_charset_thai;
239 Lisp_Object Qw32_charset_johab;
240 Lisp_Object Qw32_charset_mac;
241 #endif
242
243 #ifdef UNICODE_CHARSET
244 Lisp_Object Qw32_charset_unicode;
245 #endif
246
247 /* The ANSI codepage. */
248 int w32_ansi_code_page;
249
250 /* Prefix for system colors. */
251 #define SYSTEM_COLOR_PREFIX "System"
252 #define SYSTEM_COLOR_PREFIX_LEN (sizeof (SYSTEM_COLOR_PREFIX) - 1)
253
254 /* State variables for emulating a three button mouse. */
255 #define LMOUSE 1
256 #define MMOUSE 2
257 #define RMOUSE 4
258
259 static int button_state = 0;
260 static W32Msg saved_mouse_button_msg;
261 static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
262 static W32Msg saved_mouse_move_msg;
263 static unsigned mouse_move_timer = 0;
264
265 /* Window that is tracking the mouse. */
266 static HWND track_mouse_window;
267
268 /* Multi-monitor API definitions that are not pulled from the headers
269 since we are compiling for NT 4. */
270 #ifndef MONITOR_DEFAULT_TO_NEAREST
271 #define MONITOR_DEFAULT_TO_NEAREST 2
272 #endif
273 /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
274 To avoid a compile error on one or the other, redefine with a new name. */
275 struct MONITOR_INFO
276 {
277 DWORD cbSize;
278 RECT rcMonitor;
279 RECT rcWork;
280 DWORD dwFlags;
281 };
282
283 typedef BOOL (WINAPI * TrackMouseEvent_Proc)
284 (IN OUT LPTRACKMOUSEEVENT lpEventTrack);
285 typedef LONG (WINAPI * ImmGetCompositionString_Proc)
286 (IN HIMC context, IN DWORD index, OUT LPVOID buffer, IN DWORD bufLen);
287 typedef HIMC (WINAPI * ImmGetContext_Proc) (IN HWND window);
288 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
289 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
290 (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
291
292 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
293 ClipboardSequence_Proc clipboard_sequence_fn = NULL;
294 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
295 ImmGetContext_Proc get_ime_context_fn = NULL;
296 MonitorFromPoint_Proc monitor_from_point_fn = NULL;
297 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
298
299 extern AppendMenuW_Proc unicode_append_menu;
300
301 /* Flag to selectively ignore WM_IME_CHAR messages. */
302 static int ignore_ime_char = 0;
303
304 /* W95 mousewheel handler */
305 unsigned int msh_mousewheel = 0;
306
307 /* Timers */
308 #define MOUSE_BUTTON_ID 1
309 #define MOUSE_MOVE_ID 2
310 #define MENU_FREE_ID 3
311 #define HOURGLASS_ID 4
312 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
313 is received. */
314 #define MENU_FREE_DELAY 1000
315 static unsigned menu_free_timer = 0;
316
317 /* The below are defined in frame.c. */
318
319 extern Lisp_Object Vwindow_system_version;
320
321 #ifdef GLYPH_DEBUG
322 int image_cache_refcount, dpyinfo_refcount;
323 #endif
324
325
326 /* From w32term.c. */
327 extern int w32_num_mouse_buttons;
328 extern Lisp_Object Vw32_recognize_altgr;
329
330 extern HWND w32_system_caret_hwnd;
331
332 extern int w32_system_caret_height;
333 extern int w32_system_caret_x;
334 extern int w32_system_caret_y;
335 extern int w32_use_visible_system_caret;
336
337 static HWND w32_visible_system_caret_hwnd;
338
339 /* From w32menu.c */
340 extern HMENU current_popup_menu;
341 static int menubar_in_use = 0;
342
343 /* From w32uniscribe.c */
344 extern void syms_of_w32uniscribe ();
345 extern int uniscribe_available;
346
347 /* Function prototypes for hourglass support. */
348 static void show_hourglass P_ ((struct frame *));
349 static void hide_hourglass P_ ((void));
350
351
352 \f
353 /* Error if we are not connected to MS-Windows. */
354 void
355 check_w32 ()
356 {
357 if (! w32_in_use)
358 error ("MS-Windows not in use or not initialized");
359 }
360
361 /* Nonzero if we can use mouse menus.
362 You should not call this unless HAVE_MENUS is defined. */
363
364 int
365 have_menus_p ()
366 {
367 return w32_in_use;
368 }
369
370 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
371 and checking validity for W32. */
372
373 FRAME_PTR
374 check_x_frame (frame)
375 Lisp_Object frame;
376 {
377 FRAME_PTR f;
378
379 if (NILP (frame))
380 frame = selected_frame;
381 CHECK_LIVE_FRAME (frame);
382 f = XFRAME (frame);
383 if (! FRAME_W32_P (f))
384 error ("Non-W32 frame used");
385 return f;
386 }
387
388 /* Let the user specify a display with a frame.
389 nil stands for the selected frame--or, if that is not a w32 frame,
390 the first display on the list. */
391
392 struct w32_display_info *
393 check_x_display_info (frame)
394 Lisp_Object frame;
395 {
396 if (NILP (frame))
397 {
398 struct frame *sf = XFRAME (selected_frame);
399
400 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
401 return FRAME_W32_DISPLAY_INFO (sf);
402 else
403 return &one_w32_display_info;
404 }
405 else if (STRINGP (frame))
406 return x_display_info_for_name (frame);
407 else
408 {
409 FRAME_PTR f;
410
411 CHECK_LIVE_FRAME (frame);
412 f = XFRAME (frame);
413 if (! FRAME_W32_P (f))
414 error ("Non-W32 frame used");
415 return FRAME_W32_DISPLAY_INFO (f);
416 }
417 }
418 \f
419 /* Return the Emacs frame-object corresponding to an w32 window.
420 It could be the frame's main window or an icon window. */
421
422 /* This function can be called during GC, so use GC_xxx type test macros. */
423
424 struct frame *
425 x_window_to_frame (dpyinfo, wdesc)
426 struct w32_display_info *dpyinfo;
427 HWND wdesc;
428 {
429 Lisp_Object tail, frame;
430 struct frame *f;
431
432 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
433 {
434 frame = XCAR (tail);
435 if (!FRAMEP (frame))
436 continue;
437 f = XFRAME (frame);
438 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
439 continue;
440
441 if (FRAME_W32_WINDOW (f) == wdesc)
442 return f;
443 }
444 return 0;
445 }
446
447 \f
448 static Lisp_Object unwind_create_frame P_ ((Lisp_Object));
449 static Lisp_Object unwind_create_tip_frame P_ ((Lisp_Object));
450 static void my_create_window P_ ((struct frame *));
451 static void my_create_tip_window P_ ((struct frame *));
452
453 /* TODO: Native Input Method support; see x_create_im. */
454 void x_set_foreground_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
455 void x_set_background_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
456 void x_set_mouse_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
457 void x_set_cursor_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
458 void x_set_border_color P_ ((struct frame *, Lisp_Object, Lisp_Object));
459 void x_set_cursor_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
460 void x_set_icon_type P_ ((struct frame *, Lisp_Object, Lisp_Object));
461 void x_set_icon_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
462 void x_explicitly_set_name P_ ((struct frame *, Lisp_Object, Lisp_Object));
463 void x_set_menu_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
464 void x_set_title P_ ((struct frame *, Lisp_Object, Lisp_Object));
465 void x_set_tool_bar_lines P_ ((struct frame *, Lisp_Object, Lisp_Object));
466 static void x_edge_detection P_ ((struct frame *, struct image *, Lisp_Object,
467 Lisp_Object));
468
469
470 \f
471
472 /* Store the screen positions of frame F into XPTR and YPTR.
473 These are the positions of the containing window manager window,
474 not Emacs's own window. */
475
476 void
477 x_real_positions (f, xptr, yptr)
478 FRAME_PTR f;
479 int *xptr, *yptr;
480 {
481 POINT pt;
482 RECT rect;
483
484 /* Get the bounds of the WM window. */
485 GetWindowRect (FRAME_W32_WINDOW (f), &rect);
486
487 pt.x = 0;
488 pt.y = 0;
489
490 /* Convert (0, 0) in the client area to screen co-ordinates. */
491 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
492
493 /* Remember x_pixels_diff and y_pixels_diff. */
494 f->x_pixels_diff = pt.x - rect.left;
495 f->y_pixels_diff = pt.y - rect.top;
496
497 *xptr = rect.left;
498 *yptr = rect.top;
499 }
500
501 \f
502
503 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
504 Sw32_define_rgb_color, 4, 4, 0,
505 doc: /* Convert RGB numbers to a Windows color reference and associate with NAME.
506 This adds or updates a named color to `w32-color-map', making it
507 available for use. The original entry's RGB ref is returned, or nil
508 if the entry is new. */)
509 (red, green, blue, name)
510 Lisp_Object red, green, blue, name;
511 {
512 Lisp_Object rgb;
513 Lisp_Object oldrgb = Qnil;
514 Lisp_Object entry;
515
516 CHECK_NUMBER (red);
517 CHECK_NUMBER (green);
518 CHECK_NUMBER (blue);
519 CHECK_STRING (name);
520
521 XSETINT (rgb, RGB (XUINT (red), XUINT (green), XUINT (blue)));
522
523 BLOCK_INPUT;
524
525 /* replace existing entry in w32-color-map or add new entry. */
526 entry = Fassoc (name, Vw32_color_map);
527 if (NILP (entry))
528 {
529 entry = Fcons (name, rgb);
530 Vw32_color_map = Fcons (entry, Vw32_color_map);
531 }
532 else
533 {
534 oldrgb = Fcdr (entry);
535 Fsetcdr (entry, rgb);
536 }
537
538 UNBLOCK_INPUT;
539
540 return (oldrgb);
541 }
542
543 DEFUN ("w32-load-color-file", Fw32_load_color_file,
544 Sw32_load_color_file, 1, 1, 0,
545 doc: /* Create an alist of color entries from an external file.
546 Assign this value to `w32-color-map' to replace the existing color map.
547
548 The file should define one named RGB color per line like so:
549 R G B name
550 where R,G,B are numbers between 0 and 255 and name is an arbitrary string. */)
551 (filename)
552 Lisp_Object filename;
553 {
554 FILE *fp;
555 Lisp_Object cmap = Qnil;
556 Lisp_Object abspath;
557
558 CHECK_STRING (filename);
559 abspath = Fexpand_file_name (filename, Qnil);
560
561 fp = fopen (SDATA (filename), "rt");
562 if (fp)
563 {
564 char buf[512];
565 int red, green, blue;
566 int num;
567
568 BLOCK_INPUT;
569
570 while (fgets (buf, sizeof (buf), fp) != NULL) {
571 if (sscanf (buf, "%u %u %u %n", &red, &green, &blue, &num) == 3)
572 {
573 char *name = buf + num;
574 num = strlen (name) - 1;
575 if (name[num] == '\n')
576 name[num] = 0;
577 cmap = Fcons (Fcons (build_string (name),
578 make_number (RGB (red, green, blue))),
579 cmap);
580 }
581 }
582 fclose (fp);
583
584 UNBLOCK_INPUT;
585 }
586
587 return cmap;
588 }
589
590 /* The default colors for the w32 color map */
591 typedef struct colormap_t
592 {
593 char *name;
594 COLORREF colorref;
595 } colormap_t;
596
597 colormap_t w32_color_map[] =
598 {
599 {"snow" , PALETTERGB (255,250,250)},
600 {"ghost white" , PALETTERGB (248,248,255)},
601 {"GhostWhite" , PALETTERGB (248,248,255)},
602 {"white smoke" , PALETTERGB (245,245,245)},
603 {"WhiteSmoke" , PALETTERGB (245,245,245)},
604 {"gainsboro" , PALETTERGB (220,220,220)},
605 {"floral white" , PALETTERGB (255,250,240)},
606 {"FloralWhite" , PALETTERGB (255,250,240)},
607 {"old lace" , PALETTERGB (253,245,230)},
608 {"OldLace" , PALETTERGB (253,245,230)},
609 {"linen" , PALETTERGB (250,240,230)},
610 {"antique white" , PALETTERGB (250,235,215)},
611 {"AntiqueWhite" , PALETTERGB (250,235,215)},
612 {"papaya whip" , PALETTERGB (255,239,213)},
613 {"PapayaWhip" , PALETTERGB (255,239,213)},
614 {"blanched almond" , PALETTERGB (255,235,205)},
615 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
616 {"bisque" , PALETTERGB (255,228,196)},
617 {"peach puff" , PALETTERGB (255,218,185)},
618 {"PeachPuff" , PALETTERGB (255,218,185)},
619 {"navajo white" , PALETTERGB (255,222,173)},
620 {"NavajoWhite" , PALETTERGB (255,222,173)},
621 {"moccasin" , PALETTERGB (255,228,181)},
622 {"cornsilk" , PALETTERGB (255,248,220)},
623 {"ivory" , PALETTERGB (255,255,240)},
624 {"lemon chiffon" , PALETTERGB (255,250,205)},
625 {"LemonChiffon" , PALETTERGB (255,250,205)},
626 {"seashell" , PALETTERGB (255,245,238)},
627 {"honeydew" , PALETTERGB (240,255,240)},
628 {"mint cream" , PALETTERGB (245,255,250)},
629 {"MintCream" , PALETTERGB (245,255,250)},
630 {"azure" , PALETTERGB (240,255,255)},
631 {"alice blue" , PALETTERGB (240,248,255)},
632 {"AliceBlue" , PALETTERGB (240,248,255)},
633 {"lavender" , PALETTERGB (230,230,250)},
634 {"lavender blush" , PALETTERGB (255,240,245)},
635 {"LavenderBlush" , PALETTERGB (255,240,245)},
636 {"misty rose" , PALETTERGB (255,228,225)},
637 {"MistyRose" , PALETTERGB (255,228,225)},
638 {"white" , PALETTERGB (255,255,255)},
639 {"black" , PALETTERGB ( 0, 0, 0)},
640 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
641 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
642 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
643 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
644 {"dim gray" , PALETTERGB (105,105,105)},
645 {"DimGray" , PALETTERGB (105,105,105)},
646 {"dim grey" , PALETTERGB (105,105,105)},
647 {"DimGrey" , PALETTERGB (105,105,105)},
648 {"slate gray" , PALETTERGB (112,128,144)},
649 {"SlateGray" , PALETTERGB (112,128,144)},
650 {"slate grey" , PALETTERGB (112,128,144)},
651 {"SlateGrey" , PALETTERGB (112,128,144)},
652 {"light slate gray" , PALETTERGB (119,136,153)},
653 {"LightSlateGray" , PALETTERGB (119,136,153)},
654 {"light slate grey" , PALETTERGB (119,136,153)},
655 {"LightSlateGrey" , PALETTERGB (119,136,153)},
656 {"gray" , PALETTERGB (190,190,190)},
657 {"grey" , PALETTERGB (190,190,190)},
658 {"light grey" , PALETTERGB (211,211,211)},
659 {"LightGrey" , PALETTERGB (211,211,211)},
660 {"light gray" , PALETTERGB (211,211,211)},
661 {"LightGray" , PALETTERGB (211,211,211)},
662 {"midnight blue" , PALETTERGB ( 25, 25,112)},
663 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
664 {"navy" , PALETTERGB ( 0, 0,128)},
665 {"navy blue" , PALETTERGB ( 0, 0,128)},
666 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
667 {"cornflower blue" , PALETTERGB (100,149,237)},
668 {"CornflowerBlue" , PALETTERGB (100,149,237)},
669 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
670 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
671 {"slate blue" , PALETTERGB (106, 90,205)},
672 {"SlateBlue" , PALETTERGB (106, 90,205)},
673 {"medium slate blue" , PALETTERGB (123,104,238)},
674 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
675 {"light slate blue" , PALETTERGB (132,112,255)},
676 {"LightSlateBlue" , PALETTERGB (132,112,255)},
677 {"medium blue" , PALETTERGB ( 0, 0,205)},
678 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
679 {"royal blue" , PALETTERGB ( 65,105,225)},
680 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
681 {"blue" , PALETTERGB ( 0, 0,255)},
682 {"dodger blue" , PALETTERGB ( 30,144,255)},
683 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
684 {"deep sky blue" , PALETTERGB ( 0,191,255)},
685 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
686 {"sky blue" , PALETTERGB (135,206,235)},
687 {"SkyBlue" , PALETTERGB (135,206,235)},
688 {"light sky blue" , PALETTERGB (135,206,250)},
689 {"LightSkyBlue" , PALETTERGB (135,206,250)},
690 {"steel blue" , PALETTERGB ( 70,130,180)},
691 {"SteelBlue" , PALETTERGB ( 70,130,180)},
692 {"light steel blue" , PALETTERGB (176,196,222)},
693 {"LightSteelBlue" , PALETTERGB (176,196,222)},
694 {"light blue" , PALETTERGB (173,216,230)},
695 {"LightBlue" , PALETTERGB (173,216,230)},
696 {"powder blue" , PALETTERGB (176,224,230)},
697 {"PowderBlue" , PALETTERGB (176,224,230)},
698 {"pale turquoise" , PALETTERGB (175,238,238)},
699 {"PaleTurquoise" , PALETTERGB (175,238,238)},
700 {"dark turquoise" , PALETTERGB ( 0,206,209)},
701 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
702 {"medium turquoise" , PALETTERGB ( 72,209,204)},
703 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
704 {"turquoise" , PALETTERGB ( 64,224,208)},
705 {"cyan" , PALETTERGB ( 0,255,255)},
706 {"light cyan" , PALETTERGB (224,255,255)},
707 {"LightCyan" , PALETTERGB (224,255,255)},
708 {"cadet blue" , PALETTERGB ( 95,158,160)},
709 {"CadetBlue" , PALETTERGB ( 95,158,160)},
710 {"medium aquamarine" , PALETTERGB (102,205,170)},
711 {"MediumAquamarine" , PALETTERGB (102,205,170)},
712 {"aquamarine" , PALETTERGB (127,255,212)},
713 {"dark green" , PALETTERGB ( 0,100, 0)},
714 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
715 {"dark olive green" , PALETTERGB ( 85,107, 47)},
716 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
717 {"dark sea green" , PALETTERGB (143,188,143)},
718 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
719 {"sea green" , PALETTERGB ( 46,139, 87)},
720 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
721 {"medium sea green" , PALETTERGB ( 60,179,113)},
722 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
723 {"light sea green" , PALETTERGB ( 32,178,170)},
724 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
725 {"pale green" , PALETTERGB (152,251,152)},
726 {"PaleGreen" , PALETTERGB (152,251,152)},
727 {"spring green" , PALETTERGB ( 0,255,127)},
728 {"SpringGreen" , PALETTERGB ( 0,255,127)},
729 {"lawn green" , PALETTERGB (124,252, 0)},
730 {"LawnGreen" , PALETTERGB (124,252, 0)},
731 {"green" , PALETTERGB ( 0,255, 0)},
732 {"chartreuse" , PALETTERGB (127,255, 0)},
733 {"medium spring green" , PALETTERGB ( 0,250,154)},
734 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
735 {"green yellow" , PALETTERGB (173,255, 47)},
736 {"GreenYellow" , PALETTERGB (173,255, 47)},
737 {"lime green" , PALETTERGB ( 50,205, 50)},
738 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
739 {"yellow green" , PALETTERGB (154,205, 50)},
740 {"YellowGreen" , PALETTERGB (154,205, 50)},
741 {"forest green" , PALETTERGB ( 34,139, 34)},
742 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
743 {"olive drab" , PALETTERGB (107,142, 35)},
744 {"OliveDrab" , PALETTERGB (107,142, 35)},
745 {"dark khaki" , PALETTERGB (189,183,107)},
746 {"DarkKhaki" , PALETTERGB (189,183,107)},
747 {"khaki" , PALETTERGB (240,230,140)},
748 {"pale goldenrod" , PALETTERGB (238,232,170)},
749 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
750 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
751 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
752 {"light yellow" , PALETTERGB (255,255,224)},
753 {"LightYellow" , PALETTERGB (255,255,224)},
754 {"yellow" , PALETTERGB (255,255, 0)},
755 {"gold" , PALETTERGB (255,215, 0)},
756 {"light goldenrod" , PALETTERGB (238,221,130)},
757 {"LightGoldenrod" , PALETTERGB (238,221,130)},
758 {"goldenrod" , PALETTERGB (218,165, 32)},
759 {"dark goldenrod" , PALETTERGB (184,134, 11)},
760 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
761 {"rosy brown" , PALETTERGB (188,143,143)},
762 {"RosyBrown" , PALETTERGB (188,143,143)},
763 {"indian red" , PALETTERGB (205, 92, 92)},
764 {"IndianRed" , PALETTERGB (205, 92, 92)},
765 {"saddle brown" , PALETTERGB (139, 69, 19)},
766 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
767 {"sienna" , PALETTERGB (160, 82, 45)},
768 {"peru" , PALETTERGB (205,133, 63)},
769 {"burlywood" , PALETTERGB (222,184,135)},
770 {"beige" , PALETTERGB (245,245,220)},
771 {"wheat" , PALETTERGB (245,222,179)},
772 {"sandy brown" , PALETTERGB (244,164, 96)},
773 {"SandyBrown" , PALETTERGB (244,164, 96)},
774 {"tan" , PALETTERGB (210,180,140)},
775 {"chocolate" , PALETTERGB (210,105, 30)},
776 {"firebrick" , PALETTERGB (178,34, 34)},
777 {"brown" , PALETTERGB (165,42, 42)},
778 {"dark salmon" , PALETTERGB (233,150,122)},
779 {"DarkSalmon" , PALETTERGB (233,150,122)},
780 {"salmon" , PALETTERGB (250,128,114)},
781 {"light salmon" , PALETTERGB (255,160,122)},
782 {"LightSalmon" , PALETTERGB (255,160,122)},
783 {"orange" , PALETTERGB (255,165, 0)},
784 {"dark orange" , PALETTERGB (255,140, 0)},
785 {"DarkOrange" , PALETTERGB (255,140, 0)},
786 {"coral" , PALETTERGB (255,127, 80)},
787 {"light coral" , PALETTERGB (240,128,128)},
788 {"LightCoral" , PALETTERGB (240,128,128)},
789 {"tomato" , PALETTERGB (255, 99, 71)},
790 {"orange red" , PALETTERGB (255, 69, 0)},
791 {"OrangeRed" , PALETTERGB (255, 69, 0)},
792 {"red" , PALETTERGB (255, 0, 0)},
793 {"hot pink" , PALETTERGB (255,105,180)},
794 {"HotPink" , PALETTERGB (255,105,180)},
795 {"deep pink" , PALETTERGB (255, 20,147)},
796 {"DeepPink" , PALETTERGB (255, 20,147)},
797 {"pink" , PALETTERGB (255,192,203)},
798 {"light pink" , PALETTERGB (255,182,193)},
799 {"LightPink" , PALETTERGB (255,182,193)},
800 {"pale violet red" , PALETTERGB (219,112,147)},
801 {"PaleVioletRed" , PALETTERGB (219,112,147)},
802 {"maroon" , PALETTERGB (176, 48, 96)},
803 {"medium violet red" , PALETTERGB (199, 21,133)},
804 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
805 {"violet red" , PALETTERGB (208, 32,144)},
806 {"VioletRed" , PALETTERGB (208, 32,144)},
807 {"magenta" , PALETTERGB (255, 0,255)},
808 {"violet" , PALETTERGB (238,130,238)},
809 {"plum" , PALETTERGB (221,160,221)},
810 {"orchid" , PALETTERGB (218,112,214)},
811 {"medium orchid" , PALETTERGB (186, 85,211)},
812 {"MediumOrchid" , PALETTERGB (186, 85,211)},
813 {"dark orchid" , PALETTERGB (153, 50,204)},
814 {"DarkOrchid" , PALETTERGB (153, 50,204)},
815 {"dark violet" , PALETTERGB (148, 0,211)},
816 {"DarkViolet" , PALETTERGB (148, 0,211)},
817 {"blue violet" , PALETTERGB (138, 43,226)},
818 {"BlueViolet" , PALETTERGB (138, 43,226)},
819 {"purple" , PALETTERGB (160, 32,240)},
820 {"medium purple" , PALETTERGB (147,112,219)},
821 {"MediumPurple" , PALETTERGB (147,112,219)},
822 {"thistle" , PALETTERGB (216,191,216)},
823 {"gray0" , PALETTERGB ( 0, 0, 0)},
824 {"grey0" , PALETTERGB ( 0, 0, 0)},
825 {"dark grey" , PALETTERGB (169,169,169)},
826 {"DarkGrey" , PALETTERGB (169,169,169)},
827 {"dark gray" , PALETTERGB (169,169,169)},
828 {"DarkGray" , PALETTERGB (169,169,169)},
829 {"dark blue" , PALETTERGB ( 0, 0,139)},
830 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
831 {"dark cyan" , PALETTERGB ( 0,139,139)},
832 {"DarkCyan" , PALETTERGB ( 0,139,139)},
833 {"dark magenta" , PALETTERGB (139, 0,139)},
834 {"DarkMagenta" , PALETTERGB (139, 0,139)},
835 {"dark red" , PALETTERGB (139, 0, 0)},
836 {"DarkRed" , PALETTERGB (139, 0, 0)},
837 {"light green" , PALETTERGB (144,238,144)},
838 {"LightGreen" , PALETTERGB (144,238,144)},
839 };
840
841 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
842 0, 0, 0, doc: /* Return the default color map. */)
843 ()
844 {
845 int i;
846 colormap_t *pc = w32_color_map;
847 Lisp_Object cmap;
848
849 BLOCK_INPUT;
850
851 cmap = Qnil;
852
853 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
854 pc++, i++)
855 cmap = Fcons (Fcons (build_string (pc->name),
856 make_number (pc->colorref)),
857 cmap);
858
859 UNBLOCK_INPUT;
860
861 return (cmap);
862 }
863
864 static Lisp_Object
865 w32_to_x_color (rgb)
866 Lisp_Object rgb;
867 {
868 Lisp_Object color;
869
870 CHECK_NUMBER (rgb);
871
872 BLOCK_INPUT;
873
874 color = Frassq (rgb, Vw32_color_map);
875
876 UNBLOCK_INPUT;
877
878 if (!NILP (color))
879 return (Fcar (color));
880 else
881 return Qnil;
882 }
883
884 static Lisp_Object
885 w32_color_map_lookup (colorname)
886 char *colorname;
887 {
888 Lisp_Object tail, ret = Qnil;
889
890 BLOCK_INPUT;
891
892 for (tail = Vw32_color_map; CONSP (tail); tail = XCDR (tail))
893 {
894 register Lisp_Object elt, tem;
895
896 elt = XCAR (tail);
897 if (!CONSP (elt)) continue;
898
899 tem = Fcar (elt);
900
901 if (lstrcmpi (SDATA (tem), colorname) == 0)
902 {
903 ret = Fcdr (elt);
904 break;
905 }
906
907 QUIT;
908 }
909
910
911 UNBLOCK_INPUT;
912
913 return ret;
914 }
915
916
917 static void
918 add_system_logical_colors_to_map (system_colors)
919 Lisp_Object *system_colors;
920 {
921 HKEY colors_key;
922
923 /* Other registry operations are done with input blocked. */
924 BLOCK_INPUT;
925
926 /* Look for "Control Panel/Colors" under User and Machine registry
927 settings. */
928 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Control Panel\\Colors", 0,
929 KEY_READ, &colors_key) == ERROR_SUCCESS
930 || RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Control Panel\\Colors", 0,
931 KEY_READ, &colors_key) == ERROR_SUCCESS)
932 {
933 /* List all keys. */
934 char color_buffer[64];
935 char full_name_buffer[MAX_PATH + SYSTEM_COLOR_PREFIX_LEN];
936 int index = 0;
937 DWORD name_size, color_size;
938 char *name_buffer = full_name_buffer + SYSTEM_COLOR_PREFIX_LEN;
939
940 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
941 color_size = sizeof (color_buffer);
942
943 strcpy (full_name_buffer, SYSTEM_COLOR_PREFIX);
944
945 while (RegEnumValueA (colors_key, index, name_buffer, &name_size,
946 NULL, NULL, color_buffer, &color_size)
947 == ERROR_SUCCESS)
948 {
949 int r, g, b;
950 if (sscanf (color_buffer, " %u %u %u", &r, &g, &b) == 3)
951 *system_colors = Fcons (Fcons (build_string (full_name_buffer),
952 make_number (RGB (r, g, b))),
953 *system_colors);
954
955 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
956 color_size = sizeof (color_buffer);
957 index++;
958 }
959 RegCloseKey (colors_key);
960 }
961
962 UNBLOCK_INPUT;
963 }
964
965
966 static Lisp_Object
967 x_to_w32_color (colorname)
968 char * colorname;
969 {
970 register Lisp_Object ret = Qnil;
971
972 BLOCK_INPUT;
973
974 if (colorname[0] == '#')
975 {
976 /* Could be an old-style RGB Device specification. */
977 char *color;
978 int size;
979 color = colorname + 1;
980
981 size = strlen (color);
982 if (size == 3 || size == 6 || size == 9 || size == 12)
983 {
984 UINT colorval;
985 int i, pos;
986 pos = 0;
987 size /= 3;
988 colorval = 0;
989
990 for (i = 0; i < 3; i++)
991 {
992 char *end;
993 char t;
994 unsigned long value;
995
996 /* The check for 'x' in the following conditional takes into
997 account the fact that strtol allows a "0x" in front of
998 our numbers, and we don't. */
999 if (!isxdigit (color[0]) || color[1] == 'x')
1000 break;
1001 t = color[size];
1002 color[size] = '\0';
1003 value = strtoul (color, &end, 16);
1004 color[size] = t;
1005 if (errno == ERANGE || end - color != size)
1006 break;
1007 switch (size)
1008 {
1009 case 1:
1010 value = value * 0x10;
1011 break;
1012 case 2:
1013 break;
1014 case 3:
1015 value /= 0x10;
1016 break;
1017 case 4:
1018 value /= 0x100;
1019 break;
1020 }
1021 colorval |= (value << pos);
1022 pos += 0x8;
1023 if (i == 2)
1024 {
1025 UNBLOCK_INPUT;
1026 XSETINT (ret, colorval);
1027 return ret;
1028 }
1029 color = end;
1030 }
1031 }
1032 }
1033 else if (strnicmp (colorname, "rgb:", 4) == 0)
1034 {
1035 char *color;
1036 UINT colorval;
1037 int i, pos;
1038 pos = 0;
1039
1040 colorval = 0;
1041 color = colorname + 4;
1042 for (i = 0; i < 3; i++)
1043 {
1044 char *end;
1045 unsigned long value;
1046
1047 /* The check for 'x' in the following conditional takes into
1048 account the fact that strtol allows a "0x" in front of
1049 our numbers, and we don't. */
1050 if (!isxdigit (color[0]) || color[1] == 'x')
1051 break;
1052 value = strtoul (color, &end, 16);
1053 if (errno == ERANGE)
1054 break;
1055 switch (end - color)
1056 {
1057 case 1:
1058 value = value * 0x10 + value;
1059 break;
1060 case 2:
1061 break;
1062 case 3:
1063 value /= 0x10;
1064 break;
1065 case 4:
1066 value /= 0x100;
1067 break;
1068 default:
1069 value = ULONG_MAX;
1070 }
1071 if (value == ULONG_MAX)
1072 break;
1073 colorval |= (value << pos);
1074 pos += 0x8;
1075 if (i == 2)
1076 {
1077 if (*end != '\0')
1078 break;
1079 UNBLOCK_INPUT;
1080 XSETINT (ret, colorval);
1081 return ret;
1082 }
1083 if (*end != '/')
1084 break;
1085 color = end + 1;
1086 }
1087 }
1088 else if (strnicmp (colorname, "rgbi:", 5) == 0)
1089 {
1090 /* This is an RGB Intensity specification. */
1091 char *color;
1092 UINT colorval;
1093 int i, pos;
1094 pos = 0;
1095
1096 colorval = 0;
1097 color = colorname + 5;
1098 for (i = 0; i < 3; i++)
1099 {
1100 char *end;
1101 double value;
1102 UINT val;
1103
1104 value = strtod (color, &end);
1105 if (errno == ERANGE)
1106 break;
1107 if (value < 0.0 || value > 1.0)
1108 break;
1109 val = (UINT)(0x100 * value);
1110 /* We used 0x100 instead of 0xFF to give a continuous
1111 range between 0.0 and 1.0 inclusive. The next statement
1112 fixes the 1.0 case. */
1113 if (val == 0x100)
1114 val = 0xFF;
1115 colorval |= (val << pos);
1116 pos += 0x8;
1117 if (i == 2)
1118 {
1119 if (*end != '\0')
1120 break;
1121 UNBLOCK_INPUT;
1122 XSETINT (ret, colorval);
1123 return ret;
1124 }
1125 if (*end != '/')
1126 break;
1127 color = end + 1;
1128 }
1129 }
1130 /* I am not going to attempt to handle any of the CIE color schemes
1131 or TekHVC, since I don't know the algorithms for conversion to
1132 RGB. */
1133
1134 /* If we fail to lookup the color name in w32_color_map, then check the
1135 colorname to see if it can be crudely approximated: If the X color
1136 ends in a number (e.g., "darkseagreen2"), strip the number and
1137 return the result of looking up the base color name. */
1138 ret = w32_color_map_lookup (colorname);
1139 if (NILP (ret))
1140 {
1141 int len = strlen (colorname);
1142
1143 if (isdigit (colorname[len - 1]))
1144 {
1145 char *ptr, *approx = alloca (len + 1);
1146
1147 strcpy (approx, colorname);
1148 ptr = &approx[len - 1];
1149 while (ptr > approx && isdigit (*ptr))
1150 *ptr-- = '\0';
1151
1152 ret = w32_color_map_lookup (approx);
1153 }
1154 }
1155
1156 UNBLOCK_INPUT;
1157 return ret;
1158 }
1159
1160 void
1161 w32_regenerate_palette (FRAME_PTR f)
1162 {
1163 struct w32_palette_entry * list;
1164 LOGPALETTE * log_palette;
1165 HPALETTE new_palette;
1166 int i;
1167
1168 /* don't bother trying to create palette if not supported */
1169 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1170 return;
1171
1172 log_palette = (LOGPALETTE *)
1173 alloca (sizeof (LOGPALETTE) +
1174 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1175 log_palette->palVersion = 0x300;
1176 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1177
1178 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1179 for (i = 0;
1180 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1181 i++, list = list->next)
1182 log_palette->palPalEntry[i] = list->entry;
1183
1184 new_palette = CreatePalette (log_palette);
1185
1186 enter_crit ();
1187
1188 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1189 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1190 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1191
1192 /* Realize display palette and garbage all frames. */
1193 release_frame_dc (f, get_frame_dc (f));
1194
1195 leave_crit ();
1196 }
1197
1198 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1199 #define SET_W32_COLOR(pe, color) \
1200 do \
1201 { \
1202 pe.peRed = GetRValue (color); \
1203 pe.peGreen = GetGValue (color); \
1204 pe.peBlue = GetBValue (color); \
1205 pe.peFlags = 0; \
1206 } while (0)
1207
1208 #if 0
1209 /* Keep these around in case we ever want to track color usage. */
1210 void
1211 w32_map_color (FRAME_PTR f, COLORREF color)
1212 {
1213 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1214
1215 if (NILP (Vw32_enable_palette))
1216 return;
1217
1218 /* check if color is already mapped */
1219 while (list)
1220 {
1221 if (W32_COLOR (list->entry) == color)
1222 {
1223 ++list->refcount;
1224 return;
1225 }
1226 list = list->next;
1227 }
1228
1229 /* not already mapped, so add to list and recreate Windows palette */
1230 list = (struct w32_palette_entry *)
1231 xmalloc (sizeof (struct w32_palette_entry));
1232 SET_W32_COLOR (list->entry, color);
1233 list->refcount = 1;
1234 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1235 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1236 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1237
1238 /* set flag that palette must be regenerated */
1239 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1240 }
1241
1242 void
1243 w32_unmap_color (FRAME_PTR f, COLORREF color)
1244 {
1245 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1246 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1247
1248 if (NILP (Vw32_enable_palette))
1249 return;
1250
1251 /* check if color is already mapped */
1252 while (list)
1253 {
1254 if (W32_COLOR (list->entry) == color)
1255 {
1256 if (--list->refcount == 0)
1257 {
1258 *prev = list->next;
1259 xfree (list);
1260 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1261 break;
1262 }
1263 else
1264 return;
1265 }
1266 prev = &list->next;
1267 list = list->next;
1268 }
1269
1270 /* set flag that palette must be regenerated */
1271 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1272 }
1273 #endif
1274
1275
1276 /* Gamma-correct COLOR on frame F. */
1277
1278 void
1279 gamma_correct (f, color)
1280 struct frame *f;
1281 COLORREF *color;
1282 {
1283 if (f->gamma)
1284 {
1285 *color = PALETTERGB (
1286 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1287 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1288 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1289 }
1290 }
1291
1292
1293 /* Decide if color named COLOR is valid for the display associated with
1294 the selected frame; if so, return the rgb values in COLOR_DEF.
1295 If ALLOC is nonzero, allocate a new colormap cell. */
1296
1297 int
1298 w32_defined_color (f, color, color_def, alloc)
1299 FRAME_PTR f;
1300 char *color;
1301 XColor *color_def;
1302 int alloc;
1303 {
1304 register Lisp_Object tem;
1305 COLORREF w32_color_ref;
1306
1307 tem = x_to_w32_color (color);
1308
1309 if (!NILP (tem))
1310 {
1311 if (f)
1312 {
1313 /* Apply gamma correction. */
1314 w32_color_ref = XUINT (tem);
1315 gamma_correct (f, &w32_color_ref);
1316 XSETINT (tem, w32_color_ref);
1317 }
1318
1319 /* Map this color to the palette if it is enabled. */
1320 if (!NILP (Vw32_enable_palette))
1321 {
1322 struct w32_palette_entry * entry =
1323 one_w32_display_info.color_list;
1324 struct w32_palette_entry ** prev =
1325 &one_w32_display_info.color_list;
1326
1327 /* check if color is already mapped */
1328 while (entry)
1329 {
1330 if (W32_COLOR (entry->entry) == XUINT (tem))
1331 break;
1332 prev = &entry->next;
1333 entry = entry->next;
1334 }
1335
1336 if (entry == NULL && alloc)
1337 {
1338 /* not already mapped, so add to list */
1339 entry = (struct w32_palette_entry *)
1340 xmalloc (sizeof (struct w32_palette_entry));
1341 SET_W32_COLOR (entry->entry, XUINT (tem));
1342 entry->next = NULL;
1343 *prev = entry;
1344 one_w32_display_info.num_colors++;
1345
1346 /* set flag that palette must be regenerated */
1347 one_w32_display_info.regen_palette = TRUE;
1348 }
1349 }
1350 /* Ensure COLORREF value is snapped to nearest color in (default)
1351 palette by simulating the PALETTERGB macro. This works whether
1352 or not the display device has a palette. */
1353 w32_color_ref = XUINT (tem) | 0x2000000;
1354
1355 color_def->pixel = w32_color_ref;
1356 color_def->red = GetRValue (w32_color_ref) * 256;
1357 color_def->green = GetGValue (w32_color_ref) * 256;
1358 color_def->blue = GetBValue (w32_color_ref) * 256;
1359
1360 return 1;
1361 }
1362 else
1363 {
1364 return 0;
1365 }
1366 }
1367
1368 /* Given a string ARG naming a color, compute a pixel value from it
1369 suitable for screen F.
1370 If F is not a color screen, return DEF (default) regardless of what
1371 ARG says. */
1372
1373 int
1374 x_decode_color (f, arg, def)
1375 FRAME_PTR f;
1376 Lisp_Object arg;
1377 int def;
1378 {
1379 XColor cdef;
1380
1381 CHECK_STRING (arg);
1382
1383 if (strcmp (SDATA (arg), "black") == 0)
1384 return BLACK_PIX_DEFAULT (f);
1385 else if (strcmp (SDATA (arg), "white") == 0)
1386 return WHITE_PIX_DEFAULT (f);
1387
1388 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1389 return def;
1390
1391 /* w32_defined_color is responsible for coping with failures
1392 by looking for a near-miss. */
1393 if (w32_defined_color (f, SDATA (arg), &cdef, 1))
1394 return cdef.pixel;
1395
1396 /* defined_color failed; return an ultimate default. */
1397 return def;
1398 }
1399 \f
1400
1401
1402 /* Functions called only from `x_set_frame_param'
1403 to set individual parameters.
1404
1405 If FRAME_W32_WINDOW (f) is 0,
1406 the frame is being created and its window does not exist yet.
1407 In that case, just record the parameter's new value
1408 in the standard place; do not attempt to change the window. */
1409
1410 void
1411 x_set_foreground_color (f, arg, oldval)
1412 struct frame *f;
1413 Lisp_Object arg, oldval;
1414 {
1415 struct w32_output *x = f->output_data.w32;
1416 PIX_TYPE fg, old_fg;
1417
1418 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1419 old_fg = FRAME_FOREGROUND_PIXEL (f);
1420 FRAME_FOREGROUND_PIXEL (f) = fg;
1421
1422 if (FRAME_W32_WINDOW (f) != 0)
1423 {
1424 if (x->cursor_pixel == old_fg)
1425 x->cursor_pixel = fg;
1426
1427 update_face_from_frame_parameter (f, Qforeground_color, arg);
1428 if (FRAME_VISIBLE_P (f))
1429 redraw_frame (f);
1430 }
1431 }
1432
1433 void
1434 x_set_background_color (f, arg, oldval)
1435 struct frame *f;
1436 Lisp_Object arg, oldval;
1437 {
1438 FRAME_BACKGROUND_PIXEL (f)
1439 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1440
1441 if (FRAME_W32_WINDOW (f) != 0)
1442 {
1443 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1444 FRAME_BACKGROUND_PIXEL (f));
1445
1446 update_face_from_frame_parameter (f, Qbackground_color, arg);
1447
1448 if (FRAME_VISIBLE_P (f))
1449 redraw_frame (f);
1450 }
1451 }
1452
1453 void
1454 x_set_mouse_color (f, arg, oldval)
1455 struct frame *f;
1456 Lisp_Object arg, oldval;
1457 {
1458 Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
1459 int count;
1460 int mask_color;
1461
1462 if (!EQ (Qnil, arg))
1463 f->output_data.w32->mouse_pixel
1464 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1465 mask_color = FRAME_BACKGROUND_PIXEL (f);
1466
1467 /* Don't let pointers be invisible. */
1468 if (mask_color == f->output_data.w32->mouse_pixel
1469 && mask_color == FRAME_BACKGROUND_PIXEL (f))
1470 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
1471
1472 #if 0 /* TODO : cursor changes */
1473 BLOCK_INPUT;
1474
1475 /* It's not okay to crash if the user selects a screwy cursor. */
1476 count = x_catch_errors (FRAME_W32_DISPLAY (f));
1477
1478 if (!EQ (Qnil, Vx_pointer_shape))
1479 {
1480 CHECK_NUMBER (Vx_pointer_shape);
1481 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
1482 }
1483 else
1484 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1485 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
1486
1487 if (!EQ (Qnil, Vx_nontext_pointer_shape))
1488 {
1489 CHECK_NUMBER (Vx_nontext_pointer_shape);
1490 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1491 XINT (Vx_nontext_pointer_shape));
1492 }
1493 else
1494 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
1495 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1496
1497 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
1498 {
1499 CHECK_NUMBER (Vx_hourglass_pointer_shape);
1500 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1501 XINT (Vx_hourglass_pointer_shape));
1502 }
1503 else
1504 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
1505 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
1506
1507 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1508 if (!EQ (Qnil, Vx_mode_pointer_shape))
1509 {
1510 CHECK_NUMBER (Vx_mode_pointer_shape);
1511 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1512 XINT (Vx_mode_pointer_shape));
1513 }
1514 else
1515 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1516 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
1517
1518 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
1519 {
1520 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
1521 hand_cursor
1522 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1523 XINT (Vx_sensitive_text_pointer_shape));
1524 }
1525 else
1526 hand_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
1527
1528 if (!NILP (Vx_window_horizontal_drag_shape))
1529 {
1530 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
1531 horizontal_drag_cursor
1532 = XCreateFontCursor (FRAME_X_DISPLAY (f),
1533 XINT (Vx_window_horizontal_drag_shape));
1534 }
1535 else
1536 horizontal_drag_cursor
1537 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
1538
1539 /* Check and report errors with the above calls. */
1540 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
1541 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
1542
1543 {
1544 XColor fore_color, back_color;
1545
1546 fore_color.pixel = f->output_data.w32->mouse_pixel;
1547 back_color.pixel = mask_color;
1548 XQueryColor (FRAME_W32_DISPLAY (f),
1549 DefaultColormap (FRAME_W32_DISPLAY (f),
1550 DefaultScreen (FRAME_W32_DISPLAY (f))),
1551 &fore_color);
1552 XQueryColor (FRAME_W32_DISPLAY (f),
1553 DefaultColormap (FRAME_W32_DISPLAY (f),
1554 DefaultScreen (FRAME_W32_DISPLAY (f))),
1555 &back_color);
1556 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
1557 &fore_color, &back_color);
1558 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
1559 &fore_color, &back_color);
1560 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
1561 &fore_color, &back_color);
1562 XRecolorCursor (FRAME_W32_DISPLAY (f), hand_cursor,
1563 &fore_color, &back_color);
1564 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
1565 &fore_color, &back_color);
1566 }
1567
1568 if (FRAME_W32_WINDOW (f) != 0)
1569 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
1570
1571 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
1572 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
1573 f->output_data.w32->text_cursor = cursor;
1574
1575 if (nontext_cursor != f->output_data.w32->nontext_cursor
1576 && f->output_data.w32->nontext_cursor != 0)
1577 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
1578 f->output_data.w32->nontext_cursor = nontext_cursor;
1579
1580 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
1581 && f->output_data.w32->hourglass_cursor != 0)
1582 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
1583 f->output_data.w32->hourglass_cursor = hourglass_cursor;
1584
1585 if (mode_cursor != f->output_data.w32->modeline_cursor
1586 && f->output_data.w32->modeline_cursor != 0)
1587 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
1588 f->output_data.w32->modeline_cursor = mode_cursor;
1589
1590 if (hand_cursor != f->output_data.w32->hand_cursor
1591 && f->output_data.w32->hand_cursor != 0)
1592 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hand_cursor);
1593 f->output_data.w32->hand_cursor = hand_cursor;
1594
1595 XFlush (FRAME_W32_DISPLAY (f));
1596 UNBLOCK_INPUT;
1597
1598 update_face_from_frame_parameter (f, Qmouse_color, arg);
1599 #endif /* TODO */
1600 }
1601
1602 void
1603 x_set_cursor_color (f, arg, oldval)
1604 struct frame *f;
1605 Lisp_Object arg, oldval;
1606 {
1607 unsigned long fore_pixel, pixel;
1608
1609 if (!NILP (Vx_cursor_fore_pixel))
1610 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1611 WHITE_PIX_DEFAULT (f));
1612 else
1613 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
1614
1615 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1616
1617 /* Make sure that the cursor color differs from the background color. */
1618 if (pixel == FRAME_BACKGROUND_PIXEL (f))
1619 {
1620 pixel = f->output_data.w32->mouse_pixel;
1621 if (pixel == fore_pixel)
1622 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
1623 }
1624
1625 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
1626 f->output_data.w32->cursor_pixel = pixel;
1627
1628 if (FRAME_W32_WINDOW (f) != 0)
1629 {
1630 BLOCK_INPUT;
1631 /* Update frame's cursor_gc. */
1632 f->output_data.w32->cursor_gc->foreground = fore_pixel;
1633 f->output_data.w32->cursor_gc->background = pixel;
1634
1635 UNBLOCK_INPUT;
1636
1637 if (FRAME_VISIBLE_P (f))
1638 {
1639 x_update_cursor (f, 0);
1640 x_update_cursor (f, 1);
1641 }
1642 }
1643
1644 update_face_from_frame_parameter (f, Qcursor_color, arg);
1645 }
1646
1647 /* Set the border-color of frame F to pixel value PIX.
1648 Note that this does not fully take effect if done before
1649 F has a window. */
1650
1651 void
1652 x_set_border_pixel (f, pix)
1653 struct frame *f;
1654 int pix;
1655 {
1656
1657 f->output_data.w32->border_pixel = pix;
1658
1659 if (FRAME_W32_WINDOW (f) != 0 && f->border_width > 0)
1660 {
1661 if (FRAME_VISIBLE_P (f))
1662 redraw_frame (f);
1663 }
1664 }
1665
1666 /* Set the border-color of frame F to value described by ARG.
1667 ARG can be a string naming a color.
1668 The border-color is used for the border that is drawn by the server.
1669 Note that this does not fully take effect if done before
1670 F has a window; it must be redone when the window is created. */
1671
1672 void
1673 x_set_border_color (f, arg, oldval)
1674 struct frame *f;
1675 Lisp_Object arg, oldval;
1676 {
1677 int pix;
1678
1679 CHECK_STRING (arg);
1680 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1681 x_set_border_pixel (f, pix);
1682 update_face_from_frame_parameter (f, Qborder_color, arg);
1683 }
1684
1685
1686 void
1687 x_set_cursor_type (f, arg, oldval)
1688 FRAME_PTR f;
1689 Lisp_Object arg, oldval;
1690 {
1691 set_frame_cursor_types (f, arg);
1692
1693 /* Make sure the cursor gets redrawn. */
1694 cursor_type_changed = 1;
1695 }
1696 \f
1697 void
1698 x_set_icon_type (f, arg, oldval)
1699 struct frame *f;
1700 Lisp_Object arg, oldval;
1701 {
1702 int result;
1703
1704 if (NILP (arg) && NILP (oldval))
1705 return;
1706
1707 if (STRINGP (arg) && STRINGP (oldval)
1708 && EQ (Fstring_equal (oldval, arg), Qt))
1709 return;
1710
1711 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
1712 return;
1713
1714 BLOCK_INPUT;
1715
1716 result = x_bitmap_icon (f, arg);
1717 if (result)
1718 {
1719 UNBLOCK_INPUT;
1720 error ("No icon window available");
1721 }
1722
1723 UNBLOCK_INPUT;
1724 }
1725
1726 void
1727 x_set_icon_name (f, arg, oldval)
1728 struct frame *f;
1729 Lisp_Object arg, oldval;
1730 {
1731 if (STRINGP (arg))
1732 {
1733 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1734 return;
1735 }
1736 else if (!NILP (arg) || NILP (oldval))
1737 return;
1738
1739 f->icon_name = arg;
1740
1741 #if 0
1742 if (f->output_data.w32->icon_bitmap != 0)
1743 return;
1744
1745 BLOCK_INPUT;
1746
1747 result = x_text_icon (f,
1748 (char *) SDATA ((!NILP (f->icon_name)
1749 ? f->icon_name
1750 : !NILP (f->title)
1751 ? f->title
1752 : f->name)));
1753
1754 if (result)
1755 {
1756 UNBLOCK_INPUT;
1757 error ("No icon window available");
1758 }
1759
1760 /* If the window was unmapped (and its icon was mapped),
1761 the new icon is not mapped, so map the window in its stead. */
1762 if (FRAME_VISIBLE_P (f))
1763 {
1764 #ifdef USE_X_TOOLKIT
1765 XtPopup (f->output_data.w32->widget, XtGrabNone);
1766 #endif
1767 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
1768 }
1769
1770 XFlush (FRAME_W32_DISPLAY (f));
1771 UNBLOCK_INPUT;
1772 #endif
1773 }
1774
1775 \f
1776 void
1777 x_set_menu_bar_lines (f, value, oldval)
1778 struct frame *f;
1779 Lisp_Object value, oldval;
1780 {
1781 int nlines;
1782 int olines = FRAME_MENU_BAR_LINES (f);
1783
1784 /* Right now, menu bars don't work properly in minibuf-only frames;
1785 most of the commands try to apply themselves to the minibuffer
1786 frame itself, and get an error because you can't switch buffers
1787 in or split the minibuffer window. */
1788 if (FRAME_MINIBUF_ONLY_P (f))
1789 return;
1790
1791 if (INTEGERP (value))
1792 nlines = XINT (value);
1793 else
1794 nlines = 0;
1795
1796 FRAME_MENU_BAR_LINES (f) = 0;
1797 if (nlines)
1798 FRAME_EXTERNAL_MENU_BAR (f) = 1;
1799 else
1800 {
1801 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
1802 free_frame_menubar (f);
1803 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1804
1805 /* Adjust the frame size so that the client (text) dimensions
1806 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
1807 set correctly. */
1808 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1809 do_pending_window_change (0);
1810 }
1811 adjust_glyphs (f);
1812 }
1813
1814
1815 /* Set the number of lines used for the tool bar of frame F to VALUE.
1816 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
1817 is the old number of tool bar lines. This function changes the
1818 height of all windows on frame F to match the new tool bar height.
1819 The frame's height doesn't change. */
1820
1821 void
1822 x_set_tool_bar_lines (f, value, oldval)
1823 struct frame *f;
1824 Lisp_Object value, oldval;
1825 {
1826 int delta, nlines, root_height;
1827 Lisp_Object root_window;
1828
1829 /* Treat tool bars like menu bars. */
1830 if (FRAME_MINIBUF_ONLY_P (f))
1831 return;
1832
1833 /* Use VALUE only if an integer >= 0. */
1834 if (INTEGERP (value) && XINT (value) >= 0)
1835 nlines = XFASTINT (value);
1836 else
1837 nlines = 0;
1838
1839 /* Make sure we redisplay all windows in this frame. */
1840 ++windows_or_buffers_changed;
1841
1842 delta = nlines - FRAME_TOOL_BAR_LINES (f);
1843
1844 /* Don't resize the tool-bar to more than we have room for. */
1845 root_window = FRAME_ROOT_WINDOW (f);
1846 root_height = WINDOW_TOTAL_LINES (XWINDOW (root_window));
1847 if (root_height - delta < 1)
1848 {
1849 delta = root_height - 1;
1850 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
1851 }
1852
1853 FRAME_TOOL_BAR_LINES (f) = nlines;
1854 change_window_heights (root_window, delta);
1855 adjust_glyphs (f);
1856
1857 /* We also have to make sure that the internal border at the top of
1858 the frame, below the menu bar or tool bar, is redrawn when the
1859 tool bar disappears. This is so because the internal border is
1860 below the tool bar if one is displayed, but is below the menu bar
1861 if there isn't a tool bar. The tool bar draws into the area
1862 below the menu bar. */
1863 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
1864 {
1865 clear_frame (f);
1866 clear_current_matrices (f);
1867 }
1868
1869 /* If the tool bar gets smaller, the internal border below it
1870 has to be cleared. It was formerly part of the display
1871 of the larger tool bar, and updating windows won't clear it. */
1872 if (delta < 0)
1873 {
1874 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
1875 int width = FRAME_PIXEL_WIDTH (f);
1876 int y = nlines * FRAME_LINE_HEIGHT (f);
1877
1878 BLOCK_INPUT;
1879 {
1880 HDC hdc = get_frame_dc (f);
1881 w32_clear_area (f, hdc, 0, y, width, height);
1882 release_frame_dc (f, hdc);
1883 }
1884 UNBLOCK_INPUT;
1885
1886 if (WINDOWP (f->tool_bar_window))
1887 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
1888 }
1889 }
1890
1891
1892 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
1893 w32_id_name.
1894
1895 If EXPLICIT is non-zero, that indicates that lisp code is setting the
1896 name; if NAME is a string, set F's name to NAME and set
1897 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
1898
1899 If EXPLICIT is zero, that indicates that Emacs redisplay code is
1900 suggesting a new name, which lisp code should override; if
1901 F->explicit_name is set, ignore the new name; otherwise, set it. */
1902
1903 void
1904 x_set_name (f, name, explicit)
1905 struct frame *f;
1906 Lisp_Object name;
1907 int explicit;
1908 {
1909 /* Make sure that requests from lisp code override requests from
1910 Emacs redisplay code. */
1911 if (explicit)
1912 {
1913 /* If we're switching from explicit to implicit, we had better
1914 update the mode lines and thereby update the title. */
1915 if (f->explicit_name && NILP (name))
1916 update_mode_lines = 1;
1917
1918 f->explicit_name = ! NILP (name);
1919 }
1920 else if (f->explicit_name)
1921 return;
1922
1923 /* If NAME is nil, set the name to the w32_id_name. */
1924 if (NILP (name))
1925 {
1926 /* Check for no change needed in this very common case
1927 before we do any consing. */
1928 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
1929 SDATA (f->name)))
1930 return;
1931 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
1932 }
1933 else
1934 CHECK_STRING (name);
1935
1936 /* Don't change the name if it's already NAME. */
1937 if (! NILP (Fstring_equal (name, f->name)))
1938 return;
1939
1940 f->name = name;
1941
1942 /* For setting the frame title, the title parameter should override
1943 the name parameter. */
1944 if (! NILP (f->title))
1945 name = f->title;
1946
1947 if (FRAME_W32_WINDOW (f))
1948 {
1949 if (STRING_MULTIBYTE (name))
1950 name = ENCODE_SYSTEM (name);
1951
1952 BLOCK_INPUT;
1953 SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
1954 UNBLOCK_INPUT;
1955 }
1956 }
1957
1958 /* This function should be called when the user's lisp code has
1959 specified a name for the frame; the name will override any set by the
1960 redisplay code. */
1961 void
1962 x_explicitly_set_name (f, arg, oldval)
1963 FRAME_PTR f;
1964 Lisp_Object arg, oldval;
1965 {
1966 x_set_name (f, arg, 1);
1967 }
1968
1969 /* This function should be called by Emacs redisplay code to set the
1970 name; names set this way will never override names set by the user's
1971 lisp code. */
1972 void
1973 x_implicitly_set_name (f, arg, oldval)
1974 FRAME_PTR f;
1975 Lisp_Object arg, oldval;
1976 {
1977 x_set_name (f, arg, 0);
1978 }
1979 \f
1980 /* Change the title of frame F to NAME.
1981 If NAME is nil, use the frame name as the title. */
1982
1983 void
1984 x_set_title (f, name, old_name)
1985 struct frame *f;
1986 Lisp_Object name, old_name;
1987 {
1988 /* Don't change the title if it's already NAME. */
1989 if (EQ (name, f->title))
1990 return;
1991
1992 update_mode_lines = 1;
1993
1994 f->title = name;
1995
1996 if (NILP (name))
1997 name = f->name;
1998
1999 if (FRAME_W32_WINDOW (f))
2000 {
2001 if (STRING_MULTIBYTE (name))
2002 name = ENCODE_SYSTEM (name);
2003
2004 BLOCK_INPUT;
2005 SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
2006 UNBLOCK_INPUT;
2007 }
2008 }
2009
2010
2011 void x_set_scroll_bar_default_width (f)
2012 struct frame *f;
2013 {
2014 int wid = FRAME_COLUMN_WIDTH (f);
2015
2016 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
2017 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
2018 wid - 1) / wid;
2019 }
2020
2021 \f
2022 /* Subroutines of creating a frame. */
2023
2024
2025 /* Return the value of parameter PARAM.
2026
2027 First search ALIST, then Vdefault_frame_alist, then the X defaults
2028 database, using ATTRIBUTE as the attribute name and CLASS as its class.
2029
2030 Convert the resource to the type specified by desired_type.
2031
2032 If no default is specified, return Qunbound. If you call
2033 w32_get_arg, make sure you deal with Qunbound in a reasonable way,
2034 and don't let it get stored in any Lisp-visible variables! */
2035
2036 static Lisp_Object
2037 w32_get_arg (alist, param, attribute, class, type)
2038 Lisp_Object alist, param;
2039 char *attribute;
2040 char *class;
2041 enum resource_types type;
2042 {
2043 return x_get_arg (check_x_display_info (Qnil),
2044 alist, param, attribute, class, type);
2045 }
2046
2047 \f
2048 Cursor
2049 w32_load_cursor (LPCTSTR name)
2050 {
2051 /* Try first to load cursor from application resource. */
2052 Cursor cursor = LoadImage ((HINSTANCE) GetModuleHandle (NULL),
2053 name, IMAGE_CURSOR, 0, 0,
2054 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
2055 if (!cursor)
2056 {
2057 /* Then try to load a shared predefined cursor. */
2058 cursor = LoadImage (NULL, name, IMAGE_CURSOR, 0, 0,
2059 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
2060 }
2061 return cursor;
2062 }
2063
2064 extern LRESULT CALLBACK w32_wnd_proc ();
2065
2066 static BOOL
2067 w32_init_class (hinst)
2068 HINSTANCE hinst;
2069 {
2070 WNDCLASS wc;
2071
2072 wc.style = CS_HREDRAW | CS_VREDRAW;
2073 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
2074 wc.cbClsExtra = 0;
2075 wc.cbWndExtra = WND_EXTRA_BYTES;
2076 wc.hInstance = hinst;
2077 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
2078 wc.hCursor = w32_load_cursor (IDC_ARROW);
2079 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
2080 wc.lpszMenuName = NULL;
2081 wc.lpszClassName = EMACS_CLASS;
2082
2083 return (RegisterClass (&wc));
2084 }
2085
2086 static HWND
2087 w32_createscrollbar (f, bar)
2088 struct frame *f;
2089 struct scroll_bar * bar;
2090 {
2091 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
2092 /* Position and size of scroll bar. */
2093 XINT (bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
2094 XINT (bar->top),
2095 XINT (bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
2096 XINT (bar->height),
2097 FRAME_W32_WINDOW (f),
2098 NULL,
2099 hinst,
2100 NULL));
2101 }
2102
2103 static void
2104 w32_createwindow (f)
2105 struct frame *f;
2106 {
2107 HWND hwnd;
2108 RECT rect;
2109 Lisp_Object top = Qunbound;
2110 Lisp_Object left = Qunbound;
2111
2112 rect.left = rect.top = 0;
2113 rect.right = FRAME_PIXEL_WIDTH (f);
2114 rect.bottom = FRAME_PIXEL_HEIGHT (f);
2115
2116 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
2117 FRAME_EXTERNAL_MENU_BAR (f));
2118
2119 /* Do first time app init */
2120
2121 if (!hprevinst)
2122 {
2123 w32_init_class (hinst);
2124 }
2125
2126 if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition)
2127 {
2128 XSETINT (left, f->left_pos);
2129 XSETINT (top, f->top_pos);
2130 }
2131 else if (EQ (left, Qunbound) && EQ (top, Qunbound))
2132 {
2133 /* When called with RES_TYPE_NUMBER, w32_get_arg will return zero
2134 for anything that is not a number and is not Qunbound. */
2135 left = w32_get_arg (Qnil, Qleft, "left", "Left", RES_TYPE_NUMBER);
2136 top = w32_get_arg (Qnil, Qtop, "top", "Top", RES_TYPE_NUMBER);
2137 }
2138
2139 FRAME_W32_WINDOW (f) = hwnd
2140 = CreateWindow (EMACS_CLASS,
2141 f->namebuf,
2142 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
2143 EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left),
2144 EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top),
2145 rect.right - rect.left,
2146 rect.bottom - rect.top,
2147 NULL,
2148 NULL,
2149 hinst,
2150 NULL);
2151
2152 if (hwnd)
2153 {
2154 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
2155 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
2156 SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
2157 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->scroll_bar_actual_width);
2158 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
2159
2160 /* Enable drag-n-drop. */
2161 DragAcceptFiles (hwnd, TRUE);
2162
2163 /* Do this to discard the default setting specified by our parent. */
2164 ShowWindow (hwnd, SW_HIDE);
2165
2166 /* Update frame positions. */
2167 GetWindowRect (hwnd, &rect);
2168 f->left_pos = rect.left;
2169 f->top_pos = rect.top;
2170 }
2171 }
2172
2173 static void
2174 my_post_msg (wmsg, hwnd, msg, wParam, lParam)
2175 W32Msg * wmsg;
2176 HWND hwnd;
2177 UINT msg;
2178 WPARAM wParam;
2179 LPARAM lParam;
2180 {
2181 wmsg->msg.hwnd = hwnd;
2182 wmsg->msg.message = msg;
2183 wmsg->msg.wParam = wParam;
2184 wmsg->msg.lParam = lParam;
2185 wmsg->msg.time = GetMessageTime ();
2186
2187 post_msg (wmsg);
2188 }
2189
2190 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
2191 between left and right keys as advertised. We test for this
2192 support dynamically, and set a flag when the support is absent. If
2193 absent, we keep track of the left and right control and alt keys
2194 ourselves. This is particularly necessary on keyboards that rely
2195 upon the AltGr key, which is represented as having the left control
2196 and right alt keys pressed. For these keyboards, we need to know
2197 when the left alt key has been pressed in addition to the AltGr key
2198 so that we can properly support M-AltGr-key sequences (such as M-@
2199 on Swedish keyboards). */
2200
2201 #define EMACS_LCONTROL 0
2202 #define EMACS_RCONTROL 1
2203 #define EMACS_LMENU 2
2204 #define EMACS_RMENU 3
2205
2206 static int modifiers[4];
2207 static int modifiers_recorded;
2208 static int modifier_key_support_tested;
2209
2210 static void
2211 test_modifier_support (unsigned int wparam)
2212 {
2213 unsigned int l, r;
2214
2215 if (wparam != VK_CONTROL && wparam != VK_MENU)
2216 return;
2217 if (wparam == VK_CONTROL)
2218 {
2219 l = VK_LCONTROL;
2220 r = VK_RCONTROL;
2221 }
2222 else
2223 {
2224 l = VK_LMENU;
2225 r = VK_RMENU;
2226 }
2227 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
2228 modifiers_recorded = 1;
2229 else
2230 modifiers_recorded = 0;
2231 modifier_key_support_tested = 1;
2232 }
2233
2234 static void
2235 record_keydown (unsigned int wparam, unsigned int lparam)
2236 {
2237 int i;
2238
2239 if (!modifier_key_support_tested)
2240 test_modifier_support (wparam);
2241
2242 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2243 return;
2244
2245 if (wparam == VK_CONTROL)
2246 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2247 else
2248 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2249
2250 modifiers[i] = 1;
2251 }
2252
2253 static void
2254 record_keyup (unsigned int wparam, unsigned int lparam)
2255 {
2256 int i;
2257
2258 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2259 return;
2260
2261 if (wparam == VK_CONTROL)
2262 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2263 else
2264 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2265
2266 modifiers[i] = 0;
2267 }
2268
2269 /* Emacs can lose focus while a modifier key has been pressed. When
2270 it regains focus, be conservative and clear all modifiers since
2271 we cannot reconstruct the left and right modifier state. */
2272 static void
2273 reset_modifiers ()
2274 {
2275 SHORT ctrl, alt;
2276
2277 if (GetFocus () == NULL)
2278 /* Emacs doesn't have keyboard focus. Do nothing. */
2279 return;
2280
2281 ctrl = GetAsyncKeyState (VK_CONTROL);
2282 alt = GetAsyncKeyState (VK_MENU);
2283
2284 if (!(ctrl & 0x08000))
2285 /* Clear any recorded control modifier state. */
2286 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2287
2288 if (!(alt & 0x08000))
2289 /* Clear any recorded alt modifier state. */
2290 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2291
2292 /* Update the state of all modifier keys, because modifiers used in
2293 hot-key combinations can get stuck on if Emacs loses focus as a
2294 result of a hot-key being pressed. */
2295 {
2296 BYTE keystate[256];
2297
2298 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
2299
2300 GetKeyboardState (keystate);
2301 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
2302 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
2303 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
2304 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
2305 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
2306 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
2307 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
2308 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
2309 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
2310 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
2311 SetKeyboardState (keystate);
2312 }
2313 }
2314
2315 /* Synchronize modifier state with what is reported with the current
2316 keystroke. Even if we cannot distinguish between left and right
2317 modifier keys, we know that, if no modifiers are set, then neither
2318 the left or right modifier should be set. */
2319 static void
2320 sync_modifiers ()
2321 {
2322 if (!modifiers_recorded)
2323 return;
2324
2325 if (!(GetKeyState (VK_CONTROL) & 0x8000))
2326 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2327
2328 if (!(GetKeyState (VK_MENU) & 0x8000))
2329 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2330 }
2331
2332 static int
2333 modifier_set (int vkey)
2334 {
2335 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
2336 return (GetKeyState (vkey) & 0x1);
2337 if (!modifiers_recorded)
2338 return (GetKeyState (vkey) & 0x8000);
2339
2340 switch (vkey)
2341 {
2342 case VK_LCONTROL:
2343 return modifiers[EMACS_LCONTROL];
2344 case VK_RCONTROL:
2345 return modifiers[EMACS_RCONTROL];
2346 case VK_LMENU:
2347 return modifiers[EMACS_LMENU];
2348 case VK_RMENU:
2349 return modifiers[EMACS_RMENU];
2350 }
2351 return (GetKeyState (vkey) & 0x8000);
2352 }
2353
2354 /* Convert between the modifier bits W32 uses and the modifier bits
2355 Emacs uses. */
2356
2357 unsigned int
2358 w32_key_to_modifier (int key)
2359 {
2360 Lisp_Object key_mapping;
2361
2362 switch (key)
2363 {
2364 case VK_LWIN:
2365 key_mapping = Vw32_lwindow_modifier;
2366 break;
2367 case VK_RWIN:
2368 key_mapping = Vw32_rwindow_modifier;
2369 break;
2370 case VK_APPS:
2371 key_mapping = Vw32_apps_modifier;
2372 break;
2373 case VK_SCROLL:
2374 key_mapping = Vw32_scroll_lock_modifier;
2375 break;
2376 default:
2377 key_mapping = Qnil;
2378 }
2379
2380 /* NB. This code runs in the input thread, asychronously to the lisp
2381 thread, so we must be careful to ensure access to lisp data is
2382 thread-safe. The following code is safe because the modifier
2383 variable values are updated atomically from lisp and symbols are
2384 not relocated by GC. Also, we don't have to worry about seeing GC
2385 markbits here. */
2386 if (EQ (key_mapping, Qhyper))
2387 return hyper_modifier;
2388 if (EQ (key_mapping, Qsuper))
2389 return super_modifier;
2390 if (EQ (key_mapping, Qmeta))
2391 return meta_modifier;
2392 if (EQ (key_mapping, Qalt))
2393 return alt_modifier;
2394 if (EQ (key_mapping, Qctrl))
2395 return ctrl_modifier;
2396 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
2397 return ctrl_modifier;
2398 if (EQ (key_mapping, Qshift))
2399 return shift_modifier;
2400
2401 /* Don't generate any modifier if not explicitly requested. */
2402 return 0;
2403 }
2404
2405 static unsigned int
2406 w32_get_modifiers ()
2407 {
2408 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
2409 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
2410 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
2411 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
2412 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
2413 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
2414 (modifier_set (VK_MENU) ?
2415 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
2416 }
2417
2418 /* We map the VK_* modifiers into console modifier constants
2419 so that we can use the same routines to handle both console
2420 and window input. */
2421
2422 static int
2423 construct_console_modifiers ()
2424 {
2425 int mods;
2426
2427 mods = 0;
2428 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
2429 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
2430 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
2431 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
2432 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
2433 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
2434 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
2435 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
2436 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
2437 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
2438 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
2439
2440 return mods;
2441 }
2442
2443 static int
2444 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
2445 {
2446 int mods;
2447
2448 /* Convert to emacs modifiers. */
2449 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
2450
2451 return mods;
2452 }
2453
2454 unsigned int
2455 map_keypad_keys (unsigned int virt_key, unsigned int extended)
2456 {
2457 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
2458 return virt_key;
2459
2460 if (virt_key == VK_RETURN)
2461 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
2462
2463 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
2464 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
2465
2466 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
2467 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
2468
2469 if (virt_key == VK_CLEAR)
2470 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
2471
2472 return virt_key;
2473 }
2474
2475 /* List of special key combinations which w32 would normally capture,
2476 but Emacs should grab instead. Not directly visible to lisp, to
2477 simplify synchronization. Each item is an integer encoding a virtual
2478 key code and modifier combination to capture. */
2479 static Lisp_Object w32_grabbed_keys;
2480
2481 #define HOTKEY(vk, mods) make_number (((vk) & 255) | ((mods) << 8))
2482 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
2483 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
2484 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
2485
2486 #define RAW_HOTKEY_ID(k) ((k) & 0xbfff)
2487 #define RAW_HOTKEY_VK_CODE(k) ((k) & 255)
2488 #define RAW_HOTKEY_MODIFIERS(k) ((k) >> 8)
2489
2490 /* Register hot-keys for reserved key combinations when Emacs has
2491 keyboard focus, since this is the only way Emacs can receive key
2492 combinations like Alt-Tab which are used by the system. */
2493
2494 static void
2495 register_hot_keys (hwnd)
2496 HWND hwnd;
2497 {
2498 Lisp_Object keylist;
2499
2500 /* Use CONSP, since we are called asynchronously. */
2501 for (keylist = w32_grabbed_keys; CONSP (keylist); keylist = XCDR (keylist))
2502 {
2503 Lisp_Object key = XCAR (keylist);
2504
2505 /* Deleted entries get set to nil. */
2506 if (!INTEGERP (key))
2507 continue;
2508
2509 RegisterHotKey (hwnd, HOTKEY_ID (key),
2510 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
2511 }
2512 }
2513
2514 static void
2515 unregister_hot_keys (hwnd)
2516 HWND hwnd;
2517 {
2518 Lisp_Object keylist;
2519
2520 for (keylist = w32_grabbed_keys; CONSP (keylist); keylist = XCDR (keylist))
2521 {
2522 Lisp_Object key = XCAR (keylist);
2523
2524 if (!INTEGERP (key))
2525 continue;
2526
2527 UnregisterHotKey (hwnd, HOTKEY_ID (key));
2528 }
2529 }
2530
2531 /* Main message dispatch loop. */
2532
2533 static void
2534 w32_msg_pump (deferred_msg * msg_buf)
2535 {
2536 MSG msg;
2537 int result;
2538 HWND focus_window;
2539
2540 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
2541
2542 while (GetMessage (&msg, NULL, 0, 0))
2543 {
2544 if (msg.hwnd == NULL)
2545 {
2546 switch (msg.message)
2547 {
2548 case WM_NULL:
2549 /* Produced by complete_deferred_msg; just ignore. */
2550 break;
2551 case WM_EMACS_CREATEWINDOW:
2552 /* Initialize COM for this window. Even though we don't use it,
2553 some third party shell extensions can cause it to be used in
2554 system dialogs, which causes a crash if it is not initialized.
2555 This is a known bug in Windows, which was fixed long ago, but
2556 the patch for XP is not publically available until XP SP3,
2557 and older versions will never be patched. */
2558 CoInitialize (NULL);
2559 w32_createwindow ((struct frame *) msg.wParam);
2560 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2561 abort ();
2562 break;
2563 case WM_EMACS_SETLOCALE:
2564 SetThreadLocale (msg.wParam);
2565 /* Reply is not expected. */
2566 break;
2567 case WM_EMACS_SETKEYBOARDLAYOUT:
2568 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
2569 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2570 result, 0))
2571 abort ();
2572 break;
2573 case WM_EMACS_REGISTER_HOT_KEY:
2574 focus_window = GetFocus ();
2575 if (focus_window != NULL)
2576 RegisterHotKey (focus_window,
2577 RAW_HOTKEY_ID (msg.wParam),
2578 RAW_HOTKEY_MODIFIERS (msg.wParam),
2579 RAW_HOTKEY_VK_CODE (msg.wParam));
2580 /* Reply is not expected. */
2581 break;
2582 case WM_EMACS_UNREGISTER_HOT_KEY:
2583 focus_window = GetFocus ();
2584 if (focus_window != NULL)
2585 UnregisterHotKey (focus_window, RAW_HOTKEY_ID (msg.wParam));
2586 /* Mark item as erased. NB: this code must be
2587 thread-safe. The next line is okay because the cons
2588 cell is never made into garbage and is not relocated by
2589 GC. */
2590 XSETCAR ((Lisp_Object) ((EMACS_INT) msg.lParam), Qnil);
2591 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2592 abort ();
2593 break;
2594 case WM_EMACS_TOGGLE_LOCK_KEY:
2595 {
2596 int vk_code = (int) msg.wParam;
2597 int cur_state = (GetKeyState (vk_code) & 1);
2598 Lisp_Object new_state = (Lisp_Object) ((EMACS_INT) msg.lParam);
2599
2600 /* NB: This code must be thread-safe. It is safe to
2601 call NILP because symbols are not relocated by GC,
2602 and pointer here is not touched by GC (so the markbit
2603 can't be set). Numbers are safe because they are
2604 immediate values. */
2605 if (NILP (new_state)
2606 || (NUMBERP (new_state)
2607 && ((XUINT (new_state)) & 1) != cur_state))
2608 {
2609 one_w32_display_info.faked_key = vk_code;
2610
2611 keybd_event ((BYTE) vk_code,
2612 (BYTE) MapVirtualKey (vk_code, 0),
2613 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2614 keybd_event ((BYTE) vk_code,
2615 (BYTE) MapVirtualKey (vk_code, 0),
2616 KEYEVENTF_EXTENDEDKEY | 0, 0);
2617 keybd_event ((BYTE) vk_code,
2618 (BYTE) MapVirtualKey (vk_code, 0),
2619 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2620 cur_state = !cur_state;
2621 }
2622 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2623 cur_state, 0))
2624 abort ();
2625 }
2626 break;
2627 #ifdef MSG_DEBUG
2628 /* Broadcast messages make it here, so you need to be looking
2629 for something in particular for this to be useful. */
2630 default:
2631 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
2632 #endif
2633 }
2634 }
2635 else
2636 {
2637 DispatchMessage (&msg);
2638 }
2639
2640 /* Exit nested loop when our deferred message has completed. */
2641 if (msg_buf->completed)
2642 break;
2643 }
2644 }
2645
2646 deferred_msg * deferred_msg_head;
2647
2648 static deferred_msg *
2649 find_deferred_msg (HWND hwnd, UINT msg)
2650 {
2651 deferred_msg * item;
2652
2653 /* Don't actually need synchronization for read access, since
2654 modification of single pointer is always atomic. */
2655 /* enter_crit (); */
2656
2657 for (item = deferred_msg_head; item != NULL; item = item->next)
2658 if (item->w32msg.msg.hwnd == hwnd
2659 && item->w32msg.msg.message == msg)
2660 break;
2661
2662 /* leave_crit (); */
2663
2664 return item;
2665 }
2666
2667 static LRESULT
2668 send_deferred_msg (deferred_msg * msg_buf,
2669 HWND hwnd,
2670 UINT msg,
2671 WPARAM wParam,
2672 LPARAM lParam)
2673 {
2674 /* Only input thread can send deferred messages. */
2675 if (GetCurrentThreadId () != dwWindowsThreadId)
2676 abort ();
2677
2678 /* It is an error to send a message that is already deferred. */
2679 if (find_deferred_msg (hwnd, msg) != NULL)
2680 abort ();
2681
2682 /* Enforced synchronization is not needed because this is the only
2683 function that alters deferred_msg_head, and the following critical
2684 section is guaranteed to only be serially reentered (since only the
2685 input thread can call us). */
2686
2687 /* enter_crit (); */
2688
2689 msg_buf->completed = 0;
2690 msg_buf->next = deferred_msg_head;
2691 deferred_msg_head = msg_buf;
2692 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
2693
2694 /* leave_crit (); */
2695
2696 /* Start a new nested message loop to process other messages until
2697 this one is completed. */
2698 w32_msg_pump (msg_buf);
2699
2700 deferred_msg_head = msg_buf->next;
2701
2702 return msg_buf->result;
2703 }
2704
2705 void
2706 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
2707 {
2708 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
2709
2710 if (msg_buf == NULL)
2711 /* Message may have been cancelled, so don't abort. */
2712 return;
2713
2714 msg_buf->result = result;
2715 msg_buf->completed = 1;
2716
2717 /* Ensure input thread is woken so it notices the completion. */
2718 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2719 }
2720
2721 static void
2722 cancel_all_deferred_msgs ()
2723 {
2724 deferred_msg * item;
2725
2726 /* Don't actually need synchronization for read access, since
2727 modification of single pointer is always atomic. */
2728 /* enter_crit (); */
2729
2730 for (item = deferred_msg_head; item != NULL; item = item->next)
2731 {
2732 item->result = 0;
2733 item->completed = 1;
2734 }
2735
2736 /* leave_crit (); */
2737
2738 /* Ensure input thread is woken so it notices the completion. */
2739 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2740 }
2741
2742 DWORD WINAPI
2743 w32_msg_worker (void *arg)
2744 {
2745 MSG msg;
2746 deferred_msg dummy_buf;
2747
2748 /* Ensure our message queue is created */
2749
2750 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
2751
2752 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2753 abort ();
2754
2755 memset (&dummy_buf, 0, sizeof (dummy_buf));
2756 dummy_buf.w32msg.msg.hwnd = NULL;
2757 dummy_buf.w32msg.msg.message = WM_NULL;
2758
2759 /* This is the initial message loop which should only exit when the
2760 application quits. */
2761 w32_msg_pump (&dummy_buf);
2762
2763 return 0;
2764 }
2765
2766 static void
2767 signal_user_input ()
2768 {
2769 /* Interrupt any lisp that wants to be interrupted by input. */
2770 if (!NILP (Vthrow_on_input))
2771 {
2772 Vquit_flag = Vthrow_on_input;
2773 /* If we're inside a function that wants immediate quits,
2774 do it now. */
2775 if (immediate_quit && NILP (Vinhibit_quit))
2776 {
2777 immediate_quit = 0;
2778 QUIT;
2779 }
2780 }
2781 }
2782
2783
2784 static void
2785 post_character_message (hwnd, msg, wParam, lParam, modifiers)
2786 HWND hwnd;
2787 UINT msg;
2788 WPARAM wParam;
2789 LPARAM lParam;
2790 DWORD modifiers;
2791
2792 {
2793 W32Msg wmsg;
2794
2795 wmsg.dwModifiers = modifiers;
2796
2797 /* Detect quit_char and set quit-flag directly. Note that we
2798 still need to post a message to ensure the main thread will be
2799 woken up if blocked in sys_select, but we do NOT want to post
2800 the quit_char message itself (because it will usually be as if
2801 the user had typed quit_char twice). Instead, we post a dummy
2802 message that has no particular effect. */
2803 {
2804 int c = wParam;
2805 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
2806 c = make_ctrl_char (c) & 0377;
2807 if (c == quit_char
2808 || (wmsg.dwModifiers == 0 &&
2809 w32_quit_key && wParam == w32_quit_key))
2810 {
2811 Vquit_flag = Qt;
2812
2813 /* The choice of message is somewhat arbitrary, as long as
2814 the main thread handler just ignores it. */
2815 msg = WM_NULL;
2816
2817 /* Interrupt any blocking system calls. */
2818 signal_quit ();
2819
2820 /* As a safety precaution, forcibly complete any deferred
2821 messages. This is a kludge, but I don't see any particularly
2822 clean way to handle the situation where a deferred message is
2823 "dropped" in the lisp thread, and will thus never be
2824 completed, eg. by the user trying to activate the menubar
2825 when the lisp thread is busy, and then typing C-g when the
2826 menubar doesn't open promptly (with the result that the
2827 menubar never responds at all because the deferred
2828 WM_INITMENU message is never completed). Another problem
2829 situation is when the lisp thread calls SendMessage (to send
2830 a window manager command) when a message has been deferred;
2831 the lisp thread gets blocked indefinitely waiting for the
2832 deferred message to be completed, which itself is waiting for
2833 the lisp thread to respond.
2834
2835 Note that we don't want to block the input thread waiting for
2836 a reponse from the lisp thread (although that would at least
2837 solve the deadlock problem above), because we want to be able
2838 to receive C-g to interrupt the lisp thread. */
2839 cancel_all_deferred_msgs ();
2840 }
2841 else
2842 signal_user_input ();
2843 }
2844
2845 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2846 }
2847
2848 /* Main window procedure */
2849
2850 LRESULT CALLBACK
2851 w32_wnd_proc (hwnd, msg, wParam, lParam)
2852 HWND hwnd;
2853 UINT msg;
2854 WPARAM wParam;
2855 LPARAM lParam;
2856 {
2857 struct frame *f;
2858 struct w32_display_info *dpyinfo = &one_w32_display_info;
2859 W32Msg wmsg;
2860 int windows_translate;
2861 int key;
2862
2863 /* Note that it is okay to call x_window_to_frame, even though we are
2864 not running in the main lisp thread, because frame deletion
2865 requires the lisp thread to synchronize with this thread. Thus, if
2866 a frame struct is returned, it can be used without concern that the
2867 lisp thread might make it disappear while we are using it.
2868
2869 NB. Walking the frame list in this thread is safe (as long as
2870 writes of Lisp_Object slots are atomic, which they are on Windows).
2871 Although delete-frame can destructively modify the frame list while
2872 we are walking it, a garbage collection cannot occur until after
2873 delete-frame has synchronized with this thread.
2874
2875 It is also safe to use functions that make GDI calls, such as
2876 w32_clear_rect, because these functions must obtain a DC handle
2877 from the frame struct using get_frame_dc which is thread-aware. */
2878
2879 switch (msg)
2880 {
2881 case WM_ERASEBKGND:
2882 f = x_window_to_frame (dpyinfo, hwnd);
2883 if (f)
2884 {
2885 HDC hdc = get_frame_dc (f);
2886 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
2887 w32_clear_rect (f, hdc, &wmsg.rect);
2888 release_frame_dc (f, hdc);
2889
2890 #if defined (W32_DEBUG_DISPLAY)
2891 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
2892 f,
2893 wmsg.rect.left, wmsg.rect.top,
2894 wmsg.rect.right, wmsg.rect.bottom));
2895 #endif /* W32_DEBUG_DISPLAY */
2896 }
2897 return 1;
2898 case WM_PALETTECHANGED:
2899 /* ignore our own changes */
2900 if ((HWND)wParam != hwnd)
2901 {
2902 f = x_window_to_frame (dpyinfo, hwnd);
2903 if (f)
2904 /* get_frame_dc will realize our palette and force all
2905 frames to be redrawn if needed. */
2906 release_frame_dc (f, get_frame_dc (f));
2907 }
2908 return 0;
2909 case WM_PAINT:
2910 {
2911 PAINTSTRUCT paintStruct;
2912 RECT update_rect;
2913 bzero (&update_rect, sizeof (update_rect));
2914
2915 f = x_window_to_frame (dpyinfo, hwnd);
2916 if (f == 0)
2917 {
2918 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
2919 return 0;
2920 }
2921
2922 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
2923 fails. Apparently this can happen under some
2924 circumstances. */
2925 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
2926 {
2927 enter_crit ();
2928 BeginPaint (hwnd, &paintStruct);
2929
2930 /* The rectangles returned by GetUpdateRect and BeginPaint
2931 do not always match. Play it safe by assuming both areas
2932 are invalid. */
2933 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
2934
2935 #if defined (W32_DEBUG_DISPLAY)
2936 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
2937 f,
2938 wmsg.rect.left, wmsg.rect.top,
2939 wmsg.rect.right, wmsg.rect.bottom));
2940 DebPrint ((" [update region is %d,%d-%d,%d]\n",
2941 update_rect.left, update_rect.top,
2942 update_rect.right, update_rect.bottom));
2943 #endif
2944 EndPaint (hwnd, &paintStruct);
2945 leave_crit ();
2946
2947 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2948
2949 return 0;
2950 }
2951
2952 /* If GetUpdateRect returns 0 (meaning there is no update
2953 region), assume the whole window needs to be repainted. */
2954 GetClientRect (hwnd, &wmsg.rect);
2955 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2956 return 0;
2957 }
2958
2959 case WM_INPUTLANGCHANGE:
2960 /* Inform lisp thread of keyboard layout changes. */
2961 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2962
2963 /* Clear dead keys in the keyboard state; for simplicity only
2964 preserve modifier key states. */
2965 {
2966 int i;
2967 BYTE keystate[256];
2968
2969 GetKeyboardState (keystate);
2970 for (i = 0; i < 256; i++)
2971 if (1
2972 && i != VK_SHIFT
2973 && i != VK_LSHIFT
2974 && i != VK_RSHIFT
2975 && i != VK_CAPITAL
2976 && i != VK_NUMLOCK
2977 && i != VK_SCROLL
2978 && i != VK_CONTROL
2979 && i != VK_LCONTROL
2980 && i != VK_RCONTROL
2981 && i != VK_MENU
2982 && i != VK_LMENU
2983 && i != VK_RMENU
2984 && i != VK_LWIN
2985 && i != VK_RWIN)
2986 keystate[i] = 0;
2987 SetKeyboardState (keystate);
2988 }
2989 goto dflt;
2990
2991 case WM_HOTKEY:
2992 /* Synchronize hot keys with normal input. */
2993 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
2994 return (0);
2995
2996 case WM_KEYUP:
2997 case WM_SYSKEYUP:
2998 record_keyup (wParam, lParam);
2999 goto dflt;
3000
3001 case WM_KEYDOWN:
3002 case WM_SYSKEYDOWN:
3003 /* Ignore keystrokes we fake ourself; see below. */
3004 if (dpyinfo->faked_key == wParam)
3005 {
3006 dpyinfo->faked_key = 0;
3007 /* Make sure TranslateMessage sees them though (as long as
3008 they don't produce WM_CHAR messages). This ensures that
3009 indicator lights are toggled promptly on Windows 9x, for
3010 example. */
3011 if (wParam < 256 && lispy_function_keys[wParam])
3012 {
3013 windows_translate = 1;
3014 goto translate;
3015 }
3016 return 0;
3017 }
3018
3019 /* Synchronize modifiers with current keystroke. */
3020 sync_modifiers ();
3021 record_keydown (wParam, lParam);
3022 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
3023
3024 windows_translate = 0;
3025
3026 switch (wParam)
3027 {
3028 case VK_LWIN:
3029 if (NILP (Vw32_pass_lwindow_to_system))
3030 {
3031 /* Prevent system from acting on keyup (which opens the
3032 Start menu if no other key was pressed) by simulating a
3033 press of Space which we will ignore. */
3034 if (GetAsyncKeyState (wParam) & 1)
3035 {
3036 if (NUMBERP (Vw32_phantom_key_code))
3037 key = XUINT (Vw32_phantom_key_code) & 255;
3038 else
3039 key = VK_SPACE;
3040 dpyinfo->faked_key = key;
3041 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
3042 }
3043 }
3044 if (!NILP (Vw32_lwindow_modifier))
3045 return 0;
3046 break;
3047 case VK_RWIN:
3048 if (NILP (Vw32_pass_rwindow_to_system))
3049 {
3050 if (GetAsyncKeyState (wParam) & 1)
3051 {
3052 if (NUMBERP (Vw32_phantom_key_code))
3053 key = XUINT (Vw32_phantom_key_code) & 255;
3054 else
3055 key = VK_SPACE;
3056 dpyinfo->faked_key = key;
3057 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
3058 }
3059 }
3060 if (!NILP (Vw32_rwindow_modifier))
3061 return 0;
3062 break;
3063 case VK_APPS:
3064 if (!NILP (Vw32_apps_modifier))
3065 return 0;
3066 break;
3067 case VK_MENU:
3068 if (NILP (Vw32_pass_alt_to_system))
3069 /* Prevent DefWindowProc from activating the menu bar if an
3070 Alt key is pressed and released by itself. */
3071 return 0;
3072 windows_translate = 1;
3073 break;
3074 case VK_CAPITAL:
3075 /* Decide whether to treat as modifier or function key. */
3076 if (NILP (Vw32_enable_caps_lock))
3077 goto disable_lock_key;
3078 windows_translate = 1;
3079 break;
3080 case VK_NUMLOCK:
3081 /* Decide whether to treat as modifier or function key. */
3082 if (NILP (Vw32_enable_num_lock))
3083 goto disable_lock_key;
3084 windows_translate = 1;
3085 break;
3086 case VK_SCROLL:
3087 /* Decide whether to treat as modifier or function key. */
3088 if (NILP (Vw32_scroll_lock_modifier))
3089 goto disable_lock_key;
3090 windows_translate = 1;
3091 break;
3092 disable_lock_key:
3093 /* Ensure the appropriate lock key state (and indicator light)
3094 remains in the same state. We do this by faking another
3095 press of the relevant key. Apparently, this really is the
3096 only way to toggle the state of the indicator lights. */
3097 dpyinfo->faked_key = wParam;
3098 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3099 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3100 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3101 KEYEVENTF_EXTENDEDKEY | 0, 0);
3102 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
3103 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
3104 /* Ensure indicator lights are updated promptly on Windows 9x
3105 (TranslateMessage apparently does this), after forwarding
3106 input event. */
3107 post_character_message (hwnd, msg, wParam, lParam,
3108 w32_get_key_modifiers (wParam, lParam));
3109 windows_translate = 1;
3110 break;
3111 case VK_CONTROL:
3112 case VK_SHIFT:
3113 case VK_PROCESSKEY: /* Generated by IME. */
3114 windows_translate = 1;
3115 break;
3116 case VK_CANCEL:
3117 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
3118 which is confusing for purposes of key binding; convert
3119 VK_CANCEL events into VK_PAUSE events. */
3120 wParam = VK_PAUSE;
3121 break;
3122 case VK_PAUSE:
3123 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
3124 for purposes of key binding; convert these back into
3125 VK_NUMLOCK events, at least when we want to see NumLock key
3126 presses. (Note that there is never any possibility that
3127 VK_PAUSE with Ctrl really is C-Pause as per above.) */
3128 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
3129 wParam = VK_NUMLOCK;
3130 break;
3131 default:
3132 /* If not defined as a function key, change it to a WM_CHAR message. */
3133 if (wParam > 255 || !lispy_function_keys[wParam])
3134 {
3135 DWORD modifiers = construct_console_modifiers ();
3136
3137 if (!NILP (Vw32_recognize_altgr)
3138 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
3139 {
3140 /* Always let TranslateMessage handle AltGr key chords;
3141 for some reason, ToAscii doesn't always process AltGr
3142 chords correctly. */
3143 windows_translate = 1;
3144 }
3145 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
3146 {
3147 /* Handle key chords including any modifiers other
3148 than shift directly, in order to preserve as much
3149 modifier information as possible. */
3150 if ('A' <= wParam && wParam <= 'Z')
3151 {
3152 /* Don't translate modified alphabetic keystrokes,
3153 so the user doesn't need to constantly switch
3154 layout to type control or meta keystrokes when
3155 the normal layout translates alphabetic
3156 characters to non-ascii characters. */
3157 if (!modifier_set (VK_SHIFT))
3158 wParam += ('a' - 'A');
3159 msg = WM_CHAR;
3160 }
3161 else
3162 {
3163 /* Try to handle other keystrokes by determining the
3164 base character (ie. translating the base key plus
3165 shift modifier). */
3166 int add;
3167 int isdead = 0;
3168 KEY_EVENT_RECORD key;
3169
3170 key.bKeyDown = TRUE;
3171 key.wRepeatCount = 1;
3172 key.wVirtualKeyCode = wParam;
3173 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
3174 key.uChar.AsciiChar = 0;
3175 key.dwControlKeyState = modifiers;
3176
3177 add = w32_kbd_patch_key (&key);
3178 /* 0 means an unrecognised keycode, negative means
3179 dead key. Ignore both. */
3180 while (--add >= 0)
3181 {
3182 /* Forward asciified character sequence. */
3183 post_character_message
3184 (hwnd, WM_CHAR,
3185 (unsigned char) key.uChar.AsciiChar, lParam,
3186 w32_get_key_modifiers (wParam, lParam));
3187 w32_kbd_patch_key (&key);
3188 }
3189 return 0;
3190 }
3191 }
3192 else
3193 {
3194 /* Let TranslateMessage handle everything else. */
3195 windows_translate = 1;
3196 }
3197 }
3198 }
3199
3200 translate:
3201 if (windows_translate)
3202 {
3203 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
3204 windows_msg.time = GetMessageTime ();
3205 TranslateMessage (&windows_msg);
3206 goto dflt;
3207 }
3208
3209 /* Fall through */
3210
3211 case WM_SYSCHAR:
3212 case WM_CHAR:
3213 post_character_message (hwnd, msg, wParam, lParam,
3214 w32_get_key_modifiers (wParam, lParam));
3215 break;
3216
3217 case WM_UNICHAR:
3218 /* WM_UNICHAR looks promising from the docs, but the exact
3219 circumstances in which TranslateMessage sends it is one of those
3220 Microsoft secret API things that EU and US courts are supposed
3221 to have put a stop to already. Spy++ shows it being sent to Notepad
3222 and other MS apps, but never to Emacs.
3223
3224 Some third party IMEs send it in accordance with the official
3225 documentation though, so handle it here.
3226
3227 UNICODE_NOCHAR is used to test for support for this message.
3228 TRUE indicates that the message is supported. */
3229 if (wParam == UNICODE_NOCHAR)
3230 return TRUE;
3231
3232 {
3233 W32Msg wmsg;
3234 wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam);
3235 signal_user_input ();
3236 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3237 }
3238 break;
3239
3240 case WM_IME_CHAR:
3241 /* If we can't get the IME result as unicode, use default processing,
3242 which will at least allow characters decodable in the system locale
3243 get through. */
3244 if (!get_composition_string_fn)
3245 goto dflt;
3246
3247 else if (!ignore_ime_char)
3248 {
3249 wchar_t * buffer;
3250 int size, i;
3251 W32Msg wmsg;
3252 HIMC context = get_ime_context_fn (hwnd);
3253 wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam);
3254 /* Get buffer size. */
3255 size = get_composition_string_fn (context, GCS_RESULTSTR, buffer, 0);
3256 buffer = alloca(size);
3257 size = get_composition_string_fn (context, GCS_RESULTSTR,
3258 buffer, size);
3259 signal_user_input ();
3260 for (i = 0; i < size / sizeof (wchar_t); i++)
3261 {
3262 my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i],
3263 lParam);
3264 }
3265 /* We output the whole string above, so ignore following ones
3266 until we are notified of the end of composition. */
3267 ignore_ime_char = 1;
3268 }
3269 break;
3270
3271 case WM_IME_ENDCOMPOSITION:
3272 ignore_ime_char = 0;
3273 goto dflt;
3274
3275 /* Simulate middle mouse button events when left and right buttons
3276 are used together, but only if user has two button mouse. */
3277 case WM_LBUTTONDOWN:
3278 case WM_RBUTTONDOWN:
3279 if (w32_num_mouse_buttons > 2)
3280 goto handle_plain_button;
3281
3282 {
3283 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
3284 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
3285
3286 if (button_state & this)
3287 return 0;
3288
3289 if (button_state == 0)
3290 SetCapture (hwnd);
3291
3292 button_state |= this;
3293
3294 if (button_state & other)
3295 {
3296 if (mouse_button_timer)
3297 {
3298 KillTimer (hwnd, mouse_button_timer);
3299 mouse_button_timer = 0;
3300
3301 /* Generate middle mouse event instead. */
3302 msg = WM_MBUTTONDOWN;
3303 button_state |= MMOUSE;
3304 }
3305 else if (button_state & MMOUSE)
3306 {
3307 /* Ignore button event if we've already generated a
3308 middle mouse down event. This happens if the
3309 user releases and press one of the two buttons
3310 after we've faked a middle mouse event. */
3311 return 0;
3312 }
3313 else
3314 {
3315 /* Flush out saved message. */
3316 post_msg (&saved_mouse_button_msg);
3317 }
3318 wmsg.dwModifiers = w32_get_modifiers ();
3319 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3320 signal_user_input ();
3321
3322 /* Clear message buffer. */
3323 saved_mouse_button_msg.msg.hwnd = 0;
3324 }
3325 else
3326 {
3327 /* Hold onto message for now. */
3328 mouse_button_timer =
3329 SetTimer (hwnd, MOUSE_BUTTON_ID,
3330 w32_mouse_button_tolerance, NULL);
3331 saved_mouse_button_msg.msg.hwnd = hwnd;
3332 saved_mouse_button_msg.msg.message = msg;
3333 saved_mouse_button_msg.msg.wParam = wParam;
3334 saved_mouse_button_msg.msg.lParam = lParam;
3335 saved_mouse_button_msg.msg.time = GetMessageTime ();
3336 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
3337 }
3338 }
3339 return 0;
3340
3341 case WM_LBUTTONUP:
3342 case WM_RBUTTONUP:
3343 if (w32_num_mouse_buttons > 2)
3344 goto handle_plain_button;
3345
3346 {
3347 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
3348 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
3349
3350 if ((button_state & this) == 0)
3351 return 0;
3352
3353 button_state &= ~this;
3354
3355 if (button_state & MMOUSE)
3356 {
3357 /* Only generate event when second button is released. */
3358 if ((button_state & other) == 0)
3359 {
3360 msg = WM_MBUTTONUP;
3361 button_state &= ~MMOUSE;
3362
3363 if (button_state) abort ();
3364 }
3365 else
3366 return 0;
3367 }
3368 else
3369 {
3370 /* Flush out saved message if necessary. */
3371 if (saved_mouse_button_msg.msg.hwnd)
3372 {
3373 post_msg (&saved_mouse_button_msg);
3374 }
3375 }
3376 wmsg.dwModifiers = w32_get_modifiers ();
3377 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3378 signal_user_input ();
3379
3380 /* Always clear message buffer and cancel timer. */
3381 saved_mouse_button_msg.msg.hwnd = 0;
3382 KillTimer (hwnd, mouse_button_timer);
3383 mouse_button_timer = 0;
3384
3385 if (button_state == 0)
3386 ReleaseCapture ();
3387 }
3388 return 0;
3389
3390 case WM_XBUTTONDOWN:
3391 case WM_XBUTTONUP:
3392 if (w32_pass_extra_mouse_buttons_to_system)
3393 goto dflt;
3394 /* else fall through and process them. */
3395 case WM_MBUTTONDOWN:
3396 case WM_MBUTTONUP:
3397 handle_plain_button:
3398 {
3399 BOOL up;
3400 int button;
3401
3402 /* Ignore middle and extra buttons as long as the menu is active. */
3403 f = x_window_to_frame (dpyinfo, hwnd);
3404 if (f && f->output_data.w32->menubar_active)
3405 return 0;
3406
3407 if (parse_button (msg, HIWORD (wParam), &button, &up))
3408 {
3409 if (up) ReleaseCapture ();
3410 else SetCapture (hwnd);
3411 button = (button == 0) ? LMOUSE :
3412 ((button == 1) ? MMOUSE : RMOUSE);
3413 if (up)
3414 button_state &= ~button;
3415 else
3416 button_state |= button;
3417 }
3418 }
3419
3420 wmsg.dwModifiers = w32_get_modifiers ();
3421 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3422 signal_user_input ();
3423
3424 /* Need to return true for XBUTTON messages, false for others,
3425 to indicate that we processed the message. */
3426 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
3427
3428 case WM_MOUSEMOVE:
3429 /* Ignore mouse movements as long as the menu is active. These
3430 movements are processed by the window manager anyway, and
3431 it's wrong to handle them as if they happened on the
3432 underlying frame. */
3433 f = x_window_to_frame (dpyinfo, hwnd);
3434 if (f && f->output_data.w32->menubar_active)
3435 return 0;
3436
3437 /* If the mouse has just moved into the frame, start tracking
3438 it, so we will be notified when it leaves the frame. Mouse
3439 tracking only works under W98 and NT4 and later. On earlier
3440 versions, there is no way of telling when the mouse leaves the
3441 frame, so we just have to put up with help-echo and mouse
3442 highlighting remaining while the frame is not active. */
3443 if (track_mouse_event_fn && !track_mouse_window)
3444 {
3445 TRACKMOUSEEVENT tme;
3446 tme.cbSize = sizeof (tme);
3447 tme.dwFlags = TME_LEAVE;
3448 tme.hwndTrack = hwnd;
3449
3450 track_mouse_event_fn (&tme);
3451 track_mouse_window = hwnd;
3452 }
3453 case WM_VSCROLL:
3454 if (w32_mouse_move_interval <= 0
3455 || (msg == WM_MOUSEMOVE && button_state == 0))
3456 {
3457 wmsg.dwModifiers = w32_get_modifiers ();
3458 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3459 return 0;
3460 }
3461
3462 /* Hang onto mouse move and scroll messages for a bit, to avoid
3463 sending such events to Emacs faster than it can process them.
3464 If we get more events before the timer from the first message
3465 expires, we just replace the first message. */
3466
3467 if (saved_mouse_move_msg.msg.hwnd == 0)
3468 mouse_move_timer =
3469 SetTimer (hwnd, MOUSE_MOVE_ID,
3470 w32_mouse_move_interval, NULL);
3471
3472 /* Hold onto message for now. */
3473 saved_mouse_move_msg.msg.hwnd = hwnd;
3474 saved_mouse_move_msg.msg.message = msg;
3475 saved_mouse_move_msg.msg.wParam = wParam;
3476 saved_mouse_move_msg.msg.lParam = lParam;
3477 saved_mouse_move_msg.msg.time = GetMessageTime ();
3478 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
3479
3480 return 0;
3481
3482 case WM_MOUSEWHEEL:
3483 case WM_DROPFILES:
3484 wmsg.dwModifiers = w32_get_modifiers ();
3485 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3486 signal_user_input ();
3487 return 0;
3488
3489 case WM_APPCOMMAND:
3490 if (w32_pass_multimedia_buttons_to_system)
3491 goto dflt;
3492 /* Otherwise, pass to lisp, the same way we do with mousehwheel. */
3493 case WM_MOUSEHWHEEL:
3494 wmsg.dwModifiers = w32_get_modifiers ();
3495 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3496 signal_user_input ();
3497 /* Non-zero must be returned when WM_MOUSEHWHEEL messages are
3498 handled, to prevent the system trying to handle it by faking
3499 scroll bar events. */
3500 return 1;
3501
3502 case WM_TIMER:
3503 /* Flush out saved messages if necessary. */
3504 if (wParam == mouse_button_timer)
3505 {
3506 if (saved_mouse_button_msg.msg.hwnd)
3507 {
3508 post_msg (&saved_mouse_button_msg);
3509 signal_user_input ();
3510 saved_mouse_button_msg.msg.hwnd = 0;
3511 }
3512 KillTimer (hwnd, mouse_button_timer);
3513 mouse_button_timer = 0;
3514 }
3515 else if (wParam == mouse_move_timer)
3516 {
3517 if (saved_mouse_move_msg.msg.hwnd)
3518 {
3519 post_msg (&saved_mouse_move_msg);
3520 saved_mouse_move_msg.msg.hwnd = 0;
3521 }
3522 KillTimer (hwnd, mouse_move_timer);
3523 mouse_move_timer = 0;
3524 }
3525 else if (wParam == menu_free_timer)
3526 {
3527 KillTimer (hwnd, menu_free_timer);
3528 menu_free_timer = 0;
3529 f = x_window_to_frame (dpyinfo, hwnd);
3530 /* If a popup menu is active, don't wipe its strings. */
3531 if (menubar_in_use
3532 && current_popup_menu == NULL)
3533 {
3534 /* Free memory used by owner-drawn and help-echo strings. */
3535 w32_free_menu_strings (hwnd);
3536 f->output_data.w32->menubar_active = 0;
3537 menubar_in_use = 0;
3538 }
3539 }
3540 else if (wParam == hourglass_timer)
3541 {
3542 KillTimer (hwnd, hourglass_timer);
3543 hourglass_timer = 0;
3544 show_hourglass (x_window_to_frame (dpyinfo, hwnd));
3545 }
3546 return 0;
3547
3548 case WM_NCACTIVATE:
3549 /* Windows doesn't send us focus messages when putting up and
3550 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
3551 The only indication we get that something happened is receiving
3552 this message afterwards. So this is a good time to reset our
3553 keyboard modifiers' state. */
3554 reset_modifiers ();
3555 goto dflt;
3556
3557 case WM_INITMENU:
3558 button_state = 0;
3559 ReleaseCapture ();
3560 /* We must ensure menu bar is fully constructed and up to date
3561 before allowing user interaction with it. To achieve this
3562 we send this message to the lisp thread and wait for a
3563 reply (whose value is not actually needed) to indicate that
3564 the menu bar is now ready for use, so we can now return.
3565
3566 To remain responsive in the meantime, we enter a nested message
3567 loop that can process all other messages.
3568
3569 However, we skip all this if the message results from calling
3570 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
3571 thread a message because it is blocked on us at this point. We
3572 set menubar_active before calling TrackPopupMenu to indicate
3573 this (there is no possibility of confusion with real menubar
3574 being active). */
3575
3576 f = x_window_to_frame (dpyinfo, hwnd);
3577 if (f
3578 && (f->output_data.w32->menubar_active
3579 /* We can receive this message even in the absence of a
3580 menubar (ie. when the system menu is activated) - in this
3581 case we do NOT want to forward the message, otherwise it
3582 will cause the menubar to suddenly appear when the user
3583 had requested it to be turned off! */
3584 || f->output_data.w32->menubar_widget == NULL))
3585 return 0;
3586
3587 {
3588 deferred_msg msg_buf;
3589
3590 /* Detect if message has already been deferred; in this case
3591 we cannot return any sensible value to ignore this. */
3592 if (find_deferred_msg (hwnd, msg) != NULL)
3593 abort ();
3594
3595 menubar_in_use = 1;
3596
3597 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
3598 }
3599
3600 case WM_EXITMENULOOP:
3601 f = x_window_to_frame (dpyinfo, hwnd);
3602
3603 /* If a menu is still active, check again after a short delay,
3604 since Windows often (always?) sends the WM_EXITMENULOOP
3605 before the corresponding WM_COMMAND message.
3606 Don't do this if a popup menu is active, since it is only
3607 menubar menus that require cleaning up in this way.
3608 */
3609 if (f && menubar_in_use && current_popup_menu == NULL)
3610 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
3611
3612 /* If hourglass cursor should be displayed, display it now. */
3613 if (f && f->output_data.w32->hourglass_p)
3614 SetCursor (f->output_data.w32->hourglass_cursor);
3615
3616 goto dflt;
3617
3618 case WM_MENUSELECT:
3619 /* Direct handling of help_echo in menus. Should be safe now
3620 that we generate the help_echo by placing a help event in the
3621 keyboard buffer. */
3622 {
3623 HMENU menu = (HMENU) lParam;
3624 UINT menu_item = (UINT) LOWORD (wParam);
3625 UINT flags = (UINT) HIWORD (wParam);
3626
3627 w32_menu_display_help (hwnd, menu, menu_item, flags);
3628 }
3629 return 0;
3630
3631 case WM_MEASUREITEM:
3632 f = x_window_to_frame (dpyinfo, hwnd);
3633 if (f)
3634 {
3635 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
3636
3637 if (pMis->CtlType == ODT_MENU)
3638 {
3639 /* Work out dimensions for popup menu titles. */
3640 char * title = (char *) pMis->itemData;
3641 HDC hdc = GetDC (hwnd);
3642 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3643 LOGFONT menu_logfont;
3644 HFONT old_font;
3645 SIZE size;
3646
3647 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3648 menu_logfont.lfWeight = FW_BOLD;
3649 menu_font = CreateFontIndirect (&menu_logfont);
3650 old_font = SelectObject (hdc, menu_font);
3651
3652 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
3653 if (title)
3654 {
3655 if (unicode_append_menu)
3656 GetTextExtentPoint32W (hdc, (WCHAR *) title,
3657 wcslen ((WCHAR *) title),
3658 &size);
3659 else
3660 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
3661
3662 pMis->itemWidth = size.cx;
3663 if (pMis->itemHeight < size.cy)
3664 pMis->itemHeight = size.cy;
3665 }
3666 else
3667 pMis->itemWidth = 0;
3668
3669 SelectObject (hdc, old_font);
3670 DeleteObject (menu_font);
3671 ReleaseDC (hwnd, hdc);
3672 return TRUE;
3673 }
3674 }
3675 return 0;
3676
3677 case WM_DRAWITEM:
3678 f = x_window_to_frame (dpyinfo, hwnd);
3679 if (f)
3680 {
3681 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
3682
3683 if (pDis->CtlType == ODT_MENU)
3684 {
3685 /* Draw popup menu title. */
3686 char * title = (char *) pDis->itemData;
3687 if (title)
3688 {
3689 HDC hdc = pDis->hDC;
3690 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3691 LOGFONT menu_logfont;
3692 HFONT old_font;
3693
3694 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3695 menu_logfont.lfWeight = FW_BOLD;
3696 menu_font = CreateFontIndirect (&menu_logfont);
3697 old_font = SelectObject (hdc, menu_font);
3698
3699 /* Always draw title as if not selected. */
3700 if (unicode_append_menu)
3701 ExtTextOutW (hdc,
3702 pDis->rcItem.left
3703 + GetSystemMetrics (SM_CXMENUCHECK),
3704 pDis->rcItem.top,
3705 ETO_OPAQUE, &pDis->rcItem,
3706 (WCHAR *) title,
3707 wcslen ((WCHAR *) title), NULL);
3708 else
3709 ExtTextOut (hdc,
3710 pDis->rcItem.left
3711 + GetSystemMetrics (SM_CXMENUCHECK),
3712 pDis->rcItem.top,
3713 ETO_OPAQUE, &pDis->rcItem,
3714 title, strlen (title), NULL);
3715
3716 SelectObject (hdc, old_font);
3717 DeleteObject (menu_font);
3718 }
3719 return TRUE;
3720 }
3721 }
3722 return 0;
3723
3724 #if 0
3725 /* Still not right - can't distinguish between clicks in the
3726 client area of the frame from clicks forwarded from the scroll
3727 bars - may have to hook WM_NCHITTEST to remember the mouse
3728 position and then check if it is in the client area ourselves. */
3729 case WM_MOUSEACTIVATE:
3730 /* Discard the mouse click that activates a frame, allowing the
3731 user to click anywhere without changing point (or worse!).
3732 Don't eat mouse clicks on scrollbars though!! */
3733 if (LOWORD (lParam) == HTCLIENT )
3734 return MA_ACTIVATEANDEAT;
3735 goto dflt;
3736 #endif
3737
3738 case WM_MOUSELEAVE:
3739 /* No longer tracking mouse. */
3740 track_mouse_window = NULL;
3741
3742 case WM_ACTIVATEAPP:
3743 case WM_ACTIVATE:
3744 case WM_WINDOWPOSCHANGED:
3745 case WM_SHOWWINDOW:
3746 /* Inform lisp thread that a frame might have just been obscured
3747 or exposed, so should recheck visibility of all frames. */
3748 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3749 goto dflt;
3750
3751 case WM_SETFOCUS:
3752 dpyinfo->faked_key = 0;
3753 reset_modifiers ();
3754 register_hot_keys (hwnd);
3755 goto command;
3756 case WM_KILLFOCUS:
3757 unregister_hot_keys (hwnd);
3758 button_state = 0;
3759 ReleaseCapture ();
3760 /* Relinquish the system caret. */
3761 if (w32_system_caret_hwnd)
3762 {
3763 w32_visible_system_caret_hwnd = NULL;
3764 w32_system_caret_hwnd = NULL;
3765 DestroyCaret ();
3766 }
3767 goto command;
3768 case WM_COMMAND:
3769 menubar_in_use = 0;
3770 f = x_window_to_frame (dpyinfo, hwnd);
3771 if (f && HIWORD (wParam) == 0)
3772 {
3773 if (menu_free_timer)
3774 {
3775 KillTimer (hwnd, menu_free_timer);
3776 menu_free_timer = 0;
3777 }
3778 }
3779 case WM_MOVE:
3780 case WM_SIZE:
3781 command:
3782 wmsg.dwModifiers = w32_get_modifiers ();
3783 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3784 goto dflt;
3785
3786 case WM_DESTROY:
3787 CoUninitialize ();
3788 return 0;
3789
3790 case WM_CLOSE:
3791 wmsg.dwModifiers = w32_get_modifiers ();
3792 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3793 return 0;
3794
3795 case WM_WINDOWPOSCHANGING:
3796 /* Don't restrict the sizing of tip frames. */
3797 if (hwnd == tip_window)
3798 return 0;
3799 {
3800 WINDOWPLACEMENT wp;
3801 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
3802
3803 wp.length = sizeof (WINDOWPLACEMENT);
3804 GetWindowPlacement (hwnd, &wp);
3805
3806 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
3807 {
3808 RECT rect;
3809 int wdiff;
3810 int hdiff;
3811 DWORD font_width;
3812 DWORD line_height;
3813 DWORD internal_border;
3814 DWORD scrollbar_extra;
3815 RECT wr;
3816
3817 wp.length = sizeof (wp);
3818 GetWindowRect (hwnd, &wr);
3819
3820 enter_crit ();
3821
3822 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
3823 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
3824 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
3825 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
3826
3827 leave_crit ();
3828
3829 memset (&rect, 0, sizeof (rect));
3830 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
3831 GetMenu (hwnd) != NULL);
3832
3833 /* Force width and height of client area to be exact
3834 multiples of the character cell dimensions. */
3835 wdiff = (lppos->cx - (rect.right - rect.left)
3836 - 2 * internal_border - scrollbar_extra)
3837 % font_width;
3838 hdiff = (lppos->cy - (rect.bottom - rect.top)
3839 - 2 * internal_border)
3840 % line_height;
3841
3842 if (wdiff || hdiff)
3843 {
3844 /* For right/bottom sizing we can just fix the sizes.
3845 However for top/left sizing we will need to fix the X
3846 and Y positions as well. */
3847
3848 int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK);
3849 int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK);
3850
3851 lppos->cx = max (lppos->cx - wdiff, cx_mintrack);
3852 lppos->cy = max (lppos->cy - hdiff, cy_mintrack);
3853
3854 if (wp.showCmd != SW_SHOWMAXIMIZED
3855 && (lppos->flags & SWP_NOMOVE) == 0)
3856 {
3857 if (lppos->x != wr.left || lppos->y != wr.top)
3858 {
3859 lppos->x += wdiff;
3860 lppos->y += hdiff;
3861 }
3862 else
3863 {
3864 lppos->flags |= SWP_NOMOVE;
3865 }
3866 }
3867
3868 return 0;
3869 }
3870 }
3871 }
3872
3873 goto dflt;
3874
3875 case WM_GETMINMAXINFO:
3876 /* Hack to allow resizing the Emacs frame above the screen size.
3877 Note that Windows 9x limits coordinates to 16-bits. */
3878 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
3879 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
3880 return 0;
3881
3882 case WM_SETCURSOR:
3883 if (LOWORD (lParam) == HTCLIENT)
3884 {
3885 f = x_window_to_frame (dpyinfo, hwnd);
3886 if (f->output_data.w32->hourglass_p && !menubar_in_use
3887 && !current_popup_menu)
3888 SetCursor (f->output_data.w32->hourglass_cursor);
3889 else
3890 SetCursor (f->output_data.w32->current_cursor);
3891 return 0;
3892 }
3893 goto dflt;
3894
3895 case WM_EMACS_SETCURSOR:
3896 {
3897 Cursor cursor = (Cursor) wParam;
3898 f = x_window_to_frame (dpyinfo, hwnd);
3899 if (f && cursor)
3900 {
3901 f->output_data.w32->current_cursor = cursor;
3902 if (!f->output_data.w32->hourglass_p)
3903 SetCursor (cursor);
3904 }
3905 return 0;
3906 }
3907
3908 case WM_EMACS_CREATESCROLLBAR:
3909 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
3910 (struct scroll_bar *) lParam);
3911
3912 case WM_EMACS_SHOWWINDOW:
3913 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
3914
3915 case WM_EMACS_SETFOREGROUND:
3916 {
3917 HWND foreground_window;
3918 DWORD foreground_thread, retval;
3919
3920 /* On NT 5.0, and apparently Windows 98, it is necessary to
3921 attach to the thread that currently has focus in order to
3922 pull the focus away from it. */
3923 foreground_window = GetForegroundWindow ();
3924 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
3925 if (!foreground_window
3926 || foreground_thread == GetCurrentThreadId ()
3927 || !AttachThreadInput (GetCurrentThreadId (),
3928 foreground_thread, TRUE))
3929 foreground_thread = 0;
3930
3931 retval = SetForegroundWindow ((HWND) wParam);
3932
3933 /* Detach from the previous foreground thread. */
3934 if (foreground_thread)
3935 AttachThreadInput (GetCurrentThreadId (),
3936 foreground_thread, FALSE);
3937
3938 return retval;
3939 }
3940
3941 case WM_EMACS_SETWINDOWPOS:
3942 {
3943 WINDOWPOS * pos = (WINDOWPOS *) wParam;
3944 return SetWindowPos (hwnd, pos->hwndInsertAfter,
3945 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
3946 }
3947
3948 case WM_EMACS_DESTROYWINDOW:
3949 DragAcceptFiles ((HWND) wParam, FALSE);
3950 return DestroyWindow ((HWND) wParam);
3951
3952 case WM_EMACS_HIDE_CARET:
3953 return HideCaret (hwnd);
3954
3955 case WM_EMACS_SHOW_CARET:
3956 return ShowCaret (hwnd);
3957
3958 case WM_EMACS_DESTROY_CARET:
3959 w32_system_caret_hwnd = NULL;
3960 w32_visible_system_caret_hwnd = NULL;
3961 return DestroyCaret ();
3962
3963 case WM_EMACS_TRACK_CARET:
3964 /* If there is currently no system caret, create one. */
3965 if (w32_system_caret_hwnd == NULL)
3966 {
3967 /* Use the default caret width, and avoid changing it
3968 unneccesarily, as it confuses screen reader software. */
3969 w32_system_caret_hwnd = hwnd;
3970 CreateCaret (hwnd, NULL, 0,
3971 w32_system_caret_height);
3972 }
3973
3974 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
3975 return 0;
3976 /* Ensure visible caret gets turned on when requested. */
3977 else if (w32_use_visible_system_caret
3978 && w32_visible_system_caret_hwnd != hwnd)
3979 {
3980 w32_visible_system_caret_hwnd = hwnd;
3981 return ShowCaret (hwnd);
3982 }
3983 /* Ensure visible caret gets turned off when requested. */
3984 else if (!w32_use_visible_system_caret
3985 && w32_visible_system_caret_hwnd)
3986 {
3987 w32_visible_system_caret_hwnd = NULL;
3988 return HideCaret (hwnd);
3989 }
3990 else
3991 return 1;
3992
3993 case WM_EMACS_TRACKPOPUPMENU:
3994 {
3995 UINT flags;
3996 POINT *pos;
3997 int retval;
3998 pos = (POINT *)lParam;
3999 flags = TPM_CENTERALIGN;
4000 if (button_state & LMOUSE)
4001 flags |= TPM_LEFTBUTTON;
4002 else if (button_state & RMOUSE)
4003 flags |= TPM_RIGHTBUTTON;
4004
4005 /* Remember we did a SetCapture on the initial mouse down event,
4006 so for safety, we make sure the capture is cancelled now. */
4007 ReleaseCapture ();
4008 button_state = 0;
4009
4010 /* Use menubar_active to indicate that WM_INITMENU is from
4011 TrackPopupMenu below, and should be ignored. */
4012 f = x_window_to_frame (dpyinfo, hwnd);
4013 if (f)
4014 f->output_data.w32->menubar_active = 1;
4015
4016 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
4017 0, hwnd, NULL))
4018 {
4019 MSG amsg;
4020 /* Eat any mouse messages during popupmenu */
4021 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
4022 PM_REMOVE));
4023 /* Get the menu selection, if any */
4024 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
4025 {
4026 retval = LOWORD (amsg.wParam);
4027 }
4028 else
4029 {
4030 retval = 0;
4031 }
4032 }
4033 else
4034 {
4035 retval = -1;
4036 }
4037
4038 return retval;
4039 }
4040
4041 default:
4042 /* Check for messages registered at runtime. */
4043 if (msg == msh_mousewheel)
4044 {
4045 wmsg.dwModifiers = w32_get_modifiers ();
4046 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
4047 signal_user_input ();
4048 return 0;
4049 }
4050
4051 dflt:
4052 return DefWindowProc (hwnd, msg, wParam, lParam);
4053 }
4054
4055
4056 /* The most common default return code for handled messages is 0. */
4057 return 0;
4058 }
4059
4060 static void
4061 my_create_window (f)
4062 struct frame * f;
4063 {
4064 MSG msg;
4065
4066 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
4067 abort ();
4068 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
4069 }
4070
4071
4072 /* Create a tooltip window. Unlike my_create_window, we do not do this
4073 indirectly via the Window thread, as we do not need to process Window
4074 messages for the tooltip. Creating tooltips indirectly also creates
4075 deadlocks when tooltips are created for menu items. */
4076 static void
4077 my_create_tip_window (f)
4078 struct frame *f;
4079 {
4080 RECT rect;
4081
4082 rect.left = rect.top = 0;
4083 rect.right = FRAME_PIXEL_WIDTH (f);
4084 rect.bottom = FRAME_PIXEL_HEIGHT (f);
4085
4086 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
4087 FRAME_EXTERNAL_MENU_BAR (f));
4088
4089 tip_window = FRAME_W32_WINDOW (f)
4090 = CreateWindow (EMACS_CLASS,
4091 f->namebuf,
4092 f->output_data.w32->dwStyle,
4093 f->left_pos,
4094 f->top_pos,
4095 rect.right - rect.left,
4096 rect.bottom - rect.top,
4097 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
4098 NULL,
4099 hinst,
4100 NULL);
4101
4102 if (tip_window)
4103 {
4104 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
4105 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
4106 SetWindowLong (tip_window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
4107 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
4108
4109 /* Tip frames have no scrollbars. */
4110 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
4111
4112 /* Do this to discard the default setting specified by our parent. */
4113 ShowWindow (tip_window, SW_HIDE);
4114 }
4115 }
4116
4117
4118 /* Create and set up the w32 window for frame F. */
4119
4120 static void
4121 w32_window (f, window_prompting, minibuffer_only)
4122 struct frame *f;
4123 long window_prompting;
4124 int minibuffer_only;
4125 {
4126 BLOCK_INPUT;
4127
4128 /* Use the resource name as the top-level window name
4129 for looking up resources. Make a non-Lisp copy
4130 for the window manager, so GC relocation won't bother it.
4131
4132 Elsewhere we specify the window name for the window manager. */
4133
4134 {
4135 char *str = (char *) SDATA (Vx_resource_name);
4136 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4137 strcpy (f->namebuf, str);
4138 }
4139
4140 my_create_window (f);
4141
4142 validate_x_resource_name ();
4143
4144 /* x_set_name normally ignores requests to set the name if the
4145 requested name is the same as the current name. This is the one
4146 place where that assumption isn't correct; f->name is set, but
4147 the server hasn't been told. */
4148 {
4149 Lisp_Object name;
4150 int explicit = f->explicit_name;
4151
4152 f->explicit_name = 0;
4153 name = f->name;
4154 f->name = Qnil;
4155 x_set_name (f, name, explicit);
4156 }
4157
4158 UNBLOCK_INPUT;
4159
4160 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4161 initialize_frame_menubar (f);
4162
4163 if (FRAME_W32_WINDOW (f) == 0)
4164 error ("Unable to create window");
4165 }
4166
4167 /* Handle the icon stuff for this window. Perhaps later we might
4168 want an x_set_icon_position which can be called interactively as
4169 well. */
4170
4171 static void
4172 x_icon (f, parms)
4173 struct frame *f;
4174 Lisp_Object parms;
4175 {
4176 Lisp_Object icon_x, icon_y;
4177
4178 /* Set the position of the icon. Note that Windows 95 groups all
4179 icons in the tray. */
4180 icon_x = w32_get_arg (parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4181 icon_y = w32_get_arg (parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4182 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4183 {
4184 CHECK_NUMBER (icon_x);
4185 CHECK_NUMBER (icon_y);
4186 }
4187 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4188 error ("Both left and top icon corners of icon must be specified");
4189
4190 BLOCK_INPUT;
4191
4192 if (! EQ (icon_x, Qunbound))
4193 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4194
4195 #if 0 /* TODO */
4196 /* Start up iconic or window? */
4197 x_wm_set_window_state
4198 (f, (EQ (w32_get_arg (parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4199 ? IconicState
4200 : NormalState));
4201
4202 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
4203 ? f->icon_name
4204 : f->name)));
4205 #endif
4206
4207 UNBLOCK_INPUT;
4208 }
4209
4210
4211 static void
4212 x_make_gc (f)
4213 struct frame *f;
4214 {
4215 XGCValues gc_values;
4216
4217 BLOCK_INPUT;
4218
4219 /* Create the GC's of this frame.
4220 Note that many default values are used. */
4221
4222 /* Normal video */
4223 gc_values.font = FRAME_FONT (f);
4224
4225 /* Cursor has cursor-color background, background-color foreground. */
4226 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
4227 gc_values.background = f->output_data.w32->cursor_pixel;
4228 f->output_data.w32->cursor_gc
4229 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
4230 (GCFont | GCForeground | GCBackground),
4231 &gc_values);
4232
4233 /* Reliefs. */
4234 f->output_data.w32->white_relief.gc = 0;
4235 f->output_data.w32->black_relief.gc = 0;
4236
4237 UNBLOCK_INPUT;
4238 }
4239
4240
4241 /* Handler for signals raised during x_create_frame and
4242 x_create_top_frame. FRAME is the frame which is partially
4243 constructed. */
4244
4245 static Lisp_Object
4246 unwind_create_frame (frame)
4247 Lisp_Object frame;
4248 {
4249 struct frame *f = XFRAME (frame);
4250
4251 /* If frame is ``official'', nothing to do. */
4252 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4253 {
4254 #ifdef GLYPH_DEBUG
4255 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4256 #endif
4257
4258 x_free_frame_resources (f);
4259
4260 /* Check that reference counts are indeed correct. */
4261 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4262 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
4263
4264 return Qt;
4265 }
4266
4267 return Qnil;
4268 }
4269
4270 static void
4271 x_default_font_parameter (f, parms)
4272 struct frame *f;
4273 Lisp_Object parms;
4274 {
4275 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4276 Lisp_Object font = x_get_arg (dpyinfo, parms, Qfont, "font", "Font",
4277 RES_TYPE_STRING);
4278
4279 if (!STRINGP (font))
4280 {
4281 int i;
4282 static char *names[]
4283 = { "Courier New-10",
4284 "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1",
4285 "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1",
4286 "Fixedsys",
4287 NULL };
4288
4289 for (i = 0; names[i]; i++)
4290 {
4291 font = font_open_by_name (f, names[i]);
4292 if (! NILP (font))
4293 break;
4294 }
4295 if (NILP (font))
4296 error ("No suitable font was found");
4297 }
4298 x_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING);
4299 }
4300
4301 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4302 1, 1, 0,
4303 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
4304 Return an Emacs frame object.
4305 PARAMETERS is an alist of frame parameters.
4306 If the parameters specify that the frame should not have a minibuffer,
4307 and do not specify a specific minibuffer window to use,
4308 then `default-minibuffer-frame' must be a frame whose minibuffer can
4309 be shared by the new frame.
4310
4311 This function is an internal primitive--use `make-frame' instead. */)
4312 (parameters)
4313 Lisp_Object parameters;
4314 {
4315 struct frame *f;
4316 Lisp_Object frame, tem;
4317 Lisp_Object name;
4318 int minibuffer_only = 0;
4319 long window_prompting = 0;
4320 int width, height;
4321 int count = SPECPDL_INDEX ();
4322 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
4323 Lisp_Object display;
4324 struct w32_display_info *dpyinfo = NULL;
4325 Lisp_Object parent;
4326 struct kboard *kb;
4327
4328 check_w32 ();
4329
4330 /* Make copy of frame parameters because the original is in pure
4331 storage now. */
4332 parameters = Fcopy_alist (parameters);
4333
4334 /* Use this general default value to start with
4335 until we know if this frame has a specified name. */
4336 Vx_resource_name = Vinvocation_name;
4337
4338 display = w32_get_arg (parameters, Qdisplay, 0, 0, RES_TYPE_STRING);
4339 if (EQ (display, Qunbound))
4340 display = Qnil;
4341 dpyinfo = check_x_display_info (display);
4342 #ifdef MULTI_KBOARD
4343 kb = dpyinfo->terminal->kboard;
4344 #else
4345 kb = &the_only_kboard;
4346 #endif
4347
4348 name = w32_get_arg (parameters, Qname, "name", "Name", RES_TYPE_STRING);
4349 if (!STRINGP (name)
4350 && ! EQ (name, Qunbound)
4351 && ! NILP (name))
4352 error ("Invalid frame name--not a string or nil");
4353
4354 if (STRINGP (name))
4355 Vx_resource_name = name;
4356
4357 /* See if parent window is specified. */
4358 parent = w32_get_arg (parameters, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
4359 if (EQ (parent, Qunbound))
4360 parent = Qnil;
4361 if (! NILP (parent))
4362 CHECK_NUMBER (parent);
4363
4364 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4365 /* No need to protect DISPLAY because that's not used after passing
4366 it to make_frame_without_minibuffer. */
4367 frame = Qnil;
4368 GCPRO4 (parameters, parent, name, frame);
4369 tem = w32_get_arg (parameters, Qminibuffer, "minibuffer", "Minibuffer",
4370 RES_TYPE_SYMBOL);
4371 if (EQ (tem, Qnone) || NILP (tem))
4372 f = make_frame_without_minibuffer (Qnil, kb, display);
4373 else if (EQ (tem, Qonly))
4374 {
4375 f = make_minibuffer_frame ();
4376 minibuffer_only = 1;
4377 }
4378 else if (WINDOWP (tem))
4379 f = make_frame_without_minibuffer (tem, kb, display);
4380 else
4381 f = make_frame (1);
4382
4383 XSETFRAME (frame, f);
4384
4385 /* Note that Windows does support scroll bars. */
4386 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
4387
4388 /* By default, make scrollbars the system standard width. */
4389 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
4390
4391 f->terminal = dpyinfo->terminal;
4392 f->terminal->reference_count++;
4393
4394 f->output_method = output_w32;
4395 f->output_data.w32 =
4396 (struct w32_output *) xmalloc (sizeof (struct w32_output));
4397 bzero (f->output_data.w32, sizeof (struct w32_output));
4398 FRAME_FONTSET (f) = -1;
4399 record_unwind_protect (unwind_create_frame, frame);
4400
4401 f->icon_name
4402 = w32_get_arg (parameters, Qicon_name, "iconName", "Title", RES_TYPE_STRING);
4403 if (! STRINGP (f->icon_name))
4404 f->icon_name = Qnil;
4405
4406 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
4407 #ifdef MULTI_KBOARD
4408 FRAME_KBOARD (f) = kb;
4409 #endif
4410
4411 /* Specify the parent under which to make this window. */
4412
4413 if (!NILP (parent))
4414 {
4415 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
4416 f->output_data.w32->explicit_parent = 1;
4417 }
4418 else
4419 {
4420 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4421 f->output_data.w32->explicit_parent = 0;
4422 }
4423
4424 /* Set the name; the functions to which we pass f expect the name to
4425 be set. */
4426 if (EQ (name, Qunbound) || NILP (name))
4427 {
4428 f->name = build_string (dpyinfo->w32_id_name);
4429 f->explicit_name = 0;
4430 }
4431 else
4432 {
4433 f->name = name;
4434 f->explicit_name = 1;
4435 /* use the frame's title when getting resources for this frame. */
4436 specbind (Qx_resource_name, name);
4437 }
4438
4439 f->resx = dpyinfo->resx;
4440 f->resy = dpyinfo->resy;
4441
4442 if (uniscribe_available)
4443 register_font_driver (&uniscribe_font_driver, f);
4444 register_font_driver (&w32font_driver, f);
4445
4446 x_default_parameter (f, parameters, Qfont_backend, Qnil,
4447 "fontBackend", "FontBackend", RES_TYPE_STRING);
4448 /* Extract the window parameters from the supplied values
4449 that are needed to determine window geometry. */
4450 x_default_font_parameter (f, parameters);
4451 x_default_parameter (f, parameters, Qborder_width, make_number (2),
4452 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4453 /* This defaults to 2 in order to match xterm. We recognize either
4454 internalBorderWidth or internalBorder (which is what xterm calls
4455 it). */
4456 if (NILP (Fassq (Qinternal_border_width, parameters)))
4457 {
4458 Lisp_Object value;
4459
4460 value = w32_get_arg (parameters, Qinternal_border_width,
4461 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
4462 if (! EQ (value, Qunbound))
4463 parameters = Fcons (Fcons (Qinternal_border_width, value),
4464 parameters);
4465 }
4466 /* Default internalBorderWidth to 0 on Windows to match other programs. */
4467 x_default_parameter (f, parameters, Qinternal_border_width, make_number (0),
4468 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
4469 x_default_parameter (f, parameters, Qvertical_scroll_bars, Qright,
4470 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
4471
4472 /* Also do the stuff which must be set before the window exists. */
4473 x_default_parameter (f, parameters, Qforeground_color, build_string ("black"),
4474 "foreground", "Foreground", RES_TYPE_STRING);
4475 x_default_parameter (f, parameters, Qbackground_color, build_string ("white"),
4476 "background", "Background", RES_TYPE_STRING);
4477 x_default_parameter (f, parameters, Qmouse_color, build_string ("black"),
4478 "pointerColor", "Foreground", RES_TYPE_STRING);
4479 x_default_parameter (f, parameters, Qcursor_color, build_string ("black"),
4480 "cursorColor", "Foreground", RES_TYPE_STRING);
4481 x_default_parameter (f, parameters, Qborder_color, build_string ("black"),
4482 "borderColor", "BorderColor", RES_TYPE_STRING);
4483 x_default_parameter (f, parameters, Qscreen_gamma, Qnil,
4484 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
4485 x_default_parameter (f, parameters, Qline_spacing, Qnil,
4486 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
4487 x_default_parameter (f, parameters, Qleft_fringe, Qnil,
4488 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4489 x_default_parameter (f, parameters, Qright_fringe, Qnil,
4490 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
4491
4492
4493 /* Init faces before x_default_parameter is called for scroll-bar
4494 parameters because that function calls x_set_scroll_bar_width,
4495 which calls change_frame_size, which calls Fset_window_buffer,
4496 which runs hooks, which call Fvertical_motion. At the end, we
4497 end up in init_iterator with a null face cache, which should not
4498 happen. */
4499 init_frame_faces (f);
4500
4501 x_default_parameter (f, parameters, Qmenu_bar_lines, make_number (1),
4502 "menuBar", "MenuBar", RES_TYPE_NUMBER);
4503 x_default_parameter (f, parameters, Qtool_bar_lines, make_number (1),
4504 "toolBar", "ToolBar", RES_TYPE_NUMBER);
4505
4506 x_default_parameter (f, parameters, Qbuffer_predicate, Qnil,
4507 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
4508 x_default_parameter (f, parameters, Qtitle, Qnil,
4509 "title", "Title", RES_TYPE_STRING);
4510 x_default_parameter (f, parameters, Qfullscreen, Qnil,
4511 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
4512
4513 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
4514 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4515
4516 f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM);
4517 f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW);
4518 f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW);
4519 f->output_data.w32->hand_cursor = w32_load_cursor (IDC_HAND);
4520 f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT);
4521 f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE);
4522
4523 f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor;
4524
4525 window_prompting = x_figure_window_size (f, parameters, 1);
4526
4527 tem = w32_get_arg (parameters, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4528 f->no_split = minibuffer_only || EQ (tem, Qt);
4529
4530 w32_window (f, window_prompting, minibuffer_only);
4531 x_icon (f, parameters);
4532
4533 x_make_gc (f);
4534
4535 /* Now consider the frame official. */
4536 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
4537 Vframe_list = Fcons (frame, Vframe_list);
4538
4539 /* We need to do this after creating the window, so that the
4540 icon-creation functions can say whose icon they're describing. */
4541 x_default_parameter (f, parameters, Qicon_type, Qnil,
4542 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
4543
4544 x_default_parameter (f, parameters, Qauto_raise, Qnil,
4545 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4546 x_default_parameter (f, parameters, Qauto_lower, Qnil,
4547 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4548 x_default_parameter (f, parameters, Qcursor_type, Qbox,
4549 "cursorType", "CursorType", RES_TYPE_SYMBOL);
4550 x_default_parameter (f, parameters, Qscroll_bar_width, Qnil,
4551 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
4552
4553 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
4554 Change will not be effected unless different from the current
4555 FRAME_LINES (f). */
4556 width = FRAME_COLS (f);
4557 height = FRAME_LINES (f);
4558
4559 FRAME_LINES (f) = 0;
4560 SET_FRAME_COLS (f, 0);
4561 change_frame_size (f, height, width, 1, 0, 0);
4562
4563 /* Tell the server what size and position, etc, we want, and how
4564 badly we want them. This should be done after we have the menu
4565 bar so that its size can be taken into account. */
4566 BLOCK_INPUT;
4567 x_wm_set_size_hint (f, window_prompting, 0);
4568 UNBLOCK_INPUT;
4569
4570 /* Make the window appear on the frame and enable display, unless
4571 the caller says not to. However, with explicit parent, Emacs
4572 cannot control visibility, so don't try. */
4573 if (! f->output_data.w32->explicit_parent)
4574 {
4575 Lisp_Object visibility;
4576
4577 visibility = w32_get_arg (parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
4578 if (EQ (visibility, Qunbound))
4579 visibility = Qt;
4580
4581 if (EQ (visibility, Qicon))
4582 x_iconify_frame (f);
4583 else if (! NILP (visibility))
4584 x_make_frame_visible (f);
4585 else
4586 /* Must have been Qnil. */
4587 ;
4588 }
4589
4590 /* Initialize `default-minibuffer-frame' in case this is the first
4591 frame on this terminal. */
4592 if (FRAME_HAS_MINIBUF_P (f)
4593 && (!FRAMEP (kb->Vdefault_minibuffer_frame)
4594 || !FRAME_LIVE_P (XFRAME (kb->Vdefault_minibuffer_frame))))
4595 kb->Vdefault_minibuffer_frame = frame;
4596
4597 /* All remaining specified parameters, which have not been "used"
4598 by x_get_arg and friends, now go in the misc. alist of the frame. */
4599 for (tem = parameters; CONSP (tem); tem = XCDR (tem))
4600 if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
4601 f->param_alist = Fcons (XCAR (tem), f->param_alist);
4602
4603 UNGCPRO;
4604
4605 /* Make sure windows on this frame appear in calls to next-window
4606 and similar functions. */
4607 Vwindow_list = Qnil;
4608
4609 return unbind_to (count, frame);
4610 }
4611
4612 /* FRAME is used only to get a handle on the X display. We don't pass the
4613 display info directly because we're called from frame.c, which doesn't
4614 know about that structure. */
4615 Lisp_Object
4616 x_get_focus_frame (frame)
4617 struct frame *frame;
4618 {
4619 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
4620 Lisp_Object xfocus;
4621 if (! dpyinfo->w32_focus_frame)
4622 return Qnil;
4623
4624 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
4625 return xfocus;
4626 }
4627
4628 DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
4629 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
4630 (frame)
4631 Lisp_Object frame;
4632 {
4633 x_focus_on_frame (check_x_frame (frame));
4634 return Qnil;
4635 }
4636
4637 \f
4638 #if OLD_FONT
4639
4640 /* Return the charset portion of a font name. */
4641 char *
4642 xlfd_charset_of_font (char * fontname)
4643 {
4644 char *charset, *encoding;
4645
4646 encoding = strrchr (fontname, '-');
4647 if (!encoding || encoding == fontname)
4648 return NULL;
4649
4650 for (charset = encoding - 1; charset >= fontname; charset--)
4651 if (*charset == '-')
4652 break;
4653
4654 if (charset == fontname || strcmp (charset, "-*-*") == 0)
4655 return NULL;
4656
4657 return charset + 1;
4658 }
4659
4660 struct font_info *w32_load_bdf_font (struct frame *f, char *fontname,
4661 int size, char* filename);
4662 static Lisp_Object w32_list_bdf_fonts (Lisp_Object pattern, int max_names);
4663 static BOOL w32_to_x_font (LOGFONT * lplf, char * lpxstr, int len,
4664 char * charset);
4665 static BOOL x_to_w32_font (char *lpxstr, LOGFONT *lplogfont);
4666
4667 static struct font_info *
4668 w32_load_system_font (f, fontname, size)
4669 struct frame *f;
4670 char * fontname;
4671 int size;
4672 {
4673 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4674 Lisp_Object font_names;
4675
4676 /* Get a list of all the fonts that match this name. Once we
4677 have a list of matching fonts, we compare them against the fonts
4678 we already have loaded by comparing names. */
4679 font_names = w32_list_fonts (f, build_string (fontname), size, 100);
4680
4681 if (!NILP (font_names))
4682 {
4683 Lisp_Object tail;
4684 int i;
4685
4686 /* First check if any are already loaded, as that is cheaper
4687 than loading another one. */
4688 for (i = 0; i < dpyinfo->n_fonts; i++)
4689 for (tail = font_names; CONSP (tail); tail = XCDR (tail))
4690 if (dpyinfo->font_table[i].name
4691 && (!strcmp (dpyinfo->font_table[i].name,
4692 SDATA (XCAR (tail)))
4693 || !strcmp (dpyinfo->font_table[i].full_name,
4694 SDATA (XCAR (tail)))))
4695 return (dpyinfo->font_table + i);
4696
4697 fontname = (char *) SDATA (XCAR (font_names));
4698 }
4699 else if (w32_strict_fontnames)
4700 {
4701 /* If EnumFontFamiliesEx was available, we got a full list of
4702 fonts back so stop now to avoid the possibility of loading a
4703 random font. If we had to fall back to EnumFontFamilies, the
4704 list is incomplete, so continue whether the font we want was
4705 listed or not. */
4706 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
4707 FARPROC enum_font_families_ex
4708 = GetProcAddress (gdi32, "EnumFontFamiliesExA");
4709 if (enum_font_families_ex)
4710 return NULL;
4711 }
4712
4713 /* Load the font and add it to the table. */
4714 {
4715 char *full_name, *encoding, *charset;
4716 XFontStruct *font;
4717 struct font_info *fontp;
4718 LOGFONT lf;
4719 BOOL ok;
4720 int codepage;
4721 int i;
4722
4723 if (!fontname || !x_to_w32_font (fontname, &lf))
4724 return (NULL);
4725
4726 if (!*lf.lfFaceName)
4727 /* If no name was specified for the font, we get a random font
4728 from CreateFontIndirect - this is not particularly
4729 desirable, especially since CreateFontIndirect does not
4730 fill out the missing name in lf, so we never know what we
4731 ended up with. */
4732 return NULL;
4733
4734 lf.lfQuality = DEFAULT_QUALITY;
4735
4736 font = (XFontStruct *) xmalloc (sizeof (XFontStruct));
4737 bzero (font, sizeof (*font));
4738
4739 /* Set bdf to NULL to indicate that this is a Windows font. */
4740 font->bdf = NULL;
4741
4742 BLOCK_INPUT;
4743
4744 font->hfont = CreateFontIndirect (&lf);
4745
4746 if (font->hfont == NULL)
4747 {
4748 ok = FALSE;
4749 }
4750 else
4751 {
4752 HDC hdc;
4753 HANDLE oldobj;
4754
4755 codepage = w32_codepage_for_font (fontname);
4756
4757 hdc = GetDC (dpyinfo->root_window);
4758 oldobj = SelectObject (hdc, font->hfont);
4759
4760 ok = GetTextMetrics (hdc, &font->tm);
4761 if (codepage == CP_UNICODE)
4762 font->double_byte_p = 1;
4763 else
4764 {
4765 /* Unfortunately, some fonts (eg. MingLiU, a big5 ttf font)
4766 don't report themselves as double byte fonts, when
4767 patently they are. So instead of trusting
4768 GetFontLanguageInfo, we check the properties of the
4769 codepage directly, since that is ultimately what we are
4770 working from anyway. */
4771 /* font->double_byte_p = GetFontLanguageInfo (hdc) & GCP_DBCS; */
4772 CPINFO cpi = {0};
4773 GetCPInfo (codepage, &cpi);
4774 font->double_byte_p = cpi.MaxCharSize > 1;
4775 }
4776
4777 SelectObject (hdc, oldobj);
4778 ReleaseDC (dpyinfo->root_window, hdc);
4779 /* Fill out details in lf according to the font that was
4780 actually loaded. */
4781 lf.lfHeight = font->tm.tmInternalLeading - font->tm.tmHeight;
4782 lf.lfWidth = font->tm.tmMaxCharWidth;
4783 lf.lfWeight = font->tm.tmWeight;
4784 lf.lfItalic = font->tm.tmItalic;
4785 lf.lfCharSet = font->tm.tmCharSet;
4786 lf.lfPitchAndFamily = ((font->tm.tmPitchAndFamily & TMPF_FIXED_PITCH)
4787 ? VARIABLE_PITCH : FIXED_PITCH);
4788 lf.lfOutPrecision = ((font->tm.tmPitchAndFamily & TMPF_VECTOR)
4789 ? OUT_STROKE_PRECIS : OUT_STRING_PRECIS);
4790
4791 w32_cache_char_metrics (font);
4792 }
4793
4794 UNBLOCK_INPUT;
4795
4796 if (!ok)
4797 {
4798 w32_unload_font (dpyinfo, font);
4799 return (NULL);
4800 }
4801
4802 /* Find a free slot in the font table. */
4803 for (i = 0; i < dpyinfo->n_fonts; ++i)
4804 if (dpyinfo->font_table[i].name == NULL)
4805 break;
4806
4807 /* If no free slot found, maybe enlarge the font table. */
4808 if (i == dpyinfo->n_fonts
4809 && dpyinfo->n_fonts == dpyinfo->font_table_size)
4810 {
4811 int sz;
4812 dpyinfo->font_table_size = max (16, 2 * dpyinfo->font_table_size);
4813 sz = dpyinfo->font_table_size * sizeof *dpyinfo->font_table;
4814 dpyinfo->font_table
4815 = (struct font_info *) xrealloc (dpyinfo->font_table, sz);
4816 }
4817
4818 fontp = dpyinfo->font_table + i;
4819 if (i == dpyinfo->n_fonts)
4820 ++dpyinfo->n_fonts;
4821
4822 /* Now fill in the slots of *FONTP. */
4823 BLOCK_INPUT;
4824 bzero (fontp, sizeof (*fontp));
4825 fontp->font = font;
4826 fontp->font_idx = i;
4827 fontp->name = (char *) xmalloc (strlen (fontname) + 1);
4828 bcopy (fontname, fontp->name, strlen (fontname) + 1);
4829
4830 if ((lf.lfPitchAndFamily & 0x03) == FIXED_PITCH)
4831 {
4832 /* Fixed width font. */
4833 fontp->average_width = fontp->space_width = FONT_AVG_WIDTH (font);
4834 }
4835 else
4836 {
4837 wchar_t space = 32;
4838 XCharStruct* pcm;
4839 pcm = w32_per_char_metric (font, &space, ANSI_FONT);
4840 if (pcm)
4841 fontp->space_width = pcm->width;
4842 else
4843 fontp->space_width = FONT_AVG_WIDTH (font);
4844
4845 fontp->average_width = font->tm.tmAveCharWidth;
4846 }
4847
4848 fontp->charset = -1;
4849 charset = xlfd_charset_of_font (fontname);
4850
4851 /* Cache the W32 codepage for a font. This makes w32_encode_char
4852 (called for every glyph during redisplay) much faster. */
4853 fontp->codepage = codepage;
4854
4855 /* Work out the font's full name. */
4856 full_name = (char *)xmalloc (100);
4857 if (full_name && w32_to_x_font (&lf, full_name, 100, charset))
4858 fontp->full_name = full_name;
4859 else
4860 {
4861 /* If all else fails - just use the name we used to load it. */
4862 xfree (full_name);
4863 fontp->full_name = fontp->name;
4864 }
4865
4866 fontp->size = FONT_WIDTH (font);
4867 fontp->height = FONT_HEIGHT (font);
4868
4869 /* The slot `encoding' specifies how to map a character
4870 code-points (0x20..0x7F or 0x2020..0x7F7F) of each charset to
4871 the font code-points (0:0x20..0x7F, 1:0xA0..0xFF), or
4872 (0:0x20..0x7F, 1:0xA0..0xFF,
4873 (0:0x2020..0x7F7F, 1:0xA0A0..0xFFFF, 3:0x20A0..0x7FFF,
4874 2:0xA020..0xFF7F). For the moment, we don't know which charset
4875 uses this font. So, we set information in fontp->encoding_type
4876 which is never used by any charset. If mapping can't be
4877 decided, set FONT_ENCODING_NOT_DECIDED. */
4878
4879 /* SJIS fonts need to be set to type 4, all others seem to work as
4880 type FONT_ENCODING_NOT_DECIDED. */
4881 encoding = strrchr (fontp->name, '-');
4882 if (encoding && strnicmp (encoding+1, "sjis", 4) == 0)
4883 fontp->encoding_type = 4;
4884 else
4885 fontp->encoding_type = FONT_ENCODING_NOT_DECIDED;
4886
4887 /* The following three values are set to 0 under W32, which is
4888 what they get set to if XGetFontProperty fails under X. */
4889 fontp->baseline_offset = 0;
4890 fontp->relative_compose = 0;
4891 fontp->default_ascent = 0;
4892
4893 /* Set global flag fonts_changed_p to non-zero if the font loaded
4894 has a character with a smaller width than any other character
4895 before, or if the font loaded has a smaller height than any
4896 other font loaded before. If this happens, it will make a
4897 glyph matrix reallocation necessary. */
4898 fonts_changed_p |= x_compute_min_glyph_bounds (f);
4899 UNBLOCK_INPUT;
4900 return fontp;
4901 }
4902 }
4903
4904 /* Load font named FONTNAME of size SIZE for frame F, and return a
4905 pointer to the structure font_info while allocating it dynamically.
4906 If loading fails, return NULL. */
4907 struct font_info *
4908 w32_load_font (f, fontname, size)
4909 struct frame *f;
4910 char * fontname;
4911 int size;
4912 {
4913 Lisp_Object bdf_fonts;
4914 struct font_info *retval = NULL;
4915 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4916
4917 bdf_fonts = w32_list_bdf_fonts (build_string (fontname), 1);
4918
4919 while (!retval && CONSP (bdf_fonts))
4920 {
4921 char *bdf_name, *bdf_file;
4922 Lisp_Object bdf_pair;
4923 int i;
4924
4925 bdf_name = SDATA (XCAR (bdf_fonts));
4926 bdf_pair = Fassoc (XCAR (bdf_fonts), Vw32_bdf_filename_alist);
4927 bdf_file = SDATA (XCDR (bdf_pair));
4928
4929 /* If the font is already loaded, do not load it again. */
4930 for (i = 0; i < dpyinfo->n_fonts; i++)
4931 {
4932 if ((dpyinfo->font_table[i].name
4933 && !strcmp (dpyinfo->font_table[i].name, bdf_name))
4934 || (dpyinfo->font_table[i].full_name
4935 && !strcmp (dpyinfo->font_table[i].full_name, bdf_name)))
4936 return dpyinfo->font_table + i;
4937 }
4938
4939 retval = w32_load_bdf_font (f, bdf_name, size, bdf_file);
4940
4941 bdf_fonts = XCDR (bdf_fonts);
4942 }
4943
4944 if (retval)
4945 return retval;
4946
4947 return w32_load_system_font (f, fontname, size);
4948 }
4949
4950
4951 void
4952 w32_unload_font (dpyinfo, font)
4953 struct w32_display_info *dpyinfo;
4954 XFontStruct * font;
4955 {
4956 if (font)
4957 {
4958 xfree (font->per_char);
4959 if (font->bdf) w32_free_bdf_font (font->bdf);
4960
4961 if (font->hfont) DeleteObject (font->hfont);
4962 xfree (font);
4963 }
4964 }
4965 #endif /* OLD_FONT */
4966
4967 /* The font conversion stuff between x and w32 */
4968
4969 /* X font string is as follows (from faces.el)
4970 * (let ((- "[-?]")
4971 * (foundry "[^-]+")
4972 * (family "[^-]+")
4973 * (weight "\\(bold\\|demibold\\|medium\\)") ; 1
4974 * (weight\? "\\([^-]*\\)") ; 1
4975 * (slant "\\([ior]\\)") ; 2
4976 * (slant\? "\\([^-]?\\)") ; 2
4977 * (swidth "\\([^-]*\\)") ; 3
4978 * (adstyle "[^-]*") ; 4
4979 * (pixelsize "[0-9]+")
4980 * (pointsize "[0-9][0-9]+")
4981 * (resx "[0-9][0-9]+")
4982 * (resy "[0-9][0-9]+")
4983 * (spacing "[cmp?*]")
4984 * (avgwidth "[0-9]+")
4985 * (registry "[^-]+")
4986 * (encoding "[^-]+")
4987 * )
4988 */
4989
4990 static LONG
4991 x_to_w32_weight (lpw)
4992 char * lpw;
4993 {
4994 if (!lpw) return (FW_DONTCARE);
4995
4996 if (xstrcasecmp (lpw, "heavy") == 0) return FW_HEAVY;
4997 else if (xstrcasecmp (lpw, "extrabold") == 0) return FW_EXTRABOLD;
4998 else if (xstrcasecmp (lpw, "bold") == 0) return FW_BOLD;
4999 else if (xstrcasecmp (lpw, "demibold") == 0) return FW_SEMIBOLD;
5000 else if (xstrcasecmp (lpw, "semibold") == 0) return FW_SEMIBOLD;
5001 else if (xstrcasecmp (lpw, "medium") == 0) return FW_MEDIUM;
5002 else if (xstrcasecmp (lpw, "normal") == 0) return FW_NORMAL;
5003 else if (xstrcasecmp (lpw, "light") == 0) return FW_LIGHT;
5004 else if (xstrcasecmp (lpw, "extralight") == 0) return FW_EXTRALIGHT;
5005 else if (xstrcasecmp (lpw, "thin") == 0) return FW_THIN;
5006 else
5007 return FW_DONTCARE;
5008 }
5009
5010
5011 static char *
5012 w32_to_x_weight (fnweight)
5013 int fnweight;
5014 {
5015 if (fnweight >= FW_HEAVY) return "heavy";
5016 if (fnweight >= FW_EXTRABOLD) return "extrabold";
5017 if (fnweight >= FW_BOLD) return "bold";
5018 if (fnweight >= FW_SEMIBOLD) return "demibold";
5019 if (fnweight >= FW_MEDIUM) return "medium";
5020 if (fnweight >= FW_NORMAL) return "normal";
5021 if (fnweight >= FW_LIGHT) return "light";
5022 if (fnweight >= FW_EXTRALIGHT) return "extralight";
5023 if (fnweight >= FW_THIN) return "thin";
5024 else
5025 return "*";
5026 }
5027
5028 LONG
5029 x_to_w32_charset (lpcs)
5030 char * lpcs;
5031 {
5032 Lisp_Object this_entry, w32_charset;
5033 char *charset;
5034 int len = strlen (lpcs);
5035
5036 /* Support "*-#nnn" format for unknown charsets. */
5037 if (strncmp (lpcs, "*-#", 3) == 0)
5038 return atoi (lpcs + 3);
5039
5040 /* All Windows fonts qualify as unicode. */
5041 if (!strncmp (lpcs, "iso10646", 8))
5042 return DEFAULT_CHARSET;
5043
5044 /* Handle wildcards by ignoring them; eg. treat "big5*-*" as "big5". */
5045 charset = alloca (len + 1);
5046 strcpy (charset, lpcs);
5047 lpcs = strchr (charset, '*');
5048 if (lpcs)
5049 *lpcs = '\0';
5050
5051 /* Look through w32-charset-info-alist for the character set.
5052 Format of each entry is
5053 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5054 */
5055 this_entry = Fassoc (build_string (charset), Vw32_charset_info_alist);
5056
5057 if (NILP (this_entry))
5058 {
5059 /* At startup, we want iso8859-1 fonts to come up properly. */
5060 if (xstrcasecmp (charset, "iso8859-1") == 0)
5061 return ANSI_CHARSET;
5062 else
5063 return DEFAULT_CHARSET;
5064 }
5065
5066 w32_charset = Fcar (Fcdr (this_entry));
5067
5068 /* Translate Lisp symbol to number. */
5069 if (EQ (w32_charset, Qw32_charset_ansi))
5070 return ANSI_CHARSET;
5071 if (EQ (w32_charset, Qw32_charset_symbol))
5072 return SYMBOL_CHARSET;
5073 if (EQ (w32_charset, Qw32_charset_shiftjis))
5074 return SHIFTJIS_CHARSET;
5075 if (EQ (w32_charset, Qw32_charset_hangeul))
5076 return HANGEUL_CHARSET;
5077 if (EQ (w32_charset, Qw32_charset_chinesebig5))
5078 return CHINESEBIG5_CHARSET;
5079 if (EQ (w32_charset, Qw32_charset_gb2312))
5080 return GB2312_CHARSET;
5081 if (EQ (w32_charset, Qw32_charset_oem))
5082 return OEM_CHARSET;
5083 #ifdef JOHAB_CHARSET
5084 if (EQ (w32_charset, Qw32_charset_johab))
5085 return JOHAB_CHARSET;
5086 if (EQ (w32_charset, Qw32_charset_easteurope))
5087 return EASTEUROPE_CHARSET;
5088 if (EQ (w32_charset, Qw32_charset_turkish))
5089 return TURKISH_CHARSET;
5090 if (EQ (w32_charset, Qw32_charset_baltic))
5091 return BALTIC_CHARSET;
5092 if (EQ (w32_charset, Qw32_charset_russian))
5093 return RUSSIAN_CHARSET;
5094 if (EQ (w32_charset, Qw32_charset_arabic))
5095 return ARABIC_CHARSET;
5096 if (EQ (w32_charset, Qw32_charset_greek))
5097 return GREEK_CHARSET;
5098 if (EQ (w32_charset, Qw32_charset_hebrew))
5099 return HEBREW_CHARSET;
5100 if (EQ (w32_charset, Qw32_charset_vietnamese))
5101 return VIETNAMESE_CHARSET;
5102 if (EQ (w32_charset, Qw32_charset_thai))
5103 return THAI_CHARSET;
5104 if (EQ (w32_charset, Qw32_charset_mac))
5105 return MAC_CHARSET;
5106 #endif /* JOHAB_CHARSET */
5107 #ifdef UNICODE_CHARSET
5108 if (EQ (w32_charset, Qw32_charset_unicode))
5109 return UNICODE_CHARSET;
5110 #endif
5111
5112 return DEFAULT_CHARSET;
5113 }
5114
5115
5116 char *
5117 w32_to_x_charset (fncharset, matching)
5118 int fncharset;
5119 char *matching;
5120 {
5121 static char buf[32];
5122 Lisp_Object charset_type;
5123 int match_len = 0;
5124
5125 if (matching)
5126 {
5127 /* If fully specified, accept it as it is. Otherwise use a
5128 substring match. */
5129 char *wildcard = strchr (matching, '*');
5130 if (wildcard)
5131 *wildcard = '\0';
5132 else if (strchr (matching, '-'))
5133 return matching;
5134
5135 match_len = strlen (matching);
5136 }
5137
5138 switch (fncharset)
5139 {
5140 case ANSI_CHARSET:
5141 /* Handle startup case of w32-charset-info-alist not
5142 being set up yet. */
5143 if (NILP (Vw32_charset_info_alist))
5144 return "iso8859-1";
5145 charset_type = Qw32_charset_ansi;
5146 break;
5147 case DEFAULT_CHARSET:
5148 charset_type = Qw32_charset_default;
5149 break;
5150 case SYMBOL_CHARSET:
5151 charset_type = Qw32_charset_symbol;
5152 break;
5153 case SHIFTJIS_CHARSET:
5154 charset_type = Qw32_charset_shiftjis;
5155 break;
5156 case HANGEUL_CHARSET:
5157 charset_type = Qw32_charset_hangeul;
5158 break;
5159 case GB2312_CHARSET:
5160 charset_type = Qw32_charset_gb2312;
5161 break;
5162 case CHINESEBIG5_CHARSET:
5163 charset_type = Qw32_charset_chinesebig5;
5164 break;
5165 case OEM_CHARSET:
5166 charset_type = Qw32_charset_oem;
5167 break;
5168
5169 /* More recent versions of Windows (95 and NT4.0) define more
5170 character sets. */
5171 #ifdef EASTEUROPE_CHARSET
5172 case EASTEUROPE_CHARSET:
5173 charset_type = Qw32_charset_easteurope;
5174 break;
5175 case TURKISH_CHARSET:
5176 charset_type = Qw32_charset_turkish;
5177 break;
5178 case BALTIC_CHARSET:
5179 charset_type = Qw32_charset_baltic;
5180 break;
5181 case RUSSIAN_CHARSET:
5182 charset_type = Qw32_charset_russian;
5183 break;
5184 case ARABIC_CHARSET:
5185 charset_type = Qw32_charset_arabic;
5186 break;
5187 case GREEK_CHARSET:
5188 charset_type = Qw32_charset_greek;
5189 break;
5190 case HEBREW_CHARSET:
5191 charset_type = Qw32_charset_hebrew;
5192 break;
5193 case VIETNAMESE_CHARSET:
5194 charset_type = Qw32_charset_vietnamese;
5195 break;
5196 case THAI_CHARSET:
5197 charset_type = Qw32_charset_thai;
5198 break;
5199 case MAC_CHARSET:
5200 charset_type = Qw32_charset_mac;
5201 break;
5202 case JOHAB_CHARSET:
5203 charset_type = Qw32_charset_johab;
5204 break;
5205 #endif
5206
5207 #ifdef UNICODE_CHARSET
5208 case UNICODE_CHARSET:
5209 charset_type = Qw32_charset_unicode;
5210 break;
5211 #endif
5212 default:
5213 /* Encode numerical value of unknown charset. */
5214 sprintf (buf, "*-#%u", fncharset);
5215 return buf;
5216 }
5217
5218 {
5219 Lisp_Object rest;
5220 char * best_match = NULL;
5221 int matching_found = 0;
5222
5223 /* Look through w32-charset-info-alist for the character set.
5224 Prefer ISO codepages, and prefer lower numbers in the ISO
5225 range. Only return charsets for codepages which are installed.
5226
5227 Format of each entry is
5228 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5229 */
5230 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5231 {
5232 char * x_charset;
5233 Lisp_Object w32_charset;
5234 Lisp_Object codepage;
5235
5236 Lisp_Object this_entry = XCAR (rest);
5237
5238 /* Skip invalid entries in alist. */
5239 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
5240 || !CONSP (XCDR (this_entry))
5241 || !SYMBOLP (XCAR (XCDR (this_entry))))
5242 continue;
5243
5244 x_charset = SDATA (XCAR (this_entry));
5245 w32_charset = XCAR (XCDR (this_entry));
5246 codepage = XCDR (XCDR (this_entry));
5247
5248 /* Look for Same charset and a valid codepage (or non-int
5249 which means ignore). */
5250 if (EQ (w32_charset, charset_type)
5251 && (!INTEGERP (codepage) || XINT (codepage) == CP_DEFAULT
5252 || IsValidCodePage (XINT (codepage))))
5253 {
5254 /* If we don't have a match already, then this is the
5255 best. */
5256 if (!best_match)
5257 {
5258 best_match = x_charset;
5259 if (matching && !strnicmp (x_charset, matching, match_len))
5260 matching_found = 1;
5261 }
5262 /* If we already found a match for MATCHING, then
5263 only consider other matches. */
5264 else if (matching_found
5265 && strnicmp (x_charset, matching, match_len))
5266 continue;
5267 /* If this matches what we want, and the best so far doesn't,
5268 then this is better. */
5269 else if (!matching_found && matching
5270 && !strnicmp (x_charset, matching, match_len))
5271 {
5272 best_match = x_charset;
5273 matching_found = 1;
5274 }
5275 /* If this is fully specified, and the best so far isn't,
5276 then this is better. */
5277 else if ((!strchr (best_match, '-') && strchr (x_charset, '-'))
5278 /* If this is an ISO codepage, and the best so far isn't,
5279 then this is better, but only if it fully specifies the
5280 encoding. */
5281 || (strnicmp (best_match, "iso", 3) != 0
5282 && strnicmp (x_charset, "iso", 3) == 0
5283 && strchr (x_charset, '-')))
5284 best_match = x_charset;
5285 /* If both are ISO8859 codepages, choose the one with the
5286 lowest number in the encoding field. */
5287 else if (strnicmp (best_match, "iso8859-", 8) == 0
5288 && strnicmp (x_charset, "iso8859-", 8) == 0)
5289 {
5290 int best_enc = atoi (best_match + 8);
5291 int this_enc = atoi (x_charset + 8);
5292 if (this_enc > 0 && this_enc < best_enc)
5293 best_match = x_charset;
5294 }
5295 }
5296 }
5297
5298 /* If no match, encode the numeric value. */
5299 if (!best_match)
5300 {
5301 sprintf (buf, "*-#%u", fncharset);
5302 return buf;
5303 }
5304
5305 strncpy (buf, best_match, 31);
5306 /* If the charset is not fully specified, put -0 on the end. */
5307 if (!strchr (best_match, '-'))
5308 {
5309 int pos = strlen (best_match);
5310 /* Charset specifiers shouldn't be very long. If it is a made
5311 up one, truncating it should not do any harm since it isn't
5312 recognized anyway. */
5313 if (pos > 29)
5314 pos = 29;
5315 strcpy (buf + pos, "-0");
5316 }
5317 buf[31] = '\0';
5318 return buf;
5319 }
5320 }
5321
5322
5323 /* Return all the X charsets that map to a font. */
5324 static Lisp_Object
5325 w32_to_all_x_charsets (fncharset)
5326 int fncharset;
5327 {
5328 static char buf[32];
5329 Lisp_Object charset_type;
5330 Lisp_Object retval = Qnil;
5331
5332 switch (fncharset)
5333 {
5334 case ANSI_CHARSET:
5335 /* Handle startup case of w32-charset-info-alist not
5336 being set up yet. */
5337 if (NILP (Vw32_charset_info_alist))
5338 return Fcons (build_string ("iso8859-1"), Qnil);
5339
5340 charset_type = Qw32_charset_ansi;
5341 break;
5342 case DEFAULT_CHARSET:
5343 charset_type = Qw32_charset_default;
5344 break;
5345 case SYMBOL_CHARSET:
5346 charset_type = Qw32_charset_symbol;
5347 break;
5348 case SHIFTJIS_CHARSET:
5349 charset_type = Qw32_charset_shiftjis;
5350 break;
5351 case HANGEUL_CHARSET:
5352 charset_type = Qw32_charset_hangeul;
5353 break;
5354 case GB2312_CHARSET:
5355 charset_type = Qw32_charset_gb2312;
5356 break;
5357 case CHINESEBIG5_CHARSET:
5358 charset_type = Qw32_charset_chinesebig5;
5359 break;
5360 case OEM_CHARSET:
5361 charset_type = Qw32_charset_oem;
5362 break;
5363
5364 /* More recent versions of Windows (95 and NT4.0) define more
5365 character sets. */
5366 #ifdef EASTEUROPE_CHARSET
5367 case EASTEUROPE_CHARSET:
5368 charset_type = Qw32_charset_easteurope;
5369 break;
5370 case TURKISH_CHARSET:
5371 charset_type = Qw32_charset_turkish;
5372 break;
5373 case BALTIC_CHARSET:
5374 charset_type = Qw32_charset_baltic;
5375 break;
5376 case RUSSIAN_CHARSET:
5377 charset_type = Qw32_charset_russian;
5378 break;
5379 case ARABIC_CHARSET:
5380 charset_type = Qw32_charset_arabic;
5381 break;
5382 case GREEK_CHARSET:
5383 charset_type = Qw32_charset_greek;
5384 break;
5385 case HEBREW_CHARSET:
5386 charset_type = Qw32_charset_hebrew;
5387 break;
5388 case VIETNAMESE_CHARSET:
5389 charset_type = Qw32_charset_vietnamese;
5390 break;
5391 case THAI_CHARSET:
5392 charset_type = Qw32_charset_thai;
5393 break;
5394 case MAC_CHARSET:
5395 charset_type = Qw32_charset_mac;
5396 break;
5397 case JOHAB_CHARSET:
5398 charset_type = Qw32_charset_johab;
5399 break;
5400 #endif
5401
5402 #ifdef UNICODE_CHARSET
5403 case UNICODE_CHARSET:
5404 charset_type = Qw32_charset_unicode;
5405 break;
5406 #endif
5407 default:
5408 /* Encode numerical value of unknown charset. */
5409 sprintf (buf, "*-#%u", fncharset);
5410 return Fcons (build_string (buf), Qnil);
5411 }
5412
5413 {
5414 Lisp_Object rest;
5415 /* Look through w32-charset-info-alist for the character set.
5416 Only return fully specified charsets for codepages which are
5417 installed.
5418
5419 Format of each entry in Vw32_charset_info_alist is
5420 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE)).
5421 */
5422 for (rest = Vw32_charset_info_alist; CONSP (rest); rest = XCDR (rest))
5423 {
5424 Lisp_Object x_charset;
5425 Lisp_Object w32_charset;
5426 Lisp_Object codepage;
5427
5428 Lisp_Object this_entry = XCAR (rest);
5429
5430 /* Skip invalid entries in alist. */
5431 if (!CONSP (this_entry) || !STRINGP (XCAR (this_entry))
5432 || !CONSP (XCDR (this_entry))
5433 || !SYMBOLP (XCAR (XCDR (this_entry))))
5434 continue;
5435
5436 x_charset = XCAR (this_entry);
5437 w32_charset = XCAR (XCDR (this_entry));
5438 codepage = XCDR (XCDR (this_entry));
5439
5440 if (!strchr (SDATA (x_charset), '-'))
5441 continue;
5442
5443 /* Look for Same charset and a valid codepage (or non-int
5444 which means ignore). */
5445 if (EQ (w32_charset, charset_type)
5446 && (!INTEGERP (codepage) || XINT (codepage) == CP_DEFAULT
5447 || IsValidCodePage (XINT (codepage))))
5448 {
5449 retval = Fcons (x_charset, retval);
5450 }
5451 }
5452
5453 /* If no match, encode the numeric value. */
5454 if (NILP (retval))
5455 {
5456 sprintf (buf, "*-#%u", fncharset);
5457 return Fcons (build_string (buf), Qnil);
5458 }
5459
5460 return retval;
5461 }
5462 }
5463
5464 #if OLD_FONT
5465
5466 /* Get the Windows codepage corresponding to the specified font. The
5467 charset info in the font name is used to look up
5468 w32-charset-to-codepage-alist. */
5469 int
5470 w32_codepage_for_font (char *fontname)
5471 {
5472 Lisp_Object codepage, entry;
5473 char *charset_str, *charset, *end;
5474
5475 /* Extract charset part of font string. */
5476 charset = xlfd_charset_of_font (fontname);
5477
5478 if (!charset)
5479 return CP_UNKNOWN;
5480
5481 charset_str = (char *) alloca (strlen (charset) + 1);
5482 strcpy (charset_str, charset);
5483
5484 #if 0
5485 /* Remove leading "*-". */
5486 if (strncmp ("*-", charset_str, 2) == 0)
5487 charset = charset_str + 2;
5488 else
5489 #endif
5490 charset = charset_str;
5491
5492 /* Stop match at wildcard (including preceding '-'). */
5493 if (end = strchr (charset, '*'))
5494 {
5495 if (end > charset && *(end-1) == '-')
5496 end--;
5497 *end = '\0';
5498 }
5499
5500 if (!strcmp (charset, "iso10646"))
5501 return CP_UNICODE;
5502
5503 if (NILP (Vw32_charset_info_alist))
5504 return CP_DEFAULT;
5505
5506 entry = Fassoc (build_string(charset), Vw32_charset_info_alist);
5507 if (NILP (entry))
5508 return CP_UNKNOWN;
5509
5510 codepage = Fcdr (Fcdr (entry));
5511
5512 if (NILP (codepage))
5513 return CP_8BIT;
5514 else if (XFASTINT (codepage) == XFASTINT (Qt))
5515 return CP_UNICODE;
5516 else if (INTEGERP (codepage))
5517 return XINT (codepage);
5518 else
5519 return CP_UNKNOWN;
5520 }
5521 #endif /* OLD_FONT */
5522
5523 static BOOL
5524 w32_to_x_font (lplogfont, lpxstr, len, specific_charset)
5525 LOGFONT * lplogfont;
5526 char * lpxstr;
5527 int len;
5528 char * specific_charset;
5529 {
5530 char* fonttype;
5531 char *fontname;
5532 char height_pixels[8];
5533 char height_dpi[8];
5534 char width_pixels[8];
5535 char *fontname_dash;
5536 int display_resy = (int) one_w32_display_info.resy;
5537 int display_resx = (int) one_w32_display_info.resx;
5538 struct coding_system coding;
5539
5540 if (!lpxstr) abort ();
5541
5542 if (!lplogfont)
5543 return FALSE;
5544
5545 if (lplogfont->lfOutPrecision == OUT_STRING_PRECIS)
5546 fonttype = "raster";
5547 else if (lplogfont->lfOutPrecision == OUT_STROKE_PRECIS)
5548 fonttype = "outline";
5549 else
5550 fonttype = "unknown";
5551
5552 setup_coding_system (Fcheck_coding_system (Vlocale_coding_system),
5553 &coding);
5554 coding.src_multibyte = 0;
5555 coding.dst_multibyte = 1;
5556 coding.mode |= CODING_MODE_LAST_BLOCK;
5557 /* We explicitely disable composition handling because selection
5558 data should not contain any composition sequence. */
5559 coding.common_flags &= ~CODING_ANNOTATION_MASK;
5560
5561 coding.dst_bytes = LF_FACESIZE * 2;
5562 coding.destination = (unsigned char *) xmalloc (coding.dst_bytes + 1);
5563 decode_coding_c_string (&coding, lplogfont->lfFaceName,
5564 strlen(lplogfont->lfFaceName), Qnil);
5565 fontname = coding.destination;
5566
5567 *(fontname + coding.produced) = '\0';
5568
5569 /* Replace dashes with underscores so the dashes are not
5570 misinterpreted. */
5571 fontname_dash = fontname;
5572 while (fontname_dash = strchr (fontname_dash, '-'))
5573 *fontname_dash = '_';
5574
5575 if (lplogfont->lfHeight)
5576 {
5577 sprintf (height_pixels, "%u", eabs (lplogfont->lfHeight));
5578 sprintf (height_dpi, "%u",
5579 eabs (lplogfont->lfHeight) * 720 / display_resy);
5580 }
5581 else
5582 {
5583 strcpy (height_pixels, "*");
5584 strcpy (height_dpi, "*");
5585 }
5586
5587 #if 0 /* Never put the width in the xlfd. It fails on fonts with
5588 double-width characters. */
5589 if (lplogfont->lfWidth)
5590 sprintf (width_pixels, "%u", lplogfont->lfWidth * 10);
5591 else
5592 #endif
5593 strcpy (width_pixels, "*");
5594
5595 _snprintf (lpxstr, len - 1,
5596 "-%s-%s-%s-%c-normal-normal-%s-%s-%d-%d-%c-%s-%s",
5597 fonttype, /* foundry */
5598 fontname, /* family */
5599 w32_to_x_weight (lplogfont->lfWeight), /* weight */
5600 lplogfont->lfItalic?'i':'r', /* slant */
5601 /* setwidth name */
5602 /* add style name */
5603 height_pixels, /* pixel size */
5604 height_dpi, /* point size */
5605 display_resx, /* resx */
5606 display_resy, /* resy */
5607 ((lplogfont->lfPitchAndFamily & 0x3) == VARIABLE_PITCH)
5608 ? 'p' : 'c', /* spacing */
5609 width_pixels, /* avg width */
5610 w32_to_x_charset (lplogfont->lfCharSet, specific_charset)
5611 /* charset registry and encoding */
5612 );
5613
5614 lpxstr[len - 1] = 0; /* just to be sure */
5615 return (TRUE);
5616 }
5617
5618 static BOOL
5619 x_to_w32_font (lpxstr, lplogfont)
5620 char * lpxstr;
5621 LOGFONT * lplogfont;
5622 {
5623 struct coding_system coding;
5624
5625 if (!lplogfont) return (FALSE);
5626
5627 memset (lplogfont, 0, sizeof (*lplogfont));
5628
5629 /* Set default value for each field. */
5630 #if 1
5631 lplogfont->lfOutPrecision = OUT_DEFAULT_PRECIS;
5632 lplogfont->lfClipPrecision = CLIP_DEFAULT_PRECIS;
5633 lplogfont->lfQuality = DEFAULT_QUALITY;
5634 #else
5635 /* go for maximum quality */
5636 lplogfont->lfOutPrecision = OUT_STROKE_PRECIS;
5637 lplogfont->lfClipPrecision = CLIP_STROKE_PRECIS;
5638 lplogfont->lfQuality = PROOF_QUALITY;
5639 #endif
5640
5641 lplogfont->lfCharSet = DEFAULT_CHARSET;
5642 lplogfont->lfWeight = FW_DONTCARE;
5643 lplogfont->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
5644
5645 if (!lpxstr)
5646 return FALSE;
5647
5648 /* Provide a simple escape mechanism for specifying Windows font names
5649 * directly -- if font spec does not beginning with '-', assume this
5650 * format:
5651 * "<font name>[:height in pixels[:width in pixels[:weight]]]"
5652 */
5653
5654 if (*lpxstr == '-')
5655 {
5656 int fields, tem;
5657 char name[50], weight[20], slant, pitch, pixels[10], height[10],
5658 width[10], resy[10], remainder[50];
5659 char * encoding;
5660 int dpi = (int) one_w32_display_info.resy;
5661
5662 fields = sscanf (lpxstr,
5663 "-%*[^-]-%49[^-]-%19[^-]-%c-%*[^-]-%*[^-]-%9[^-]-%9[^-]-%*[^-]-%9[^-]-%c-%9[^-]-%49s",
5664 name, weight, &slant, pixels, height, resy, &pitch, width, remainder);
5665 if (fields == EOF)
5666 return (FALSE);
5667
5668 /* In the general case when wildcards cover more than one field,
5669 we don't know which field is which, so don't fill any in.
5670 However, we need to cope with this particular form, which is
5671 generated by font_list_1 (invoked by try_font_list):
5672 "-raster-6x10-*-gb2312*-*"
5673 and make sure to correctly parse the charset field. */
5674 if (fields == 3)
5675 {
5676 fields = sscanf (lpxstr,
5677 "-%*[^-]-%49[^-]-*-%49s",
5678 name, remainder);
5679 }
5680 else if (fields < 9)
5681 {
5682 fields = 0;
5683 remainder[0] = 0;
5684 }
5685
5686 if (fields > 0 && name[0] != '*')
5687 {
5688 Lisp_Object string = build_string (name);
5689 setup_coding_system
5690 (Fcheck_coding_system (Vlocale_coding_system), &coding);
5691 coding.mode |= (CODING_MODE_SAFE_ENCODING | CODING_MODE_LAST_BLOCK);
5692 /* Disable composition/charset annotation. */
5693 coding.common_flags &= ~CODING_ANNOTATION_MASK;
5694 coding.dst_bytes = SCHARS (string) * 2;
5695
5696 coding.destination = (unsigned char *) xmalloc (coding.dst_bytes);
5697 encode_coding_object (&coding, string, 0, 0,
5698 SCHARS (string), SBYTES (string), Qnil);
5699 if (coding.produced >= LF_FACESIZE)
5700 coding.produced = LF_FACESIZE - 1;
5701
5702 coding.destination[coding.produced] = '\0';
5703
5704 strcpy (lplogfont->lfFaceName, coding.destination);
5705 xfree (coding.destination);
5706 }
5707 else
5708 {
5709 lplogfont->lfFaceName[0] = '\0';
5710 }
5711
5712 fields--;
5713
5714 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5715
5716 fields--;
5717
5718 lplogfont->lfItalic = (fields > 0 && slant == 'i');
5719
5720 fields--;
5721
5722 if (fields > 0 && pixels[0] != '*')
5723 lplogfont->lfHeight = atoi (pixels);
5724
5725 fields--;
5726 fields--;
5727 if (fields > 0 && resy[0] != '*')
5728 {
5729 tem = atoi (resy);
5730 if (tem > 0) dpi = tem;
5731 }
5732
5733 if (fields > -1 && lplogfont->lfHeight == 0 && height[0] != '*')
5734 lplogfont->lfHeight = atoi (height) * dpi / 720;
5735
5736 if (fields > 0)
5737 {
5738 if (pitch == 'p')
5739 lplogfont->lfPitchAndFamily = VARIABLE_PITCH | FF_DONTCARE;
5740 else if (pitch == 'c')
5741 lplogfont->lfPitchAndFamily = FIXED_PITCH | FF_DONTCARE;
5742 }
5743
5744 fields--;
5745
5746 if (fields > 0 && width[0] != '*')
5747 lplogfont->lfWidth = atoi (width) / 10;
5748
5749 fields--;
5750
5751 /* Strip the trailing '-' if present. (it shouldn't be, as it
5752 fails the test against xlfd-tight-regexp in fontset.el). */
5753 {
5754 int len = strlen (remainder);
5755 if (len > 0 && remainder[len-1] == '-')
5756 remainder[len-1] = 0;
5757 }
5758 encoding = remainder;
5759 #if 0
5760 if (strncmp (encoding, "*-", 2) == 0)
5761 encoding += 2;
5762 #endif
5763 lplogfont->lfCharSet = x_to_w32_charset (encoding);
5764 }
5765 else
5766 {
5767 int fields;
5768 char name[100], height[10], width[10], weight[20];
5769
5770 fields = sscanf (lpxstr,
5771 "%99[^:]:%9[^:]:%9[^:]:%19s",
5772 name, height, width, weight);
5773
5774 if (fields == EOF) return (FALSE);
5775
5776 if (fields > 0)
5777 {
5778 strncpy (lplogfont->lfFaceName, name, LF_FACESIZE);
5779 lplogfont->lfFaceName[LF_FACESIZE-1] = 0;
5780 }
5781 else
5782 {
5783 lplogfont->lfFaceName[0] = 0;
5784 }
5785
5786 fields--;
5787
5788 if (fields > 0)
5789 lplogfont->lfHeight = atoi (height);
5790
5791 fields--;
5792
5793 if (fields > 0)
5794 lplogfont->lfWidth = atoi (width);
5795
5796 fields--;
5797
5798 lplogfont->lfWeight = x_to_w32_weight ((fields > 0 ? weight : ""));
5799 }
5800
5801 /* This makes TrueType fonts work better. */
5802 lplogfont->lfHeight = - eabs (lplogfont->lfHeight);
5803
5804 return (TRUE);
5805 }
5806
5807 #if OLD_FONT
5808
5809 /* Strip the pixel height and point height from the given xlfd, and
5810 return the pixel height. If no pixel height is specified, calculate
5811 one from the point height, or if that isn't defined either, return
5812 0 (which usually signifies a scalable font).
5813 */
5814 static int
5815 xlfd_strip_height (char *fontname)
5816 {
5817 int pixel_height, field_number;
5818 char *read_from, *write_to;
5819
5820 xassert (fontname);
5821
5822 pixel_height = field_number = 0;
5823 write_to = NULL;
5824
5825 /* Look for height fields. */
5826 for (read_from = fontname; *read_from; read_from++)
5827 {
5828 if (*read_from == '-')
5829 {
5830 field_number++;
5831 if (field_number == 7) /* Pixel height. */
5832 {
5833 read_from++;
5834 write_to = read_from;
5835
5836 /* Find end of field. */
5837 for (;*read_from && *read_from != '-'; read_from++)
5838 ;
5839
5840 /* Split the fontname at end of field. */
5841 if (*read_from)
5842 {
5843 *read_from = '\0';
5844 read_from++;
5845 }
5846 pixel_height = atoi (write_to);
5847 /* Blank out field. */
5848 if (read_from > write_to)
5849 {
5850 *write_to = '-';
5851 write_to++;
5852 }
5853 /* If the pixel height field is at the end (partial xlfd),
5854 return now. */
5855 else
5856 return pixel_height;
5857
5858 /* If we got a pixel height, the point height can be
5859 ignored. Just blank it out and break now. */
5860 if (pixel_height)
5861 {
5862 /* Find end of point size field. */
5863 for (; *read_from && *read_from != '-'; read_from++)
5864 ;
5865
5866 if (*read_from)
5867 read_from++;
5868
5869 /* Blank out the point size field. */
5870 if (read_from > write_to)
5871 {
5872 *write_to = '-';
5873 write_to++;
5874 }
5875 else
5876 return pixel_height;
5877
5878 break;
5879 }
5880 /* If the point height is already blank, break now. */
5881 if (*read_from == '-')
5882 {
5883 read_from++;
5884 break;
5885 }
5886 }
5887 else if (field_number == 8)
5888 {
5889 /* If we didn't get a pixel height, try to get the point
5890 height and convert that. */
5891 int point_size;
5892 char *point_size_start = read_from++;
5893
5894 /* Find end of field. */
5895 for (; *read_from && *read_from != '-'; read_from++)
5896 ;
5897
5898 if (*read_from)
5899 {
5900 *read_from = '\0';
5901 read_from++;
5902 }
5903
5904 point_size = atoi (point_size_start);
5905
5906 /* Convert to pixel height. */
5907 pixel_height = point_size
5908 * one_w32_display_info.height_in / 720;
5909
5910 /* Blank out this field and break. */
5911 *write_to = '-';
5912 write_to++;
5913 break;
5914 }
5915 }
5916 }
5917
5918 /* Shift the rest of the font spec into place. */
5919 if (write_to && read_from > write_to)
5920 {
5921 for (; *read_from; read_from++, write_to++)
5922 *write_to = *read_from;
5923 *write_to = '\0';
5924 }
5925
5926 return pixel_height;
5927 }
5928
5929 /* Assume parameter 1 is fully qualified, no wildcards. */
5930 static BOOL
5931 w32_font_match (fontname, pattern)
5932 char * fontname;
5933 char * pattern;
5934 {
5935 char *ptr;
5936 char *font_name_copy;
5937 char *regex = alloca (strlen (pattern) * 2 + 3);
5938
5939 font_name_copy = alloca (strlen (fontname) + 1);
5940 strcpy (font_name_copy, fontname);
5941
5942 ptr = regex;
5943 *ptr++ = '^';
5944
5945 /* Turn pattern into a regexp and do a regexp match. */
5946 for (; *pattern; pattern++)
5947 {
5948 if (*pattern == '?')
5949 *ptr++ = '.';
5950 else if (*pattern == '*')
5951 {
5952 *ptr++ = '.';
5953 *ptr++ = '*';
5954 }
5955 else
5956 *ptr++ = *pattern;
5957 }
5958 *ptr = '$';
5959 *(ptr + 1) = '\0';
5960
5961 /* Strip out font heights and compare them seperately, since
5962 rounding error can cause mismatches. This also allows a
5963 comparison between a font that declares only a pixel height and a
5964 pattern that declares the point height.
5965 */
5966 {
5967 int font_height, pattern_height;
5968
5969 font_height = xlfd_strip_height (font_name_copy);
5970 pattern_height = xlfd_strip_height (regex);
5971
5972 /* Compare now, and don't bother doing expensive regexp matching
5973 if the heights differ. */
5974 if (font_height && pattern_height && (font_height != pattern_height))
5975 return FALSE;
5976 }
5977
5978 return (fast_string_match_ignore_case (build_string (regex),
5979 build_string (font_name_copy)) >= 0);
5980 }
5981
5982 /* Callback functions, and a structure holding info they need, for
5983 listing system fonts on W32. We need one set of functions to do the
5984 job properly, but these don't work on NT 3.51 and earlier, so we
5985 have a second set which don't handle character sets properly to
5986 fall back on.
5987
5988 In both cases, there are two passes made. The first pass gets one
5989 font from each family, the second pass lists all the fonts from
5990 each family. */
5991
5992 typedef struct enumfont_t
5993 {
5994 HDC hdc;
5995 int numFonts;
5996 LOGFONT logfont;
5997 XFontStruct *size_ref;
5998 Lisp_Object pattern;
5999 Lisp_Object list;
6000 } enumfont_t;
6001
6002
6003 static void
6004 enum_font_maybe_add_to_list (enumfont_t *, LOGFONT *, char *, Lisp_Object);
6005
6006
6007 static int CALLBACK
6008 enum_font_cb2 (lplf, lptm, FontType, lpef)
6009 ENUMLOGFONT * lplf;
6010 NEWTEXTMETRIC * lptm;
6011 int FontType;
6012 enumfont_t * lpef;
6013 {
6014 /* Ignore struck out and underlined versions of fonts. */
6015 if (lplf->elfLogFont.lfStrikeOut || lplf->elfLogFont.lfUnderline)
6016 return 1;
6017
6018 /* Only return fonts with names starting with @ if they were
6019 explicitly specified, since Microsoft uses an initial @ to
6020 denote fonts for vertical writing, without providing a more
6021 convenient way of identifying them. */
6022 if (lplf->elfLogFont.lfFaceName[0] == '@'
6023 && lpef->logfont.lfFaceName[0] != '@')
6024 return 1;
6025
6026 /* Check that the character set matches if it was specified */
6027 if (lpef->logfont.lfCharSet != DEFAULT_CHARSET &&
6028 lplf->elfLogFont.lfCharSet != lpef->logfont.lfCharSet)
6029 return 1;
6030
6031 if (FontType == RASTER_FONTTYPE)
6032 {
6033 /* DBCS raster fonts have problems displaying, so skip them. */
6034 int charset = lplf->elfLogFont.lfCharSet;
6035 if (charset == SHIFTJIS_CHARSET
6036 || charset == HANGEUL_CHARSET
6037 || charset == CHINESEBIG5_CHARSET
6038 || charset == GB2312_CHARSET
6039 #ifdef JOHAB_CHARSET
6040 || charset == JOHAB_CHARSET
6041 #endif
6042 )
6043 return 1;
6044 }
6045
6046 {
6047 char buf[100];
6048 Lisp_Object width = Qnil;
6049 Lisp_Object charset_list = Qnil;
6050 char *charset = NULL;
6051
6052 /* Truetype fonts do not report their true metrics until loaded */
6053 if (FontType != RASTER_FONTTYPE)
6054 {
6055 if (!NILP (lpef->pattern))
6056 {
6057 /* Scalable fonts are as big as you want them to be. */
6058 lplf->elfLogFont.lfHeight = lpef->logfont.lfHeight;
6059 lplf->elfLogFont.lfWidth = lpef->logfont.lfWidth;
6060 width = make_number (lpef->logfont.lfWidth);
6061 }
6062 else
6063 {
6064 lplf->elfLogFont.lfHeight = 0;
6065 lplf->elfLogFont.lfWidth = 0;
6066 }
6067 }
6068
6069 /* Make sure the height used here is the same as everywhere
6070 else (ie character height, not cell height). */
6071 if (lplf->elfLogFont.lfHeight > 0)
6072 {
6073 /* lptm can be trusted for RASTER fonts, but not scalable ones. */
6074 if (FontType == RASTER_FONTTYPE)
6075 lplf->elfLogFont.lfHeight = lptm->tmInternalLeading - lptm->tmHeight;
6076 else
6077 lplf->elfLogFont.lfHeight = -lplf->elfLogFont.lfHeight;
6078 }
6079
6080 if (!NILP (lpef->pattern))
6081 {
6082 charset = xlfd_charset_of_font (SDATA (lpef->pattern));
6083
6084 /* We already checked charsets above, but DEFAULT_CHARSET
6085 slipped through. So only allow exact matches for DEFAULT_CHARSET. */
6086 if (charset
6087 && strncmp (charset, "*-*", 3) != 0
6088 && lpef->logfont.lfCharSet == DEFAULT_CHARSET
6089 && strcmp (charset, w32_to_x_charset (DEFAULT_CHARSET, NULL)) != 0)
6090 return 1;
6091
6092 /* Reject raster fonts if we are looking for a unicode font. */
6093 if (charset
6094 && FontType == RASTER_FONTTYPE
6095 && strncmp (charset, "iso10646", 8) == 0)
6096 return 1;
6097 }
6098
6099 if (charset)
6100 charset_list = Fcons (build_string (charset), Qnil);
6101 else
6102 /* Always prefer unicode. */
6103 charset_list
6104 = Fcons (build_string ("iso10646-1"),
6105 w32_to_all_x_charsets (lplf->elfLogFont.lfCharSet));
6106
6107 /* Loop through the charsets. */
6108 for ( ; CONSP (charset_list); charset_list = Fcdr (charset_list))
6109 {
6110 Lisp_Object this_charset = Fcar (charset_list);
6111 charset = SDATA (this_charset);
6112
6113 /* Don't list raster fonts as unicode. */
6114 if (charset
6115 && FontType == RASTER_FONTTYPE
6116 && strncmp (charset, "iso10646", 8) == 0)
6117 continue;
6118
6119 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
6120 charset, width);
6121
6122 /* List bold and italic variations if w32-enable-synthesized-fonts
6123 is non-nil and this is a plain font. */
6124 if (w32_enable_synthesized_fonts
6125 && lplf->elfLogFont.lfWeight == FW_NORMAL
6126 && lplf->elfLogFont.lfItalic == FALSE)
6127 {
6128 /* bold. */
6129 lplf->elfLogFont.lfWeight = FW_BOLD;
6130 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
6131 charset, width);
6132 /* bold italic. */
6133 lplf->elfLogFont.lfItalic = TRUE;
6134 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
6135 charset, width);
6136 /* italic. */
6137 lplf->elfLogFont.lfWeight = FW_NORMAL;
6138 enum_font_maybe_add_to_list (lpef, &(lplf->elfLogFont),
6139 charset, width);
6140 }
6141 }
6142 }
6143
6144 return 1;
6145 }
6146
6147 static void
6148 enum_font_maybe_add_to_list (lpef, logfont, match_charset, width)
6149 enumfont_t * lpef;
6150 LOGFONT * logfont;
6151 char * match_charset;
6152 Lisp_Object width;
6153 {
6154 char buf[100];
6155
6156 if (!w32_to_x_font (logfont, buf, 100, match_charset))
6157 return;
6158
6159 if (NILP (lpef->pattern)
6160 || w32_font_match (buf, SDATA (lpef->pattern)))
6161 {
6162 /* Check if we already listed this font. This may happen if
6163 w32_enable_synthesized_fonts is non-nil, and there are real
6164 bold and italic versions of the font. */
6165 Lisp_Object font_name = build_string (buf);
6166 if (NILP (Fmember (font_name, lpef->list)))
6167 {
6168 Lisp_Object entry = Fcons (font_name, width);
6169 lpef->list = Fcons (entry, lpef->list);
6170 lpef->numFonts++;
6171 }
6172 }
6173 }
6174
6175
6176 static int CALLBACK
6177 enum_font_cb1 (lplf, lptm, FontType, lpef)
6178 ENUMLOGFONT * lplf;
6179 NEWTEXTMETRIC * lptm;
6180 int FontType;
6181 enumfont_t * lpef;
6182 {
6183 return EnumFontFamilies (lpef->hdc,
6184 lplf->elfLogFont.lfFaceName,
6185 (FONTENUMPROC) enum_font_cb2,
6186 (LPARAM) lpef);
6187 }
6188
6189
6190 static int CALLBACK
6191 enum_fontex_cb2 (lplf, lptm, font_type, lpef)
6192 ENUMLOGFONTEX * lplf;
6193 NEWTEXTMETRICEX * lptm;
6194 int font_type;
6195 enumfont_t * lpef;
6196 {
6197 /* We are not interested in the extra info we get back from the 'Ex
6198 version - only the fact that we get character set variations
6199 enumerated seperately. */
6200 return enum_font_cb2 ((ENUMLOGFONT *) lplf, (NEWTEXTMETRIC *) lptm,
6201 font_type, lpef);
6202 }
6203
6204 static int CALLBACK
6205 enum_fontex_cb1 (lplf, lptm, font_type, lpef)
6206 ENUMLOGFONTEX * lplf;
6207 NEWTEXTMETRICEX * lptm;
6208 int font_type;
6209 enumfont_t * lpef;
6210 {
6211 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6212 FARPROC enum_font_families_ex
6213 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6214 /* We don't really expect EnumFontFamiliesEx to disappear once we
6215 get here, so don't bother handling it gracefully. */
6216 if (enum_font_families_ex == NULL)
6217 error ("gdi32.dll has disappeared!");
6218 return enum_font_families_ex (lpef->hdc,
6219 &lplf->elfLogFont,
6220 (FONTENUMPROC) enum_fontex_cb2,
6221 (LPARAM) lpef, 0);
6222 }
6223
6224 /* Interface to fontset handler. (adapted from mw32font.c in Meadow
6225 and xterm.c in Emacs 20.3) */
6226
6227 static Lisp_Object
6228 w32_list_bdf_fonts (Lisp_Object pattern, int max_names)
6229 {
6230 char *fontname, *ptnstr;
6231 Lisp_Object list, tem, newlist = Qnil;
6232 int n_fonts = 0;
6233
6234 list = Vw32_bdf_filename_alist;
6235 ptnstr = SDATA (pattern);
6236
6237 for ( ; CONSP (list); list = XCDR (list))
6238 {
6239 tem = XCAR (list);
6240 if (CONSP (tem))
6241 fontname = SDATA (XCAR (tem));
6242 else if (STRINGP (tem))
6243 fontname = SDATA (tem);
6244 else
6245 continue;
6246
6247 if (w32_font_match (fontname, ptnstr))
6248 {
6249 newlist = Fcons (XCAR (tem), newlist);
6250 n_fonts++;
6251 if (max_names >= 0 && n_fonts >= max_names)
6252 break;
6253 }
6254 }
6255
6256 return newlist;
6257 }
6258
6259
6260 /* Return a list of names of available fonts matching PATTERN on frame
6261 F. If SIZE is not 0, it is the size (maximum bound width) of fonts
6262 to be listed. Frame F NULL means we have not yet created any
6263 frame, which means we can't get proper size info, as we don't have
6264 a device context to use for GetTextMetrics.
6265 MAXNAMES sets a limit on how many fonts to match. If MAXNAMES is
6266 negative, then all matching fonts are returned. */
6267
6268 Lisp_Object
6269 w32_list_fonts (f, pattern, size, maxnames)
6270 struct frame *f;
6271 Lisp_Object pattern;
6272 int size;
6273 int maxnames;
6274 {
6275 Lisp_Object patterns, key = Qnil, tem, tpat;
6276 Lisp_Object list = Qnil, newlist = Qnil, second_best = Qnil;
6277 struct w32_display_info *dpyinfo = &one_w32_display_info;
6278 int n_fonts = 0;
6279
6280 patterns = Fassoc (pattern, Valternate_fontname_alist);
6281 if (NILP (patterns))
6282 patterns = Fcons (pattern, Qnil);
6283
6284 for (; CONSP (patterns); patterns = XCDR (patterns))
6285 {
6286 enumfont_t ef;
6287 int codepage;
6288
6289 tpat = XCAR (patterns);
6290
6291 if (!STRINGP (tpat))
6292 continue;
6293
6294 /* Avoid expensive EnumFontFamilies functions if we are not
6295 going to be able to output one of these anyway. */
6296 codepage = w32_codepage_for_font (SDATA (tpat));
6297 if (codepage != CP_8BIT && codepage != CP_UNICODE
6298 && codepage != CP_DEFAULT && codepage != CP_UNKNOWN
6299 && !IsValidCodePage (codepage))
6300 continue;
6301
6302 /* See if we cached the result for this particular query.
6303 The cache is an alist of the form:
6304 ((PATTERN (FONTNAME . WIDTH) ...) ...)
6305 */
6306 if (tem = XCDR (dpyinfo->name_list_element),
6307 !NILP (list = Fassoc (tpat, tem)))
6308 {
6309 list = Fcdr_safe (list);
6310 /* We have a cached list. Don't have to get the list again. */
6311 goto label_cached;
6312 }
6313
6314 BLOCK_INPUT;
6315 /* At first, put PATTERN in the cache. */
6316 ef.pattern = tpat;
6317 ef.list = Qnil;
6318 ef.numFonts = 0;
6319
6320 /* Use EnumFontFamiliesEx where it is available, as it knows
6321 about character sets. Fall back to EnumFontFamilies for
6322 older versions of NT that don't support the 'Ex function. */
6323 x_to_w32_font (SDATA (tpat), &ef.logfont);
6324 {
6325 LOGFONT font_match_pattern;
6326 HMODULE gdi32 = GetModuleHandle ("gdi32.dll");
6327 FARPROC enum_font_families_ex
6328 = GetProcAddress ( gdi32, "EnumFontFamiliesExA");
6329
6330 /* We do our own pattern matching so we can handle wildcards. */
6331 font_match_pattern.lfFaceName[0] = 0;
6332 font_match_pattern.lfPitchAndFamily = 0;
6333 /* We can use the charset, because if it is a wildcard it will
6334 be DEFAULT_CHARSET anyway. */
6335 font_match_pattern.lfCharSet = ef.logfont.lfCharSet;
6336
6337 ef.hdc = GetDC (dpyinfo->root_window);
6338
6339 if (enum_font_families_ex)
6340 enum_font_families_ex (ef.hdc,
6341 &font_match_pattern,
6342 (FONTENUMPROC) enum_fontex_cb1,
6343 (LPARAM) &ef, 0);
6344 else
6345 EnumFontFamilies (ef.hdc, NULL, (FONTENUMPROC) enum_font_cb1,
6346 (LPARAM)&ef);
6347
6348 ReleaseDC (dpyinfo->root_window, ef.hdc);
6349 }
6350
6351 UNBLOCK_INPUT;
6352 list = ef.list;
6353
6354 /* Make a list of the fonts we got back.
6355 Store that in the font cache for the display. */
6356 XSETCDR (dpyinfo->name_list_element,
6357 Fcons (Fcons (tpat, list),
6358 XCDR (dpyinfo->name_list_element)));
6359
6360 label_cached:
6361 if (NILP (list)) continue; /* Try the remaining alternatives. */
6362
6363 newlist = second_best = Qnil;
6364
6365 /* Make a list of the fonts that have the right width. */
6366 for (; CONSP (list); list = XCDR (list))
6367 {
6368 int found_size;
6369 tem = XCAR (list);
6370
6371 if (!CONSP (tem))
6372 continue;
6373 if (NILP (XCAR (tem)))
6374 continue;
6375 if (!size)
6376 {
6377 newlist = Fcons (XCAR (tem), newlist);
6378 n_fonts++;
6379 if (maxnames >= 0 && n_fonts >= maxnames)
6380 break;
6381 else
6382 continue;
6383 }
6384 if (!INTEGERP (XCDR (tem)))
6385 {
6386 /* Since we don't yet know the size of the font, we must
6387 load it and try GetTextMetrics. */
6388 W32FontStruct thisinfo;
6389 LOGFONT lf;
6390 HDC hdc;
6391 HANDLE oldobj;
6392
6393 if (!x_to_w32_font (SDATA (XCAR (tem)), &lf))
6394 continue;
6395
6396 BLOCK_INPUT;
6397 thisinfo.bdf = NULL;
6398 thisinfo.hfont = CreateFontIndirect (&lf);
6399 if (thisinfo.hfont == NULL)
6400 continue;
6401
6402 hdc = GetDC (dpyinfo->root_window);
6403 oldobj = SelectObject (hdc, thisinfo.hfont);
6404 if (GetTextMetrics (hdc, &thisinfo.tm))
6405 XSETCDR (tem, make_number (FONT_AVG_WIDTH (&thisinfo)));
6406 else
6407 XSETCDR (tem, make_number (0));
6408 SelectObject (hdc, oldobj);
6409 ReleaseDC (dpyinfo->root_window, hdc);
6410 DeleteObject (thisinfo.hfont);
6411 UNBLOCK_INPUT;
6412 }
6413 found_size = XINT (XCDR (tem));
6414 if (found_size == size)
6415 {
6416 newlist = Fcons (XCAR (tem), newlist);
6417 n_fonts++;
6418 if (maxnames >= 0 && n_fonts >= maxnames)
6419 break;
6420 }
6421 /* keep track of the closest matching size in case
6422 no exact match is found. */
6423 else if (found_size > 0)
6424 {
6425 if (NILP (second_best))
6426 second_best = tem;
6427
6428 else if (found_size < size)
6429 {
6430 if (XINT (XCDR (second_best)) > size
6431 || XINT (XCDR (second_best)) < found_size)
6432 second_best = tem;
6433 }
6434 else
6435 {
6436 if (XINT (XCDR (second_best)) > size
6437 && XINT (XCDR (second_best)) >
6438 found_size)
6439 second_best = tem;
6440 }
6441 }
6442 }
6443
6444 if (!NILP (newlist))
6445 break;
6446 else if (!NILP (second_best))
6447 {
6448 newlist = Fcons (XCAR (second_best), Qnil);
6449 break;
6450 }
6451 }
6452
6453 /* Include any bdf fonts. */
6454 if (n_fonts < maxnames || maxnames < 0)
6455 {
6456 Lisp_Object combined[2];
6457 combined[0] = w32_list_bdf_fonts (pattern, maxnames - n_fonts);
6458 combined[1] = newlist;
6459 newlist = Fnconc (2, combined);
6460 }
6461
6462 return newlist;
6463 }
6464
6465
6466 /* Return a pointer to struct font_info of font FONT_IDX of frame F. */
6467 struct font_info *
6468 w32_get_font_info (f, font_idx)
6469 FRAME_PTR f;
6470 int font_idx;
6471 {
6472 return (FRAME_W32_FONT_TABLE (f) + font_idx);
6473 }
6474
6475
6476 struct font_info*
6477 w32_query_font (struct frame *f, char *fontname)
6478 {
6479 int i;
6480 struct font_info *pfi;
6481
6482 pfi = FRAME_W32_FONT_TABLE (f);
6483
6484 for (i = 0; i < one_w32_display_info.n_fonts ;i++, pfi++)
6485 {
6486 if (xstrcasecmp (pfi->name, fontname) == 0) return pfi;
6487 }
6488
6489 return NULL;
6490 }
6491
6492 /* Find a CCL program for a font specified by FONTP, and set the member
6493 `encoder' of the structure. */
6494
6495 void
6496 w32_find_ccl_program (fontp)
6497 struct font_info *fontp;
6498 {
6499 Lisp_Object list, elt;
6500
6501 for (list = Vfont_ccl_encoder_alist; CONSP (list); list = XCDR (list))
6502 {
6503 elt = XCAR (list);
6504 if (CONSP (elt)
6505 && STRINGP (XCAR (elt))
6506 && (fast_c_string_match_ignore_case (XCAR (elt), fontp->name)
6507 >= 0))
6508 break;
6509 }
6510 if (! NILP (list))
6511 {
6512 struct ccl_program *ccl
6513 = (struct ccl_program *) xmalloc (sizeof (struct ccl_program));
6514
6515 if (setup_ccl_program (ccl, XCDR (elt)) < 0)
6516 xfree (ccl);
6517 else
6518 fontp->font_encoder = ccl;
6519 }
6520 }
6521
6522 #endif /* OLD_FONT */
6523
6524 /* directory-files from dired.c. */
6525 Lisp_Object Fdirectory_files P_ ((Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object));
6526
6527 \f
6528 #if OLD_FONT
6529
6530 /* Find BDF files in a specified directory. (use GCPRO when calling,
6531 as this calls lisp to get a directory listing). */
6532 static Lisp_Object
6533 w32_find_bdf_fonts_in_dir (Lisp_Object directory)
6534 {
6535 Lisp_Object filelist, list = Qnil;
6536 char fontname[100];
6537
6538 if (!STRINGP (directory))
6539 return Qnil;
6540
6541 filelist = Fdirectory_files (directory, Qt,
6542 build_string (".*\\.[bB][dD][fF]"), Qt);
6543
6544 for ( ; CONSP (filelist); filelist = XCDR (filelist))
6545 {
6546 Lisp_Object filename = XCAR (filelist);
6547 if (w32_BDF_to_x_font (SDATA (filename), fontname, 100))
6548 store_in_alist (&list, build_string (fontname), filename);
6549 }
6550 return list;
6551 }
6552
6553 DEFUN ("w32-find-bdf-fonts", Fw32_find_bdf_fonts, Sw32_find_bdf_fonts,
6554 1, 1, 0,
6555 doc: /* Return a list of BDF fonts in DIRECTORY.
6556 The list is suitable for appending to `w32-bdf-filename-alist'.
6557 Fonts which do not contain an xlfd description will not be included
6558 in the list. DIRECTORY may be a list of directories. */)
6559 (directory)
6560 Lisp_Object directory;
6561 {
6562 Lisp_Object list = Qnil;
6563 struct gcpro gcpro1, gcpro2;
6564
6565 if (!CONSP (directory))
6566 return w32_find_bdf_fonts_in_dir (directory);
6567
6568 for ( ; CONSP (directory); directory = XCDR (directory))
6569 {
6570 Lisp_Object pair[2];
6571 pair[0] = list;
6572 pair[1] = Qnil;
6573 GCPRO2 (directory, list);
6574 pair[1] = w32_find_bdf_fonts_in_dir ( XCAR (directory) );
6575 list = Fnconc ( 2, pair );
6576 UNGCPRO;
6577 }
6578 return list;
6579 }
6580 #endif /* OLD_FONT */
6581
6582 \f
6583 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
6584 doc: /* Internal function called by `color-defined-p', which see. */)
6585 (color, frame)
6586 Lisp_Object color, frame;
6587 {
6588 XColor foo;
6589 FRAME_PTR f = check_x_frame (frame);
6590
6591 CHECK_STRING (color);
6592
6593 if (w32_defined_color (f, SDATA (color), &foo, 0))
6594 return Qt;
6595 else
6596 return Qnil;
6597 }
6598
6599 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
6600 doc: /* Internal function called by `color-values', which see. */)
6601 (color, frame)
6602 Lisp_Object color, frame;
6603 {
6604 XColor foo;
6605 FRAME_PTR f = check_x_frame (frame);
6606
6607 CHECK_STRING (color);
6608
6609 if (w32_defined_color (f, SDATA (color), &foo, 0))
6610 return list3 (make_number ((GetRValue (foo.pixel) << 8)
6611 | GetRValue (foo.pixel)),
6612 make_number ((GetGValue (foo.pixel) << 8)
6613 | GetGValue (foo.pixel)),
6614 make_number ((GetBValue (foo.pixel) << 8)
6615 | GetBValue (foo.pixel)));
6616 else
6617 return Qnil;
6618 }
6619
6620 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
6621 doc: /* Internal function called by `display-color-p', which see. */)
6622 (display)
6623 Lisp_Object display;
6624 {
6625 struct w32_display_info *dpyinfo = check_x_display_info (display);
6626
6627 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
6628 return Qnil;
6629
6630 return Qt;
6631 }
6632
6633 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
6634 Sx_display_grayscale_p, 0, 1, 0,
6635 doc: /* Return t if DISPLAY supports shades of gray.
6636 Note that color displays do support shades of gray.
6637 The optional argument DISPLAY specifies which display to ask about.
6638 DISPLAY should be either a frame or a display name (a string).
6639 If omitted or nil, that stands for the selected frame's display. */)
6640 (display)
6641 Lisp_Object display;
6642 {
6643 struct w32_display_info *dpyinfo = check_x_display_info (display);
6644
6645 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
6646 return Qnil;
6647
6648 return Qt;
6649 }
6650
6651 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
6652 Sx_display_pixel_width, 0, 1, 0,
6653 doc: /* Return the width in pixels of DISPLAY.
6654 The optional argument DISPLAY specifies which display to ask about.
6655 DISPLAY should be either a frame or a display name (a string).
6656 If omitted or nil, that stands for the selected frame's display. */)
6657 (display)
6658 Lisp_Object display;
6659 {
6660 struct w32_display_info *dpyinfo = check_x_display_info (display);
6661
6662 return make_number (dpyinfo->width);
6663 }
6664
6665 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
6666 Sx_display_pixel_height, 0, 1, 0,
6667 doc: /* Return the height in pixels of DISPLAY.
6668 The optional argument DISPLAY specifies which display to ask about.
6669 DISPLAY should be either a frame or a display name (a string).
6670 If omitted or nil, that stands for the selected frame's display. */)
6671 (display)
6672 Lisp_Object display;
6673 {
6674 struct w32_display_info *dpyinfo = check_x_display_info (display);
6675
6676 return make_number (dpyinfo->height);
6677 }
6678
6679 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
6680 0, 1, 0,
6681 doc: /* Return the number of bitplanes of DISPLAY.
6682 The optional argument DISPLAY specifies which display to ask about.
6683 DISPLAY should be either a frame or a display name (a string).
6684 If omitted or nil, that stands for the selected frame's display. */)
6685 (display)
6686 Lisp_Object display;
6687 {
6688 struct w32_display_info *dpyinfo = check_x_display_info (display);
6689
6690 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
6691 }
6692
6693 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
6694 0, 1, 0,
6695 doc: /* Return the number of color cells of DISPLAY.
6696 The optional argument DISPLAY specifies which display to ask about.
6697 DISPLAY should be either a frame or a display name (a string).
6698 If omitted or nil, that stands for the selected frame's display. */)
6699 (display)
6700 Lisp_Object display;
6701 {
6702 struct w32_display_info *dpyinfo = check_x_display_info (display);
6703 HDC hdc;
6704 int cap;
6705
6706 hdc = GetDC (dpyinfo->root_window);
6707 if (dpyinfo->has_palette)
6708 cap = GetDeviceCaps (hdc, SIZEPALETTE);
6709 else
6710 cap = GetDeviceCaps (hdc, NUMCOLORS);
6711
6712 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
6713 and because probably is more meaningful on Windows anyway */
6714 if (cap < 0)
6715 cap = 1 << min (dpyinfo->n_planes * dpyinfo->n_cbits, 24);
6716
6717 ReleaseDC (dpyinfo->root_window, hdc);
6718
6719 return make_number (cap);
6720 }
6721
6722 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
6723 Sx_server_max_request_size,
6724 0, 1, 0,
6725 doc: /* Return the maximum request size of the server of DISPLAY.
6726 The optional argument DISPLAY specifies which display to ask about.
6727 DISPLAY should be either a frame or a display name (a string).
6728 If omitted or nil, that stands for the selected frame's display. */)
6729 (display)
6730 Lisp_Object display;
6731 {
6732 struct w32_display_info *dpyinfo = check_x_display_info (display);
6733
6734 return make_number (1);
6735 }
6736
6737 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
6738 doc: /* Return the "vendor ID" string of the W32 system (Microsoft).
6739 The optional argument DISPLAY specifies which display to ask about.
6740 DISPLAY should be either a frame or a display name (a string).
6741 If omitted or nil, that stands for the selected frame's display. */)
6742 (display)
6743 Lisp_Object display;
6744 {
6745 return build_string ("Microsoft Corp.");
6746 }
6747
6748 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
6749 doc: /* Return the version numbers of the server of DISPLAY.
6750 The value is a list of three integers: the major and minor
6751 version numbers of the X Protocol in use, and the distributor-specific
6752 release number. See also the function `x-server-vendor'.
6753
6754 The optional argument DISPLAY specifies which display to ask about.
6755 DISPLAY should be either a frame or a display name (a string).
6756 If omitted or nil, that stands for the selected frame's display. */)
6757 (display)
6758 Lisp_Object display;
6759 {
6760 return Fcons (make_number (w32_major_version),
6761 Fcons (make_number (w32_minor_version),
6762 Fcons (make_number (w32_build_number), Qnil)));
6763 }
6764
6765 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
6766 doc: /* Return the number of screens on the server of DISPLAY.
6767 The optional argument DISPLAY specifies which display to ask about.
6768 DISPLAY should be either a frame or a display name (a string).
6769 If omitted or nil, that stands for the selected frame's display. */)
6770 (display)
6771 Lisp_Object display;
6772 {
6773 return make_number (1);
6774 }
6775
6776 DEFUN ("x-display-mm-height", Fx_display_mm_height,
6777 Sx_display_mm_height, 0, 1, 0,
6778 doc: /* Return the height in millimeters of DISPLAY.
6779 The optional argument DISPLAY specifies which display to ask about.
6780 DISPLAY should be either a frame or a display name (a string).
6781 If omitted or nil, that stands for the selected frame's display. */)
6782 (display)
6783 Lisp_Object display;
6784 {
6785 struct w32_display_info *dpyinfo = check_x_display_info (display);
6786 HDC hdc;
6787 int cap;
6788
6789 hdc = GetDC (dpyinfo->root_window);
6790
6791 cap = GetDeviceCaps (hdc, VERTSIZE);
6792
6793 ReleaseDC (dpyinfo->root_window, hdc);
6794
6795 return make_number (cap);
6796 }
6797
6798 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
6799 doc: /* Return the width in millimeters of DISPLAY.
6800 The optional argument DISPLAY specifies which display to ask about.
6801 DISPLAY should be either a frame or a display name (a string).
6802 If omitted or nil, that stands for the selected frame's display. */)
6803 (display)
6804 Lisp_Object display;
6805 {
6806 struct w32_display_info *dpyinfo = check_x_display_info (display);
6807
6808 HDC hdc;
6809 int cap;
6810
6811 hdc = GetDC (dpyinfo->root_window);
6812
6813 cap = GetDeviceCaps (hdc, HORZSIZE);
6814
6815 ReleaseDC (dpyinfo->root_window, hdc);
6816
6817 return make_number (cap);
6818 }
6819
6820 DEFUN ("x-display-backing-store", Fx_display_backing_store,
6821 Sx_display_backing_store, 0, 1, 0,
6822 doc: /* Return an indication of whether DISPLAY does backing store.
6823 The value may be `always', `when-mapped', or `not-useful'.
6824 The optional argument DISPLAY specifies which display to ask about.
6825 DISPLAY should be either a frame or a display name (a string).
6826 If omitted or nil, that stands for the selected frame's display. */)
6827 (display)
6828 Lisp_Object display;
6829 {
6830 return intern ("not-useful");
6831 }
6832
6833 DEFUN ("x-display-visual-class", Fx_display_visual_class,
6834 Sx_display_visual_class, 0, 1, 0,
6835 doc: /* Return the visual class of DISPLAY.
6836 The value is one of the symbols `static-gray', `gray-scale',
6837 `static-color', `pseudo-color', `true-color', or `direct-color'.
6838
6839 The optional argument DISPLAY specifies which display to ask about.
6840 DISPLAY should be either a frame or a display name (a string).
6841 If omitted or nil, that stands for the selected frame's display. */)
6842 (display)
6843 Lisp_Object display;
6844 {
6845 struct w32_display_info *dpyinfo = check_x_display_info (display);
6846 Lisp_Object result = Qnil;
6847
6848 if (dpyinfo->has_palette)
6849 result = intern ("pseudo-color");
6850 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
6851 result = intern ("static-grey");
6852 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
6853 result = intern ("static-color");
6854 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
6855 result = intern ("true-color");
6856
6857 return result;
6858 }
6859
6860 DEFUN ("x-display-save-under", Fx_display_save_under,
6861 Sx_display_save_under, 0, 1, 0,
6862 doc: /* Return t if DISPLAY supports the save-under feature.
6863 The optional argument DISPLAY specifies which display to ask about.
6864 DISPLAY should be either a frame or a display name (a string).
6865 If omitted or nil, that stands for the selected frame's display. */)
6866 (display)
6867 Lisp_Object display;
6868 {
6869 return Qnil;
6870 }
6871 \f
6872 int
6873 x_pixel_width (f)
6874 register struct frame *f;
6875 {
6876 return FRAME_PIXEL_WIDTH (f);
6877 }
6878
6879 int
6880 x_pixel_height (f)
6881 register struct frame *f;
6882 {
6883 return FRAME_PIXEL_HEIGHT (f);
6884 }
6885
6886 int
6887 x_char_width (f)
6888 register struct frame *f;
6889 {
6890 return FRAME_COLUMN_WIDTH (f);
6891 }
6892
6893 int
6894 x_char_height (f)
6895 register struct frame *f;
6896 {
6897 return FRAME_LINE_HEIGHT (f);
6898 }
6899
6900 int
6901 x_screen_planes (f)
6902 register struct frame *f;
6903 {
6904 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
6905 }
6906 \f
6907 /* Return the display structure for the display named NAME.
6908 Open a new connection if necessary. */
6909
6910 struct w32_display_info *
6911 x_display_info_for_name (name)
6912 Lisp_Object name;
6913 {
6914 Lisp_Object names;
6915 struct w32_display_info *dpyinfo;
6916
6917 CHECK_STRING (name);
6918
6919 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
6920 dpyinfo;
6921 dpyinfo = dpyinfo->next, names = XCDR (names))
6922 {
6923 Lisp_Object tem;
6924 tem = Fstring_equal (XCAR (XCAR (names)), name);
6925 if (!NILP (tem))
6926 return dpyinfo;
6927 }
6928
6929 /* Use this general default value to start with. */
6930 Vx_resource_name = Vinvocation_name;
6931
6932 validate_x_resource_name ();
6933
6934 dpyinfo = w32_term_init (name, (unsigned char *)0,
6935 (char *) SDATA (Vx_resource_name));
6936
6937 if (dpyinfo == 0)
6938 error ("Cannot connect to server %s", SDATA (name));
6939
6940 w32_in_use = 1;
6941 XSETFASTINT (Vwindow_system_version, 3);
6942
6943 return dpyinfo;
6944 }
6945
6946 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
6947 1, 3, 0, doc: /* Open a connection to a server.
6948 DISPLAY is the name of the display to connect to.
6949 Optional second arg XRM-STRING is a string of resources in xrdb format.
6950 If the optional third arg MUST-SUCCEED is non-nil,
6951 terminate Emacs if we can't open the connection. */)
6952 (display, xrm_string, must_succeed)
6953 Lisp_Object display, xrm_string, must_succeed;
6954 {
6955 unsigned char *xrm_option;
6956 struct w32_display_info *dpyinfo;
6957
6958 /* If initialization has already been done, return now to avoid
6959 overwriting critical parts of one_w32_display_info. */
6960 if (w32_in_use)
6961 return Qnil;
6962
6963 CHECK_STRING (display);
6964 if (! NILP (xrm_string))
6965 CHECK_STRING (xrm_string);
6966
6967 #if 0
6968 if (! EQ (Vwindow_system, intern ("w32")))
6969 error ("Not using Microsoft Windows");
6970 #endif
6971
6972 /* Allow color mapping to be defined externally; first look in user's
6973 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
6974 {
6975 Lisp_Object color_file;
6976 struct gcpro gcpro1;
6977
6978 color_file = build_string ("~/rgb.txt");
6979
6980 GCPRO1 (color_file);
6981
6982 if (NILP (Ffile_readable_p (color_file)))
6983 color_file =
6984 Fexpand_file_name (build_string ("rgb.txt"),
6985 Fsymbol_value (intern ("data-directory")));
6986
6987 Vw32_color_map = Fw32_load_color_file (color_file);
6988
6989 UNGCPRO;
6990 }
6991 if (NILP (Vw32_color_map))
6992 Vw32_color_map = Fw32_default_color_map ();
6993
6994 /* Merge in system logical colors. */
6995 add_system_logical_colors_to_map (&Vw32_color_map);
6996
6997 if (! NILP (xrm_string))
6998 xrm_option = (unsigned char *) SDATA (xrm_string);
6999 else
7000 xrm_option = (unsigned char *) 0;
7001
7002 /* Use this general default value to start with. */
7003 /* First remove .exe suffix from invocation-name - it looks ugly. */
7004 {
7005 char basename[ MAX_PATH ], *str;
7006
7007 strcpy (basename, SDATA (Vinvocation_name));
7008 str = strrchr (basename, '.');
7009 if (str) *str = 0;
7010 Vinvocation_name = build_string (basename);
7011 }
7012 Vx_resource_name = Vinvocation_name;
7013
7014 validate_x_resource_name ();
7015
7016 /* This is what opens the connection and sets x_current_display.
7017 This also initializes many symbols, such as those used for input. */
7018 dpyinfo = w32_term_init (display, xrm_option,
7019 (char *) SDATA (Vx_resource_name));
7020
7021 if (dpyinfo == 0)
7022 {
7023 if (!NILP (must_succeed))
7024 fatal ("Cannot connect to server %s.\n",
7025 SDATA (display));
7026 else
7027 error ("Cannot connect to server %s", SDATA (display));
7028 }
7029
7030 w32_in_use = 1;
7031
7032 XSETFASTINT (Vwindow_system_version, 3);
7033 return Qnil;
7034 }
7035
7036 DEFUN ("x-close-connection", Fx_close_connection,
7037 Sx_close_connection, 1, 1, 0,
7038 doc: /* Close the connection to DISPLAY's server.
7039 For DISPLAY, specify either a frame or a display name (a string).
7040 If DISPLAY is nil, that stands for the selected frame's display. */)
7041 (display)
7042 Lisp_Object display;
7043 {
7044 struct w32_display_info *dpyinfo = check_x_display_info (display);
7045 int i;
7046
7047 if (dpyinfo->reference_count > 0)
7048 error ("Display still has frames on it");
7049
7050 BLOCK_INPUT;
7051 #if OLD_FONT
7052 /* Free the fonts in the font table. */
7053 for (i = 0; i < dpyinfo->n_fonts; i++)
7054 if (dpyinfo->font_table[i].name)
7055 {
7056 if (dpyinfo->font_table[i].name != dpyinfo->font_table[i].full_name)
7057 xfree (dpyinfo->font_table[i].full_name);
7058 xfree (dpyinfo->font_table[i].name);
7059 w32_unload_font (dpyinfo, dpyinfo->font_table[i].font);
7060 }
7061 #endif
7062 x_destroy_all_bitmaps (dpyinfo);
7063
7064 x_delete_display (dpyinfo);
7065 UNBLOCK_INPUT;
7066
7067 return Qnil;
7068 }
7069
7070 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
7071 doc: /* Return the list of display names that Emacs has connections to. */)
7072 ()
7073 {
7074 Lisp_Object tail, result;
7075
7076 result = Qnil;
7077 for (tail = w32_display_name_list; CONSP (tail); tail = XCDR (tail))
7078 result = Fcons (XCAR (XCAR (tail)), result);
7079
7080 return result;
7081 }
7082
7083 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
7084 doc: /* This is a noop on W32 systems. */)
7085 (on, display)
7086 Lisp_Object display, on;
7087 {
7088 return Qnil;
7089 }
7090
7091
7092 \f
7093 /***********************************************************************
7094 Window properties
7095 ***********************************************************************/
7096
7097 DEFUN ("x-change-window-property", Fx_change_window_property,
7098 Sx_change_window_property, 2, 6, 0,
7099 doc: /* Change window property PROP to VALUE on the X window of FRAME.
7100 VALUE may be a string or a list of conses, numbers and/or strings.
7101 If an element in the list is a string, it is converted to
7102 an Atom and the value of the Atom is used. If an element is a cons,
7103 it is converted to a 32 bit number where the car is the 16 top bits and the
7104 cdr is the lower 16 bits.
7105 FRAME nil or omitted means use the selected frame.
7106 If TYPE is given and non-nil, it is the name of the type of VALUE.
7107 If TYPE is not given or nil, the type is STRING.
7108 FORMAT gives the size in bits of each element if VALUE is a list.
7109 It must be one of 8, 16 or 32.
7110 If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8.
7111 If OUTER_P is non-nil, the property is changed for the outer X window of
7112 FRAME. Default is to change on the edit X window.
7113
7114 Value is VALUE. */)
7115 (prop, value, frame, type, format, outer_p)
7116 Lisp_Object prop, value, frame, type, format, outer_p;
7117 {
7118 #if 0 /* TODO : port window properties to W32 */
7119 struct frame *f = check_x_frame (frame);
7120 Atom prop_atom;
7121
7122 CHECK_STRING (prop);
7123 CHECK_STRING (value);
7124
7125 BLOCK_INPUT;
7126 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
7127 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
7128 prop_atom, XA_STRING, 8, PropModeReplace,
7129 SDATA (value), SCHARS (value));
7130
7131 /* Make sure the property is set when we return. */
7132 XFlush (FRAME_W32_DISPLAY (f));
7133 UNBLOCK_INPUT;
7134
7135 #endif /* TODO */
7136
7137 return value;
7138 }
7139
7140
7141 DEFUN ("x-delete-window-property", Fx_delete_window_property,
7142 Sx_delete_window_property, 1, 2, 0,
7143 doc: /* Remove window property PROP from X window of FRAME.
7144 FRAME nil or omitted means use the selected frame. Value is PROP. */)
7145 (prop, frame)
7146 Lisp_Object prop, frame;
7147 {
7148 #if 0 /* TODO : port window properties to W32 */
7149
7150 struct frame *f = check_x_frame (frame);
7151 Atom prop_atom;
7152
7153 CHECK_STRING (prop);
7154 BLOCK_INPUT;
7155 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
7156 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
7157
7158 /* Make sure the property is removed when we return. */
7159 XFlush (FRAME_W32_DISPLAY (f));
7160 UNBLOCK_INPUT;
7161 #endif /* TODO */
7162
7163 return prop;
7164 }
7165
7166
7167 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
7168 1, 2, 0,
7169 doc: /* Value is the value of window property PROP on FRAME.
7170 If FRAME is nil or omitted, use the selected frame. Value is nil
7171 if FRAME hasn't a property with name PROP or if PROP has no string
7172 value. */)
7173 (prop, frame)
7174 Lisp_Object prop, frame;
7175 {
7176 #if 0 /* TODO : port window properties to W32 */
7177
7178 struct frame *f = check_x_frame (frame);
7179 Atom prop_atom;
7180 int rc;
7181 Lisp_Object prop_value = Qnil;
7182 char *tmp_data = NULL;
7183 Atom actual_type;
7184 int actual_format;
7185 unsigned long actual_size, bytes_remaining;
7186
7187 CHECK_STRING (prop);
7188 BLOCK_INPUT;
7189 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
7190 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
7191 prop_atom, 0, 0, False, XA_STRING,
7192 &actual_type, &actual_format, &actual_size,
7193 &bytes_remaining, (unsigned char **) &tmp_data);
7194 if (rc == Success)
7195 {
7196 int size = bytes_remaining;
7197
7198 XFree (tmp_data);
7199 tmp_data = NULL;
7200
7201 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
7202 prop_atom, 0, bytes_remaining,
7203 False, XA_STRING,
7204 &actual_type, &actual_format,
7205 &actual_size, &bytes_remaining,
7206 (unsigned char **) &tmp_data);
7207 if (rc == Success)
7208 prop_value = make_string (tmp_data, size);
7209
7210 XFree (tmp_data);
7211 }
7212
7213 UNBLOCK_INPUT;
7214
7215 return prop_value;
7216
7217 #endif /* TODO */
7218 return Qnil;
7219 }
7220
7221
7222 \f
7223 /***********************************************************************
7224 Busy cursor
7225 ***********************************************************************/
7226
7227 /* Non-zero means an hourglass cursor is currently shown. */
7228
7229 static int hourglass_shown_p;
7230
7231 /* Number of seconds to wait before displaying an hourglass cursor. */
7232
7233 static Lisp_Object Vhourglass_delay;
7234
7235 /* Default number of seconds to wait before displaying an hourglass
7236 cursor. */
7237
7238 #define DEFAULT_HOURGLASS_DELAY 1
7239
7240 /* Return non-zero if houglass timer has been started or hourglass is shown. */
7241
7242 int
7243 hourglass_started ()
7244 {
7245 return hourglass_shown_p || hourglass_timer;
7246 }
7247
7248 /* Cancel a currently active hourglass timer, and start a new one. */
7249
7250 void
7251 start_hourglass ()
7252 {
7253 DWORD delay;
7254 int secs, msecs = 0;
7255 struct frame * f = SELECTED_FRAME ();
7256
7257 /* No cursors on non GUI frames. */
7258 if (!FRAME_W32_P (f))
7259 return;
7260
7261 cancel_hourglass ();
7262
7263 if (INTEGERP (Vhourglass_delay)
7264 && XINT (Vhourglass_delay) > 0)
7265 secs = XFASTINT (Vhourglass_delay);
7266 else if (FLOATP (Vhourglass_delay)
7267 && XFLOAT_DATA (Vhourglass_delay) > 0)
7268 {
7269 Lisp_Object tem;
7270 tem = Ftruncate (Vhourglass_delay, Qnil);
7271 secs = XFASTINT (tem);
7272 msecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000;
7273 }
7274 else
7275 secs = DEFAULT_HOURGLASS_DELAY;
7276
7277 delay = secs * 1000 + msecs;
7278 hourglass_hwnd = FRAME_W32_WINDOW (f);
7279 hourglass_timer = SetTimer (hourglass_hwnd, HOURGLASS_ID, delay, NULL);
7280 }
7281
7282
7283 /* Cancel the hourglass cursor timer if active, hide an hourglass
7284 cursor if shown. */
7285
7286 void
7287 cancel_hourglass ()
7288 {
7289 if (hourglass_timer)
7290 {
7291 KillTimer (hourglass_hwnd, hourglass_timer);
7292 hourglass_timer = 0;
7293 }
7294
7295 if (hourglass_shown_p)
7296 hide_hourglass ();
7297 }
7298
7299
7300 /* Timer function of hourglass_timer.
7301
7302 Display an hourglass cursor. Set the hourglass_p flag in display info
7303 to indicate that an hourglass cursor is shown. */
7304
7305 static void
7306 show_hourglass (f)
7307 struct frame *f;
7308 {
7309 if (!hourglass_shown_p)
7310 {
7311 f->output_data.w32->hourglass_p = 1;
7312 if (!menubar_in_use && !current_popup_menu)
7313 SetCursor (f->output_data.w32->hourglass_cursor);
7314 hourglass_shown_p = 1;
7315 }
7316 }
7317
7318
7319 /* Hide the hourglass cursor on all frames, if it is currently shown. */
7320
7321 static void
7322 hide_hourglass ()
7323 {
7324 if (hourglass_shown_p)
7325 {
7326 struct frame *f = x_window_to_frame (&one_w32_display_info,
7327 hourglass_hwnd);
7328
7329 f->output_data.w32->hourglass_p = 0;
7330 SetCursor (f->output_data.w32->current_cursor);
7331 hourglass_shown_p = 0;
7332 }
7333 }
7334
7335
7336 \f
7337 /***********************************************************************
7338 Tool tips
7339 ***********************************************************************/
7340
7341 static Lisp_Object x_create_tip_frame P_ ((struct w32_display_info *,
7342 Lisp_Object, Lisp_Object));
7343 static void compute_tip_xy P_ ((struct frame *, Lisp_Object, Lisp_Object,
7344 Lisp_Object, int, int, int *, int *));
7345
7346 /* The frame of a currently visible tooltip. */
7347
7348 Lisp_Object tip_frame;
7349
7350 /* If non-nil, a timer started that hides the last tooltip when it
7351 fires. */
7352
7353 Lisp_Object tip_timer;
7354 Window tip_window;
7355
7356 /* If non-nil, a vector of 3 elements containing the last args
7357 with which x-show-tip was called. See there. */
7358
7359 Lisp_Object last_show_tip_args;
7360
7361 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
7362
7363 Lisp_Object Vx_max_tooltip_size;
7364
7365
7366 static Lisp_Object
7367 unwind_create_tip_frame (frame)
7368 Lisp_Object frame;
7369 {
7370 Lisp_Object deleted;
7371
7372 deleted = unwind_create_frame (frame);
7373 if (EQ (deleted, Qt))
7374 {
7375 tip_window = NULL;
7376 tip_frame = Qnil;
7377 }
7378
7379 return deleted;
7380 }
7381
7382
7383 /* Create a frame for a tooltip on the display described by DPYINFO.
7384 PARMS is a list of frame parameters. TEXT is the string to
7385 display in the tip frame. Value is the frame.
7386
7387 Note that functions called here, esp. x_default_parameter can
7388 signal errors, for instance when a specified color name is
7389 undefined. We have to make sure that we're in a consistent state
7390 when this happens. */
7391
7392 static Lisp_Object
7393 x_create_tip_frame (dpyinfo, parms, text)
7394 struct w32_display_info *dpyinfo;
7395 Lisp_Object parms, text;
7396 {
7397 struct frame *f;
7398 Lisp_Object frame, tem;
7399 Lisp_Object name;
7400 long window_prompting = 0;
7401 int width, height;
7402 int count = SPECPDL_INDEX ();
7403 struct gcpro gcpro1, gcpro2, gcpro3;
7404 struct kboard *kb;
7405 int face_change_count_before = face_change_count;
7406 Lisp_Object buffer;
7407 struct buffer *old_buffer;
7408
7409 check_w32 ();
7410
7411 /* Use this general default value to start with until we know if
7412 this frame has a specified name. */
7413 Vx_resource_name = Vinvocation_name;
7414
7415 #ifdef MULTI_KBOARD
7416 kb = dpyinfo->terminal->kboard;
7417 #else
7418 kb = &the_only_kboard;
7419 #endif
7420
7421 /* Get the name of the frame to use for resource lookup. */
7422 name = w32_get_arg (parms, Qname, "name", "Name", RES_TYPE_STRING);
7423 if (!STRINGP (name)
7424 && !EQ (name, Qunbound)
7425 && !NILP (name))
7426 error ("Invalid frame name--not a string or nil");
7427 Vx_resource_name = name;
7428
7429 frame = Qnil;
7430 GCPRO3 (parms, name, frame);
7431 /* Make a frame without minibuffer nor mode-line. */
7432 f = make_frame (0);
7433 f->wants_modeline = 0;
7434 XSETFRAME (frame, f);
7435
7436 buffer = Fget_buffer_create (build_string (" *tip*"));
7437 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
7438 old_buffer = current_buffer;
7439 set_buffer_internal_1 (XBUFFER (buffer));
7440 current_buffer->truncate_lines = Qnil;
7441 specbind (Qinhibit_read_only, Qt);
7442 specbind (Qinhibit_modification_hooks, Qt);
7443 Ferase_buffer ();
7444 Finsert (1, &text);
7445 set_buffer_internal_1 (old_buffer);
7446
7447 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
7448 record_unwind_protect (unwind_create_tip_frame, frame);
7449
7450 /* By setting the output method, we're essentially saying that
7451 the frame is live, as per FRAME_LIVE_P. If we get a signal
7452 from this point on, x_destroy_window might screw up reference
7453 counts etc. */
7454 f->terminal = dpyinfo->terminal;
7455 f->terminal->reference_count++;
7456 f->output_method = output_w32;
7457 f->output_data.w32 =
7458 (struct w32_output *) xmalloc (sizeof (struct w32_output));
7459 bzero (f->output_data.w32, sizeof (struct w32_output));
7460
7461 FRAME_FONTSET (f) = -1;
7462 f->icon_name = Qnil;
7463
7464 #if 0 /* GLYPH_DEBUG TODO: image support. */
7465 image_cache_refcount = FRAME_IMAGE_CACHE (f)->refcount;
7466 dpyinfo_refcount = dpyinfo->reference_count;
7467 #endif /* GLYPH_DEBUG */
7468 #ifdef MULTI_KBOARD
7469 FRAME_KBOARD (f) = kb;
7470 #endif
7471 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
7472 f->output_data.w32->explicit_parent = 0;
7473
7474 /* Set the name; the functions to which we pass f expect the name to
7475 be set. */
7476 if (EQ (name, Qunbound) || NILP (name))
7477 {
7478 f->name = build_string (dpyinfo->w32_id_name);
7479 f->explicit_name = 0;
7480 }
7481 else
7482 {
7483 f->name = name;
7484 f->explicit_name = 1;
7485 /* use the frame's title when getting resources for this frame. */
7486 specbind (Qx_resource_name, name);
7487 }
7488
7489 f->resx = dpyinfo->resx;
7490 f->resy = dpyinfo->resy;
7491
7492 /* Perhaps, we must allow frame parameter, say `font-backend',
7493 to specify which font backends to use. */
7494 register_font_driver (&w32font_driver, f);
7495
7496 x_default_parameter (f, parms, Qfont_backend, Qnil,
7497 "fontBackend", "FontBackend", RES_TYPE_STRING);
7498
7499 /* Extract the window parameters from the supplied values
7500 that are needed to determine window geometry. */
7501 x_default_font_parameter (f, parms);
7502
7503 x_default_parameter (f, parms, Qborder_width, make_number (2),
7504 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
7505 /* This defaults to 2 in order to match xterm. We recognize either
7506 internalBorderWidth or internalBorder (which is what xterm calls
7507 it). */
7508 if (NILP (Fassq (Qinternal_border_width, parms)))
7509 {
7510 Lisp_Object value;
7511
7512 value = w32_get_arg (parms, Qinternal_border_width,
7513 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
7514 if (! EQ (value, Qunbound))
7515 parms = Fcons (Fcons (Qinternal_border_width, value),
7516 parms);
7517 }
7518 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
7519 "internalBorderWidth", "internalBorderWidth",
7520 RES_TYPE_NUMBER);
7521
7522 /* Also do the stuff which must be set before the window exists. */
7523 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
7524 "foreground", "Foreground", RES_TYPE_STRING);
7525 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
7526 "background", "Background", RES_TYPE_STRING);
7527 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
7528 "pointerColor", "Foreground", RES_TYPE_STRING);
7529 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
7530 "cursorColor", "Foreground", RES_TYPE_STRING);
7531 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
7532 "borderColor", "BorderColor", RES_TYPE_STRING);
7533
7534 /* Init faces before x_default_parameter is called for scroll-bar
7535 parameters because that function calls x_set_scroll_bar_width,
7536 which calls change_frame_size, which calls Fset_window_buffer,
7537 which runs hooks, which call Fvertical_motion. At the end, we
7538 end up in init_iterator with a null face cache, which should not
7539 happen. */
7540 init_frame_faces (f);
7541
7542 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
7543 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
7544
7545 window_prompting = x_figure_window_size (f, parms, 0);
7546
7547 /* No fringes on tip frame. */
7548 f->fringe_cols = 0;
7549 f->left_fringe_width = 0;
7550 f->right_fringe_width = 0;
7551
7552 BLOCK_INPUT;
7553 my_create_tip_window (f);
7554 UNBLOCK_INPUT;
7555
7556 x_make_gc (f);
7557
7558 x_default_parameter (f, parms, Qauto_raise, Qnil,
7559 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
7560 x_default_parameter (f, parms, Qauto_lower, Qnil,
7561 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
7562 x_default_parameter (f, parms, Qcursor_type, Qbox,
7563 "cursorType", "CursorType", RES_TYPE_SYMBOL);
7564
7565 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
7566 Change will not be effected unless different from the current
7567 FRAME_LINES (f). */
7568 width = FRAME_COLS (f);
7569 height = FRAME_LINES (f);
7570 FRAME_LINES (f) = 0;
7571 SET_FRAME_COLS (f, 0);
7572 change_frame_size (f, height, width, 1, 0, 0);
7573
7574 /* Add `tooltip' frame parameter's default value. */
7575 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
7576 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
7577 Qnil));
7578
7579 /* Set up faces after all frame parameters are known. This call
7580 also merges in face attributes specified for new frames.
7581
7582 Frame parameters may be changed if .Xdefaults contains
7583 specifications for the default font. For example, if there is an
7584 `Emacs.default.attributeBackground: pink', the `background-color'
7585 attribute of the frame get's set, which let's the internal border
7586 of the tooltip frame appear in pink. Prevent this. */
7587 {
7588 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
7589
7590 /* Set tip_frame here, so that */
7591 tip_frame = frame;
7592 call1 (Qface_set_after_frame_default, frame);
7593
7594 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
7595 Fmodify_frame_parameters (frame, Fcons (Fcons (Qbackground_color, bg),
7596 Qnil));
7597 }
7598
7599 f->no_split = 1;
7600
7601 UNGCPRO;
7602
7603 /* It is now ok to make the frame official even if we get an error
7604 below. And the frame needs to be on Vframe_list or making it
7605 visible won't work. */
7606 Vframe_list = Fcons (frame, Vframe_list);
7607
7608 /* Now that the frame is official, it counts as a reference to
7609 its display. */
7610 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
7611
7612 /* Setting attributes of faces of the tooltip frame from resources
7613 and similar will increment face_change_count, which leads to the
7614 clearing of all current matrices. Since this isn't necessary
7615 here, avoid it by resetting face_change_count to the value it
7616 had before we created the tip frame. */
7617 face_change_count = face_change_count_before;
7618
7619 /* Discard the unwind_protect. */
7620 return unbind_to (count, frame);
7621 }
7622
7623
7624 /* Compute where to display tip frame F. PARMS is the list of frame
7625 parameters for F. DX and DY are specified offsets from the current
7626 location of the mouse. WIDTH and HEIGHT are the width and height
7627 of the tooltip. Return coordinates relative to the root window of
7628 the display in *ROOT_X, and *ROOT_Y. */
7629
7630 static void
7631 compute_tip_xy (f, parms, dx, dy, width, height, root_x, root_y)
7632 struct frame *f;
7633 Lisp_Object parms, dx, dy;
7634 int width, height;
7635 int *root_x, *root_y;
7636 {
7637 Lisp_Object left, top;
7638 int min_x, min_y, max_x, max_y;
7639
7640 /* User-specified position? */
7641 left = Fcdr (Fassq (Qleft, parms));
7642 top = Fcdr (Fassq (Qtop, parms));
7643
7644 /* Move the tooltip window where the mouse pointer is. Resize and
7645 show it. */
7646 if (!INTEGERP (left) || !INTEGERP (top))
7647 {
7648 POINT pt;
7649
7650 /* Default min and max values. */
7651 min_x = 0;
7652 min_y = 0;
7653 max_x = FRAME_W32_DISPLAY_INFO (f)->width;
7654 max_y = FRAME_W32_DISPLAY_INFO (f)->height;
7655
7656 BLOCK_INPUT;
7657 GetCursorPos (&pt);
7658 *root_x = pt.x;
7659 *root_y = pt.y;
7660 UNBLOCK_INPUT;
7661
7662 /* If multiple monitor support is available, constrain the tip onto
7663 the current monitor. This improves the above by allowing negative
7664 co-ordinates if monitor positions are such that they are valid, and
7665 snaps a tooltip onto a single monitor if we are close to the edge
7666 where it would otherwise flow onto the other monitor (or into
7667 nothingness if there is a gap in the overlap). */
7668 if (monitor_from_point_fn && get_monitor_info_fn)
7669 {
7670 struct MONITOR_INFO info;
7671 HMONITOR monitor
7672 = monitor_from_point_fn (pt, MONITOR_DEFAULT_TO_NEAREST);
7673 info.cbSize = sizeof (info);
7674
7675 if (get_monitor_info_fn (monitor, &info))
7676 {
7677 min_x = info.rcWork.left;
7678 min_y = info.rcWork.top;
7679 max_x = info.rcWork.right;
7680 max_y = info.rcWork.bottom;
7681 }
7682 }
7683 }
7684
7685 if (INTEGERP (top))
7686 *root_y = XINT (top);
7687 else if (*root_y + XINT (dy) <= min_y)
7688 *root_y = min_y; /* Can happen for negative dy */
7689 else if (*root_y + XINT (dy) + height <= max_y)
7690 /* It fits below the pointer */
7691 *root_y += XINT (dy);
7692 else if (height + XINT (dy) + min_y <= *root_y)
7693 /* It fits above the pointer. */
7694 *root_y -= height + XINT (dy);
7695 else
7696 /* Put it on the top. */
7697 *root_y = min_y;
7698
7699 if (INTEGERP (left))
7700 *root_x = XINT (left);
7701 else if (*root_x + XINT (dx) <= min_x)
7702 *root_x = 0; /* Can happen for negative dx */
7703 else if (*root_x + XINT (dx) + width <= max_x)
7704 /* It fits to the right of the pointer. */
7705 *root_x += XINT (dx);
7706 else if (width + XINT (dx) + min_x <= *root_x)
7707 /* It fits to the left of the pointer. */
7708 *root_x -= width + XINT (dx);
7709 else
7710 /* Put it left justified on the screen -- it ought to fit that way. */
7711 *root_x = min_x;
7712 }
7713
7714
7715 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
7716 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
7717 A tooltip window is a small window displaying a string.
7718
7719 This is an internal function; Lisp code should call `tooltip-show'.
7720
7721 FRAME nil or omitted means use the selected frame.
7722
7723 PARMS is an optional list of frame parameters which can be
7724 used to change the tooltip's appearance.
7725
7726 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
7727 means use the default timeout of 5 seconds.
7728
7729 If the list of frame parameters PARMS contains a `left' parameter,
7730 the tooltip is displayed at that x-position. Otherwise it is
7731 displayed at the mouse position, with offset DX added (default is 5 if
7732 DX isn't specified). Likewise for the y-position; if a `top' frame
7733 parameter is specified, it determines the y-position of the tooltip
7734 window, otherwise it is displayed at the mouse position, with offset
7735 DY added (default is -10).
7736
7737 A tooltip's maximum size is specified by `x-max-tooltip-size'.
7738 Text larger than the specified size is clipped. */)
7739 (string, frame, parms, timeout, dx, dy)
7740 Lisp_Object string, frame, parms, timeout, dx, dy;
7741 {
7742 struct frame *f;
7743 struct window *w;
7744 int root_x, root_y;
7745 struct buffer *old_buffer;
7746 struct text_pos pos;
7747 int i, width, height;
7748 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
7749 int old_windows_or_buffers_changed = windows_or_buffers_changed;
7750 int count = SPECPDL_INDEX ();
7751
7752 specbind (Qinhibit_redisplay, Qt);
7753
7754 GCPRO4 (string, parms, frame, timeout);
7755
7756 CHECK_STRING (string);
7757 f = check_x_frame (frame);
7758 if (NILP (timeout))
7759 timeout = make_number (5);
7760 else
7761 CHECK_NATNUM (timeout);
7762
7763 if (NILP (dx))
7764 dx = make_number (5);
7765 else
7766 CHECK_NUMBER (dx);
7767
7768 if (NILP (dy))
7769 dy = make_number (-10);
7770 else
7771 CHECK_NUMBER (dy);
7772
7773 if (NILP (last_show_tip_args))
7774 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
7775
7776 if (!NILP (tip_frame))
7777 {
7778 Lisp_Object last_string = AREF (last_show_tip_args, 0);
7779 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
7780 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
7781
7782 if (EQ (frame, last_frame)
7783 && !NILP (Fequal (last_string, string))
7784 && !NILP (Fequal (last_parms, parms)))
7785 {
7786 struct frame *f = XFRAME (tip_frame);
7787
7788 /* Only DX and DY have changed. */
7789 if (!NILP (tip_timer))
7790 {
7791 Lisp_Object timer = tip_timer;
7792 tip_timer = Qnil;
7793 call1 (Qcancel_timer, timer);
7794 }
7795
7796 BLOCK_INPUT;
7797 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
7798 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
7799
7800 /* Put tooltip in topmost group and in position. */
7801 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
7802 root_x, root_y, 0, 0,
7803 SWP_NOSIZE | SWP_NOACTIVATE);
7804
7805 /* Ensure tooltip is on top of other topmost windows (eg menus). */
7806 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
7807 0, 0, 0, 0,
7808 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
7809
7810 UNBLOCK_INPUT;
7811 goto start_timer;
7812 }
7813 }
7814
7815 /* Hide a previous tip, if any. */
7816 Fx_hide_tip ();
7817
7818 ASET (last_show_tip_args, 0, string);
7819 ASET (last_show_tip_args, 1, frame);
7820 ASET (last_show_tip_args, 2, parms);
7821
7822 /* Add default values to frame parameters. */
7823 if (NILP (Fassq (Qname, parms)))
7824 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
7825 if (NILP (Fassq (Qinternal_border_width, parms)))
7826 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
7827 if (NILP (Fassq (Qborder_width, parms)))
7828 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
7829 if (NILP (Fassq (Qborder_color, parms)))
7830 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
7831 if (NILP (Fassq (Qbackground_color, parms)))
7832 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
7833 parms);
7834
7835 /* Block input until the tip has been fully drawn, to avoid crashes
7836 when drawing tips in menus. */
7837 BLOCK_INPUT;
7838
7839 /* Create a frame for the tooltip, and record it in the global
7840 variable tip_frame. */
7841 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
7842 f = XFRAME (frame);
7843
7844 /* Set up the frame's root window. */
7845 w = XWINDOW (FRAME_ROOT_WINDOW (f));
7846 w->left_col = w->top_line = make_number (0);
7847
7848 if (CONSP (Vx_max_tooltip_size)
7849 && INTEGERP (XCAR (Vx_max_tooltip_size))
7850 && XINT (XCAR (Vx_max_tooltip_size)) > 0
7851 && INTEGERP (XCDR (Vx_max_tooltip_size))
7852 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
7853 {
7854 w->total_cols = XCAR (Vx_max_tooltip_size);
7855 w->total_lines = XCDR (Vx_max_tooltip_size);
7856 }
7857 else
7858 {
7859 w->total_cols = make_number (80);
7860 w->total_lines = make_number (40);
7861 }
7862
7863 FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
7864 adjust_glyphs (f);
7865 w->pseudo_window_p = 1;
7866
7867 /* Display the tooltip text in a temporary buffer. */
7868 old_buffer = current_buffer;
7869 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
7870 current_buffer->truncate_lines = Qnil;
7871 clear_glyph_matrix (w->desired_matrix);
7872 clear_glyph_matrix (w->current_matrix);
7873 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
7874 try_window (FRAME_ROOT_WINDOW (f), pos, 0);
7875
7876 /* Compute width and height of the tooltip. */
7877 width = height = 0;
7878 for (i = 0; i < w->desired_matrix->nrows; ++i)
7879 {
7880 struct glyph_row *row = &w->desired_matrix->rows[i];
7881 struct glyph *last;
7882 int row_width;
7883
7884 /* Stop at the first empty row at the end. */
7885 if (!row->enabled_p || !row->displays_text_p)
7886 break;
7887
7888 /* Let the row go over the full width of the frame. */
7889 row->full_width_p = 1;
7890
7891 #ifdef TODO /* Investigate why some fonts need more width than is
7892 calculated for some tooltips. */
7893 /* There's a glyph at the end of rows that is use to place
7894 the cursor there. Don't include the width of this glyph. */
7895 if (row->used[TEXT_AREA])
7896 {
7897 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
7898 row_width = row->pixel_width - last->pixel_width;
7899 }
7900 else
7901 #endif
7902 row_width = row->pixel_width;
7903
7904 /* TODO: find why tips do not draw along baseline as instructed. */
7905 height += row->height;
7906 width = max (width, row_width);
7907 }
7908
7909 /* Add the frame's internal border to the width and height the X
7910 window should have. */
7911 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
7912 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
7913
7914 /* Move the tooltip window where the mouse pointer is. Resize and
7915 show it. */
7916 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
7917
7918 {
7919 /* Adjust Window size to take border into account. */
7920 RECT rect;
7921 rect.left = rect.top = 0;
7922 rect.right = width;
7923 rect.bottom = height;
7924 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
7925 FRAME_EXTERNAL_MENU_BAR (f));
7926
7927 /* Position and size tooltip, and put it in the topmost group.
7928 The add-on of 3 to the 5th argument is a kludge: without it,
7929 some fonts cause the last character of the tip to be truncated,
7930 for some obscure reason. */
7931 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
7932 root_x, root_y, rect.right - rect.left + 3,
7933 rect.bottom - rect.top, SWP_NOACTIVATE);
7934
7935 /* Ensure tooltip is on top of other topmost windows (eg menus). */
7936 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
7937 0, 0, 0, 0,
7938 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
7939
7940 /* Let redisplay know that we have made the frame visible already. */
7941 f->async_visible = 1;
7942
7943 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
7944 }
7945
7946 /* Draw into the window. */
7947 w->must_be_updated_p = 1;
7948 update_single_window (w, 1);
7949
7950 UNBLOCK_INPUT;
7951
7952 /* Restore original current buffer. */
7953 set_buffer_internal_1 (old_buffer);
7954 windows_or_buffers_changed = old_windows_or_buffers_changed;
7955
7956 start_timer:
7957 /* Let the tip disappear after timeout seconds. */
7958 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
7959 intern ("x-hide-tip"));
7960
7961 UNGCPRO;
7962 return unbind_to (count, Qnil);
7963 }
7964
7965
7966 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
7967 doc: /* Hide the current tooltip window, if there is any.
7968 Value is t if tooltip was open, nil otherwise. */)
7969 ()
7970 {
7971 int count;
7972 Lisp_Object deleted, frame, timer;
7973 struct gcpro gcpro1, gcpro2;
7974
7975 /* Return quickly if nothing to do. */
7976 if (NILP (tip_timer) && NILP (tip_frame))
7977 return Qnil;
7978
7979 frame = tip_frame;
7980 timer = tip_timer;
7981 GCPRO2 (frame, timer);
7982 tip_frame = tip_timer = deleted = Qnil;
7983
7984 count = SPECPDL_INDEX ();
7985 specbind (Qinhibit_redisplay, Qt);
7986 specbind (Qinhibit_quit, Qt);
7987
7988 if (!NILP (timer))
7989 call1 (Qcancel_timer, timer);
7990
7991 if (FRAMEP (frame))
7992 {
7993 Fdelete_frame (frame, Qnil);
7994 deleted = Qt;
7995 }
7996
7997 UNGCPRO;
7998 return unbind_to (count, deleted);
7999 }
8000
8001
8002 \f
8003 /***********************************************************************
8004 File selection dialog
8005 ***********************************************************************/
8006 extern Lisp_Object Qfile_name_history;
8007
8008 /* Callback for altering the behaviour of the Open File dialog.
8009 Makes the Filename text field contain "Current Directory" and be
8010 read-only when "Directories" is selected in the filter. This
8011 allows us to work around the fact that the standard Open File
8012 dialog does not support directories. */
8013 UINT CALLBACK
8014 file_dialog_callback (hwnd, msg, wParam, lParam)
8015 HWND hwnd;
8016 UINT msg;
8017 WPARAM wParam;
8018 LPARAM lParam;
8019 {
8020 if (msg == WM_NOTIFY)
8021 {
8022 OFNOTIFY * notify = (OFNOTIFY *)lParam;
8023 /* Detect when the Filter dropdown is changed. */
8024 if (notify->hdr.code == CDN_TYPECHANGE
8025 || notify->hdr.code == CDN_INITDONE)
8026 {
8027 HWND dialog = GetParent (hwnd);
8028 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
8029
8030 /* Directories is in index 2. */
8031 if (notify->lpOFN->nFilterIndex == 2)
8032 {
8033 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
8034 "Current Directory");
8035 EnableWindow (edit_control, FALSE);
8036 }
8037 else
8038 {
8039 /* Don't override default filename on init done. */
8040 if (notify->hdr.code == CDN_TYPECHANGE)
8041 CommDlg_OpenSave_SetControlText (dialog,
8042 FILE_NAME_TEXT_FIELD, "");
8043 EnableWindow (edit_control, TRUE);
8044 }
8045 }
8046 }
8047 return 0;
8048 }
8049
8050 /* Since we compile with _WIN32_WINNT set to 0x0400 (for NT4 compatibility)
8051 we end up with the old file dialogs. Define a big enough struct for the
8052 new dialog to trick GetOpenFileName into giving us the new dialogs on
8053 Windows 2000 and XP. */
8054 typedef struct
8055 {
8056 OPENFILENAME real_details;
8057 void * pReserved;
8058 DWORD dwReserved;
8059 DWORD FlagsEx;
8060 } NEWOPENFILENAME;
8061
8062
8063 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
8064 doc: /* Read file name, prompting with PROMPT in directory DIR.
8065 Use a file selection dialog.
8066 Select DEFAULT-FILENAME in the dialog's file selection box, if
8067 specified. Ensure that file exists if MUSTMATCH is non-nil.
8068 If ONLY-DIR-P is non-nil, the user can only select directories. */)
8069 (prompt, dir, default_filename, mustmatch, only_dir_p)
8070 Lisp_Object prompt, dir, default_filename, mustmatch, only_dir_p;
8071 {
8072 struct frame *f = SELECTED_FRAME ();
8073 Lisp_Object file = Qnil;
8074 int count = SPECPDL_INDEX ();
8075 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
8076 char filename[MAX_PATH + 1];
8077 char init_dir[MAX_PATH + 1];
8078 int default_filter_index = 1; /* 1: All Files, 2: Directories only */
8079
8080 GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, file);
8081 CHECK_STRING (prompt);
8082 CHECK_STRING (dir);
8083
8084 /* Create the dialog with PROMPT as title, using DIR as initial
8085 directory and using "*" as pattern. */
8086 dir = Fexpand_file_name (dir, Qnil);
8087 strncpy (init_dir, SDATA (ENCODE_FILE (dir)), MAX_PATH);
8088 init_dir[MAX_PATH] = '\0';
8089 unixtodos_filename (init_dir);
8090
8091 if (STRINGP (default_filename))
8092 {
8093 char *file_name_only;
8094 char *full_path_name = SDATA (ENCODE_FILE (default_filename));
8095
8096 unixtodos_filename (full_path_name);
8097
8098 file_name_only = strrchr (full_path_name, '\\');
8099 if (!file_name_only)
8100 file_name_only = full_path_name;
8101 else
8102 file_name_only++;
8103
8104 strncpy (filename, file_name_only, MAX_PATH);
8105 filename[MAX_PATH] = '\0';
8106 }
8107 else
8108 filename[0] = '\0';
8109
8110 {
8111 NEWOPENFILENAME new_file_details;
8112 BOOL file_opened = FALSE;
8113 OPENFILENAME * file_details = &new_file_details.real_details;
8114
8115 /* Prevent redisplay. */
8116 specbind (Qinhibit_redisplay, Qt);
8117 BLOCK_INPUT;
8118
8119 bzero (&new_file_details, sizeof (new_file_details));
8120 /* Apparently NT4 crashes if you give it an unexpected size.
8121 I'm not sure about Windows 9x, so play it safe. */
8122 if (w32_major_version > 4 && w32_major_version < 95)
8123 file_details->lStructSize = sizeof (NEWOPENFILENAME);
8124 else
8125 file_details->lStructSize = sizeof (OPENFILENAME);
8126
8127 file_details->hwndOwner = FRAME_W32_WINDOW (f);
8128 /* Undocumented Bug in Common File Dialog:
8129 If a filter is not specified, shell links are not resolved. */
8130 file_details->lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
8131 file_details->lpstrFile = filename;
8132 file_details->nMaxFile = sizeof (filename);
8133 file_details->lpstrInitialDir = init_dir;
8134 file_details->lpstrTitle = SDATA (prompt);
8135
8136 if (! NILP (only_dir_p))
8137 default_filter_index = 2;
8138
8139 file_details->nFilterIndex = default_filter_index;
8140
8141 file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
8142 | OFN_EXPLORER | OFN_ENABLEHOOK);
8143 if (!NILP (mustmatch))
8144 {
8145 /* Require that the path to the parent directory exists. */
8146 file_details->Flags |= OFN_PATHMUSTEXIST;
8147 /* If we are looking for a file, require that it exists. */
8148 if (NILP (only_dir_p))
8149 file_details->Flags |= OFN_FILEMUSTEXIST;
8150 }
8151
8152 file_details->lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
8153
8154 file_opened = GetOpenFileName (file_details);
8155
8156 UNBLOCK_INPUT;
8157
8158 if (file_opened)
8159 {
8160 dostounix_filename (filename);
8161
8162 if (file_details->nFilterIndex == 2)
8163 {
8164 /* "Directories" selected - strip dummy file name. */
8165 char * last = strrchr (filename, '/');
8166 *last = '\0';
8167 }
8168
8169 file = DECODE_FILE (build_string (filename));
8170 }
8171 /* User cancelled the dialog without making a selection. */
8172 else if (!CommDlgExtendedError ())
8173 file = Qnil;
8174 /* An error occurred, fallback on reading from the mini-buffer. */
8175 else
8176 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
8177 dir, mustmatch, dir, Qfile_name_history,
8178 default_filename, Qnil);
8179
8180 file = unbind_to (count, file);
8181 }
8182
8183 UNGCPRO;
8184
8185 /* Make "Cancel" equivalent to C-g. */
8186 if (NILP (file))
8187 Fsignal (Qquit, Qnil);
8188
8189 return unbind_to (count, file);
8190 }
8191
8192
8193 \f
8194 /***********************************************************************
8195 w32 specialized functions
8196 ***********************************************************************/
8197
8198 DEFUN ("w32-select-font", Fw32_select_font, Sw32_select_font, 0, 2, 0,
8199 doc: /* Select a font for the named FRAME using the W32 font dialog.
8200 Return an X-style font string corresponding to the selection.
8201
8202 If FRAME is omitted or nil, it defaults to the selected frame.
8203 If INCLUDE-PROPORTIONAL is non-nil, include proportional fonts
8204 in the font selection dialog. */)
8205 (frame, include_proportional)
8206 Lisp_Object frame, include_proportional;
8207 {
8208 FRAME_PTR f = check_x_frame (frame);
8209 CHOOSEFONT cf;
8210 LOGFONT lf;
8211 TEXTMETRIC tm;
8212 HDC hdc;
8213 HANDLE oldobj;
8214 char buf[100];
8215
8216 bzero (&cf, sizeof (cf));
8217 bzero (&lf, sizeof (lf));
8218
8219 cf.lStructSize = sizeof (cf);
8220 cf.hwndOwner = FRAME_W32_WINDOW (f);
8221 cf.Flags = CF_FORCEFONTEXIST | CF_SCREENFONTS | CF_NOVERTFONTS;
8222
8223 /* Unless include_proportional is non-nil, limit the selection to
8224 monospaced fonts. */
8225 if (NILP (include_proportional))
8226 cf.Flags |= CF_FIXEDPITCHONLY;
8227
8228 cf.lpLogFont = &lf;
8229
8230 /* Initialize as much of the font details as we can from the current
8231 default font. */
8232 hdc = GetDC (FRAME_W32_WINDOW (f));
8233 oldobj = SelectObject (hdc, FONT_COMPAT (FRAME_FONT (f))->hfont);
8234 GetTextFace (hdc, LF_FACESIZE, lf.lfFaceName);
8235 if (GetTextMetrics (hdc, &tm))
8236 {
8237 lf.lfHeight = tm.tmInternalLeading - tm.tmHeight;
8238 lf.lfWeight = tm.tmWeight;
8239 lf.lfItalic = tm.tmItalic;
8240 lf.lfUnderline = tm.tmUnderlined;
8241 lf.lfStrikeOut = tm.tmStruckOut;
8242 lf.lfCharSet = tm.tmCharSet;
8243 cf.Flags |= CF_INITTOLOGFONTSTRUCT;
8244 }
8245 SelectObject (hdc, oldobj);
8246 ReleaseDC (FRAME_W32_WINDOW (f), hdc);
8247
8248 if (!ChooseFont (&cf) || !w32_to_x_font (&lf, buf, 100, NULL))
8249 return Qnil;
8250
8251 return build_string (buf);
8252 }
8253
8254 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
8255 Sw32_send_sys_command, 1, 2, 0,
8256 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
8257 Some useful values for COMMAND are #xf030 to maximize frame (#xf020
8258 to minimize), #xf120 to restore frame to original size, and #xf100
8259 to activate the menubar for keyboard access. #xf140 activates the
8260 screen saver if defined.
8261
8262 If optional parameter FRAME is not specified, use selected frame. */)
8263 (command, frame)
8264 Lisp_Object command, frame;
8265 {
8266 FRAME_PTR f = check_x_frame (frame);
8267
8268 CHECK_NUMBER (command);
8269
8270 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
8271
8272 return Qnil;
8273 }
8274
8275 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
8276 doc: /* Get Windows to perform OPERATION on DOCUMENT.
8277 This is a wrapper around the ShellExecute system function, which
8278 invokes the application registered to handle OPERATION for DOCUMENT.
8279
8280 OPERATION is either nil or a string that names a supported operation.
8281 What operations can be used depends on the particular DOCUMENT and its
8282 handler application, but typically it is one of the following common
8283 operations:
8284
8285 \"open\" - open DOCUMENT, which could be a file, a directory, or an
8286 executable program. If it is an application, that
8287 application is launched in the current buffer's default
8288 directory. Otherwise, the application associated with
8289 DOCUMENT is launched in the buffer's default directory.
8290 \"print\" - print DOCUMENT, which must be a file
8291 \"explore\" - start the Windows Explorer on DOCUMENT
8292 \"edit\" - launch an editor and open DOCUMENT for editing; which
8293 editor is launched depends on the association for the
8294 specified DOCUMENT
8295 \"find\" - initiate search starting from DOCUMENT which must specify
8296 a directory
8297 nil - invoke the default OPERATION, or \"open\" if default is
8298 not defined or unavailable
8299
8300 DOCUMENT is typically the name of a document file or a URL, but can
8301 also be a program executable to run, or a directory to open in the
8302 Windows Explorer.
8303
8304 If DOCUMENT is a program executable, the optional third arg PARAMETERS
8305 can be a string containing command line parameters that will be passed
8306 to the program; otherwise, PARAMETERS should be nil or unspecified.
8307
8308 Optional fourth argument SHOW-FLAG can be used to control how the
8309 application will be displayed when it is invoked. If SHOW-FLAG is nil
8310 or unspecified, the application is displayed normally, otherwise it is
8311 an integer representing a ShowWindow flag:
8312
8313 0 - start hidden
8314 1 - start normally
8315 3 - start maximized
8316 6 - start minimized */)
8317 (operation, document, parameters, show_flag)
8318 Lisp_Object operation, document, parameters, show_flag;
8319 {
8320 Lisp_Object current_dir;
8321
8322 CHECK_STRING (document);
8323
8324 /* Encode filename, current directory and parameters. */
8325 current_dir = ENCODE_FILE (current_buffer->directory);
8326 document = ENCODE_FILE (document);
8327 if (STRINGP (parameters))
8328 parameters = ENCODE_SYSTEM (parameters);
8329
8330 if ((int) ShellExecute (NULL,
8331 (STRINGP (operation) ?
8332 SDATA (operation) : NULL),
8333 SDATA (document),
8334 (STRINGP (parameters) ?
8335 SDATA (parameters) : NULL),
8336 SDATA (current_dir),
8337 (INTEGERP (show_flag) ?
8338 XINT (show_flag) : SW_SHOWDEFAULT))
8339 > 32)
8340 return Qt;
8341 error ("ShellExecute failed: %s", w32_strerror (0));
8342 }
8343
8344 /* Lookup virtual keycode from string representing the name of a
8345 non-ascii keystroke into the corresponding virtual key, using
8346 lispy_function_keys. */
8347 static int
8348 lookup_vk_code (char *key)
8349 {
8350 int i;
8351
8352 for (i = 0; i < 256; i++)
8353 if (lispy_function_keys[i]
8354 && strcmp (lispy_function_keys[i], key) == 0)
8355 return i;
8356
8357 return -1;
8358 }
8359
8360 /* Convert a one-element vector style key sequence to a hot key
8361 definition. */
8362 static Lisp_Object
8363 w32_parse_hot_key (key)
8364 Lisp_Object key;
8365 {
8366 /* Copied from Fdefine_key and store_in_keymap. */
8367 register Lisp_Object c;
8368 int vk_code;
8369 int lisp_modifiers;
8370 int w32_modifiers;
8371 struct gcpro gcpro1;
8372
8373 CHECK_VECTOR (key);
8374
8375 if (XFASTINT (Flength (key)) != 1)
8376 return Qnil;
8377
8378 GCPRO1 (key);
8379
8380 c = Faref (key, make_number (0));
8381
8382 if (CONSP (c) && lucid_event_type_list_p (c))
8383 c = Fevent_convert_list (c);
8384
8385 UNGCPRO;
8386
8387 if (! INTEGERP (c) && ! SYMBOLP (c))
8388 error ("Key definition is invalid");
8389
8390 /* Work out the base key and the modifiers. */
8391 if (SYMBOLP (c))
8392 {
8393 c = parse_modifiers (c);
8394 lisp_modifiers = XINT (Fcar (Fcdr (c)));
8395 c = Fcar (c);
8396 if (!SYMBOLP (c))
8397 abort ();
8398 vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
8399 }
8400 else if (INTEGERP (c))
8401 {
8402 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
8403 /* Many ascii characters are their own virtual key code. */
8404 vk_code = XINT (c) & CHARACTERBITS;
8405 }
8406
8407 if (vk_code < 0 || vk_code > 255)
8408 return Qnil;
8409
8410 if ((lisp_modifiers & meta_modifier) != 0
8411 && !NILP (Vw32_alt_is_meta))
8412 lisp_modifiers |= alt_modifier;
8413
8414 /* Supply defs missing from mingw32. */
8415 #ifndef MOD_ALT
8416 #define MOD_ALT 0x0001
8417 #define MOD_CONTROL 0x0002
8418 #define MOD_SHIFT 0x0004
8419 #define MOD_WIN 0x0008
8420 #endif
8421
8422 /* Convert lisp modifiers to Windows hot-key form. */
8423 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
8424 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
8425 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
8426 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
8427
8428 return HOTKEY (vk_code, w32_modifiers);
8429 }
8430
8431 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
8432 Sw32_register_hot_key, 1, 1, 0,
8433 doc: /* Register KEY as a hot-key combination.
8434 Certain key combinations like Alt-Tab are reserved for system use on
8435 Windows, and therefore are normally intercepted by the system. However,
8436 most of these key combinations can be received by registering them as
8437 hot-keys, overriding their special meaning.
8438
8439 KEY must be a one element key definition in vector form that would be
8440 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
8441 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
8442 is always interpreted as the Windows modifier keys.
8443
8444 The return value is the hotkey-id if registered, otherwise nil. */)
8445 (key)
8446 Lisp_Object key;
8447 {
8448 key = w32_parse_hot_key (key);
8449
8450 if (!NILP (key) && NILP (Fmemq (key, w32_grabbed_keys)))
8451 {
8452 /* Reuse an empty slot if possible. */
8453 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
8454
8455 /* Safe to add new key to list, even if we have focus. */
8456 if (NILP (item))
8457 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
8458 else
8459 XSETCAR (item, key);
8460
8461 /* Notify input thread about new hot-key definition, so that it
8462 takes effect without needing to switch focus. */
8463 #ifdef USE_LISP_UNION_TYPE
8464 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
8465 (WPARAM) key.i, 0);
8466 #else
8467 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
8468 (WPARAM) key, 0);
8469 #endif
8470 }
8471
8472 return key;
8473 }
8474
8475 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
8476 Sw32_unregister_hot_key, 1, 1, 0,
8477 doc: /* Unregister KEY as a hot-key combination. */)
8478 (key)
8479 Lisp_Object key;
8480 {
8481 Lisp_Object item;
8482
8483 if (!INTEGERP (key))
8484 key = w32_parse_hot_key (key);
8485
8486 item = Fmemq (key, w32_grabbed_keys);
8487
8488 if (!NILP (item))
8489 {
8490 /* Notify input thread about hot-key definition being removed, so
8491 that it takes effect without needing focus switch. */
8492 #ifdef USE_LISP_UNION_TYPE
8493 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
8494 (WPARAM) XINT (XCAR (item)), (LPARAM) item.i))
8495 #else
8496 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
8497 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
8498 #endif
8499 {
8500 MSG msg;
8501 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
8502 }
8503 return Qt;
8504 }
8505 return Qnil;
8506 }
8507
8508 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
8509 Sw32_registered_hot_keys, 0, 0, 0,
8510 doc: /* Return list of registered hot-key IDs. */)
8511 ()
8512 {
8513 return Fdelq (Qnil, Fcopy_sequence (w32_grabbed_keys));
8514 }
8515
8516 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
8517 Sw32_reconstruct_hot_key, 1, 1, 0,
8518 doc: /* Convert hot-key ID to a lisp key combination.
8519 usage: (w32-reconstruct-hot-key ID) */)
8520 (hotkeyid)
8521 Lisp_Object hotkeyid;
8522 {
8523 int vk_code, w32_modifiers;
8524 Lisp_Object key;
8525
8526 CHECK_NUMBER (hotkeyid);
8527
8528 vk_code = HOTKEY_VK_CODE (hotkeyid);
8529 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
8530
8531 if (vk_code < 256 && lispy_function_keys[vk_code])
8532 key = intern (lispy_function_keys[vk_code]);
8533 else
8534 key = make_number (vk_code);
8535
8536 key = Fcons (key, Qnil);
8537 if (w32_modifiers & MOD_SHIFT)
8538 key = Fcons (Qshift, key);
8539 if (w32_modifiers & MOD_CONTROL)
8540 key = Fcons (Qctrl, key);
8541 if (w32_modifiers & MOD_ALT)
8542 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
8543 if (w32_modifiers & MOD_WIN)
8544 key = Fcons (Qhyper, key);
8545
8546 return key;
8547 }
8548
8549 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
8550 Sw32_toggle_lock_key, 1, 2, 0,
8551 doc: /* Toggle the state of the lock key KEY.
8552 KEY can be `capslock', `kp-numlock', or `scroll'.
8553 If the optional parameter NEW-STATE is a number, then the state of KEY
8554 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
8555 (key, new_state)
8556 Lisp_Object key, new_state;
8557 {
8558 int vk_code;
8559
8560 if (EQ (key, intern ("capslock")))
8561 vk_code = VK_CAPITAL;
8562 else if (EQ (key, intern ("kp-numlock")))
8563 vk_code = VK_NUMLOCK;
8564 else if (EQ (key, intern ("scroll")))
8565 vk_code = VK_SCROLL;
8566 else
8567 return Qnil;
8568
8569 if (!dwWindowsThreadId)
8570 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
8571
8572 #ifdef USE_LISP_UNION_TYPE
8573 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
8574 (WPARAM) vk_code, (LPARAM) new_state.i))
8575 #else
8576 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
8577 (WPARAM) vk_code, (LPARAM) new_state))
8578 #endif
8579 {
8580 MSG msg;
8581 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
8582 return make_number (msg.wParam);
8583 }
8584 return Qnil;
8585 }
8586
8587 DEFUN ("w32-window-exists-p", Fw32_window_exists_p, Sw32_window_exists_p,
8588 2, 2, 0,
8589 doc: /* Return non-nil if a window exists with the specified CLASS and NAME.
8590
8591 This is a direct interface to the Windows API FindWindow function. */)
8592 (class, name)
8593 Lisp_Object class, name;
8594 {
8595 HWND hnd;
8596
8597 if (!NILP (class))
8598 CHECK_STRING (class);
8599 if (!NILP (name))
8600 CHECK_STRING (name);
8601
8602 hnd = FindWindow (STRINGP (class) ? ((LPCTSTR) SDATA (class)) : NULL,
8603 STRINGP (name) ? ((LPCTSTR) SDATA (name)) : NULL);
8604 if (!hnd)
8605 return Qnil;
8606 return Qt;
8607 }
8608
8609 DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0,
8610 doc: /* Get power status information from Windows system.
8611
8612 The following %-sequences are provided:
8613 %L AC line status (verbose)
8614 %B Battery status (verbose)
8615 %b Battery status, empty means high, `-' means low,
8616 `!' means critical, and `+' means charging
8617 %p Battery load percentage
8618 %s Remaining time (to charge or discharge) in seconds
8619 %m Remaining time (to charge or discharge) in minutes
8620 %h Remaining time (to charge or discharge) in hours
8621 %t Remaining time (to charge or discharge) in the form `h:min' */)
8622 ()
8623 {
8624 Lisp_Object status = Qnil;
8625
8626 SYSTEM_POWER_STATUS system_status;
8627 if (GetSystemPowerStatus (&system_status))
8628 {
8629 Lisp_Object line_status, battery_status, battery_status_symbol;
8630 Lisp_Object load_percentage, seconds, minutes, hours, remain;
8631 Lisp_Object sequences[8];
8632
8633 long seconds_left = (long) system_status.BatteryLifeTime;
8634
8635 if (system_status.ACLineStatus == 0)
8636 line_status = build_string ("off-line");
8637 else if (system_status.ACLineStatus == 1)
8638 line_status = build_string ("on-line");
8639 else
8640 line_status = build_string ("N/A");
8641
8642 if (system_status.BatteryFlag & 128)
8643 {
8644 battery_status = build_string ("N/A");
8645 battery_status_symbol = build_string ("");
8646 }
8647 else if (system_status.BatteryFlag & 8)
8648 {
8649 battery_status = build_string ("charging");
8650 battery_status_symbol = build_string ("+");
8651 if (system_status.BatteryFullLifeTime != -1L)
8652 seconds_left = system_status.BatteryFullLifeTime - seconds_left;
8653 }
8654 else if (system_status.BatteryFlag & 4)
8655 {
8656 battery_status = build_string ("critical");
8657 battery_status_symbol = build_string ("!");
8658 }
8659 else if (system_status.BatteryFlag & 2)
8660 {
8661 battery_status = build_string ("low");
8662 battery_status_symbol = build_string ("-");
8663 }
8664 else if (system_status.BatteryFlag & 1)
8665 {
8666 battery_status = build_string ("high");
8667 battery_status_symbol = build_string ("");
8668 }
8669 else
8670 {
8671 battery_status = build_string ("medium");
8672 battery_status_symbol = build_string ("");
8673 }
8674
8675 if (system_status.BatteryLifePercent > 100)
8676 load_percentage = build_string ("N/A");
8677 else
8678 {
8679 char buffer[16];
8680 _snprintf (buffer, 16, "%d", system_status.BatteryLifePercent);
8681 load_percentage = build_string (buffer);
8682 }
8683
8684 if (seconds_left < 0)
8685 seconds = minutes = hours = remain = build_string ("N/A");
8686 else
8687 {
8688 long m;
8689 float h;
8690 char buffer[16];
8691 _snprintf (buffer, 16, "%ld", seconds_left);
8692 seconds = build_string (buffer);
8693
8694 m = seconds_left / 60;
8695 _snprintf (buffer, 16, "%ld", m);
8696 minutes = build_string (buffer);
8697
8698 h = seconds_left / 3600.0;
8699 _snprintf (buffer, 16, "%3.1f", h);
8700 hours = build_string (buffer);
8701
8702 _snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60);
8703 remain = build_string (buffer);
8704 }
8705 sequences[0] = Fcons (make_number ('L'), line_status);
8706 sequences[1] = Fcons (make_number ('B'), battery_status);
8707 sequences[2] = Fcons (make_number ('b'), battery_status_symbol);
8708 sequences[3] = Fcons (make_number ('p'), load_percentage);
8709 sequences[4] = Fcons (make_number ('s'), seconds);
8710 sequences[5] = Fcons (make_number ('m'), minutes);
8711 sequences[6] = Fcons (make_number ('h'), hours);
8712 sequences[7] = Fcons (make_number ('t'), remain);
8713
8714 status = Flist (8, sequences);
8715 }
8716 return status;
8717 }
8718
8719 \f
8720 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
8721 doc: /* Return storage information about the file system FILENAME is on.
8722 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
8723 storage of the file system, FREE is the free storage, and AVAIL is the
8724 storage available to a non-superuser. All 3 numbers are in bytes.
8725 If the underlying system call fails, value is nil. */)
8726 (filename)
8727 Lisp_Object filename;
8728 {
8729 Lisp_Object encoded, value;
8730
8731 CHECK_STRING (filename);
8732 filename = Fexpand_file_name (filename, Qnil);
8733 encoded = ENCODE_FILE (filename);
8734
8735 value = Qnil;
8736
8737 /* Determining the required information on Windows turns out, sadly,
8738 to be more involved than one would hope. The original Win32 api
8739 call for this will return bogus information on some systems, but we
8740 must dynamically probe for the replacement api, since that was
8741 added rather late on. */
8742 {
8743 HMODULE hKernel = GetModuleHandle ("kernel32");
8744 BOOL (*pfn_GetDiskFreeSpaceEx)
8745 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
8746 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
8747
8748 /* On Windows, we may need to specify the root directory of the
8749 volume holding FILENAME. */
8750 char rootname[MAX_PATH];
8751 char *name = SDATA (encoded);
8752
8753 /* find the root name of the volume if given */
8754 if (isalpha (name[0]) && name[1] == ':')
8755 {
8756 rootname[0] = name[0];
8757 rootname[1] = name[1];
8758 rootname[2] = '\\';
8759 rootname[3] = 0;
8760 }
8761 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
8762 {
8763 char *str = rootname;
8764 int slashes = 4;
8765 do
8766 {
8767 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
8768 break;
8769 *str++ = *name++;
8770 }
8771 while ( *name );
8772
8773 *str++ = '\\';
8774 *str = 0;
8775 }
8776
8777 if (pfn_GetDiskFreeSpaceEx)
8778 {
8779 /* Unsigned large integers cannot be cast to double, so
8780 use signed ones instead. */
8781 LARGE_INTEGER availbytes;
8782 LARGE_INTEGER freebytes;
8783 LARGE_INTEGER totalbytes;
8784
8785 if (pfn_GetDiskFreeSpaceEx (rootname,
8786 (ULARGE_INTEGER *)&availbytes,
8787 (ULARGE_INTEGER *)&totalbytes,
8788 (ULARGE_INTEGER *)&freebytes))
8789 value = list3 (make_float ((double) totalbytes.QuadPart),
8790 make_float ((double) freebytes.QuadPart),
8791 make_float ((double) availbytes.QuadPart));
8792 }
8793 else
8794 {
8795 DWORD sectors_per_cluster;
8796 DWORD bytes_per_sector;
8797 DWORD free_clusters;
8798 DWORD total_clusters;
8799
8800 if (GetDiskFreeSpace (rootname,
8801 &sectors_per_cluster,
8802 &bytes_per_sector,
8803 &free_clusters,
8804 &total_clusters))
8805 value = list3 (make_float ((double) total_clusters
8806 * sectors_per_cluster * bytes_per_sector),
8807 make_float ((double) free_clusters
8808 * sectors_per_cluster * bytes_per_sector),
8809 make_float ((double) free_clusters
8810 * sectors_per_cluster * bytes_per_sector));
8811 }
8812 }
8813
8814 return value;
8815 }
8816 \f
8817 DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
8818 0, 0, 0, doc: /* Return the name of Windows default printer device. */)
8819 ()
8820 {
8821 static char pname_buf[256];
8822 int err;
8823 HANDLE hPrn;
8824 PRINTER_INFO_2 *ppi2 = NULL;
8825 DWORD dwNeeded = 0, dwReturned = 0;
8826
8827 /* Retrieve the default string from Win.ini (the registry).
8828 * String will be in form "printername,drivername,portname".
8829 * This is the most portable way to get the default printer. */
8830 if (GetProfileString ("windows", "device", ",,", pname_buf, sizeof (pname_buf)) <= 0)
8831 return Qnil;
8832 /* printername precedes first "," character */
8833 strtok (pname_buf, ",");
8834 /* We want to know more than the printer name */
8835 if (!OpenPrinter (pname_buf, &hPrn, NULL))
8836 return Qnil;
8837 GetPrinter (hPrn, 2, NULL, 0, &dwNeeded);
8838 if (dwNeeded == 0)
8839 {
8840 ClosePrinter (hPrn);
8841 return Qnil;
8842 }
8843 /* Allocate memory for the PRINTER_INFO_2 struct */
8844 ppi2 = (PRINTER_INFO_2 *) xmalloc (dwNeeded);
8845 if (!ppi2)
8846 {
8847 ClosePrinter (hPrn);
8848 return Qnil;
8849 }
8850 /* Call GetPrinter again with big enouth memory block */
8851 err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
8852 ClosePrinter (hPrn);
8853 if (!err)
8854 {
8855 xfree (ppi2);
8856 return Qnil;
8857 }
8858
8859 if (ppi2)
8860 {
8861 if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName)
8862 {
8863 /* a remote printer */
8864 if (*ppi2->pServerName == '\\')
8865 _snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
8866 ppi2->pShareName);
8867 else
8868 _snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
8869 ppi2->pShareName);
8870 pname_buf[sizeof (pname_buf) - 1] = '\0';
8871 }
8872 else
8873 {
8874 /* a local printer */
8875 strncpy (pname_buf, ppi2->pPortName, sizeof (pname_buf));
8876 pname_buf[sizeof (pname_buf) - 1] = '\0';
8877 /* `pPortName' can include several ports, delimited by ','.
8878 * we only use the first one. */
8879 strtok (pname_buf, ",");
8880 }
8881 xfree (ppi2);
8882 }
8883
8884 return build_string (pname_buf);
8885 }
8886 \f
8887 /***********************************************************************
8888 Initialization
8889 ***********************************************************************/
8890
8891 /* Keep this list in the same order as frame_parms in frame.c.
8892 Use 0 for unsupported frame parameters. */
8893
8894 frame_parm_handler w32_frame_parm_handlers[] =
8895 {
8896 x_set_autoraise,
8897 x_set_autolower,
8898 x_set_background_color,
8899 x_set_border_color,
8900 x_set_border_width,
8901 x_set_cursor_color,
8902 x_set_cursor_type,
8903 x_set_font,
8904 x_set_foreground_color,
8905 x_set_icon_name,
8906 x_set_icon_type,
8907 x_set_internal_border_width,
8908 x_set_menu_bar_lines,
8909 x_set_mouse_color,
8910 x_explicitly_set_name,
8911 x_set_scroll_bar_width,
8912 x_set_title,
8913 x_set_unsplittable,
8914 x_set_vertical_scroll_bars,
8915 x_set_visibility,
8916 x_set_tool_bar_lines,
8917 0, /* x_set_scroll_bar_foreground, */
8918 0, /* x_set_scroll_bar_background, */
8919 x_set_screen_gamma,
8920 x_set_line_spacing,
8921 x_set_fringe_width,
8922 x_set_fringe_width,
8923 0, /* x_set_wait_for_wm, */
8924 x_set_fullscreen,
8925 x_set_font_backend,
8926 0 /* x_set_alpha, */
8927 };
8928
8929 void
8930 syms_of_w32fns ()
8931 {
8932 globals_of_w32fns ();
8933 /* This is zero if not using MS-Windows. */
8934 w32_in_use = 0;
8935 track_mouse_window = NULL;
8936
8937 w32_visible_system_caret_hwnd = NULL;
8938
8939 DEFSYM (Qnone, "none");
8940 DEFSYM (Qsuppress_icon, "suppress-icon");
8941 DEFSYM (Qundefined_color, "undefined-color");
8942 DEFSYM (Qcancel_timer, "cancel-timer");
8943 DEFSYM (Qhyper, "hyper");
8944 DEFSYM (Qsuper, "super");
8945 DEFSYM (Qmeta, "meta");
8946 DEFSYM (Qalt, "alt");
8947 DEFSYM (Qctrl, "ctrl");
8948 DEFSYM (Qcontrol, "control");
8949 DEFSYM (Qshift, "shift");
8950 /* This is the end of symbol initialization. */
8951
8952 /* Text property `display' should be nonsticky by default. */
8953 Vtext_property_default_nonsticky
8954 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
8955
8956
8957 Fput (Qundefined_color, Qerror_conditions,
8958 Fcons (Qundefined_color, Fcons (Qerror, Qnil)));
8959 Fput (Qundefined_color, Qerror_message,
8960 build_string ("Undefined color"));
8961
8962 staticpro (&w32_grabbed_keys);
8963 w32_grabbed_keys = Qnil;
8964
8965 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
8966 doc: /* An array of color name mappings for Windows. */);
8967 Vw32_color_map = Qnil;
8968
8969 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
8970 doc: /* Non-nil if Alt key presses are passed on to Windows.
8971 When non-nil, for example, Alt pressed and released and then space will
8972 open the System menu. When nil, Emacs processes the Alt key events, and
8973 then silently swallows them. */);
8974 Vw32_pass_alt_to_system = Qnil;
8975
8976 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
8977 doc: /* Non-nil if the Alt key is to be considered the same as the META key.
8978 When nil, Emacs will translate the Alt key to the ALT modifier, not to META. */);
8979 Vw32_alt_is_meta = Qt;
8980
8981 DEFVAR_INT ("w32-quit-key", &w32_quit_key,
8982 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
8983 w32_quit_key = 0;
8984
8985 DEFVAR_LISP ("w32-pass-lwindow-to-system",
8986 &Vw32_pass_lwindow_to_system,
8987 doc: /* If non-nil, the left \"Windows\" key is passed on to Windows.
8988
8989 When non-nil, the Start menu is opened by tapping the key.
8990 If you set this to nil, the left \"Windows\" key is processed by Emacs
8991 according to the value of `w32-lwindow-modifier', which see.
8992
8993 Note that some combinations of the left \"Windows\" key with other keys are
8994 caught by Windows at low level, and so binding them in Emacs will have no
8995 effect. For example, <lwindow>-r always pops up the Windows Run dialog,
8996 <lwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see
8997 the doc string of `w32-phantom-key-code'. */);
8998 Vw32_pass_lwindow_to_system = Qt;
8999
9000 DEFVAR_LISP ("w32-pass-rwindow-to-system",
9001 &Vw32_pass_rwindow_to_system,
9002 doc: /* If non-nil, the right \"Windows\" key is passed on to Windows.
9003
9004 When non-nil, the Start menu is opened by tapping the key.
9005 If you set this to nil, the right \"Windows\" key is processed by Emacs
9006 according to the value of `w32-rwindow-modifier', which see.
9007
9008 Note that some combinations of the right \"Windows\" key with other keys are
9009 caught by Windows at low level, and so binding them in Emacs will have no
9010 effect. For example, <rwindow>-r always pops up the Windows Run dialog,
9011 <rwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see
9012 the doc string of `w32-phantom-key-code'. */);
9013 Vw32_pass_rwindow_to_system = Qt;
9014
9015 DEFVAR_LISP ("w32-phantom-key-code",
9016 &Vw32_phantom_key_code,
9017 doc: /* Virtual key code used to generate \"phantom\" key presses.
9018 Value is a number between 0 and 255.
9019
9020 Phantom key presses are generated in order to stop the system from
9021 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
9022 `w32-pass-rwindow-to-system' is nil. */);
9023 /* Although 255 is technically not a valid key code, it works and
9024 means that this hack won't interfere with any real key code. */
9025 XSETINT (Vw32_phantom_key_code, 255);
9026
9027 DEFVAR_LISP ("w32-enable-num-lock",
9028 &Vw32_enable_num_lock,
9029 doc: /* If non-nil, the Num Lock key acts normally.
9030 Set to nil to handle Num Lock as the `kp-numlock' key. */);
9031 Vw32_enable_num_lock = Qt;
9032
9033 DEFVAR_LISP ("w32-enable-caps-lock",
9034 &Vw32_enable_caps_lock,
9035 doc: /* If non-nil, the Caps Lock key acts normally.
9036 Set to nil to handle Caps Lock as the `capslock' key. */);
9037 Vw32_enable_caps_lock = Qt;
9038
9039 DEFVAR_LISP ("w32-scroll-lock-modifier",
9040 &Vw32_scroll_lock_modifier,
9041 doc: /* Modifier to use for the Scroll Lock ON state.
9042 The value can be hyper, super, meta, alt, control or shift for the
9043 respective modifier, or nil to handle Scroll Lock as the `scroll' key.
9044 Any other value will cause the Scroll Lock key to be ignored. */);
9045 Vw32_scroll_lock_modifier = Qt;
9046
9047 DEFVAR_LISP ("w32-lwindow-modifier",
9048 &Vw32_lwindow_modifier,
9049 doc: /* Modifier to use for the left \"Windows\" key.
9050 The value can be hyper, super, meta, alt, control or shift for the
9051 respective modifier, or nil to appear as the `lwindow' key.
9052 Any other value will cause the key to be ignored. */);
9053 Vw32_lwindow_modifier = Qnil;
9054
9055 DEFVAR_LISP ("w32-rwindow-modifier",
9056 &Vw32_rwindow_modifier,
9057 doc: /* Modifier to use for the right \"Windows\" key.
9058 The value can be hyper, super, meta, alt, control or shift for the
9059 respective modifier, or nil to appear as the `rwindow' key.
9060 Any other value will cause the key to be ignored. */);
9061 Vw32_rwindow_modifier = Qnil;
9062
9063 DEFVAR_LISP ("w32-apps-modifier",
9064 &Vw32_apps_modifier,
9065 doc: /* Modifier to use for the \"Apps\" key.
9066 The value can be hyper, super, meta, alt, control or shift for the
9067 respective modifier, or nil to appear as the `apps' key.
9068 Any other value will cause the key to be ignored. */);
9069 Vw32_apps_modifier = Qnil;
9070
9071 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
9072 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
9073 w32_enable_synthesized_fonts = 0;
9074
9075 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
9076 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
9077 Vw32_enable_palette = Qt;
9078
9079 DEFVAR_INT ("w32-mouse-button-tolerance",
9080 &w32_mouse_button_tolerance,
9081 doc: /* Analogue of double click interval for faking middle mouse events.
9082 The value is the minimum time in milliseconds that must elapse between
9083 left and right button down events before they are considered distinct events.
9084 If both mouse buttons are depressed within this interval, a middle mouse
9085 button down event is generated instead. */);
9086 w32_mouse_button_tolerance = GetDoubleClickTime () / 2;
9087
9088 DEFVAR_INT ("w32-mouse-move-interval",
9089 &w32_mouse_move_interval,
9090 doc: /* Minimum interval between mouse move events.
9091 The value is the minimum time in milliseconds that must elapse between
9092 successive mouse move (or scroll bar drag) events before they are
9093 reported as lisp events. */);
9094 w32_mouse_move_interval = 0;
9095
9096 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
9097 &w32_pass_extra_mouse_buttons_to_system,
9098 doc: /* If non-nil, the fourth and fifth mouse buttons are passed to Windows.
9099 Recent versions of Windows support mice with up to five buttons.
9100 Since most applications don't support these extra buttons, most mouse
9101 drivers will allow you to map them to functions at the system level.
9102 If this variable is non-nil, Emacs will pass them on, allowing the
9103 system to handle them. */);
9104 w32_pass_extra_mouse_buttons_to_system = 0;
9105
9106 DEFVAR_BOOL ("w32-pass-multimedia-buttons-to-system",
9107 &w32_pass_multimedia_buttons_to_system,
9108 doc: /* If non-nil, media buttons are passed to Windows.
9109 Some modern keyboards contain buttons for controlling media players, web
9110 browsers and other applications. Generally these buttons are handled on a
9111 system wide basis, but by setting this to nil they are made available
9112 to Emacs for binding. Depending on your keyboard, additional keys that
9113 may be available are:
9114
9115 browser-back, browser-forward, browser-refresh, browser-stop,
9116 browser-search, browser-favorites, browser-home,
9117 mail, mail-reply, mail-forward, mail-send,
9118 app-1, app-2,
9119 help, find, new, open, close, save, print, undo, redo, copy, cut, paste,
9120 spell-check, correction-list, toggle-dictate-command,
9121 media-next, media-previous, media-stop, media-play-pause, media-select,
9122 media-play, media-pause, media-record, media-fast-forward, media-rewind,
9123 media-channel-up, media-channel-down,
9124 volume-mute, volume-up, volume-down,
9125 mic-volume-mute, mic-volume-down, mic-volume-up, mic-toggle,
9126 bass-down, bass-boost, bass-up, treble-down, treble-up */);
9127 w32_pass_multimedia_buttons_to_system = 1;
9128
9129 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
9130 doc: /* The shape of the pointer when over text.
9131 Changing the value does not affect existing frames
9132 unless you set the mouse color. */);
9133 Vx_pointer_shape = Qnil;
9134
9135 Vx_nontext_pointer_shape = Qnil;
9136
9137 Vx_mode_pointer_shape = Qnil;
9138
9139 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
9140 doc: /* The shape of the pointer when Emacs is busy.
9141 This variable takes effect when you create a new frame
9142 or when you set the mouse color. */);
9143 Vx_hourglass_pointer_shape = Qnil;
9144
9145 DEFVAR_BOOL ("display-hourglass", &display_hourglass_p,
9146 doc: /* Non-zero means Emacs displays an hourglass pointer on window systems. */);
9147 display_hourglass_p = 1;
9148
9149 DEFVAR_LISP ("hourglass-delay", &Vhourglass_delay,
9150 doc: /* *Seconds to wait before displaying an hourglass pointer.
9151 Value must be an integer or float. */);
9152 Vhourglass_delay = make_number (DEFAULT_HOURGLASS_DELAY);
9153
9154 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
9155 &Vx_sensitive_text_pointer_shape,
9156 doc: /* The shape of the pointer when over mouse-sensitive text.
9157 This variable takes effect when you create a new frame
9158 or when you set the mouse color. */);
9159 Vx_sensitive_text_pointer_shape = Qnil;
9160
9161 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
9162 &Vx_window_horizontal_drag_shape,
9163 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
9164 This variable takes effect when you create a new frame
9165 or when you set the mouse color. */);
9166 Vx_window_horizontal_drag_shape = Qnil;
9167
9168 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
9169 doc: /* A string indicating the foreground color of the cursor box. */);
9170 Vx_cursor_fore_pixel = Qnil;
9171
9172 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
9173 doc: /* Maximum size for tooltips.
9174 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
9175 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
9176
9177 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
9178 doc: /* Non-nil if no window manager is in use.
9179 Emacs doesn't try to figure this out; this is always nil
9180 unless you set it to something else. */);
9181 /* We don't have any way to find this out, so set it to nil
9182 and maybe the user would like to set it to t. */
9183 Vx_no_window_manager = Qnil;
9184
9185 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
9186 &Vx_pixel_size_width_font_regexp,
9187 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
9188
9189 Since Emacs gets width of a font matching with this regexp from
9190 PIXEL_SIZE field of the name, font finding mechanism gets faster for
9191 such a font. This is especially effective for such large fonts as
9192 Chinese, Japanese, and Korean. */);
9193 Vx_pixel_size_width_font_regexp = Qnil;
9194
9195 DEFVAR_LISP ("w32-bdf-filename-alist",
9196 &Vw32_bdf_filename_alist,
9197 doc: /* List of bdf fonts and their corresponding filenames. */);
9198 Vw32_bdf_filename_alist = Qnil;
9199
9200 DEFVAR_BOOL ("w32-strict-fontnames",
9201 &w32_strict_fontnames,
9202 doc: /* Non-nil means only use fonts that are exact matches for those requested.
9203 Default is nil, which allows old fontnames that are not XLFD compliant,
9204 and allows third-party CJK display to work by specifying false charset
9205 fields to trick Emacs into translating to Big5, SJIS etc.
9206 Setting this to t will prevent wrong fonts being selected when
9207 fontsets are automatically created. */);
9208 w32_strict_fontnames = 0;
9209
9210 DEFVAR_BOOL ("w32-strict-painting",
9211 &w32_strict_painting,
9212 doc: /* Non-nil means use strict rules for repainting frames.
9213 Set this to nil to get the old behavior for repainting; this should
9214 only be necessary if the default setting causes problems. */);
9215 w32_strict_painting = 1;
9216
9217 DEFVAR_LISP ("w32-charset-info-alist",
9218 &Vw32_charset_info_alist,
9219 doc: /* Alist linking Emacs character sets to Windows fonts and codepages.
9220 Each entry should be of the form:
9221
9222 (CHARSET_NAME . (WINDOWS_CHARSET . CODEPAGE))
9223
9224 where CHARSET_NAME is a string used in font names to identify the charset,
9225 WINDOWS_CHARSET is a symbol that can be one of:
9226 w32-charset-ansi, w32-charset-default, w32-charset-symbol,
9227 w32-charset-shiftjis, w32-charset-hangeul, w32-charset-gb2312,
9228 w32-charset-chinesebig5,
9229 w32-charset-johab, w32-charset-hebrew,
9230 w32-charset-arabic, w32-charset-greek, w32-charset-turkish,
9231 w32-charset-vietnamese, w32-charset-thai, w32-charset-easteurope,
9232 w32-charset-russian, w32-charset-mac, w32-charset-baltic,
9233 w32-charset-unicode,
9234 or w32-charset-oem.
9235 CODEPAGE should be an integer specifying the codepage that should be used
9236 to display the character set, t to do no translation and output as Unicode,
9237 or nil to do no translation and output as 8 bit (or multibyte on far-east
9238 versions of Windows) characters. */);
9239 Vw32_charset_info_alist = Qnil;
9240
9241 DEFSYM (Qw32_charset_ansi, "w32-charset-ansi");
9242 DEFSYM (Qw32_charset_symbol, "w32-charset-symbol");
9243 DEFSYM (Qw32_charset_default, "w32-charset-default");
9244 DEFSYM (Qw32_charset_shiftjis, "w32-charset-shiftjis");
9245 DEFSYM (Qw32_charset_hangeul, "w32-charset-hangeul");
9246 DEFSYM (Qw32_charset_chinesebig5, "w32-charset-chinesebig5");
9247 DEFSYM (Qw32_charset_gb2312, "w32-charset-gb2312");
9248 DEFSYM (Qw32_charset_oem, "w32-charset-oem");
9249
9250 #ifdef JOHAB_CHARSET
9251 {
9252 static int w32_extra_charsets_defined = 1;
9253 DEFVAR_BOOL ("w32-extra-charsets-defined", &w32_extra_charsets_defined,
9254 doc: /* Internal variable. */);
9255
9256 DEFSYM (Qw32_charset_johab, "w32-charset-johab");
9257 DEFSYM (Qw32_charset_easteurope, "w32-charset-easteurope");
9258 DEFSYM (Qw32_charset_turkish, "w32-charset-turkish");
9259 DEFSYM (Qw32_charset_baltic, "w32-charset-baltic");
9260 DEFSYM (Qw32_charset_russian, "w32-charset-russian");
9261 DEFSYM (Qw32_charset_arabic, "w32-charset-arabic");
9262 DEFSYM (Qw32_charset_greek, "w32-charset-greek");
9263 DEFSYM (Qw32_charset_hebrew, "w32-charset-hebrew");
9264 DEFSYM (Qw32_charset_vietnamese, "w32-charset-vietnamese");
9265 DEFSYM (Qw32_charset_thai, "w32-charset-thai");
9266 DEFSYM (Qw32_charset_mac, "w32-charset-mac");
9267 }
9268 #endif
9269
9270 #ifdef UNICODE_CHARSET
9271 {
9272 static int w32_unicode_charset_defined = 1;
9273 DEFVAR_BOOL ("w32-unicode-charset-defined",
9274 &w32_unicode_charset_defined,
9275 doc: /* Internal variable. */);
9276 DEFSYM (Qw32_charset_unicode, "w32-charset-unicode");
9277 }
9278 #endif
9279
9280 #if 0 /* TODO: Port to W32 */
9281 defsubr (&Sx_change_window_property);
9282 defsubr (&Sx_delete_window_property);
9283 defsubr (&Sx_window_property);
9284 #endif
9285 defsubr (&Sxw_display_color_p);
9286 defsubr (&Sx_display_grayscale_p);
9287 defsubr (&Sxw_color_defined_p);
9288 defsubr (&Sxw_color_values);
9289 defsubr (&Sx_server_max_request_size);
9290 defsubr (&Sx_server_vendor);
9291 defsubr (&Sx_server_version);
9292 defsubr (&Sx_display_pixel_width);
9293 defsubr (&Sx_display_pixel_height);
9294 defsubr (&Sx_display_mm_width);
9295 defsubr (&Sx_display_mm_height);
9296 defsubr (&Sx_display_screens);
9297 defsubr (&Sx_display_planes);
9298 defsubr (&Sx_display_color_cells);
9299 defsubr (&Sx_display_visual_class);
9300 defsubr (&Sx_display_backing_store);
9301 defsubr (&Sx_display_save_under);
9302 defsubr (&Sx_create_frame);
9303 defsubr (&Sx_open_connection);
9304 defsubr (&Sx_close_connection);
9305 defsubr (&Sx_display_list);
9306 defsubr (&Sx_synchronize);
9307 defsubr (&Sx_focus_frame);
9308
9309 /* W32 specific functions */
9310
9311 defsubr (&Sw32_select_font);
9312 defsubr (&Sw32_define_rgb_color);
9313 defsubr (&Sw32_default_color_map);
9314 defsubr (&Sw32_load_color_file);
9315 defsubr (&Sw32_send_sys_command);
9316 defsubr (&Sw32_shell_execute);
9317 defsubr (&Sw32_register_hot_key);
9318 defsubr (&Sw32_unregister_hot_key);
9319 defsubr (&Sw32_registered_hot_keys);
9320 defsubr (&Sw32_reconstruct_hot_key);
9321 defsubr (&Sw32_toggle_lock_key);
9322 defsubr (&Sw32_window_exists_p);
9323 #if OLD_FONT
9324 defsubr (&Sw32_find_bdf_fonts);
9325 #endif
9326 defsubr (&Sw32_battery_status);
9327
9328 defsubr (&Sfile_system_info);
9329 defsubr (&Sdefault_printer_name);
9330
9331 #if OLD_FONT
9332 /* Setting callback functions for fontset handler. */
9333 get_font_info_func = w32_get_font_info;
9334
9335 #if 0 /* This function pointer doesn't seem to be used anywhere.
9336 And the pointer assigned has the wrong type, anyway. */
9337 list_fonts_func = w32_list_fonts;
9338 #endif
9339
9340 load_font_func = w32_load_font;
9341 find_ccl_program_func = w32_find_ccl_program;
9342 query_font_func = w32_query_font;
9343 set_frame_fontset_func = x_set_font;
9344 get_font_repertory_func = x_get_font_repertory;
9345 #endif
9346 check_window_system_func = check_w32;
9347
9348
9349 hourglass_timer = 0;
9350 hourglass_hwnd = NULL;
9351 hourglass_shown_p = 0;
9352 defsubr (&Sx_show_tip);
9353 defsubr (&Sx_hide_tip);
9354 tip_timer = Qnil;
9355 staticpro (&tip_timer);
9356 tip_frame = Qnil;
9357 staticpro (&tip_frame);
9358
9359 last_show_tip_args = Qnil;
9360 staticpro (&last_show_tip_args);
9361
9362 defsubr (&Sx_file_dialog);
9363 }
9364
9365
9366 /*
9367 globals_of_w32fns is used to initialize those global variables that
9368 must always be initialized on startup even when the global variable
9369 initialized is non zero (see the function main in emacs.c).
9370 globals_of_w32fns is called from syms_of_w32fns when the global
9371 variable initialized is 0 and directly from main when initialized
9372 is non zero.
9373 */
9374 void
9375 globals_of_w32fns ()
9376 {
9377 HMODULE user32_lib = GetModuleHandle ("user32.dll");
9378 /*
9379 TrackMouseEvent not available in all versions of Windows, so must load
9380 it dynamically. Do it once, here, instead of every time it is used.
9381 */
9382 track_mouse_event_fn = (TrackMouseEvent_Proc)
9383 GetProcAddress (user32_lib, "TrackMouseEvent");
9384 /* ditto for GetClipboardSequenceNumber. */
9385 clipboard_sequence_fn = (ClipboardSequence_Proc)
9386 GetProcAddress (user32_lib, "GetClipboardSequenceNumber");
9387
9388 monitor_from_point_fn = (MonitorFromPoint_Proc)
9389 GetProcAddress (user32_lib, "MonitorFromPoint");
9390 get_monitor_info_fn = (GetMonitorInfo_Proc)
9391 GetProcAddress (user32_lib, "GetMonitorInfoA");
9392
9393 {
9394 HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
9395 get_composition_string_fn = (ImmGetCompositionString_Proc)
9396 GetProcAddress (imm32_lib, "ImmGetCompositionStringW");
9397 get_ime_context_fn = (ImmGetContext_Proc)
9398 GetProcAddress (imm32_lib, "ImmGetContext");
9399 }
9400 DEFVAR_INT ("w32-ansi-code-page",
9401 &w32_ansi_code_page,
9402 doc: /* The ANSI code page used by the system. */);
9403 w32_ansi_code_page = GetACP ();
9404
9405 /* MessageBox does not work without this when linked to comctl32.dll 6.0. */
9406 InitCommonControls ();
9407
9408 syms_of_w32uniscribe ();
9409 }
9410
9411 #undef abort
9412
9413 void
9414 w32_abort ()
9415 {
9416 int button;
9417 button = MessageBox (NULL,
9418 "A fatal error has occurred!\n\n"
9419 "Would you like to attach a debugger?\n\n"
9420 "Select YES to debug, NO to abort Emacs"
9421 #if __GNUC__
9422 "\n\n(type \"gdb -p <emacs-PID>\" and\n"
9423 "\"continue\" inside GDB before clicking YES.)"
9424 #endif
9425 , "Emacs Abort Dialog",
9426 MB_ICONEXCLAMATION | MB_TASKMODAL
9427 | MB_SETFOREGROUND | MB_YESNO);
9428 switch (button)
9429 {
9430 case IDYES:
9431 DebugBreak ();
9432 exit (2); /* tell the compiler we will never return */
9433 case IDNO:
9434 default:
9435 abort ();
9436 break;
9437 }
9438 }
9439
9440 /* For convenience when debugging. */
9441 int
9442 w32_last_error ()
9443 {
9444 return GetLastError ();
9445 }
9446
9447 /* arch-tag: 707589ab-b9be-4638-8cdd-74629cc9b446
9448 (do not change this comment) */