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