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