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