merge trunk
[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, 2009, 2010
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 #include <setjmp.h>
31
32 #include "lisp.h"
33 #include "w32term.h"
34 #include "frame.h"
35 #include "window.h"
36 #include "buffer.h"
37 #include "intervals.h"
38 #include "dispextern.h"
39 #include "keyboard.h"
40 #include "blockinput.h"
41 #include "epaths.h"
42 #include "character.h"
43 #include "charset.h"
44 #include "coding.h"
45 #include "ccl.h"
46 #include "fontset.h"
47 #include "systime.h"
48 #include "termhooks.h"
49 #include "w32heap.h"
50 #include "w32.h"
51
52 #include "bitmaps/gray.xbm"
53
54 #include <commctrl.h>
55 #include <commdlg.h>
56 #include <shellapi.h>
57 #include <ctype.h>
58 #include <winspool.h>
59 #include <objbase.h>
60
61 #include <dlgs.h>
62 #include <imm.h>
63 #define FILE_NAME_TEXT_FIELD edt1
64
65 #include "font.h"
66 #include "w32font.h"
67
68 #ifndef FOF_NO_CONNECTED_ELEMENTS
69 #define FOF_NO_CONNECTED_ELEMENTS 0x2000
70 #endif
71
72 void syms_of_w32fns (void);
73 void globals_of_w32fns (void);
74
75 extern void free_frame_menubar (struct frame *);
76 extern double atof (const char *);
77 extern int w32_console_toggle_lock_key (int, Lisp_Object);
78 extern void w32_menu_display_help (HWND, HMENU, UINT, UINT);
79 extern void w32_free_menu_strings (HWND);
80 extern const char *map_w32_filename (const char *, const char **);
81
82 extern int quit_char;
83
84 extern char *lispy_function_keys[];
85
86 /* The colormap for converting color names to RGB values */
87 Lisp_Object Vw32_color_map;
88
89 /* Non nil if alt key presses are passed on to Windows. */
90 Lisp_Object Vw32_pass_alt_to_system;
91
92 /* Non nil if alt key is translated to meta_modifier, nil if it is translated
93 to alt_modifier. */
94 Lisp_Object Vw32_alt_is_meta;
95
96 /* If non-zero, the windows virtual key code for an alternative quit key. */
97 int w32_quit_key;
98
99 /* Non nil if left window key events are passed on to Windows (this only
100 affects whether "tapping" the key opens the Start menu). */
101 Lisp_Object Vw32_pass_lwindow_to_system;
102
103 /* Non nil if right window key events are passed on to Windows (this
104 only affects whether "tapping" the key opens the Start menu). */
105 Lisp_Object Vw32_pass_rwindow_to_system;
106
107 /* Virtual key code used to generate "phantom" key presses in order
108 to stop system from acting on Windows key events. */
109 Lisp_Object Vw32_phantom_key_code;
110
111 /* Modifier associated with the left "Windows" key, or nil to act as a
112 normal key. */
113 Lisp_Object Vw32_lwindow_modifier;
114
115 /* Modifier associated with the right "Windows" key, or nil to act as a
116 normal key. */
117 Lisp_Object Vw32_rwindow_modifier;
118
119 /* Modifier associated with the "Apps" key, or nil to act as a normal
120 key. */
121 Lisp_Object Vw32_apps_modifier;
122
123 /* Value is nil if Num Lock acts as a function key. */
124 Lisp_Object Vw32_enable_num_lock;
125
126 /* Value is nil if Caps Lock acts as a function key. */
127 Lisp_Object Vw32_enable_caps_lock;
128
129 /* Modifier associated with Scroll Lock, or nil to act as a normal key. */
130 Lisp_Object Vw32_scroll_lock_modifier;
131
132 /* Switch to control whether we inhibit requests for synthesized bold
133 and italic versions of fonts. */
134 int w32_enable_synthesized_fonts;
135
136 /* Enable palette management. */
137 Lisp_Object Vw32_enable_palette;
138
139 /* Control how close left/right button down events must be to
140 be converted to a middle button down event. */
141 int w32_mouse_button_tolerance;
142
143 /* Minimum interval between mouse movement (and scroll bar drag)
144 events that are passed on to the event loop. */
145 int w32_mouse_move_interval;
146
147 /* Flag to indicate if XBUTTON events should be passed on to Windows. */
148 static int w32_pass_extra_mouse_buttons_to_system;
149
150 /* Flag to indicate if media keys should be passed on to Windows. */
151 static int w32_pass_multimedia_buttons_to_system;
152
153 /* Non nil if no window manager is in use. */
154 Lisp_Object Vx_no_window_manager;
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 #if 0 /* TODO: Mouse cursor customization. */
162 /* The background and shape of the mouse pointer, and shape when not
163 over text or in the modeline. */
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 #endif
171
172 #ifndef IDC_HAND
173 #define IDC_HAND MAKEINTRESOURCE(32649)
174 #endif
175
176 /* Color of chars displayed in cursor box. */
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 Lisp_Object Qnone;
198 Lisp_Object Qsuppress_icon;
199 Lisp_Object Qundefined_color;
200 Lisp_Object Qcancel_timer;
201 Lisp_Object Qfont_param;
202 Lisp_Object Qhyper;
203 Lisp_Object Qsuper;
204 Lisp_Object Qmeta;
205 Lisp_Object Qalt;
206 Lisp_Object Qctrl;
207 Lisp_Object Qcontrol;
208 Lisp_Object Qshift;
209
210
211 /* The ANSI codepage. */
212 int w32_ansi_code_page;
213
214 /* Prefix for system colors. */
215 #define SYSTEM_COLOR_PREFIX "System"
216 #define SYSTEM_COLOR_PREFIX_LEN (sizeof (SYSTEM_COLOR_PREFIX) - 1)
217
218 /* State variables for emulating a three button mouse. */
219 #define LMOUSE 1
220 #define MMOUSE 2
221 #define RMOUSE 4
222
223 static int button_state = 0;
224 static W32Msg saved_mouse_button_msg;
225 static unsigned mouse_button_timer = 0; /* non-zero when timer is active */
226 static W32Msg saved_mouse_move_msg;
227 static unsigned mouse_move_timer = 0;
228
229 /* Window that is tracking the mouse. */
230 static HWND track_mouse_window;
231
232 /* Multi-monitor API definitions that are not pulled from the headers
233 since we are compiling for NT 4. */
234 #ifndef MONITOR_DEFAULT_TO_NEAREST
235 #define MONITOR_DEFAULT_TO_NEAREST 2
236 #endif
237 /* MinGW headers define MONITORINFO unconditionally, but MSVC ones don't.
238 To avoid a compile error on one or the other, redefine with a new name. */
239 struct MONITOR_INFO
240 {
241 DWORD cbSize;
242 RECT rcMonitor;
243 RECT rcWork;
244 DWORD dwFlags;
245 };
246
247 /* Reportedly, VS 6 does not have this in its headers. */
248 #if defined(_MSC_VER) && _MSC_VER < 1300
249 DECLARE_HANDLE(HMONITOR);
250 #endif
251
252 typedef BOOL (WINAPI * TrackMouseEvent_Proc)
253 (IN OUT LPTRACKMOUSEEVENT lpEventTrack);
254 typedef LONG (WINAPI * ImmGetCompositionString_Proc)
255 (IN HIMC context, IN DWORD index, OUT LPVOID buffer, IN DWORD bufLen);
256 typedef HIMC (WINAPI * ImmGetContext_Proc) (IN HWND window);
257 typedef HWND (WINAPI * ImmReleaseContext_Proc) (IN HWND wnd, IN HIMC context);
258 typedef HWND (WINAPI * ImmSetCompositionWindow_Proc) (IN HIMC context,
259 IN COMPOSITIONFORM *form);
260 typedef HMONITOR (WINAPI * MonitorFromPoint_Proc) (IN POINT pt, IN DWORD flags);
261 typedef BOOL (WINAPI * GetMonitorInfo_Proc)
262 (IN HMONITOR monitor, OUT struct MONITOR_INFO* info);
263
264 TrackMouseEvent_Proc track_mouse_event_fn = NULL;
265 ClipboardSequence_Proc clipboard_sequence_fn = NULL;
266 ImmGetCompositionString_Proc get_composition_string_fn = NULL;
267 ImmGetContext_Proc get_ime_context_fn = NULL;
268 ImmReleaseContext_Proc release_ime_context_fn = NULL;
269 ImmSetCompositionWindow_Proc set_ime_composition_window_fn = NULL;
270 MonitorFromPoint_Proc monitor_from_point_fn = NULL;
271 GetMonitorInfo_Proc get_monitor_info_fn = NULL;
272
273 extern AppendMenuW_Proc unicode_append_menu;
274
275 /* Flag to selectively ignore WM_IME_CHAR messages. */
276 static int ignore_ime_char = 0;
277
278 /* W95 mousewheel handler */
279 unsigned int msh_mousewheel = 0;
280
281 /* Timers */
282 #define MOUSE_BUTTON_ID 1
283 #define MOUSE_MOVE_ID 2
284 #define MENU_FREE_ID 3
285 #define HOURGLASS_ID 4
286 /* The delay (milliseconds) before a menu is freed after WM_EXITMENULOOP
287 is received. */
288 #define MENU_FREE_DELAY 1000
289 static unsigned menu_free_timer = 0;
290
291 /* The below are defined in frame.c. */
292
293 extern Lisp_Object Vmenu_bar_mode, Vtool_bar_mode;
294 extern Lisp_Object Vwindow_system_version;
295
296 #ifdef GLYPH_DEBUG
297 int image_cache_refcount, dpyinfo_refcount;
298 #endif
299
300
301 /* From w32term.c. */
302 extern int w32_num_mouse_buttons;
303 extern Lisp_Object Vw32_recognize_altgr;
304
305 extern HWND w32_system_caret_hwnd;
306
307 extern int w32_system_caret_height;
308 extern int w32_system_caret_x;
309 extern int w32_system_caret_y;
310 extern int w32_use_visible_system_caret;
311
312 static HWND w32_visible_system_caret_hwnd;
313
314 /* From w32menu.c */
315 extern HMENU current_popup_menu;
316 static int menubar_in_use = 0;
317
318 /* From w32uniscribe.c */
319 extern void syms_of_w32uniscribe (void);
320 extern int uniscribe_available;
321
322 /* Function prototypes for hourglass support. */
323 static void w32_show_hourglass (struct frame *);
324 static void w32_hide_hourglass (void);
325
326
327 \f
328 /* Error if we are not connected to MS-Windows. */
329 void
330 check_w32 (void)
331 {
332 if (! w32_in_use)
333 error ("MS-Windows not in use or not initialized");
334 }
335
336 /* Nonzero if we can use mouse menus.
337 You should not call this unless HAVE_MENUS is defined. */
338
339 int
340 have_menus_p (void)
341 {
342 return w32_in_use;
343 }
344
345 /* Extract a frame as a FRAME_PTR, defaulting to the selected frame
346 and checking validity for W32. */
347
348 FRAME_PTR
349 check_x_frame (Lisp_Object frame)
350 {
351 FRAME_PTR f;
352
353 if (NILP (frame))
354 frame = selected_frame;
355 CHECK_LIVE_FRAME (frame);
356 f = XFRAME (frame);
357 if (! FRAME_W32_P (f))
358 error ("Non-W32 frame used");
359 return f;
360 }
361
362 /* Let the user specify a display with a frame.
363 nil stands for the selected frame--or, if that is not a w32 frame,
364 the first display on the list. */
365
366 struct w32_display_info *
367 check_x_display_info (Lisp_Object frame)
368 {
369 if (NILP (frame))
370 {
371 struct frame *sf = XFRAME (selected_frame);
372
373 if (FRAME_W32_P (sf) && FRAME_LIVE_P (sf))
374 return FRAME_W32_DISPLAY_INFO (sf);
375 else
376 return &one_w32_display_info;
377 }
378 else if (STRINGP (frame))
379 return x_display_info_for_name (frame);
380 else
381 {
382 FRAME_PTR f;
383
384 CHECK_LIVE_FRAME (frame);
385 f = XFRAME (frame);
386 if (! FRAME_W32_P (f))
387 error ("Non-W32 frame used");
388 return FRAME_W32_DISPLAY_INFO (f);
389 }
390 }
391 \f
392 /* Return the Emacs frame-object corresponding to an w32 window.
393 It could be the frame's main window or an icon window. */
394
395 /* This function can be called during GC, so use GC_xxx type test macros. */
396
397 struct frame *
398 x_window_to_frame (struct w32_display_info *dpyinfo, HWND wdesc)
399 {
400 Lisp_Object tail, frame;
401 struct frame *f;
402
403 for (tail = Vframe_list; CONSP (tail); tail = XCDR (tail))
404 {
405 frame = XCAR (tail);
406 if (!FRAMEP (frame))
407 continue;
408 f = XFRAME (frame);
409 if (!FRAME_W32_P (f) || FRAME_W32_DISPLAY_INFO (f) != dpyinfo)
410 continue;
411
412 if (FRAME_W32_WINDOW (f) == wdesc)
413 return f;
414 }
415 return 0;
416 }
417
418 \f
419 static Lisp_Object unwind_create_frame (Lisp_Object);
420 static Lisp_Object unwind_create_tip_frame (Lisp_Object);
421 static void my_create_window (struct frame *);
422 static void my_create_tip_window (struct frame *);
423
424 /* TODO: Native Input Method support; see x_create_im. */
425 void x_set_foreground_color (struct frame *, Lisp_Object, Lisp_Object);
426 void x_set_background_color (struct frame *, Lisp_Object, Lisp_Object);
427 void x_set_mouse_color (struct frame *, Lisp_Object, Lisp_Object);
428 void x_set_cursor_color (struct frame *, Lisp_Object, Lisp_Object);
429 void x_set_border_color (struct frame *, Lisp_Object, Lisp_Object);
430 void x_set_cursor_type (struct frame *, Lisp_Object, Lisp_Object);
431 void x_set_icon_type (struct frame *, Lisp_Object, Lisp_Object);
432 void x_set_icon_name (struct frame *, Lisp_Object, Lisp_Object);
433 void x_explicitly_set_name (struct frame *, Lisp_Object, Lisp_Object);
434 void x_set_menu_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
435 void x_set_title (struct frame *, Lisp_Object, Lisp_Object);
436 void x_set_tool_bar_lines (struct frame *, Lisp_Object, Lisp_Object);
437 static void x_edge_detection (struct frame *, struct image *, Lisp_Object,
438 Lisp_Object);
439
440
441 \f
442
443 /* Store the screen positions of frame F into XPTR and YPTR.
444 These are the positions of the containing window manager window,
445 not Emacs's own window. */
446
447 void
448 x_real_positions (FRAME_PTR f, int *xptr, int *yptr)
449 {
450 POINT pt;
451 RECT rect;
452
453 /* Get the bounds of the WM window. */
454 GetWindowRect (FRAME_W32_WINDOW (f), &rect);
455
456 pt.x = 0;
457 pt.y = 0;
458
459 /* Convert (0, 0) in the client area to screen co-ordinates. */
460 ClientToScreen (FRAME_W32_WINDOW (f), &pt);
461
462 /* Remember x_pixels_diff and y_pixels_diff. */
463 f->x_pixels_diff = pt.x - rect.left;
464 f->y_pixels_diff = pt.y - rect.top;
465
466 *xptr = rect.left;
467 *yptr = rect.top;
468 }
469
470 \f
471
472 DEFUN ("w32-define-rgb-color", Fw32_define_rgb_color,
473 Sw32_define_rgb_color, 4, 4, 0,
474 doc: /* Convert RGB numbers to a Windows color reference and associate with NAME.
475 This adds or updates a named color to `w32-color-map', making it
476 available for use. The original entry's RGB ref is returned, or nil
477 if the entry is new. */)
478 (Lisp_Object red, Lisp_Object green, Lisp_Object blue, Lisp_Object name)
479 {
480 Lisp_Object rgb;
481 Lisp_Object oldrgb = Qnil;
482 Lisp_Object entry;
483
484 CHECK_NUMBER (red);
485 CHECK_NUMBER (green);
486 CHECK_NUMBER (blue);
487 CHECK_STRING (name);
488
489 XSETINT (rgb, RGB (XUINT (red), XUINT (green), XUINT (blue)));
490
491 BLOCK_INPUT;
492
493 /* replace existing entry in w32-color-map or add new entry. */
494 entry = Fassoc (name, Vw32_color_map);
495 if (NILP (entry))
496 {
497 entry = Fcons (name, rgb);
498 Vw32_color_map = Fcons (entry, Vw32_color_map);
499 }
500 else
501 {
502 oldrgb = Fcdr (entry);
503 Fsetcdr (entry, rgb);
504 }
505
506 UNBLOCK_INPUT;
507
508 return (oldrgb);
509 }
510
511 /* The default colors for the w32 color map */
512 typedef struct colormap_t
513 {
514 char *name;
515 COLORREF colorref;
516 } colormap_t;
517
518 colormap_t w32_color_map[] =
519 {
520 {"snow" , PALETTERGB (255,250,250)},
521 {"ghost white" , PALETTERGB (248,248,255)},
522 {"GhostWhite" , PALETTERGB (248,248,255)},
523 {"white smoke" , PALETTERGB (245,245,245)},
524 {"WhiteSmoke" , PALETTERGB (245,245,245)},
525 {"gainsboro" , PALETTERGB (220,220,220)},
526 {"floral white" , PALETTERGB (255,250,240)},
527 {"FloralWhite" , PALETTERGB (255,250,240)},
528 {"old lace" , PALETTERGB (253,245,230)},
529 {"OldLace" , PALETTERGB (253,245,230)},
530 {"linen" , PALETTERGB (250,240,230)},
531 {"antique white" , PALETTERGB (250,235,215)},
532 {"AntiqueWhite" , PALETTERGB (250,235,215)},
533 {"papaya whip" , PALETTERGB (255,239,213)},
534 {"PapayaWhip" , PALETTERGB (255,239,213)},
535 {"blanched almond" , PALETTERGB (255,235,205)},
536 {"BlanchedAlmond" , PALETTERGB (255,235,205)},
537 {"bisque" , PALETTERGB (255,228,196)},
538 {"peach puff" , PALETTERGB (255,218,185)},
539 {"PeachPuff" , PALETTERGB (255,218,185)},
540 {"navajo white" , PALETTERGB (255,222,173)},
541 {"NavajoWhite" , PALETTERGB (255,222,173)},
542 {"moccasin" , PALETTERGB (255,228,181)},
543 {"cornsilk" , PALETTERGB (255,248,220)},
544 {"ivory" , PALETTERGB (255,255,240)},
545 {"lemon chiffon" , PALETTERGB (255,250,205)},
546 {"LemonChiffon" , PALETTERGB (255,250,205)},
547 {"seashell" , PALETTERGB (255,245,238)},
548 {"honeydew" , PALETTERGB (240,255,240)},
549 {"mint cream" , PALETTERGB (245,255,250)},
550 {"MintCream" , PALETTERGB (245,255,250)},
551 {"azure" , PALETTERGB (240,255,255)},
552 {"alice blue" , PALETTERGB (240,248,255)},
553 {"AliceBlue" , PALETTERGB (240,248,255)},
554 {"lavender" , PALETTERGB (230,230,250)},
555 {"lavender blush" , PALETTERGB (255,240,245)},
556 {"LavenderBlush" , PALETTERGB (255,240,245)},
557 {"misty rose" , PALETTERGB (255,228,225)},
558 {"MistyRose" , PALETTERGB (255,228,225)},
559 {"white" , PALETTERGB (255,255,255)},
560 {"black" , PALETTERGB ( 0, 0, 0)},
561 {"dark slate gray" , PALETTERGB ( 47, 79, 79)},
562 {"DarkSlateGray" , PALETTERGB ( 47, 79, 79)},
563 {"dark slate grey" , PALETTERGB ( 47, 79, 79)},
564 {"DarkSlateGrey" , PALETTERGB ( 47, 79, 79)},
565 {"dim gray" , PALETTERGB (105,105,105)},
566 {"DimGray" , PALETTERGB (105,105,105)},
567 {"dim grey" , PALETTERGB (105,105,105)},
568 {"DimGrey" , PALETTERGB (105,105,105)},
569 {"slate gray" , PALETTERGB (112,128,144)},
570 {"SlateGray" , PALETTERGB (112,128,144)},
571 {"slate grey" , PALETTERGB (112,128,144)},
572 {"SlateGrey" , PALETTERGB (112,128,144)},
573 {"light slate gray" , PALETTERGB (119,136,153)},
574 {"LightSlateGray" , PALETTERGB (119,136,153)},
575 {"light slate grey" , PALETTERGB (119,136,153)},
576 {"LightSlateGrey" , PALETTERGB (119,136,153)},
577 {"gray" , PALETTERGB (190,190,190)},
578 {"grey" , PALETTERGB (190,190,190)},
579 {"light grey" , PALETTERGB (211,211,211)},
580 {"LightGrey" , PALETTERGB (211,211,211)},
581 {"light gray" , PALETTERGB (211,211,211)},
582 {"LightGray" , PALETTERGB (211,211,211)},
583 {"midnight blue" , PALETTERGB ( 25, 25,112)},
584 {"MidnightBlue" , PALETTERGB ( 25, 25,112)},
585 {"navy" , PALETTERGB ( 0, 0,128)},
586 {"navy blue" , PALETTERGB ( 0, 0,128)},
587 {"NavyBlue" , PALETTERGB ( 0, 0,128)},
588 {"cornflower blue" , PALETTERGB (100,149,237)},
589 {"CornflowerBlue" , PALETTERGB (100,149,237)},
590 {"dark slate blue" , PALETTERGB ( 72, 61,139)},
591 {"DarkSlateBlue" , PALETTERGB ( 72, 61,139)},
592 {"slate blue" , PALETTERGB (106, 90,205)},
593 {"SlateBlue" , PALETTERGB (106, 90,205)},
594 {"medium slate blue" , PALETTERGB (123,104,238)},
595 {"MediumSlateBlue" , PALETTERGB (123,104,238)},
596 {"light slate blue" , PALETTERGB (132,112,255)},
597 {"LightSlateBlue" , PALETTERGB (132,112,255)},
598 {"medium blue" , PALETTERGB ( 0, 0,205)},
599 {"MediumBlue" , PALETTERGB ( 0, 0,205)},
600 {"royal blue" , PALETTERGB ( 65,105,225)},
601 {"RoyalBlue" , PALETTERGB ( 65,105,225)},
602 {"blue" , PALETTERGB ( 0, 0,255)},
603 {"dodger blue" , PALETTERGB ( 30,144,255)},
604 {"DodgerBlue" , PALETTERGB ( 30,144,255)},
605 {"deep sky blue" , PALETTERGB ( 0,191,255)},
606 {"DeepSkyBlue" , PALETTERGB ( 0,191,255)},
607 {"sky blue" , PALETTERGB (135,206,235)},
608 {"SkyBlue" , PALETTERGB (135,206,235)},
609 {"light sky blue" , PALETTERGB (135,206,250)},
610 {"LightSkyBlue" , PALETTERGB (135,206,250)},
611 {"steel blue" , PALETTERGB ( 70,130,180)},
612 {"SteelBlue" , PALETTERGB ( 70,130,180)},
613 {"light steel blue" , PALETTERGB (176,196,222)},
614 {"LightSteelBlue" , PALETTERGB (176,196,222)},
615 {"light blue" , PALETTERGB (173,216,230)},
616 {"LightBlue" , PALETTERGB (173,216,230)},
617 {"powder blue" , PALETTERGB (176,224,230)},
618 {"PowderBlue" , PALETTERGB (176,224,230)},
619 {"pale turquoise" , PALETTERGB (175,238,238)},
620 {"PaleTurquoise" , PALETTERGB (175,238,238)},
621 {"dark turquoise" , PALETTERGB ( 0,206,209)},
622 {"DarkTurquoise" , PALETTERGB ( 0,206,209)},
623 {"medium turquoise" , PALETTERGB ( 72,209,204)},
624 {"MediumTurquoise" , PALETTERGB ( 72,209,204)},
625 {"turquoise" , PALETTERGB ( 64,224,208)},
626 {"cyan" , PALETTERGB ( 0,255,255)},
627 {"light cyan" , PALETTERGB (224,255,255)},
628 {"LightCyan" , PALETTERGB (224,255,255)},
629 {"cadet blue" , PALETTERGB ( 95,158,160)},
630 {"CadetBlue" , PALETTERGB ( 95,158,160)},
631 {"medium aquamarine" , PALETTERGB (102,205,170)},
632 {"MediumAquamarine" , PALETTERGB (102,205,170)},
633 {"aquamarine" , PALETTERGB (127,255,212)},
634 {"dark green" , PALETTERGB ( 0,100, 0)},
635 {"DarkGreen" , PALETTERGB ( 0,100, 0)},
636 {"dark olive green" , PALETTERGB ( 85,107, 47)},
637 {"DarkOliveGreen" , PALETTERGB ( 85,107, 47)},
638 {"dark sea green" , PALETTERGB (143,188,143)},
639 {"DarkSeaGreen" , PALETTERGB (143,188,143)},
640 {"sea green" , PALETTERGB ( 46,139, 87)},
641 {"SeaGreen" , PALETTERGB ( 46,139, 87)},
642 {"medium sea green" , PALETTERGB ( 60,179,113)},
643 {"MediumSeaGreen" , PALETTERGB ( 60,179,113)},
644 {"light sea green" , PALETTERGB ( 32,178,170)},
645 {"LightSeaGreen" , PALETTERGB ( 32,178,170)},
646 {"pale green" , PALETTERGB (152,251,152)},
647 {"PaleGreen" , PALETTERGB (152,251,152)},
648 {"spring green" , PALETTERGB ( 0,255,127)},
649 {"SpringGreen" , PALETTERGB ( 0,255,127)},
650 {"lawn green" , PALETTERGB (124,252, 0)},
651 {"LawnGreen" , PALETTERGB (124,252, 0)},
652 {"green" , PALETTERGB ( 0,255, 0)},
653 {"chartreuse" , PALETTERGB (127,255, 0)},
654 {"medium spring green" , PALETTERGB ( 0,250,154)},
655 {"MediumSpringGreen" , PALETTERGB ( 0,250,154)},
656 {"green yellow" , PALETTERGB (173,255, 47)},
657 {"GreenYellow" , PALETTERGB (173,255, 47)},
658 {"lime green" , PALETTERGB ( 50,205, 50)},
659 {"LimeGreen" , PALETTERGB ( 50,205, 50)},
660 {"yellow green" , PALETTERGB (154,205, 50)},
661 {"YellowGreen" , PALETTERGB (154,205, 50)},
662 {"forest green" , PALETTERGB ( 34,139, 34)},
663 {"ForestGreen" , PALETTERGB ( 34,139, 34)},
664 {"olive drab" , PALETTERGB (107,142, 35)},
665 {"OliveDrab" , PALETTERGB (107,142, 35)},
666 {"dark khaki" , PALETTERGB (189,183,107)},
667 {"DarkKhaki" , PALETTERGB (189,183,107)},
668 {"khaki" , PALETTERGB (240,230,140)},
669 {"pale goldenrod" , PALETTERGB (238,232,170)},
670 {"PaleGoldenrod" , PALETTERGB (238,232,170)},
671 {"light goldenrod yellow" , PALETTERGB (250,250,210)},
672 {"LightGoldenrodYellow" , PALETTERGB (250,250,210)},
673 {"light yellow" , PALETTERGB (255,255,224)},
674 {"LightYellow" , PALETTERGB (255,255,224)},
675 {"yellow" , PALETTERGB (255,255, 0)},
676 {"gold" , PALETTERGB (255,215, 0)},
677 {"light goldenrod" , PALETTERGB (238,221,130)},
678 {"LightGoldenrod" , PALETTERGB (238,221,130)},
679 {"goldenrod" , PALETTERGB (218,165, 32)},
680 {"dark goldenrod" , PALETTERGB (184,134, 11)},
681 {"DarkGoldenrod" , PALETTERGB (184,134, 11)},
682 {"rosy brown" , PALETTERGB (188,143,143)},
683 {"RosyBrown" , PALETTERGB (188,143,143)},
684 {"indian red" , PALETTERGB (205, 92, 92)},
685 {"IndianRed" , PALETTERGB (205, 92, 92)},
686 {"saddle brown" , PALETTERGB (139, 69, 19)},
687 {"SaddleBrown" , PALETTERGB (139, 69, 19)},
688 {"sienna" , PALETTERGB (160, 82, 45)},
689 {"peru" , PALETTERGB (205,133, 63)},
690 {"burlywood" , PALETTERGB (222,184,135)},
691 {"beige" , PALETTERGB (245,245,220)},
692 {"wheat" , PALETTERGB (245,222,179)},
693 {"sandy brown" , PALETTERGB (244,164, 96)},
694 {"SandyBrown" , PALETTERGB (244,164, 96)},
695 {"tan" , PALETTERGB (210,180,140)},
696 {"chocolate" , PALETTERGB (210,105, 30)},
697 {"firebrick" , PALETTERGB (178,34, 34)},
698 {"brown" , PALETTERGB (165,42, 42)},
699 {"dark salmon" , PALETTERGB (233,150,122)},
700 {"DarkSalmon" , PALETTERGB (233,150,122)},
701 {"salmon" , PALETTERGB (250,128,114)},
702 {"light salmon" , PALETTERGB (255,160,122)},
703 {"LightSalmon" , PALETTERGB (255,160,122)},
704 {"orange" , PALETTERGB (255,165, 0)},
705 {"dark orange" , PALETTERGB (255,140, 0)},
706 {"DarkOrange" , PALETTERGB (255,140, 0)},
707 {"coral" , PALETTERGB (255,127, 80)},
708 {"light coral" , PALETTERGB (240,128,128)},
709 {"LightCoral" , PALETTERGB (240,128,128)},
710 {"tomato" , PALETTERGB (255, 99, 71)},
711 {"orange red" , PALETTERGB (255, 69, 0)},
712 {"OrangeRed" , PALETTERGB (255, 69, 0)},
713 {"red" , PALETTERGB (255, 0, 0)},
714 {"hot pink" , PALETTERGB (255,105,180)},
715 {"HotPink" , PALETTERGB (255,105,180)},
716 {"deep pink" , PALETTERGB (255, 20,147)},
717 {"DeepPink" , PALETTERGB (255, 20,147)},
718 {"pink" , PALETTERGB (255,192,203)},
719 {"light pink" , PALETTERGB (255,182,193)},
720 {"LightPink" , PALETTERGB (255,182,193)},
721 {"pale violet red" , PALETTERGB (219,112,147)},
722 {"PaleVioletRed" , PALETTERGB (219,112,147)},
723 {"maroon" , PALETTERGB (176, 48, 96)},
724 {"medium violet red" , PALETTERGB (199, 21,133)},
725 {"MediumVioletRed" , PALETTERGB (199, 21,133)},
726 {"violet red" , PALETTERGB (208, 32,144)},
727 {"VioletRed" , PALETTERGB (208, 32,144)},
728 {"magenta" , PALETTERGB (255, 0,255)},
729 {"violet" , PALETTERGB (238,130,238)},
730 {"plum" , PALETTERGB (221,160,221)},
731 {"orchid" , PALETTERGB (218,112,214)},
732 {"medium orchid" , PALETTERGB (186, 85,211)},
733 {"MediumOrchid" , PALETTERGB (186, 85,211)},
734 {"dark orchid" , PALETTERGB (153, 50,204)},
735 {"DarkOrchid" , PALETTERGB (153, 50,204)},
736 {"dark violet" , PALETTERGB (148, 0,211)},
737 {"DarkViolet" , PALETTERGB (148, 0,211)},
738 {"blue violet" , PALETTERGB (138, 43,226)},
739 {"BlueViolet" , PALETTERGB (138, 43,226)},
740 {"purple" , PALETTERGB (160, 32,240)},
741 {"medium purple" , PALETTERGB (147,112,219)},
742 {"MediumPurple" , PALETTERGB (147,112,219)},
743 {"thistle" , PALETTERGB (216,191,216)},
744 {"gray0" , PALETTERGB ( 0, 0, 0)},
745 {"grey0" , PALETTERGB ( 0, 0, 0)},
746 {"dark grey" , PALETTERGB (169,169,169)},
747 {"DarkGrey" , PALETTERGB (169,169,169)},
748 {"dark gray" , PALETTERGB (169,169,169)},
749 {"DarkGray" , PALETTERGB (169,169,169)},
750 {"dark blue" , PALETTERGB ( 0, 0,139)},
751 {"DarkBlue" , PALETTERGB ( 0, 0,139)},
752 {"dark cyan" , PALETTERGB ( 0,139,139)},
753 {"DarkCyan" , PALETTERGB ( 0,139,139)},
754 {"dark magenta" , PALETTERGB (139, 0,139)},
755 {"DarkMagenta" , PALETTERGB (139, 0,139)},
756 {"dark red" , PALETTERGB (139, 0, 0)},
757 {"DarkRed" , PALETTERGB (139, 0, 0)},
758 {"light green" , PALETTERGB (144,238,144)},
759 {"LightGreen" , PALETTERGB (144,238,144)},
760 };
761
762 DEFUN ("w32-default-color-map", Fw32_default_color_map, Sw32_default_color_map,
763 0, 0, 0, doc: /* Return the default color map. */)
764 (void)
765 {
766 int i;
767 colormap_t *pc = w32_color_map;
768 Lisp_Object cmap;
769
770 BLOCK_INPUT;
771
772 cmap = Qnil;
773
774 for (i = 0; i < sizeof (w32_color_map) / sizeof (w32_color_map[0]);
775 pc++, i++)
776 cmap = Fcons (Fcons (build_string (pc->name),
777 make_number (pc->colorref)),
778 cmap);
779
780 UNBLOCK_INPUT;
781
782 return (cmap);
783 }
784
785 static Lisp_Object
786 w32_to_x_color (Lisp_Object rgb)
787 {
788 Lisp_Object color;
789
790 CHECK_NUMBER (rgb);
791
792 BLOCK_INPUT;
793
794 color = Frassq (rgb, Vw32_color_map);
795
796 UNBLOCK_INPUT;
797
798 if (!NILP (color))
799 return (Fcar (color));
800 else
801 return Qnil;
802 }
803
804 static Lisp_Object
805 w32_color_map_lookup (char *colorname)
806 {
807 Lisp_Object tail, ret = Qnil;
808
809 BLOCK_INPUT;
810
811 for (tail = Vw32_color_map; CONSP (tail); tail = XCDR (tail))
812 {
813 register Lisp_Object elt, tem;
814
815 elt = XCAR (tail);
816 if (!CONSP (elt)) continue;
817
818 tem = Fcar (elt);
819
820 if (lstrcmpi (SDATA (tem), colorname) == 0)
821 {
822 ret = Fcdr (elt);
823 break;
824 }
825
826 QUIT;
827 }
828
829
830 UNBLOCK_INPUT;
831
832 return ret;
833 }
834
835
836 static void
837 add_system_logical_colors_to_map (Lisp_Object *system_colors)
838 {
839 HKEY colors_key;
840
841 /* Other registry operations are done with input blocked. */
842 BLOCK_INPUT;
843
844 /* Look for "Control Panel/Colors" under User and Machine registry
845 settings. */
846 if (RegOpenKeyEx (HKEY_CURRENT_USER, "Control Panel\\Colors", 0,
847 KEY_READ, &colors_key) == ERROR_SUCCESS
848 || RegOpenKeyEx (HKEY_LOCAL_MACHINE, "Control Panel\\Colors", 0,
849 KEY_READ, &colors_key) == ERROR_SUCCESS)
850 {
851 /* List all keys. */
852 char color_buffer[64];
853 char full_name_buffer[MAX_PATH + SYSTEM_COLOR_PREFIX_LEN];
854 int index = 0;
855 DWORD name_size, color_size;
856 char *name_buffer = full_name_buffer + SYSTEM_COLOR_PREFIX_LEN;
857
858 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
859 color_size = sizeof (color_buffer);
860
861 strcpy (full_name_buffer, SYSTEM_COLOR_PREFIX);
862
863 while (RegEnumValueA (colors_key, index, name_buffer, &name_size,
864 NULL, NULL, color_buffer, &color_size)
865 == ERROR_SUCCESS)
866 {
867 int r, g, b;
868 if (sscanf (color_buffer, " %u %u %u", &r, &g, &b) == 3)
869 *system_colors = Fcons (Fcons (build_string (full_name_buffer),
870 make_number (RGB (r, g, b))),
871 *system_colors);
872
873 name_size = sizeof (full_name_buffer) - SYSTEM_COLOR_PREFIX_LEN;
874 color_size = sizeof (color_buffer);
875 index++;
876 }
877 RegCloseKey (colors_key);
878 }
879
880 UNBLOCK_INPUT;
881 }
882
883
884 static Lisp_Object
885 x_to_w32_color (char * colorname)
886 {
887 register Lisp_Object ret = Qnil;
888
889 BLOCK_INPUT;
890
891 if (colorname[0] == '#')
892 {
893 /* Could be an old-style RGB Device specification. */
894 char *color;
895 int size;
896 color = colorname + 1;
897
898 size = strlen (color);
899 if (size == 3 || size == 6 || size == 9 || size == 12)
900 {
901 UINT colorval;
902 int i, pos;
903 pos = 0;
904 size /= 3;
905 colorval = 0;
906
907 for (i = 0; i < 3; i++)
908 {
909 char *end;
910 char t;
911 unsigned long value;
912
913 /* The check for 'x' in the following conditional takes into
914 account the fact that strtol allows a "0x" in front of
915 our numbers, and we don't. */
916 if (!isxdigit (color[0]) || color[1] == 'x')
917 break;
918 t = color[size];
919 color[size] = '\0';
920 value = strtoul (color, &end, 16);
921 color[size] = t;
922 if (errno == ERANGE || end - color != size)
923 break;
924 switch (size)
925 {
926 case 1:
927 value = value * 0x10;
928 break;
929 case 2:
930 break;
931 case 3:
932 value /= 0x10;
933 break;
934 case 4:
935 value /= 0x100;
936 break;
937 }
938 colorval |= (value << pos);
939 pos += 0x8;
940 if (i == 2)
941 {
942 UNBLOCK_INPUT;
943 XSETINT (ret, colorval);
944 return ret;
945 }
946 color = end;
947 }
948 }
949 }
950 else if (strnicmp (colorname, "rgb:", 4) == 0)
951 {
952 char *color;
953 UINT colorval;
954 int i, pos;
955 pos = 0;
956
957 colorval = 0;
958 color = colorname + 4;
959 for (i = 0; i < 3; i++)
960 {
961 char *end;
962 unsigned long value;
963
964 /* The check for 'x' in the following conditional takes into
965 account the fact that strtol allows a "0x" in front of
966 our numbers, and we don't. */
967 if (!isxdigit (color[0]) || color[1] == 'x')
968 break;
969 value = strtoul (color, &end, 16);
970 if (errno == ERANGE)
971 break;
972 switch (end - color)
973 {
974 case 1:
975 value = value * 0x10 + value;
976 break;
977 case 2:
978 break;
979 case 3:
980 value /= 0x10;
981 break;
982 case 4:
983 value /= 0x100;
984 break;
985 default:
986 value = ULONG_MAX;
987 }
988 if (value == ULONG_MAX)
989 break;
990 colorval |= (value << pos);
991 pos += 0x8;
992 if (i == 2)
993 {
994 if (*end != '\0')
995 break;
996 UNBLOCK_INPUT;
997 XSETINT (ret, colorval);
998 return ret;
999 }
1000 if (*end != '/')
1001 break;
1002 color = end + 1;
1003 }
1004 }
1005 else if (strnicmp (colorname, "rgbi:", 5) == 0)
1006 {
1007 /* This is an RGB Intensity specification. */
1008 char *color;
1009 UINT colorval;
1010 int i, pos;
1011 pos = 0;
1012
1013 colorval = 0;
1014 color = colorname + 5;
1015 for (i = 0; i < 3; i++)
1016 {
1017 char *end;
1018 double value;
1019 UINT val;
1020
1021 value = strtod (color, &end);
1022 if (errno == ERANGE)
1023 break;
1024 if (value < 0.0 || value > 1.0)
1025 break;
1026 val = (UINT)(0x100 * value);
1027 /* We used 0x100 instead of 0xFF to give a continuous
1028 range between 0.0 and 1.0 inclusive. The next statement
1029 fixes the 1.0 case. */
1030 if (val == 0x100)
1031 val = 0xFF;
1032 colorval |= (val << pos);
1033 pos += 0x8;
1034 if (i == 2)
1035 {
1036 if (*end != '\0')
1037 break;
1038 UNBLOCK_INPUT;
1039 XSETINT (ret, colorval);
1040 return ret;
1041 }
1042 if (*end != '/')
1043 break;
1044 color = end + 1;
1045 }
1046 }
1047 /* I am not going to attempt to handle any of the CIE color schemes
1048 or TekHVC, since I don't know the algorithms for conversion to
1049 RGB. */
1050
1051 /* If we fail to lookup the color name in w32_color_map, then check the
1052 colorname to see if it can be crudely approximated: If the X color
1053 ends in a number (e.g., "darkseagreen2"), strip the number and
1054 return the result of looking up the base color name. */
1055 ret = w32_color_map_lookup (colorname);
1056 if (NILP (ret))
1057 {
1058 int len = strlen (colorname);
1059
1060 if (isdigit (colorname[len - 1]))
1061 {
1062 char *ptr, *approx = alloca (len + 1);
1063
1064 strcpy (approx, colorname);
1065 ptr = &approx[len - 1];
1066 while (ptr > approx && isdigit (*ptr))
1067 *ptr-- = '\0';
1068
1069 ret = w32_color_map_lookup (approx);
1070 }
1071 }
1072
1073 UNBLOCK_INPUT;
1074 return ret;
1075 }
1076
1077 void
1078 w32_regenerate_palette (FRAME_PTR f)
1079 {
1080 struct w32_palette_entry * list;
1081 LOGPALETTE * log_palette;
1082 HPALETTE new_palette;
1083 int i;
1084
1085 /* don't bother trying to create palette if not supported */
1086 if (! FRAME_W32_DISPLAY_INFO (f)->has_palette)
1087 return;
1088
1089 log_palette = (LOGPALETTE *)
1090 alloca (sizeof (LOGPALETTE) +
1091 FRAME_W32_DISPLAY_INFO (f)->num_colors * sizeof (PALETTEENTRY));
1092 log_palette->palVersion = 0x300;
1093 log_palette->palNumEntries = FRAME_W32_DISPLAY_INFO (f)->num_colors;
1094
1095 list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1096 for (i = 0;
1097 i < FRAME_W32_DISPLAY_INFO (f)->num_colors;
1098 i++, list = list->next)
1099 log_palette->palPalEntry[i] = list->entry;
1100
1101 new_palette = CreatePalette (log_palette);
1102
1103 enter_crit ();
1104
1105 if (FRAME_W32_DISPLAY_INFO (f)->palette)
1106 DeleteObject (FRAME_W32_DISPLAY_INFO (f)->palette);
1107 FRAME_W32_DISPLAY_INFO (f)->palette = new_palette;
1108
1109 /* Realize display palette and garbage all frames. */
1110 release_frame_dc (f, get_frame_dc (f));
1111
1112 leave_crit ();
1113 }
1114
1115 #define W32_COLOR(pe) RGB (pe.peRed, pe.peGreen, pe.peBlue)
1116 #define SET_W32_COLOR(pe, color) \
1117 do \
1118 { \
1119 pe.peRed = GetRValue (color); \
1120 pe.peGreen = GetGValue (color); \
1121 pe.peBlue = GetBValue (color); \
1122 pe.peFlags = 0; \
1123 } while (0)
1124
1125 #if 0
1126 /* Keep these around in case we ever want to track color usage. */
1127 void
1128 w32_map_color (FRAME_PTR f, COLORREF color)
1129 {
1130 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1131
1132 if (NILP (Vw32_enable_palette))
1133 return;
1134
1135 /* check if color is already mapped */
1136 while (list)
1137 {
1138 if (W32_COLOR (list->entry) == color)
1139 {
1140 ++list->refcount;
1141 return;
1142 }
1143 list = list->next;
1144 }
1145
1146 /* not already mapped, so add to list and recreate Windows palette */
1147 list = (struct w32_palette_entry *)
1148 xmalloc (sizeof (struct w32_palette_entry));
1149 SET_W32_COLOR (list->entry, color);
1150 list->refcount = 1;
1151 list->next = FRAME_W32_DISPLAY_INFO (f)->color_list;
1152 FRAME_W32_DISPLAY_INFO (f)->color_list = list;
1153 FRAME_W32_DISPLAY_INFO (f)->num_colors++;
1154
1155 /* set flag that palette must be regenerated */
1156 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1157 }
1158
1159 void
1160 w32_unmap_color (FRAME_PTR f, COLORREF color)
1161 {
1162 struct w32_palette_entry * list = FRAME_W32_DISPLAY_INFO (f)->color_list;
1163 struct w32_palette_entry **prev = &FRAME_W32_DISPLAY_INFO (f)->color_list;
1164
1165 if (NILP (Vw32_enable_palette))
1166 return;
1167
1168 /* check if color is already mapped */
1169 while (list)
1170 {
1171 if (W32_COLOR (list->entry) == color)
1172 {
1173 if (--list->refcount == 0)
1174 {
1175 *prev = list->next;
1176 xfree (list);
1177 FRAME_W32_DISPLAY_INFO (f)->num_colors--;
1178 break;
1179 }
1180 else
1181 return;
1182 }
1183 prev = &list->next;
1184 list = list->next;
1185 }
1186
1187 /* set flag that palette must be regenerated */
1188 FRAME_W32_DISPLAY_INFO (f)->regen_palette = TRUE;
1189 }
1190 #endif
1191
1192
1193 /* Gamma-correct COLOR on frame F. */
1194
1195 void
1196 gamma_correct (struct frame *f, COLORREF *color)
1197 {
1198 if (f->gamma)
1199 {
1200 *color = PALETTERGB (
1201 pow (GetRValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1202 pow (GetGValue (*color) / 255.0, f->gamma) * 255.0 + 0.5,
1203 pow (GetBValue (*color) / 255.0, f->gamma) * 255.0 + 0.5);
1204 }
1205 }
1206
1207
1208 /* Decide if color named COLOR is valid for the display associated with
1209 the selected frame; if so, return the rgb values in COLOR_DEF.
1210 If ALLOC is nonzero, allocate a new colormap cell. */
1211
1212 int
1213 w32_defined_color (FRAME_PTR f, char *color, XColor *color_def, int alloc)
1214 {
1215 register Lisp_Object tem;
1216 COLORREF w32_color_ref;
1217
1218 tem = x_to_w32_color (color);
1219
1220 if (!NILP (tem))
1221 {
1222 if (f)
1223 {
1224 /* Apply gamma correction. */
1225 w32_color_ref = XUINT (tem);
1226 gamma_correct (f, &w32_color_ref);
1227 XSETINT (tem, w32_color_ref);
1228 }
1229
1230 /* Map this color to the palette if it is enabled. */
1231 if (!NILP (Vw32_enable_palette))
1232 {
1233 struct w32_palette_entry * entry =
1234 one_w32_display_info.color_list;
1235 struct w32_palette_entry ** prev =
1236 &one_w32_display_info.color_list;
1237
1238 /* check if color is already mapped */
1239 while (entry)
1240 {
1241 if (W32_COLOR (entry->entry) == XUINT (tem))
1242 break;
1243 prev = &entry->next;
1244 entry = entry->next;
1245 }
1246
1247 if (entry == NULL && alloc)
1248 {
1249 /* not already mapped, so add to list */
1250 entry = (struct w32_palette_entry *)
1251 xmalloc (sizeof (struct w32_palette_entry));
1252 SET_W32_COLOR (entry->entry, XUINT (tem));
1253 entry->next = NULL;
1254 *prev = entry;
1255 one_w32_display_info.num_colors++;
1256
1257 /* set flag that palette must be regenerated */
1258 one_w32_display_info.regen_palette = TRUE;
1259 }
1260 }
1261 /* Ensure COLORREF value is snapped to nearest color in (default)
1262 palette by simulating the PALETTERGB macro. This works whether
1263 or not the display device has a palette. */
1264 w32_color_ref = XUINT (tem) | 0x2000000;
1265
1266 color_def->pixel = w32_color_ref;
1267 color_def->red = GetRValue (w32_color_ref) * 256;
1268 color_def->green = GetGValue (w32_color_ref) * 256;
1269 color_def->blue = GetBValue (w32_color_ref) * 256;
1270
1271 return 1;
1272 }
1273 else
1274 {
1275 return 0;
1276 }
1277 }
1278
1279 /* Given a string ARG naming a color, compute a pixel value from it
1280 suitable for screen F.
1281 If F is not a color screen, return DEF (default) regardless of what
1282 ARG says. */
1283
1284 int
1285 x_decode_color (FRAME_PTR f, Lisp_Object arg, int def)
1286 {
1287 XColor cdef;
1288
1289 CHECK_STRING (arg);
1290
1291 if (strcmp (SDATA (arg), "black") == 0)
1292 return BLACK_PIX_DEFAULT (f);
1293 else if (strcmp (SDATA (arg), "white") == 0)
1294 return WHITE_PIX_DEFAULT (f);
1295
1296 if ((FRAME_W32_DISPLAY_INFO (f)->n_planes * FRAME_W32_DISPLAY_INFO (f)->n_cbits) == 1)
1297 return def;
1298
1299 /* w32_defined_color is responsible for coping with failures
1300 by looking for a near-miss. */
1301 if (w32_defined_color (f, SDATA (arg), &cdef, 1))
1302 return cdef.pixel;
1303
1304 /* defined_color failed; return an ultimate default. */
1305 return def;
1306 }
1307 \f
1308
1309
1310 /* Functions called only from `x_set_frame_param'
1311 to set individual parameters.
1312
1313 If FRAME_W32_WINDOW (f) is 0,
1314 the frame is being created and its window does not exist yet.
1315 In that case, just record the parameter's new value
1316 in the standard place; do not attempt to change the window. */
1317
1318 void
1319 x_set_foreground_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1320 {
1321 struct w32_output *x = f->output_data.w32;
1322 PIX_TYPE fg, old_fg;
1323
1324 fg = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1325 old_fg = FRAME_FOREGROUND_PIXEL (f);
1326 FRAME_FOREGROUND_PIXEL (f) = fg;
1327
1328 if (FRAME_W32_WINDOW (f) != 0)
1329 {
1330 if (x->cursor_pixel == old_fg)
1331 x->cursor_pixel = fg;
1332
1333 update_face_from_frame_parameter (f, Qforeground_color, arg);
1334 if (FRAME_VISIBLE_P (f))
1335 redraw_frame (f);
1336 }
1337 }
1338
1339 void
1340 x_set_background_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1341 {
1342 FRAME_BACKGROUND_PIXEL (f)
1343 = x_decode_color (f, arg, WHITE_PIX_DEFAULT (f));
1344
1345 if (FRAME_W32_WINDOW (f) != 0)
1346 {
1347 SetWindowLong (FRAME_W32_WINDOW (f), WND_BACKGROUND_INDEX,
1348 FRAME_BACKGROUND_PIXEL (f));
1349
1350 update_face_from_frame_parameter (f, Qbackground_color, arg);
1351
1352 if (FRAME_VISIBLE_P (f))
1353 redraw_frame (f);
1354 }
1355 }
1356
1357 void
1358 x_set_mouse_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1359 {
1360 Cursor cursor, nontext_cursor, mode_cursor, hand_cursor;
1361 int count;
1362 int mask_color;
1363
1364 if (!EQ (Qnil, arg))
1365 f->output_data.w32->mouse_pixel
1366 = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1367 mask_color = FRAME_BACKGROUND_PIXEL (f);
1368
1369 /* Don't let pointers be invisible. */
1370 if (mask_color == f->output_data.w32->mouse_pixel
1371 && mask_color == FRAME_BACKGROUND_PIXEL (f))
1372 f->output_data.w32->mouse_pixel = FRAME_FOREGROUND_PIXEL (f);
1373
1374 #if 0 /* TODO : Mouse cursor customization. */
1375 BLOCK_INPUT;
1376
1377 /* It's not okay to crash if the user selects a screwy cursor. */
1378 count = x_catch_errors (FRAME_W32_DISPLAY (f));
1379
1380 if (!EQ (Qnil, Vx_pointer_shape))
1381 {
1382 CHECK_NUMBER (Vx_pointer_shape);
1383 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XINT (Vx_pointer_shape));
1384 }
1385 else
1386 cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1387 x_check_errors (FRAME_W32_DISPLAY (f), "bad text pointer cursor: %s");
1388
1389 if (!EQ (Qnil, Vx_nontext_pointer_shape))
1390 {
1391 CHECK_NUMBER (Vx_nontext_pointer_shape);
1392 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1393 XINT (Vx_nontext_pointer_shape));
1394 }
1395 else
1396 nontext_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_left_ptr);
1397 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1398
1399 if (!EQ (Qnil, Vx_hourglass_pointer_shape))
1400 {
1401 CHECK_NUMBER (Vx_hourglass_pointer_shape);
1402 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1403 XINT (Vx_hourglass_pointer_shape));
1404 }
1405 else
1406 hourglass_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_watch);
1407 x_check_errors (FRAME_W32_DISPLAY (f), "bad busy pointer cursor: %s");
1408
1409 x_check_errors (FRAME_W32_DISPLAY (f), "bad nontext pointer cursor: %s");
1410 if (!EQ (Qnil, Vx_mode_pointer_shape))
1411 {
1412 CHECK_NUMBER (Vx_mode_pointer_shape);
1413 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1414 XINT (Vx_mode_pointer_shape));
1415 }
1416 else
1417 mode_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_xterm);
1418 x_check_errors (FRAME_W32_DISPLAY (f), "bad modeline pointer cursor: %s");
1419
1420 if (!EQ (Qnil, Vx_sensitive_text_pointer_shape))
1421 {
1422 CHECK_NUMBER (Vx_sensitive_text_pointer_shape);
1423 hand_cursor
1424 = XCreateFontCursor (FRAME_W32_DISPLAY (f),
1425 XINT (Vx_sensitive_text_pointer_shape));
1426 }
1427 else
1428 hand_cursor = XCreateFontCursor (FRAME_W32_DISPLAY (f), XC_crosshair);
1429
1430 if (!NILP (Vx_window_horizontal_drag_shape))
1431 {
1432 CHECK_NUMBER (Vx_window_horizontal_drag_shape);
1433 horizontal_drag_cursor
1434 = XCreateFontCursor (FRAME_X_DISPLAY (f),
1435 XINT (Vx_window_horizontal_drag_shape));
1436 }
1437 else
1438 horizontal_drag_cursor
1439 = XCreateFontCursor (FRAME_X_DISPLAY (f), XC_sb_h_double_arrow);
1440
1441 /* Check and report errors with the above calls. */
1442 x_check_errors (FRAME_W32_DISPLAY (f), "can't set cursor shape: %s");
1443 x_uncatch_errors (FRAME_W32_DISPLAY (f), count);
1444
1445 {
1446 XColor fore_color, back_color;
1447
1448 fore_color.pixel = f->output_data.w32->mouse_pixel;
1449 back_color.pixel = mask_color;
1450 XQueryColor (FRAME_W32_DISPLAY (f),
1451 DefaultColormap (FRAME_W32_DISPLAY (f),
1452 DefaultScreen (FRAME_W32_DISPLAY (f))),
1453 &fore_color);
1454 XQueryColor (FRAME_W32_DISPLAY (f),
1455 DefaultColormap (FRAME_W32_DISPLAY (f),
1456 DefaultScreen (FRAME_W32_DISPLAY (f))),
1457 &back_color);
1458 XRecolorCursor (FRAME_W32_DISPLAY (f), cursor,
1459 &fore_color, &back_color);
1460 XRecolorCursor (FRAME_W32_DISPLAY (f), nontext_cursor,
1461 &fore_color, &back_color);
1462 XRecolorCursor (FRAME_W32_DISPLAY (f), mode_cursor,
1463 &fore_color, &back_color);
1464 XRecolorCursor (FRAME_W32_DISPLAY (f), hand_cursor,
1465 &fore_color, &back_color);
1466 XRecolorCursor (FRAME_W32_DISPLAY (f), hourglass_cursor,
1467 &fore_color, &back_color);
1468 }
1469
1470 if (FRAME_W32_WINDOW (f) != 0)
1471 XDefineCursor (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), cursor);
1472
1473 if (cursor != f->output_data.w32->text_cursor && f->output_data.w32->text_cursor != 0)
1474 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->text_cursor);
1475 f->output_data.w32->text_cursor = cursor;
1476
1477 if (nontext_cursor != f->output_data.w32->nontext_cursor
1478 && f->output_data.w32->nontext_cursor != 0)
1479 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->nontext_cursor);
1480 f->output_data.w32->nontext_cursor = nontext_cursor;
1481
1482 if (hourglass_cursor != f->output_data.w32->hourglass_cursor
1483 && f->output_data.w32->hourglass_cursor != 0)
1484 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hourglass_cursor);
1485 f->output_data.w32->hourglass_cursor = hourglass_cursor;
1486
1487 if (mode_cursor != f->output_data.w32->modeline_cursor
1488 && f->output_data.w32->modeline_cursor != 0)
1489 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->modeline_cursor);
1490 f->output_data.w32->modeline_cursor = mode_cursor;
1491
1492 if (hand_cursor != f->output_data.w32->hand_cursor
1493 && f->output_data.w32->hand_cursor != 0)
1494 XFreeCursor (FRAME_W32_DISPLAY (f), f->output_data.w32->hand_cursor);
1495 f->output_data.w32->hand_cursor = hand_cursor;
1496
1497 XFlush (FRAME_W32_DISPLAY (f));
1498 UNBLOCK_INPUT;
1499
1500 update_face_from_frame_parameter (f, Qmouse_color, arg);
1501 #endif /* TODO */
1502 }
1503
1504 void
1505 x_set_cursor_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1506 {
1507 unsigned long fore_pixel, pixel;
1508
1509 if (!NILP (Vx_cursor_fore_pixel))
1510 fore_pixel = x_decode_color (f, Vx_cursor_fore_pixel,
1511 WHITE_PIX_DEFAULT (f));
1512 else
1513 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
1514
1515 pixel = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1516
1517 /* Make sure that the cursor color differs from the background color. */
1518 if (pixel == FRAME_BACKGROUND_PIXEL (f))
1519 {
1520 pixel = f->output_data.w32->mouse_pixel;
1521 if (pixel == fore_pixel)
1522 fore_pixel = FRAME_BACKGROUND_PIXEL (f);
1523 }
1524
1525 f->output_data.w32->cursor_foreground_pixel = fore_pixel;
1526 f->output_data.w32->cursor_pixel = pixel;
1527
1528 if (FRAME_W32_WINDOW (f) != 0)
1529 {
1530 BLOCK_INPUT;
1531 /* Update frame's cursor_gc. */
1532 f->output_data.w32->cursor_gc->foreground = fore_pixel;
1533 f->output_data.w32->cursor_gc->background = pixel;
1534
1535 UNBLOCK_INPUT;
1536
1537 if (FRAME_VISIBLE_P (f))
1538 {
1539 x_update_cursor (f, 0);
1540 x_update_cursor (f, 1);
1541 }
1542 }
1543
1544 update_face_from_frame_parameter (f, Qcursor_color, arg);
1545 }
1546
1547 /* Set the border-color of frame F to pixel value PIX.
1548 Note that this does not fully take effect if done before
1549 F has a window. */
1550
1551 void
1552 x_set_border_pixel (struct frame *f, int pix)
1553 {
1554
1555 f->output_data.w32->border_pixel = pix;
1556
1557 if (FRAME_W32_WINDOW (f) != 0 && f->border_width > 0)
1558 {
1559 if (FRAME_VISIBLE_P (f))
1560 redraw_frame (f);
1561 }
1562 }
1563
1564 /* Set the border-color of frame F to value described by ARG.
1565 ARG can be a string naming a color.
1566 The border-color is used for the border that is drawn by the server.
1567 Note that this does not fully take effect if done before
1568 F has a window; it must be redone when the window is created. */
1569
1570 void
1571 x_set_border_color (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1572 {
1573 int pix;
1574
1575 CHECK_STRING (arg);
1576 pix = x_decode_color (f, arg, BLACK_PIX_DEFAULT (f));
1577 x_set_border_pixel (f, pix);
1578 update_face_from_frame_parameter (f, Qborder_color, arg);
1579 }
1580
1581
1582 void
1583 x_set_cursor_type (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval)
1584 {
1585 set_frame_cursor_types (f, arg);
1586
1587 /* Make sure the cursor gets redrawn. */
1588 cursor_type_changed = 1;
1589 }
1590 \f
1591 void
1592 x_set_icon_type (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1593 {
1594 int result;
1595
1596 if (NILP (arg) && NILP (oldval))
1597 return;
1598
1599 if (STRINGP (arg) && STRINGP (oldval)
1600 && EQ (Fstring_equal (oldval, arg), Qt))
1601 return;
1602
1603 if (SYMBOLP (arg) && SYMBOLP (oldval) && EQ (arg, oldval))
1604 return;
1605
1606 BLOCK_INPUT;
1607
1608 result = x_bitmap_icon (f, arg);
1609 if (result)
1610 {
1611 UNBLOCK_INPUT;
1612 error ("No icon window available");
1613 }
1614
1615 UNBLOCK_INPUT;
1616 }
1617
1618 void
1619 x_set_icon_name (struct frame *f, Lisp_Object arg, Lisp_Object oldval)
1620 {
1621 if (STRINGP (arg))
1622 {
1623 if (STRINGP (oldval) && EQ (Fstring_equal (oldval, arg), Qt))
1624 return;
1625 }
1626 else if (!NILP (arg) || NILP (oldval))
1627 return;
1628
1629 f->icon_name = arg;
1630
1631 #if 0
1632 if (f->output_data.w32->icon_bitmap != 0)
1633 return;
1634
1635 BLOCK_INPUT;
1636
1637 result = x_text_icon (f,
1638 (char *) SDATA ((!NILP (f->icon_name)
1639 ? f->icon_name
1640 : !NILP (f->title)
1641 ? f->title
1642 : f->name)));
1643
1644 if (result)
1645 {
1646 UNBLOCK_INPUT;
1647 error ("No icon window available");
1648 }
1649
1650 /* If the window was unmapped (and its icon was mapped),
1651 the new icon is not mapped, so map the window in its stead. */
1652 if (FRAME_VISIBLE_P (f))
1653 {
1654 #ifdef USE_X_TOOLKIT
1655 XtPopup (f->output_data.w32->widget, XtGrabNone);
1656 #endif
1657 XMapWindow (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f));
1658 }
1659
1660 XFlush (FRAME_W32_DISPLAY (f));
1661 UNBLOCK_INPUT;
1662 #endif
1663 }
1664
1665 \f
1666 void
1667 x_set_menu_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1668 {
1669 int nlines;
1670 int olines = FRAME_MENU_BAR_LINES (f);
1671
1672 /* Right now, menu bars don't work properly in minibuf-only frames;
1673 most of the commands try to apply themselves to the minibuffer
1674 frame itself, and get an error because you can't switch buffers
1675 in or split the minibuffer window. */
1676 if (FRAME_MINIBUF_ONLY_P (f))
1677 return;
1678
1679 if (INTEGERP (value))
1680 nlines = XINT (value);
1681 else
1682 nlines = 0;
1683
1684 FRAME_MENU_BAR_LINES (f) = 0;
1685 if (nlines)
1686 FRAME_EXTERNAL_MENU_BAR (f) = 1;
1687 else
1688 {
1689 if (FRAME_EXTERNAL_MENU_BAR (f) == 1)
1690 free_frame_menubar (f);
1691 FRAME_EXTERNAL_MENU_BAR (f) = 0;
1692
1693 /* Adjust the frame size so that the client (text) dimensions
1694 remain the same. This depends on FRAME_EXTERNAL_MENU_BAR being
1695 set correctly. */
1696 x_set_window_size (f, 0, FRAME_COLS (f), FRAME_LINES (f));
1697 do_pending_window_change (0);
1698 }
1699 adjust_glyphs (f);
1700 }
1701
1702
1703 /* Set the number of lines used for the tool bar of frame F to VALUE.
1704 VALUE not an integer, or < 0 means set the lines to zero. OLDVAL
1705 is the old number of tool bar lines. This function changes the
1706 height of all windows on frame F to match the new tool bar height.
1707 The frame's height doesn't change. */
1708
1709 void
1710 x_set_tool_bar_lines (struct frame *f, Lisp_Object value, Lisp_Object oldval)
1711 {
1712 int delta, nlines, root_height;
1713 Lisp_Object root_window;
1714
1715 /* Treat tool bars like menu bars. */
1716 if (FRAME_MINIBUF_ONLY_P (f))
1717 return;
1718
1719 /* Use VALUE only if an integer >= 0. */
1720 if (INTEGERP (value) && XINT (value) >= 0)
1721 nlines = XFASTINT (value);
1722 else
1723 nlines = 0;
1724
1725 /* Make sure we redisplay all windows in this frame. */
1726 ++windows_or_buffers_changed;
1727
1728 delta = nlines - FRAME_TOOL_BAR_LINES (f);
1729
1730 /* Don't resize the tool-bar to more than we have room for. */
1731 root_window = FRAME_ROOT_WINDOW (f);
1732 root_height = WINDOW_TOTAL_LINES (XWINDOW (root_window));
1733 if (root_height - delta < 1)
1734 {
1735 delta = root_height - 1;
1736 nlines = FRAME_TOOL_BAR_LINES (f) + delta;
1737 }
1738
1739 FRAME_TOOL_BAR_LINES (f) = nlines;
1740 change_window_heights (root_window, delta);
1741 adjust_glyphs (f);
1742
1743 /* We also have to make sure that the internal border at the top of
1744 the frame, below the menu bar or tool bar, is redrawn when the
1745 tool bar disappears. This is so because the internal border is
1746 below the tool bar if one is displayed, but is below the menu bar
1747 if there isn't a tool bar. The tool bar draws into the area
1748 below the menu bar. */
1749 if (FRAME_W32_WINDOW (f) && FRAME_TOOL_BAR_LINES (f) == 0)
1750 {
1751 clear_frame (f);
1752 clear_current_matrices (f);
1753 }
1754
1755 /* If the tool bar gets smaller, the internal border below it
1756 has to be cleared. It was formerly part of the display
1757 of the larger tool bar, and updating windows won't clear it. */
1758 if (delta < 0)
1759 {
1760 int height = FRAME_INTERNAL_BORDER_WIDTH (f);
1761 int width = FRAME_PIXEL_WIDTH (f);
1762 int y = nlines * FRAME_LINE_HEIGHT (f);
1763
1764 BLOCK_INPUT;
1765 {
1766 HDC hdc = get_frame_dc (f);
1767 w32_clear_area (f, hdc, 0, y, width, height);
1768 release_frame_dc (f, hdc);
1769 }
1770 UNBLOCK_INPUT;
1771
1772 if (WINDOWP (f->tool_bar_window))
1773 clear_glyph_matrix (XWINDOW (f->tool_bar_window)->current_matrix);
1774 }
1775 }
1776
1777
1778 /* Change the name of frame F to NAME. If NAME is nil, set F's name to
1779 w32_id_name.
1780
1781 If EXPLICIT is non-zero, that indicates that lisp code is setting the
1782 name; if NAME is a string, set F's name to NAME and set
1783 F->explicit_name; if NAME is Qnil, then clear F->explicit_name.
1784
1785 If EXPLICIT is zero, that indicates that Emacs redisplay code is
1786 suggesting a new name, which lisp code should override; if
1787 F->explicit_name is set, ignore the new name; otherwise, set it. */
1788
1789 void
1790 x_set_name (struct frame *f, Lisp_Object name, int explicit)
1791 {
1792 /* Make sure that requests from lisp code override requests from
1793 Emacs redisplay code. */
1794 if (explicit)
1795 {
1796 /* If we're switching from explicit to implicit, we had better
1797 update the mode lines and thereby update the title. */
1798 if (f->explicit_name && NILP (name))
1799 update_mode_lines = 1;
1800
1801 f->explicit_name = ! NILP (name);
1802 }
1803 else if (f->explicit_name)
1804 return;
1805
1806 /* If NAME is nil, set the name to the w32_id_name. */
1807 if (NILP (name))
1808 {
1809 /* Check for no change needed in this very common case
1810 before we do any consing. */
1811 if (!strcmp (FRAME_W32_DISPLAY_INFO (f)->w32_id_name,
1812 SDATA (f->name)))
1813 return;
1814 name = build_string (FRAME_W32_DISPLAY_INFO (f)->w32_id_name);
1815 }
1816 else
1817 CHECK_STRING (name);
1818
1819 /* Don't change the name if it's already NAME. */
1820 if (! NILP (Fstring_equal (name, f->name)))
1821 return;
1822
1823 f->name = name;
1824
1825 /* For setting the frame title, the title parameter should override
1826 the name parameter. */
1827 if (! NILP (f->title))
1828 name = f->title;
1829
1830 if (FRAME_W32_WINDOW (f))
1831 {
1832 if (STRING_MULTIBYTE (name))
1833 name = ENCODE_SYSTEM (name);
1834
1835 BLOCK_INPUT;
1836 SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
1837 UNBLOCK_INPUT;
1838 }
1839 }
1840
1841 /* This function should be called when the user's lisp code has
1842 specified a name for the frame; the name will override any set by the
1843 redisplay code. */
1844 void
1845 x_explicitly_set_name (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval)
1846 {
1847 x_set_name (f, arg, 1);
1848 }
1849
1850 /* This function should be called by Emacs redisplay code to set the
1851 name; names set this way will never override names set by the user's
1852 lisp code. */
1853 void
1854 x_implicitly_set_name (FRAME_PTR f, Lisp_Object arg, Lisp_Object oldval)
1855 {
1856 x_set_name (f, arg, 0);
1857 }
1858 \f
1859 /* Change the title of frame F to NAME.
1860 If NAME is nil, use the frame name as the title. */
1861
1862 void
1863 x_set_title (struct frame *f, Lisp_Object name, Lisp_Object old_name)
1864 {
1865 /* Don't change the title if it's already NAME. */
1866 if (EQ (name, f->title))
1867 return;
1868
1869 update_mode_lines = 1;
1870
1871 f->title = name;
1872
1873 if (NILP (name))
1874 name = f->name;
1875
1876 if (FRAME_W32_WINDOW (f))
1877 {
1878 if (STRING_MULTIBYTE (name))
1879 name = ENCODE_SYSTEM (name);
1880
1881 BLOCK_INPUT;
1882 SetWindowText (FRAME_W32_WINDOW (f), SDATA (name));
1883 UNBLOCK_INPUT;
1884 }
1885 }
1886
1887
1888 void
1889 x_set_scroll_bar_default_width (struct frame *f)
1890 {
1891 int wid = FRAME_COLUMN_WIDTH (f);
1892
1893 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
1894 FRAME_CONFIG_SCROLL_BAR_COLS (f) = (FRAME_CONFIG_SCROLL_BAR_WIDTH (f) +
1895 wid - 1) / wid;
1896 }
1897
1898 \f
1899 /* Subroutines for creating a frame. */
1900
1901 Cursor
1902 w32_load_cursor (LPCTSTR name)
1903 {
1904 /* Try first to load cursor from application resource. */
1905 Cursor cursor = LoadImage ((HINSTANCE) GetModuleHandle (NULL),
1906 name, IMAGE_CURSOR, 0, 0,
1907 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
1908 if (!cursor)
1909 {
1910 /* Then try to load a shared predefined cursor. */
1911 cursor = LoadImage (NULL, name, IMAGE_CURSOR, 0, 0,
1912 LR_DEFAULTCOLOR | LR_DEFAULTSIZE | LR_SHARED);
1913 }
1914 return cursor;
1915 }
1916
1917 extern LRESULT CALLBACK w32_wnd_proc (HWND, UINT, WPARAM, LPARAM);
1918
1919 static BOOL
1920 w32_init_class (HINSTANCE hinst)
1921 {
1922 WNDCLASS wc;
1923
1924 wc.style = CS_HREDRAW | CS_VREDRAW;
1925 wc.lpfnWndProc = (WNDPROC) w32_wnd_proc;
1926 wc.cbClsExtra = 0;
1927 wc.cbWndExtra = WND_EXTRA_BYTES;
1928 wc.hInstance = hinst;
1929 wc.hIcon = LoadIcon (hinst, EMACS_CLASS);
1930 wc.hCursor = w32_load_cursor (IDC_ARROW);
1931 wc.hbrBackground = NULL; /* GetStockObject (WHITE_BRUSH); */
1932 wc.lpszMenuName = NULL;
1933 wc.lpszClassName = EMACS_CLASS;
1934
1935 return (RegisterClass (&wc));
1936 }
1937
1938 static HWND
1939 w32_createscrollbar (struct frame *f, struct scroll_bar * bar)
1940 {
1941 return (CreateWindow ("SCROLLBAR", "", SBS_VERT | WS_CHILD | WS_VISIBLE,
1942 /* Position and size of scroll bar. */
1943 XINT (bar->left) + VERTICAL_SCROLL_BAR_WIDTH_TRIM,
1944 XINT (bar->top),
1945 XINT (bar->width) - VERTICAL_SCROLL_BAR_WIDTH_TRIM * 2,
1946 XINT (bar->height),
1947 FRAME_W32_WINDOW (f),
1948 NULL,
1949 hinst,
1950 NULL));
1951 }
1952
1953 static void
1954 w32_createwindow (struct frame *f)
1955 {
1956 HWND hwnd;
1957 RECT rect;
1958 Lisp_Object top = Qunbound;
1959 Lisp_Object left = Qunbound;
1960 struct w32_display_info *dpyinfo = &one_w32_display_info;
1961
1962 rect.left = rect.top = 0;
1963 rect.right = FRAME_PIXEL_WIDTH (f);
1964 rect.bottom = FRAME_PIXEL_HEIGHT (f);
1965
1966 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
1967 FRAME_EXTERNAL_MENU_BAR (f));
1968
1969 /* Do first time app init */
1970
1971 if (!hprevinst)
1972 {
1973 w32_init_class (hinst);
1974 }
1975
1976 if (f->size_hint_flags & USPosition || f->size_hint_flags & PPosition)
1977 {
1978 XSETINT (left, f->left_pos);
1979 XSETINT (top, f->top_pos);
1980 }
1981 else if (EQ (left, Qunbound) && EQ (top, Qunbound))
1982 {
1983 /* When called with RES_TYPE_NUMBER, w32_get_arg will return zero
1984 for anything that is not a number and is not Qunbound. */
1985 left = x_get_arg (dpyinfo, Qnil, Qleft, "left", "Left", RES_TYPE_NUMBER);
1986 top = x_get_arg (dpyinfo, Qnil, Qtop, "top", "Top", RES_TYPE_NUMBER);
1987 }
1988
1989 FRAME_W32_WINDOW (f) = hwnd
1990 = CreateWindow (EMACS_CLASS,
1991 f->namebuf,
1992 f->output_data.w32->dwStyle | WS_CLIPCHILDREN,
1993 EQ (left, Qunbound) ? CW_USEDEFAULT : XINT (left),
1994 EQ (top, Qunbound) ? CW_USEDEFAULT : XINT (top),
1995 rect.right - rect.left,
1996 rect.bottom - rect.top,
1997 NULL,
1998 NULL,
1999 hinst,
2000 NULL);
2001
2002 if (hwnd)
2003 {
2004 SetWindowLong (hwnd, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
2005 SetWindowLong (hwnd, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
2006 SetWindowLong (hwnd, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
2007 SetWindowLong (hwnd, WND_SCROLLBAR_INDEX, f->scroll_bar_actual_width);
2008 SetWindowLong (hwnd, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
2009
2010 /* Enable drag-n-drop. */
2011 DragAcceptFiles (hwnd, TRUE);
2012
2013 /* Do this to discard the default setting specified by our parent. */
2014 ShowWindow (hwnd, SW_HIDE);
2015
2016 /* Update frame positions. */
2017 GetWindowRect (hwnd, &rect);
2018 f->left_pos = rect.left;
2019 f->top_pos = rect.top;
2020 }
2021 }
2022
2023 static void
2024 my_post_msg (W32Msg * wmsg, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2025 {
2026 wmsg->msg.hwnd = hwnd;
2027 wmsg->msg.message = msg;
2028 wmsg->msg.wParam = wParam;
2029 wmsg->msg.lParam = lParam;
2030 wmsg->msg.time = GetMessageTime ();
2031
2032 post_msg (wmsg);
2033 }
2034
2035 /* GetKeyState and MapVirtualKey on Windows 95 do not actually distinguish
2036 between left and right keys as advertised. We test for this
2037 support dynamically, and set a flag when the support is absent. If
2038 absent, we keep track of the left and right control and alt keys
2039 ourselves. This is particularly necessary on keyboards that rely
2040 upon the AltGr key, which is represented as having the left control
2041 and right alt keys pressed. For these keyboards, we need to know
2042 when the left alt key has been pressed in addition to the AltGr key
2043 so that we can properly support M-AltGr-key sequences (such as M-@
2044 on Swedish keyboards). */
2045
2046 #define EMACS_LCONTROL 0
2047 #define EMACS_RCONTROL 1
2048 #define EMACS_LMENU 2
2049 #define EMACS_RMENU 3
2050
2051 static int modifiers[4];
2052 static int modifiers_recorded;
2053 static int modifier_key_support_tested;
2054
2055 static void
2056 test_modifier_support (unsigned int wparam)
2057 {
2058 unsigned int l, r;
2059
2060 if (wparam != VK_CONTROL && wparam != VK_MENU)
2061 return;
2062 if (wparam == VK_CONTROL)
2063 {
2064 l = VK_LCONTROL;
2065 r = VK_RCONTROL;
2066 }
2067 else
2068 {
2069 l = VK_LMENU;
2070 r = VK_RMENU;
2071 }
2072 if (!(GetKeyState (l) & 0x8000) && !(GetKeyState (r) & 0x8000))
2073 modifiers_recorded = 1;
2074 else
2075 modifiers_recorded = 0;
2076 modifier_key_support_tested = 1;
2077 }
2078
2079 static void
2080 record_keydown (unsigned int wparam, unsigned int lparam)
2081 {
2082 int i;
2083
2084 if (!modifier_key_support_tested)
2085 test_modifier_support (wparam);
2086
2087 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2088 return;
2089
2090 if (wparam == VK_CONTROL)
2091 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2092 else
2093 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2094
2095 modifiers[i] = 1;
2096 }
2097
2098 static void
2099 record_keyup (unsigned int wparam, unsigned int lparam)
2100 {
2101 int i;
2102
2103 if ((wparam != VK_CONTROL && wparam != VK_MENU) || !modifiers_recorded)
2104 return;
2105
2106 if (wparam == VK_CONTROL)
2107 i = (lparam & 0x1000000) ? EMACS_RCONTROL : EMACS_LCONTROL;
2108 else
2109 i = (lparam & 0x1000000) ? EMACS_RMENU : EMACS_LMENU;
2110
2111 modifiers[i] = 0;
2112 }
2113
2114 /* Emacs can lose focus while a modifier key has been pressed. When
2115 it regains focus, be conservative and clear all modifiers since
2116 we cannot reconstruct the left and right modifier state. */
2117 static void
2118 reset_modifiers (void)
2119 {
2120 SHORT ctrl, alt;
2121
2122 if (GetFocus () == NULL)
2123 /* Emacs doesn't have keyboard focus. Do nothing. */
2124 return;
2125
2126 ctrl = GetAsyncKeyState (VK_CONTROL);
2127 alt = GetAsyncKeyState (VK_MENU);
2128
2129 if (!(ctrl & 0x08000))
2130 /* Clear any recorded control modifier state. */
2131 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2132
2133 if (!(alt & 0x08000))
2134 /* Clear any recorded alt modifier state. */
2135 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2136
2137 /* Update the state of all modifier keys, because modifiers used in
2138 hot-key combinations can get stuck on if Emacs loses focus as a
2139 result of a hot-key being pressed. */
2140 {
2141 BYTE keystate[256];
2142
2143 #define CURRENT_STATE(key) ((GetAsyncKeyState (key) & 0x8000) >> 8)
2144
2145 GetKeyboardState (keystate);
2146 keystate[VK_SHIFT] = CURRENT_STATE (VK_SHIFT);
2147 keystate[VK_CONTROL] = CURRENT_STATE (VK_CONTROL);
2148 keystate[VK_LCONTROL] = CURRENT_STATE (VK_LCONTROL);
2149 keystate[VK_RCONTROL] = CURRENT_STATE (VK_RCONTROL);
2150 keystate[VK_MENU] = CURRENT_STATE (VK_MENU);
2151 keystate[VK_LMENU] = CURRENT_STATE (VK_LMENU);
2152 keystate[VK_RMENU] = CURRENT_STATE (VK_RMENU);
2153 keystate[VK_LWIN] = CURRENT_STATE (VK_LWIN);
2154 keystate[VK_RWIN] = CURRENT_STATE (VK_RWIN);
2155 keystate[VK_APPS] = CURRENT_STATE (VK_APPS);
2156 SetKeyboardState (keystate);
2157 }
2158 }
2159
2160 /* Synchronize modifier state with what is reported with the current
2161 keystroke. Even if we cannot distinguish between left and right
2162 modifier keys, we know that, if no modifiers are set, then neither
2163 the left or right modifier should be set. */
2164 static void
2165 sync_modifiers (void)
2166 {
2167 if (!modifiers_recorded)
2168 return;
2169
2170 if (!(GetKeyState (VK_CONTROL) & 0x8000))
2171 modifiers[EMACS_RCONTROL] = modifiers[EMACS_LCONTROL] = 0;
2172
2173 if (!(GetKeyState (VK_MENU) & 0x8000))
2174 modifiers[EMACS_RMENU] = modifiers[EMACS_LMENU] = 0;
2175 }
2176
2177 static int
2178 modifier_set (int vkey)
2179 {
2180 if (vkey == VK_CAPITAL || vkey == VK_SCROLL)
2181 return (GetKeyState (vkey) & 0x1);
2182 if (!modifiers_recorded)
2183 return (GetKeyState (vkey) & 0x8000);
2184
2185 switch (vkey)
2186 {
2187 case VK_LCONTROL:
2188 return modifiers[EMACS_LCONTROL];
2189 case VK_RCONTROL:
2190 return modifiers[EMACS_RCONTROL];
2191 case VK_LMENU:
2192 return modifiers[EMACS_LMENU];
2193 case VK_RMENU:
2194 return modifiers[EMACS_RMENU];
2195 }
2196 return (GetKeyState (vkey) & 0x8000);
2197 }
2198
2199 /* Convert between the modifier bits W32 uses and the modifier bits
2200 Emacs uses. */
2201
2202 unsigned int
2203 w32_key_to_modifier (int key)
2204 {
2205 Lisp_Object key_mapping;
2206
2207 switch (key)
2208 {
2209 case VK_LWIN:
2210 key_mapping = Vw32_lwindow_modifier;
2211 break;
2212 case VK_RWIN:
2213 key_mapping = Vw32_rwindow_modifier;
2214 break;
2215 case VK_APPS:
2216 key_mapping = Vw32_apps_modifier;
2217 break;
2218 case VK_SCROLL:
2219 key_mapping = Vw32_scroll_lock_modifier;
2220 break;
2221 default:
2222 key_mapping = Qnil;
2223 }
2224
2225 /* NB. This code runs in the input thread, asychronously to the lisp
2226 thread, so we must be careful to ensure access to lisp data is
2227 thread-safe. The following code is safe because the modifier
2228 variable values are updated atomically from lisp and symbols are
2229 not relocated by GC. Also, we don't have to worry about seeing GC
2230 markbits here. */
2231 if (EQ (key_mapping, Qhyper))
2232 return hyper_modifier;
2233 if (EQ (key_mapping, Qsuper))
2234 return super_modifier;
2235 if (EQ (key_mapping, Qmeta))
2236 return meta_modifier;
2237 if (EQ (key_mapping, Qalt))
2238 return alt_modifier;
2239 if (EQ (key_mapping, Qctrl))
2240 return ctrl_modifier;
2241 if (EQ (key_mapping, Qcontrol)) /* synonym for ctrl */
2242 return ctrl_modifier;
2243 if (EQ (key_mapping, Qshift))
2244 return shift_modifier;
2245
2246 /* Don't generate any modifier if not explicitly requested. */
2247 return 0;
2248 }
2249
2250 static unsigned int
2251 w32_get_modifiers (void)
2252 {
2253 return ((modifier_set (VK_SHIFT) ? shift_modifier : 0) |
2254 (modifier_set (VK_CONTROL) ? ctrl_modifier : 0) |
2255 (modifier_set (VK_LWIN) ? w32_key_to_modifier (VK_LWIN) : 0) |
2256 (modifier_set (VK_RWIN) ? w32_key_to_modifier (VK_RWIN) : 0) |
2257 (modifier_set (VK_APPS) ? w32_key_to_modifier (VK_APPS) : 0) |
2258 (modifier_set (VK_SCROLL) ? w32_key_to_modifier (VK_SCROLL) : 0) |
2259 (modifier_set (VK_MENU) ?
2260 ((NILP (Vw32_alt_is_meta)) ? alt_modifier : meta_modifier) : 0));
2261 }
2262
2263 /* We map the VK_* modifiers into console modifier constants
2264 so that we can use the same routines to handle both console
2265 and window input. */
2266
2267 static int
2268 construct_console_modifiers (void)
2269 {
2270 int mods;
2271
2272 mods = 0;
2273 mods |= (modifier_set (VK_SHIFT)) ? SHIFT_PRESSED : 0;
2274 mods |= (modifier_set (VK_CAPITAL)) ? CAPSLOCK_ON : 0;
2275 mods |= (modifier_set (VK_SCROLL)) ? SCROLLLOCK_ON : 0;
2276 mods |= (modifier_set (VK_NUMLOCK)) ? NUMLOCK_ON : 0;
2277 mods |= (modifier_set (VK_LCONTROL)) ? LEFT_CTRL_PRESSED : 0;
2278 mods |= (modifier_set (VK_RCONTROL)) ? RIGHT_CTRL_PRESSED : 0;
2279 mods |= (modifier_set (VK_LMENU)) ? LEFT_ALT_PRESSED : 0;
2280 mods |= (modifier_set (VK_RMENU)) ? RIGHT_ALT_PRESSED : 0;
2281 mods |= (modifier_set (VK_LWIN)) ? LEFT_WIN_PRESSED : 0;
2282 mods |= (modifier_set (VK_RWIN)) ? RIGHT_WIN_PRESSED : 0;
2283 mods |= (modifier_set (VK_APPS)) ? APPS_PRESSED : 0;
2284
2285 return mods;
2286 }
2287
2288 static int
2289 w32_get_key_modifiers (unsigned int wparam, unsigned int lparam)
2290 {
2291 int mods;
2292
2293 /* Convert to emacs modifiers. */
2294 mods = w32_kbd_mods_to_emacs (construct_console_modifiers (), wparam);
2295
2296 return mods;
2297 }
2298
2299 unsigned int
2300 map_keypad_keys (unsigned int virt_key, unsigned int extended)
2301 {
2302 if (virt_key < VK_CLEAR || virt_key > VK_DELETE)
2303 return virt_key;
2304
2305 if (virt_key == VK_RETURN)
2306 return (extended ? VK_NUMPAD_ENTER : VK_RETURN);
2307
2308 if (virt_key >= VK_PRIOR && virt_key <= VK_DOWN)
2309 return (!extended ? (VK_NUMPAD_PRIOR + (virt_key - VK_PRIOR)) : virt_key);
2310
2311 if (virt_key == VK_INSERT || virt_key == VK_DELETE)
2312 return (!extended ? (VK_NUMPAD_INSERT + (virt_key - VK_INSERT)) : virt_key);
2313
2314 if (virt_key == VK_CLEAR)
2315 return (!extended ? VK_NUMPAD_CLEAR : virt_key);
2316
2317 return virt_key;
2318 }
2319
2320 /* List of special key combinations which w32 would normally capture,
2321 but Emacs should grab instead. Not directly visible to lisp, to
2322 simplify synchronization. Each item is an integer encoding a virtual
2323 key code and modifier combination to capture. */
2324 static Lisp_Object w32_grabbed_keys;
2325
2326 #define HOTKEY(vk, mods) make_number (((vk) & 255) | ((mods) << 8))
2327 #define HOTKEY_ID(k) (XFASTINT (k) & 0xbfff)
2328 #define HOTKEY_VK_CODE(k) (XFASTINT (k) & 255)
2329 #define HOTKEY_MODIFIERS(k) (XFASTINT (k) >> 8)
2330
2331 #define RAW_HOTKEY_ID(k) ((k) & 0xbfff)
2332 #define RAW_HOTKEY_VK_CODE(k) ((k) & 255)
2333 #define RAW_HOTKEY_MODIFIERS(k) ((k) >> 8)
2334
2335 /* Register hot-keys for reserved key combinations when Emacs has
2336 keyboard focus, since this is the only way Emacs can receive key
2337 combinations like Alt-Tab which are used by the system. */
2338
2339 static void
2340 register_hot_keys (HWND hwnd)
2341 {
2342 Lisp_Object keylist;
2343
2344 /* Use CONSP, since we are called asynchronously. */
2345 for (keylist = w32_grabbed_keys; CONSP (keylist); keylist = XCDR (keylist))
2346 {
2347 Lisp_Object key = XCAR (keylist);
2348
2349 /* Deleted entries get set to nil. */
2350 if (!INTEGERP (key))
2351 continue;
2352
2353 RegisterHotKey (hwnd, HOTKEY_ID (key),
2354 HOTKEY_MODIFIERS (key), HOTKEY_VK_CODE (key));
2355 }
2356 }
2357
2358 static void
2359 unregister_hot_keys (HWND hwnd)
2360 {
2361 Lisp_Object keylist;
2362
2363 for (keylist = w32_grabbed_keys; CONSP (keylist); keylist = XCDR (keylist))
2364 {
2365 Lisp_Object key = XCAR (keylist);
2366
2367 if (!INTEGERP (key))
2368 continue;
2369
2370 UnregisterHotKey (hwnd, HOTKEY_ID (key));
2371 }
2372 }
2373
2374 /* Main message dispatch loop. */
2375
2376 static void
2377 w32_msg_pump (deferred_msg * msg_buf)
2378 {
2379 MSG msg;
2380 int result;
2381 HWND focus_window;
2382
2383 msh_mousewheel = RegisterWindowMessage (MSH_MOUSEWHEEL);
2384
2385 while (GetMessage (&msg, NULL, 0, 0))
2386 {
2387 if (msg.hwnd == NULL)
2388 {
2389 switch (msg.message)
2390 {
2391 case WM_NULL:
2392 /* Produced by complete_deferred_msg; just ignore. */
2393 break;
2394 case WM_EMACS_CREATEWINDOW:
2395 /* Initialize COM for this window. Even though we don't use it,
2396 some third party shell extensions can cause it to be used in
2397 system dialogs, which causes a crash if it is not initialized.
2398 This is a known bug in Windows, which was fixed long ago, but
2399 the patch for XP is not publically available until XP SP3,
2400 and older versions will never be patched. */
2401 CoInitialize (NULL);
2402 w32_createwindow ((struct frame *) msg.wParam);
2403 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2404 abort ();
2405 break;
2406 case WM_EMACS_SETLOCALE:
2407 SetThreadLocale (msg.wParam);
2408 /* Reply is not expected. */
2409 break;
2410 case WM_EMACS_SETKEYBOARDLAYOUT:
2411 result = (int) ActivateKeyboardLayout ((HKL) msg.wParam, 0);
2412 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2413 result, 0))
2414 abort ();
2415 break;
2416 case WM_EMACS_REGISTER_HOT_KEY:
2417 focus_window = GetFocus ();
2418 if (focus_window != NULL)
2419 RegisterHotKey (focus_window,
2420 RAW_HOTKEY_ID (msg.wParam),
2421 RAW_HOTKEY_MODIFIERS (msg.wParam),
2422 RAW_HOTKEY_VK_CODE (msg.wParam));
2423 /* Reply is not expected. */
2424 break;
2425 case WM_EMACS_UNREGISTER_HOT_KEY:
2426 focus_window = GetFocus ();
2427 if (focus_window != NULL)
2428 UnregisterHotKey (focus_window, RAW_HOTKEY_ID (msg.wParam));
2429 /* Mark item as erased. NB: this code must be
2430 thread-safe. The next line is okay because the cons
2431 cell is never made into garbage and is not relocated by
2432 GC. */
2433 XSETCAR ((Lisp_Object) ((EMACS_INT) msg.lParam), Qnil);
2434 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2435 abort ();
2436 break;
2437 case WM_EMACS_TOGGLE_LOCK_KEY:
2438 {
2439 int vk_code = (int) msg.wParam;
2440 int cur_state = (GetKeyState (vk_code) & 1);
2441 Lisp_Object new_state = (Lisp_Object) ((EMACS_INT) msg.lParam);
2442
2443 /* NB: This code must be thread-safe. It is safe to
2444 call NILP because symbols are not relocated by GC,
2445 and pointer here is not touched by GC (so the markbit
2446 can't be set). Numbers are safe because they are
2447 immediate values. */
2448 if (NILP (new_state)
2449 || (NUMBERP (new_state)
2450 && ((XUINT (new_state)) & 1) != cur_state))
2451 {
2452 one_w32_display_info.faked_key = vk_code;
2453
2454 keybd_event ((BYTE) vk_code,
2455 (BYTE) MapVirtualKey (vk_code, 0),
2456 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2457 keybd_event ((BYTE) vk_code,
2458 (BYTE) MapVirtualKey (vk_code, 0),
2459 KEYEVENTF_EXTENDEDKEY | 0, 0);
2460 keybd_event ((BYTE) vk_code,
2461 (BYTE) MapVirtualKey (vk_code, 0),
2462 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2463 cur_state = !cur_state;
2464 }
2465 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE,
2466 cur_state, 0))
2467 abort ();
2468 }
2469 break;
2470 #ifdef MSG_DEBUG
2471 /* Broadcast messages make it here, so you need to be looking
2472 for something in particular for this to be useful. */
2473 default:
2474 DebPrint (("msg %x not expected by w32_msg_pump\n", msg.message));
2475 #endif
2476 }
2477 }
2478 else
2479 {
2480 DispatchMessage (&msg);
2481 }
2482
2483 /* Exit nested loop when our deferred message has completed. */
2484 if (msg_buf->completed)
2485 break;
2486 }
2487 }
2488
2489 deferred_msg * deferred_msg_head;
2490
2491 static deferred_msg *
2492 find_deferred_msg (HWND hwnd, UINT msg)
2493 {
2494 deferred_msg * item;
2495
2496 /* Don't actually need synchronization for read access, since
2497 modification of single pointer is always atomic. */
2498 /* enter_crit (); */
2499
2500 for (item = deferred_msg_head; item != NULL; item = item->next)
2501 if (item->w32msg.msg.hwnd == hwnd
2502 && item->w32msg.msg.message == msg)
2503 break;
2504
2505 /* leave_crit (); */
2506
2507 return item;
2508 }
2509
2510 static LRESULT
2511 send_deferred_msg (deferred_msg * msg_buf,
2512 HWND hwnd,
2513 UINT msg,
2514 WPARAM wParam,
2515 LPARAM lParam)
2516 {
2517 /* Only input thread can send deferred messages. */
2518 if (GetCurrentThreadId () != dwWindowsThreadId)
2519 abort ();
2520
2521 /* It is an error to send a message that is already deferred. */
2522 if (find_deferred_msg (hwnd, msg) != NULL)
2523 abort ();
2524
2525 /* Enforced synchronization is not needed because this is the only
2526 function that alters deferred_msg_head, and the following critical
2527 section is guaranteed to only be serially reentered (since only the
2528 input thread can call us). */
2529
2530 /* enter_crit (); */
2531
2532 msg_buf->completed = 0;
2533 msg_buf->next = deferred_msg_head;
2534 deferred_msg_head = msg_buf;
2535 my_post_msg (&msg_buf->w32msg, hwnd, msg, wParam, lParam);
2536
2537 /* leave_crit (); */
2538
2539 /* Start a new nested message loop to process other messages until
2540 this one is completed. */
2541 w32_msg_pump (msg_buf);
2542
2543 deferred_msg_head = msg_buf->next;
2544
2545 return msg_buf->result;
2546 }
2547
2548 void
2549 complete_deferred_msg (HWND hwnd, UINT msg, LRESULT result)
2550 {
2551 deferred_msg * msg_buf = find_deferred_msg (hwnd, msg);
2552
2553 if (msg_buf == NULL)
2554 /* Message may have been cancelled, so don't abort. */
2555 return;
2556
2557 msg_buf->result = result;
2558 msg_buf->completed = 1;
2559
2560 /* Ensure input thread is woken so it notices the completion. */
2561 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2562 }
2563
2564 static void
2565 cancel_all_deferred_msgs (void)
2566 {
2567 deferred_msg * item;
2568
2569 /* Don't actually need synchronization for read access, since
2570 modification of single pointer is always atomic. */
2571 /* enter_crit (); */
2572
2573 for (item = deferred_msg_head; item != NULL; item = item->next)
2574 {
2575 item->result = 0;
2576 item->completed = 1;
2577 }
2578
2579 /* leave_crit (); */
2580
2581 /* Ensure input thread is woken so it notices the completion. */
2582 PostThreadMessage (dwWindowsThreadId, WM_NULL, 0, 0);
2583 }
2584
2585 DWORD WINAPI
2586 w32_msg_worker (void *arg)
2587 {
2588 MSG msg;
2589 deferred_msg dummy_buf;
2590
2591 /* Ensure our message queue is created */
2592
2593 PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE);
2594
2595 if (!PostThreadMessage (dwMainThreadId, WM_EMACS_DONE, 0, 0))
2596 abort ();
2597
2598 memset (&dummy_buf, 0, sizeof (dummy_buf));
2599 dummy_buf.w32msg.msg.hwnd = NULL;
2600 dummy_buf.w32msg.msg.message = WM_NULL;
2601
2602 /* This is the initial message loop which should only exit when the
2603 application quits. */
2604 w32_msg_pump (&dummy_buf);
2605
2606 return 0;
2607 }
2608
2609 static void
2610 signal_user_input (void)
2611 {
2612 /* Interrupt any lisp that wants to be interrupted by input. */
2613 if (!NILP (Vthrow_on_input))
2614 {
2615 Vquit_flag = Vthrow_on_input;
2616 /* If we're inside a function that wants immediate quits,
2617 do it now. */
2618 if (immediate_quit && NILP (Vinhibit_quit))
2619 {
2620 immediate_quit = 0;
2621 QUIT;
2622 }
2623 }
2624 }
2625
2626
2627 static void
2628 post_character_message (HWND hwnd, UINT msg,
2629 WPARAM wParam, LPARAM lParam,
2630 DWORD modifiers)
2631 {
2632 W32Msg wmsg;
2633
2634 wmsg.dwModifiers = modifiers;
2635
2636 /* Detect quit_char and set quit-flag directly. Note that we
2637 still need to post a message to ensure the main thread will be
2638 woken up if blocked in sys_select, but we do NOT want to post
2639 the quit_char message itself (because it will usually be as if
2640 the user had typed quit_char twice). Instead, we post a dummy
2641 message that has no particular effect. */
2642 {
2643 int c = wParam;
2644 if (isalpha (c) && wmsg.dwModifiers == ctrl_modifier)
2645 c = make_ctrl_char (c) & 0377;
2646 if (c == quit_char
2647 || (wmsg.dwModifiers == 0 &&
2648 w32_quit_key && wParam == w32_quit_key))
2649 {
2650 Vquit_flag = Qt;
2651
2652 /* The choice of message is somewhat arbitrary, as long as
2653 the main thread handler just ignores it. */
2654 msg = WM_NULL;
2655
2656 /* Interrupt any blocking system calls. */
2657 signal_quit ();
2658
2659 /* As a safety precaution, forcibly complete any deferred
2660 messages. This is a kludge, but I don't see any particularly
2661 clean way to handle the situation where a deferred message is
2662 "dropped" in the lisp thread, and will thus never be
2663 completed, eg. by the user trying to activate the menubar
2664 when the lisp thread is busy, and then typing C-g when the
2665 menubar doesn't open promptly (with the result that the
2666 menubar never responds at all because the deferred
2667 WM_INITMENU message is never completed). Another problem
2668 situation is when the lisp thread calls SendMessage (to send
2669 a window manager command) when a message has been deferred;
2670 the lisp thread gets blocked indefinitely waiting for the
2671 deferred message to be completed, which itself is waiting for
2672 the lisp thread to respond.
2673
2674 Note that we don't want to block the input thread waiting for
2675 a reponse from the lisp thread (although that would at least
2676 solve the deadlock problem above), because we want to be able
2677 to receive C-g to interrupt the lisp thread. */
2678 cancel_all_deferred_msgs ();
2679 }
2680 else
2681 signal_user_input ();
2682 }
2683
2684 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2685 }
2686
2687 /* Main window procedure */
2688
2689 LRESULT CALLBACK
2690 w32_wnd_proc (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
2691 {
2692 struct frame *f;
2693 struct w32_display_info *dpyinfo = &one_w32_display_info;
2694 W32Msg wmsg;
2695 int windows_translate;
2696 int key;
2697
2698 /* Note that it is okay to call x_window_to_frame, even though we are
2699 not running in the main lisp thread, because frame deletion
2700 requires the lisp thread to synchronize with this thread. Thus, if
2701 a frame struct is returned, it can be used without concern that the
2702 lisp thread might make it disappear while we are using it.
2703
2704 NB. Walking the frame list in this thread is safe (as long as
2705 writes of Lisp_Object slots are atomic, which they are on Windows).
2706 Although delete-frame can destructively modify the frame list while
2707 we are walking it, a garbage collection cannot occur until after
2708 delete-frame has synchronized with this thread.
2709
2710 It is also safe to use functions that make GDI calls, such as
2711 w32_clear_rect, because these functions must obtain a DC handle
2712 from the frame struct using get_frame_dc which is thread-aware. */
2713
2714 switch (msg)
2715 {
2716 case WM_ERASEBKGND:
2717 f = x_window_to_frame (dpyinfo, hwnd);
2718 if (f)
2719 {
2720 HDC hdc = get_frame_dc (f);
2721 GetUpdateRect (hwnd, &wmsg.rect, FALSE);
2722 w32_clear_rect (f, hdc, &wmsg.rect);
2723 release_frame_dc (f, hdc);
2724
2725 #if defined (W32_DEBUG_DISPLAY)
2726 DebPrint (("WM_ERASEBKGND (frame %p): erasing %d,%d-%d,%d\n",
2727 f,
2728 wmsg.rect.left, wmsg.rect.top,
2729 wmsg.rect.right, wmsg.rect.bottom));
2730 #endif /* W32_DEBUG_DISPLAY */
2731 }
2732 return 1;
2733 case WM_PALETTECHANGED:
2734 /* ignore our own changes */
2735 if ((HWND)wParam != hwnd)
2736 {
2737 f = x_window_to_frame (dpyinfo, hwnd);
2738 if (f)
2739 /* get_frame_dc will realize our palette and force all
2740 frames to be redrawn if needed. */
2741 release_frame_dc (f, get_frame_dc (f));
2742 }
2743 return 0;
2744 case WM_PAINT:
2745 {
2746 PAINTSTRUCT paintStruct;
2747 RECT update_rect;
2748 memset (&update_rect, 0, sizeof (update_rect));
2749
2750 f = x_window_to_frame (dpyinfo, hwnd);
2751 if (f == 0)
2752 {
2753 DebPrint (("WM_PAINT received for unknown window %p\n", hwnd));
2754 return 0;
2755 }
2756
2757 /* MSDN Docs say not to call BeginPaint if GetUpdateRect
2758 fails. Apparently this can happen under some
2759 circumstances. */
2760 if (GetUpdateRect (hwnd, &update_rect, FALSE) || !w32_strict_painting)
2761 {
2762 enter_crit ();
2763 BeginPaint (hwnd, &paintStruct);
2764
2765 /* The rectangles returned by GetUpdateRect and BeginPaint
2766 do not always match. Play it safe by assuming both areas
2767 are invalid. */
2768 UnionRect (&(wmsg.rect), &update_rect, &(paintStruct.rcPaint));
2769
2770 #if defined (W32_DEBUG_DISPLAY)
2771 DebPrint (("WM_PAINT (frame %p): painting %d,%d-%d,%d\n",
2772 f,
2773 wmsg.rect.left, wmsg.rect.top,
2774 wmsg.rect.right, wmsg.rect.bottom));
2775 DebPrint ((" [update region is %d,%d-%d,%d]\n",
2776 update_rect.left, update_rect.top,
2777 update_rect.right, update_rect.bottom));
2778 #endif
2779 EndPaint (hwnd, &paintStruct);
2780 leave_crit ();
2781
2782 /* Change the message type to prevent Windows from
2783 combining WM_PAINT messages in the Lisp thread's queue,
2784 since Windows assumes that each message queue is
2785 dedicated to one frame and does not bother checking
2786 that hwnd matches before combining them. */
2787 my_post_msg (&wmsg, hwnd, WM_EMACS_PAINT, wParam, lParam);
2788
2789 return 0;
2790 }
2791
2792 /* If GetUpdateRect returns 0 (meaning there is no update
2793 region), assume the whole window needs to be repainted. */
2794 GetClientRect (hwnd, &wmsg.rect);
2795 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2796 return 0;
2797 }
2798
2799 case WM_INPUTLANGCHANGE:
2800 /* Inform lisp thread of keyboard layout changes. */
2801 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
2802
2803 /* Clear dead keys in the keyboard state; for simplicity only
2804 preserve modifier key states. */
2805 {
2806 int i;
2807 BYTE keystate[256];
2808
2809 GetKeyboardState (keystate);
2810 for (i = 0; i < 256; i++)
2811 if (1
2812 && i != VK_SHIFT
2813 && i != VK_LSHIFT
2814 && i != VK_RSHIFT
2815 && i != VK_CAPITAL
2816 && i != VK_NUMLOCK
2817 && i != VK_SCROLL
2818 && i != VK_CONTROL
2819 && i != VK_LCONTROL
2820 && i != VK_RCONTROL
2821 && i != VK_MENU
2822 && i != VK_LMENU
2823 && i != VK_RMENU
2824 && i != VK_LWIN
2825 && i != VK_RWIN)
2826 keystate[i] = 0;
2827 SetKeyboardState (keystate);
2828 }
2829 goto dflt;
2830
2831 case WM_HOTKEY:
2832 /* Synchronize hot keys with normal input. */
2833 PostMessage (hwnd, WM_KEYDOWN, HIWORD (lParam), 0);
2834 return (0);
2835
2836 case WM_KEYUP:
2837 case WM_SYSKEYUP:
2838 record_keyup (wParam, lParam);
2839 goto dflt;
2840
2841 case WM_KEYDOWN:
2842 case WM_SYSKEYDOWN:
2843 /* Ignore keystrokes we fake ourself; see below. */
2844 if (dpyinfo->faked_key == wParam)
2845 {
2846 dpyinfo->faked_key = 0;
2847 /* Make sure TranslateMessage sees them though (as long as
2848 they don't produce WM_CHAR messages). This ensures that
2849 indicator lights are toggled promptly on Windows 9x, for
2850 example. */
2851 if (wParam < 256 && lispy_function_keys[wParam])
2852 {
2853 windows_translate = 1;
2854 goto translate;
2855 }
2856 return 0;
2857 }
2858
2859 /* Synchronize modifiers with current keystroke. */
2860 sync_modifiers ();
2861 record_keydown (wParam, lParam);
2862 wParam = map_keypad_keys (wParam, (lParam & 0x1000000L) != 0);
2863
2864 windows_translate = 0;
2865
2866 switch (wParam)
2867 {
2868 case VK_LWIN:
2869 if (NILP (Vw32_pass_lwindow_to_system))
2870 {
2871 /* Prevent system from acting on keyup (which opens the
2872 Start menu if no other key was pressed) by simulating a
2873 press of Space which we will ignore. */
2874 if (GetAsyncKeyState (wParam) & 1)
2875 {
2876 if (NUMBERP (Vw32_phantom_key_code))
2877 key = XUINT (Vw32_phantom_key_code) & 255;
2878 else
2879 key = VK_SPACE;
2880 dpyinfo->faked_key = key;
2881 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
2882 }
2883 }
2884 if (!NILP (Vw32_lwindow_modifier))
2885 return 0;
2886 break;
2887 case VK_RWIN:
2888 if (NILP (Vw32_pass_rwindow_to_system))
2889 {
2890 if (GetAsyncKeyState (wParam) & 1)
2891 {
2892 if (NUMBERP (Vw32_phantom_key_code))
2893 key = XUINT (Vw32_phantom_key_code) & 255;
2894 else
2895 key = VK_SPACE;
2896 dpyinfo->faked_key = key;
2897 keybd_event (key, (BYTE) MapVirtualKey (key, 0), 0, 0);
2898 }
2899 }
2900 if (!NILP (Vw32_rwindow_modifier))
2901 return 0;
2902 break;
2903 case VK_APPS:
2904 if (!NILP (Vw32_apps_modifier))
2905 return 0;
2906 break;
2907 case VK_MENU:
2908 if (NILP (Vw32_pass_alt_to_system))
2909 /* Prevent DefWindowProc from activating the menu bar if an
2910 Alt key is pressed and released by itself. */
2911 return 0;
2912 windows_translate = 1;
2913 break;
2914 case VK_CAPITAL:
2915 /* Decide whether to treat as modifier or function key. */
2916 if (NILP (Vw32_enable_caps_lock))
2917 goto disable_lock_key;
2918 windows_translate = 1;
2919 break;
2920 case VK_NUMLOCK:
2921 /* Decide whether to treat as modifier or function key. */
2922 if (NILP (Vw32_enable_num_lock))
2923 goto disable_lock_key;
2924 windows_translate = 1;
2925 break;
2926 case VK_SCROLL:
2927 /* Decide whether to treat as modifier or function key. */
2928 if (NILP (Vw32_scroll_lock_modifier))
2929 goto disable_lock_key;
2930 windows_translate = 1;
2931 break;
2932 disable_lock_key:
2933 /* Ensure the appropriate lock key state (and indicator light)
2934 remains in the same state. We do this by faking another
2935 press of the relevant key. Apparently, this really is the
2936 only way to toggle the state of the indicator lights. */
2937 dpyinfo->faked_key = wParam;
2938 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
2939 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2940 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
2941 KEYEVENTF_EXTENDEDKEY | 0, 0);
2942 keybd_event ((BYTE) wParam, (BYTE) MapVirtualKey (wParam, 0),
2943 KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
2944 /* Ensure indicator lights are updated promptly on Windows 9x
2945 (TranslateMessage apparently does this), after forwarding
2946 input event. */
2947 post_character_message (hwnd, msg, wParam, lParam,
2948 w32_get_key_modifiers (wParam, lParam));
2949 windows_translate = 1;
2950 break;
2951 case VK_CONTROL:
2952 case VK_SHIFT:
2953 case VK_PROCESSKEY: /* Generated by IME. */
2954 windows_translate = 1;
2955 break;
2956 case VK_CANCEL:
2957 /* Windows maps Ctrl-Pause (aka Ctrl-Break) into VK_CANCEL,
2958 which is confusing for purposes of key binding; convert
2959 VK_CANCEL events into VK_PAUSE events. */
2960 wParam = VK_PAUSE;
2961 break;
2962 case VK_PAUSE:
2963 /* Windows maps Ctrl-NumLock into VK_PAUSE, which is confusing
2964 for purposes of key binding; convert these back into
2965 VK_NUMLOCK events, at least when we want to see NumLock key
2966 presses. (Note that there is never any possibility that
2967 VK_PAUSE with Ctrl really is C-Pause as per above.) */
2968 if (NILP (Vw32_enable_num_lock) && modifier_set (VK_CONTROL))
2969 wParam = VK_NUMLOCK;
2970 break;
2971 default:
2972 /* If not defined as a function key, change it to a WM_CHAR message. */
2973 if (wParam > 255 || !lispy_function_keys[wParam])
2974 {
2975 DWORD modifiers = construct_console_modifiers ();
2976
2977 if (!NILP (Vw32_recognize_altgr)
2978 && modifier_set (VK_LCONTROL) && modifier_set (VK_RMENU))
2979 {
2980 /* Always let TranslateMessage handle AltGr key chords;
2981 for some reason, ToAscii doesn't always process AltGr
2982 chords correctly. */
2983 windows_translate = 1;
2984 }
2985 else if ((modifiers & (~SHIFT_PRESSED & ~CAPSLOCK_ON)) != 0)
2986 {
2987 /* Handle key chords including any modifiers other
2988 than shift directly, in order to preserve as much
2989 modifier information as possible. */
2990 if ('A' <= wParam && wParam <= 'Z')
2991 {
2992 /* Don't translate modified alphabetic keystrokes,
2993 so the user doesn't need to constantly switch
2994 layout to type control or meta keystrokes when
2995 the normal layout translates alphabetic
2996 characters to non-ascii characters. */
2997 if (!modifier_set (VK_SHIFT))
2998 wParam += ('a' - 'A');
2999 msg = WM_CHAR;
3000 }
3001 else
3002 {
3003 /* Try to handle other keystrokes by determining the
3004 base character (ie. translating the base key plus
3005 shift modifier). */
3006 int add;
3007 int isdead = 0;
3008 KEY_EVENT_RECORD key;
3009
3010 key.bKeyDown = TRUE;
3011 key.wRepeatCount = 1;
3012 key.wVirtualKeyCode = wParam;
3013 key.wVirtualScanCode = (lParam & 0xFF0000) >> 16;
3014 key.uChar.AsciiChar = 0;
3015 key.dwControlKeyState = modifiers;
3016
3017 add = w32_kbd_patch_key (&key);
3018 /* 0 means an unrecognised keycode, negative means
3019 dead key. Ignore both. */
3020 while (--add >= 0)
3021 {
3022 /* Forward asciified character sequence. */
3023 post_character_message
3024 (hwnd, WM_CHAR,
3025 (unsigned char) key.uChar.AsciiChar, lParam,
3026 w32_get_key_modifiers (wParam, lParam));
3027 w32_kbd_patch_key (&key);
3028 }
3029 return 0;
3030 }
3031 }
3032 else
3033 {
3034 /* Let TranslateMessage handle everything else. */
3035 windows_translate = 1;
3036 }
3037 }
3038 }
3039
3040 translate:
3041 if (windows_translate)
3042 {
3043 MSG windows_msg = { hwnd, msg, wParam, lParam, 0, {0,0} };
3044 windows_msg.time = GetMessageTime ();
3045 TranslateMessage (&windows_msg);
3046 goto dflt;
3047 }
3048
3049 /* Fall through */
3050
3051 case WM_SYSCHAR:
3052 case WM_CHAR:
3053 post_character_message (hwnd, msg, wParam, lParam,
3054 w32_get_key_modifiers (wParam, lParam));
3055 break;
3056
3057 case WM_UNICHAR:
3058 /* WM_UNICHAR looks promising from the docs, but the exact
3059 circumstances in which TranslateMessage sends it is one of those
3060 Microsoft secret API things that EU and US courts are supposed
3061 to have put a stop to already. Spy++ shows it being sent to Notepad
3062 and other MS apps, but never to Emacs.
3063
3064 Some third party IMEs send it in accordance with the official
3065 documentation though, so handle it here.
3066
3067 UNICODE_NOCHAR is used to test for support for this message.
3068 TRUE indicates that the message is supported. */
3069 if (wParam == UNICODE_NOCHAR)
3070 return TRUE;
3071
3072 {
3073 W32Msg wmsg;
3074 wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam);
3075 signal_user_input ();
3076 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3077 }
3078 break;
3079
3080 case WM_IME_CHAR:
3081 /* If we can't get the IME result as unicode, use default processing,
3082 which will at least allow characters decodable in the system locale
3083 get through. */
3084 if (!get_composition_string_fn)
3085 goto dflt;
3086
3087 else if (!ignore_ime_char)
3088 {
3089 wchar_t * buffer;
3090 int size, i;
3091 W32Msg wmsg;
3092 HIMC context = get_ime_context_fn (hwnd);
3093 wmsg.dwModifiers = w32_get_key_modifiers (wParam, lParam);
3094 /* Get buffer size. */
3095 size = get_composition_string_fn (context, GCS_RESULTSTR, buffer, 0);
3096 buffer = alloca (size);
3097 size = get_composition_string_fn (context, GCS_RESULTSTR,
3098 buffer, size);
3099 release_ime_context_fn (hwnd, context);
3100
3101 signal_user_input ();
3102 for (i = 0; i < size / sizeof (wchar_t); i++)
3103 {
3104 my_post_msg (&wmsg, hwnd, WM_UNICHAR, (WPARAM) buffer[i],
3105 lParam);
3106 }
3107 /* Ignore the messages for the rest of the
3108 characters in the string that was output above. */
3109 ignore_ime_char = (size / sizeof (wchar_t)) - 1;
3110 }
3111 else
3112 ignore_ime_char--;
3113
3114 break;
3115
3116 case WM_IME_STARTCOMPOSITION:
3117 if (!set_ime_composition_window_fn)
3118 goto dflt;
3119 else
3120 {
3121 COMPOSITIONFORM form;
3122 HIMC context;
3123 struct window *w;
3124
3125 if (!context)
3126 break;
3127
3128 f = x_window_to_frame (dpyinfo, hwnd);
3129 w = XWINDOW (FRAME_SELECTED_WINDOW (f));
3130
3131 form.dwStyle = CFS_RECT;
3132 form.ptCurrentPos.x = w32_system_caret_x;
3133 form.ptCurrentPos.y = w32_system_caret_y;
3134
3135 form.rcArea.left = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, 0);
3136 form.rcArea.top = (WINDOW_TOP_EDGE_Y (w)
3137 + WINDOW_HEADER_LINE_HEIGHT (w));
3138 form.rcArea.right = (WINDOW_BOX_RIGHT_EDGE_X (w)
3139 - WINDOW_RIGHT_MARGIN_WIDTH (w)
3140 - WINDOW_RIGHT_FRINGE_WIDTH (w));
3141 form.rcArea.bottom = (WINDOW_BOTTOM_EDGE_Y (w)
3142 - WINDOW_MODE_LINE_HEIGHT (w));
3143
3144 context = get_ime_context_fn (hwnd);
3145 set_ime_composition_window_fn (context, &form);
3146 release_ime_context_fn (hwnd, context);
3147 }
3148 break;
3149
3150 case WM_IME_ENDCOMPOSITION:
3151 ignore_ime_char = 0;
3152 goto dflt;
3153
3154 /* Simulate middle mouse button events when left and right buttons
3155 are used together, but only if user has two button mouse. */
3156 case WM_LBUTTONDOWN:
3157 case WM_RBUTTONDOWN:
3158 if (w32_num_mouse_buttons > 2)
3159 goto handle_plain_button;
3160
3161 {
3162 int this = (msg == WM_LBUTTONDOWN) ? LMOUSE : RMOUSE;
3163 int other = (msg == WM_LBUTTONDOWN) ? RMOUSE : LMOUSE;
3164
3165 if (button_state & this)
3166 return 0;
3167
3168 if (button_state == 0)
3169 SetCapture (hwnd);
3170
3171 button_state |= this;
3172
3173 if (button_state & other)
3174 {
3175 if (mouse_button_timer)
3176 {
3177 KillTimer (hwnd, mouse_button_timer);
3178 mouse_button_timer = 0;
3179
3180 /* Generate middle mouse event instead. */
3181 msg = WM_MBUTTONDOWN;
3182 button_state |= MMOUSE;
3183 }
3184 else if (button_state & MMOUSE)
3185 {
3186 /* Ignore button event if we've already generated a
3187 middle mouse down event. This happens if the
3188 user releases and press one of the two buttons
3189 after we've faked a middle mouse event. */
3190 return 0;
3191 }
3192 else
3193 {
3194 /* Flush out saved message. */
3195 post_msg (&saved_mouse_button_msg);
3196 }
3197 wmsg.dwModifiers = w32_get_modifiers ();
3198 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3199 signal_user_input ();
3200
3201 /* Clear message buffer. */
3202 saved_mouse_button_msg.msg.hwnd = 0;
3203 }
3204 else
3205 {
3206 /* Hold onto message for now. */
3207 mouse_button_timer =
3208 SetTimer (hwnd, MOUSE_BUTTON_ID,
3209 w32_mouse_button_tolerance, NULL);
3210 saved_mouse_button_msg.msg.hwnd = hwnd;
3211 saved_mouse_button_msg.msg.message = msg;
3212 saved_mouse_button_msg.msg.wParam = wParam;
3213 saved_mouse_button_msg.msg.lParam = lParam;
3214 saved_mouse_button_msg.msg.time = GetMessageTime ();
3215 saved_mouse_button_msg.dwModifiers = w32_get_modifiers ();
3216 }
3217 }
3218 return 0;
3219
3220 case WM_LBUTTONUP:
3221 case WM_RBUTTONUP:
3222 if (w32_num_mouse_buttons > 2)
3223 goto handle_plain_button;
3224
3225 {
3226 int this = (msg == WM_LBUTTONUP) ? LMOUSE : RMOUSE;
3227 int other = (msg == WM_LBUTTONUP) ? RMOUSE : LMOUSE;
3228
3229 if ((button_state & this) == 0)
3230 return 0;
3231
3232 button_state &= ~this;
3233
3234 if (button_state & MMOUSE)
3235 {
3236 /* Only generate event when second button is released. */
3237 if ((button_state & other) == 0)
3238 {
3239 msg = WM_MBUTTONUP;
3240 button_state &= ~MMOUSE;
3241
3242 if (button_state) abort ();
3243 }
3244 else
3245 return 0;
3246 }
3247 else
3248 {
3249 /* Flush out saved message if necessary. */
3250 if (saved_mouse_button_msg.msg.hwnd)
3251 {
3252 post_msg (&saved_mouse_button_msg);
3253 }
3254 }
3255 wmsg.dwModifiers = w32_get_modifiers ();
3256 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3257 signal_user_input ();
3258
3259 /* Always clear message buffer and cancel timer. */
3260 saved_mouse_button_msg.msg.hwnd = 0;
3261 KillTimer (hwnd, mouse_button_timer);
3262 mouse_button_timer = 0;
3263
3264 if (button_state == 0)
3265 ReleaseCapture ();
3266 }
3267 return 0;
3268
3269 case WM_XBUTTONDOWN:
3270 case WM_XBUTTONUP:
3271 if (w32_pass_extra_mouse_buttons_to_system)
3272 goto dflt;
3273 /* else fall through and process them. */
3274 case WM_MBUTTONDOWN:
3275 case WM_MBUTTONUP:
3276 handle_plain_button:
3277 {
3278 BOOL up;
3279 int button;
3280
3281 /* Ignore middle and extra buttons as long as the menu is active. */
3282 f = x_window_to_frame (dpyinfo, hwnd);
3283 if (f && f->output_data.w32->menubar_active)
3284 return 0;
3285
3286 if (parse_button (msg, HIWORD (wParam), &button, &up))
3287 {
3288 if (up) ReleaseCapture ();
3289 else SetCapture (hwnd);
3290 button = (button == 0) ? LMOUSE :
3291 ((button == 1) ? MMOUSE : RMOUSE);
3292 if (up)
3293 button_state &= ~button;
3294 else
3295 button_state |= button;
3296 }
3297 }
3298
3299 wmsg.dwModifiers = w32_get_modifiers ();
3300 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3301 signal_user_input ();
3302
3303 /* Need to return true for XBUTTON messages, false for others,
3304 to indicate that we processed the message. */
3305 return (msg == WM_XBUTTONDOWN || msg == WM_XBUTTONUP);
3306
3307 case WM_MOUSEMOVE:
3308 /* Ignore mouse movements as long as the menu is active. These
3309 movements are processed by the window manager anyway, and
3310 it's wrong to handle them as if they happened on the
3311 underlying frame. */
3312 f = x_window_to_frame (dpyinfo, hwnd);
3313 if (f && f->output_data.w32->menubar_active)
3314 return 0;
3315
3316 /* If the mouse has just moved into the frame, start tracking
3317 it, so we will be notified when it leaves the frame. Mouse
3318 tracking only works under W98 and NT4 and later. On earlier
3319 versions, there is no way of telling when the mouse leaves the
3320 frame, so we just have to put up with help-echo and mouse
3321 highlighting remaining while the frame is not active. */
3322 if (track_mouse_event_fn && !track_mouse_window)
3323 {
3324 TRACKMOUSEEVENT tme;
3325 tme.cbSize = sizeof (tme);
3326 tme.dwFlags = TME_LEAVE;
3327 tme.hwndTrack = hwnd;
3328
3329 track_mouse_event_fn (&tme);
3330 track_mouse_window = hwnd;
3331 }
3332 case WM_VSCROLL:
3333 if (w32_mouse_move_interval <= 0
3334 || (msg == WM_MOUSEMOVE && button_state == 0))
3335 {
3336 wmsg.dwModifiers = w32_get_modifiers ();
3337 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3338 return 0;
3339 }
3340
3341 /* Hang onto mouse move and scroll messages for a bit, to avoid
3342 sending such events to Emacs faster than it can process them.
3343 If we get more events before the timer from the first message
3344 expires, we just replace the first message. */
3345
3346 if (saved_mouse_move_msg.msg.hwnd == 0)
3347 mouse_move_timer =
3348 SetTimer (hwnd, MOUSE_MOVE_ID,
3349 w32_mouse_move_interval, NULL);
3350
3351 /* Hold onto message for now. */
3352 saved_mouse_move_msg.msg.hwnd = hwnd;
3353 saved_mouse_move_msg.msg.message = msg;
3354 saved_mouse_move_msg.msg.wParam = wParam;
3355 saved_mouse_move_msg.msg.lParam = lParam;
3356 saved_mouse_move_msg.msg.time = GetMessageTime ();
3357 saved_mouse_move_msg.dwModifiers = w32_get_modifiers ();
3358
3359 return 0;
3360
3361 case WM_MOUSEWHEEL:
3362 case WM_DROPFILES:
3363 wmsg.dwModifiers = w32_get_modifiers ();
3364 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3365 signal_user_input ();
3366 return 0;
3367
3368 case WM_APPCOMMAND:
3369 if (w32_pass_multimedia_buttons_to_system)
3370 goto dflt;
3371 /* Otherwise, pass to lisp, the same way we do with mousehwheel. */
3372 case WM_MOUSEHWHEEL:
3373 wmsg.dwModifiers = w32_get_modifiers ();
3374 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3375 signal_user_input ();
3376 /* Non-zero must be returned when WM_MOUSEHWHEEL messages are
3377 handled, to prevent the system trying to handle it by faking
3378 scroll bar events. */
3379 return 1;
3380
3381 case WM_TIMER:
3382 /* Flush out saved messages if necessary. */
3383 if (wParam == mouse_button_timer)
3384 {
3385 if (saved_mouse_button_msg.msg.hwnd)
3386 {
3387 post_msg (&saved_mouse_button_msg);
3388 signal_user_input ();
3389 saved_mouse_button_msg.msg.hwnd = 0;
3390 }
3391 KillTimer (hwnd, mouse_button_timer);
3392 mouse_button_timer = 0;
3393 }
3394 else if (wParam == mouse_move_timer)
3395 {
3396 if (saved_mouse_move_msg.msg.hwnd)
3397 {
3398 post_msg (&saved_mouse_move_msg);
3399 saved_mouse_move_msg.msg.hwnd = 0;
3400 }
3401 KillTimer (hwnd, mouse_move_timer);
3402 mouse_move_timer = 0;
3403 }
3404 else if (wParam == menu_free_timer)
3405 {
3406 KillTimer (hwnd, menu_free_timer);
3407 menu_free_timer = 0;
3408 f = x_window_to_frame (dpyinfo, hwnd);
3409 /* If a popup menu is active, don't wipe its strings. */
3410 if (menubar_in_use
3411 && current_popup_menu == NULL)
3412 {
3413 /* Free memory used by owner-drawn and help-echo strings. */
3414 w32_free_menu_strings (hwnd);
3415 f->output_data.w32->menubar_active = 0;
3416 menubar_in_use = 0;
3417 }
3418 }
3419 else if (wParam == hourglass_timer)
3420 {
3421 KillTimer (hwnd, hourglass_timer);
3422 hourglass_timer = 0;
3423 w32_show_hourglass (x_window_to_frame (dpyinfo, hwnd));
3424 }
3425 return 0;
3426
3427 case WM_NCACTIVATE:
3428 /* Windows doesn't send us focus messages when putting up and
3429 taking down a system popup dialog as for Ctrl-Alt-Del on Windows 95.
3430 The only indication we get that something happened is receiving
3431 this message afterwards. So this is a good time to reset our
3432 keyboard modifiers' state. */
3433 reset_modifiers ();
3434 goto dflt;
3435
3436 case WM_INITMENU:
3437 button_state = 0;
3438 ReleaseCapture ();
3439 /* We must ensure menu bar is fully constructed and up to date
3440 before allowing user interaction with it. To achieve this
3441 we send this message to the lisp thread and wait for a
3442 reply (whose value is not actually needed) to indicate that
3443 the menu bar is now ready for use, so we can now return.
3444
3445 To remain responsive in the meantime, we enter a nested message
3446 loop that can process all other messages.
3447
3448 However, we skip all this if the message results from calling
3449 TrackPopupMenu - in fact, we must NOT attempt to send the lisp
3450 thread a message because it is blocked on us at this point. We
3451 set menubar_active before calling TrackPopupMenu to indicate
3452 this (there is no possibility of confusion with real menubar
3453 being active). */
3454
3455 f = x_window_to_frame (dpyinfo, hwnd);
3456 if (f
3457 && (f->output_data.w32->menubar_active
3458 /* We can receive this message even in the absence of a
3459 menubar (ie. when the system menu is activated) - in this
3460 case we do NOT want to forward the message, otherwise it
3461 will cause the menubar to suddenly appear when the user
3462 had requested it to be turned off! */
3463 || f->output_data.w32->menubar_widget == NULL))
3464 return 0;
3465
3466 {
3467 deferred_msg msg_buf;
3468
3469 /* Detect if message has already been deferred; in this case
3470 we cannot return any sensible value to ignore this. */
3471 if (find_deferred_msg (hwnd, msg) != NULL)
3472 abort ();
3473
3474 menubar_in_use = 1;
3475
3476 return send_deferred_msg (&msg_buf, hwnd, msg, wParam, lParam);
3477 }
3478
3479 case WM_EXITMENULOOP:
3480 f = x_window_to_frame (dpyinfo, hwnd);
3481
3482 /* If a menu is still active, check again after a short delay,
3483 since Windows often (always?) sends the WM_EXITMENULOOP
3484 before the corresponding WM_COMMAND message.
3485 Don't do this if a popup menu is active, since it is only
3486 menubar menus that require cleaning up in this way.
3487 */
3488 if (f && menubar_in_use && current_popup_menu == NULL)
3489 menu_free_timer = SetTimer (hwnd, MENU_FREE_ID, MENU_FREE_DELAY, NULL);
3490
3491 /* If hourglass cursor should be displayed, display it now. */
3492 if (f && f->output_data.w32->hourglass_p)
3493 SetCursor (f->output_data.w32->hourglass_cursor);
3494
3495 goto dflt;
3496
3497 case WM_MENUSELECT:
3498 /* Direct handling of help_echo in menus. Should be safe now
3499 that we generate the help_echo by placing a help event in the
3500 keyboard buffer. */
3501 {
3502 HMENU menu = (HMENU) lParam;
3503 UINT menu_item = (UINT) LOWORD (wParam);
3504 UINT flags = (UINT) HIWORD (wParam);
3505
3506 w32_menu_display_help (hwnd, menu, menu_item, flags);
3507 }
3508 return 0;
3509
3510 case WM_MEASUREITEM:
3511 f = x_window_to_frame (dpyinfo, hwnd);
3512 if (f)
3513 {
3514 MEASUREITEMSTRUCT * pMis = (MEASUREITEMSTRUCT *) lParam;
3515
3516 if (pMis->CtlType == ODT_MENU)
3517 {
3518 /* Work out dimensions for popup menu titles. */
3519 char * title = (char *) pMis->itemData;
3520 HDC hdc = GetDC (hwnd);
3521 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3522 LOGFONT menu_logfont;
3523 HFONT old_font;
3524 SIZE size;
3525
3526 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3527 menu_logfont.lfWeight = FW_BOLD;
3528 menu_font = CreateFontIndirect (&menu_logfont);
3529 old_font = SelectObject (hdc, menu_font);
3530
3531 pMis->itemHeight = GetSystemMetrics (SM_CYMENUSIZE);
3532 if (title)
3533 {
3534 if (unicode_append_menu)
3535 GetTextExtentPoint32W (hdc, (WCHAR *) title,
3536 wcslen ((WCHAR *) title),
3537 &size);
3538 else
3539 GetTextExtentPoint32 (hdc, title, strlen (title), &size);
3540
3541 pMis->itemWidth = size.cx;
3542 if (pMis->itemHeight < size.cy)
3543 pMis->itemHeight = size.cy;
3544 }
3545 else
3546 pMis->itemWidth = 0;
3547
3548 SelectObject (hdc, old_font);
3549 DeleteObject (menu_font);
3550 ReleaseDC (hwnd, hdc);
3551 return TRUE;
3552 }
3553 }
3554 return 0;
3555
3556 case WM_DRAWITEM:
3557 f = x_window_to_frame (dpyinfo, hwnd);
3558 if (f)
3559 {
3560 DRAWITEMSTRUCT * pDis = (DRAWITEMSTRUCT *) lParam;
3561
3562 if (pDis->CtlType == ODT_MENU)
3563 {
3564 /* Draw popup menu title. */
3565 char * title = (char *) pDis->itemData;
3566 if (title)
3567 {
3568 HDC hdc = pDis->hDC;
3569 HFONT menu_font = GetCurrentObject (hdc, OBJ_FONT);
3570 LOGFONT menu_logfont;
3571 HFONT old_font;
3572
3573 GetObject (menu_font, sizeof (menu_logfont), &menu_logfont);
3574 menu_logfont.lfWeight = FW_BOLD;
3575 menu_font = CreateFontIndirect (&menu_logfont);
3576 old_font = SelectObject (hdc, menu_font);
3577
3578 /* Always draw title as if not selected. */
3579 if (unicode_append_menu)
3580 ExtTextOutW (hdc,
3581 pDis->rcItem.left
3582 + GetSystemMetrics (SM_CXMENUCHECK),
3583 pDis->rcItem.top,
3584 ETO_OPAQUE, &pDis->rcItem,
3585 (WCHAR *) title,
3586 wcslen ((WCHAR *) title), NULL);
3587 else
3588 ExtTextOut (hdc,
3589 pDis->rcItem.left
3590 + GetSystemMetrics (SM_CXMENUCHECK),
3591 pDis->rcItem.top,
3592 ETO_OPAQUE, &pDis->rcItem,
3593 title, strlen (title), NULL);
3594
3595 SelectObject (hdc, old_font);
3596 DeleteObject (menu_font);
3597 }
3598 return TRUE;
3599 }
3600 }
3601 return 0;
3602
3603 #if 0
3604 /* Still not right - can't distinguish between clicks in the
3605 client area of the frame from clicks forwarded from the scroll
3606 bars - may have to hook WM_NCHITTEST to remember the mouse
3607 position and then check if it is in the client area ourselves. */
3608 case WM_MOUSEACTIVATE:
3609 /* Discard the mouse click that activates a frame, allowing the
3610 user to click anywhere without changing point (or worse!).
3611 Don't eat mouse clicks on scrollbars though!! */
3612 if (LOWORD (lParam) == HTCLIENT )
3613 return MA_ACTIVATEANDEAT;
3614 goto dflt;
3615 #endif
3616
3617 case WM_MOUSELEAVE:
3618 /* No longer tracking mouse. */
3619 track_mouse_window = NULL;
3620
3621 case WM_ACTIVATEAPP:
3622 case WM_ACTIVATE:
3623 case WM_WINDOWPOSCHANGED:
3624 case WM_SHOWWINDOW:
3625 /* Inform lisp thread that a frame might have just been obscured
3626 or exposed, so should recheck visibility of all frames. */
3627 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3628 goto dflt;
3629
3630 case WM_SETFOCUS:
3631 dpyinfo->faked_key = 0;
3632 reset_modifiers ();
3633 register_hot_keys (hwnd);
3634 goto command;
3635 case WM_KILLFOCUS:
3636 unregister_hot_keys (hwnd);
3637 button_state = 0;
3638 ReleaseCapture ();
3639 /* Relinquish the system caret. */
3640 if (w32_system_caret_hwnd)
3641 {
3642 w32_visible_system_caret_hwnd = NULL;
3643 w32_system_caret_hwnd = NULL;
3644 DestroyCaret ();
3645 }
3646 goto command;
3647 case WM_COMMAND:
3648 menubar_in_use = 0;
3649 f = x_window_to_frame (dpyinfo, hwnd);
3650 if (f && HIWORD (wParam) == 0)
3651 {
3652 if (menu_free_timer)
3653 {
3654 KillTimer (hwnd, menu_free_timer);
3655 menu_free_timer = 0;
3656 }
3657 }
3658 case WM_MOVE:
3659 case WM_SIZE:
3660 command:
3661 wmsg.dwModifiers = w32_get_modifiers ();
3662 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3663 goto dflt;
3664
3665 case WM_DESTROY:
3666 CoUninitialize ();
3667 return 0;
3668
3669 case WM_CLOSE:
3670 wmsg.dwModifiers = w32_get_modifiers ();
3671 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3672 return 0;
3673
3674 case WM_WINDOWPOSCHANGING:
3675 /* Don't restrict the sizing of tip frames. */
3676 if (hwnd == tip_window)
3677 return 0;
3678 {
3679 WINDOWPLACEMENT wp;
3680 LPWINDOWPOS lppos = (WINDOWPOS *) lParam;
3681
3682 wp.length = sizeof (WINDOWPLACEMENT);
3683 GetWindowPlacement (hwnd, &wp);
3684
3685 if (wp.showCmd != SW_SHOWMINIMIZED && (lppos->flags & SWP_NOSIZE) == 0)
3686 {
3687 RECT rect;
3688 int wdiff;
3689 int hdiff;
3690 DWORD font_width;
3691 DWORD line_height;
3692 DWORD internal_border;
3693 DWORD scrollbar_extra;
3694 RECT wr;
3695
3696 wp.length = sizeof (wp);
3697 GetWindowRect (hwnd, &wr);
3698
3699 enter_crit ();
3700
3701 font_width = GetWindowLong (hwnd, WND_FONTWIDTH_INDEX);
3702 line_height = GetWindowLong (hwnd, WND_LINEHEIGHT_INDEX);
3703 internal_border = GetWindowLong (hwnd, WND_BORDER_INDEX);
3704 scrollbar_extra = GetWindowLong (hwnd, WND_SCROLLBAR_INDEX);
3705
3706 leave_crit ();
3707
3708 memset (&rect, 0, sizeof (rect));
3709 AdjustWindowRect (&rect, GetWindowLong (hwnd, GWL_STYLE),
3710 GetMenu (hwnd) != NULL);
3711
3712 /* Force width and height of client area to be exact
3713 multiples of the character cell dimensions. */
3714 wdiff = (lppos->cx - (rect.right - rect.left)
3715 - 2 * internal_border - scrollbar_extra)
3716 % font_width;
3717 hdiff = (lppos->cy - (rect.bottom - rect.top)
3718 - 2 * internal_border)
3719 % line_height;
3720
3721 if (wdiff || hdiff)
3722 {
3723 /* For right/bottom sizing we can just fix the sizes.
3724 However for top/left sizing we will need to fix the X
3725 and Y positions as well. */
3726
3727 int cx_mintrack = GetSystemMetrics (SM_CXMINTRACK);
3728 int cy_mintrack = GetSystemMetrics (SM_CYMINTRACK);
3729
3730 lppos->cx = max (lppos->cx - wdiff, cx_mintrack);
3731 lppos->cy = max (lppos->cy - hdiff, cy_mintrack);
3732
3733 if (wp.showCmd != SW_SHOWMAXIMIZED
3734 && (lppos->flags & SWP_NOMOVE) == 0)
3735 {
3736 if (lppos->x != wr.left || lppos->y != wr.top)
3737 {
3738 lppos->x += wdiff;
3739 lppos->y += hdiff;
3740 }
3741 else
3742 {
3743 lppos->flags |= SWP_NOMOVE;
3744 }
3745 }
3746
3747 return 0;
3748 }
3749 }
3750 }
3751
3752 goto dflt;
3753
3754 case WM_GETMINMAXINFO:
3755 /* Hack to allow resizing the Emacs frame above the screen size.
3756 Note that Windows 9x limits coordinates to 16-bits. */
3757 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.x = 32767;
3758 ((LPMINMAXINFO) lParam)->ptMaxTrackSize.y = 32767;
3759 return 0;
3760
3761 case WM_SETCURSOR:
3762 if (LOWORD (lParam) == HTCLIENT)
3763 {
3764 f = x_window_to_frame (dpyinfo, hwnd);
3765 if (f->output_data.w32->hourglass_p && !menubar_in_use
3766 && !current_popup_menu)
3767 SetCursor (f->output_data.w32->hourglass_cursor);
3768 else
3769 SetCursor (f->output_data.w32->current_cursor);
3770 return 0;
3771 }
3772 goto dflt;
3773
3774 case WM_EMACS_SETCURSOR:
3775 {
3776 Cursor cursor = (Cursor) wParam;
3777 f = x_window_to_frame (dpyinfo, hwnd);
3778 if (f && cursor)
3779 {
3780 f->output_data.w32->current_cursor = cursor;
3781 if (!f->output_data.w32->hourglass_p)
3782 SetCursor (cursor);
3783 }
3784 return 0;
3785 }
3786
3787 case WM_EMACS_CREATESCROLLBAR:
3788 return (LRESULT) w32_createscrollbar ((struct frame *) wParam,
3789 (struct scroll_bar *) lParam);
3790
3791 case WM_EMACS_SHOWWINDOW:
3792 return ShowWindow ((HWND) wParam, (WPARAM) lParam);
3793
3794 case WM_EMACS_SETFOREGROUND:
3795 {
3796 HWND foreground_window;
3797 DWORD foreground_thread, retval;
3798
3799 /* On NT 5.0, and apparently Windows 98, it is necessary to
3800 attach to the thread that currently has focus in order to
3801 pull the focus away from it. */
3802 foreground_window = GetForegroundWindow ();
3803 foreground_thread = GetWindowThreadProcessId (foreground_window, NULL);
3804 if (!foreground_window
3805 || foreground_thread == GetCurrentThreadId ()
3806 || !AttachThreadInput (GetCurrentThreadId (),
3807 foreground_thread, TRUE))
3808 foreground_thread = 0;
3809
3810 retval = SetForegroundWindow ((HWND) wParam);
3811
3812 /* Detach from the previous foreground thread. */
3813 if (foreground_thread)
3814 AttachThreadInput (GetCurrentThreadId (),
3815 foreground_thread, FALSE);
3816
3817 return retval;
3818 }
3819
3820 case WM_EMACS_SETWINDOWPOS:
3821 {
3822 WINDOWPOS * pos = (WINDOWPOS *) wParam;
3823 return SetWindowPos (hwnd, pos->hwndInsertAfter,
3824 pos->x, pos->y, pos->cx, pos->cy, pos->flags);
3825 }
3826
3827 case WM_EMACS_DESTROYWINDOW:
3828 DragAcceptFiles ((HWND) wParam, FALSE);
3829 return DestroyWindow ((HWND) wParam);
3830
3831 case WM_EMACS_HIDE_CARET:
3832 return HideCaret (hwnd);
3833
3834 case WM_EMACS_SHOW_CARET:
3835 return ShowCaret (hwnd);
3836
3837 case WM_EMACS_DESTROY_CARET:
3838 w32_system_caret_hwnd = NULL;
3839 w32_visible_system_caret_hwnd = NULL;
3840 return DestroyCaret ();
3841
3842 case WM_EMACS_TRACK_CARET:
3843 /* If there is currently no system caret, create one. */
3844 if (w32_system_caret_hwnd == NULL)
3845 {
3846 /* Use the default caret width, and avoid changing it
3847 unneccesarily, as it confuses screen reader software. */
3848 w32_system_caret_hwnd = hwnd;
3849 CreateCaret (hwnd, NULL, 0,
3850 w32_system_caret_height);
3851 }
3852
3853 if (!SetCaretPos (w32_system_caret_x, w32_system_caret_y))
3854 return 0;
3855 /* Ensure visible caret gets turned on when requested. */
3856 else if (w32_use_visible_system_caret
3857 && w32_visible_system_caret_hwnd != hwnd)
3858 {
3859 w32_visible_system_caret_hwnd = hwnd;
3860 return ShowCaret (hwnd);
3861 }
3862 /* Ensure visible caret gets turned off when requested. */
3863 else if (!w32_use_visible_system_caret
3864 && w32_visible_system_caret_hwnd)
3865 {
3866 w32_visible_system_caret_hwnd = NULL;
3867 return HideCaret (hwnd);
3868 }
3869 else
3870 return 1;
3871
3872 case WM_EMACS_TRACKPOPUPMENU:
3873 {
3874 UINT flags;
3875 POINT *pos;
3876 int retval;
3877 pos = (POINT *)lParam;
3878 flags = TPM_CENTERALIGN;
3879 if (button_state & LMOUSE)
3880 flags |= TPM_LEFTBUTTON;
3881 else if (button_state & RMOUSE)
3882 flags |= TPM_RIGHTBUTTON;
3883
3884 /* Remember we did a SetCapture on the initial mouse down event,
3885 so for safety, we make sure the capture is cancelled now. */
3886 ReleaseCapture ();
3887 button_state = 0;
3888
3889 /* Use menubar_active to indicate that WM_INITMENU is from
3890 TrackPopupMenu below, and should be ignored. */
3891 f = x_window_to_frame (dpyinfo, hwnd);
3892 if (f)
3893 f->output_data.w32->menubar_active = 1;
3894
3895 if (TrackPopupMenu ((HMENU)wParam, flags, pos->x, pos->y,
3896 0, hwnd, NULL))
3897 {
3898 MSG amsg;
3899 /* Eat any mouse messages during popupmenu */
3900 while (PeekMessage (&amsg, hwnd, WM_MOUSEFIRST, WM_MOUSELAST,
3901 PM_REMOVE));
3902 /* Get the menu selection, if any */
3903 if (PeekMessage (&amsg, hwnd, WM_COMMAND, WM_COMMAND, PM_REMOVE))
3904 {
3905 retval = LOWORD (amsg.wParam);
3906 }
3907 else
3908 {
3909 retval = 0;
3910 }
3911 }
3912 else
3913 {
3914 retval = -1;
3915 }
3916
3917 return retval;
3918 }
3919
3920 default:
3921 /* Check for messages registered at runtime. */
3922 if (msg == msh_mousewheel)
3923 {
3924 wmsg.dwModifiers = w32_get_modifiers ();
3925 my_post_msg (&wmsg, hwnd, msg, wParam, lParam);
3926 signal_user_input ();
3927 return 0;
3928 }
3929
3930 dflt:
3931 return DefWindowProc (hwnd, msg, wParam, lParam);
3932 }
3933
3934
3935 /* The most common default return code for handled messages is 0. */
3936 return 0;
3937 }
3938
3939 static void
3940 my_create_window (struct frame * f)
3941 {
3942 MSG msg;
3943
3944 if (!PostThreadMessage (dwWindowsThreadId, WM_EMACS_CREATEWINDOW, (WPARAM)f, 0))
3945 abort ();
3946 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
3947 }
3948
3949
3950 /* Create a tooltip window. Unlike my_create_window, we do not do this
3951 indirectly via the Window thread, as we do not need to process Window
3952 messages for the tooltip. Creating tooltips indirectly also creates
3953 deadlocks when tooltips are created for menu items. */
3954 static void
3955 my_create_tip_window (struct frame *f)
3956 {
3957 RECT rect;
3958
3959 rect.left = rect.top = 0;
3960 rect.right = FRAME_PIXEL_WIDTH (f);
3961 rect.bottom = FRAME_PIXEL_HEIGHT (f);
3962
3963 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
3964 FRAME_EXTERNAL_MENU_BAR (f));
3965
3966 tip_window = FRAME_W32_WINDOW (f)
3967 = CreateWindow (EMACS_CLASS,
3968 f->namebuf,
3969 f->output_data.w32->dwStyle,
3970 f->left_pos,
3971 f->top_pos,
3972 rect.right - rect.left,
3973 rect.bottom - rect.top,
3974 FRAME_W32_WINDOW (SELECTED_FRAME ()), /* owner */
3975 NULL,
3976 hinst,
3977 NULL);
3978
3979 if (tip_window)
3980 {
3981 SetWindowLong (tip_window, WND_FONTWIDTH_INDEX, FRAME_COLUMN_WIDTH (f));
3982 SetWindowLong (tip_window, WND_LINEHEIGHT_INDEX, FRAME_LINE_HEIGHT (f));
3983 SetWindowLong (tip_window, WND_BORDER_INDEX, FRAME_INTERNAL_BORDER_WIDTH (f));
3984 SetWindowLong (tip_window, WND_BACKGROUND_INDEX, FRAME_BACKGROUND_PIXEL (f));
3985
3986 /* Tip frames have no scrollbars. */
3987 SetWindowLong (tip_window, WND_SCROLLBAR_INDEX, 0);
3988
3989 /* Do this to discard the default setting specified by our parent. */
3990 ShowWindow (tip_window, SW_HIDE);
3991 }
3992 }
3993
3994
3995 /* Create and set up the w32 window for frame F. */
3996
3997 static void
3998 w32_window (struct frame *f, long window_prompting, int minibuffer_only)
3999 {
4000 BLOCK_INPUT;
4001
4002 /* Use the resource name as the top-level window name
4003 for looking up resources. Make a non-Lisp copy
4004 for the window manager, so GC relocation won't bother it.
4005
4006 Elsewhere we specify the window name for the window manager. */
4007
4008 {
4009 char *str = (char *) SDATA (Vx_resource_name);
4010 f->namebuf = (char *) xmalloc (strlen (str) + 1);
4011 strcpy (f->namebuf, str);
4012 }
4013
4014 my_create_window (f);
4015
4016 validate_x_resource_name ();
4017
4018 /* x_set_name normally ignores requests to set the name if the
4019 requested name is the same as the current name. This is the one
4020 place where that assumption isn't correct; f->name is set, but
4021 the server hasn't been told. */
4022 {
4023 Lisp_Object name;
4024 int explicit = f->explicit_name;
4025
4026 f->explicit_name = 0;
4027 name = f->name;
4028 f->name = Qnil;
4029 x_set_name (f, name, explicit);
4030 }
4031
4032 UNBLOCK_INPUT;
4033
4034 if (!minibuffer_only && FRAME_EXTERNAL_MENU_BAR (f))
4035 initialize_frame_menubar (f);
4036
4037 if (FRAME_W32_WINDOW (f) == 0)
4038 error ("Unable to create window");
4039 }
4040
4041 /* Handle the icon stuff for this window. Perhaps later we might
4042 want an x_set_icon_position which can be called interactively as
4043 well. */
4044
4045 static void
4046 x_icon (struct frame *f, Lisp_Object parms)
4047 {
4048 Lisp_Object icon_x, icon_y;
4049 struct w32_display_info *dpyinfo = &one_w32_display_info;
4050
4051 /* Set the position of the icon. Note that Windows 95 groups all
4052 icons in the tray. */
4053 icon_x = x_get_arg (dpyinfo, parms, Qicon_left, 0, 0, RES_TYPE_NUMBER);
4054 icon_y = x_get_arg (dpyinfo, parms, Qicon_top, 0, 0, RES_TYPE_NUMBER);
4055 if (!EQ (icon_x, Qunbound) && !EQ (icon_y, Qunbound))
4056 {
4057 CHECK_NUMBER (icon_x);
4058 CHECK_NUMBER (icon_y);
4059 }
4060 else if (!EQ (icon_x, Qunbound) || !EQ (icon_y, Qunbound))
4061 error ("Both left and top icon corners of icon must be specified");
4062
4063 BLOCK_INPUT;
4064
4065 if (! EQ (icon_x, Qunbound))
4066 x_wm_set_icon_position (f, XINT (icon_x), XINT (icon_y));
4067
4068 #if 0 /* TODO */
4069 /* Start up iconic or window? */
4070 x_wm_set_window_state
4071 (f, (EQ (x_get_arg (dpyinfo, parms, Qvisibility, 0, 0, RES_TYPE_SYMBOL), Qicon)
4072 ? IconicState
4073 : NormalState));
4074
4075 x_text_icon (f, (char *) SDATA ((!NILP (f->icon_name)
4076 ? f->icon_name
4077 : f->name)));
4078 #endif
4079
4080 UNBLOCK_INPUT;
4081 }
4082
4083
4084 static void
4085 x_make_gc (struct frame *f)
4086 {
4087 XGCValues gc_values;
4088
4089 BLOCK_INPUT;
4090
4091 /* Create the GC's of this frame.
4092 Note that many default values are used. */
4093
4094 /* Normal video */
4095 gc_values.font = FRAME_FONT (f);
4096
4097 /* Cursor has cursor-color background, background-color foreground. */
4098 gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
4099 gc_values.background = f->output_data.w32->cursor_pixel;
4100 f->output_data.w32->cursor_gc
4101 = XCreateGC (NULL, FRAME_W32_WINDOW (f),
4102 (GCFont | GCForeground | GCBackground),
4103 &gc_values);
4104
4105 /* Reliefs. */
4106 f->output_data.w32->white_relief.gc = 0;
4107 f->output_data.w32->black_relief.gc = 0;
4108
4109 UNBLOCK_INPUT;
4110 }
4111
4112
4113 /* Handler for signals raised during x_create_frame and
4114 x_create_top_frame. FRAME is the frame which is partially
4115 constructed. */
4116
4117 static Lisp_Object
4118 unwind_create_frame (Lisp_Object frame)
4119 {
4120 struct frame *f = XFRAME (frame);
4121
4122 /* If frame is ``official'', nothing to do. */
4123 if (!CONSP (Vframe_list) || !EQ (XCAR (Vframe_list), frame))
4124 {
4125 #ifdef GLYPH_DEBUG
4126 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4127 #endif
4128
4129 x_free_frame_resources (f);
4130
4131 #if GLYPH_DEBUG
4132 /* Check that reference counts are indeed correct. */
4133 xassert (dpyinfo->reference_count == dpyinfo_refcount);
4134 xassert (dpyinfo->image_cache->refcount == image_cache_refcount);
4135 #endif
4136 return Qt;
4137 }
4138
4139 return Qnil;
4140 }
4141
4142 static void
4143 x_default_font_parameter (struct frame *f, Lisp_Object parms)
4144 {
4145 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (f);
4146 Lisp_Object font_param = x_get_arg (dpyinfo, parms, Qfont, NULL, NULL,
4147 RES_TYPE_STRING);
4148 Lisp_Object font;
4149 if (EQ (font_param, Qunbound))
4150 font_param = Qnil;
4151 font = !NILP (font_param) ? font_param
4152 : x_get_arg (dpyinfo, parms, Qfont, "font", "Font", RES_TYPE_STRING);
4153
4154 if (!STRINGP (font))
4155 {
4156 int i;
4157 static char *names[]
4158 = { "Courier New-10",
4159 "-*-Courier-normal-r-*-*-13-*-*-*-c-*-iso8859-1",
4160 "-*-Fixedsys-normal-r-*-*-12-*-*-*-c-*-iso8859-1",
4161 "Fixedsys",
4162 NULL };
4163
4164 for (i = 0; names[i]; i++)
4165 {
4166 font = font_open_by_name (f, names[i]);
4167 if (! NILP (font))
4168 break;
4169 }
4170 if (NILP (font))
4171 error ("No suitable font was found");
4172 }
4173 else if (!NILP (font_param))
4174 {
4175 /* Remember the explicit font parameter, so we can re-apply it after
4176 we've applied the `default' face settings. */
4177 x_set_frame_parameters (f, Fcons (Fcons (Qfont_param, font_param), Qnil));
4178 }
4179 x_default_parameter (f, parms, Qfont, font, "font", "Font", RES_TYPE_STRING);
4180 }
4181
4182 DEFUN ("x-create-frame", Fx_create_frame, Sx_create_frame,
4183 1, 1, 0,
4184 doc: /* Make a new window, which is called a \"frame\" in Emacs terms.
4185 Return an Emacs frame object.
4186 PARAMETERS is an alist of frame parameters.
4187 If the parameters specify that the frame should not have a minibuffer,
4188 and do not specify a specific minibuffer window to use,
4189 then `default-minibuffer-frame' must be a frame whose minibuffer can
4190 be shared by the new frame.
4191
4192 This function is an internal primitive--use `make-frame' instead. */)
4193 (Lisp_Object parameters)
4194 {
4195 struct frame *f;
4196 Lisp_Object frame, tem;
4197 Lisp_Object name;
4198 int minibuffer_only = 0;
4199 long window_prompting = 0;
4200 int width, height;
4201 int count = SPECPDL_INDEX ();
4202 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
4203 Lisp_Object display;
4204 struct w32_display_info *dpyinfo = NULL;
4205 Lisp_Object parent;
4206 struct kboard *kb;
4207
4208 /* Make copy of frame parameters because the original is in pure
4209 storage now. */
4210 parameters = Fcopy_alist (parameters);
4211
4212 /* Use this general default value to start with
4213 until we know if this frame has a specified name. */
4214 Vx_resource_name = Vinvocation_name;
4215
4216 display = x_get_arg (dpyinfo, parameters, Qterminal, 0, 0, RES_TYPE_NUMBER);
4217 if (EQ (display, Qunbound))
4218 display = x_get_arg (dpyinfo, parameters, Qdisplay, 0, 0, RES_TYPE_STRING);
4219 if (EQ (display, Qunbound))
4220 display = Qnil;
4221 dpyinfo = check_x_display_info (display);
4222 kb = dpyinfo->terminal->kboard;
4223
4224 if (!dpyinfo->terminal->name)
4225 error ("Terminal is not live, can't create new frames on it");
4226
4227 name = x_get_arg (dpyinfo, parameters, Qname, "name", "Name", RES_TYPE_STRING);
4228 if (!STRINGP (name)
4229 && ! EQ (name, Qunbound)
4230 && ! NILP (name))
4231 error ("Invalid frame name--not a string or nil");
4232
4233 if (STRINGP (name))
4234 Vx_resource_name = name;
4235
4236 /* See if parent window is specified. */
4237 parent = x_get_arg (dpyinfo, parameters, Qparent_id, NULL, NULL, RES_TYPE_NUMBER);
4238 if (EQ (parent, Qunbound))
4239 parent = Qnil;
4240 if (! NILP (parent))
4241 CHECK_NUMBER (parent);
4242
4243 /* make_frame_without_minibuffer can run Lisp code and garbage collect. */
4244 /* No need to protect DISPLAY because that's not used after passing
4245 it to make_frame_without_minibuffer. */
4246 frame = Qnil;
4247 GCPRO4 (parameters, parent, name, frame);
4248 tem = x_get_arg (dpyinfo, parameters, Qminibuffer, "minibuffer", "Minibuffer",
4249 RES_TYPE_SYMBOL);
4250 if (EQ (tem, Qnone) || NILP (tem))
4251 f = make_frame_without_minibuffer (Qnil, kb, display);
4252 else if (EQ (tem, Qonly))
4253 {
4254 f = make_minibuffer_frame ();
4255 minibuffer_only = 1;
4256 }
4257 else if (WINDOWP (tem))
4258 f = make_frame_without_minibuffer (tem, kb, display);
4259 else
4260 f = make_frame (1);
4261
4262 XSETFRAME (frame, f);
4263
4264 /* Note that Windows does support scroll bars. */
4265 FRAME_CAN_HAVE_SCROLL_BARS (f) = 1;
4266
4267 /* By default, make scrollbars the system standard width. */
4268 FRAME_CONFIG_SCROLL_BAR_WIDTH (f) = GetSystemMetrics (SM_CXVSCROLL);
4269
4270 f->terminal = dpyinfo->terminal;
4271 f->terminal->reference_count++;
4272
4273 f->output_method = output_w32;
4274 f->output_data.w32 =
4275 (struct w32_output *) xmalloc (sizeof (struct w32_output));
4276 memset (f->output_data.w32, 0, sizeof (struct w32_output));
4277 FRAME_FONTSET (f) = -1;
4278
4279 f->icon_name
4280 = x_get_arg (dpyinfo, parameters, Qicon_name, "iconName", "Title",
4281 RES_TYPE_STRING);
4282 if (! STRINGP (f->icon_name))
4283 f->icon_name = Qnil;
4284
4285 /* FRAME_W32_DISPLAY_INFO (f) = dpyinfo; */
4286
4287 /* With FRAME_X_DISPLAY_INFO set up, this unwind-protect is safe. */
4288 record_unwind_protect (unwind_create_frame, frame);
4289 #if GLYPH_DEBUG
4290 image_cache_refcount = FRAME_IMAGE_CACHE (f)->refcount;
4291 dpyinfo_refcount = dpyinfo->reference_count;
4292 #endif /* GLYPH_DEBUG */
4293
4294 /* Specify the parent under which to make this window. */
4295
4296 if (!NILP (parent))
4297 {
4298 f->output_data.w32->parent_desc = (Window) XFASTINT (parent);
4299 f->output_data.w32->explicit_parent = 1;
4300 }
4301 else
4302 {
4303 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4304 f->output_data.w32->explicit_parent = 0;
4305 }
4306
4307 /* Set the name; the functions to which we pass f expect the name to
4308 be set. */
4309 if (EQ (name, Qunbound) || NILP (name))
4310 {
4311 f->name = build_string (dpyinfo->w32_id_name);
4312 f->explicit_name = 0;
4313 }
4314 else
4315 {
4316 f->name = name;
4317 f->explicit_name = 1;
4318 /* use the frame's title when getting resources for this frame. */
4319 specbind (Qx_resource_name, name);
4320 }
4321
4322 f->resx = dpyinfo->resx;
4323 f->resy = dpyinfo->resy;
4324
4325 if (uniscribe_available)
4326 register_font_driver (&uniscribe_font_driver, f);
4327 register_font_driver (&w32font_driver, f);
4328
4329 x_default_parameter (f, parameters, Qfont_backend, Qnil,
4330 "fontBackend", "FontBackend", RES_TYPE_STRING);
4331 /* Extract the window parameters from the supplied values
4332 that are needed to determine window geometry. */
4333 x_default_font_parameter (f, parameters);
4334 x_default_parameter (f, parameters, Qborder_width, make_number (2),
4335 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
4336
4337 /* We recognize either internalBorderWidth or internalBorder
4338 (which is what xterm calls it). */
4339 if (NILP (Fassq (Qinternal_border_width, parameters)))
4340 {
4341 Lisp_Object value;
4342
4343 value = x_get_arg (dpyinfo, parameters, Qinternal_border_width,
4344 "internalBorder", "InternalBorder", RES_TYPE_NUMBER);
4345 if (! EQ (value, Qunbound))
4346 parameters = Fcons (Fcons (Qinternal_border_width, value),
4347 parameters);
4348 }
4349 /* Default internalBorderWidth to 0 on Windows to match other programs. */
4350 x_default_parameter (f, parameters, Qinternal_border_width, make_number (0),
4351 "internalBorderWidth", "InternalBorder", RES_TYPE_NUMBER);
4352 x_default_parameter (f, parameters, Qvertical_scroll_bars, Qright,
4353 "verticalScrollBars", "ScrollBars", RES_TYPE_SYMBOL);
4354
4355 /* Also do the stuff which must be set before the window exists. */
4356 x_default_parameter (f, parameters, Qforeground_color, build_string ("black"),
4357 "foreground", "Foreground", RES_TYPE_STRING);
4358 x_default_parameter (f, parameters, Qbackground_color, build_string ("white"),
4359 "background", "Background", RES_TYPE_STRING);
4360 x_default_parameter (f, parameters, Qmouse_color, build_string ("black"),
4361 "pointerColor", "Foreground", RES_TYPE_STRING);
4362 x_default_parameter (f, parameters, Qcursor_color, build_string ("black"),
4363 "cursorColor", "Foreground", RES_TYPE_STRING);
4364 x_default_parameter (f, parameters, Qborder_color, build_string ("black"),
4365 "borderColor", "BorderColor", RES_TYPE_STRING);
4366 x_default_parameter (f, parameters, Qscreen_gamma, Qnil,
4367 "screenGamma", "ScreenGamma", RES_TYPE_FLOAT);
4368 x_default_parameter (f, parameters, Qline_spacing, Qnil,
4369 "lineSpacing", "LineSpacing", RES_TYPE_NUMBER);
4370 x_default_parameter (f, parameters, Qleft_fringe, Qnil,
4371 "leftFringe", "LeftFringe", RES_TYPE_NUMBER);
4372 x_default_parameter (f, parameters, Qright_fringe, Qnil,
4373 "rightFringe", "RightFringe", RES_TYPE_NUMBER);
4374
4375
4376 /* Init faces before x_default_parameter is called for scroll-bar
4377 parameters because that function calls x_set_scroll_bar_width,
4378 which calls change_frame_size, which calls Fset_window_buffer,
4379 which runs hooks, which call Fvertical_motion. At the end, we
4380 end up in init_iterator with a null face cache, which should not
4381 happen. */
4382 init_frame_faces (f);
4383
4384 /* The X resources controlling the menu-bar and tool-bar are
4385 processed specially at startup, and reflected in the mode
4386 variables; ignore them here. */
4387 x_default_parameter (f, parameters, Qmenu_bar_lines,
4388 NILP (Vmenu_bar_mode)
4389 ? make_number (0) : make_number (1),
4390 NULL, NULL, RES_TYPE_NUMBER);
4391 x_default_parameter (f, parameters, Qtool_bar_lines,
4392 NILP (Vtool_bar_mode)
4393 ? make_number (0) : make_number (1),
4394 NULL, NULL, RES_TYPE_NUMBER);
4395
4396 x_default_parameter (f, parameters, Qbuffer_predicate, Qnil,
4397 "bufferPredicate", "BufferPredicate", RES_TYPE_SYMBOL);
4398 x_default_parameter (f, parameters, Qtitle, Qnil,
4399 "title", "Title", RES_TYPE_STRING);
4400 x_default_parameter (f, parameters, Qfullscreen, Qnil,
4401 "fullscreen", "Fullscreen", RES_TYPE_SYMBOL);
4402
4403 f->output_data.w32->dwStyle = WS_OVERLAPPEDWINDOW;
4404 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
4405
4406 f->output_data.w32->text_cursor = w32_load_cursor (IDC_IBEAM);
4407 f->output_data.w32->nontext_cursor = w32_load_cursor (IDC_ARROW);
4408 f->output_data.w32->modeline_cursor = w32_load_cursor (IDC_ARROW);
4409 f->output_data.w32->hand_cursor = w32_load_cursor (IDC_HAND);
4410 f->output_data.w32->hourglass_cursor = w32_load_cursor (IDC_WAIT);
4411 f->output_data.w32->horizontal_drag_cursor = w32_load_cursor (IDC_SIZEWE);
4412
4413 f->output_data.w32->current_cursor = f->output_data.w32->nontext_cursor;
4414
4415 window_prompting = x_figure_window_size (f, parameters, 1);
4416
4417 tem = x_get_arg (dpyinfo, parameters, Qunsplittable, 0, 0, RES_TYPE_BOOLEAN);
4418 f->no_split = minibuffer_only || EQ (tem, Qt);
4419
4420 w32_window (f, window_prompting, minibuffer_only);
4421 x_icon (f, parameters);
4422
4423 x_make_gc (f);
4424
4425 /* Now consider the frame official. */
4426 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
4427 Vframe_list = Fcons (frame, Vframe_list);
4428
4429 /* We need to do this after creating the window, so that the
4430 icon-creation functions can say whose icon they're describing. */
4431 x_default_parameter (f, parameters, Qicon_type, Qnil,
4432 "bitmapIcon", "BitmapIcon", RES_TYPE_SYMBOL);
4433
4434 x_default_parameter (f, parameters, Qauto_raise, Qnil,
4435 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4436 x_default_parameter (f, parameters, Qauto_lower, Qnil,
4437 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
4438 x_default_parameter (f, parameters, Qcursor_type, Qbox,
4439 "cursorType", "CursorType", RES_TYPE_SYMBOL);
4440 x_default_parameter (f, parameters, Qscroll_bar_width, Qnil,
4441 "scrollBarWidth", "ScrollBarWidth", RES_TYPE_NUMBER);
4442 x_default_parameter (f, parameters, Qalpha, Qnil,
4443 "alpha", "Alpha", RES_TYPE_NUMBER);
4444
4445 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
4446 Change will not be effected unless different from the current
4447 FRAME_LINES (f). */
4448 width = FRAME_COLS (f);
4449 height = FRAME_LINES (f);
4450
4451 FRAME_LINES (f) = 0;
4452 SET_FRAME_COLS (f, 0);
4453 change_frame_size (f, height, width, 1, 0, 0);
4454
4455 /* Tell the server what size and position, etc, we want, and how
4456 badly we want them. This should be done after we have the menu
4457 bar so that its size can be taken into account. */
4458 BLOCK_INPUT;
4459 x_wm_set_size_hint (f, window_prompting, 0);
4460 UNBLOCK_INPUT;
4461
4462 /* Make the window appear on the frame and enable display, unless
4463 the caller says not to. However, with explicit parent, Emacs
4464 cannot control visibility, so don't try. */
4465 if (! f->output_data.w32->explicit_parent)
4466 {
4467 Lisp_Object visibility;
4468
4469 visibility = x_get_arg (dpyinfo, parameters, Qvisibility, 0, 0, RES_TYPE_SYMBOL);
4470 if (EQ (visibility, Qunbound))
4471 visibility = Qt;
4472
4473 if (EQ (visibility, Qicon))
4474 x_iconify_frame (f);
4475 else if (! NILP (visibility))
4476 x_make_frame_visible (f);
4477 else
4478 /* Must have been Qnil. */
4479 ;
4480 }
4481
4482 /* Initialize `default-minibuffer-frame' in case this is the first
4483 frame on this terminal. */
4484 if (FRAME_HAS_MINIBUF_P (f)
4485 && (!FRAMEP (kb->Vdefault_minibuffer_frame)
4486 || !FRAME_LIVE_P (XFRAME (kb->Vdefault_minibuffer_frame))))
4487 kb->Vdefault_minibuffer_frame = frame;
4488
4489 /* All remaining specified parameters, which have not been "used"
4490 by x_get_arg and friends, now go in the misc. alist of the frame. */
4491 for (tem = parameters; CONSP (tem); tem = XCDR (tem))
4492 if (CONSP (XCAR (tem)) && !NILP (XCAR (XCAR (tem))))
4493 f->param_alist = Fcons (XCAR (tem), f->param_alist);
4494
4495 UNGCPRO;
4496
4497 /* Make sure windows on this frame appear in calls to next-window
4498 and similar functions. */
4499 Vwindow_list = Qnil;
4500
4501 return unbind_to (count, frame);
4502 }
4503
4504 /* FRAME is used only to get a handle on the X display. We don't pass the
4505 display info directly because we're called from frame.c, which doesn't
4506 know about that structure. */
4507 Lisp_Object
4508 x_get_focus_frame (struct frame *frame)
4509 {
4510 struct w32_display_info *dpyinfo = FRAME_W32_DISPLAY_INFO (frame);
4511 Lisp_Object xfocus;
4512 if (! dpyinfo->w32_focus_frame)
4513 return Qnil;
4514
4515 XSETFRAME (xfocus, dpyinfo->w32_focus_frame);
4516 return xfocus;
4517 }
4518
4519 DEFUN ("x-focus-frame", Fx_focus_frame, Sx_focus_frame, 1, 1, 0,
4520 doc: /* Give FRAME input focus, raising to foreground if necessary. */)
4521 (Lisp_Object frame)
4522 {
4523 x_focus_on_frame (check_x_frame (frame));
4524 return Qnil;
4525 }
4526
4527 \f
4528 DEFUN ("xw-color-defined-p", Fxw_color_defined_p, Sxw_color_defined_p, 1, 2, 0,
4529 doc: /* Internal function called by `color-defined-p', which see. */)
4530 (Lisp_Object color, Lisp_Object frame)
4531 {
4532 XColor foo;
4533 FRAME_PTR f = check_x_frame (frame);
4534
4535 CHECK_STRING (color);
4536
4537 if (w32_defined_color (f, SDATA (color), &foo, 0))
4538 return Qt;
4539 else
4540 return Qnil;
4541 }
4542
4543 DEFUN ("xw-color-values", Fxw_color_values, Sxw_color_values, 1, 2, 0,
4544 doc: /* Internal function called by `color-values', which see. */)
4545 (Lisp_Object color, Lisp_Object frame)
4546 {
4547 XColor foo;
4548 FRAME_PTR f = check_x_frame (frame);
4549
4550 CHECK_STRING (color);
4551
4552 if (w32_defined_color (f, SDATA (color), &foo, 0))
4553 return list3 (make_number ((GetRValue (foo.pixel) << 8)
4554 | GetRValue (foo.pixel)),
4555 make_number ((GetGValue (foo.pixel) << 8)
4556 | GetGValue (foo.pixel)),
4557 make_number ((GetBValue (foo.pixel) << 8)
4558 | GetBValue (foo.pixel)));
4559 else
4560 return Qnil;
4561 }
4562
4563 DEFUN ("xw-display-color-p", Fxw_display_color_p, Sxw_display_color_p, 0, 1, 0,
4564 doc: /* Internal function called by `display-color-p', which see. */)
4565 (Lisp_Object display)
4566 {
4567 struct w32_display_info *dpyinfo = check_x_display_info (display);
4568
4569 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 2)
4570 return Qnil;
4571
4572 return Qt;
4573 }
4574
4575 DEFUN ("x-display-grayscale-p", Fx_display_grayscale_p,
4576 Sx_display_grayscale_p, 0, 1, 0,
4577 doc: /* Return t if DISPLAY supports shades of gray.
4578 Note that color displays do support shades of gray.
4579 The optional argument DISPLAY specifies which display to ask about.
4580 DISPLAY should be either a frame or a display name (a string).
4581 If omitted or nil, that stands for the selected frame's display. */)
4582 (Lisp_Object display)
4583 {
4584 struct w32_display_info *dpyinfo = check_x_display_info (display);
4585
4586 if ((dpyinfo->n_planes * dpyinfo->n_cbits) <= 1)
4587 return Qnil;
4588
4589 return Qt;
4590 }
4591
4592 DEFUN ("x-display-pixel-width", Fx_display_pixel_width,
4593 Sx_display_pixel_width, 0, 1, 0,
4594 doc: /* Return the width in pixels of DISPLAY.
4595 The optional argument DISPLAY specifies which display to ask about.
4596 DISPLAY should be either a frame or a display name (a string).
4597 If omitted or nil, that stands for the selected frame's display. */)
4598 (Lisp_Object display)
4599 {
4600 struct w32_display_info *dpyinfo = check_x_display_info (display);
4601
4602 return make_number (x_display_pixel_width (dpyinfo));
4603 }
4604
4605 DEFUN ("x-display-pixel-height", Fx_display_pixel_height,
4606 Sx_display_pixel_height, 0, 1, 0,
4607 doc: /* Return the height in pixels of DISPLAY.
4608 The optional argument DISPLAY specifies which display to ask about.
4609 DISPLAY should be either a frame or a display name (a string).
4610 If omitted or nil, that stands for the selected frame's display. */)
4611 (Lisp_Object display)
4612 {
4613 struct w32_display_info *dpyinfo = check_x_display_info (display);
4614
4615 return make_number (x_display_pixel_height (dpyinfo));
4616 }
4617
4618 DEFUN ("x-display-planes", Fx_display_planes, Sx_display_planes,
4619 0, 1, 0,
4620 doc: /* Return the number of bitplanes of DISPLAY.
4621 The optional argument DISPLAY specifies which display to ask about.
4622 DISPLAY should be either a frame or a display name (a string).
4623 If omitted or nil, that stands for the selected frame's display. */)
4624 (Lisp_Object display)
4625 {
4626 struct w32_display_info *dpyinfo = check_x_display_info (display);
4627
4628 return make_number (dpyinfo->n_planes * dpyinfo->n_cbits);
4629 }
4630
4631 DEFUN ("x-display-color-cells", Fx_display_color_cells, Sx_display_color_cells,
4632 0, 1, 0,
4633 doc: /* Return the number of color cells of DISPLAY.
4634 The optional argument DISPLAY specifies which display to ask about.
4635 DISPLAY should be either a frame or a display name (a string).
4636 If omitted or nil, that stands for the selected frame's display. */)
4637 (Lisp_Object display)
4638 {
4639 struct w32_display_info *dpyinfo = check_x_display_info (display);
4640 HDC hdc;
4641 int cap;
4642
4643 hdc = GetDC (dpyinfo->root_window);
4644 if (dpyinfo->has_palette)
4645 cap = GetDeviceCaps (hdc, SIZEPALETTE);
4646 else
4647 cap = GetDeviceCaps (hdc, NUMCOLORS);
4648
4649 /* We force 24+ bit depths to 24-bit, both to prevent an overflow
4650 and because probably is more meaningful on Windows anyway */
4651 if (cap < 0)
4652 cap = 1 << min (dpyinfo->n_planes * dpyinfo->n_cbits, 24);
4653
4654 ReleaseDC (dpyinfo->root_window, hdc);
4655
4656 return make_number (cap);
4657 }
4658
4659 DEFUN ("x-server-max-request-size", Fx_server_max_request_size,
4660 Sx_server_max_request_size,
4661 0, 1, 0,
4662 doc: /* Return the maximum request size of the server of DISPLAY.
4663 The optional argument DISPLAY specifies which display to ask about.
4664 DISPLAY should be either a frame or a display name (a string).
4665 If omitted or nil, that stands for the selected frame's display. */)
4666 (Lisp_Object display)
4667 {
4668 struct w32_display_info *dpyinfo = check_x_display_info (display);
4669
4670 return make_number (1);
4671 }
4672
4673 DEFUN ("x-server-vendor", Fx_server_vendor, Sx_server_vendor, 0, 1, 0,
4674 doc: /* Return the "vendor ID" string of the W32 system (Microsoft).
4675 The optional argument DISPLAY specifies which display to ask about.
4676 DISPLAY should be either a frame or a display name (a string).
4677 If omitted or nil, that stands for the selected frame's display. */)
4678 (Lisp_Object display)
4679 {
4680 return build_string ("Microsoft Corp.");
4681 }
4682
4683 DEFUN ("x-server-version", Fx_server_version, Sx_server_version, 0, 1, 0,
4684 doc: /* Return the version numbers of the server of DISPLAY.
4685 The value is a list of three integers: the major and minor
4686 version numbers of the X Protocol in use, and the distributor-specific
4687 release number. See also the function `x-server-vendor'.
4688
4689 The optional argument DISPLAY specifies which display to ask about.
4690 DISPLAY should be either a frame or a display name (a string).
4691 If omitted or nil, that stands for the selected frame's display. */)
4692 (Lisp_Object display)
4693 {
4694 return Fcons (make_number (w32_major_version),
4695 Fcons (make_number (w32_minor_version),
4696 Fcons (make_number (w32_build_number), Qnil)));
4697 }
4698
4699 DEFUN ("x-display-screens", Fx_display_screens, Sx_display_screens, 0, 1, 0,
4700 doc: /* Return the number of screens on the server of DISPLAY.
4701 The optional argument DISPLAY specifies which display to ask about.
4702 DISPLAY should be either a frame or a display name (a string).
4703 If omitted or nil, that stands for the selected frame's display. */)
4704 (Lisp_Object display)
4705 {
4706 return make_number (1);
4707 }
4708
4709 DEFUN ("x-display-mm-height", Fx_display_mm_height,
4710 Sx_display_mm_height, 0, 1, 0,
4711 doc: /* Return the height in millimeters of DISPLAY.
4712 The optional argument DISPLAY specifies which display to ask about.
4713 DISPLAY should be either a frame or a display name (a string).
4714 If omitted or nil, that stands for the selected frame's display. */)
4715 (Lisp_Object display)
4716 {
4717 struct w32_display_info *dpyinfo = check_x_display_info (display);
4718 HDC hdc;
4719 int cap;
4720
4721 hdc = GetDC (dpyinfo->root_window);
4722
4723 cap = GetDeviceCaps (hdc, VERTSIZE);
4724
4725 ReleaseDC (dpyinfo->root_window, hdc);
4726
4727 return make_number (cap);
4728 }
4729
4730 DEFUN ("x-display-mm-width", Fx_display_mm_width, Sx_display_mm_width, 0, 1, 0,
4731 doc: /* Return the width in millimeters of DISPLAY.
4732 The optional argument DISPLAY specifies which display to ask about.
4733 DISPLAY should be either a frame or a display name (a string).
4734 If omitted or nil, that stands for the selected frame's display. */)
4735 (Lisp_Object display)
4736 {
4737 struct w32_display_info *dpyinfo = check_x_display_info (display);
4738
4739 HDC hdc;
4740 int cap;
4741
4742 hdc = GetDC (dpyinfo->root_window);
4743
4744 cap = GetDeviceCaps (hdc, HORZSIZE);
4745
4746 ReleaseDC (dpyinfo->root_window, hdc);
4747
4748 return make_number (cap);
4749 }
4750
4751 DEFUN ("x-display-backing-store", Fx_display_backing_store,
4752 Sx_display_backing_store, 0, 1, 0,
4753 doc: /* Return an indication of whether DISPLAY does backing store.
4754 The value may be `always', `when-mapped', or `not-useful'.
4755 The optional argument DISPLAY specifies which display to ask about.
4756 DISPLAY should be either a frame or a display name (a string).
4757 If omitted or nil, that stands for the selected frame's display. */)
4758 (Lisp_Object display)
4759 {
4760 return intern ("not-useful");
4761 }
4762
4763 DEFUN ("x-display-visual-class", Fx_display_visual_class,
4764 Sx_display_visual_class, 0, 1, 0,
4765 doc: /* Return the visual class of DISPLAY.
4766 The value is one of the symbols `static-gray', `gray-scale',
4767 `static-color', `pseudo-color', `true-color', or `direct-color'.
4768
4769 The optional argument DISPLAY specifies which display to ask about.
4770 DISPLAY should be either a frame or a display name (a string).
4771 If omitted or nil, that stands for the selected frame's display. */)
4772 (Lisp_Object display)
4773 {
4774 struct w32_display_info *dpyinfo = check_x_display_info (display);
4775 Lisp_Object result = Qnil;
4776
4777 if (dpyinfo->has_palette)
4778 result = intern ("pseudo-color");
4779 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 1)
4780 result = intern ("static-grey");
4781 else if (dpyinfo->n_planes * dpyinfo->n_cbits == 4)
4782 result = intern ("static-color");
4783 else if (dpyinfo->n_planes * dpyinfo->n_cbits > 8)
4784 result = intern ("true-color");
4785
4786 return result;
4787 }
4788
4789 DEFUN ("x-display-save-under", Fx_display_save_under,
4790 Sx_display_save_under, 0, 1, 0,
4791 doc: /* Return t if DISPLAY supports the save-under feature.
4792 The optional argument DISPLAY specifies which display to ask about.
4793 DISPLAY should be either a frame or a display name (a string).
4794 If omitted or nil, that stands for the selected frame's display. */)
4795 (Lisp_Object display)
4796 {
4797 return Qnil;
4798 }
4799 \f
4800 int
4801 x_pixel_width (register struct frame *f)
4802 {
4803 return FRAME_PIXEL_WIDTH (f);
4804 }
4805
4806 int
4807 x_pixel_height (register struct frame *f)
4808 {
4809 return FRAME_PIXEL_HEIGHT (f);
4810 }
4811
4812 int
4813 x_char_width (register struct frame *f)
4814 {
4815 return FRAME_COLUMN_WIDTH (f);
4816 }
4817
4818 int
4819 x_char_height (register struct frame *f)
4820 {
4821 return FRAME_LINE_HEIGHT (f);
4822 }
4823
4824 int
4825 x_screen_planes (register struct frame *f)
4826 {
4827 return FRAME_W32_DISPLAY_INFO (f)->n_planes;
4828 }
4829 \f
4830 /* Return the display structure for the display named NAME.
4831 Open a new connection if necessary. */
4832
4833 struct w32_display_info *
4834 x_display_info_for_name (Lisp_Object name)
4835 {
4836 Lisp_Object names;
4837 struct w32_display_info *dpyinfo;
4838
4839 CHECK_STRING (name);
4840
4841 for (dpyinfo = &one_w32_display_info, names = w32_display_name_list;
4842 dpyinfo;
4843 dpyinfo = dpyinfo->next, names = XCDR (names))
4844 {
4845 Lisp_Object tem;
4846 tem = Fstring_equal (XCAR (XCAR (names)), name);
4847 if (!NILP (tem))
4848 return dpyinfo;
4849 }
4850
4851 /* Use this general default value to start with. */
4852 Vx_resource_name = Vinvocation_name;
4853
4854 validate_x_resource_name ();
4855
4856 dpyinfo = w32_term_init (name, (unsigned char *)0,
4857 (char *) SDATA (Vx_resource_name));
4858
4859 if (dpyinfo == 0)
4860 error ("Cannot connect to server %s", SDATA (name));
4861
4862 w32_in_use = 1;
4863 XSETFASTINT (Vwindow_system_version, w32_major_version);
4864
4865 return dpyinfo;
4866 }
4867
4868 DEFUN ("x-open-connection", Fx_open_connection, Sx_open_connection,
4869 1, 3, 0, doc: /* Open a connection to a server.
4870 DISPLAY is the name of the display to connect to.
4871 Optional second arg XRM-STRING is a string of resources in xrdb format.
4872 If the optional third arg MUST-SUCCEED is non-nil,
4873 terminate Emacs if we can't open the connection. */)
4874 (Lisp_Object display, Lisp_Object xrm_string, Lisp_Object must_succeed)
4875 {
4876 unsigned char *xrm_option;
4877 struct w32_display_info *dpyinfo;
4878
4879 /* If initialization has already been done, return now to avoid
4880 overwriting critical parts of one_w32_display_info. */
4881 if (w32_in_use)
4882 return Qnil;
4883
4884 CHECK_STRING (display);
4885 if (! NILP (xrm_string))
4886 CHECK_STRING (xrm_string);
4887
4888 #if 0
4889 if (! EQ (Vwindow_system, intern ("w32")))
4890 error ("Not using Microsoft Windows");
4891 #endif
4892
4893 /* Allow color mapping to be defined externally; first look in user's
4894 HOME directory, then in Emacs etc dir for a file called rgb.txt. */
4895 {
4896 Lisp_Object color_file;
4897 struct gcpro gcpro1;
4898
4899 color_file = build_string ("~/rgb.txt");
4900
4901 GCPRO1 (color_file);
4902
4903 if (NILP (Ffile_readable_p (color_file)))
4904 color_file =
4905 Fexpand_file_name (build_string ("rgb.txt"),
4906 Fsymbol_value (intern ("data-directory")));
4907
4908 Vw32_color_map = Fx_load_color_file (color_file);
4909
4910 UNGCPRO;
4911 }
4912 if (NILP (Vw32_color_map))
4913 Vw32_color_map = Fw32_default_color_map ();
4914
4915 /* Merge in system logical colors. */
4916 add_system_logical_colors_to_map (&Vw32_color_map);
4917
4918 if (! NILP (xrm_string))
4919 xrm_option = (unsigned char *) SDATA (xrm_string);
4920 else
4921 xrm_option = (unsigned char *) 0;
4922
4923 /* Use this general default value to start with. */
4924 /* First remove .exe suffix from invocation-name - it looks ugly. */
4925 {
4926 char basename[ MAX_PATH ], *str;
4927
4928 strcpy (basename, SDATA (Vinvocation_name));
4929 str = strrchr (basename, '.');
4930 if (str) *str = 0;
4931 Vinvocation_name = build_string (basename);
4932 }
4933 Vx_resource_name = Vinvocation_name;
4934
4935 validate_x_resource_name ();
4936
4937 /* This is what opens the connection and sets x_current_display.
4938 This also initializes many symbols, such as those used for input. */
4939 dpyinfo = w32_term_init (display, xrm_option,
4940 (char *) SDATA (Vx_resource_name));
4941
4942 if (dpyinfo == 0)
4943 {
4944 if (!NILP (must_succeed))
4945 fatal ("Cannot connect to server %s.\n",
4946 SDATA (display));
4947 else
4948 error ("Cannot connect to server %s", SDATA (display));
4949 }
4950
4951 w32_in_use = 1;
4952
4953 XSETFASTINT (Vwindow_system_version, w32_major_version);
4954 return Qnil;
4955 }
4956
4957 DEFUN ("x-close-connection", Fx_close_connection,
4958 Sx_close_connection, 1, 1, 0,
4959 doc: /* Close the connection to DISPLAY's server.
4960 For DISPLAY, specify either a frame or a display name (a string).
4961 If DISPLAY is nil, that stands for the selected frame's display. */)
4962 (Lisp_Object display)
4963 {
4964 struct w32_display_info *dpyinfo = check_x_display_info (display);
4965 int i;
4966
4967 if (dpyinfo->reference_count > 0)
4968 error ("Display still has frames on it");
4969
4970 BLOCK_INPUT;
4971 x_destroy_all_bitmaps (dpyinfo);
4972
4973 x_delete_display (dpyinfo);
4974 UNBLOCK_INPUT;
4975
4976 return Qnil;
4977 }
4978
4979 DEFUN ("x-display-list", Fx_display_list, Sx_display_list, 0, 0, 0,
4980 doc: /* Return the list of display names that Emacs has connections to. */)
4981 (void)
4982 {
4983 Lisp_Object tail, result;
4984
4985 result = Qnil;
4986 for (tail = w32_display_name_list; CONSP (tail); tail = XCDR (tail))
4987 result = Fcons (XCAR (XCAR (tail)), result);
4988
4989 return result;
4990 }
4991
4992 DEFUN ("x-synchronize", Fx_synchronize, Sx_synchronize, 1, 2, 0,
4993 doc: /* This is a noop on W32 systems. */)
4994 (Lisp_Object on, Lisp_Object display)
4995 {
4996 return Qnil;
4997 }
4998
4999
5000 \f
5001 /***********************************************************************
5002 Window properties
5003 ***********************************************************************/
5004
5005 DEFUN ("x-change-window-property", Fx_change_window_property,
5006 Sx_change_window_property, 2, 6, 0,
5007 doc: /* Change window property PROP to VALUE on the X window of FRAME.
5008 VALUE may be a string or a list of conses, numbers and/or strings.
5009 If an element in the list is a string, it is converted to
5010 an Atom and the value of the Atom is used. If an element is a cons,
5011 it is converted to a 32 bit number where the car is the 16 top bits and the
5012 cdr is the lower 16 bits.
5013 FRAME nil or omitted means use the selected frame.
5014 If TYPE is given and non-nil, it is the name of the type of VALUE.
5015 If TYPE is not given or nil, the type is STRING.
5016 FORMAT gives the size in bits of each element if VALUE is a list.
5017 It must be one of 8, 16 or 32.
5018 If VALUE is a string or FORMAT is nil or not given, FORMAT defaults to 8.
5019 If OUTER_P is non-nil, the property is changed for the outer X window of
5020 FRAME. Default is to change on the edit X window.
5021
5022 Value is VALUE. */)
5023 (Lisp_Object prop, Lisp_Object value, Lisp_Object frame, Lisp_Object type, Lisp_Object format, Lisp_Object outer_p)
5024 {
5025 #if 0 /* TODO : port window properties to W32 */
5026 struct frame *f = check_x_frame (frame);
5027 Atom prop_atom;
5028
5029 CHECK_STRING (prop);
5030 CHECK_STRING (value);
5031
5032 BLOCK_INPUT;
5033 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
5034 XChangeProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
5035 prop_atom, XA_STRING, 8, PropModeReplace,
5036 SDATA (value), SCHARS (value));
5037
5038 /* Make sure the property is set when we return. */
5039 XFlush (FRAME_W32_DISPLAY (f));
5040 UNBLOCK_INPUT;
5041
5042 #endif /* TODO */
5043
5044 return value;
5045 }
5046
5047
5048 DEFUN ("x-delete-window-property", Fx_delete_window_property,
5049 Sx_delete_window_property, 1, 2, 0,
5050 doc: /* Remove window property PROP from X window of FRAME.
5051 FRAME nil or omitted means use the selected frame. Value is PROP. */)
5052 (Lisp_Object prop, Lisp_Object frame)
5053 {
5054 #if 0 /* TODO : port window properties to W32 */
5055
5056 struct frame *f = check_x_frame (frame);
5057 Atom prop_atom;
5058
5059 CHECK_STRING (prop);
5060 BLOCK_INPUT;
5061 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
5062 XDeleteProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f), prop_atom);
5063
5064 /* Make sure the property is removed when we return. */
5065 XFlush (FRAME_W32_DISPLAY (f));
5066 UNBLOCK_INPUT;
5067 #endif /* TODO */
5068
5069 return prop;
5070 }
5071
5072
5073 DEFUN ("x-window-property", Fx_window_property, Sx_window_property,
5074 1, 2, 0,
5075 doc: /* Value is the value of window property PROP on FRAME.
5076 If FRAME is nil or omitted, use the selected frame. Value is nil
5077 if FRAME hasn't a property with name PROP or if PROP has no string
5078 value. */)
5079 (Lisp_Object prop, Lisp_Object frame)
5080 {
5081 #if 0 /* TODO : port window properties to W32 */
5082
5083 struct frame *f = check_x_frame (frame);
5084 Atom prop_atom;
5085 int rc;
5086 Lisp_Object prop_value = Qnil;
5087 char *tmp_data = NULL;
5088 Atom actual_type;
5089 int actual_format;
5090 unsigned long actual_size, bytes_remaining;
5091
5092 CHECK_STRING (prop);
5093 BLOCK_INPUT;
5094 prop_atom = XInternAtom (FRAME_W32_DISPLAY (f), SDATA (prop), False);
5095 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
5096 prop_atom, 0, 0, False, XA_STRING,
5097 &actual_type, &actual_format, &actual_size,
5098 &bytes_remaining, (unsigned char **) &tmp_data);
5099 if (rc == Success)
5100 {
5101 int size = bytes_remaining;
5102
5103 XFree (tmp_data);
5104 tmp_data = NULL;
5105
5106 rc = XGetWindowProperty (FRAME_W32_DISPLAY (f), FRAME_W32_WINDOW (f),
5107 prop_atom, 0, bytes_remaining,
5108 False, XA_STRING,
5109 &actual_type, &actual_format,
5110 &actual_size, &bytes_remaining,
5111 (unsigned char **) &tmp_data);
5112 if (rc == Success)
5113 prop_value = make_string (tmp_data, size);
5114
5115 XFree (tmp_data);
5116 }
5117
5118 UNBLOCK_INPUT;
5119
5120 return prop_value;
5121
5122 #endif /* TODO */
5123 return Qnil;
5124 }
5125
5126
5127 \f
5128 /***********************************************************************
5129 Busy cursor
5130 ***********************************************************************/
5131
5132 /* Default number of seconds to wait before displaying an hourglass
5133 cursor. Duplicated from xdisp.c, but cannot use the version there
5134 due to lack of atimers on w32. */
5135 #define DEFAULT_HOURGLASS_DELAY 1
5136 extern Lisp_Object Vhourglass_delay;
5137
5138 /* Return non-zero if houglass timer has been started or hourglass is shown. */
5139 /* PENDING: if W32 can use atimers (atimer.[hc]) then the common impl in
5140 xdisp.c could be used. */
5141
5142 int
5143 hourglass_started (void)
5144 {
5145 return hourglass_shown_p || hourglass_timer;
5146 }
5147
5148 /* Cancel a currently active hourglass timer, and start a new one. */
5149
5150 void
5151 start_hourglass (void)
5152 {
5153 DWORD delay;
5154 int secs, msecs = 0;
5155 struct frame * f = SELECTED_FRAME ();
5156
5157 /* No cursors on non GUI frames. */
5158 if (!FRAME_W32_P (f))
5159 return;
5160
5161 cancel_hourglass ();
5162
5163 if (INTEGERP (Vhourglass_delay)
5164 && XINT (Vhourglass_delay) > 0)
5165 secs = XFASTINT (Vhourglass_delay);
5166 else if (FLOATP (Vhourglass_delay)
5167 && XFLOAT_DATA (Vhourglass_delay) > 0)
5168 {
5169 Lisp_Object tem;
5170 tem = Ftruncate (Vhourglass_delay, Qnil);
5171 secs = XFASTINT (tem);
5172 msecs = (XFLOAT_DATA (Vhourglass_delay) - secs) * 1000;
5173 }
5174 else
5175 secs = DEFAULT_HOURGLASS_DELAY;
5176
5177 delay = secs * 1000 + msecs;
5178 hourglass_hwnd = FRAME_W32_WINDOW (f);
5179 hourglass_timer = SetTimer (hourglass_hwnd, HOURGLASS_ID, delay, NULL);
5180 }
5181
5182
5183 /* Cancel the hourglass cursor timer if active, hide an hourglass
5184 cursor if shown. */
5185
5186 void
5187 cancel_hourglass (void)
5188 {
5189 if (hourglass_timer)
5190 {
5191 KillTimer (hourglass_hwnd, hourglass_timer);
5192 hourglass_timer = 0;
5193 }
5194
5195 if (hourglass_shown_p)
5196 w32_hide_hourglass ();
5197 }
5198
5199
5200 /* Timer function of hourglass_timer.
5201
5202 Display an hourglass cursor. Set the hourglass_p flag in display info
5203 to indicate that an hourglass cursor is shown. */
5204
5205 static void
5206 w32_show_hourglass (struct frame *f)
5207 {
5208 if (!hourglass_shown_p)
5209 {
5210 f->output_data.w32->hourglass_p = 1;
5211 if (!menubar_in_use && !current_popup_menu)
5212 SetCursor (f->output_data.w32->hourglass_cursor);
5213 hourglass_shown_p = 1;
5214 }
5215 }
5216
5217
5218 /* Hide the hourglass cursor on all frames, if it is currently shown. */
5219
5220 static void
5221 w32_hide_hourglass (void)
5222 {
5223 if (hourglass_shown_p)
5224 {
5225 struct frame *f = x_window_to_frame (&one_w32_display_info,
5226 hourglass_hwnd);
5227 if (f)
5228 f->output_data.w32->hourglass_p = 0;
5229 else
5230 /* If frame was deleted, restore to selected frame's cursor. */
5231 f = SELECTED_FRAME ();
5232
5233 if (FRAME_W32_P (f))
5234 SetCursor (f->output_data.w32->current_cursor);
5235 else
5236 /* No cursors on non GUI frames - restore to stock arrow cursor. */
5237 SetCursor (w32_load_cursor (IDC_ARROW));
5238
5239 hourglass_shown_p = 0;
5240 }
5241 }
5242
5243
5244 \f
5245 /***********************************************************************
5246 Tool tips
5247 ***********************************************************************/
5248
5249 static Lisp_Object x_create_tip_frame (struct w32_display_info *,
5250 Lisp_Object, Lisp_Object);
5251 static void compute_tip_xy (struct frame *, Lisp_Object, Lisp_Object,
5252 Lisp_Object, int, int, int *, int *);
5253
5254 /* The frame of a currently visible tooltip. */
5255
5256 Lisp_Object tip_frame;
5257
5258 /* If non-nil, a timer started that hides the last tooltip when it
5259 fires. */
5260
5261 Lisp_Object tip_timer;
5262 Window tip_window;
5263
5264 /* If non-nil, a vector of 3 elements containing the last args
5265 with which x-show-tip was called. See there. */
5266
5267 Lisp_Object last_show_tip_args;
5268
5269 /* Maximum size for tooltips; a cons (COLUMNS . ROWS). */
5270
5271 Lisp_Object Vx_max_tooltip_size;
5272
5273
5274 static Lisp_Object
5275 unwind_create_tip_frame (Lisp_Object frame)
5276 {
5277 Lisp_Object deleted;
5278
5279 deleted = unwind_create_frame (frame);
5280 if (EQ (deleted, Qt))
5281 {
5282 tip_window = NULL;
5283 tip_frame = Qnil;
5284 }
5285
5286 return deleted;
5287 }
5288
5289
5290 /* Create a frame for a tooltip on the display described by DPYINFO.
5291 PARMS is a list of frame parameters. TEXT is the string to
5292 display in the tip frame. Value is the frame.
5293
5294 Note that functions called here, esp. x_default_parameter can
5295 signal errors, for instance when a specified color name is
5296 undefined. We have to make sure that we're in a consistent state
5297 when this happens. */
5298
5299 static Lisp_Object
5300 x_create_tip_frame (struct w32_display_info *dpyinfo,
5301 Lisp_Object parms, Lisp_Object text)
5302 {
5303 struct frame *f;
5304 Lisp_Object frame, tem;
5305 Lisp_Object name;
5306 long window_prompting = 0;
5307 int width, height;
5308 int count = SPECPDL_INDEX ();
5309 struct gcpro gcpro1, gcpro2, gcpro3;
5310 struct kboard *kb;
5311 int face_change_count_before = face_change_count;
5312 Lisp_Object buffer;
5313 struct buffer *old_buffer;
5314
5315 check_w32 ();
5316
5317 /* Use this general default value to start with until we know if
5318 this frame has a specified name. */
5319 Vx_resource_name = Vinvocation_name;
5320
5321 kb = dpyinfo->terminal->kboard;
5322
5323 /* The calls to x_get_arg remove elements from PARMS, so copy it to
5324 avoid destructive changes behind our caller's back. */
5325 parms = Fcopy_alist (parms);
5326
5327 /* Get the name of the frame to use for resource lookup. */
5328 name = x_get_arg (dpyinfo, parms, Qname, "name", "Name", RES_TYPE_STRING);
5329 if (!STRINGP (name)
5330 && !EQ (name, Qunbound)
5331 && !NILP (name))
5332 error ("Invalid frame name--not a string or nil");
5333 Vx_resource_name = name;
5334
5335 frame = Qnil;
5336 GCPRO3 (parms, name, frame);
5337 /* Make a frame without minibuffer nor mode-line. */
5338 f = make_frame (0);
5339 f->wants_modeline = 0;
5340 XSETFRAME (frame, f);
5341
5342 buffer = Fget_buffer_create (build_string (" *tip*"));
5343 Fset_window_buffer (FRAME_ROOT_WINDOW (f), buffer, Qnil);
5344 old_buffer = current_buffer;
5345 set_buffer_internal_1 (XBUFFER (buffer));
5346 current_buffer->truncate_lines = Qnil;
5347 specbind (Qinhibit_read_only, Qt);
5348 specbind (Qinhibit_modification_hooks, Qt);
5349 Ferase_buffer ();
5350 Finsert (1, &text);
5351 set_buffer_internal_1 (old_buffer);
5352
5353 FRAME_CAN_HAVE_SCROLL_BARS (f) = 0;
5354 record_unwind_protect (unwind_create_tip_frame, frame);
5355
5356 /* By setting the output method, we're essentially saying that
5357 the frame is live, as per FRAME_LIVE_P. If we get a signal
5358 from this point on, x_destroy_window might screw up reference
5359 counts etc. */
5360 f->terminal = dpyinfo->terminal;
5361 f->terminal->reference_count++;
5362 f->output_method = output_w32;
5363 f->output_data.w32 =
5364 (struct w32_output *) xmalloc (sizeof (struct w32_output));
5365 memset (f->output_data.w32, 0, sizeof (struct w32_output));
5366
5367 FRAME_FONTSET (f) = -1;
5368 f->icon_name = Qnil;
5369
5370 #if GLYPH_DEBUG
5371 image_cache_refcount = FRAME_IMAGE_CACHE (f)->refcount;
5372 dpyinfo_refcount = dpyinfo->reference_count;
5373 #endif /* GLYPH_DEBUG */
5374 FRAME_KBOARD (f) = kb;
5375 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5376 f->output_data.w32->explicit_parent = 0;
5377
5378 /* Set the name; the functions to which we pass f expect the name to
5379 be set. */
5380 if (EQ (name, Qunbound) || NILP (name))
5381 {
5382 f->name = build_string (dpyinfo->w32_id_name);
5383 f->explicit_name = 0;
5384 }
5385 else
5386 {
5387 f->name = name;
5388 f->explicit_name = 1;
5389 /* use the frame's title when getting resources for this frame. */
5390 specbind (Qx_resource_name, name);
5391 }
5392
5393 f->resx = dpyinfo->resx;
5394 f->resy = dpyinfo->resy;
5395
5396 if (uniscribe_available)
5397 register_font_driver (&uniscribe_font_driver, f);
5398 register_font_driver (&w32font_driver, f);
5399
5400 x_default_parameter (f, parms, Qfont_backend, Qnil,
5401 "fontBackend", "FontBackend", RES_TYPE_STRING);
5402
5403 /* Extract the window parameters from the supplied values
5404 that are needed to determine window geometry. */
5405 x_default_font_parameter (f, parms);
5406
5407 x_default_parameter (f, parms, Qborder_width, make_number (2),
5408 "borderWidth", "BorderWidth", RES_TYPE_NUMBER);
5409 /* This defaults to 2 in order to match xterm. We recognize either
5410 internalBorderWidth or internalBorder (which is what xterm calls
5411 it). */
5412 if (NILP (Fassq (Qinternal_border_width, parms)))
5413 {
5414 Lisp_Object value;
5415
5416 value = x_get_arg (dpyinfo, parms, Qinternal_border_width,
5417 "internalBorder", "internalBorder", RES_TYPE_NUMBER);
5418 if (! EQ (value, Qunbound))
5419 parms = Fcons (Fcons (Qinternal_border_width, value),
5420 parms);
5421 }
5422 x_default_parameter (f, parms, Qinternal_border_width, make_number (1),
5423 "internalBorderWidth", "internalBorderWidth",
5424 RES_TYPE_NUMBER);
5425
5426 /* Also do the stuff which must be set before the window exists. */
5427 x_default_parameter (f, parms, Qforeground_color, build_string ("black"),
5428 "foreground", "Foreground", RES_TYPE_STRING);
5429 x_default_parameter (f, parms, Qbackground_color, build_string ("white"),
5430 "background", "Background", RES_TYPE_STRING);
5431 x_default_parameter (f, parms, Qmouse_color, build_string ("black"),
5432 "pointerColor", "Foreground", RES_TYPE_STRING);
5433 x_default_parameter (f, parms, Qcursor_color, build_string ("black"),
5434 "cursorColor", "Foreground", RES_TYPE_STRING);
5435 x_default_parameter (f, parms, Qborder_color, build_string ("black"),
5436 "borderColor", "BorderColor", RES_TYPE_STRING);
5437
5438 /* Init faces before x_default_parameter is called for scroll-bar
5439 parameters because that function calls x_set_scroll_bar_width,
5440 which calls change_frame_size, which calls Fset_window_buffer,
5441 which runs hooks, which call Fvertical_motion. At the end, we
5442 end up in init_iterator with a null face cache, which should not
5443 happen. */
5444 init_frame_faces (f);
5445
5446 f->output_data.w32->dwStyle = WS_BORDER | WS_POPUP | WS_DISABLED;
5447 f->output_data.w32->parent_desc = FRAME_W32_DISPLAY_INFO (f)->root_window;
5448
5449 window_prompting = x_figure_window_size (f, parms, 0);
5450
5451 /* No fringes on tip frame. */
5452 f->fringe_cols = 0;
5453 f->left_fringe_width = 0;
5454 f->right_fringe_width = 0;
5455
5456 BLOCK_INPUT;
5457 my_create_tip_window (f);
5458 UNBLOCK_INPUT;
5459
5460 x_make_gc (f);
5461
5462 x_default_parameter (f, parms, Qauto_raise, Qnil,
5463 "autoRaise", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5464 x_default_parameter (f, parms, Qauto_lower, Qnil,
5465 "autoLower", "AutoRaiseLower", RES_TYPE_BOOLEAN);
5466 x_default_parameter (f, parms, Qcursor_type, Qbox,
5467 "cursorType", "CursorType", RES_TYPE_SYMBOL);
5468
5469 /* Dimensions, especially FRAME_LINES (f), must be done via change_frame_size.
5470 Change will not be effected unless different from the current
5471 FRAME_LINES (f). */
5472 width = FRAME_COLS (f);
5473 height = FRAME_LINES (f);
5474 FRAME_LINES (f) = 0;
5475 SET_FRAME_COLS (f, 0);
5476 change_frame_size (f, height, width, 1, 0, 0);
5477
5478 /* Add `tooltip' frame parameter's default value. */
5479 if (NILP (Fframe_parameter (frame, intern ("tooltip"))))
5480 Fmodify_frame_parameters (frame, Fcons (Fcons (intern ("tooltip"), Qt),
5481 Qnil));
5482
5483 /* Set up faces after all frame parameters are known. This call
5484 also merges in face attributes specified for new frames.
5485
5486 Frame parameters may be changed if .Xdefaults contains
5487 specifications for the default font. For example, if there is an
5488 `Emacs.default.attributeBackground: pink', the `background-color'
5489 attribute of the frame get's set, which let's the internal border
5490 of the tooltip frame appear in pink. Prevent this. */
5491 {
5492 Lisp_Object bg = Fframe_parameter (frame, Qbackground_color);
5493 Lisp_Object fg = Fframe_parameter (frame, Qforeground_color);
5494 Lisp_Object colors = Qnil;
5495
5496 /* Set tip_frame here, so that */
5497 tip_frame = frame;
5498 call2 (Qface_set_after_frame_default, frame, Qnil);
5499
5500 if (!EQ (bg, Fframe_parameter (frame, Qbackground_color)))
5501 colors = Fcons (Fcons (Qbackground_color, bg), colors);
5502 if (!EQ (fg, Fframe_parameter (frame, Qforeground_color)))
5503 colors = Fcons (Fcons (Qforeground_color, fg), colors);
5504
5505 if (!NILP (colors))
5506 Fmodify_frame_parameters (frame, colors);
5507 }
5508
5509 f->no_split = 1;
5510
5511 UNGCPRO;
5512
5513 /* It is now ok to make the frame official even if we get an error
5514 below. And the frame needs to be on Vframe_list or making it
5515 visible won't work. */
5516 Vframe_list = Fcons (frame, Vframe_list);
5517
5518 /* Now that the frame is official, it counts as a reference to
5519 its display. */
5520 FRAME_W32_DISPLAY_INFO (f)->reference_count++;
5521
5522 /* Setting attributes of faces of the tooltip frame from resources
5523 and similar will increment face_change_count, which leads to the
5524 clearing of all current matrices. Since this isn't necessary
5525 here, avoid it by resetting face_change_count to the value it
5526 had before we created the tip frame. */
5527 face_change_count = face_change_count_before;
5528
5529 /* Discard the unwind_protect. */
5530 return unbind_to (count, frame);
5531 }
5532
5533
5534 /* Compute where to display tip frame F. PARMS is the list of frame
5535 parameters for F. DX and DY are specified offsets from the current
5536 location of the mouse. WIDTH and HEIGHT are the width and height
5537 of the tooltip. Return coordinates relative to the root window of
5538 the display in *ROOT_X, and *ROOT_Y. */
5539
5540 static void
5541 compute_tip_xy (struct frame *f,
5542 Lisp_Object parms, Lisp_Object dx, Lisp_Object dy,
5543 int width, int height, int *root_x, int *root_y)
5544 {
5545 Lisp_Object left, top;
5546 int min_x, min_y, max_x, max_y;
5547
5548 /* User-specified position? */
5549 left = Fcdr (Fassq (Qleft, parms));
5550 top = Fcdr (Fassq (Qtop, parms));
5551
5552 /* Move the tooltip window where the mouse pointer is. Resize and
5553 show it. */
5554 if (!INTEGERP (left) || !INTEGERP (top))
5555 {
5556 POINT pt;
5557
5558 /* Default min and max values. */
5559 min_x = 0;
5560 min_y = 0;
5561 max_x = x_display_pixel_width (FRAME_W32_DISPLAY_INFO (f));
5562 max_y = x_display_pixel_height (FRAME_W32_DISPLAY_INFO (f));
5563
5564 BLOCK_INPUT;
5565 GetCursorPos (&pt);
5566 *root_x = pt.x;
5567 *root_y = pt.y;
5568 UNBLOCK_INPUT;
5569
5570 /* If multiple monitor support is available, constrain the tip onto
5571 the current monitor. This improves the above by allowing negative
5572 co-ordinates if monitor positions are such that they are valid, and
5573 snaps a tooltip onto a single monitor if we are close to the edge
5574 where it would otherwise flow onto the other monitor (or into
5575 nothingness if there is a gap in the overlap). */
5576 if (monitor_from_point_fn && get_monitor_info_fn)
5577 {
5578 struct MONITOR_INFO info;
5579 HMONITOR monitor
5580 = monitor_from_point_fn (pt, MONITOR_DEFAULT_TO_NEAREST);
5581 info.cbSize = sizeof (info);
5582
5583 if (get_monitor_info_fn (monitor, &info))
5584 {
5585 min_x = info.rcWork.left;
5586 min_y = info.rcWork.top;
5587 max_x = info.rcWork.right;
5588 max_y = info.rcWork.bottom;
5589 }
5590 }
5591 }
5592
5593 if (INTEGERP (top))
5594 *root_y = XINT (top);
5595 else if (*root_y + XINT (dy) <= min_y)
5596 *root_y = min_y; /* Can happen for negative dy */
5597 else if (*root_y + XINT (dy) + height <= max_y)
5598 /* It fits below the pointer */
5599 *root_y += XINT (dy);
5600 else if (height + XINT (dy) + min_y <= *root_y)
5601 /* It fits above the pointer. */
5602 *root_y -= height + XINT (dy);
5603 else
5604 /* Put it on the top. */
5605 *root_y = min_y;
5606
5607 if (INTEGERP (left))
5608 *root_x = XINT (left);
5609 else if (*root_x + XINT (dx) <= min_x)
5610 *root_x = 0; /* Can happen for negative dx */
5611 else if (*root_x + XINT (dx) + width <= max_x)
5612 /* It fits to the right of the pointer. */
5613 *root_x += XINT (dx);
5614 else if (width + XINT (dx) + min_x <= *root_x)
5615 /* It fits to the left of the pointer. */
5616 *root_x -= width + XINT (dx);
5617 else
5618 /* Put it left justified on the screen -- it ought to fit that way. */
5619 *root_x = min_x;
5620 }
5621
5622
5623 DEFUN ("x-show-tip", Fx_show_tip, Sx_show_tip, 1, 6, 0,
5624 doc: /* Show STRING in a \"tooltip\" window on frame FRAME.
5625 A tooltip window is a small window displaying a string.
5626
5627 This is an internal function; Lisp code should call `tooltip-show'.
5628
5629 FRAME nil or omitted means use the selected frame.
5630
5631 PARMS is an optional list of frame parameters which can be
5632 used to change the tooltip's appearance.
5633
5634 Automatically hide the tooltip after TIMEOUT seconds. TIMEOUT nil
5635 means use the default timeout of 5 seconds.
5636
5637 If the list of frame parameters PARMS contains a `left' parameter,
5638 the tooltip is displayed at that x-position. Otherwise it is
5639 displayed at the mouse position, with offset DX added (default is 5 if
5640 DX isn't specified). Likewise for the y-position; if a `top' frame
5641 parameter is specified, it determines the y-position of the tooltip
5642 window, otherwise it is displayed at the mouse position, with offset
5643 DY added (default is -10).
5644
5645 A tooltip's maximum size is specified by `x-max-tooltip-size'.
5646 Text larger than the specified size is clipped. */)
5647 (Lisp_Object string, Lisp_Object frame, Lisp_Object parms, Lisp_Object timeout, Lisp_Object dx, Lisp_Object dy)
5648 {
5649 struct frame *f;
5650 struct window *w;
5651 int root_x, root_y;
5652 struct buffer *old_buffer;
5653 struct text_pos pos;
5654 int i, width, height;
5655 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4;
5656 int old_windows_or_buffers_changed = windows_or_buffers_changed;
5657 int count = SPECPDL_INDEX ();
5658
5659 specbind (Qinhibit_redisplay, Qt);
5660
5661 GCPRO4 (string, parms, frame, timeout);
5662
5663 CHECK_STRING (string);
5664 f = check_x_frame (frame);
5665 if (NILP (timeout))
5666 timeout = make_number (5);
5667 else
5668 CHECK_NATNUM (timeout);
5669
5670 if (NILP (dx))
5671 dx = make_number (5);
5672 else
5673 CHECK_NUMBER (dx);
5674
5675 if (NILP (dy))
5676 dy = make_number (-10);
5677 else
5678 CHECK_NUMBER (dy);
5679
5680 if (NILP (last_show_tip_args))
5681 last_show_tip_args = Fmake_vector (make_number (3), Qnil);
5682
5683 if (!NILP (tip_frame))
5684 {
5685 Lisp_Object last_string = AREF (last_show_tip_args, 0);
5686 Lisp_Object last_frame = AREF (last_show_tip_args, 1);
5687 Lisp_Object last_parms = AREF (last_show_tip_args, 2);
5688
5689 if (EQ (frame, last_frame)
5690 && !NILP (Fequal (last_string, string))
5691 && !NILP (Fequal (last_parms, parms)))
5692 {
5693 struct frame *f = XFRAME (tip_frame);
5694
5695 /* Only DX and DY have changed. */
5696 if (!NILP (tip_timer))
5697 {
5698 Lisp_Object timer = tip_timer;
5699 tip_timer = Qnil;
5700 call1 (Qcancel_timer, timer);
5701 }
5702
5703 BLOCK_INPUT;
5704 compute_tip_xy (f, parms, dx, dy, FRAME_PIXEL_WIDTH (f),
5705 FRAME_PIXEL_HEIGHT (f), &root_x, &root_y);
5706
5707 /* Put tooltip in topmost group and in position. */
5708 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
5709 root_x, root_y, 0, 0,
5710 SWP_NOSIZE | SWP_NOACTIVATE);
5711
5712 /* Ensure tooltip is on top of other topmost windows (eg menus). */
5713 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
5714 0, 0, 0, 0,
5715 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
5716
5717 UNBLOCK_INPUT;
5718 goto start_timer;
5719 }
5720 }
5721
5722 /* Hide a previous tip, if any. */
5723 Fx_hide_tip ();
5724
5725 ASET (last_show_tip_args, 0, string);
5726 ASET (last_show_tip_args, 1, frame);
5727 ASET (last_show_tip_args, 2, parms);
5728
5729 /* Add default values to frame parameters. */
5730 if (NILP (Fassq (Qname, parms)))
5731 parms = Fcons (Fcons (Qname, build_string ("tooltip")), parms);
5732 if (NILP (Fassq (Qinternal_border_width, parms)))
5733 parms = Fcons (Fcons (Qinternal_border_width, make_number (3)), parms);
5734 if (NILP (Fassq (Qborder_width, parms)))
5735 parms = Fcons (Fcons (Qborder_width, make_number (1)), parms);
5736 if (NILP (Fassq (Qborder_color, parms)))
5737 parms = Fcons (Fcons (Qborder_color, build_string ("lightyellow")), parms);
5738 if (NILP (Fassq (Qbackground_color, parms)))
5739 parms = Fcons (Fcons (Qbackground_color, build_string ("lightyellow")),
5740 parms);
5741
5742 /* Block input until the tip has been fully drawn, to avoid crashes
5743 when drawing tips in menus. */
5744 BLOCK_INPUT;
5745
5746 /* Create a frame for the tooltip, and record it in the global
5747 variable tip_frame. */
5748 frame = x_create_tip_frame (FRAME_W32_DISPLAY_INFO (f), parms, string);
5749 f = XFRAME (frame);
5750
5751 /* Set up the frame's root window. */
5752 w = XWINDOW (FRAME_ROOT_WINDOW (f));
5753 w->left_col = w->top_line = make_number (0);
5754
5755 if (CONSP (Vx_max_tooltip_size)
5756 && INTEGERP (XCAR (Vx_max_tooltip_size))
5757 && XINT (XCAR (Vx_max_tooltip_size)) > 0
5758 && INTEGERP (XCDR (Vx_max_tooltip_size))
5759 && XINT (XCDR (Vx_max_tooltip_size)) > 0)
5760 {
5761 w->total_cols = XCAR (Vx_max_tooltip_size);
5762 w->total_lines = XCDR (Vx_max_tooltip_size);
5763 }
5764 else
5765 {
5766 w->total_cols = make_number (80);
5767 w->total_lines = make_number (40);
5768 }
5769
5770 FRAME_TOTAL_COLS (f) = XINT (w->total_cols);
5771 adjust_glyphs (f);
5772 w->pseudo_window_p = 1;
5773
5774 /* Display the tooltip text in a temporary buffer. */
5775 old_buffer = current_buffer;
5776 set_buffer_internal_1 (XBUFFER (XWINDOW (FRAME_ROOT_WINDOW (f))->buffer));
5777 current_buffer->truncate_lines = Qnil;
5778 clear_glyph_matrix (w->desired_matrix);
5779 clear_glyph_matrix (w->current_matrix);
5780 SET_TEXT_POS (pos, BEGV, BEGV_BYTE);
5781 try_window (FRAME_ROOT_WINDOW (f), pos, 0);
5782
5783 /* Compute width and height of the tooltip. */
5784 width = height = 0;
5785 for (i = 0; i < w->desired_matrix->nrows; ++i)
5786 {
5787 struct glyph_row *row = &w->desired_matrix->rows[i];
5788 struct glyph *last;
5789 int row_width;
5790
5791 /* Stop at the first empty row at the end. */
5792 if (!row->enabled_p || !row->displays_text_p)
5793 break;
5794
5795 /* Let the row go over the full width of the frame. */
5796 row->full_width_p = 1;
5797
5798 #ifdef TODO /* Investigate why some fonts need more width than is
5799 calculated for some tooltips. */
5800 /* There's a glyph at the end of rows that is use to place
5801 the cursor there. Don't include the width of this glyph. */
5802 if (row->used[TEXT_AREA])
5803 {
5804 last = &row->glyphs[TEXT_AREA][row->used[TEXT_AREA] - 1];
5805 row_width = row->pixel_width - last->pixel_width;
5806 }
5807 else
5808 #endif
5809 row_width = row->pixel_width;
5810
5811 /* TODO: find why tips do not draw along baseline as instructed. */
5812 height += row->height;
5813 width = max (width, row_width);
5814 }
5815
5816 /* Add the frame's internal border to the width and height the X
5817 window should have. */
5818 height += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
5819 width += 2 * FRAME_INTERNAL_BORDER_WIDTH (f);
5820
5821 /* Move the tooltip window where the mouse pointer is. Resize and
5822 show it. */
5823 compute_tip_xy (f, parms, dx, dy, width, height, &root_x, &root_y);
5824
5825 {
5826 /* Adjust Window size to take border into account. */
5827 RECT rect;
5828 rect.left = rect.top = 0;
5829 rect.right = width;
5830 rect.bottom = height;
5831 AdjustWindowRect (&rect, f->output_data.w32->dwStyle,
5832 FRAME_EXTERNAL_MENU_BAR (f));
5833
5834 /* Position and size tooltip, and put it in the topmost group.
5835 The add-on of 3 to the 5th argument is a kludge: without it,
5836 some fonts cause the last character of the tip to be truncated,
5837 for some obscure reason. */
5838 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOPMOST,
5839 root_x, root_y, rect.right - rect.left + 3,
5840 rect.bottom - rect.top, SWP_NOACTIVATE);
5841
5842 /* Ensure tooltip is on top of other topmost windows (eg menus). */
5843 SetWindowPos (FRAME_W32_WINDOW (f), HWND_TOP,
5844 0, 0, 0, 0,
5845 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
5846
5847 /* Let redisplay know that we have made the frame visible already. */
5848 f->async_visible = 1;
5849
5850 ShowWindow (FRAME_W32_WINDOW (f), SW_SHOWNOACTIVATE);
5851 }
5852
5853 /* Draw into the window. */
5854 w->must_be_updated_p = 1;
5855 update_single_window (w, 1);
5856
5857 UNBLOCK_INPUT;
5858
5859 /* Restore original current buffer. */
5860 set_buffer_internal_1 (old_buffer);
5861 windows_or_buffers_changed = old_windows_or_buffers_changed;
5862
5863 start_timer:
5864 /* Let the tip disappear after timeout seconds. */
5865 tip_timer = call3 (intern ("run-at-time"), timeout, Qnil,
5866 intern ("x-hide-tip"));
5867
5868 UNGCPRO;
5869 return unbind_to (count, Qnil);
5870 }
5871
5872
5873 DEFUN ("x-hide-tip", Fx_hide_tip, Sx_hide_tip, 0, 0, 0,
5874 doc: /* Hide the current tooltip window, if there is any.
5875 Value is t if tooltip was open, nil otherwise. */)
5876 (void)
5877 {
5878 int count;
5879 Lisp_Object deleted, frame, timer;
5880 struct gcpro gcpro1, gcpro2;
5881
5882 /* Return quickly if nothing to do. */
5883 if (NILP (tip_timer) && NILP (tip_frame))
5884 return Qnil;
5885
5886 frame = tip_frame;
5887 timer = tip_timer;
5888 GCPRO2 (frame, timer);
5889 tip_frame = tip_timer = deleted = Qnil;
5890
5891 count = SPECPDL_INDEX ();
5892 specbind (Qinhibit_redisplay, Qt);
5893 specbind (Qinhibit_quit, Qt);
5894
5895 if (!NILP (timer))
5896 call1 (Qcancel_timer, timer);
5897
5898 if (FRAMEP (frame))
5899 {
5900 delete_frame (frame, Qnil);
5901 deleted = Qt;
5902 }
5903
5904 UNGCPRO;
5905 return unbind_to (count, deleted);
5906 }
5907
5908
5909 \f
5910 /***********************************************************************
5911 File selection dialog
5912 ***********************************************************************/
5913 extern Lisp_Object Qfile_name_history;
5914
5915 /* Callback for altering the behavior of the Open File dialog.
5916 Makes the Filename text field contain "Current Directory" and be
5917 read-only when "Directories" is selected in the filter. This
5918 allows us to work around the fact that the standard Open File
5919 dialog does not support directories. */
5920 UINT CALLBACK
5921 file_dialog_callback (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
5922 {
5923 if (msg == WM_NOTIFY)
5924 {
5925 OFNOTIFY * notify = (OFNOTIFY *)lParam;
5926 /* Detect when the Filter dropdown is changed. */
5927 if (notify->hdr.code == CDN_TYPECHANGE
5928 || notify->hdr.code == CDN_INITDONE)
5929 {
5930 HWND dialog = GetParent (hwnd);
5931 HWND edit_control = GetDlgItem (dialog, FILE_NAME_TEXT_FIELD);
5932
5933 /* Directories is in index 2. */
5934 if (notify->lpOFN->nFilterIndex == 2)
5935 {
5936 CommDlg_OpenSave_SetControlText (dialog, FILE_NAME_TEXT_FIELD,
5937 "Current Directory");
5938 EnableWindow (edit_control, FALSE);
5939 }
5940 else
5941 {
5942 /* Don't override default filename on init done. */
5943 if (notify->hdr.code == CDN_TYPECHANGE)
5944 CommDlg_OpenSave_SetControlText (dialog,
5945 FILE_NAME_TEXT_FIELD, "");
5946 EnableWindow (edit_control, TRUE);
5947 }
5948 }
5949 }
5950 return 0;
5951 }
5952
5953 /* Since we compile with _WIN32_WINNT set to 0x0400 (for NT4 compatibility)
5954 we end up with the old file dialogs. Define a big enough struct for the
5955 new dialog to trick GetOpenFileName into giving us the new dialogs on
5956 Windows 2000 and XP. */
5957 typedef struct
5958 {
5959 OPENFILENAME real_details;
5960 void * pReserved;
5961 DWORD dwReserved;
5962 DWORD FlagsEx;
5963 } NEWOPENFILENAME;
5964
5965
5966 DEFUN ("x-file-dialog", Fx_file_dialog, Sx_file_dialog, 2, 5, 0,
5967 doc: /* Read file name, prompting with PROMPT in directory DIR.
5968 Use a file selection dialog.
5969 Select DEFAULT-FILENAME in the dialog's file selection box, if
5970 specified. Ensure that file exists if MUSTMATCH is non-nil.
5971 If ONLY-DIR-P is non-nil, the user can only select directories. */)
5972 (Lisp_Object prompt, Lisp_Object dir, Lisp_Object default_filename, Lisp_Object mustmatch, Lisp_Object only_dir_p)
5973 {
5974 struct frame *f = SELECTED_FRAME ();
5975 Lisp_Object file = Qnil;
5976 int count = SPECPDL_INDEX ();
5977 struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6;
5978 char filename[MAX_PATH + 1];
5979 char init_dir[MAX_PATH + 1];
5980 int default_filter_index = 1; /* 1: All Files, 2: Directories only */
5981
5982 GCPRO6 (prompt, dir, default_filename, mustmatch, only_dir_p, file);
5983 CHECK_STRING (prompt);
5984 CHECK_STRING (dir);
5985
5986 /* Create the dialog with PROMPT as title, using DIR as initial
5987 directory and using "*" as pattern. */
5988 dir = Fexpand_file_name (dir, Qnil);
5989 strncpy (init_dir, SDATA (ENCODE_FILE (dir)), MAX_PATH);
5990 init_dir[MAX_PATH] = '\0';
5991 unixtodos_filename (init_dir);
5992
5993 if (STRINGP (default_filename))
5994 {
5995 char *file_name_only;
5996 char *full_path_name = SDATA (ENCODE_FILE (default_filename));
5997
5998 unixtodos_filename (full_path_name);
5999
6000 file_name_only = strrchr (full_path_name, '\\');
6001 if (!file_name_only)
6002 file_name_only = full_path_name;
6003 else
6004 file_name_only++;
6005
6006 strncpy (filename, file_name_only, MAX_PATH);
6007 filename[MAX_PATH] = '\0';
6008 }
6009 else
6010 filename[0] = '\0';
6011
6012 {
6013 NEWOPENFILENAME new_file_details;
6014 BOOL file_opened = FALSE;
6015 OPENFILENAME * file_details = &new_file_details.real_details;
6016
6017 /* Prevent redisplay. */
6018 specbind (Qinhibit_redisplay, Qt);
6019 BLOCK_INPUT;
6020
6021 memset (&new_file_details, 0, sizeof (new_file_details));
6022 /* Apparently NT4 crashes if you give it an unexpected size.
6023 I'm not sure about Windows 9x, so play it safe. */
6024 if (w32_major_version > 4 && w32_major_version < 95)
6025 file_details->lStructSize = sizeof (NEWOPENFILENAME);
6026 else
6027 file_details->lStructSize = sizeof (OPENFILENAME);
6028
6029 file_details->hwndOwner = FRAME_W32_WINDOW (f);
6030 /* Undocumented Bug in Common File Dialog:
6031 If a filter is not specified, shell links are not resolved. */
6032 file_details->lpstrFilter = "All Files (*.*)\0*.*\0Directories\0*|*\0\0";
6033 file_details->lpstrFile = filename;
6034 file_details->nMaxFile = sizeof (filename);
6035 file_details->lpstrInitialDir = init_dir;
6036 file_details->lpstrTitle = SDATA (prompt);
6037
6038 if (! NILP (only_dir_p))
6039 default_filter_index = 2;
6040
6041 file_details->nFilterIndex = default_filter_index;
6042
6043 file_details->Flags = (OFN_HIDEREADONLY | OFN_NOCHANGEDIR
6044 | OFN_EXPLORER | OFN_ENABLEHOOK);
6045 if (!NILP (mustmatch))
6046 {
6047 /* Require that the path to the parent directory exists. */
6048 file_details->Flags |= OFN_PATHMUSTEXIST;
6049 /* If we are looking for a file, require that it exists. */
6050 if (NILP (only_dir_p))
6051 file_details->Flags |= OFN_FILEMUSTEXIST;
6052 }
6053
6054 file_details->lpfnHook = (LPOFNHOOKPROC) file_dialog_callback;
6055
6056 file_opened = GetOpenFileName (file_details);
6057
6058 UNBLOCK_INPUT;
6059
6060 if (file_opened)
6061 {
6062 dostounix_filename (filename);
6063
6064 if (file_details->nFilterIndex == 2)
6065 {
6066 /* "Directories" selected - strip dummy file name. */
6067 char * last = strrchr (filename, '/');
6068 *last = '\0';
6069 }
6070
6071 file = DECODE_FILE (build_string (filename));
6072 }
6073 /* User cancelled the dialog without making a selection. */
6074 else if (!CommDlgExtendedError ())
6075 file = Qnil;
6076 /* An error occurred, fallback on reading from the mini-buffer. */
6077 else
6078 file = Fcompleting_read (prompt, intern ("read-file-name-internal"),
6079 dir, mustmatch, dir, Qfile_name_history,
6080 default_filename, Qnil);
6081
6082 file = unbind_to (count, file);
6083 }
6084
6085 UNGCPRO;
6086
6087 /* Make "Cancel" equivalent to C-g. */
6088 if (NILP (file))
6089 Fsignal (Qquit, Qnil);
6090
6091 return unbind_to (count, file);
6092 }
6093
6094
6095 /* Moving files to the system recycle bin.
6096 Used by `move-file-to-trash' instead of the default moving to ~/.Trash */
6097 DEFUN ("system-move-file-to-trash", Fsystem_move_file_to_trash,
6098 Ssystem_move_file_to_trash, 1, 1, 0,
6099 doc: /* Move file or directory named FILENAME to the recycle bin. */)
6100 (Lisp_Object filename)
6101 {
6102 Lisp_Object handler;
6103 Lisp_Object encoded_file;
6104 Lisp_Object operation;
6105
6106 operation = Qdelete_file;
6107 if (!NILP (Ffile_directory_p (filename))
6108 && NILP (Ffile_symlink_p (filename)))
6109 {
6110 operation = intern ("delete-directory");
6111 filename = Fdirectory_file_name (filename);
6112 }
6113 filename = Fexpand_file_name (filename, Qnil);
6114
6115 handler = Ffind_file_name_handler (filename, operation);
6116 if (!NILP (handler))
6117 return call2 (handler, operation, filename);
6118
6119 encoded_file = ENCODE_FILE (filename);
6120
6121 {
6122 const char * path;
6123 SHFILEOPSTRUCT file_op;
6124 char tmp_path[MAX_PATH + 1];
6125
6126 path = map_w32_filename (SDATA (encoded_file), NULL);
6127
6128 /* On Windows, write permission is required to delete/move files. */
6129 _chmod (path, 0666);
6130
6131 memset (tmp_path, 0, sizeof (tmp_path));
6132 strcpy (tmp_path, path);
6133
6134 memset (&file_op, 0, sizeof (file_op));
6135 file_op.hwnd = HWND_DESKTOP;
6136 file_op.wFunc = FO_DELETE;
6137 file_op.pFrom = tmp_path;
6138 file_op.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_ALLOWUNDO
6139 | FOF_NOERRORUI | FOF_NO_CONNECTED_ELEMENTS;
6140 file_op.fAnyOperationsAborted = FALSE;
6141
6142 if (SHFileOperation (&file_op) != 0)
6143 report_file_error ("Removing old name", list1 (filename));
6144 }
6145 return Qnil;
6146 }
6147
6148 \f
6149 /***********************************************************************
6150 w32 specialized functions
6151 ***********************************************************************/
6152
6153 DEFUN ("w32-send-sys-command", Fw32_send_sys_command,
6154 Sw32_send_sys_command, 1, 2, 0,
6155 doc: /* Send frame a Windows WM_SYSCOMMAND message of type COMMAND.
6156 Some useful values for COMMAND are #xf030 to maximize frame (#xf020
6157 to minimize), #xf120 to restore frame to original size, and #xf100
6158 to activate the menubar for keyboard access. #xf140 activates the
6159 screen saver if defined.
6160
6161 If optional parameter FRAME is not specified, use selected frame. */)
6162 (Lisp_Object command, Lisp_Object frame)
6163 {
6164 FRAME_PTR f = check_x_frame (frame);
6165
6166 CHECK_NUMBER (command);
6167
6168 PostMessage (FRAME_W32_WINDOW (f), WM_SYSCOMMAND, XINT (command), 0);
6169
6170 return Qnil;
6171 }
6172
6173 DEFUN ("w32-shell-execute", Fw32_shell_execute, Sw32_shell_execute, 2, 4, 0,
6174 doc: /* Get Windows to perform OPERATION on DOCUMENT.
6175 This is a wrapper around the ShellExecute system function, which
6176 invokes the application registered to handle OPERATION for DOCUMENT.
6177
6178 OPERATION is either nil or a string that names a supported operation.
6179 What operations can be used depends on the particular DOCUMENT and its
6180 handler application, but typically it is one of the following common
6181 operations:
6182
6183 \"open\" - open DOCUMENT, which could be a file, a directory, or an
6184 executable program. If it is an application, that
6185 application is launched in the current buffer's default
6186 directory. Otherwise, the application associated with
6187 DOCUMENT is launched in the buffer's default directory.
6188 \"print\" - print DOCUMENT, which must be a file
6189 \"explore\" - start the Windows Explorer on DOCUMENT
6190 \"edit\" - launch an editor and open DOCUMENT for editing; which
6191 editor is launched depends on the association for the
6192 specified DOCUMENT
6193 \"find\" - initiate search starting from DOCUMENT which must specify
6194 a directory
6195 nil - invoke the default OPERATION, or \"open\" if default is
6196 not defined or unavailable
6197
6198 DOCUMENT is typically the name of a document file or a URL, but can
6199 also be a program executable to run, or a directory to open in the
6200 Windows Explorer.
6201
6202 If DOCUMENT is a program executable, the optional third arg PARAMETERS
6203 can be a string containing command line parameters that will be passed
6204 to the program; otherwise, PARAMETERS should be nil or unspecified.
6205
6206 Optional fourth argument SHOW-FLAG can be used to control how the
6207 application will be displayed when it is invoked. If SHOW-FLAG is nil
6208 or unspecified, the application is displayed normally, otherwise it is
6209 an integer representing a ShowWindow flag:
6210
6211 0 - start hidden
6212 1 - start normally
6213 3 - start maximized
6214 6 - start minimized */)
6215 (Lisp_Object operation, Lisp_Object document, Lisp_Object parameters, Lisp_Object show_flag)
6216 {
6217 Lisp_Object current_dir;
6218 char *errstr;
6219
6220 CHECK_STRING (document);
6221
6222 /* Encode filename, current directory and parameters. */
6223 current_dir = ENCODE_FILE (current_buffer->directory);
6224 document = ENCODE_FILE (document);
6225 if (STRINGP (parameters))
6226 parameters = ENCODE_SYSTEM (parameters);
6227
6228 if ((int) ShellExecute (NULL,
6229 (STRINGP (operation) ?
6230 SDATA (operation) : NULL),
6231 SDATA (document),
6232 (STRINGP (parameters) ?
6233 SDATA (parameters) : NULL),
6234 SDATA (current_dir),
6235 (INTEGERP (show_flag) ?
6236 XINT (show_flag) : SW_SHOWDEFAULT))
6237 > 32)
6238 return Qt;
6239 errstr = w32_strerror (0);
6240 /* The error string might be encoded in the locale's encoding. */
6241 if (!NILP (Vlocale_coding_system))
6242 {
6243 Lisp_Object decoded =
6244 code_convert_string_norecord (make_unibyte_string (errstr,
6245 strlen (errstr)),
6246 Vlocale_coding_system, 0);
6247 errstr = (char *)SDATA (decoded);
6248 }
6249 error ("ShellExecute failed: %s", errstr);
6250 }
6251
6252 /* Lookup virtual keycode from string representing the name of a
6253 non-ascii keystroke into the corresponding virtual key, using
6254 lispy_function_keys. */
6255 static int
6256 lookup_vk_code (char *key)
6257 {
6258 int i;
6259
6260 for (i = 0; i < 256; i++)
6261 if (lispy_function_keys[i]
6262 && strcmp (lispy_function_keys[i], key) == 0)
6263 return i;
6264
6265 return -1;
6266 }
6267
6268 /* Convert a one-element vector style key sequence to a hot key
6269 definition. */
6270 static Lisp_Object
6271 w32_parse_hot_key (Lisp_Object key)
6272 {
6273 /* Copied from Fdefine_key and store_in_keymap. */
6274 register Lisp_Object c;
6275 int vk_code;
6276 int lisp_modifiers;
6277 int w32_modifiers;
6278 struct gcpro gcpro1;
6279
6280 CHECK_VECTOR (key);
6281
6282 if (XFASTINT (Flength (key)) != 1)
6283 return Qnil;
6284
6285 GCPRO1 (key);
6286
6287 c = Faref (key, make_number (0));
6288
6289 if (CONSP (c) && lucid_event_type_list_p (c))
6290 c = Fevent_convert_list (c);
6291
6292 UNGCPRO;
6293
6294 if (! INTEGERP (c) && ! SYMBOLP (c))
6295 error ("Key definition is invalid");
6296
6297 /* Work out the base key and the modifiers. */
6298 if (SYMBOLP (c))
6299 {
6300 c = parse_modifiers (c);
6301 lisp_modifiers = XINT (Fcar (Fcdr (c)));
6302 c = Fcar (c);
6303 if (!SYMBOLP (c))
6304 abort ();
6305 vk_code = lookup_vk_code (SDATA (SYMBOL_NAME (c)));
6306 }
6307 else if (INTEGERP (c))
6308 {
6309 lisp_modifiers = XINT (c) & ~CHARACTERBITS;
6310 /* Many ascii characters are their own virtual key code. */
6311 vk_code = XINT (c) & CHARACTERBITS;
6312 }
6313
6314 if (vk_code < 0 || vk_code > 255)
6315 return Qnil;
6316
6317 if ((lisp_modifiers & meta_modifier) != 0
6318 && !NILP (Vw32_alt_is_meta))
6319 lisp_modifiers |= alt_modifier;
6320
6321 /* Supply defs missing from mingw32. */
6322 #ifndef MOD_ALT
6323 #define MOD_ALT 0x0001
6324 #define MOD_CONTROL 0x0002
6325 #define MOD_SHIFT 0x0004
6326 #define MOD_WIN 0x0008
6327 #endif
6328
6329 /* Convert lisp modifiers to Windows hot-key form. */
6330 w32_modifiers = (lisp_modifiers & hyper_modifier) ? MOD_WIN : 0;
6331 w32_modifiers |= (lisp_modifiers & alt_modifier) ? MOD_ALT : 0;
6332 w32_modifiers |= (lisp_modifiers & ctrl_modifier) ? MOD_CONTROL : 0;
6333 w32_modifiers |= (lisp_modifiers & shift_modifier) ? MOD_SHIFT : 0;
6334
6335 return HOTKEY (vk_code, w32_modifiers);
6336 }
6337
6338 DEFUN ("w32-register-hot-key", Fw32_register_hot_key,
6339 Sw32_register_hot_key, 1, 1, 0,
6340 doc: /* Register KEY as a hot-key combination.
6341 Certain key combinations like Alt-Tab are reserved for system use on
6342 Windows, and therefore are normally intercepted by the system. However,
6343 most of these key combinations can be received by registering them as
6344 hot-keys, overriding their special meaning.
6345
6346 KEY must be a one element key definition in vector form that would be
6347 acceptable to `define-key' (e.g. [A-tab] for Alt-Tab). The meta
6348 modifier is interpreted as Alt if `w32-alt-is-meta' is t, and hyper
6349 is always interpreted as the Windows modifier keys.
6350
6351 The return value is the hotkey-id if registered, otherwise nil. */)
6352 (Lisp_Object key)
6353 {
6354 key = w32_parse_hot_key (key);
6355
6356 if (!NILP (key) && NILP (Fmemq (key, w32_grabbed_keys)))
6357 {
6358 /* Reuse an empty slot if possible. */
6359 Lisp_Object item = Fmemq (Qnil, w32_grabbed_keys);
6360
6361 /* Safe to add new key to list, even if we have focus. */
6362 if (NILP (item))
6363 w32_grabbed_keys = Fcons (key, w32_grabbed_keys);
6364 else
6365 XSETCAR (item, key);
6366
6367 /* Notify input thread about new hot-key definition, so that it
6368 takes effect without needing to switch focus. */
6369 #ifdef USE_LISP_UNION_TYPE
6370 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
6371 (WPARAM) key.i, 0);
6372 #else
6373 PostThreadMessage (dwWindowsThreadId, WM_EMACS_REGISTER_HOT_KEY,
6374 (WPARAM) key, 0);
6375 #endif
6376 }
6377
6378 return key;
6379 }
6380
6381 DEFUN ("w32-unregister-hot-key", Fw32_unregister_hot_key,
6382 Sw32_unregister_hot_key, 1, 1, 0,
6383 doc: /* Unregister KEY as a hot-key combination. */)
6384 (Lisp_Object key)
6385 {
6386 Lisp_Object item;
6387
6388 if (!INTEGERP (key))
6389 key = w32_parse_hot_key (key);
6390
6391 item = Fmemq (key, w32_grabbed_keys);
6392
6393 if (!NILP (item))
6394 {
6395 /* Notify input thread about hot-key definition being removed, so
6396 that it takes effect without needing focus switch. */
6397 #ifdef USE_LISP_UNION_TYPE
6398 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
6399 (WPARAM) XINT (XCAR (item)), (LPARAM) item.i))
6400 #else
6401 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_UNREGISTER_HOT_KEY,
6402 (WPARAM) XINT (XCAR (item)), (LPARAM) item))
6403 #endif
6404 {
6405 MSG msg;
6406 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
6407 }
6408 return Qt;
6409 }
6410 return Qnil;
6411 }
6412
6413 DEFUN ("w32-registered-hot-keys", Fw32_registered_hot_keys,
6414 Sw32_registered_hot_keys, 0, 0, 0,
6415 doc: /* Return list of registered hot-key IDs. */)
6416 (void)
6417 {
6418 return Fdelq (Qnil, Fcopy_sequence (w32_grabbed_keys));
6419 }
6420
6421 DEFUN ("w32-reconstruct-hot-key", Fw32_reconstruct_hot_key,
6422 Sw32_reconstruct_hot_key, 1, 1, 0,
6423 doc: /* Convert hot-key ID to a lisp key combination.
6424 usage: (w32-reconstruct-hot-key ID) */)
6425 (Lisp_Object hotkeyid)
6426 {
6427 int vk_code, w32_modifiers;
6428 Lisp_Object key;
6429
6430 CHECK_NUMBER (hotkeyid);
6431
6432 vk_code = HOTKEY_VK_CODE (hotkeyid);
6433 w32_modifiers = HOTKEY_MODIFIERS (hotkeyid);
6434
6435 if (vk_code < 256 && lispy_function_keys[vk_code])
6436 key = intern (lispy_function_keys[vk_code]);
6437 else
6438 key = make_number (vk_code);
6439
6440 key = Fcons (key, Qnil);
6441 if (w32_modifiers & MOD_SHIFT)
6442 key = Fcons (Qshift, key);
6443 if (w32_modifiers & MOD_CONTROL)
6444 key = Fcons (Qctrl, key);
6445 if (w32_modifiers & MOD_ALT)
6446 key = Fcons (NILP (Vw32_alt_is_meta) ? Qalt : Qmeta, key);
6447 if (w32_modifiers & MOD_WIN)
6448 key = Fcons (Qhyper, key);
6449
6450 return key;
6451 }
6452
6453 DEFUN ("w32-toggle-lock-key", Fw32_toggle_lock_key,
6454 Sw32_toggle_lock_key, 1, 2, 0,
6455 doc: /* Toggle the state of the lock key KEY.
6456 KEY can be `capslock', `kp-numlock', or `scroll'.
6457 If the optional parameter NEW-STATE is a number, then the state of KEY
6458 is set to off if the low bit of NEW-STATE is zero, otherwise on. */)
6459 (Lisp_Object key, Lisp_Object new_state)
6460 {
6461 int vk_code;
6462
6463 if (EQ (key, intern ("capslock")))
6464 vk_code = VK_CAPITAL;
6465 else if (EQ (key, intern ("kp-numlock")))
6466 vk_code = VK_NUMLOCK;
6467 else if (EQ (key, intern ("scroll")))
6468 vk_code = VK_SCROLL;
6469 else
6470 return Qnil;
6471
6472 if (!dwWindowsThreadId)
6473 return make_number (w32_console_toggle_lock_key (vk_code, new_state));
6474
6475 #ifdef USE_LISP_UNION_TYPE
6476 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
6477 (WPARAM) vk_code, (LPARAM) new_state.i))
6478 #else
6479 if (PostThreadMessage (dwWindowsThreadId, WM_EMACS_TOGGLE_LOCK_KEY,
6480 (WPARAM) vk_code, (LPARAM) new_state))
6481 #endif
6482 {
6483 MSG msg;
6484 GetMessage (&msg, NULL, WM_EMACS_DONE, WM_EMACS_DONE);
6485 return make_number (msg.wParam);
6486 }
6487 return Qnil;
6488 }
6489
6490 DEFUN ("w32-window-exists-p", Fw32_window_exists_p, Sw32_window_exists_p,
6491 2, 2, 0,
6492 doc: /* Return non-nil if a window exists with the specified CLASS and NAME.
6493
6494 This is a direct interface to the Windows API FindWindow function. */)
6495 (Lisp_Object class, Lisp_Object name)
6496 {
6497 HWND hnd;
6498
6499 if (!NILP (class))
6500 CHECK_STRING (class);
6501 if (!NILP (name))
6502 CHECK_STRING (name);
6503
6504 hnd = FindWindow (STRINGP (class) ? ((LPCTSTR) SDATA (class)) : NULL,
6505 STRINGP (name) ? ((LPCTSTR) SDATA (name)) : NULL);
6506 if (!hnd)
6507 return Qnil;
6508 return Qt;
6509 }
6510
6511 DEFUN ("w32-battery-status", Fw32_battery_status, Sw32_battery_status, 0, 0, 0,
6512 doc: /* Get power status information from Windows system.
6513
6514 The following %-sequences are provided:
6515 %L AC line status (verbose)
6516 %B Battery status (verbose)
6517 %b Battery status, empty means high, `-' means low,
6518 `!' means critical, and `+' means charging
6519 %p Battery load percentage
6520 %s Remaining time (to charge or discharge) in seconds
6521 %m Remaining time (to charge or discharge) in minutes
6522 %h Remaining time (to charge or discharge) in hours
6523 %t Remaining time (to charge or discharge) in the form `h:min' */)
6524 (void)
6525 {
6526 Lisp_Object status = Qnil;
6527
6528 SYSTEM_POWER_STATUS system_status;
6529 if (GetSystemPowerStatus (&system_status))
6530 {
6531 Lisp_Object line_status, battery_status, battery_status_symbol;
6532 Lisp_Object load_percentage, seconds, minutes, hours, remain;
6533 Lisp_Object sequences[8];
6534
6535 long seconds_left = (long) system_status.BatteryLifeTime;
6536
6537 if (system_status.ACLineStatus == 0)
6538 line_status = build_string ("off-line");
6539 else if (system_status.ACLineStatus == 1)
6540 line_status = build_string ("on-line");
6541 else
6542 line_status = build_string ("N/A");
6543
6544 if (system_status.BatteryFlag & 128)
6545 {
6546 battery_status = build_string ("N/A");
6547 battery_status_symbol = empty_unibyte_string;
6548 }
6549 else if (system_status.BatteryFlag & 8)
6550 {
6551 battery_status = build_string ("charging");
6552 battery_status_symbol = build_string ("+");
6553 if (system_status.BatteryFullLifeTime != -1L)
6554 seconds_left = system_status.BatteryFullLifeTime - seconds_left;
6555 }
6556 else if (system_status.BatteryFlag & 4)
6557 {
6558 battery_status = build_string ("critical");
6559 battery_status_symbol = build_string ("!");
6560 }
6561 else if (system_status.BatteryFlag & 2)
6562 {
6563 battery_status = build_string ("low");
6564 battery_status_symbol = build_string ("-");
6565 }
6566 else if (system_status.BatteryFlag & 1)
6567 {
6568 battery_status = build_string ("high");
6569 battery_status_symbol = empty_unibyte_string;
6570 }
6571 else
6572 {
6573 battery_status = build_string ("medium");
6574 battery_status_symbol = empty_unibyte_string;
6575 }
6576
6577 if (system_status.BatteryLifePercent > 100)
6578 load_percentage = build_string ("N/A");
6579 else
6580 {
6581 char buffer[16];
6582 _snprintf (buffer, 16, "%d", system_status.BatteryLifePercent);
6583 load_percentage = build_string (buffer);
6584 }
6585
6586 if (seconds_left < 0)
6587 seconds = minutes = hours = remain = build_string ("N/A");
6588 else
6589 {
6590 long m;
6591 float h;
6592 char buffer[16];
6593 _snprintf (buffer, 16, "%ld", seconds_left);
6594 seconds = build_string (buffer);
6595
6596 m = seconds_left / 60;
6597 _snprintf (buffer, 16, "%ld", m);
6598 minutes = build_string (buffer);
6599
6600 h = seconds_left / 3600.0;
6601 _snprintf (buffer, 16, "%3.1f", h);
6602 hours = build_string (buffer);
6603
6604 _snprintf (buffer, 16, "%ld:%02ld", m / 60, m % 60);
6605 remain = build_string (buffer);
6606 }
6607 sequences[0] = Fcons (make_number ('L'), line_status);
6608 sequences[1] = Fcons (make_number ('B'), battery_status);
6609 sequences[2] = Fcons (make_number ('b'), battery_status_symbol);
6610 sequences[3] = Fcons (make_number ('p'), load_percentage);
6611 sequences[4] = Fcons (make_number ('s'), seconds);
6612 sequences[5] = Fcons (make_number ('m'), minutes);
6613 sequences[6] = Fcons (make_number ('h'), hours);
6614 sequences[7] = Fcons (make_number ('t'), remain);
6615
6616 status = Flist (8, sequences);
6617 }
6618 return status;
6619 }
6620
6621 \f
6622 DEFUN ("file-system-info", Ffile_system_info, Sfile_system_info, 1, 1, 0,
6623 doc: /* Return storage information about the file system FILENAME is on.
6624 Value is a list of floats (TOTAL FREE AVAIL), where TOTAL is the total
6625 storage of the file system, FREE is the free storage, and AVAIL is the
6626 storage available to a non-superuser. All 3 numbers are in bytes.
6627 If the underlying system call fails, value is nil. */)
6628 (Lisp_Object filename)
6629 {
6630 Lisp_Object encoded, value;
6631
6632 CHECK_STRING (filename);
6633 filename = Fexpand_file_name (filename, Qnil);
6634 encoded = ENCODE_FILE (filename);
6635
6636 value = Qnil;
6637
6638 /* Determining the required information on Windows turns out, sadly,
6639 to be more involved than one would hope. The original Win32 api
6640 call for this will return bogus information on some systems, but we
6641 must dynamically probe for the replacement api, since that was
6642 added rather late on. */
6643 {
6644 HMODULE hKernel = GetModuleHandle ("kernel32");
6645 BOOL (*pfn_GetDiskFreeSpaceEx)
6646 (char *, PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER)
6647 = (void *) GetProcAddress (hKernel, "GetDiskFreeSpaceEx");
6648
6649 /* On Windows, we may need to specify the root directory of the
6650 volume holding FILENAME. */
6651 char rootname[MAX_PATH];
6652 char *name = SDATA (encoded);
6653
6654 /* find the root name of the volume if given */
6655 if (isalpha (name[0]) && name[1] == ':')
6656 {
6657 rootname[0] = name[0];
6658 rootname[1] = name[1];
6659 rootname[2] = '\\';
6660 rootname[3] = 0;
6661 }
6662 else if (IS_DIRECTORY_SEP (name[0]) && IS_DIRECTORY_SEP (name[1]))
6663 {
6664 char *str = rootname;
6665 int slashes = 4;
6666 do
6667 {
6668 if (IS_DIRECTORY_SEP (*name) && --slashes == 0)
6669 break;
6670 *str++ = *name++;
6671 }
6672 while ( *name );
6673
6674 *str++ = '\\';
6675 *str = 0;
6676 }
6677
6678 if (pfn_GetDiskFreeSpaceEx)
6679 {
6680 /* Unsigned large integers cannot be cast to double, so
6681 use signed ones instead. */
6682 LARGE_INTEGER availbytes;
6683 LARGE_INTEGER freebytes;
6684 LARGE_INTEGER totalbytes;
6685
6686 if (pfn_GetDiskFreeSpaceEx (rootname,
6687 (ULARGE_INTEGER *)&availbytes,
6688 (ULARGE_INTEGER *)&totalbytes,
6689 (ULARGE_INTEGER *)&freebytes))
6690 value = list3 (make_float ((double) totalbytes.QuadPart),
6691 make_float ((double) freebytes.QuadPart),
6692 make_float ((double) availbytes.QuadPart));
6693 }
6694 else
6695 {
6696 DWORD sectors_per_cluster;
6697 DWORD bytes_per_sector;
6698 DWORD free_clusters;
6699 DWORD total_clusters;
6700
6701 if (GetDiskFreeSpace (rootname,
6702 &sectors_per_cluster,
6703 &bytes_per_sector,
6704 &free_clusters,
6705 &total_clusters))
6706 value = list3 (make_float ((double) total_clusters
6707 * sectors_per_cluster * bytes_per_sector),
6708 make_float ((double) free_clusters
6709 * sectors_per_cluster * bytes_per_sector),
6710 make_float ((double) free_clusters
6711 * sectors_per_cluster * bytes_per_sector));
6712 }
6713 }
6714
6715 return value;
6716 }
6717 \f
6718 DEFUN ("default-printer-name", Fdefault_printer_name, Sdefault_printer_name,
6719 0, 0, 0, doc: /* Return the name of Windows default printer device. */)
6720 (void)
6721 {
6722 static char pname_buf[256];
6723 int err;
6724 HANDLE hPrn;
6725 PRINTER_INFO_2 *ppi2 = NULL;
6726 DWORD dwNeeded = 0, dwReturned = 0;
6727
6728 /* Retrieve the default string from Win.ini (the registry).
6729 * String will be in form "printername,drivername,portname".
6730 * This is the most portable way to get the default printer. */
6731 if (GetProfileString ("windows", "device", ",,", pname_buf, sizeof (pname_buf)) <= 0)
6732 return Qnil;
6733 /* printername precedes first "," character */
6734 strtok (pname_buf, ",");
6735 /* We want to know more than the printer name */
6736 if (!OpenPrinter (pname_buf, &hPrn, NULL))
6737 return Qnil;
6738 GetPrinter (hPrn, 2, NULL, 0, &dwNeeded);
6739 if (dwNeeded == 0)
6740 {
6741 ClosePrinter (hPrn);
6742 return Qnil;
6743 }
6744 /* Allocate memory for the PRINTER_INFO_2 struct */
6745 ppi2 = (PRINTER_INFO_2 *) xmalloc (dwNeeded);
6746 if (!ppi2)
6747 {
6748 ClosePrinter (hPrn);
6749 return Qnil;
6750 }
6751 /* Call GetPrinter again with big enouth memory block */
6752 err = GetPrinter (hPrn, 2, (LPBYTE)ppi2, dwNeeded, &dwReturned);
6753 ClosePrinter (hPrn);
6754 if (!err)
6755 {
6756 xfree (ppi2);
6757 return Qnil;
6758 }
6759
6760 if (ppi2)
6761 {
6762 if (ppi2->Attributes & PRINTER_ATTRIBUTE_SHARED && ppi2->pServerName)
6763 {
6764 /* a remote printer */
6765 if (*ppi2->pServerName == '\\')
6766 _snprintf (pname_buf, sizeof (pname_buf), "%s\\%s", ppi2->pServerName,
6767 ppi2->pShareName);
6768 else
6769 _snprintf (pname_buf, sizeof (pname_buf), "\\\\%s\\%s", ppi2->pServerName,
6770 ppi2->pShareName);
6771 pname_buf[sizeof (pname_buf) - 1] = '\0';
6772 }
6773 else
6774 {
6775 /* a local printer */
6776 strncpy (pname_buf, ppi2->pPortName, sizeof (pname_buf));
6777 pname_buf[sizeof (pname_buf) - 1] = '\0';
6778 /* `pPortName' can include several ports, delimited by ','.
6779 * we only use the first one. */
6780 strtok (pname_buf, ",");
6781 }
6782 xfree (ppi2);
6783 }
6784
6785 return build_string (pname_buf);
6786 }
6787 \f
6788 /***********************************************************************
6789 Initialization
6790 ***********************************************************************/
6791
6792 /* Keep this list in the same order as frame_parms in frame.c.
6793 Use 0 for unsupported frame parameters. */
6794
6795 frame_parm_handler w32_frame_parm_handlers[] =
6796 {
6797 x_set_autoraise,
6798 x_set_autolower,
6799 x_set_background_color,
6800 x_set_border_color,
6801 x_set_border_width,
6802 x_set_cursor_color,
6803 x_set_cursor_type,
6804 x_set_font,
6805 x_set_foreground_color,
6806 x_set_icon_name,
6807 x_set_icon_type,
6808 x_set_internal_border_width,
6809 x_set_menu_bar_lines,
6810 x_set_mouse_color,
6811 x_explicitly_set_name,
6812 x_set_scroll_bar_width,
6813 x_set_title,
6814 x_set_unsplittable,
6815 x_set_vertical_scroll_bars,
6816 x_set_visibility,
6817 x_set_tool_bar_lines,
6818 0, /* x_set_scroll_bar_foreground, */
6819 0, /* x_set_scroll_bar_background, */
6820 x_set_screen_gamma,
6821 x_set_line_spacing,
6822 x_set_fringe_width,
6823 x_set_fringe_width,
6824 0, /* x_set_wait_for_wm, */
6825 x_set_fullscreen,
6826 x_set_font_backend,
6827 x_set_alpha,
6828 0, /* x_set_sticky */
6829 };
6830
6831 void
6832 syms_of_w32fns (void)
6833 {
6834 globals_of_w32fns ();
6835 /* This is zero if not using MS-Windows. */
6836 w32_in_use = 0;
6837 track_mouse_window = NULL;
6838
6839 w32_visible_system_caret_hwnd = NULL;
6840
6841 DEFSYM (Qnone, "none");
6842 DEFSYM (Qsuppress_icon, "suppress-icon");
6843 DEFSYM (Qundefined_color, "undefined-color");
6844 DEFSYM (Qcancel_timer, "cancel-timer");
6845 DEFSYM (Qhyper, "hyper");
6846 DEFSYM (Qsuper, "super");
6847 DEFSYM (Qmeta, "meta");
6848 DEFSYM (Qalt, "alt");
6849 DEFSYM (Qctrl, "ctrl");
6850 DEFSYM (Qcontrol, "control");
6851 DEFSYM (Qshift, "shift");
6852 DEFSYM (Qfont_param, "font-parameter");
6853 /* This is the end of symbol initialization. */
6854
6855 /* Text property `display' should be nonsticky by default. */
6856 Vtext_property_default_nonsticky
6857 = Fcons (Fcons (Qdisplay, Qt), Vtext_property_default_nonsticky);
6858
6859
6860 Fput (Qundefined_color, Qerror_conditions,
6861 pure_cons (Qundefined_color, pure_cons (Qerror, Qnil)));
6862 Fput (Qundefined_color, Qerror_message,
6863 make_pure_c_string ("Undefined color"));
6864
6865 staticpro (&w32_grabbed_keys);
6866 w32_grabbed_keys = Qnil;
6867
6868 DEFVAR_LISP ("w32-color-map", &Vw32_color_map,
6869 doc: /* An array of color name mappings for Windows. */);
6870 Vw32_color_map = Qnil;
6871
6872 DEFVAR_LISP ("w32-pass-alt-to-system", &Vw32_pass_alt_to_system,
6873 doc: /* Non-nil if Alt key presses are passed on to Windows.
6874 When non-nil, for example, Alt pressed and released and then space will
6875 open the System menu. When nil, Emacs processes the Alt key events, and
6876 then silently swallows them. */);
6877 Vw32_pass_alt_to_system = Qnil;
6878
6879 DEFVAR_LISP ("w32-alt-is-meta", &Vw32_alt_is_meta,
6880 doc: /* Non-nil if the Alt key is to be considered the same as the META key.
6881 When nil, Emacs will translate the Alt key to the ALT modifier, not to META. */);
6882 Vw32_alt_is_meta = Qt;
6883
6884 DEFVAR_INT ("w32-quit-key", &w32_quit_key,
6885 doc: /* If non-zero, the virtual key code for an alternative quit key. */);
6886 w32_quit_key = 0;
6887
6888 DEFVAR_LISP ("w32-pass-lwindow-to-system",
6889 &Vw32_pass_lwindow_to_system,
6890 doc: /* If non-nil, the left \"Windows\" key is passed on to Windows.
6891
6892 When non-nil, the Start menu is opened by tapping the key.
6893 If you set this to nil, the left \"Windows\" key is processed by Emacs
6894 according to the value of `w32-lwindow-modifier', which see.
6895
6896 Note that some combinations of the left \"Windows\" key with other keys are
6897 caught by Windows at low level, and so binding them in Emacs will have no
6898 effect. For example, <lwindow>-r always pops up the Windows Run dialog,
6899 <lwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see
6900 the doc string of `w32-phantom-key-code'. */);
6901 Vw32_pass_lwindow_to_system = Qt;
6902
6903 DEFVAR_LISP ("w32-pass-rwindow-to-system",
6904 &Vw32_pass_rwindow_to_system,
6905 doc: /* If non-nil, the right \"Windows\" key is passed on to Windows.
6906
6907 When non-nil, the Start menu is opened by tapping the key.
6908 If you set this to nil, the right \"Windows\" key is processed by Emacs
6909 according to the value of `w32-rwindow-modifier', which see.
6910
6911 Note that some combinations of the right \"Windows\" key with other keys are
6912 caught by Windows at low level, and so binding them in Emacs will have no
6913 effect. For example, <rwindow>-r always pops up the Windows Run dialog,
6914 <rwindow>-<Pause> pops up the "System Properties" dialog, etc. However, see
6915 the doc string of `w32-phantom-key-code'. */);
6916 Vw32_pass_rwindow_to_system = Qt;
6917
6918 DEFVAR_LISP ("w32-phantom-key-code",
6919 &Vw32_phantom_key_code,
6920 doc: /* Virtual key code used to generate \"phantom\" key presses.
6921 Value is a number between 0 and 255.
6922
6923 Phantom key presses are generated in order to stop the system from
6924 acting on \"Windows\" key events when `w32-pass-lwindow-to-system' or
6925 `w32-pass-rwindow-to-system' is nil. */);
6926 /* Although 255 is technically not a valid key code, it works and
6927 means that this hack won't interfere with any real key code. */
6928 XSETINT (Vw32_phantom_key_code, 255);
6929
6930 DEFVAR_LISP ("w32-enable-num-lock",
6931 &Vw32_enable_num_lock,
6932 doc: /* If non-nil, the Num Lock key acts normally.
6933 Set to nil to handle Num Lock as the `kp-numlock' key. */);
6934 Vw32_enable_num_lock = Qt;
6935
6936 DEFVAR_LISP ("w32-enable-caps-lock",
6937 &Vw32_enable_caps_lock,
6938 doc: /* If non-nil, the Caps Lock key acts normally.
6939 Set to nil to handle Caps Lock as the `capslock' key. */);
6940 Vw32_enable_caps_lock = Qt;
6941
6942 DEFVAR_LISP ("w32-scroll-lock-modifier",
6943 &Vw32_scroll_lock_modifier,
6944 doc: /* Modifier to use for the Scroll Lock ON state.
6945 The value can be hyper, super, meta, alt, control or shift for the
6946 respective modifier, or nil to handle Scroll Lock as the `scroll' key.
6947 Any other value will cause the Scroll Lock key to be ignored. */);
6948 Vw32_scroll_lock_modifier = Qnil;
6949
6950 DEFVAR_LISP ("w32-lwindow-modifier",
6951 &Vw32_lwindow_modifier,
6952 doc: /* Modifier to use for the left \"Windows\" key.
6953 The value can be hyper, super, meta, alt, control or shift for the
6954 respective modifier, or nil to appear as the `lwindow' key.
6955 Any other value will cause the key to be ignored. */);
6956 Vw32_lwindow_modifier = Qnil;
6957
6958 DEFVAR_LISP ("w32-rwindow-modifier",
6959 &Vw32_rwindow_modifier,
6960 doc: /* Modifier to use for the right \"Windows\" key.
6961 The value can be hyper, super, meta, alt, control or shift for the
6962 respective modifier, or nil to appear as the `rwindow' key.
6963 Any other value will cause the key to be ignored. */);
6964 Vw32_rwindow_modifier = Qnil;
6965
6966 DEFVAR_LISP ("w32-apps-modifier",
6967 &Vw32_apps_modifier,
6968 doc: /* Modifier to use for the \"Apps\" key.
6969 The value can be hyper, super, meta, alt, control or shift for the
6970 respective modifier, or nil to appear as the `apps' key.
6971 Any other value will cause the key to be ignored. */);
6972 Vw32_apps_modifier = Qnil;
6973
6974 DEFVAR_BOOL ("w32-enable-synthesized-fonts", &w32_enable_synthesized_fonts,
6975 doc: /* Non-nil enables selection of artificially italicized and bold fonts. */);
6976 w32_enable_synthesized_fonts = 0;
6977
6978 DEFVAR_LISP ("w32-enable-palette", &Vw32_enable_palette,
6979 doc: /* Non-nil enables Windows palette management to map colors exactly. */);
6980 Vw32_enable_palette = Qt;
6981
6982 DEFVAR_INT ("w32-mouse-button-tolerance",
6983 &w32_mouse_button_tolerance,
6984 doc: /* Analogue of double click interval for faking middle mouse events.
6985 The value is the minimum time in milliseconds that must elapse between
6986 left and right button down events before they are considered distinct events.
6987 If both mouse buttons are depressed within this interval, a middle mouse
6988 button down event is generated instead. */);
6989 w32_mouse_button_tolerance = GetDoubleClickTime () / 2;
6990
6991 DEFVAR_INT ("w32-mouse-move-interval",
6992 &w32_mouse_move_interval,
6993 doc: /* Minimum interval between mouse move events.
6994 The value is the minimum time in milliseconds that must elapse between
6995 successive mouse move (or scroll bar drag) events before they are
6996 reported as lisp events. */);
6997 w32_mouse_move_interval = 0;
6998
6999 DEFVAR_BOOL ("w32-pass-extra-mouse-buttons-to-system",
7000 &w32_pass_extra_mouse_buttons_to_system,
7001 doc: /* If non-nil, the fourth and fifth mouse buttons are passed to Windows.
7002 Recent versions of Windows support mice with up to five buttons.
7003 Since most applications don't support these extra buttons, most mouse
7004 drivers will allow you to map them to functions at the system level.
7005 If this variable is non-nil, Emacs will pass them on, allowing the
7006 system to handle them. */);
7007 w32_pass_extra_mouse_buttons_to_system = 0;
7008
7009 DEFVAR_BOOL ("w32-pass-multimedia-buttons-to-system",
7010 &w32_pass_multimedia_buttons_to_system,
7011 doc: /* If non-nil, media buttons are passed to Windows.
7012 Some modern keyboards contain buttons for controlling media players, web
7013 browsers and other applications. Generally these buttons are handled on a
7014 system wide basis, but by setting this to nil they are made available
7015 to Emacs for binding. Depending on your keyboard, additional keys that
7016 may be available are:
7017
7018 browser-back, browser-forward, browser-refresh, browser-stop,
7019 browser-search, browser-favorites, browser-home,
7020 mail, mail-reply, mail-forward, mail-send,
7021 app-1, app-2,
7022 help, find, new, open, close, save, print, undo, redo, copy, cut, paste,
7023 spell-check, correction-list, toggle-dictate-command,
7024 media-next, media-previous, media-stop, media-play-pause, media-select,
7025 media-play, media-pause, media-record, media-fast-forward, media-rewind,
7026 media-channel-up, media-channel-down,
7027 volume-mute, volume-up, volume-down,
7028 mic-volume-mute, mic-volume-down, mic-volume-up, mic-toggle,
7029 bass-down, bass-boost, bass-up, treble-down, treble-up */);
7030 w32_pass_multimedia_buttons_to_system = 1;
7031
7032 #if 0 /* TODO: Mouse cursor customization. */
7033 DEFVAR_LISP ("x-pointer-shape", &Vx_pointer_shape,
7034 doc: /* The shape of the pointer when over text.
7035 Changing the value does not affect existing frames
7036 unless you set the mouse color. */);
7037 Vx_pointer_shape = Qnil;
7038
7039 Vx_nontext_pointer_shape = Qnil;
7040
7041 Vx_mode_pointer_shape = Qnil;
7042
7043 DEFVAR_LISP ("x-hourglass-pointer-shape", &Vx_hourglass_pointer_shape,
7044 doc: /* The shape of the pointer when Emacs is busy.
7045 This variable takes effect when you create a new frame
7046 or when you set the mouse color. */);
7047 Vx_hourglass_pointer_shape = Qnil;
7048
7049 DEFVAR_LISP ("x-sensitive-text-pointer-shape",
7050 &Vx_sensitive_text_pointer_shape,
7051 doc: /* The shape of the pointer when over mouse-sensitive text.
7052 This variable takes effect when you create a new frame
7053 or when you set the mouse color. */);
7054 Vx_sensitive_text_pointer_shape = Qnil;
7055
7056 DEFVAR_LISP ("x-window-horizontal-drag-cursor",
7057 &Vx_window_horizontal_drag_shape,
7058 doc: /* Pointer shape to use for indicating a window can be dragged horizontally.
7059 This variable takes effect when you create a new frame
7060 or when you set the mouse color. */);
7061 Vx_window_horizontal_drag_shape = Qnil;
7062 #endif
7063
7064 DEFVAR_LISP ("x-cursor-fore-pixel", &Vx_cursor_fore_pixel,
7065 doc: /* A string indicating the foreground color of the cursor box. */);
7066 Vx_cursor_fore_pixel = Qnil;
7067
7068 DEFVAR_LISP ("x-max-tooltip-size", &Vx_max_tooltip_size,
7069 doc: /* Maximum size for tooltips.
7070 Value is a pair (COLUMNS . ROWS). Text larger than this is clipped. */);
7071 Vx_max_tooltip_size = Fcons (make_number (80), make_number (40));
7072
7073 DEFVAR_LISP ("x-no-window-manager", &Vx_no_window_manager,
7074 doc: /* Non-nil if no window manager is in use.
7075 Emacs doesn't try to figure this out; this is always nil
7076 unless you set it to something else. */);
7077 /* We don't have any way to find this out, so set it to nil
7078 and maybe the user would like to set it to t. */
7079 Vx_no_window_manager = Qnil;
7080
7081 DEFVAR_LISP ("x-pixel-size-width-font-regexp",
7082 &Vx_pixel_size_width_font_regexp,
7083 doc: /* Regexp matching a font name whose width is the same as `PIXEL_SIZE'.
7084
7085 Since Emacs gets width of a font matching with this regexp from
7086 PIXEL_SIZE field of the name, font finding mechanism gets faster for
7087 such a font. This is especially effective for such large fonts as
7088 Chinese, Japanese, and Korean. */);
7089 Vx_pixel_size_width_font_regexp = Qnil;
7090
7091 DEFVAR_LISP ("w32-bdf-filename-alist",
7092 &Vw32_bdf_filename_alist,
7093 doc: /* List of bdf fonts and their corresponding filenames. */);
7094 Vw32_bdf_filename_alist = Qnil;
7095
7096 DEFVAR_BOOL ("w32-strict-fontnames",
7097 &w32_strict_fontnames,
7098 doc: /* Non-nil means only use fonts that are exact matches for those requested.
7099 Default is nil, which allows old fontnames that are not XLFD compliant,
7100 and allows third-party CJK display to work by specifying false charset
7101 fields to trick Emacs into translating to Big5, SJIS etc.
7102 Setting this to t will prevent wrong fonts being selected when
7103 fontsets are automatically created. */);
7104 w32_strict_fontnames = 0;
7105
7106 DEFVAR_BOOL ("w32-strict-painting",
7107 &w32_strict_painting,
7108 doc: /* Non-nil means use strict rules for repainting frames.
7109 Set this to nil to get the old behavior for repainting; this should
7110 only be necessary if the default setting causes problems. */);
7111 w32_strict_painting = 1;
7112
7113 #if 0 /* TODO: Port to W32 */
7114 defsubr (&Sx_change_window_property);
7115 defsubr (&Sx_delete_window_property);
7116 defsubr (&Sx_window_property);
7117 #endif
7118 defsubr (&Sxw_display_color_p);
7119 defsubr (&Sx_display_grayscale_p);
7120 defsubr (&Sxw_color_defined_p);
7121 defsubr (&Sxw_color_values);
7122 defsubr (&Sx_server_max_request_size);
7123 defsubr (&Sx_server_vendor);
7124 defsubr (&Sx_server_version);
7125 defsubr (&Sx_display_pixel_width);
7126 defsubr (&Sx_display_pixel_height);
7127 defsubr (&Sx_display_mm_width);
7128 defsubr (&Sx_display_mm_height);
7129 defsubr (&Sx_display_screens);
7130 defsubr (&Sx_display_planes);
7131 defsubr (&Sx_display_color_cells);
7132 defsubr (&Sx_display_visual_class);
7133 defsubr (&Sx_display_backing_store);
7134 defsubr (&Sx_display_save_under);
7135 defsubr (&Sx_create_frame);
7136 defsubr (&Sx_open_connection);
7137 defsubr (&Sx_close_connection);
7138 defsubr (&Sx_display_list);
7139 defsubr (&Sx_synchronize);
7140 defsubr (&Sx_focus_frame);
7141
7142 /* W32 specific functions */
7143
7144 defsubr (&Sw32_define_rgb_color);
7145 defsubr (&Sw32_default_color_map);
7146 defsubr (&Sw32_send_sys_command);
7147 defsubr (&Sw32_shell_execute);
7148 defsubr (&Sw32_register_hot_key);
7149 defsubr (&Sw32_unregister_hot_key);
7150 defsubr (&Sw32_registered_hot_keys);
7151 defsubr (&Sw32_reconstruct_hot_key);
7152 defsubr (&Sw32_toggle_lock_key);
7153 defsubr (&Sw32_window_exists_p);
7154 defsubr (&Sw32_battery_status);
7155
7156 defsubr (&Sfile_system_info);
7157 defsubr (&Sdefault_printer_name);
7158
7159 check_window_system_func = check_w32;
7160
7161
7162 hourglass_timer = 0;
7163 hourglass_hwnd = NULL;
7164
7165 defsubr (&Sx_show_tip);
7166 defsubr (&Sx_hide_tip);
7167 tip_timer = Qnil;
7168 staticpro (&tip_timer);
7169 tip_frame = Qnil;
7170 staticpro (&tip_frame);
7171
7172 last_show_tip_args = Qnil;
7173 staticpro (&last_show_tip_args);
7174
7175 defsubr (&Sx_file_dialog);
7176 defsubr (&Ssystem_move_file_to_trash);
7177 }
7178
7179
7180 /*
7181 globals_of_w32fns is used to initialize those global variables that
7182 must always be initialized on startup even when the global variable
7183 initialized is non zero (see the function main in emacs.c).
7184 globals_of_w32fns is called from syms_of_w32fns when the global
7185 variable initialized is 0 and directly from main when initialized
7186 is non zero.
7187 */
7188 void
7189 globals_of_w32fns (void)
7190 {
7191 HMODULE user32_lib = GetModuleHandle ("user32.dll");
7192 /*
7193 TrackMouseEvent not available in all versions of Windows, so must load
7194 it dynamically. Do it once, here, instead of every time it is used.
7195 */
7196 track_mouse_event_fn = (TrackMouseEvent_Proc)
7197 GetProcAddress (user32_lib, "TrackMouseEvent");
7198 /* ditto for GetClipboardSequenceNumber. */
7199 clipboard_sequence_fn = (ClipboardSequence_Proc)
7200 GetProcAddress (user32_lib, "GetClipboardSequenceNumber");
7201
7202 monitor_from_point_fn = (MonitorFromPoint_Proc)
7203 GetProcAddress (user32_lib, "MonitorFromPoint");
7204 get_monitor_info_fn = (GetMonitorInfo_Proc)
7205 GetProcAddress (user32_lib, "GetMonitorInfoA");
7206
7207 {
7208 HMODULE imm32_lib = GetModuleHandle ("imm32.dll");
7209 get_composition_string_fn = (ImmGetCompositionString_Proc)
7210 GetProcAddress (imm32_lib, "ImmGetCompositionStringW");
7211 get_ime_context_fn = (ImmGetContext_Proc)
7212 GetProcAddress (imm32_lib, "ImmGetContext");
7213 release_ime_context_fn = (ImmReleaseContext_Proc)
7214 GetProcAddress (imm32_lib, "ImmReleaseContext");
7215 set_ime_composition_window_fn = (ImmSetCompositionWindow_Proc)
7216 GetProcAddress (imm32_lib, "ImmSetCompositionWindow");
7217 }
7218 DEFVAR_INT ("w32-ansi-code-page",
7219 &w32_ansi_code_page,
7220 doc: /* The ANSI code page used by the system. */);
7221 w32_ansi_code_page = GetACP ();
7222
7223 /* MessageBox does not work without this when linked to comctl32.dll 6.0. */
7224 InitCommonControls ();
7225
7226 syms_of_w32uniscribe ();
7227 }
7228
7229 #undef abort
7230
7231 void
7232 w32_abort (void)
7233 {
7234 int button;
7235 button = MessageBox (NULL,
7236 "A fatal error has occurred!\n\n"
7237 "Would you like to attach a debugger?\n\n"
7238 "Select YES to debug, NO to abort Emacs"
7239 #if __GNUC__
7240 "\n\n(type \"gdb -p <emacs-PID>\" and\n"
7241 "\"continue\" inside GDB before clicking YES.)"
7242 #endif
7243 , "Emacs Abort Dialog",
7244 MB_ICONEXCLAMATION | MB_TASKMODAL
7245 | MB_SETFOREGROUND | MB_YESNO);
7246 switch (button)
7247 {
7248 case IDYES:
7249 DebugBreak ();
7250 exit (2); /* tell the compiler we will never return */
7251 case IDNO:
7252 default:
7253 abort ();
7254 break;
7255 }
7256 }
7257
7258 /* For convenience when debugging. */
7259 int
7260 w32_last_error (void)
7261 {
7262 return GetLastError ();
7263 }
7264
7265 /* arch-tag: 707589ab-b9be-4638-8cdd-74629cc9b446
7266 (do not change this comment) */