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