xref: /vim-8.2.3635/src/gui_w32.c (revision 723d165c)
1 /* vi:set ts=8 sts=4 sw=4 noet:
2  *
3  * VIM - Vi IMproved		by Bram Moolenaar
4  *				GUI support by Robert Webb
5  *
6  * Do ":help uganda"  in Vim to read copying and usage conditions.
7  * Do ":help credits" in Vim to see a list of people who contributed.
8  * See README.txt for an overview of the Vim source code.
9  */
10 /*
11  * Windows GUI.
12  *
13  * GUI support for Microsoft Windows, aka Win32.  Also for Win64.
14  *
15  * George V. Reilly <[email protected]> wrote the original Win32 GUI.
16  * Robert Webb reworked it to use the existing GUI stuff and added menu,
17  * scrollbars, etc.
18  *
19  * Note: Clipboard stuff, for cutting and pasting text to other windows, is in
20  * winclip.c.	(It can also be done from the terminal version).
21  *
22  * TODO: Some of the function signatures ought to be updated for Win64;
23  * e.g., replace LONG with LONG_PTR, etc.
24  */
25 
26 #include "vim.h"
27 
28 #if defined(FEAT_DIRECTX)
29 # include "gui_dwrite.h"
30 #endif
31 
32 #if defined(FEAT_DIRECTX)
33 static DWriteContext *s_dwc = NULL;
34 static int s_directx_enabled = 0;
35 static int s_directx_load_attempted = 0;
36 # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL && enc_utf8)
37 static int directx_enabled(void);
38 static void directx_binddc(void);
39 #endif
40 
41 #ifdef FEAT_MENU
42 static int gui_mswin_get_menu_height(int fix_window);
43 #endif
44 
45 #if defined(FEAT_RENDER_OPTIONS) || defined(PROTO)
46     int
47 gui_mch_set_rendering_options(char_u *s)
48 {
49 # ifdef FEAT_DIRECTX
50     char_u  *p, *q;
51 
52     int	    dx_enable = 0;
53     int	    dx_flags = 0;
54     float   dx_gamma = 0.0f;
55     float   dx_contrast = 0.0f;
56     float   dx_level = 0.0f;
57     int	    dx_geom = 0;
58     int	    dx_renmode = 0;
59     int	    dx_taamode = 0;
60 
61     /* parse string as rendering options. */
62     for (p = s; p != NULL && *p != NUL; )
63     {
64 	char_u  item[256];
65 	char_u  name[128];
66 	char_u  value[128];
67 
68 	copy_option_part(&p, item, sizeof(item), ",");
69 	if (p == NULL)
70 	    break;
71 	q = &item[0];
72 	copy_option_part(&q, name, sizeof(name), ":");
73 	if (q == NULL)
74 	    return FAIL;
75 	copy_option_part(&q, value, sizeof(value), ":");
76 
77 	if (STRCMP(name, "type") == 0)
78 	{
79 	    if (STRCMP(value, "directx") == 0)
80 		dx_enable = 1;
81 	    else
82 		return FAIL;
83 	}
84 	else if (STRCMP(name, "gamma") == 0)
85 	{
86 	    dx_flags |= 1 << 0;
87 	    dx_gamma = (float)atof((char *)value);
88 	}
89 	else if (STRCMP(name, "contrast") == 0)
90 	{
91 	    dx_flags |= 1 << 1;
92 	    dx_contrast = (float)atof((char *)value);
93 	}
94 	else if (STRCMP(name, "level") == 0)
95 	{
96 	    dx_flags |= 1 << 2;
97 	    dx_level = (float)atof((char *)value);
98 	}
99 	else if (STRCMP(name, "geom") == 0)
100 	{
101 	    dx_flags |= 1 << 3;
102 	    dx_geom = atoi((char *)value);
103 	    if (dx_geom < 0 || dx_geom > 2)
104 		return FAIL;
105 	}
106 	else if (STRCMP(name, "renmode") == 0)
107 	{
108 	    dx_flags |= 1 << 4;
109 	    dx_renmode = atoi((char *)value);
110 	    if (dx_renmode < 0 || dx_renmode > 6)
111 		return FAIL;
112 	}
113 	else if (STRCMP(name, "taamode") == 0)
114 	{
115 	    dx_flags |= 1 << 5;
116 	    dx_taamode = atoi((char *)value);
117 	    if (dx_taamode < 0 || dx_taamode > 3)
118 		return FAIL;
119 	}
120 	else if (STRCMP(name, "scrlines") == 0)
121 	{
122 	    /* Deprecated.  Simply ignore it. */
123 	}
124 	else
125 	    return FAIL;
126     }
127 
128     if (!gui.in_use)
129 	return OK;  /* only checking the syntax of the value */
130 
131     /* Enable DirectX/DirectWrite */
132     if (dx_enable)
133     {
134 	if (!directx_enabled())
135 	    return FAIL;
136 	DWriteContext_SetRenderingParams(s_dwc, NULL);
137 	if (dx_flags)
138 	{
139 	    DWriteRenderingParams param;
140 	    DWriteContext_GetRenderingParams(s_dwc, &param);
141 	    if (dx_flags & (1 << 0))
142 		param.gamma = dx_gamma;
143 	    if (dx_flags & (1 << 1))
144 		param.enhancedContrast = dx_contrast;
145 	    if (dx_flags & (1 << 2))
146 		param.clearTypeLevel = dx_level;
147 	    if (dx_flags & (1 << 3))
148 		param.pixelGeometry = dx_geom;
149 	    if (dx_flags & (1 << 4))
150 		param.renderingMode = dx_renmode;
151 	    if (dx_flags & (1 << 5))
152 		param.textAntialiasMode = dx_taamode;
153 	    DWriteContext_SetRenderingParams(s_dwc, &param);
154 	}
155     }
156     s_directx_enabled = dx_enable;
157 
158     return OK;
159 # else
160     return FAIL;
161 # endif
162 }
163 #endif
164 
165 /*
166  * These are new in Windows ME/XP, only defined in recent compilers.
167  */
168 #ifndef HANDLE_WM_XBUTTONUP
169 # define HANDLE_WM_XBUTTONUP(hwnd, wParam, lParam, fn) \
170    ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
171 #endif
172 #ifndef HANDLE_WM_XBUTTONDOWN
173 # define HANDLE_WM_XBUTTONDOWN(hwnd, wParam, lParam, fn) \
174    ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
175 #endif
176 #ifndef HANDLE_WM_XBUTTONDBLCLK
177 # define HANDLE_WM_XBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
178    ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
179 #endif
180 
181 
182 #include "version.h"	/* used by dialog box routine for default title */
183 #ifdef DEBUG
184 # include <tchar.h>
185 #endif
186 
187 /* cproto fails on missing include files */
188 #ifndef PROTO
189 
190 #ifndef __MINGW32__
191 # include <shellapi.h>
192 #endif
193 #if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL_GUI) || defined(FEAT_GUI_TABLINE)
194 # include <commctrl.h>
195 #endif
196 #include <windowsx.h>
197 
198 #ifdef GLOBAL_IME
199 # include "glbl_ime.h"
200 #endif
201 
202 #endif /* PROTO */
203 
204 #ifdef FEAT_MENU
205 # define MENUHINTS		/* show menu hints in command line */
206 #endif
207 
208 /* Some parameters for dialog boxes.  All in pixels. */
209 #define DLG_PADDING_X		10
210 #define DLG_PADDING_Y		10
211 #define DLG_OLD_STYLE_PADDING_X	5
212 #define DLG_OLD_STYLE_PADDING_Y	5
213 #define DLG_VERT_PADDING_X	4	/* For vertical buttons */
214 #define DLG_VERT_PADDING_Y	4
215 #define DLG_ICON_WIDTH		34
216 #define DLG_ICON_HEIGHT		34
217 #define DLG_MIN_WIDTH		150
218 #define DLG_FONT_NAME		"MS Sans Serif"
219 #define DLG_FONT_POINT_SIZE	8
220 #define DLG_MIN_MAX_WIDTH	400
221 #define DLG_MIN_MAX_HEIGHT	400
222 
223 #define DLG_NONBUTTON_CONTROL	5000	/* First ID of non-button controls */
224 
225 #ifndef WM_XBUTTONDOWN /* For Win2K / winME ONLY */
226 # define WM_XBUTTONDOWN		0x020B
227 # define WM_XBUTTONUP		0x020C
228 # define WM_XBUTTONDBLCLK	0x020D
229 # define MK_XBUTTON1		0x0020
230 # define MK_XBUTTON2		0x0040
231 #endif
232 
233 #ifdef PROTO
234 /*
235  * Define a few things for generating prototypes.  This is just to avoid
236  * syntax errors, the defines do not need to be correct.
237  */
238 # define APIENTRY
239 # define CALLBACK
240 # define CONST
241 # define FAR
242 # define NEAR
243 # undef _cdecl
244 # define _cdecl
245 typedef int BOOL;
246 typedef int BYTE;
247 typedef int DWORD;
248 typedef int WCHAR;
249 typedef int ENUMLOGFONT;
250 typedef int FINDREPLACE;
251 typedef int HANDLE;
252 typedef int HBITMAP;
253 typedef int HBRUSH;
254 typedef int HDROP;
255 typedef int INT;
256 typedef int LOGFONT[];
257 typedef int LPARAM;
258 typedef int LPCREATESTRUCT;
259 typedef int LPCSTR;
260 typedef int LPCTSTR;
261 typedef int LPRECT;
262 typedef int LPSTR;
263 typedef int LPWINDOWPOS;
264 typedef int LPWORD;
265 typedef int LRESULT;
266 typedef int HRESULT;
267 # undef MSG
268 typedef int MSG;
269 typedef int NEWTEXTMETRIC;
270 typedef int OSVERSIONINFO;
271 typedef int PWORD;
272 typedef int RECT;
273 typedef int UINT;
274 typedef int WORD;
275 typedef int WPARAM;
276 typedef int POINT;
277 typedef void *HINSTANCE;
278 typedef void *HMENU;
279 typedef void *HWND;
280 typedef void *HDC;
281 typedef void VOID;
282 typedef int LPNMHDR;
283 typedef int LONG;
284 typedef int WNDPROC;
285 typedef int UINT_PTR;
286 typedef int COLORREF;
287 typedef int HCURSOR;
288 #endif
289 
290 #ifndef GET_X_LPARAM
291 # define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
292 #endif
293 
294 static void _OnPaint( HWND hwnd);
295 static void fill_rect(const RECT *rcp, HBRUSH hbr, COLORREF color);
296 static void clear_rect(RECT *rcp);
297 
298 static WORD		s_dlgfntheight;		/* height of the dialog font */
299 static WORD		s_dlgfntwidth;		/* width of the dialog font */
300 
301 #ifdef FEAT_MENU
302 static HMENU		s_menuBar = NULL;
303 #endif
304 #ifdef FEAT_TEAROFF
305 static void rebuild_tearoff(vimmenu_T *menu);
306 static HBITMAP	s_htearbitmap;	    /* bitmap used to indicate tearoff */
307 #endif
308 
309 /* Flag that is set while processing a message that must not be interrupted by
310  * processing another message. */
311 static int		s_busy_processing = FALSE;
312 
313 static int		destroying = FALSE;	/* call DestroyWindow() ourselves */
314 
315 #ifdef MSWIN_FIND_REPLACE
316 static UINT		s_findrep_msg = 0;	/* set in gui_w[16/32].c */
317 static FINDREPLACE	s_findrep_struct;
318 static FINDREPLACEW	s_findrep_struct_w;
319 static HWND		s_findrep_hwnd = NULL;
320 static int		s_findrep_is_find;	/* TRUE for find dialog, FALSE
321 						   for find/replace dialog */
322 #endif
323 
324 static HINSTANCE	s_hinst = NULL;
325 #if !defined(FEAT_GUI)
326 static
327 #endif
328 HWND			s_hwnd = NULL;
329 static HDC		s_hdc = NULL;
330 static HBRUSH	s_brush = NULL;
331 
332 #ifdef FEAT_TOOLBAR
333 static HWND		s_toolbarhwnd = NULL;
334 static WNDPROC		s_toolbar_wndproc = NULL;
335 #endif
336 
337 #ifdef FEAT_GUI_TABLINE
338 static HWND		s_tabhwnd = NULL;
339 static WNDPROC		s_tabline_wndproc = NULL;
340 static int		showing_tabline = 0;
341 #endif
342 
343 static WPARAM		s_wParam = 0;
344 static LPARAM		s_lParam = 0;
345 
346 static HWND		s_textArea = NULL;
347 static UINT		s_uMsg = 0;
348 
349 static char_u		*s_textfield; /* Used by dialogs to pass back strings */
350 
351 static int		s_need_activate = FALSE;
352 
353 /* This variable is set when waiting for an event, which is the only moment
354  * scrollbar dragging can be done directly.  It's not allowed while commands
355  * are executed, because it may move the cursor and that may cause unexpected
356  * problems (e.g., while ":s" is working).
357  */
358 static int allow_scrollbar = FALSE;
359 
360 #ifdef GLOBAL_IME
361 # define MyTranslateMessage(x) global_ime_TranslateMessage(x)
362 #else
363 # define MyTranslateMessage(x) TranslateMessage(x)
364 #endif
365 
366 #if defined(FEAT_DIRECTX)
367     static int
368 directx_enabled(void)
369 {
370     if (s_dwc != NULL)
371 	return 1;
372     else if (s_directx_load_attempted)
373 	return 0;
374     /* load DirectX */
375     DWrite_Init();
376     s_directx_load_attempted = 1;
377     s_dwc = DWriteContext_Open();
378     directx_binddc();
379     return s_dwc != NULL ? 1 : 0;
380 }
381 
382     static void
383 directx_binddc(void)
384 {
385     if (s_textArea != NULL)
386     {
387 	RECT	rect;
388 	GetClientRect(s_textArea, &rect);
389 	DWriteContext_BindDC(s_dwc, s_hdc, &rect);
390     }
391 }
392 #endif
393 
394 /* use of WindowProc depends on wide_WindowProc */
395 #define MyWindowProc vim_WindowProc
396 
397 extern int current_font_height;	    /* this is in os_mswin.c */
398 
399 static struct
400 {
401     UINT    key_sym;
402     char_u  vim_code0;
403     char_u  vim_code1;
404 } special_keys[] =
405 {
406     {VK_UP,		'k', 'u'},
407     {VK_DOWN,		'k', 'd'},
408     {VK_LEFT,		'k', 'l'},
409     {VK_RIGHT,		'k', 'r'},
410 
411     {VK_F1,		'k', '1'},
412     {VK_F2,		'k', '2'},
413     {VK_F3,		'k', '3'},
414     {VK_F4,		'k', '4'},
415     {VK_F5,		'k', '5'},
416     {VK_F6,		'k', '6'},
417     {VK_F7,		'k', '7'},
418     {VK_F8,		'k', '8'},
419     {VK_F9,		'k', '9'},
420     {VK_F10,		'k', ';'},
421 
422     {VK_F11,		'F', '1'},
423     {VK_F12,		'F', '2'},
424     {VK_F13,		'F', '3'},
425     {VK_F14,		'F', '4'},
426     {VK_F15,		'F', '5'},
427     {VK_F16,		'F', '6'},
428     {VK_F17,		'F', '7'},
429     {VK_F18,		'F', '8'},
430     {VK_F19,		'F', '9'},
431     {VK_F20,		'F', 'A'},
432 
433     {VK_F21,		'F', 'B'},
434 #ifdef FEAT_NETBEANS_INTG
435     {VK_PAUSE,		'F', 'B'},	/* Pause == F21 (see gui_gtk_x11.c) */
436 #endif
437     {VK_F22,		'F', 'C'},
438     {VK_F23,		'F', 'D'},
439     {VK_F24,		'F', 'E'},	/* winuser.h defines up to F24 */
440 
441     {VK_HELP,		'%', '1'},
442     {VK_BACK,		'k', 'b'},
443     {VK_INSERT,		'k', 'I'},
444     {VK_DELETE,		'k', 'D'},
445     {VK_HOME,		'k', 'h'},
446     {VK_END,		'@', '7'},
447     {VK_PRIOR,		'k', 'P'},
448     {VK_NEXT,		'k', 'N'},
449     {VK_PRINT,		'%', '9'},
450     {VK_ADD,		'K', '6'},
451     {VK_SUBTRACT,	'K', '7'},
452     {VK_DIVIDE,		'K', '8'},
453     {VK_MULTIPLY,	'K', '9'},
454     {VK_SEPARATOR,	'K', 'A'},	/* Keypad Enter */
455     {VK_DECIMAL,	'K', 'B'},
456 
457     {VK_NUMPAD0,	'K', 'C'},
458     {VK_NUMPAD1,	'K', 'D'},
459     {VK_NUMPAD2,	'K', 'E'},
460     {VK_NUMPAD3,	'K', 'F'},
461     {VK_NUMPAD4,	'K', 'G'},
462     {VK_NUMPAD5,	'K', 'H'},
463     {VK_NUMPAD6,	'K', 'I'},
464     {VK_NUMPAD7,	'K', 'J'},
465     {VK_NUMPAD8,	'K', 'K'},
466     {VK_NUMPAD9,	'K', 'L'},
467 
468     /* Keys that we want to be able to use any modifier with: */
469     {VK_SPACE,		' ', NUL},
470     {VK_TAB,		TAB, NUL},
471     {VK_ESCAPE,		ESC, NUL},
472     {NL,		NL, NUL},
473     {CAR,		CAR, NUL},
474 
475     /* End of list marker: */
476     {0,			0, 0}
477 };
478 
479 /* Local variables */
480 static int	s_button_pending = -1;
481 
482 /* s_getting_focus is set when we got focus but didn't see mouse-up event yet,
483  * so don't reset s_button_pending. */
484 static int	s_getting_focus = FALSE;
485 
486 static int	s_x_pending;
487 static int	s_y_pending;
488 static UINT	s_kFlags_pending;
489 static UINT	s_wait_timer = 0;	  // Timer for get char from user
490 static int	s_timed_out = FALSE;
491 static int	dead_key = 0;		  // 0: no dead key, 1: dead key pressed
492 static UINT	surrogate_pending_ch = 0; // 0: no surrogate pending,
493 					  // else a high surrogate
494 
495 #ifdef FEAT_BEVAL_GUI
496 /* balloon-eval WM_NOTIFY_HANDLER */
497 static void Handle_WM_Notify(HWND hwnd, LPNMHDR pnmh);
498 static void TrackUserActivity(UINT uMsg);
499 #endif
500 
501 /*
502  * For control IME.
503  *
504  * These LOGFONT used for IME.
505  */
506 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
507 /* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */
508 static LOGFONT norm_logfont;
509 #endif
510 #ifdef FEAT_MBYTE_IME
511 /* holds LOGFONT for 'guifont' always. */
512 static LOGFONT sub_logfont;
513 #endif
514 
515 #ifdef FEAT_MBYTE_IME
516 static LRESULT _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData);
517 #endif
518 
519 #if defined(FEAT_BROWSE)
520 static char_u *convert_filter(char_u *s);
521 #endif
522 
523 #ifdef DEBUG_PRINT_ERROR
524 /*
525  * Print out the last Windows error message
526  */
527     static void
528 print_windows_error(void)
529 {
530     LPVOID  lpMsgBuf;
531 
532     FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
533 		  NULL, GetLastError(),
534 		  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
535 		  (LPTSTR) &lpMsgBuf, 0, NULL);
536     TRACE1("Error: %s\n", lpMsgBuf);
537     LocalFree(lpMsgBuf);
538 }
539 #endif
540 
541 /*
542  * Cursor blink functions.
543  *
544  * This is a simple state machine:
545  * BLINK_NONE	not blinking at all
546  * BLINK_OFF	blinking, cursor is not shown
547  * BLINK_ON	blinking, cursor is shown
548  */
549 
550 #define BLINK_NONE  0
551 #define BLINK_OFF   1
552 #define BLINK_ON    2
553 
554 static int		blink_state = BLINK_NONE;
555 static long_u		blink_waittime = 700;
556 static long_u		blink_ontime = 400;
557 static long_u		blink_offtime = 250;
558 static UINT		blink_timer = 0;
559 
560     int
561 gui_mch_is_blinking(void)
562 {
563     return blink_state != BLINK_NONE;
564 }
565 
566     int
567 gui_mch_is_blink_off(void)
568 {
569     return blink_state == BLINK_OFF;
570 }
571 
572     void
573 gui_mch_set_blinking(long wait, long on, long off)
574 {
575     blink_waittime = wait;
576     blink_ontime = on;
577     blink_offtime = off;
578 }
579 
580     static VOID CALLBACK
581 _OnBlinkTimer(
582     HWND hwnd,
583     UINT uMsg UNUSED,
584     UINT idEvent,
585     DWORD dwTime UNUSED)
586 {
587     MSG msg;
588 
589     /*
590     TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
591     */
592 
593     KillTimer(NULL, idEvent);
594 
595     /* Eat spurious WM_TIMER messages */
596     while (pPeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
597 	;
598 
599     if (blink_state == BLINK_ON)
600     {
601 	gui_undraw_cursor();
602 	blink_state = BLINK_OFF;
603 	blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_offtime,
604 						    (TIMERPROC)_OnBlinkTimer);
605     }
606     else
607     {
608 	gui_update_cursor(TRUE, FALSE);
609 	blink_state = BLINK_ON;
610 	blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime,
611 						    (TIMERPROC)_OnBlinkTimer);
612     }
613     gui_mch_flush();
614 }
615 
616     static void
617 gui_mswin_rm_blink_timer(void)
618 {
619     MSG msg;
620 
621     if (blink_timer != 0)
622     {
623 	KillTimer(NULL, blink_timer);
624 	/* Eat spurious WM_TIMER messages */
625 	while (pPeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
626 	    ;
627 	blink_timer = 0;
628     }
629 }
630 
631 /*
632  * Stop the cursor blinking.  Show the cursor if it wasn't shown.
633  */
634     void
635 gui_mch_stop_blink(int may_call_gui_update_cursor)
636 {
637     gui_mswin_rm_blink_timer();
638     if (blink_state == BLINK_OFF && may_call_gui_update_cursor)
639     {
640 	gui_update_cursor(TRUE, FALSE);
641 	gui_mch_flush();
642     }
643     blink_state = BLINK_NONE;
644 }
645 
646 /*
647  * Start the cursor blinking.  If it was already blinking, this restarts the
648  * waiting time and shows the cursor.
649  */
650     void
651 gui_mch_start_blink(void)
652 {
653     gui_mswin_rm_blink_timer();
654 
655     /* Only switch blinking on if none of the times is zero */
656     if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus)
657     {
658 	blink_timer = (UINT)SetTimer(NULL, 0, (UINT)blink_waittime,
659 						    (TIMERPROC)_OnBlinkTimer);
660 	blink_state = BLINK_ON;
661 	gui_update_cursor(TRUE, FALSE);
662 	gui_mch_flush();
663     }
664 }
665 
666 /*
667  * Call-back routines.
668  */
669 
670     static VOID CALLBACK
671 _OnTimer(
672     HWND hwnd,
673     UINT uMsg UNUSED,
674     UINT idEvent,
675     DWORD dwTime UNUSED)
676 {
677     MSG msg;
678 
679     /*
680     TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
681     */
682     KillTimer(NULL, idEvent);
683     s_timed_out = TRUE;
684 
685     /* Eat spurious WM_TIMER messages */
686     while (pPeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
687 	;
688     if (idEvent == s_wait_timer)
689 	s_wait_timer = 0;
690 }
691 
692     static void
693 _OnDeadChar(
694     HWND hwnd UNUSED,
695     UINT ch UNUSED,
696     int cRepeat UNUSED)
697 {
698     dead_key = 1;
699 }
700 
701 /*
702  * Convert Unicode character "ch" to bytes in "string[slen]".
703  * When "had_alt" is TRUE the ALT key was included in "ch".
704  * Return the length.
705  * Because the Windows API uses UTF-16, we have to deal with surrogate
706  * pairs; this is where we choose to deal with them: if "ch" is a high
707  * surrogate, it will be stored, and the length returned will be zero; the next
708  * char_to_string call will then include the high surrogate, decoding the pair
709  * of UTF-16 code units to a single Unicode code point, presuming it is the
710  * matching low surrogate.
711  */
712     static int
713 char_to_string(int ch, char_u *string, int slen, int had_alt)
714 {
715     int		len;
716     int		i;
717     WCHAR	wstring[2];
718     char_u	*ws = NULL;
719 
720     if (surrogate_pending_ch != 0)
721     {
722 	/* We don't guarantee ch is a low surrogate to match the high surrogate
723 	 * we already have; it should be, but if it isn't, tough luck. */
724 	wstring[0] = surrogate_pending_ch;
725 	wstring[1] = ch;
726 	surrogate_pending_ch = 0;
727 	len = 2;
728     }
729     else if (ch >= 0xD800 && ch <= 0xDBFF)	/* high surrogate */
730     {
731 	/* We don't have the entire code point yet, only the first UTF-16 code
732 	 * unit; so just remember it and use it in the next call. */
733 	surrogate_pending_ch = ch;
734 	return 0;
735     }
736     else
737     {
738 	wstring[0] = ch;
739 	len = 1;
740     }
741 
742     /* "ch" is a UTF-16 character.  Convert it to a string of bytes.  When
743      * "enc_codepage" is non-zero use the standard Win32 function,
744      * otherwise use our own conversion function (e.g., for UTF-8). */
745     if (enc_codepage > 0)
746     {
747 	len = WideCharToMultiByte(enc_codepage, 0, wstring, len,
748 		(LPSTR)string, slen, 0, NULL);
749 	/* If we had included the ALT key into the character but now the
750 	 * upper bit is no longer set, that probably means the conversion
751 	 * failed.  Convert the original character and set the upper bit
752 	 * afterwards. */
753 	if (had_alt && len == 1 && ch >= 0x80 && string[0] < 0x80)
754 	{
755 	    wstring[0] = ch & 0x7f;
756 	    len = WideCharToMultiByte(enc_codepage, 0, wstring, len,
757 		    (LPSTR)string, slen, 0, NULL);
758 	    if (len == 1) /* safety check */
759 		string[0] |= 0x80;
760 	}
761     }
762     else
763     {
764 	ws = utf16_to_enc(wstring, &len);
765 	if (ws == NULL)
766 	    len = 0;
767 	else
768 	{
769 	    if (len > slen)	/* just in case */
770 		len = slen;
771 	    mch_memmove(string, ws, len);
772 	    vim_free(ws);
773 	}
774     }
775 
776     if (len == 0)
777     {
778 	string[0] = ch;
779 	len = 1;
780     }
781 
782     for (i = 0; i < len; ++i)
783 	if (string[i] == CSI && len <= slen - 2)
784 	{
785 	    /* Insert CSI as K_CSI. */
786 	    mch_memmove(string + i + 3, string + i + 1, len - i - 1);
787 	    string[++i] = KS_EXTRA;
788 	    string[++i] = (int)KE_CSI;
789 	    len += 2;
790 	}
791 
792     return len;
793 }
794 
795 /*
796  * Key hit, add it to the input buffer.
797  */
798     static void
799 _OnChar(
800     HWND hwnd UNUSED,
801     UINT ch,
802     int cRepeat UNUSED)
803 {
804     char_u	string[40];
805     int		len = 0;
806 
807     dead_key = 0;
808 
809     len = char_to_string(ch, string, 40, FALSE);
810     if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts)
811     {
812 	trash_input_buf();
813 	got_int = TRUE;
814     }
815 
816     add_to_input_buf(string, len);
817 }
818 
819 /*
820  * Alt-Key hit, add it to the input buffer.
821  */
822     static void
823 _OnSysChar(
824     HWND hwnd UNUSED,
825     UINT cch,
826     int cRepeat UNUSED)
827 {
828     char_u	string[40]; /* Enough for multibyte character */
829     int		len;
830     int		modifiers;
831     int		ch = cch;   /* special keys are negative */
832 
833     dead_key = 0;
834 
835     /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
836 
837     /* OK, we have a character key (given by ch) which was entered with the
838      * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
839      * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
840      * CAPSLOCK is pressed) at this point.
841      */
842     modifiers = MOD_MASK_ALT;
843     if (GetKeyState(VK_SHIFT) & 0x8000)
844 	modifiers |= MOD_MASK_SHIFT;
845     if (GetKeyState(VK_CONTROL) & 0x8000)
846 	modifiers |= MOD_MASK_CTRL;
847 
848     ch = simplify_key(ch, &modifiers);
849     /* remove the SHIFT modifier for keys where it's already included, e.g.,
850      * '(' and '*' */
851     if (ch < 0x100 && !isalpha(ch) && isprint(ch))
852 	modifiers &= ~MOD_MASK_SHIFT;
853 
854     /* Interpret the ALT key as making the key META, include SHIFT, etc. */
855     ch = extract_modifiers(ch, &modifiers);
856     if (ch == CSI)
857 	ch = K_CSI;
858 
859     len = 0;
860     if (modifiers)
861     {
862 	string[len++] = CSI;
863 	string[len++] = KS_MODIFIER;
864 	string[len++] = modifiers;
865     }
866 
867     if (IS_SPECIAL((int)ch))
868     {
869 	string[len++] = CSI;
870 	string[len++] = K_SECOND((int)ch);
871 	string[len++] = K_THIRD((int)ch);
872     }
873     else
874     {
875 	/* Although the documentation isn't clear about it, we assume "ch" is
876 	 * a Unicode character. */
877 	len += char_to_string(ch, string + len, 40 - len, TRUE);
878     }
879 
880     add_to_input_buf(string, len);
881 }
882 
883     static void
884 _OnMouseEvent(
885     int button,
886     int x,
887     int y,
888     int repeated_click,
889     UINT keyFlags)
890 {
891     int vim_modifiers = 0x0;
892 
893     s_getting_focus = FALSE;
894 
895     if (keyFlags & MK_SHIFT)
896 	vim_modifiers |= MOUSE_SHIFT;
897     if (keyFlags & MK_CONTROL)
898 	vim_modifiers |= MOUSE_CTRL;
899     if (GetKeyState(VK_MENU) & 0x8000)
900 	vim_modifiers |= MOUSE_ALT;
901 
902     gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers);
903 }
904 
905     static void
906 _OnMouseButtonDown(
907     HWND hwnd UNUSED,
908     BOOL fDoubleClick UNUSED,
909     int x,
910     int y,
911     UINT keyFlags)
912 {
913     static LONG	s_prevTime = 0;
914 
915     LONG    currentTime = GetMessageTime();
916     int	    button = -1;
917     int	    repeated_click;
918 
919     /* Give main window the focus: this is so the cursor isn't hollow. */
920     (void)SetFocus(s_hwnd);
921 
922     if (s_uMsg == WM_LBUTTONDOWN || s_uMsg == WM_LBUTTONDBLCLK)
923 	button = MOUSE_LEFT;
924     else if (s_uMsg == WM_MBUTTONDOWN || s_uMsg == WM_MBUTTONDBLCLK)
925 	button = MOUSE_MIDDLE;
926     else if (s_uMsg == WM_RBUTTONDOWN || s_uMsg == WM_RBUTTONDBLCLK)
927 	button = MOUSE_RIGHT;
928     else if (s_uMsg == WM_XBUTTONDOWN || s_uMsg == WM_XBUTTONDBLCLK)
929     {
930 #ifndef GET_XBUTTON_WPARAM
931 # define GET_XBUTTON_WPARAM(wParam)	(HIWORD(wParam))
932 #endif
933 	button = ((GET_XBUTTON_WPARAM(s_wParam) == 1) ? MOUSE_X1 : MOUSE_X2);
934     }
935     else if (s_uMsg == WM_CAPTURECHANGED)
936     {
937 	/* on W95/NT4, somehow you get in here with an odd Msg
938 	 * if you press one button while holding down the other..*/
939 	if (s_button_pending == MOUSE_LEFT)
940 	    button = MOUSE_RIGHT;
941 	else
942 	    button = MOUSE_LEFT;
943     }
944     if (button >= 0)
945     {
946 	repeated_click = ((int)(currentTime - s_prevTime) < p_mouset);
947 
948 	/*
949 	 * Holding down the left and right buttons simulates pushing the middle
950 	 * button.
951 	 */
952 	if (repeated_click
953 		&& ((button == MOUSE_LEFT && s_button_pending == MOUSE_RIGHT)
954 		    || (button == MOUSE_RIGHT
955 					  && s_button_pending == MOUSE_LEFT)))
956 	{
957 	    /*
958 	     * Hmm, gui.c will ignore more than one button down at a time, so
959 	     * pretend we let go of it first.
960 	     */
961 	    gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, 0x0);
962 	    button = MOUSE_MIDDLE;
963 	    repeated_click = FALSE;
964 	    s_button_pending = -1;
965 	    _OnMouseEvent(button, x, y, repeated_click, keyFlags);
966 	}
967 	else if ((repeated_click)
968 		|| (mouse_model_popup() && (button == MOUSE_RIGHT)))
969 	{
970 	    if (s_button_pending > -1)
971 	    {
972 		    _OnMouseEvent(s_button_pending, x, y, FALSE, keyFlags);
973 		    s_button_pending = -1;
974 	    }
975 	    /* TRACE("Button down at x %d, y %d\n", x, y); */
976 	    _OnMouseEvent(button, x, y, repeated_click, keyFlags);
977 	}
978 	else
979 	{
980 	    /*
981 	     * If this is the first press (i.e. not a multiple click) don't
982 	     * action immediately, but store and wait for:
983 	     * i) button-up
984 	     * ii) mouse move
985 	     * iii) another button press
986 	     * before using it.
987 	     * This enables us to make left+right simulate middle button,
988 	     * without left or right being actioned first.  The side-effect is
989 	     * that if you click and hold the mouse without dragging, the
990 	     * cursor doesn't move until you release the button. In practice
991 	     * this is hardly a problem.
992 	     */
993 	    s_button_pending = button;
994 	    s_x_pending = x;
995 	    s_y_pending = y;
996 	    s_kFlags_pending = keyFlags;
997 	}
998 
999 	s_prevTime = currentTime;
1000     }
1001 }
1002 
1003     static void
1004 _OnMouseMoveOrRelease(
1005     HWND hwnd UNUSED,
1006     int x,
1007     int y,
1008     UINT keyFlags)
1009 {
1010     int button;
1011 
1012     s_getting_focus = FALSE;
1013     if (s_button_pending > -1)
1014     {
1015 	/* Delayed action for mouse down event */
1016 	_OnMouseEvent(s_button_pending, s_x_pending,
1017 					s_y_pending, FALSE, s_kFlags_pending);
1018 	s_button_pending = -1;
1019     }
1020     if (s_uMsg == WM_MOUSEMOVE)
1021     {
1022 	/*
1023 	 * It's only a MOUSE_DRAG if one or more mouse buttons are being held
1024 	 * down.
1025 	 */
1026 	if (!(keyFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON
1027 						| MK_XBUTTON1 | MK_XBUTTON2)))
1028 	{
1029 	    gui_mouse_moved(x, y);
1030 	    return;
1031 	}
1032 
1033 	/*
1034 	 * While button is down, keep grabbing mouse move events when
1035 	 * the mouse goes outside the window
1036 	 */
1037 	SetCapture(s_textArea);
1038 	button = MOUSE_DRAG;
1039 	/* TRACE("  move at x %d, y %d\n", x, y); */
1040     }
1041     else
1042     {
1043 	ReleaseCapture();
1044 	button = MOUSE_RELEASE;
1045 	/* TRACE("  up at x %d, y %d\n", x, y); */
1046     }
1047 
1048     _OnMouseEvent(button, x, y, FALSE, keyFlags);
1049 }
1050 
1051     static void
1052 _OnSizeTextArea(
1053     HWND hwnd UNUSED,
1054     UINT state UNUSED,
1055     int cx UNUSED,
1056     int cy UNUSED)
1057 {
1058 #if defined(FEAT_DIRECTX)
1059     if (IS_ENABLE_DIRECTX())
1060 	directx_binddc();
1061 #endif
1062 }
1063 
1064 #ifdef FEAT_MENU
1065 /*
1066  * Find the vimmenu_T with the given id
1067  */
1068     static vimmenu_T *
1069 gui_mswin_find_menu(
1070     vimmenu_T	*pMenu,
1071     int		id)
1072 {
1073     vimmenu_T	*pChildMenu;
1074 
1075     while (pMenu)
1076     {
1077 	if (pMenu->id == (UINT)id)
1078 	    break;
1079 	if (pMenu->children != NULL)
1080 	{
1081 	    pChildMenu = gui_mswin_find_menu(pMenu->children, id);
1082 	    if (pChildMenu)
1083 	    {
1084 		pMenu = pChildMenu;
1085 		break;
1086 	    }
1087 	}
1088 	pMenu = pMenu->next;
1089     }
1090     return pMenu;
1091 }
1092 
1093     static void
1094 _OnMenu(
1095     HWND	hwnd UNUSED,
1096     int		id,
1097     HWND	hwndCtl UNUSED,
1098     UINT	codeNotify UNUSED)
1099 {
1100     vimmenu_T	*pMenu;
1101 
1102     pMenu = gui_mswin_find_menu(root_menu, id);
1103     if (pMenu)
1104 	gui_menu_cb(pMenu);
1105 }
1106 #endif
1107 
1108 #ifdef MSWIN_FIND_REPLACE
1109 /*
1110  * copy useful data from structure LPFINDREPLACE to structure LPFINDREPLACEW
1111  */
1112     static void
1113 findrep_atow(LPFINDREPLACEW lpfrw, LPFINDREPLACE lpfr)
1114 {
1115     WCHAR *wp;
1116 
1117     lpfrw->hwndOwner = lpfr->hwndOwner;
1118     lpfrw->Flags = lpfr->Flags;
1119 
1120     wp = enc_to_utf16((char_u *)lpfr->lpstrFindWhat, NULL);
1121     wcsncpy(lpfrw->lpstrFindWhat, wp, lpfrw->wFindWhatLen - 1);
1122     vim_free(wp);
1123 
1124     /* the field "lpstrReplaceWith" doesn't need to be copied */
1125 }
1126 
1127 /*
1128  * copy useful data from structure LPFINDREPLACEW to structure LPFINDREPLACE
1129  */
1130     static void
1131 findrep_wtoa(LPFINDREPLACE lpfr, LPFINDREPLACEW lpfrw)
1132 {
1133     char_u *p;
1134 
1135     lpfr->Flags = lpfrw->Flags;
1136 
1137     p = utf16_to_enc((short_u*)lpfrw->lpstrFindWhat, NULL);
1138     vim_strncpy((char_u *)lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1);
1139     vim_free(p);
1140 
1141     p = utf16_to_enc((short_u*)lpfrw->lpstrReplaceWith, NULL);
1142     vim_strncpy((char_u *)lpfr->lpstrReplaceWith, p, lpfr->wReplaceWithLen - 1);
1143     vim_free(p);
1144 }
1145 
1146 /*
1147  * Handle a Find/Replace window message.
1148  */
1149     static void
1150 _OnFindRepl(void)
1151 {
1152     int	    flags = 0;
1153     int	    down;
1154 
1155     /* If the OS is Windows NT, and 'encoding' differs from active codepage:
1156      * convert text from wide string. */
1157     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
1158     {
1159 	findrep_wtoa(&s_findrep_struct, &s_findrep_struct_w);
1160     }
1161 
1162     if (s_findrep_struct.Flags & FR_DIALOGTERM)
1163 	/* Give main window the focus back. */
1164 	(void)SetFocus(s_hwnd);
1165 
1166     if (s_findrep_struct.Flags & FR_FINDNEXT)
1167     {
1168 	flags = FRD_FINDNEXT;
1169 
1170 	/* Give main window the focus back: this is so the cursor isn't
1171 	 * hollow. */
1172 	(void)SetFocus(s_hwnd);
1173     }
1174     else if (s_findrep_struct.Flags & FR_REPLACE)
1175     {
1176 	flags = FRD_REPLACE;
1177 
1178 	/* Give main window the focus back: this is so the cursor isn't
1179 	 * hollow. */
1180 	(void)SetFocus(s_hwnd);
1181     }
1182     else if (s_findrep_struct.Flags & FR_REPLACEALL)
1183     {
1184 	flags = FRD_REPLACEALL;
1185     }
1186 
1187     if (flags != 0)
1188     {
1189 	/* Call the generic GUI function to do the actual work. */
1190 	if (s_findrep_struct.Flags & FR_WHOLEWORD)
1191 	    flags |= FRD_WHOLE_WORD;
1192 	if (s_findrep_struct.Flags & FR_MATCHCASE)
1193 	    flags |= FRD_MATCH_CASE;
1194 	down = (s_findrep_struct.Flags & FR_DOWN) != 0;
1195 	gui_do_findrepl(flags, (char_u *)s_findrep_struct.lpstrFindWhat,
1196 			     (char_u *)s_findrep_struct.lpstrReplaceWith, down);
1197     }
1198 }
1199 #endif
1200 
1201     static void
1202 HandleMouseHide(UINT uMsg, LPARAM lParam)
1203 {
1204     static LPARAM last_lParam = 0L;
1205 
1206     /* We sometimes get a mousemove when the mouse didn't move... */
1207     if (uMsg == WM_MOUSEMOVE || uMsg == WM_NCMOUSEMOVE)
1208     {
1209 	if (lParam == last_lParam)
1210 	    return;
1211 	last_lParam = lParam;
1212     }
1213 
1214     /* Handle specially, to centralise coding. We need to be sure we catch all
1215      * possible events which should cause us to restore the cursor (as it is a
1216      * shared resource, we take full responsibility for it).
1217      */
1218     switch (uMsg)
1219     {
1220     case WM_KEYUP:
1221     case WM_CHAR:
1222 	/*
1223 	 * blank out the pointer if necessary
1224 	 */
1225 	if (p_mh)
1226 	    gui_mch_mousehide(TRUE);
1227 	break;
1228 
1229     case WM_SYSKEYUP:	 /* show the pointer when a system-key is pressed */
1230     case WM_SYSCHAR:
1231     case WM_MOUSEMOVE:	 /* show the pointer on any mouse action */
1232     case WM_LBUTTONDOWN:
1233     case WM_LBUTTONUP:
1234     case WM_MBUTTONDOWN:
1235     case WM_MBUTTONUP:
1236     case WM_RBUTTONDOWN:
1237     case WM_RBUTTONUP:
1238     case WM_XBUTTONDOWN:
1239     case WM_XBUTTONUP:
1240     case WM_NCMOUSEMOVE:
1241     case WM_NCLBUTTONDOWN:
1242     case WM_NCLBUTTONUP:
1243     case WM_NCMBUTTONDOWN:
1244     case WM_NCMBUTTONUP:
1245     case WM_NCRBUTTONDOWN:
1246     case WM_NCRBUTTONUP:
1247     case WM_KILLFOCUS:
1248 	/*
1249 	 * if the pointer is currently hidden, then we should show it.
1250 	 */
1251 	gui_mch_mousehide(FALSE);
1252 	break;
1253     }
1254 }
1255 
1256     static LRESULT CALLBACK
1257 _TextAreaWndProc(
1258     HWND hwnd,
1259     UINT uMsg,
1260     WPARAM wParam,
1261     LPARAM lParam)
1262 {
1263     /*
1264     TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
1265 	  hwnd, uMsg, wParam, lParam);
1266     */
1267 
1268     HandleMouseHide(uMsg, lParam);
1269 
1270     s_uMsg = uMsg;
1271     s_wParam = wParam;
1272     s_lParam = lParam;
1273 
1274 #ifdef FEAT_BEVAL_GUI
1275     TrackUserActivity(uMsg);
1276 #endif
1277 
1278     switch (uMsg)
1279     {
1280 	HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,_OnMouseButtonDown);
1281 	HANDLE_MSG(hwnd, WM_LBUTTONDOWN,_OnMouseButtonDown);
1282 	HANDLE_MSG(hwnd, WM_LBUTTONUP,	_OnMouseMoveOrRelease);
1283 	HANDLE_MSG(hwnd, WM_MBUTTONDBLCLK,_OnMouseButtonDown);
1284 	HANDLE_MSG(hwnd, WM_MBUTTONDOWN,_OnMouseButtonDown);
1285 	HANDLE_MSG(hwnd, WM_MBUTTONUP,	_OnMouseMoveOrRelease);
1286 	HANDLE_MSG(hwnd, WM_MOUSEMOVE,	_OnMouseMoveOrRelease);
1287 	HANDLE_MSG(hwnd, WM_PAINT,	_OnPaint);
1288 	HANDLE_MSG(hwnd, WM_RBUTTONDBLCLK,_OnMouseButtonDown);
1289 	HANDLE_MSG(hwnd, WM_RBUTTONDOWN,_OnMouseButtonDown);
1290 	HANDLE_MSG(hwnd, WM_RBUTTONUP,	_OnMouseMoveOrRelease);
1291 	HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown);
1292 	HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown);
1293 	HANDLE_MSG(hwnd, WM_XBUTTONUP,	_OnMouseMoveOrRelease);
1294 	HANDLE_MSG(hwnd, WM_SIZE,	_OnSizeTextArea);
1295 
1296 #ifdef FEAT_BEVAL_GUI
1297 	case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam);
1298 	    return TRUE;
1299 #endif
1300 	default:
1301 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
1302     }
1303 }
1304 
1305 #ifdef PROTO
1306 typedef int WINAPI;
1307 #endif
1308 
1309     LRESULT WINAPI
1310 vim_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
1311 {
1312 #ifdef GLOBAL_IME
1313     return global_ime_DefWindowProc(hwnd, message, wParam, lParam);
1314 #else
1315     if (wide_WindowProc)
1316 	return DefWindowProcW(hwnd, message, wParam, lParam);
1317     return DefWindowProc(hwnd, message, wParam, lParam);
1318 #endif
1319 }
1320 
1321 /*
1322  * Called when the foreground or background color has been changed.
1323  */
1324     void
1325 gui_mch_new_colors(void)
1326 {
1327     /* nothing to do? */
1328 }
1329 
1330 /*
1331  * Set the colors to their default values.
1332  */
1333     void
1334 gui_mch_def_colors(void)
1335 {
1336     gui.norm_pixel = GetSysColor(COLOR_WINDOWTEXT);
1337     gui.back_pixel = GetSysColor(COLOR_WINDOW);
1338     gui.def_norm_pixel = gui.norm_pixel;
1339     gui.def_back_pixel = gui.back_pixel;
1340 }
1341 
1342 /*
1343  * Open the GUI window which was created by a call to gui_mch_init().
1344  */
1345     int
1346 gui_mch_open(void)
1347 {
1348 #ifndef SW_SHOWDEFAULT
1349 # define SW_SHOWDEFAULT 10	/* Borland 5.0 doesn't have it */
1350 #endif
1351     /* Actually open the window, if not already visible
1352      * (may be done already in gui_mch_set_shellsize) */
1353     if (!IsWindowVisible(s_hwnd))
1354 	ShowWindow(s_hwnd, SW_SHOWDEFAULT);
1355 
1356 #ifdef MSWIN_FIND_REPLACE
1357     /* Init replace string here, so that we keep it when re-opening the
1358      * dialog. */
1359     s_findrep_struct.lpstrReplaceWith[0] = NUL;
1360 #endif
1361 
1362     return OK;
1363 }
1364 
1365 /*
1366  * Get the position of the top left corner of the window.
1367  */
1368     int
1369 gui_mch_get_winpos(int *x, int *y)
1370 {
1371     RECT    rect;
1372 
1373     GetWindowRect(s_hwnd, &rect);
1374     *x = rect.left;
1375     *y = rect.top;
1376     return OK;
1377 }
1378 
1379 /*
1380  * Set the position of the top left corner of the window to the given
1381  * coordinates.
1382  */
1383     void
1384 gui_mch_set_winpos(int x, int y)
1385 {
1386     SetWindowPos(s_hwnd, NULL, x, y, 0, 0,
1387 		 SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
1388 }
1389     void
1390 gui_mch_set_text_area_pos(int x, int y, int w, int h)
1391 {
1392     static int oldx = 0;
1393     static int oldy = 0;
1394 
1395     SetWindowPos(s_textArea, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE);
1396 
1397 #ifdef FEAT_TOOLBAR
1398     if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
1399 	SendMessage(s_toolbarhwnd, WM_SIZE,
1400 	      (WPARAM)0, (LPARAM)(w + ((long)(TOOLBAR_BUTTON_HEIGHT+8)<<16)));
1401 #endif
1402 #if defined(FEAT_GUI_TABLINE)
1403     if (showing_tabline)
1404     {
1405 	int	top = 0;
1406 	RECT	rect;
1407 
1408 # ifdef FEAT_TOOLBAR
1409 	if (vim_strchr(p_go, GO_TOOLBAR) != NULL)
1410 	    top = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT;
1411 # endif
1412 	GetClientRect(s_hwnd, &rect);
1413 	MoveWindow(s_tabhwnd, 0, top, rect.right, gui.tabline_height, TRUE);
1414     }
1415 #endif
1416 
1417     /* When side scroll bar is unshown, the size of window will change.
1418      * then, the text area move left or right. thus client rect should be
1419      * forcedly redrawn. (Yasuhiro Matsumoto) */
1420     if (oldx != x || oldy != y)
1421     {
1422 	InvalidateRect(s_hwnd, NULL, FALSE);
1423 	oldx = x;
1424 	oldy = y;
1425     }
1426 }
1427 
1428 
1429 /*
1430  * Scrollbar stuff:
1431  */
1432 
1433     void
1434 gui_mch_enable_scrollbar(
1435     scrollbar_T     *sb,
1436     int		    flag)
1437 {
1438     ShowScrollBar(sb->id, SB_CTL, flag);
1439 
1440     /* TODO: When the window is maximized, the size of the window stays the
1441      * same, thus the size of the text area changes.  On Win98 it's OK, on Win
1442      * NT 4.0 it's not... */
1443 }
1444 
1445     void
1446 gui_mch_set_scrollbar_pos(
1447     scrollbar_T *sb,
1448     int		x,
1449     int		y,
1450     int		w,
1451     int		h)
1452 {
1453     SetWindowPos(sb->id, NULL, x, y, w, h,
1454 			      SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
1455 }
1456 
1457     void
1458 gui_mch_create_scrollbar(
1459     scrollbar_T *sb,
1460     int		orient)	/* SBAR_VERT or SBAR_HORIZ */
1461 {
1462     sb->id = CreateWindow(
1463 	"SCROLLBAR", "Scrollbar",
1464 	WS_CHILD | ((orient == SBAR_VERT) ? SBS_VERT : SBS_HORZ), 0, 0,
1465 	10,				/* Any value will do for now */
1466 	10,				/* Any value will do for now */
1467 	s_hwnd, NULL,
1468 	s_hinst, NULL);
1469 }
1470 
1471 /*
1472  * Find the scrollbar with the given hwnd.
1473  */
1474 	 static scrollbar_T *
1475 gui_mswin_find_scrollbar(HWND hwnd)
1476 {
1477     win_T	*wp;
1478 
1479     if (gui.bottom_sbar.id == hwnd)
1480 	return &gui.bottom_sbar;
1481     FOR_ALL_WINDOWS(wp)
1482     {
1483 	if (wp->w_scrollbars[SBAR_LEFT].id == hwnd)
1484 	    return &wp->w_scrollbars[SBAR_LEFT];
1485 	if (wp->w_scrollbars[SBAR_RIGHT].id == hwnd)
1486 	    return &wp->w_scrollbars[SBAR_RIGHT];
1487     }
1488     return NULL;
1489 }
1490 
1491 /*
1492  * Get the character size of a font.
1493  */
1494     static void
1495 GetFontSize(GuiFont font)
1496 {
1497     HWND    hwnd = GetDesktopWindow();
1498     HDC	    hdc = GetWindowDC(hwnd);
1499     HFONT   hfntOld = SelectFont(hdc, (HFONT)font);
1500     TEXTMETRIC tm;
1501 
1502     GetTextMetrics(hdc, &tm);
1503     gui.char_width = tm.tmAveCharWidth + tm.tmOverhang;
1504 
1505     gui.char_height = tm.tmHeight + p_linespace;
1506 
1507     SelectFont(hdc, hfntOld);
1508 
1509     ReleaseDC(hwnd, hdc);
1510 }
1511 
1512 /*
1513  * Adjust gui.char_height (after 'linespace' was changed).
1514  */
1515     int
1516 gui_mch_adjust_charheight(void)
1517 {
1518     GetFontSize(gui.norm_font);
1519     return OK;
1520 }
1521 
1522     static GuiFont
1523 get_font_handle(LOGFONT *lf)
1524 {
1525     HFONT   font = NULL;
1526 
1527     /* Load the font */
1528     font = CreateFontIndirect(lf);
1529 
1530     if (font == NULL)
1531 	return NOFONT;
1532 
1533     return (GuiFont)font;
1534 }
1535 
1536     static int
1537 pixels_to_points(int pixels, int vertical)
1538 {
1539     int		points;
1540     HWND	hwnd;
1541     HDC		hdc;
1542 
1543     hwnd = GetDesktopWindow();
1544     hdc = GetWindowDC(hwnd);
1545 
1546     points = MulDiv(pixels, 72,
1547 		    GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX));
1548 
1549     ReleaseDC(hwnd, hdc);
1550 
1551     return points;
1552 }
1553 
1554     GuiFont
1555 gui_mch_get_font(
1556     char_u	*name,
1557     int		giveErrorIfMissing)
1558 {
1559     LOGFONT	lf;
1560     GuiFont	font = NOFONT;
1561 
1562     if (get_logfont(&lf, name, NULL, giveErrorIfMissing) == OK)
1563 	font = get_font_handle(&lf);
1564     if (font == NOFONT && giveErrorIfMissing)
1565 	semsg(_(e_font), name);
1566     return font;
1567 }
1568 
1569 #if defined(FEAT_EVAL) || defined(PROTO)
1570 /*
1571  * Return the name of font "font" in allocated memory.
1572  * Don't know how to get the actual name, thus use the provided name.
1573  */
1574     char_u *
1575 gui_mch_get_fontname(GuiFont font UNUSED, char_u *name)
1576 {
1577     if (name == NULL)
1578 	return NULL;
1579     return vim_strsave(name);
1580 }
1581 #endif
1582 
1583     void
1584 gui_mch_free_font(GuiFont font)
1585 {
1586     if (font)
1587 	DeleteObject((HFONT)font);
1588 }
1589 
1590 /*
1591  * Return the Pixel value (color) for the given color name.
1592  * Return INVALCOLOR for error.
1593  */
1594     guicolor_T
1595 gui_mch_get_color(char_u *name)
1596 {
1597     int i;
1598 
1599     typedef struct SysColorTable
1600     {
1601 	char	    *name;
1602 	int	    color;
1603     } SysColorTable;
1604 
1605     static SysColorTable sys_table[] =
1606     {
1607 	{"SYS_3DDKSHADOW", COLOR_3DDKSHADOW},
1608 	{"SYS_3DHILIGHT", COLOR_3DHILIGHT},
1609 #ifdef COLOR_3DHIGHLIGHT
1610 	{"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT},
1611 #endif
1612 	{"SYS_BTNHILIGHT", COLOR_BTNHILIGHT},
1613 	{"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT},
1614 	{"SYS_3DLIGHT", COLOR_3DLIGHT},
1615 	{"SYS_3DSHADOW", COLOR_3DSHADOW},
1616 	{"SYS_DESKTOP", COLOR_DESKTOP},
1617 	{"SYS_INFOBK", COLOR_INFOBK},
1618 	{"SYS_INFOTEXT", COLOR_INFOTEXT},
1619 	{"SYS_3DFACE", COLOR_3DFACE},
1620 	{"SYS_BTNFACE", COLOR_BTNFACE},
1621 	{"SYS_BTNSHADOW", COLOR_BTNSHADOW},
1622 	{"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER},
1623 	{"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION},
1624 	{"SYS_APPWORKSPACE", COLOR_APPWORKSPACE},
1625 	{"SYS_BACKGROUND", COLOR_BACKGROUND},
1626 	{"SYS_BTNTEXT", COLOR_BTNTEXT},
1627 	{"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT},
1628 	{"SYS_GRAYTEXT", COLOR_GRAYTEXT},
1629 	{"SYS_HIGHLIGHT", COLOR_HIGHLIGHT},
1630 	{"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT},
1631 	{"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER},
1632 	{"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION},
1633 	{"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT},
1634 	{"SYS_MENU", COLOR_MENU},
1635 	{"SYS_MENUTEXT", COLOR_MENUTEXT},
1636 	{"SYS_SCROLLBAR", COLOR_SCROLLBAR},
1637 	{"SYS_WINDOW", COLOR_WINDOW},
1638 	{"SYS_WINDOWFRAME", COLOR_WINDOWFRAME},
1639 	{"SYS_WINDOWTEXT", COLOR_WINDOWTEXT}
1640     };
1641 
1642     /*
1643      * Try to look up a system colour.
1644      */
1645     for (i = 0; i < sizeof(sys_table) / sizeof(sys_table[0]); i++)
1646 	if (STRICMP(name, sys_table[i].name) == 0)
1647 	    return GetSysColor(sys_table[i].color);
1648 
1649     return gui_get_color_cmn(name);
1650 }
1651 
1652     guicolor_T
1653 gui_mch_get_rgb_color(int r, int g, int b)
1654 {
1655     return gui_get_rgb_color_cmn(r, g, b);
1656 }
1657 
1658 /*
1659  * Return OK if the key with the termcap name "name" is supported.
1660  */
1661     int
1662 gui_mch_haskey(char_u *name)
1663 {
1664     int i;
1665 
1666     for (i = 0; special_keys[i].vim_code1 != NUL; i++)
1667 	if (name[0] == special_keys[i].vim_code0 &&
1668 					 name[1] == special_keys[i].vim_code1)
1669 	    return OK;
1670     return FAIL;
1671 }
1672 
1673     void
1674 gui_mch_beep(void)
1675 {
1676     MessageBeep(MB_OK);
1677 }
1678 /*
1679  * Invert a rectangle from row r, column c, for nr rows and nc columns.
1680  */
1681     void
1682 gui_mch_invert_rectangle(
1683     int	    r,
1684     int	    c,
1685     int	    nr,
1686     int	    nc)
1687 {
1688     RECT    rc;
1689 
1690 #if defined(FEAT_DIRECTX)
1691     if (IS_ENABLE_DIRECTX())
1692 	DWriteContext_Flush(s_dwc);
1693 #endif
1694 
1695     /*
1696      * Note: InvertRect() excludes right and bottom of rectangle.
1697      */
1698     rc.left = FILL_X(c);
1699     rc.top = FILL_Y(r);
1700     rc.right = rc.left + nc * gui.char_width;
1701     rc.bottom = rc.top + nr * gui.char_height;
1702     InvertRect(s_hdc, &rc);
1703 }
1704 
1705 /*
1706  * Iconify the GUI window.
1707  */
1708     void
1709 gui_mch_iconify(void)
1710 {
1711     ShowWindow(s_hwnd, SW_MINIMIZE);
1712 }
1713 
1714 /*
1715  * Draw a cursor without focus.
1716  */
1717     void
1718 gui_mch_draw_hollow_cursor(guicolor_T color)
1719 {
1720     HBRUSH  hbr;
1721     RECT    rc;
1722 
1723 #if defined(FEAT_DIRECTX)
1724     if (IS_ENABLE_DIRECTX())
1725 	DWriteContext_Flush(s_dwc);
1726 #endif
1727 
1728     /*
1729      * Note: FrameRect() excludes right and bottom of rectangle.
1730      */
1731     rc.left = FILL_X(gui.col);
1732     rc.top = FILL_Y(gui.row);
1733     rc.right = rc.left + gui.char_width;
1734     if (mb_lefthalve(gui.row, gui.col))
1735 	rc.right += gui.char_width;
1736     rc.bottom = rc.top + gui.char_height;
1737     hbr = CreateSolidBrush(color);
1738     FrameRect(s_hdc, &rc, hbr);
1739     DeleteBrush(hbr);
1740 }
1741 /*
1742  * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1743  * color "color".
1744  */
1745     void
1746 gui_mch_draw_part_cursor(
1747     int		w,
1748     int		h,
1749     guicolor_T	color)
1750 {
1751     RECT	rc;
1752 
1753     /*
1754      * Note: FillRect() excludes right and bottom of rectangle.
1755      */
1756     rc.left =
1757 #ifdef FEAT_RIGHTLEFT
1758 		/* vertical line should be on the right of current point */
1759 		CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w :
1760 #endif
1761 		    FILL_X(gui.col);
1762     rc.top = FILL_Y(gui.row) + gui.char_height - h;
1763     rc.right = rc.left + w;
1764     rc.bottom = rc.top + h;
1765 
1766     fill_rect(&rc, NULL, color);
1767 }
1768 
1769 
1770 /*
1771  * Generates a VK_SPACE when the internal dead_key flag is set to output the
1772  * dead key's nominal character and re-post the original message.
1773  */
1774     static void
1775 outputDeadKey_rePost(MSG originalMsg)
1776 {
1777     static MSG deadCharExpel;
1778 
1779     if (!dead_key)
1780 	return;
1781 
1782     dead_key = 0;
1783 
1784     /* Make Windows generate the dead key's character */
1785     deadCharExpel.message = originalMsg.message;
1786     deadCharExpel.hwnd    = originalMsg.hwnd;
1787     deadCharExpel.wParam  = VK_SPACE;
1788 
1789     MyTranslateMessage(&deadCharExpel);
1790 
1791     /* re-generate the current character free of the dead char influence */
1792     PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam,
1793 							  originalMsg.lParam);
1794 }
1795 
1796 
1797 /*
1798  * Process a single Windows message.
1799  * If one is not available we hang until one is.
1800  */
1801     static void
1802 process_message(void)
1803 {
1804     MSG		msg;
1805     UINT	vk = 0;		/* Virtual key */
1806     char_u	string[40];
1807     int		i;
1808     int		modifiers = 0;
1809     int		key;
1810 #ifdef FEAT_MENU
1811     static char_u k10[] = {K_SPECIAL, 'k', ';', 0};
1812 #endif
1813 
1814     pGetMessage(&msg, NULL, 0, 0);
1815 
1816 #ifdef FEAT_OLE
1817     /* Look after OLE Automation commands */
1818     if (msg.message == WM_OLE)
1819     {
1820 	char_u *str = (char_u *)msg.lParam;
1821 	if (str == NULL || *str == NUL)
1822 	{
1823 	    /* Message can't be ours, forward it.  Fixes problem with Ultramon
1824 	     * 3.0.4 */
1825 	    pDispatchMessage(&msg);
1826 	}
1827 	else
1828 	{
1829 	    add_to_input_buf(str, (int)STRLEN(str));
1830 	    vim_free(str);  /* was allocated in CVim::SendKeys() */
1831 	}
1832 	return;
1833     }
1834 #endif
1835 
1836 #ifdef MSWIN_FIND_REPLACE
1837     /* Don't process messages used by the dialog */
1838     if (s_findrep_hwnd != NULL && pIsDialogMessage(s_findrep_hwnd, &msg))
1839     {
1840 	HandleMouseHide(msg.message, msg.lParam);
1841 	return;
1842     }
1843 #endif
1844 
1845     /*
1846      * Check if it's a special key that we recognise.  If not, call
1847      * TranslateMessage().
1848      */
1849     if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN)
1850     {
1851 	vk = (int) msg.wParam;
1852 
1853 	/*
1854 	 * Handle dead keys in special conditions in other cases we let Windows
1855 	 * handle them and do not interfere.
1856 	 *
1857 	 * The dead_key flag must be reset on several occasions:
1858 	 * - in _OnChar() (or _OnSysChar()) as any dead key was necessarily
1859 	 *   consumed at that point (This is when we let Windows combine the
1860 	 *   dead character on its own)
1861 	 *
1862 	 * - Before doing something special such as regenerating keypresses to
1863 	 *   expel the dead character as this could trigger an infinite loop if
1864 	 *   for some reason MyTranslateMessage() do not trigger a call
1865 	 *   immediately to _OnChar() (or _OnSysChar()).
1866 	 */
1867 	if (dead_key)
1868 	{
1869 	    /*
1870 	     * If a dead key was pressed and the user presses VK_SPACE,
1871 	     * VK_BACK, or VK_ESCAPE it means that he actually wants to deal
1872 	     * with the dead char now, so do nothing special and let Windows
1873 	     * handle it.
1874 	     *
1875 	     * Note that VK_SPACE combines with the dead_key's character and
1876 	     * only one WM_CHAR will be generated by TranslateMessage(), in
1877 	     * the two other cases two WM_CHAR will be generated: the dead
1878 	     * char and VK_BACK or VK_ESCAPE. That is most likely what the
1879 	     * user expects.
1880 	     */
1881 	    if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE))
1882 	    {
1883 		dead_key = 0;
1884 		MyTranslateMessage(&msg);
1885 		return;
1886 	    }
1887 	    /* In modes where we are not typing, dead keys should behave
1888 	     * normally */
1889 	    else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE)))
1890 	    {
1891 		outputDeadKey_rePost(msg);
1892 		return;
1893 	    }
1894 	}
1895 
1896 	/* Check for CTRL-BREAK */
1897 	if (vk == VK_CANCEL)
1898 	{
1899 	    trash_input_buf();
1900 	    got_int = TRUE;
1901 	    ctrl_break_was_pressed = TRUE;
1902 	    string[0] = Ctrl_C;
1903 	    add_to_input_buf(string, 1);
1904 	}
1905 
1906 	for (i = 0; special_keys[i].key_sym != 0; i++)
1907 	{
1908 	    /* ignore VK_SPACE when ALT key pressed: system menu */
1909 	    if (special_keys[i].key_sym == vk
1910 		    && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000)))
1911 	    {
1912 		/*
1913 		 * Behave as expected if we have a dead key and the special key
1914 		 * is a key that would normally trigger the dead key nominal
1915 		 * character output (such as a NUMPAD printable character or
1916 		 * the TAB key, etc...).
1917 		 */
1918 		if (dead_key && (special_keys[i].vim_code0 == 'K'
1919 						|| vk == VK_TAB || vk == CAR))
1920 		{
1921 		    outputDeadKey_rePost(msg);
1922 		    return;
1923 		}
1924 
1925 #ifdef FEAT_MENU
1926 		/* Check for <F10>: Windows selects the menu.  When <F10> is
1927 		 * mapped we want to use the mapping instead. */
1928 		if (vk == VK_F10
1929 			&& gui.menu_is_active
1930 			&& check_map(k10, State, FALSE, TRUE, FALSE,
1931 							  NULL, NULL) == NULL)
1932 		    break;
1933 #endif
1934 		if (GetKeyState(VK_SHIFT) & 0x8000)
1935 		    modifiers |= MOD_MASK_SHIFT;
1936 		/*
1937 		 * Don't use caps-lock as shift, because these are special keys
1938 		 * being considered here, and we only want letters to get
1939 		 * shifted -- webb
1940 		 */
1941 		/*
1942 		if (GetKeyState(VK_CAPITAL) & 0x0001)
1943 		    modifiers ^= MOD_MASK_SHIFT;
1944 		*/
1945 		if (GetKeyState(VK_CONTROL) & 0x8000)
1946 		    modifiers |= MOD_MASK_CTRL;
1947 		if (GetKeyState(VK_MENU) & 0x8000)
1948 		    modifiers |= MOD_MASK_ALT;
1949 
1950 		if (special_keys[i].vim_code1 == NUL)
1951 		    key = special_keys[i].vim_code0;
1952 		else
1953 		    key = TO_SPECIAL(special_keys[i].vim_code0,
1954 						   special_keys[i].vim_code1);
1955 		key = simplify_key(key, &modifiers);
1956 		if (key == CSI)
1957 		    key = K_CSI;
1958 
1959 		if (modifiers)
1960 		{
1961 		    string[0] = CSI;
1962 		    string[1] = KS_MODIFIER;
1963 		    string[2] = modifiers;
1964 		    add_to_input_buf(string, 3);
1965 		}
1966 
1967 		if (IS_SPECIAL(key))
1968 		{
1969 		    string[0] = CSI;
1970 		    string[1] = K_SECOND(key);
1971 		    string[2] = K_THIRD(key);
1972 		    add_to_input_buf(string, 3);
1973 		}
1974 		else
1975 		{
1976 		    int	len;
1977 
1978 		    /* Handle "key" as a Unicode character. */
1979 		    len = char_to_string(key, string, 40, FALSE);
1980 		    add_to_input_buf(string, len);
1981 		}
1982 		break;
1983 	    }
1984 	}
1985 	if (special_keys[i].key_sym == 0)
1986 	{
1987 	    /* Some keys need C-S- where they should only need C-.
1988 	     * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1989 	     * system startup (Helmut Stiegler, 2003 Oct 3). */
1990 	    if (vk != 0xff
1991 		    && (GetKeyState(VK_CONTROL) & 0x8000)
1992 		    && !(GetKeyState(VK_SHIFT) & 0x8000)
1993 		    && !(GetKeyState(VK_MENU) & 0x8000))
1994 	    {
1995 		/* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1996 		if (vk == '6' || MapVirtualKey(vk, 2) == (UINT)'^')
1997 		{
1998 		    string[0] = Ctrl_HAT;
1999 		    add_to_input_buf(string, 1);
2000 		}
2001 		/* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
2002 		else if (vk == 0xBD)	/* QWERTY for CTRL-'-' */
2003 		{
2004 		    string[0] = Ctrl__;
2005 		    add_to_input_buf(string, 1);
2006 		}
2007 		/* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
2008 		else if (vk == '2' || MapVirtualKey(vk, 2) == (UINT)'@')
2009 		{
2010 		    string[0] = Ctrl_AT;
2011 		    add_to_input_buf(string, 1);
2012 		}
2013 		else
2014 		    MyTranslateMessage(&msg);
2015 	    }
2016 	    else
2017 		MyTranslateMessage(&msg);
2018 	}
2019     }
2020 #ifdef FEAT_MBYTE_IME
2021     else if (msg.message == WM_IME_NOTIFY)
2022 	_OnImeNotify(msg.hwnd, (DWORD)msg.wParam, (DWORD)msg.lParam);
2023     else if (msg.message == WM_KEYUP && im_get_status())
2024 	/* added for non-MS IME (Yasuhiro Matsumoto) */
2025 	MyTranslateMessage(&msg);
2026 #endif
2027 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
2028 /* GIME_TEST */
2029     else if (msg.message == WM_IME_STARTCOMPOSITION)
2030     {
2031 	POINT point;
2032 
2033 	global_ime_set_font(&norm_logfont);
2034 	point.x = FILL_X(gui.col);
2035 	point.y = FILL_Y(gui.row);
2036 	MapWindowPoints(s_textArea, s_hwnd, &point, 1);
2037 	global_ime_set_position(&point);
2038     }
2039 #endif
2040 
2041 #ifdef FEAT_MENU
2042     /* Check for <F10>: Default effect is to select the menu.  When <F10> is
2043      * mapped we need to stop it here to avoid strange effects (e.g., for the
2044      * key-up event) */
2045     if (vk != VK_F10 || check_map(k10, State, FALSE, TRUE, FALSE,
2046 							  NULL, NULL) == NULL)
2047 #endif
2048 	pDispatchMessage(&msg);
2049 }
2050 
2051 /*
2052  * Catch up with any queued events.  This may put keyboard input into the
2053  * input buffer, call resize call-backs, trigger timers etc.  If there is
2054  * nothing in the event queue (& no timers pending), then we return
2055  * immediately.
2056  */
2057     void
2058 gui_mch_update(void)
2059 {
2060     MSG	    msg;
2061 
2062     if (!s_busy_processing)
2063 	while (pPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)
2064 						  && !vim_is_input_buf_full())
2065 	    process_message();
2066 }
2067 
2068     static void
2069 remove_any_timer(void)
2070 {
2071     MSG		msg;
2072 
2073     if (s_wait_timer != 0 && !s_timed_out)
2074     {
2075 	KillTimer(NULL, s_wait_timer);
2076 
2077 	/* Eat spurious WM_TIMER messages */
2078 	while (pPeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
2079 	    ;
2080 	s_wait_timer = 0;
2081     }
2082 }
2083 
2084 /*
2085  * GUI input routine called by gui_wait_for_chars().  Waits for a character
2086  * from the keyboard.
2087  *  wtime == -1	    Wait forever.
2088  *  wtime == 0	    This should never happen.
2089  *  wtime > 0	    Wait wtime milliseconds for a character.
2090  * Returns OK if a character was found to be available within the given time,
2091  * or FAIL otherwise.
2092  */
2093     int
2094 gui_mch_wait_for_chars(int wtime)
2095 {
2096     int		focus;
2097 
2098     s_timed_out = FALSE;
2099 
2100     if (wtime >= 0)
2101     {
2102 	// Don't do anything while processing a (scroll) message.
2103 	if (s_busy_processing)
2104 	    return FAIL;
2105 
2106 	// When called with "wtime" zero, just want one msec.
2107 	s_wait_timer = (UINT)SetTimer(NULL, 0, (UINT)(wtime == 0 ? 1 : wtime),
2108 							 (TIMERPROC)_OnTimer);
2109     }
2110 
2111     allow_scrollbar = TRUE;
2112 
2113     focus = gui.in_focus;
2114     while (!s_timed_out)
2115     {
2116 	/* Stop or start blinking when focus changes */
2117 	if (gui.in_focus != focus)
2118 	{
2119 	    if (gui.in_focus)
2120 		gui_mch_start_blink();
2121 	    else
2122 		gui_mch_stop_blink(TRUE);
2123 	    focus = gui.in_focus;
2124 	}
2125 
2126 	if (s_need_activate)
2127 	{
2128 	    (void)SetForegroundWindow(s_hwnd);
2129 	    s_need_activate = FALSE;
2130 	}
2131 
2132 #ifdef FEAT_TIMERS
2133 	did_add_timer = FALSE;
2134 #endif
2135 #ifdef MESSAGE_QUEUE
2136 	/* Check channel I/O while waiting for a message. */
2137 	for (;;)
2138 	{
2139 	    MSG msg;
2140 
2141 	    parse_queued_messages();
2142 
2143 	    if (pPeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
2144 	    {
2145 		process_message();
2146 		break;
2147 	    }
2148 	    else if (MsgWaitForMultipleObjects(0, NULL, FALSE, 100, QS_ALLINPUT)
2149 							       != WAIT_TIMEOUT)
2150 		break;
2151 	}
2152 #else
2153 	/*
2154 	 * Don't use gui_mch_update() because then we will spin-lock until a
2155 	 * char arrives, instead we use GetMessage() to hang until an
2156 	 * event arrives.  No need to check for input_buf_full because we are
2157 	 * returning as soon as it contains a single char -- webb
2158 	 */
2159 	process_message();
2160 #endif
2161 
2162 	if (input_available())
2163 	{
2164 	    remove_any_timer();
2165 	    allow_scrollbar = FALSE;
2166 
2167 	    /* Clear pending mouse button, the release event may have been
2168 	     * taken by the dialog window.  But don't do this when getting
2169 	     * focus, we need the mouse-up event then. */
2170 	    if (!s_getting_focus)
2171 		s_button_pending = -1;
2172 
2173 	    return OK;
2174 	}
2175 
2176 #ifdef FEAT_TIMERS
2177 	if (did_add_timer)
2178 	{
2179 	    /* Need to recompute the waiting time. */
2180 	    remove_any_timer();
2181 	    break;
2182 	}
2183 #endif
2184     }
2185     allow_scrollbar = FALSE;
2186     return FAIL;
2187 }
2188 
2189 /*
2190  * Clear a rectangular region of the screen from text pos (row1, col1) to
2191  * (row2, col2) inclusive.
2192  */
2193     void
2194 gui_mch_clear_block(
2195     int		row1,
2196     int		col1,
2197     int		row2,
2198     int		col2)
2199 {
2200     RECT	rc;
2201 
2202     /*
2203      * Clear one extra pixel at the far right, for when bold characters have
2204      * spilled over to the window border.
2205      * Note: FillRect() excludes right and bottom of rectangle.
2206      */
2207     rc.left = FILL_X(col1);
2208     rc.top = FILL_Y(row1);
2209     rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1);
2210     rc.bottom = FILL_Y(row2 + 1);
2211     clear_rect(&rc);
2212 }
2213 
2214 /*
2215  * Clear the whole text window.
2216  */
2217     void
2218 gui_mch_clear_all(void)
2219 {
2220     RECT    rc;
2221 
2222     rc.left = 0;
2223     rc.top = 0;
2224     rc.right = Columns * gui.char_width + 2 * gui.border_width;
2225     rc.bottom = Rows * gui.char_height + 2 * gui.border_width;
2226     clear_rect(&rc);
2227 }
2228 /*
2229  * Menu stuff.
2230  */
2231 
2232     void
2233 gui_mch_enable_menu(int flag)
2234 {
2235 #ifdef FEAT_MENU
2236     SetMenu(s_hwnd, flag ? s_menuBar : NULL);
2237 #endif
2238 }
2239 
2240     void
2241 gui_mch_set_menu_pos(
2242     int	    x UNUSED,
2243     int	    y UNUSED,
2244     int	    w UNUSED,
2245     int	    h UNUSED)
2246 {
2247     /* It will be in the right place anyway */
2248 }
2249 
2250 #if defined(FEAT_MENU) || defined(PROTO)
2251 /*
2252  * Make menu item hidden or not hidden
2253  */
2254     void
2255 gui_mch_menu_hidden(
2256     vimmenu_T	*menu,
2257     int		hidden)
2258 {
2259     /*
2260      * This doesn't do what we want.  Hmm, just grey the menu items for now.
2261      */
2262     /*
2263     if (hidden)
2264 	EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2265     else
2266 	EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2267     */
2268     gui_mch_menu_grey(menu, hidden);
2269 }
2270 
2271 /*
2272  * This is called after setting all the menus to grey/hidden or not.
2273  */
2274     void
2275 gui_mch_draw_menubar(void)
2276 {
2277     DrawMenuBar(s_hwnd);
2278 }
2279 #endif /*FEAT_MENU*/
2280 
2281 #ifndef PROTO
2282 void
2283 _cdecl
2284 SaveInst(HINSTANCE hInst)
2285 {
2286     s_hinst = hInst;
2287 }
2288 #endif
2289 
2290 /*
2291  * Return the RGB value of a pixel as a long.
2292  */
2293     guicolor_T
2294 gui_mch_get_rgb(guicolor_T pixel)
2295 {
2296     return (guicolor_T)((GetRValue(pixel) << 16) + (GetGValue(pixel) << 8)
2297 							   + GetBValue(pixel));
2298 }
2299 
2300 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2301 /* Convert pixels in X to dialog units */
2302     static WORD
2303 PixelToDialogX(int numPixels)
2304 {
2305     return (WORD)((numPixels * 4) / s_dlgfntwidth);
2306 }
2307 
2308 /* Convert pixels in Y to dialog units */
2309     static WORD
2310 PixelToDialogY(int numPixels)
2311 {
2312     return (WORD)((numPixels * 8) / s_dlgfntheight);
2313 }
2314 
2315 /* Return the width in pixels of the given text in the given DC. */
2316     static int
2317 GetTextWidth(HDC hdc, char_u *str, int len)
2318 {
2319     SIZE    size;
2320 
2321     GetTextExtentPoint(hdc, (LPCSTR)str, len, &size);
2322     return size.cx;
2323 }
2324 
2325 /*
2326  * Return the width in pixels of the given text in the given DC, taking care
2327  * of 'encoding' to active codepage conversion.
2328  */
2329     static int
2330 GetTextWidthEnc(HDC hdc, char_u *str, int len)
2331 {
2332     SIZE	size;
2333     WCHAR	*wstr;
2334     int		n;
2335     int		wlen = len;
2336 
2337     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2338     {
2339 	/* 'encoding' differs from active codepage: convert text and use wide
2340 	 * function */
2341 	wstr = enc_to_utf16(str, &wlen);
2342 	if (wstr != NULL)
2343 	{
2344 	    n = GetTextExtentPointW(hdc, wstr, wlen, &size);
2345 	    vim_free(wstr);
2346 	    if (n)
2347 		return size.cx;
2348 	}
2349     }
2350 
2351     return GetTextWidth(hdc, str, len);
2352 }
2353 
2354 static void get_work_area(RECT *spi_rect);
2355 
2356 /*
2357  * A quick little routine that will center one window over another, handy for
2358  * dialog boxes.  Taken from the Win32SDK samples and modified for multiple
2359  * monitors.
2360  */
2361     static BOOL
2362 CenterWindow(
2363     HWND hwndChild,
2364     HWND hwndParent)
2365 {
2366     HMONITOR	    mon;
2367     MONITORINFO	    moninfo;
2368     RECT	    rChild, rParent, rScreen;
2369     int		    wChild, hChild, wParent, hParent;
2370     int		    xNew, yNew;
2371     HDC		    hdc;
2372 
2373     GetWindowRect(hwndChild, &rChild);
2374     wChild = rChild.right - rChild.left;
2375     hChild = rChild.bottom - rChild.top;
2376 
2377     /* If Vim is minimized put the window in the middle of the screen. */
2378     if (hwndParent == NULL || IsMinimized(hwndParent))
2379 	get_work_area(&rParent);
2380     else
2381 	GetWindowRect(hwndParent, &rParent);
2382     wParent = rParent.right - rParent.left;
2383     hParent = rParent.bottom - rParent.top;
2384 
2385     moninfo.cbSize = sizeof(MONITORINFO);
2386     mon = MonitorFromWindow(hwndChild, MONITOR_DEFAULTTOPRIMARY);
2387     if (mon != NULL && GetMonitorInfo(mon, &moninfo))
2388     {
2389 	rScreen = moninfo.rcWork;
2390     }
2391     else
2392     {
2393 	hdc = GetDC(hwndChild);
2394 	rScreen.left = 0;
2395 	rScreen.top = 0;
2396 	rScreen.right = GetDeviceCaps(hdc, HORZRES);
2397 	rScreen.bottom = GetDeviceCaps(hdc, VERTRES);
2398 	ReleaseDC(hwndChild, hdc);
2399     }
2400 
2401     xNew = rParent.left + ((wParent - wChild) / 2);
2402     if (xNew < rScreen.left)
2403 	xNew = rScreen.left;
2404     else if ((xNew + wChild) > rScreen.right)
2405 	xNew = rScreen.right - wChild;
2406 
2407     yNew = rParent.top + ((hParent - hChild) / 2);
2408     if (yNew < rScreen.top)
2409 	yNew = rScreen.top;
2410     else if ((yNew + hChild) > rScreen.bottom)
2411 	yNew = rScreen.bottom - hChild;
2412 
2413     return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0,
2414 						   SWP_NOSIZE | SWP_NOZORDER);
2415 }
2416 #endif /* FEAT_GUI_DIALOG */
2417 
2418 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2419     void
2420 gui_mch_show_toolbar(int showit)
2421 {
2422     if (s_toolbarhwnd == NULL)
2423 	return;
2424 
2425     if (showit)
2426     {
2427 # ifndef TB_SETUNICODEFORMAT
2428     /* For older compilers.  We assume this never changes. */
2429 #  define TB_SETUNICODEFORMAT 0x2005
2430 # endif
2431 	/* Enable/disable unicode support */
2432 	int uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage);
2433 	SendMessage(s_toolbarhwnd, TB_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0);
2434 	ShowWindow(s_toolbarhwnd, SW_SHOW);
2435     }
2436     else
2437 	ShowWindow(s_toolbarhwnd, SW_HIDE);
2438 }
2439 
2440 /* Then number of bitmaps is fixed.  Exit is missing! */
2441 #define TOOLBAR_BITMAP_COUNT 31
2442 
2443 #endif
2444 
2445 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2446     static void
2447 add_tabline_popup_menu_entry(HMENU pmenu, UINT item_id, char_u *item_text)
2448 {
2449     WCHAR	*wn = NULL;
2450 
2451     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2452     {
2453 	/* 'encoding' differs from active codepage: convert menu name
2454 	 * and use wide function */
2455 	wn = enc_to_utf16(item_text, NULL);
2456 	if (wn != NULL)
2457 	{
2458 	    MENUITEMINFOW	infow;
2459 
2460 	    infow.cbSize = sizeof(infow);
2461 	    infow.fMask = MIIM_TYPE | MIIM_ID;
2462 	    infow.wID = item_id;
2463 	    infow.fType = MFT_STRING;
2464 	    infow.dwTypeData = wn;
2465 	    infow.cch = (UINT)wcslen(wn);
2466 	    InsertMenuItemW(pmenu, item_id, FALSE, &infow);
2467 	    vim_free(wn);
2468 	}
2469     }
2470 
2471     if (wn == NULL)
2472     {
2473 	MENUITEMINFO	info;
2474 
2475 	info.cbSize = sizeof(info);
2476 	info.fMask = MIIM_TYPE | MIIM_ID;
2477 	info.wID = item_id;
2478 	info.fType = MFT_STRING;
2479 	info.dwTypeData = (LPTSTR)item_text;
2480 	info.cch = (UINT)STRLEN(item_text);
2481 	InsertMenuItem(pmenu, item_id, FALSE, &info);
2482     }
2483 }
2484 
2485     static void
2486 show_tabline_popup_menu(void)
2487 {
2488     HMENU	    tab_pmenu;
2489     long	    rval;
2490     POINT	    pt;
2491 
2492     /* When ignoring events don't show the menu. */
2493     if (hold_gui_events
2494 # ifdef FEAT_CMDWIN
2495 	    || cmdwin_type != 0
2496 # endif
2497        )
2498 	return;
2499 
2500     tab_pmenu = CreatePopupMenu();
2501     if (tab_pmenu == NULL)
2502 	return;
2503 
2504     if (first_tabpage->tp_next != NULL)
2505 	add_tabline_popup_menu_entry(tab_pmenu,
2506 				TABLINE_MENU_CLOSE, (char_u *)_("Close tab"));
2507     add_tabline_popup_menu_entry(tab_pmenu,
2508 				TABLINE_MENU_NEW, (char_u *)_("New tab"));
2509     add_tabline_popup_menu_entry(tab_pmenu,
2510 				TABLINE_MENU_OPEN, (char_u *)_("Open tab..."));
2511 
2512     GetCursorPos(&pt);
2513     rval = TrackPopupMenuEx(tab_pmenu, TPM_RETURNCMD, pt.x, pt.y, s_tabhwnd,
2514 									NULL);
2515 
2516     DestroyMenu(tab_pmenu);
2517 
2518     /* Add the string cmd into input buffer */
2519     if (rval > 0)
2520     {
2521 	TCHITTESTINFO htinfo;
2522 	int idx;
2523 
2524 	if (ScreenToClient(s_tabhwnd, &pt) == 0)
2525 	    return;
2526 
2527 	htinfo.pt.x = pt.x;
2528 	htinfo.pt.y = pt.y;
2529 	idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
2530 	if (idx == -1)
2531 	    idx = 0;
2532 	else
2533 	    idx += 1;
2534 
2535 	send_tabline_menu_event(idx, (int)rval);
2536     }
2537 }
2538 
2539 /*
2540  * Show or hide the tabline.
2541  */
2542     void
2543 gui_mch_show_tabline(int showit)
2544 {
2545     if (s_tabhwnd == NULL)
2546 	return;
2547 
2548     if (!showit != !showing_tabline)
2549     {
2550 	if (showit)
2551 	    ShowWindow(s_tabhwnd, SW_SHOW);
2552 	else
2553 	    ShowWindow(s_tabhwnd, SW_HIDE);
2554 	showing_tabline = showit;
2555     }
2556 }
2557 
2558 /*
2559  * Return TRUE when tabline is displayed.
2560  */
2561     int
2562 gui_mch_showing_tabline(void)
2563 {
2564     return s_tabhwnd != NULL && showing_tabline;
2565 }
2566 
2567 /*
2568  * Update the labels of the tabline.
2569  */
2570     void
2571 gui_mch_update_tabline(void)
2572 {
2573     tabpage_T	*tp;
2574     TCITEM	tie;
2575     int		nr = 0;
2576     int		curtabidx = 0;
2577     int		tabadded = 0;
2578     static int	use_unicode = FALSE;
2579     int		uu;
2580     WCHAR	*wstr = NULL;
2581 
2582     if (s_tabhwnd == NULL)
2583 	return;
2584 
2585 #ifndef CCM_SETUNICODEFORMAT
2586     /* For older compilers.  We assume this never changes. */
2587 # define CCM_SETUNICODEFORMAT 0x2005
2588 #endif
2589     uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage);
2590     if (uu != use_unicode)
2591     {
2592 	/* Enable/disable unicode support */
2593 	SendMessage(s_tabhwnd, CCM_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0);
2594 	use_unicode = uu;
2595     }
2596 
2597     tie.mask = TCIF_TEXT;
2598     tie.iImage = -1;
2599 
2600     /* Disable redraw for tab updates to eliminate O(N^2) draws. */
2601     SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)FALSE, 0);
2602 
2603     /* Add a label for each tab page.  They all contain the same text area. */
2604     for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr)
2605     {
2606 	if (tp == curtab)
2607 	    curtabidx = nr;
2608 
2609 	if (nr >= TabCtrl_GetItemCount(s_tabhwnd))
2610 	{
2611 	    /* Add the tab */
2612 	    tie.pszText = "-Empty-";
2613 	    TabCtrl_InsertItem(s_tabhwnd, nr, &tie);
2614 	    tabadded = 1;
2615 	}
2616 
2617 	get_tabline_label(tp, FALSE);
2618 	tie.pszText = (LPSTR)NameBuff;
2619 	wstr = NULL;
2620 	if (use_unicode)
2621 	{
2622 	    /* Need to go through Unicode. */
2623 	    wstr = enc_to_utf16(NameBuff, NULL);
2624 	    if (wstr != NULL)
2625 	    {
2626 		TCITEMW		tiw;
2627 
2628 		tiw.mask = TCIF_TEXT;
2629 		tiw.iImage = -1;
2630 		tiw.pszText = wstr;
2631 		SendMessage(s_tabhwnd, TCM_SETITEMW, (WPARAM)nr, (LPARAM)&tiw);
2632 		vim_free(wstr);
2633 	    }
2634 	}
2635 	if (wstr == NULL)
2636 	{
2637 	    TabCtrl_SetItem(s_tabhwnd, nr, &tie);
2638 	}
2639     }
2640 
2641     /* Remove any old labels. */
2642     while (nr < TabCtrl_GetItemCount(s_tabhwnd))
2643 	TabCtrl_DeleteItem(s_tabhwnd, nr);
2644 
2645     if (!tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx)
2646 	TabCtrl_SetCurSel(s_tabhwnd, curtabidx);
2647 
2648     /* Re-enable redraw and redraw. */
2649     SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)TRUE, 0);
2650     RedrawWindow(s_tabhwnd, NULL, NULL,
2651 		    RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
2652 
2653     if (tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx)
2654 	TabCtrl_SetCurSel(s_tabhwnd, curtabidx);
2655 }
2656 
2657 /*
2658  * Set the current tab to "nr".  First tab is 1.
2659  */
2660     void
2661 gui_mch_set_curtab(int nr)
2662 {
2663     if (s_tabhwnd == NULL)
2664 	return;
2665 
2666     if (TabCtrl_GetCurSel(s_tabhwnd) != nr - 1)
2667 	TabCtrl_SetCurSel(s_tabhwnd, nr - 1);
2668 }
2669 
2670 #endif
2671 
2672 /*
2673  * ":simalt" command.
2674  */
2675     void
2676 ex_simalt(exarg_T *eap)
2677 {
2678     char_u	*keys = eap->arg;
2679     int		fill_typebuf = FALSE;
2680     char_u	key_name[4];
2681 
2682     PostMessage(s_hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)0);
2683     while (*keys)
2684     {
2685 	if (*keys == '~')
2686 	    *keys = ' ';	    /* for showing system menu */
2687 	PostMessage(s_hwnd, WM_CHAR, (WPARAM)*keys, (LPARAM)0);
2688 	keys++;
2689 	fill_typebuf = TRUE;
2690     }
2691     if (fill_typebuf)
2692     {
2693 	/* Put a NOP in the typeahead buffer so that the message will get
2694 	 * processed. */
2695 	key_name[0] = K_SPECIAL;
2696 	key_name[1] = KS_EXTRA;
2697 	key_name[2] = KE_NOP;
2698 	key_name[3] = NUL;
2699 	typebuf_was_filled = TRUE;
2700 	(void)ins_typebuf(key_name, REMAP_NONE, 0, TRUE, FALSE);
2701     }
2702 }
2703 
2704 /*
2705  * Create the find & replace dialogs.
2706  * You can't have both at once: ":find" when replace is showing, destroys
2707  * the replace dialog first, and the other way around.
2708  */
2709 #ifdef MSWIN_FIND_REPLACE
2710     static void
2711 initialise_findrep(char_u *initial_string)
2712 {
2713     int		wword = FALSE;
2714     int		mcase = !p_ic;
2715     char_u	*entry_text;
2716 
2717     /* Get the search string to use. */
2718     entry_text = get_find_dialog_text(initial_string, &wword, &mcase);
2719 
2720     s_findrep_struct.hwndOwner = s_hwnd;
2721     s_findrep_struct.Flags = FR_DOWN;
2722     if (mcase)
2723 	s_findrep_struct.Flags |= FR_MATCHCASE;
2724     if (wword)
2725 	s_findrep_struct.Flags |= FR_WHOLEWORD;
2726     if (entry_text != NULL && *entry_text != NUL)
2727 	vim_strncpy((char_u *)s_findrep_struct.lpstrFindWhat, entry_text,
2728 					   s_findrep_struct.wFindWhatLen - 1);
2729     vim_free(entry_text);
2730 }
2731 #endif
2732 
2733     static void
2734 set_window_title(HWND hwnd, char *title)
2735 {
2736     if (title != NULL && enc_codepage >= 0 && enc_codepage != (int)GetACP())
2737     {
2738 	WCHAR	*wbuf;
2739 
2740 	/* Convert the title from 'encoding' to UTF-16. */
2741 	wbuf = (WCHAR *)enc_to_utf16((char_u *)title, NULL);
2742 	if (wbuf != NULL)
2743 	{
2744 	    SetWindowTextW(hwnd, wbuf);
2745 	    vim_free(wbuf);
2746 	}
2747 	return;
2748     }
2749     (void)SetWindowText(hwnd, (LPCSTR)title);
2750 }
2751 
2752     void
2753 gui_mch_find_dialog(exarg_T *eap)
2754 {
2755 #ifdef MSWIN_FIND_REPLACE
2756     if (s_findrep_msg != 0)
2757     {
2758 	if (IsWindow(s_findrep_hwnd) && !s_findrep_is_find)
2759 	    DestroyWindow(s_findrep_hwnd);
2760 
2761 	if (!IsWindow(s_findrep_hwnd))
2762 	{
2763 	    initialise_findrep(eap->arg);
2764 	    /* If the OS is Windows NT, and 'encoding' differs from active
2765 	     * codepage: convert text and use wide function. */
2766 	    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2767 	    {
2768 		findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
2769 		s_findrep_hwnd = FindTextW(
2770 					(LPFINDREPLACEW) &s_findrep_struct_w);
2771 	    }
2772 	    else
2773 		s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct);
2774 	}
2775 
2776 	set_window_title(s_findrep_hwnd, _("Find string"));
2777 	(void)SetFocus(s_findrep_hwnd);
2778 
2779 	s_findrep_is_find = TRUE;
2780     }
2781 #endif
2782 }
2783 
2784 
2785     void
2786 gui_mch_replace_dialog(exarg_T *eap)
2787 {
2788 #ifdef MSWIN_FIND_REPLACE
2789     if (s_findrep_msg != 0)
2790     {
2791 	if (IsWindow(s_findrep_hwnd) && s_findrep_is_find)
2792 	    DestroyWindow(s_findrep_hwnd);
2793 
2794 	if (!IsWindow(s_findrep_hwnd))
2795 	{
2796 	    initialise_findrep(eap->arg);
2797 	    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2798 	    {
2799 		findrep_atow(&s_findrep_struct_w, &s_findrep_struct);
2800 		s_findrep_hwnd = ReplaceTextW(
2801 					(LPFINDREPLACEW) &s_findrep_struct_w);
2802 	    }
2803 	    else
2804 		s_findrep_hwnd = ReplaceText(
2805 					   (LPFINDREPLACE) &s_findrep_struct);
2806 	}
2807 
2808 	set_window_title(s_findrep_hwnd, _("Find & Replace"));
2809 	(void)SetFocus(s_findrep_hwnd);
2810 
2811 	s_findrep_is_find = FALSE;
2812     }
2813 #endif
2814 }
2815 
2816 
2817 /*
2818  * Set visibility of the pointer.
2819  */
2820     void
2821 gui_mch_mousehide(int hide)
2822 {
2823     if (hide != gui.pointer_hidden)
2824     {
2825 	ShowCursor(!hide);
2826 	gui.pointer_hidden = hide;
2827     }
2828 }
2829 
2830 #ifdef FEAT_MENU
2831     static void
2832 gui_mch_show_popupmenu_at(vimmenu_T *menu, int x, int y)
2833 {
2834     /* Unhide the mouse, we don't get move events here. */
2835     gui_mch_mousehide(FALSE);
2836 
2837     (void)TrackPopupMenu(
2838 	(HMENU)menu->submenu_id,
2839 	TPM_LEFTALIGN | TPM_LEFTBUTTON,
2840 	x, y,
2841 	(int)0,	    /*reserved param*/
2842 	s_hwnd,
2843 	NULL);
2844     /*
2845      * NOTE: The pop-up menu can eat the mouse up event.
2846      * We deal with this in normal.c.
2847      */
2848 }
2849 #endif
2850 
2851 /*
2852  * Got a message when the system will go down.
2853  */
2854     static void
2855 _OnEndSession(void)
2856 {
2857     getout_preserve_modified(1);
2858 }
2859 
2860 /*
2861  * Get this message when the user clicks on the cross in the top right corner
2862  * of a Windows95 window.
2863  */
2864     static void
2865 _OnClose(HWND hwnd UNUSED)
2866 {
2867     gui_shell_closed();
2868 }
2869 
2870 /*
2871  * Get a message when the window is being destroyed.
2872  */
2873     static void
2874 _OnDestroy(HWND hwnd)
2875 {
2876     if (!destroying)
2877 	_OnClose(hwnd);
2878 }
2879 
2880     static void
2881 _OnPaint(
2882     HWND hwnd)
2883 {
2884     if (!IsMinimized(hwnd))
2885     {
2886 	PAINTSTRUCT ps;
2887 
2888 	out_flush();	    /* make sure all output has been processed */
2889 	(void)BeginPaint(hwnd, &ps);
2890 
2891 	/* prevent multi-byte characters from misprinting on an invalid
2892 	 * rectangle */
2893 	if (has_mbyte)
2894 	{
2895 	    RECT rect;
2896 
2897 	    GetClientRect(hwnd, &rect);
2898 	    ps.rcPaint.left = rect.left;
2899 	    ps.rcPaint.right = rect.right;
2900 	}
2901 
2902 	if (!IsRectEmpty(&ps.rcPaint))
2903 	{
2904 	    gui_redraw(ps.rcPaint.left, ps.rcPaint.top,
2905 		    ps.rcPaint.right - ps.rcPaint.left + 1,
2906 		    ps.rcPaint.bottom - ps.rcPaint.top + 1);
2907 	}
2908 
2909 	EndPaint(hwnd, &ps);
2910     }
2911 }
2912 
2913     static void
2914 _OnSize(
2915     HWND hwnd,
2916     UINT state UNUSED,
2917     int cx,
2918     int cy)
2919 {
2920     if (!IsMinimized(hwnd))
2921     {
2922 	gui_resize_shell(cx, cy);
2923 
2924 #ifdef FEAT_MENU
2925 	/* Menu bar may wrap differently now */
2926 	gui_mswin_get_menu_height(TRUE);
2927 #endif
2928     }
2929 }
2930 
2931     static void
2932 _OnSetFocus(
2933     HWND hwnd,
2934     HWND hwndOldFocus)
2935 {
2936     gui_focus_change(TRUE);
2937     s_getting_focus = TRUE;
2938     (void)MyWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hwndOldFocus, 0);
2939 }
2940 
2941     static void
2942 _OnKillFocus(
2943     HWND hwnd,
2944     HWND hwndNewFocus)
2945 {
2946     gui_focus_change(FALSE);
2947     s_getting_focus = FALSE;
2948     (void)MyWindowProc(hwnd, WM_KILLFOCUS, (WPARAM)hwndNewFocus, 0);
2949 }
2950 
2951 /*
2952  * Get a message when the user switches back to vim
2953  */
2954     static LRESULT
2955 _OnActivateApp(
2956     HWND hwnd,
2957     BOOL fActivate,
2958     DWORD dwThreadId)
2959 {
2960     /* we call gui_focus_change() in _OnSetFocus() */
2961     /* gui_focus_change((int)fActivate); */
2962     return MyWindowProc(hwnd, WM_ACTIVATEAPP, fActivate, (DWORD)dwThreadId);
2963 }
2964 
2965     void
2966 gui_mch_destroy_scrollbar(scrollbar_T *sb)
2967 {
2968     DestroyWindow(sb->id);
2969 }
2970 
2971 /*
2972  * Get current mouse coordinates in text window.
2973  */
2974     void
2975 gui_mch_getmouse(int *x, int *y)
2976 {
2977     RECT rct;
2978     POINT mp;
2979 
2980     (void)GetWindowRect(s_textArea, &rct);
2981     (void)GetCursorPos((LPPOINT)&mp);
2982     *x = (int)(mp.x - rct.left);
2983     *y = (int)(mp.y - rct.top);
2984 }
2985 
2986 /*
2987  * Move mouse pointer to character at (x, y).
2988  */
2989     void
2990 gui_mch_setmouse(int x, int y)
2991 {
2992     RECT rct;
2993 
2994     (void)GetWindowRect(s_textArea, &rct);
2995     (void)SetCursorPos(x + gui.border_offset + rct.left,
2996 		       y + gui.border_offset + rct.top);
2997 }
2998 
2999     static void
3000 gui_mswin_get_valid_dimensions(
3001     int w,
3002     int h,
3003     int *valid_w,
3004     int *valid_h)
3005 {
3006     int	    base_width, base_height;
3007 
3008     base_width = gui_get_base_width()
3009 	+ (GetSystemMetrics(SM_CXFRAME) +
3010 	   GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
3011     base_height = gui_get_base_height()
3012 	+ (GetSystemMetrics(SM_CYFRAME) +
3013 	   GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
3014 	+ GetSystemMetrics(SM_CYCAPTION)
3015 #ifdef FEAT_MENU
3016 	+ gui_mswin_get_menu_height(FALSE)
3017 #endif
3018 	;
3019     *valid_w = base_width +
3020 		    ((w - base_width) / gui.char_width) * gui.char_width;
3021     *valid_h = base_height +
3022 		    ((h - base_height) / gui.char_height) * gui.char_height;
3023 }
3024 
3025     void
3026 gui_mch_flash(int msec)
3027 {
3028     RECT    rc;
3029 
3030 #if defined(FEAT_DIRECTX)
3031     if (IS_ENABLE_DIRECTX())
3032 	DWriteContext_Flush(s_dwc);
3033 #endif
3034 
3035     /*
3036      * Note: InvertRect() excludes right and bottom of rectangle.
3037      */
3038     rc.left = 0;
3039     rc.top = 0;
3040     rc.right = gui.num_cols * gui.char_width;
3041     rc.bottom = gui.num_rows * gui.char_height;
3042     InvertRect(s_hdc, &rc);
3043     gui_mch_flush();			/* make sure it's displayed */
3044 
3045     ui_delay((long)msec, TRUE);	/* wait for a few msec */
3046 
3047     InvertRect(s_hdc, &rc);
3048 }
3049 
3050 /*
3051  * Return flags used for scrolling.
3052  * The SW_INVALIDATE is required when part of the window is covered or
3053  * off-screen. Refer to MS KB Q75236.
3054  */
3055     static int
3056 get_scroll_flags(void)
3057 {
3058     HWND	hwnd;
3059     RECT	rcVim, rcOther, rcDest;
3060 
3061     GetWindowRect(s_hwnd, &rcVim);
3062 
3063     /* Check if the window is partly above or below the screen.  We don't care
3064      * about partly left or right of the screen, it is not relevant when
3065      * scrolling up or down. */
3066     if (rcVim.top < 0 || rcVim.bottom > GetSystemMetrics(SM_CYFULLSCREEN))
3067 	return SW_INVALIDATE;
3068 
3069     /* Check if there is an window (partly) on top of us. */
3070     for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; )
3071 	if (IsWindowVisible(hwnd))
3072 	{
3073 	    GetWindowRect(hwnd, &rcOther);
3074 	    if (IntersectRect(&rcDest, &rcVim, &rcOther))
3075 		return SW_INVALIDATE;
3076 	}
3077     return 0;
3078 }
3079 
3080 /*
3081  * On some Intel GPUs, the regions drawn just prior to ScrollWindowEx()
3082  * may not be scrolled out properly.
3083  * For gVim, when _OnScroll() is repeated, the character at the
3084  * previous cursor position may be left drawn after scroll.
3085  * The problem can be avoided by calling GetPixel() to get a pixel in
3086  * the region before ScrollWindowEx().
3087  */
3088     static void
3089 intel_gpu_workaround(void)
3090 {
3091     GetPixel(s_hdc, FILL_X(gui.col), FILL_Y(gui.row));
3092 }
3093 
3094 /*
3095  * Delete the given number of lines from the given row, scrolling up any
3096  * text further down within the scroll region.
3097  */
3098     void
3099 gui_mch_delete_lines(
3100     int	    row,
3101     int	    num_lines)
3102 {
3103     RECT	rc;
3104 
3105     rc.left = FILL_X(gui.scroll_region_left);
3106     rc.right = FILL_X(gui.scroll_region_right + 1);
3107     rc.top = FILL_Y(row);
3108     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
3109 
3110 #if defined(FEAT_DIRECTX)
3111     if (IS_ENABLE_DIRECTX())
3112     {
3113 	DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc);
3114 	DWriteContext_Flush(s_dwc);
3115     }
3116     else
3117 #endif
3118     {
3119 	intel_gpu_workaround();
3120 	ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height,
3121 				    &rc, &rc, NULL, NULL, get_scroll_flags());
3122 	UpdateWindow(s_textArea);
3123     }
3124 
3125     /* This seems to be required to avoid the cursor disappearing when
3126      * scrolling such that the cursor ends up in the top-left character on
3127      * the screen...   But why?  (Webb) */
3128     /* It's probably fixed by disabling drawing the cursor while scrolling. */
3129     /* gui.cursor_is_valid = FALSE; */
3130 
3131     gui_clear_block(gui.scroll_region_bot - num_lines + 1,
3132 						       gui.scroll_region_left,
3133 	gui.scroll_region_bot, gui.scroll_region_right);
3134 }
3135 
3136 /*
3137  * Insert the given number of lines before the given row, scrolling down any
3138  * following text within the scroll region.
3139  */
3140     void
3141 gui_mch_insert_lines(
3142     int		row,
3143     int		num_lines)
3144 {
3145     RECT	rc;
3146 
3147     rc.left = FILL_X(gui.scroll_region_left);
3148     rc.right = FILL_X(gui.scroll_region_right + 1);
3149     rc.top = FILL_Y(row);
3150     rc.bottom = FILL_Y(gui.scroll_region_bot + 1);
3151 
3152 #if defined(FEAT_DIRECTX)
3153     if (IS_ENABLE_DIRECTX())
3154     {
3155 	DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc);
3156 	DWriteContext_Flush(s_dwc);
3157     }
3158     else
3159 #endif
3160     {
3161 	intel_gpu_workaround();
3162 	/* The SW_INVALIDATE is required when part of the window is covered or
3163 	 * off-screen.  How do we avoid it when it's not needed? */
3164 	ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height,
3165 				    &rc, &rc, NULL, NULL, get_scroll_flags());
3166 	UpdateWindow(s_textArea);
3167     }
3168 
3169     gui_clear_block(row, gui.scroll_region_left,
3170 				row + num_lines - 1, gui.scroll_region_right);
3171 }
3172 
3173 
3174     void
3175 gui_mch_exit(int rc UNUSED)
3176 {
3177 #if defined(FEAT_DIRECTX)
3178     DWriteContext_Close(s_dwc);
3179     DWrite_Final();
3180     s_dwc = NULL;
3181 #endif
3182 
3183     ReleaseDC(s_textArea, s_hdc);
3184     DeleteObject(s_brush);
3185 
3186 #ifdef FEAT_TEAROFF
3187     /* Unload the tearoff bitmap */
3188     (void)DeleteObject((HGDIOBJ)s_htearbitmap);
3189 #endif
3190 
3191     /* Destroy our window (if we have one). */
3192     if (s_hwnd != NULL)
3193     {
3194 	destroying = TRUE;	/* ignore WM_DESTROY message now */
3195 	DestroyWindow(s_hwnd);
3196     }
3197 
3198 #ifdef GLOBAL_IME
3199     global_ime_end();
3200 #endif
3201 }
3202 
3203     static char_u *
3204 logfont2name(LOGFONT lf)
3205 {
3206     char	*p;
3207     char	*res;
3208     char	*charset_name;
3209     char	*quality_name;
3210     char	*font_name = lf.lfFaceName;
3211 
3212     charset_name = charset_id2name((int)lf.lfCharSet);
3213     /* Convert a font name from the current codepage to 'encoding'.
3214      * TODO: Use Wide APIs (including LOGFONTW) instead of ANSI APIs. */
3215     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
3216     {
3217 	int	len;
3218 	acp_to_enc((char_u *)lf.lfFaceName, (int)strlen(lf.lfFaceName),
3219 						(char_u **)&font_name, &len);
3220     }
3221     quality_name = quality_id2name((int)lf.lfQuality);
3222 
3223     res = (char *)alloc((unsigned)(strlen(font_name) + 20
3224 		    + (charset_name == NULL ? 0 : strlen(charset_name) + 2)));
3225     if (res != NULL)
3226     {
3227 	p = res;
3228 	/* make a normal font string out of the lf thing:*/
3229 	sprintf((char *)p, "%s:h%d", font_name, pixels_to_points(
3230 			 lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, TRUE));
3231 	while (*p)
3232 	{
3233 	    if (*p == ' ')
3234 		*p = '_';
3235 	    ++p;
3236 	}
3237 	if (lf.lfItalic)
3238 	    STRCAT(p, ":i");
3239 	if (lf.lfWeight >= FW_BOLD)
3240 	    STRCAT(p, ":b");
3241 	if (lf.lfUnderline)
3242 	    STRCAT(p, ":u");
3243 	if (lf.lfStrikeOut)
3244 	    STRCAT(p, ":s");
3245 	if (charset_name != NULL)
3246 	{
3247 	    STRCAT(p, ":c");
3248 	    STRCAT(p, charset_name);
3249 	}
3250 	if (quality_name != NULL)
3251 	{
3252 	    STRCAT(p, ":q");
3253 	    STRCAT(p, quality_name);
3254 	}
3255     }
3256 
3257     if (font_name != lf.lfFaceName)
3258 	vim_free(font_name);
3259     return (char_u *)res;
3260 }
3261 
3262 
3263 #ifdef FEAT_MBYTE_IME
3264 /*
3265  * Set correct LOGFONT to IME.  Use 'guifontwide' if available, otherwise use
3266  * 'guifont'
3267  */
3268     static void
3269 update_im_font(void)
3270 {
3271     LOGFONT	lf_wide;
3272 
3273     if (p_guifontwide != NULL && *p_guifontwide != NUL
3274 	    && gui.wide_font != NOFONT
3275 	    && GetObject((HFONT)gui.wide_font, sizeof(lf_wide), &lf_wide))
3276 	norm_logfont = lf_wide;
3277     else
3278 	norm_logfont = sub_logfont;
3279     im_set_font(&norm_logfont);
3280 }
3281 #endif
3282 
3283 /*
3284  * Handler of gui.wide_font (p_guifontwide) changed notification.
3285  */
3286     void
3287 gui_mch_wide_font_changed(void)
3288 {
3289     LOGFONT lf;
3290 
3291 #ifdef FEAT_MBYTE_IME
3292     update_im_font();
3293 #endif
3294 
3295     gui_mch_free_font(gui.wide_ital_font);
3296     gui.wide_ital_font = NOFONT;
3297     gui_mch_free_font(gui.wide_bold_font);
3298     gui.wide_bold_font = NOFONT;
3299     gui_mch_free_font(gui.wide_boldital_font);
3300     gui.wide_boldital_font = NOFONT;
3301 
3302     if (gui.wide_font
3303 	&& GetObject((HFONT)gui.wide_font, sizeof(lf), &lf))
3304     {
3305 	if (!lf.lfItalic)
3306 	{
3307 	    lf.lfItalic = TRUE;
3308 	    gui.wide_ital_font = get_font_handle(&lf);
3309 	    lf.lfItalic = FALSE;
3310 	}
3311 	if (lf.lfWeight < FW_BOLD)
3312 	{
3313 	    lf.lfWeight = FW_BOLD;
3314 	    gui.wide_bold_font = get_font_handle(&lf);
3315 	    if (!lf.lfItalic)
3316 	    {
3317 		lf.lfItalic = TRUE;
3318 		gui.wide_boldital_font = get_font_handle(&lf);
3319 	    }
3320 	}
3321     }
3322 }
3323 
3324 /*
3325  * Initialise vim to use the font with the given name.
3326  * Return FAIL if the font could not be loaded, OK otherwise.
3327  */
3328     int
3329 gui_mch_init_font(char_u *font_name, int fontset UNUSED)
3330 {
3331     LOGFONT	lf;
3332     GuiFont	font = NOFONT;
3333     char_u	*p;
3334 
3335     /* Load the font */
3336     if (get_logfont(&lf, font_name, NULL, TRUE) == OK)
3337 	font = get_font_handle(&lf);
3338     if (font == NOFONT)
3339 	return FAIL;
3340 
3341     if (font_name == NULL)
3342 	font_name = (char_u *)lf.lfFaceName;
3343 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
3344     norm_logfont = lf;
3345 #endif
3346 #ifdef FEAT_MBYTE_IME
3347     sub_logfont = lf;
3348 #endif
3349 #ifdef FEAT_MBYTE_IME
3350     update_im_font();
3351 #endif
3352     gui_mch_free_font(gui.norm_font);
3353     gui.norm_font = font;
3354     current_font_height = lf.lfHeight;
3355     GetFontSize(font);
3356 
3357     p = logfont2name(lf);
3358     if (p != NULL)
3359     {
3360 	hl_set_font_name(p);
3361 
3362 	/* When setting 'guifont' to "*" replace it with the actual font name.
3363 	 * */
3364 	if (STRCMP(font_name, "*") == 0 && STRCMP(p_guifont, "*") == 0)
3365 	{
3366 	    vim_free(p_guifont);
3367 	    p_guifont = p;
3368 	}
3369 	else
3370 	    vim_free(p);
3371     }
3372 
3373     gui_mch_free_font(gui.ital_font);
3374     gui.ital_font = NOFONT;
3375     gui_mch_free_font(gui.bold_font);
3376     gui.bold_font = NOFONT;
3377     gui_mch_free_font(gui.boldital_font);
3378     gui.boldital_font = NOFONT;
3379 
3380     if (!lf.lfItalic)
3381     {
3382 	lf.lfItalic = TRUE;
3383 	gui.ital_font = get_font_handle(&lf);
3384 	lf.lfItalic = FALSE;
3385     }
3386     if (lf.lfWeight < FW_BOLD)
3387     {
3388 	lf.lfWeight = FW_BOLD;
3389 	gui.bold_font = get_font_handle(&lf);
3390 	if (!lf.lfItalic)
3391 	{
3392 	    lf.lfItalic = TRUE;
3393 	    gui.boldital_font = get_font_handle(&lf);
3394 	}
3395     }
3396 
3397     return OK;
3398 }
3399 
3400 #ifndef WPF_RESTORETOMAXIMIZED
3401 # define WPF_RESTORETOMAXIMIZED 2   /* just in case someone doesn't have it */
3402 #endif
3403 
3404 /*
3405  * Return TRUE if the GUI window is maximized, filling the whole screen.
3406  */
3407     int
3408 gui_mch_maximized(void)
3409 {
3410     WINDOWPLACEMENT wp;
3411 
3412     wp.length = sizeof(WINDOWPLACEMENT);
3413     if (GetWindowPlacement(s_hwnd, &wp))
3414 	return wp.showCmd == SW_SHOWMAXIMIZED
3415 	    || (wp.showCmd == SW_SHOWMINIMIZED
3416 		    && wp.flags == WPF_RESTORETOMAXIMIZED);
3417 
3418     return 0;
3419 }
3420 
3421 /*
3422  * Called when the font changed while the window is maximized or GO_KEEPWINSIZE
3423  * is set.  Compute the new Rows and Columns.  This is like resizing the
3424  * window.
3425  */
3426     void
3427 gui_mch_newfont(void)
3428 {
3429     RECT	rect;
3430 
3431     GetWindowRect(s_hwnd, &rect);
3432     if (win_socket_id == 0)
3433     {
3434 	gui_resize_shell(rect.right - rect.left
3435 	    - (GetSystemMetrics(SM_CXFRAME) +
3436 	       GetSystemMetrics(SM_CXPADDEDBORDER)) * 2,
3437 	    rect.bottom - rect.top
3438 	    - (GetSystemMetrics(SM_CYFRAME) +
3439 	       GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
3440 	    - GetSystemMetrics(SM_CYCAPTION)
3441 #ifdef FEAT_MENU
3442 	    - gui_mswin_get_menu_height(FALSE)
3443 #endif
3444 	);
3445     }
3446     else
3447     {
3448 	/* Inside another window, don't use the frame and border. */
3449 	gui_resize_shell(rect.right - rect.left,
3450 	    rect.bottom - rect.top
3451 #ifdef FEAT_MENU
3452 			- gui_mswin_get_menu_height(FALSE)
3453 #endif
3454 	);
3455     }
3456 }
3457 
3458 /*
3459  * Set the window title
3460  */
3461     void
3462 gui_mch_settitle(
3463     char_u  *title,
3464     char_u  *icon UNUSED)
3465 {
3466     set_window_title(s_hwnd, (title == NULL ? "VIM" : (char *)title));
3467 }
3468 
3469 #if defined(FEAT_MOUSESHAPE) || defined(PROTO)
3470 /* Table for shape IDCs.  Keep in sync with the mshape_names[] table in
3471  * misc2.c! */
3472 static LPCSTR mshape_idcs[] =
3473 {
3474     IDC_ARROW,			/* arrow */
3475     MAKEINTRESOURCE(0),		/* blank */
3476     IDC_IBEAM,			/* beam */
3477     IDC_SIZENS,			/* updown */
3478     IDC_SIZENS,			/* udsizing */
3479     IDC_SIZEWE,			/* leftright */
3480     IDC_SIZEWE,			/* lrsizing */
3481     IDC_WAIT,			/* busy */
3482     IDC_NO,			/* no */
3483     IDC_ARROW,			/* crosshair */
3484     IDC_ARROW,			/* hand1 */
3485     IDC_ARROW,			/* hand2 */
3486     IDC_ARROW,			/* pencil */
3487     IDC_ARROW,			/* question */
3488     IDC_ARROW,			/* right-arrow */
3489     IDC_UPARROW,		/* up-arrow */
3490     IDC_ARROW			/* last one */
3491 };
3492 
3493     void
3494 mch_set_mouse_shape(int shape)
3495 {
3496     LPCSTR idc;
3497 
3498     if (shape == MSHAPE_HIDE)
3499 	ShowCursor(FALSE);
3500     else
3501     {
3502 	if (shape >= MSHAPE_NUMBERED)
3503 	    idc = IDC_ARROW;
3504 	else
3505 	    idc = mshape_idcs[shape];
3506 #ifdef SetClassLongPtr
3507 	SetClassLongPtr(s_textArea, GCLP_HCURSOR, (__int3264)(LONG_PTR)LoadCursor(NULL, idc));
3508 #else
3509 	SetClassLong(s_textArea, GCL_HCURSOR, (long_u)LoadCursor(NULL, idc));
3510 #endif
3511 	if (!p_mh)
3512 	{
3513 	    POINT mp;
3514 
3515 	    /* Set the position to make it redrawn with the new shape. */
3516 	    (void)GetCursorPos((LPPOINT)&mp);
3517 	    (void)SetCursorPos(mp.x, mp.y);
3518 	    ShowCursor(TRUE);
3519 	}
3520     }
3521 }
3522 #endif
3523 
3524 #if defined(FEAT_BROWSE) || defined(PROTO)
3525 /*
3526  * Wide version of convert_filter().
3527  */
3528     static WCHAR *
3529 convert_filterW(char_u *s)
3530 {
3531     char_u *tmp;
3532     int len;
3533     WCHAR *res;
3534 
3535     tmp = convert_filter(s);
3536     if (tmp == NULL)
3537 	return NULL;
3538     len = (int)STRLEN(s) + 3;
3539     res = enc_to_utf16(tmp, &len);
3540     vim_free(tmp);
3541     return res;
3542 }
3543 
3544 /*
3545  * Pop open a file browser and return the file selected, in allocated memory,
3546  * or NULL if Cancel is hit.
3547  *  saving  - TRUE if the file will be saved to, FALSE if it will be opened.
3548  *  title   - Title message for the file browser dialog.
3549  *  dflt    - Default name of file.
3550  *  ext     - Default extension to be added to files without extensions.
3551  *  initdir - directory in which to open the browser (NULL = current dir)
3552  *  filter  - Filter for matched files to choose from.
3553  */
3554     char_u *
3555 gui_mch_browse(
3556 	int saving,
3557 	char_u *title,
3558 	char_u *dflt,
3559 	char_u *ext,
3560 	char_u *initdir,
3561 	char_u *filter)
3562 {
3563     /* We always use the wide function.  This means enc_to_utf16() must work,
3564      * otherwise it fails miserably! */
3565     OPENFILENAMEW	fileStruct;
3566     WCHAR		fileBuf[MAXPATHL];
3567     WCHAR		*wp;
3568     int			i;
3569     WCHAR		*titlep = NULL;
3570     WCHAR		*extp = NULL;
3571     WCHAR		*initdirp = NULL;
3572     WCHAR		*filterp;
3573     char_u		*p, *q;
3574 
3575     if (dflt == NULL)
3576 	fileBuf[0] = NUL;
3577     else
3578     {
3579 	wp = enc_to_utf16(dflt, NULL);
3580 	if (wp == NULL)
3581 	    fileBuf[0] = NUL;
3582 	else
3583 	{
3584 	    for (i = 0; wp[i] != NUL && i < MAXPATHL - 1; ++i)
3585 		fileBuf[i] = wp[i];
3586 	    fileBuf[i] = NUL;
3587 	    vim_free(wp);
3588 	}
3589     }
3590 
3591     /* Convert the filter to Windows format. */
3592     filterp = convert_filterW(filter);
3593 
3594     vim_memset(&fileStruct, 0, sizeof(OPENFILENAMEW));
3595 #  ifdef OPENFILENAME_SIZE_VERSION_400W
3596     /* be compatible with Windows NT 4.0 */
3597     fileStruct.lStructSize = OPENFILENAME_SIZE_VERSION_400W;
3598 #  else
3599     fileStruct.lStructSize = sizeof(fileStruct);
3600 #  endif
3601 
3602     if (title != NULL)
3603 	titlep = enc_to_utf16(title, NULL);
3604     fileStruct.lpstrTitle = titlep;
3605 
3606     if (ext != NULL)
3607 	extp = enc_to_utf16(ext, NULL);
3608     fileStruct.lpstrDefExt = extp;
3609 
3610     fileStruct.lpstrFile = fileBuf;
3611     fileStruct.nMaxFile = MAXPATHL;
3612     fileStruct.lpstrFilter = filterp;
3613     fileStruct.hwndOwner = s_hwnd;		/* main Vim window is owner*/
3614     /* has an initial dir been specified? */
3615     if (initdir != NULL && *initdir != NUL)
3616     {
3617 	/* Must have backslashes here, no matter what 'shellslash' says */
3618 	initdirp = enc_to_utf16(initdir, NULL);
3619 	if (initdirp != NULL)
3620 	{
3621 	    for (wp = initdirp; *wp != NUL; ++wp)
3622 		if (*wp == '/')
3623 		    *wp = '\\';
3624 	}
3625 	fileStruct.lpstrInitialDir = initdirp;
3626     }
3627 
3628     /*
3629      * TODO: Allow selection of multiple files.  Needs another arg to this
3630      * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3631      * Also, should we use OFN_FILEMUSTEXIST when opening?  Vim can edit on
3632      * files that don't exist yet, so I haven't put it in.  What about
3633      * OFN_PATHMUSTEXIST?
3634      * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3635      */
3636     fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY);
3637 #  ifdef FEAT_SHORTCUT
3638     if (curbuf->b_p_bin)
3639 	fileStruct.Flags |= OFN_NODEREFERENCELINKS;
3640 #  endif
3641     if (saving)
3642     {
3643 	if (!GetSaveFileNameW(&fileStruct))
3644 	    return NULL;
3645     }
3646     else
3647     {
3648 	if (!GetOpenFileNameW(&fileStruct))
3649 	    return NULL;
3650     }
3651 
3652     vim_free(filterp);
3653     vim_free(initdirp);
3654     vim_free(titlep);
3655     vim_free(extp);
3656 
3657     /* Convert from UCS2 to 'encoding'. */
3658     p = utf16_to_enc(fileBuf, NULL);
3659     if (p == NULL)
3660 	return NULL;
3661 
3662     /* Give focus back to main window (when using MDI). */
3663     SetFocus(s_hwnd);
3664 
3665     /* Shorten the file name if possible */
3666     q = vim_strsave(shorten_fname1(p));
3667     vim_free(p);
3668     return q;
3669 }
3670 
3671 
3672 /*
3673  * Convert the string s to the proper format for a filter string by replacing
3674  * the \t and \n delimiters with \0.
3675  * Returns the converted string in allocated memory.
3676  *
3677  * Keep in sync with convert_filterW() above!
3678  */
3679     static char_u *
3680 convert_filter(char_u *s)
3681 {
3682     char_u	*res;
3683     unsigned	s_len = (unsigned)STRLEN(s);
3684     unsigned	i;
3685 
3686     res = alloc(s_len + 3);
3687     if (res != NULL)
3688     {
3689 	for (i = 0; i < s_len; ++i)
3690 	    if (s[i] == '\t' || s[i] == '\n')
3691 		res[i] = '\0';
3692 	    else
3693 		res[i] = s[i];
3694 	res[s_len] = NUL;
3695 	/* Add two extra NULs to make sure it's properly terminated. */
3696 	res[s_len + 1] = NUL;
3697 	res[s_len + 2] = NUL;
3698     }
3699     return res;
3700 }
3701 
3702 /*
3703  * Select a directory.
3704  */
3705     char_u *
3706 gui_mch_browsedir(char_u *title, char_u *initdir)
3707 {
3708     /* We fake this: Use a filter that doesn't select anything and a default
3709      * file name that won't be used. */
3710     return gui_mch_browse(0, title, (char_u *)_("Not Used"), NULL,
3711 			      initdir, (char_u *)_("Directory\t*.nothing\n"));
3712 }
3713 #endif /* FEAT_BROWSE */
3714 
3715     static void
3716 _OnDropFiles(
3717     HWND hwnd UNUSED,
3718     HDROP hDrop)
3719 {
3720 #define BUFPATHLEN _MAX_PATH
3721 #define DRAGQVAL 0xFFFFFFFF
3722     WCHAR   wszFile[BUFPATHLEN];
3723     char    szFile[BUFPATHLEN];
3724     UINT    cFiles = DragQueryFile(hDrop, DRAGQVAL, NULL, 0);
3725     UINT    i;
3726     char_u  **fnames;
3727     POINT   pt;
3728     int_u   modifiers = 0;
3729 
3730     /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3731 
3732     /* Obtain dropped position */
3733     DragQueryPoint(hDrop, &pt);
3734     MapWindowPoints(s_hwnd, s_textArea, &pt, 1);
3735 
3736     reset_VIsual();
3737 
3738     fnames = (char_u **)alloc(cFiles * sizeof(char_u *));
3739 
3740     if (fnames != NULL)
3741 	for (i = 0; i < cFiles; ++i)
3742 	{
3743 	    if (DragQueryFileW(hDrop, i, wszFile, BUFPATHLEN) > 0)
3744 		fnames[i] = utf16_to_enc(wszFile, NULL);
3745 	    else
3746 	    {
3747 		DragQueryFile(hDrop, i, szFile, BUFPATHLEN);
3748 		fnames[i] = vim_strsave((char_u *)szFile);
3749 	    }
3750 	}
3751 
3752     DragFinish(hDrop);
3753 
3754     if (fnames != NULL)
3755     {
3756 	if ((GetKeyState(VK_SHIFT) & 0x8000) != 0)
3757 	    modifiers |= MOUSE_SHIFT;
3758 	if ((GetKeyState(VK_CONTROL) & 0x8000) != 0)
3759 	    modifiers |= MOUSE_CTRL;
3760 	if ((GetKeyState(VK_MENU) & 0x8000) != 0)
3761 	    modifiers |= MOUSE_ALT;
3762 
3763 	gui_handle_drop(pt.x, pt.y, modifiers, fnames, cFiles);
3764 
3765 	s_need_activate = TRUE;
3766     }
3767 }
3768 
3769     static int
3770 _OnScroll(
3771     HWND hwnd UNUSED,
3772     HWND hwndCtl,
3773     UINT code,
3774     int pos)
3775 {
3776     static UINT	prev_code = 0;   /* code of previous call */
3777     scrollbar_T *sb, *sb_info;
3778     long	val;
3779     int		dragging = FALSE;
3780     int		dont_scroll_save = dont_scroll;
3781     SCROLLINFO	si;
3782 
3783     si.cbSize = sizeof(si);
3784     si.fMask = SIF_POS;
3785 
3786     sb = gui_mswin_find_scrollbar(hwndCtl);
3787     if (sb == NULL)
3788 	return 0;
3789 
3790     if (sb->wp != NULL)		/* Left or right scrollbar */
3791     {
3792 	/*
3793 	 * Careful: need to get scrollbar info out of first (left) scrollbar
3794 	 * for window, but keep real scrollbar too because we must pass it to
3795 	 * gui_drag_scrollbar().
3796 	 */
3797 	sb_info = &sb->wp->w_scrollbars[0];
3798     }
3799     else	    /* Bottom scrollbar */
3800 	sb_info = sb;
3801     val = sb_info->value;
3802 
3803     switch (code)
3804     {
3805 	case SB_THUMBTRACK:
3806 	    val = pos;
3807 	    dragging = TRUE;
3808 	    if (sb->scroll_shift > 0)
3809 		val <<= sb->scroll_shift;
3810 	    break;
3811 	case SB_LINEDOWN:
3812 	    val++;
3813 	    break;
3814 	case SB_LINEUP:
3815 	    val--;
3816 	    break;
3817 	case SB_PAGEDOWN:
3818 	    val += (sb_info->size > 2 ? sb_info->size - 2 : 1);
3819 	    break;
3820 	case SB_PAGEUP:
3821 	    val -= (sb_info->size > 2 ? sb_info->size - 2 : 1);
3822 	    break;
3823 	case SB_TOP:
3824 	    val = 0;
3825 	    break;
3826 	case SB_BOTTOM:
3827 	    val = sb_info->max;
3828 	    break;
3829 	case SB_ENDSCROLL:
3830 	    if (prev_code == SB_THUMBTRACK)
3831 	    {
3832 		/*
3833 		 * "pos" only gives us 16-bit data.  In case of large file,
3834 		 * use GetScrollPos() which returns 32-bit.  Unfortunately it
3835 		 * is not valid while the scrollbar is being dragged.
3836 		 */
3837 		val = GetScrollPos(hwndCtl, SB_CTL);
3838 		if (sb->scroll_shift > 0)
3839 		    val <<= sb->scroll_shift;
3840 	    }
3841 	    break;
3842 
3843 	default:
3844 	    /* TRACE("Unknown scrollbar event %d\n", code); */
3845 	    return 0;
3846     }
3847     prev_code = code;
3848 
3849     si.nPos = (sb->scroll_shift > 0) ? val >> sb->scroll_shift : val;
3850     SetScrollInfo(hwndCtl, SB_CTL, &si, TRUE);
3851 
3852     /*
3853      * When moving a vertical scrollbar, move the other vertical scrollbar too.
3854      */
3855     if (sb->wp != NULL)
3856     {
3857 	scrollbar_T *sba = sb->wp->w_scrollbars;
3858 	HWND    id = sba[ (sb == sba + SBAR_LEFT) ? SBAR_RIGHT : SBAR_LEFT].id;
3859 
3860 	SetScrollInfo(id, SB_CTL, &si, TRUE);
3861     }
3862 
3863     /* Don't let us be interrupted here by another message. */
3864     s_busy_processing = TRUE;
3865 
3866     /* When "allow_scrollbar" is FALSE still need to remember the new
3867      * position, but don't actually scroll by setting "dont_scroll". */
3868     dont_scroll = !allow_scrollbar;
3869 
3870     mch_disable_flush();
3871     gui_drag_scrollbar(sb, val, dragging);
3872     mch_enable_flush();
3873     gui_may_flush();
3874 
3875     s_busy_processing = FALSE;
3876     dont_scroll = dont_scroll_save;
3877 
3878     return 0;
3879 }
3880 
3881 
3882 #ifdef FEAT_XPM_W32
3883 # include "xpm_w32.h"
3884 #endif
3885 
3886 #ifdef PROTO
3887 # define WINAPI
3888 #endif
3889 
3890 #ifdef __MINGW32__
3891 /*
3892  * Add a lot of missing defines.
3893  * They are not always missing, we need the #ifndef's.
3894  */
3895 # ifndef _cdecl
3896 #  define _cdecl
3897 # endif
3898 # ifndef IsMinimized
3899 #  define     IsMinimized(hwnd)		IsIconic(hwnd)
3900 # endif
3901 # ifndef IsMaximized
3902 #  define     IsMaximized(hwnd)		IsZoomed(hwnd)
3903 # endif
3904 # ifndef SelectFont
3905 #  define     SelectFont(hdc, hfont)  ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
3906 # endif
3907 # ifndef GetStockBrush
3908 #  define     GetStockBrush(i)     ((HBRUSH)GetStockObject(i))
3909 # endif
3910 # ifndef DeleteBrush
3911 #  define     DeleteBrush(hbr)     DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
3912 # endif
3913 
3914 # ifndef HANDLE_WM_RBUTTONDBLCLK
3915 #  define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
3916     ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3917 # endif
3918 # ifndef HANDLE_WM_MBUTTONUP
3919 #  define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
3920     ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3921 # endif
3922 # ifndef HANDLE_WM_MBUTTONDBLCLK
3923 #  define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
3924     ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3925 # endif
3926 # ifndef HANDLE_WM_LBUTTONDBLCLK
3927 #  define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
3928     ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3929 # endif
3930 # ifndef HANDLE_WM_RBUTTONDOWN
3931 #  define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
3932     ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3933 # endif
3934 # ifndef HANDLE_WM_MOUSEMOVE
3935 #  define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
3936     ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3937 # endif
3938 # ifndef HANDLE_WM_RBUTTONUP
3939 #  define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
3940     ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3941 # endif
3942 # ifndef HANDLE_WM_MBUTTONDOWN
3943 #  define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
3944     ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3945 # endif
3946 # ifndef HANDLE_WM_LBUTTONUP
3947 #  define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
3948     ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3949 # endif
3950 # ifndef HANDLE_WM_LBUTTONDOWN
3951 #  define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
3952     ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
3953 # endif
3954 # ifndef HANDLE_WM_SYSCHAR
3955 #  define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
3956     ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
3957 # endif
3958 # ifndef HANDLE_WM_ACTIVATEAPP
3959 #  define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
3960     ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
3961 # endif
3962 # ifndef HANDLE_WM_WINDOWPOSCHANGING
3963 #  define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
3964     (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
3965 # endif
3966 # ifndef HANDLE_WM_VSCROLL
3967 #  define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
3968     ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)),  (int)(short)HIWORD(wParam)), 0L)
3969 # endif
3970 # ifndef HANDLE_WM_SETFOCUS
3971 #  define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
3972     ((fn)((hwnd), (HWND)(wParam)), 0L)
3973 # endif
3974 # ifndef HANDLE_WM_KILLFOCUS
3975 #  define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
3976     ((fn)((hwnd), (HWND)(wParam)), 0L)
3977 # endif
3978 # ifndef HANDLE_WM_HSCROLL
3979 #  define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
3980     ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
3981 # endif
3982 # ifndef HANDLE_WM_DROPFILES
3983 #  define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
3984     ((fn)((hwnd), (HDROP)(wParam)), 0L)
3985 # endif
3986 # ifndef HANDLE_WM_CHAR
3987 #  define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
3988     ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
3989 # endif
3990 # ifndef HANDLE_WM_SYSDEADCHAR
3991 #  define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
3992     ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
3993 # endif
3994 # ifndef HANDLE_WM_DEADCHAR
3995 #  define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
3996     ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
3997 # endif
3998 #endif /* __MINGW32__ */
3999 
4000 
4001 /* Some parameters for tearoff menus.  All in pixels. */
4002 #define TEAROFF_PADDING_X	2
4003 #define TEAROFF_BUTTON_PAD_X	8
4004 #define TEAROFF_MIN_WIDTH	200
4005 #define TEAROFF_SUBMENU_LABEL	">>"
4006 #define TEAROFF_COLUMN_PADDING	3	// # spaces to pad column with.
4007 
4008 
4009 /* For the Intellimouse: */
4010 #ifndef WM_MOUSEWHEEL
4011 #define WM_MOUSEWHEEL	0x20a
4012 #endif
4013 
4014 
4015 #ifdef FEAT_BEVAL_GUI
4016 # define ID_BEVAL_TOOLTIP   200
4017 # define BEVAL_TEXT_LEN	    MAXPATHL
4018 
4019 #if (defined(_MSC_VER) && _MSC_VER < 1300) || !defined(MAXULONG_PTR)
4020 /* Work around old versions of basetsd.h which wrongly declares
4021  * UINT_PTR as unsigned long. */
4022 # undef  UINT_PTR
4023 # define UINT_PTR UINT
4024 #endif
4025 
4026 static BalloonEval  *cur_beval = NULL;
4027 static UINT_PTR	    BevalTimerId = 0;
4028 static DWORD	    LastActivity = 0;
4029 
4030 
4031 /* cproto fails on missing include files */
4032 #ifndef PROTO
4033 
4034 /*
4035  * excerpts from headers since this may not be presented
4036  * in the extremely old compilers
4037  */
4038 # include <pshpack1.h>
4039 
4040 #endif
4041 
4042 typedef struct _DllVersionInfo
4043 {
4044     DWORD cbSize;
4045     DWORD dwMajorVersion;
4046     DWORD dwMinorVersion;
4047     DWORD dwBuildNumber;
4048     DWORD dwPlatformID;
4049 } DLLVERSIONINFO;
4050 
4051 #ifndef PROTO
4052 # include <poppack.h>
4053 #endif
4054 
4055 typedef struct tagTOOLINFOA_NEW
4056 {
4057     UINT       cbSize;
4058     UINT       uFlags;
4059     HWND       hwnd;
4060     UINT_PTR   uId;
4061     RECT       rect;
4062     HINSTANCE  hinst;
4063     LPSTR      lpszText;
4064     LPARAM     lParam;
4065 } TOOLINFO_NEW;
4066 
4067 typedef struct tagNMTTDISPINFO_NEW
4068 {
4069     NMHDR      hdr;
4070     LPSTR      lpszText;
4071     char       szText[80];
4072     HINSTANCE  hinst;
4073     UINT       uFlags;
4074     LPARAM     lParam;
4075 } NMTTDISPINFO_NEW;
4076 
4077 typedef struct tagTOOLINFOW_NEW
4078 {
4079     UINT       cbSize;
4080     UINT       uFlags;
4081     HWND       hwnd;
4082     UINT_PTR   uId;
4083     RECT       rect;
4084     HINSTANCE  hinst;
4085     LPWSTR     lpszText;
4086     LPARAM     lParam;
4087     void       *lpReserved;
4088 } TOOLINFOW_NEW;
4089 
4090 typedef struct tagNMTTDISPINFOW_NEW
4091 {
4092     NMHDR      hdr;
4093     LPWSTR     lpszText;
4094     WCHAR      szText[80];
4095     HINSTANCE  hinst;
4096     UINT       uFlags;
4097     LPARAM     lParam;
4098 } NMTTDISPINFOW_NEW;
4099 
4100 
4101 typedef HRESULT (WINAPI* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
4102 #ifndef TTM_SETMAXTIPWIDTH
4103 # define TTM_SETMAXTIPWIDTH	(WM_USER+24)
4104 #endif
4105 
4106 #ifndef TTF_DI_SETITEM
4107 # define TTF_DI_SETITEM		0x8000
4108 #endif
4109 
4110 #ifndef TTN_GETDISPINFO
4111 # define TTN_GETDISPINFO	(TTN_FIRST - 0)
4112 #endif
4113 
4114 #endif /* defined(FEAT_BEVAL_GUI) */
4115 
4116 #if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
4117 /* Older MSVC compilers don't have LPNMTTDISPINFO[AW] thus we need to define
4118  * it here if LPNMTTDISPINFO isn't defined.
4119  * MingW doesn't define LPNMTTDISPINFO but typedefs it.  Thus we need to check
4120  * _MSC_VER. */
4121 # if !defined(LPNMTTDISPINFO) && defined(_MSC_VER)
4122 typedef struct tagNMTTDISPINFOA {
4123     NMHDR	hdr;
4124     LPSTR	lpszText;
4125     char	szText[80];
4126     HINSTANCE	hinst;
4127     UINT	uFlags;
4128     LPARAM	lParam;
4129 } NMTTDISPINFOA, *LPNMTTDISPINFOA;
4130 #  define LPNMTTDISPINFO LPNMTTDISPINFOA
4131 
4132 typedef struct tagNMTTDISPINFOW {
4133     NMHDR	hdr;
4134     LPWSTR	lpszText;
4135     WCHAR	szText[80];
4136     HINSTANCE	hinst;
4137     UINT	uFlags;
4138     LPARAM	lParam;
4139 } NMTTDISPINFOW, *LPNMTTDISPINFOW;
4140 # endif
4141 #endif
4142 
4143 #ifndef TTN_GETDISPINFOW
4144 # define TTN_GETDISPINFOW	(TTN_FIRST - 10)
4145 #endif
4146 
4147 /* Local variables: */
4148 
4149 #ifdef FEAT_MENU
4150 static UINT	s_menu_id = 100;
4151 #endif
4152 
4153 /*
4154  * Use the system font for dialogs and tear-off menus.  Remove this line to
4155  * use DLG_FONT_NAME.
4156  */
4157 #define USE_SYSMENU_FONT
4158 
4159 #define VIM_NAME	"vim"
4160 #define VIM_CLASS	"Vim"
4161 #define VIM_CLASSW	L"Vim"
4162 
4163 /* Initial size for the dialog template.  For gui_mch_dialog() it's fixed,
4164  * thus there should be room for every dialog.  For tearoffs it's made bigger
4165  * when needed. */
4166 #define DLG_ALLOC_SIZE 16 * 1024
4167 
4168 /*
4169  * stuff for dialogs, menus, tearoffs etc.
4170  */
4171 static PWORD
4172 add_dialog_element(
4173 	PWORD p,
4174 	DWORD lStyle,
4175 	WORD x,
4176 	WORD y,
4177 	WORD w,
4178 	WORD h,
4179 	WORD Id,
4180 	WORD clss,
4181 	const char *caption);
4182 static LPWORD lpwAlign(LPWORD);
4183 static int nCopyAnsiToWideChar(LPWORD, LPSTR, BOOL);
4184 #if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
4185 static void gui_mch_tearoff(char_u *title, vimmenu_T *menu, int initX, int initY);
4186 #endif
4187 static void get_dialog_font_metrics(void);
4188 
4189 static int dialog_default_button = -1;
4190 
4191 /* Intellimouse support */
4192 static int mouse_scroll_lines = 0;
4193 
4194 static int	s_usenewlook;	    /* emulate W95/NT4 non-bold dialogs */
4195 #ifdef FEAT_TOOLBAR
4196 static void initialise_toolbar(void);
4197 static LRESULT CALLBACK toolbar_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
4198 static int get_toolbar_bitmap(vimmenu_T *menu);
4199 #endif
4200 
4201 #ifdef FEAT_GUI_TABLINE
4202 static void initialise_tabline(void);
4203 static LRESULT CALLBACK tabline_wndproc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
4204 #endif
4205 
4206 #ifdef FEAT_MBYTE_IME
4207 static LRESULT _OnImeComposition(HWND hwnd, WPARAM dbcs, LPARAM param);
4208 static char_u *GetResultStr(HWND hwnd, int GCS, int *lenp);
4209 #endif
4210 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
4211 # ifdef NOIME
4212 typedef struct tagCOMPOSITIONFORM {
4213     DWORD dwStyle;
4214     POINT ptCurrentPos;
4215     RECT  rcArea;
4216 } COMPOSITIONFORM, *PCOMPOSITIONFORM, NEAR *NPCOMPOSITIONFORM, FAR *LPCOMPOSITIONFORM;
4217 typedef HANDLE HIMC;
4218 # endif
4219 
4220 static HINSTANCE hLibImm = NULL;
4221 static LONG (WINAPI *pImmGetCompositionStringA)(HIMC, DWORD, LPVOID, DWORD);
4222 static LONG (WINAPI *pImmGetCompositionStringW)(HIMC, DWORD, LPVOID, DWORD);
4223 static HIMC (WINAPI *pImmGetContext)(HWND);
4224 static HIMC (WINAPI *pImmAssociateContext)(HWND, HIMC);
4225 static BOOL (WINAPI *pImmReleaseContext)(HWND, HIMC);
4226 static BOOL (WINAPI *pImmGetOpenStatus)(HIMC);
4227 static BOOL (WINAPI *pImmSetOpenStatus)(HIMC, BOOL);
4228 static BOOL (WINAPI *pImmGetCompositionFont)(HIMC, LPLOGFONTA);
4229 static BOOL (WINAPI *pImmSetCompositionFont)(HIMC, LPLOGFONTA);
4230 static BOOL (WINAPI *pImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
4231 static BOOL (WINAPI *pImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
4232 static BOOL (WINAPI *pImmSetConversionStatus)(HIMC, DWORD, DWORD);
4233 static void dyn_imm_load(void);
4234 #else
4235 # define pImmGetCompositionStringA ImmGetCompositionStringA
4236 # define pImmGetCompositionStringW ImmGetCompositionStringW
4237 # define pImmGetContext		  ImmGetContext
4238 # define pImmAssociateContext	  ImmAssociateContext
4239 # define pImmReleaseContext	  ImmReleaseContext
4240 # define pImmGetOpenStatus	  ImmGetOpenStatus
4241 # define pImmSetOpenStatus	  ImmSetOpenStatus
4242 # define pImmGetCompositionFont   ImmGetCompositionFontA
4243 # define pImmSetCompositionFont   ImmSetCompositionFontA
4244 # define pImmSetCompositionWindow ImmSetCompositionWindow
4245 # define pImmGetConversionStatus  ImmGetConversionStatus
4246 # define pImmSetConversionStatus  ImmSetConversionStatus
4247 #endif
4248 
4249 #ifdef FEAT_MENU
4250 /*
4251  * Figure out how high the menu bar is at the moment.
4252  */
4253     static int
4254 gui_mswin_get_menu_height(
4255     int	    fix_window)	    /* If TRUE, resize window if menu height changed */
4256 {
4257     static int	old_menu_height = -1;
4258 
4259     RECT    rc1, rc2;
4260     int	    num;
4261     int	    menu_height;
4262 
4263     if (gui.menu_is_active)
4264 	num = GetMenuItemCount(s_menuBar);
4265     else
4266 	num = 0;
4267 
4268     if (num == 0)
4269 	menu_height = 0;
4270     else if (IsMinimized(s_hwnd))
4271     {
4272 	/* The height of the menu cannot be determined while the window is
4273 	 * minimized.  Take the previous height if the menu is changed in that
4274 	 * state, to avoid that Vim's vertical window size accidentally
4275 	 * increases due to the unaccounted-for menu height. */
4276 	menu_height = old_menu_height == -1 ? 0 : old_menu_height;
4277     }
4278     else
4279     {
4280 	/*
4281 	 * In case 'lines' is set in _vimrc/_gvimrc window width doesn't
4282 	 * seem to have been set yet, so menu wraps in default window
4283 	 * width which is very narrow.  Instead just return height of a
4284 	 * single menu item.  Will still be wrong when the menu really
4285 	 * should wrap over more than one line.
4286 	 */
4287 	GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1);
4288 	if (gui.starting)
4289 	    menu_height = rc1.bottom - rc1.top + 1;
4290 	else
4291 	{
4292 	    GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2);
4293 	    menu_height = rc2.bottom - rc1.top + 1;
4294 	}
4295     }
4296 
4297     if (fix_window && menu_height != old_menu_height)
4298     {
4299 	gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
4300     }
4301     old_menu_height = menu_height;
4302 
4303     return menu_height;
4304 }
4305 #endif /*FEAT_MENU*/
4306 
4307 
4308 /*
4309  * Setup for the Intellimouse
4310  */
4311     static void
4312 init_mouse_wheel(void)
4313 {
4314 
4315 #ifndef SPI_GETWHEELSCROLLLINES
4316 # define SPI_GETWHEELSCROLLLINES    104
4317 #endif
4318 #ifndef SPI_SETWHEELSCROLLLINES
4319 # define SPI_SETWHEELSCROLLLINES    105
4320 #endif
4321 
4322 #define VMOUSEZ_CLASSNAME  "MouseZ"		/* hidden wheel window class */
4323 #define VMOUSEZ_TITLE      "Magellan MSWHEEL"	/* hidden wheel window title */
4324 #define VMSH_MOUSEWHEEL    "MSWHEEL_ROLLMSG"
4325 #define VMSH_SCROLL_LINES  "MSH_SCROLL_LINES_MSG"
4326 
4327     mouse_scroll_lines = 3;	/* reasonable default */
4328 
4329     /* if NT 4.0+ (or Win98) get scroll lines directly from system */
4330     SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
4331 	    &mouse_scroll_lines, 0);
4332 }
4333 
4334 
4335 /* Intellimouse wheel handler */
4336     static void
4337 _OnMouseWheel(
4338     HWND hwnd,
4339     short zDelta)
4340 {
4341 /* Treat a mouse wheel event as if it were a scroll request */
4342     int i;
4343     int size;
4344     HWND hwndCtl;
4345 
4346     if (curwin->w_scrollbars[SBAR_RIGHT].id != 0)
4347     {
4348 	hwndCtl = curwin->w_scrollbars[SBAR_RIGHT].id;
4349 	size = curwin->w_scrollbars[SBAR_RIGHT].size;
4350     }
4351     else if (curwin->w_scrollbars[SBAR_LEFT].id != 0)
4352     {
4353 	hwndCtl = curwin->w_scrollbars[SBAR_LEFT].id;
4354 	size = curwin->w_scrollbars[SBAR_LEFT].size;
4355     }
4356     else
4357 	return;
4358 
4359     size = curwin->w_height;
4360     if (mouse_scroll_lines == 0)
4361 	init_mouse_wheel();
4362 
4363     mch_disable_flush();
4364     if (mouse_scroll_lines > 0
4365 	    && mouse_scroll_lines < (size > 2 ? size - 2 : 1))
4366     {
4367 	for (i = mouse_scroll_lines; i > 0; --i)
4368 	    _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_LINEUP : SB_LINEDOWN, 0);
4369     }
4370     else
4371 	_OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0);
4372     mch_enable_flush();
4373     gui_may_flush();
4374 }
4375 
4376 #ifdef USE_SYSMENU_FONT
4377 /*
4378  * Get Menu Font.
4379  * Return OK or FAIL.
4380  */
4381     static int
4382 gui_w32_get_menu_font(LOGFONT *lf)
4383 {
4384     NONCLIENTMETRICS nm;
4385 
4386     nm.cbSize = sizeof(NONCLIENTMETRICS);
4387     if (!SystemParametersInfo(
4388 	    SPI_GETNONCLIENTMETRICS,
4389 	    sizeof(NONCLIENTMETRICS),
4390 	    &nm,
4391 	    0))
4392 	return FAIL;
4393     *lf = nm.lfMenuFont;
4394     return OK;
4395 }
4396 #endif
4397 
4398 
4399 #if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
4400 /*
4401  * Set the GUI tabline font to the system menu font
4402  */
4403     static void
4404 set_tabline_font(void)
4405 {
4406     LOGFONT	lfSysmenu;
4407     HFONT	font;
4408     HWND	hwnd;
4409     HDC		hdc;
4410     HFONT	hfntOld;
4411     TEXTMETRIC	tm;
4412 
4413     if (gui_w32_get_menu_font(&lfSysmenu) != OK)
4414 	return;
4415 
4416     font = CreateFontIndirect(&lfSysmenu);
4417 
4418     SendMessage(s_tabhwnd, WM_SETFONT, (WPARAM)font, TRUE);
4419 
4420     /*
4421      * Compute the height of the font used for the tab text
4422      */
4423     hwnd = GetDesktopWindow();
4424     hdc = GetWindowDC(hwnd);
4425     hfntOld = SelectFont(hdc, font);
4426 
4427     GetTextMetrics(hdc, &tm);
4428 
4429     SelectFont(hdc, hfntOld);
4430     ReleaseDC(hwnd, hdc);
4431 
4432     /*
4433      * The space used by the tab border and the space between the tab label
4434      * and the tab border is included as 7.
4435      */
4436     gui.tabline_height = tm.tmHeight + tm.tmInternalLeading + 7;
4437 }
4438 #endif
4439 
4440 /*
4441  * Invoked when a setting was changed.
4442  */
4443     static LRESULT CALLBACK
4444 _OnSettingChange(UINT n)
4445 {
4446     if (n == SPI_SETWHEELSCROLLLINES)
4447 	SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
4448 		&mouse_scroll_lines, 0);
4449 #if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
4450     if (n == SPI_SETNONCLIENTMETRICS)
4451 	set_tabline_font();
4452 #endif
4453     return 0;
4454 }
4455 
4456 #ifdef FEAT_NETBEANS_INTG
4457     static void
4458 _OnWindowPosChanged(
4459     HWND hwnd,
4460     const LPWINDOWPOS lpwpos)
4461 {
4462     static int x = 0, y = 0, cx = 0, cy = 0;
4463     extern int WSInitialized;
4464 
4465     if (WSInitialized && (lpwpos->x != x || lpwpos->y != y
4466 				     || lpwpos->cx != cx || lpwpos->cy != cy))
4467     {
4468 	x = lpwpos->x;
4469 	y = lpwpos->y;
4470 	cx = lpwpos->cx;
4471 	cy = lpwpos->cy;
4472 	netbeans_frame_moved(x, y);
4473     }
4474     /* Allow to send WM_SIZE and WM_MOVE */
4475     FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, MyWindowProc);
4476 }
4477 #endif
4478 
4479     static int
4480 _DuringSizing(
4481     UINT fwSide,
4482     LPRECT lprc)
4483 {
4484     int	    w, h;
4485     int	    valid_w, valid_h;
4486     int	    w_offset, h_offset;
4487 
4488     w = lprc->right - lprc->left;
4489     h = lprc->bottom - lprc->top;
4490     gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h);
4491     w_offset = w - valid_w;
4492     h_offset = h - valid_h;
4493 
4494     if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT
4495 			    || fwSide == WMSZ_BOTTOMLEFT)
4496 	lprc->left += w_offset;
4497     else if (fwSide == WMSZ_RIGHT || fwSide == WMSZ_TOPRIGHT
4498 			    || fwSide == WMSZ_BOTTOMRIGHT)
4499 	lprc->right -= w_offset;
4500 
4501     if (fwSide == WMSZ_TOP || fwSide == WMSZ_TOPLEFT
4502 			    || fwSide == WMSZ_TOPRIGHT)
4503 	lprc->top += h_offset;
4504     else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT
4505 			    || fwSide == WMSZ_BOTTOMRIGHT)
4506 	lprc->bottom -= h_offset;
4507     return TRUE;
4508 }
4509 
4510 
4511 
4512     static LRESULT CALLBACK
4513 _WndProc(
4514     HWND hwnd,
4515     UINT uMsg,
4516     WPARAM wParam,
4517     LPARAM lParam)
4518 {
4519     /*
4520     TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
4521 	  hwnd, uMsg, wParam, lParam);
4522     */
4523 
4524     HandleMouseHide(uMsg, lParam);
4525 
4526     s_uMsg = uMsg;
4527     s_wParam = wParam;
4528     s_lParam = lParam;
4529 
4530     switch (uMsg)
4531     {
4532 	HANDLE_MSG(hwnd, WM_DEADCHAR,	_OnDeadChar);
4533 	HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar);
4534 	/* HANDLE_MSG(hwnd, WM_ACTIVATE,    _OnActivate); */
4535 	HANDLE_MSG(hwnd, WM_CLOSE,	_OnClose);
4536 	/* HANDLE_MSG(hwnd, WM_COMMAND,	_OnCommand); */
4537 	HANDLE_MSG(hwnd, WM_DESTROY,	_OnDestroy);
4538 	HANDLE_MSG(hwnd, WM_DROPFILES,	_OnDropFiles);
4539 	HANDLE_MSG(hwnd, WM_HSCROLL,	_OnScroll);
4540 	HANDLE_MSG(hwnd, WM_KILLFOCUS,	_OnKillFocus);
4541 #ifdef FEAT_MENU
4542 	HANDLE_MSG(hwnd, WM_COMMAND,	_OnMenu);
4543 #endif
4544 	/* HANDLE_MSG(hwnd, WM_MOVE,	    _OnMove); */
4545 	/* HANDLE_MSG(hwnd, WM_NCACTIVATE,  _OnNCActivate); */
4546 	HANDLE_MSG(hwnd, WM_SETFOCUS,	_OnSetFocus);
4547 	HANDLE_MSG(hwnd, WM_SIZE,	_OnSize);
4548 	/* HANDLE_MSG(hwnd, WM_SYSCOMMAND,  _OnSysCommand); */
4549 	/* HANDLE_MSG(hwnd, WM_SYSKEYDOWN,  _OnAltKey); */
4550 	HANDLE_MSG(hwnd, WM_VSCROLL,	_OnScroll);
4551 	// HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING,	_OnWindowPosChanging);
4552 	HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp);
4553 #ifdef FEAT_NETBEANS_INTG
4554 	HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, _OnWindowPosChanged);
4555 #endif
4556 
4557 #ifdef FEAT_GUI_TABLINE
4558 	case WM_RBUTTONUP:
4559 	{
4560 	    if (gui_mch_showing_tabline())
4561 	    {
4562 		POINT pt;
4563 		RECT rect;
4564 
4565 		/*
4566 		 * If the cursor is on the tabline, display the tab menu
4567 		 */
4568 		GetCursorPos((LPPOINT)&pt);
4569 		GetWindowRect(s_textArea, &rect);
4570 		if (pt.y < rect.top)
4571 		{
4572 		    show_tabline_popup_menu();
4573 		    return 0L;
4574 		}
4575 	    }
4576 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4577 	}
4578 	case WM_LBUTTONDBLCLK:
4579 	{
4580 	    /*
4581 	     * If the user double clicked the tabline, create a new tab
4582 	     */
4583 	    if (gui_mch_showing_tabline())
4584 	    {
4585 		POINT pt;
4586 		RECT rect;
4587 
4588 		GetCursorPos((LPPOINT)&pt);
4589 		GetWindowRect(s_textArea, &rect);
4590 		if (pt.y < rect.top)
4591 		    send_tabline_menu_event(0, TABLINE_MENU_NEW);
4592 	    }
4593 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4594 	}
4595 #endif
4596 
4597     case WM_QUERYENDSESSION:	/* System wants to go down. */
4598 	gui_shell_closed();	/* Will exit when no changed buffers. */
4599 	return FALSE;		/* Do NOT allow system to go down. */
4600 
4601     case WM_ENDSESSION:
4602 	if (wParam)	/* system only really goes down when wParam is TRUE */
4603 	{
4604 	    _OnEndSession();
4605 	    return 0L;
4606 	}
4607 	break;
4608 
4609     case WM_CHAR:
4610 	/* Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
4611 	 * byte while we want the UTF-16 character value. */
4612 	_OnChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
4613 	return 0L;
4614 
4615     case WM_SYSCHAR:
4616 	/*
4617 	 * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
4618 	 * shortcut key, handle like a typed ALT key, otherwise call Windows
4619 	 * ALT key handling.
4620 	 */
4621 #ifdef FEAT_MENU
4622 	if (	!gui.menu_is_active
4623 		|| p_wak[0] == 'n'
4624 		|| (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam))
4625 		)
4626 #endif
4627 	{
4628 	    _OnSysChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
4629 	    return 0L;
4630 	}
4631 #ifdef FEAT_MENU
4632 	else
4633 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4634 #endif
4635 
4636     case WM_SYSKEYUP:
4637 #ifdef FEAT_MENU
4638 	/* This used to be done only when menu is active: ALT key is used for
4639 	 * that.  But that caused problems when menu is disabled and using
4640 	 * Alt-Tab-Esc: get into a strange state where no mouse-moved events
4641 	 * are received, mouse pointer remains hidden. */
4642 	return MyWindowProc(hwnd, uMsg, wParam, lParam);
4643 #else
4644 	return 0L;
4645 #endif
4646 
4647     case WM_SIZING:	/* HANDLE_MSG doesn't seem to handle this one */
4648 	return _DuringSizing((UINT)wParam, (LPRECT)lParam);
4649 
4650     case WM_MOUSEWHEEL:
4651 	_OnMouseWheel(hwnd, HIWORD(wParam));
4652 	return 0L;
4653 
4654 	/* Notification for change in SystemParametersInfo() */
4655     case WM_SETTINGCHANGE:
4656 	return _OnSettingChange((UINT)wParam);
4657 
4658 #if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
4659     case WM_NOTIFY:
4660 	switch (((LPNMHDR) lParam)->code)
4661 	{
4662 	    case TTN_GETDISPINFOW:
4663 	    case TTN_GETDISPINFO:
4664 		{
4665 		    LPNMHDR		hdr = (LPNMHDR)lParam;
4666 		    char_u		*str = NULL;
4667 		    static void		*tt_text = NULL;
4668 
4669 		    VIM_CLEAR(tt_text);
4670 
4671 # ifdef FEAT_GUI_TABLINE
4672 		    if (gui_mch_showing_tabline()
4673 			   && hdr->hwndFrom == TabCtrl_GetToolTips(s_tabhwnd))
4674 		    {
4675 			POINT		pt;
4676 			/*
4677 			 * Mouse is over the GUI tabline. Display the
4678 			 * tooltip for the tab under the cursor
4679 			 *
4680 			 * Get the cursor position within the tab control
4681 			 */
4682 			GetCursorPos(&pt);
4683 			if (ScreenToClient(s_tabhwnd, &pt) != 0)
4684 			{
4685 			    TCHITTESTINFO htinfo;
4686 			    int idx;
4687 
4688 			    /*
4689 			     * Get the tab under the cursor
4690 			     */
4691 			    htinfo.pt.x = pt.x;
4692 			    htinfo.pt.y = pt.y;
4693 			    idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
4694 			    if (idx != -1)
4695 			    {
4696 				tabpage_T *tp;
4697 
4698 				tp = find_tabpage(idx + 1);
4699 				if (tp != NULL)
4700 				{
4701 				    get_tabline_label(tp, TRUE);
4702 				    str = NameBuff;
4703 				}
4704 			    }
4705 			}
4706 		    }
4707 # endif
4708 # ifdef FEAT_TOOLBAR
4709 #  ifdef FEAT_GUI_TABLINE
4710 		    else
4711 #  endif
4712 		    {
4713 			UINT		idButton;
4714 			vimmenu_T	*pMenu;
4715 
4716 			idButton = (UINT) hdr->idFrom;
4717 			pMenu = gui_mswin_find_menu(root_menu, idButton);
4718 			if (pMenu)
4719 			    str = pMenu->strings[MENU_INDEX_TIP];
4720 		    }
4721 # endif
4722 		    if (str != NULL)
4723 		    {
4724 			if (hdr->code == TTN_GETDISPINFOW)
4725 			{
4726 			    LPNMTTDISPINFOW	lpdi = (LPNMTTDISPINFOW)lParam;
4727 
4728 			    /* Set the maximum width, this also enables using
4729 			     * \n for line break. */
4730 			    SendMessage(lpdi->hdr.hwndFrom, TTM_SETMAXTIPWIDTH,
4731 								      0, 500);
4732 
4733 			    tt_text = enc_to_utf16(str, NULL);
4734 			    lpdi->lpszText = tt_text;
4735 			    /* can't show tooltip if failed */
4736 			}
4737 			else
4738 			{
4739 			    LPNMTTDISPINFO	lpdi = (LPNMTTDISPINFO)lParam;
4740 
4741 			    /* Set the maximum width, this also enables using
4742 			     * \n for line break. */
4743 			    SendMessage(lpdi->hdr.hwndFrom, TTM_SETMAXTIPWIDTH,
4744 								      0, 500);
4745 
4746 			    if (STRLEN(str) < sizeof(lpdi->szText)
4747 				    || ((tt_text = vim_strsave(str)) == NULL))
4748 				vim_strncpy((char_u *)lpdi->szText, str,
4749 						sizeof(lpdi->szText) - 1);
4750 			    else
4751 				lpdi->lpszText = tt_text;
4752 			}
4753 		    }
4754 		}
4755 		break;
4756 # ifdef FEAT_GUI_TABLINE
4757 	    case TCN_SELCHANGE:
4758 		if (gui_mch_showing_tabline()
4759 				  && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
4760 		{
4761 		    send_tabline_event(TabCtrl_GetCurSel(s_tabhwnd) + 1);
4762 		    return 0L;
4763 		}
4764 		break;
4765 
4766 	    case NM_RCLICK:
4767 		if (gui_mch_showing_tabline()
4768 			&& ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
4769 		{
4770 		    show_tabline_popup_menu();
4771 		    return 0L;
4772 		}
4773 		break;
4774 # endif
4775 	    default:
4776 # ifdef FEAT_GUI_TABLINE
4777 		if (gui_mch_showing_tabline()
4778 				  && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
4779 		    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4780 # endif
4781 		break;
4782 	}
4783 	break;
4784 #endif
4785 #if defined(MENUHINTS) && defined(FEAT_MENU)
4786     case WM_MENUSELECT:
4787 	if (((UINT) HIWORD(wParam)
4788 		    & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP)))
4789 		== MF_HILITE
4790 		&& (State & CMDLINE) == 0)
4791 	{
4792 	    UINT	idButton;
4793 	    vimmenu_T	*pMenu;
4794 	    static int	did_menu_tip = FALSE;
4795 
4796 	    if (did_menu_tip)
4797 	    {
4798 		msg_clr_cmdline();
4799 		setcursor();
4800 		out_flush();
4801 		did_menu_tip = FALSE;
4802 	    }
4803 
4804 	    idButton = (UINT)LOWORD(wParam);
4805 	    pMenu = gui_mswin_find_menu(root_menu, idButton);
4806 	    if (pMenu != NULL && pMenu->strings[MENU_INDEX_TIP] != 0
4807 		    && GetMenuState(s_menuBar, pMenu->id, MF_BYCOMMAND) != -1)
4808 	    {
4809 		++msg_hist_off;
4810 		msg((char *)pMenu->strings[MENU_INDEX_TIP]);
4811 		--msg_hist_off;
4812 		setcursor();
4813 		out_flush();
4814 		did_menu_tip = TRUE;
4815 	    }
4816 	    return 0L;
4817 	}
4818 	break;
4819 #endif
4820     case WM_NCHITTEST:
4821 	{
4822 	    LRESULT	result;
4823 	    int		x, y;
4824 	    int		xPos = GET_X_LPARAM(lParam);
4825 
4826 	    result = MyWindowProc(hwnd, uMsg, wParam, lParam);
4827 	    if (result == HTCLIENT)
4828 	    {
4829 #ifdef FEAT_GUI_TABLINE
4830 		if (gui_mch_showing_tabline())
4831 		{
4832 		    int  yPos = GET_Y_LPARAM(lParam);
4833 		    RECT rct;
4834 
4835 		    /* If the cursor is on the GUI tabline, don't process this
4836 		     * event */
4837 		    GetWindowRect(s_textArea, &rct);
4838 		    if (yPos < rct.top)
4839 			return result;
4840 		}
4841 #endif
4842 		(void)gui_mch_get_winpos(&x, &y);
4843 		xPos -= x;
4844 
4845 		if (xPos < 48) /* <VN> TODO should use system metric? */
4846 		    return HTBOTTOMLEFT;
4847 		else
4848 		    return HTBOTTOMRIGHT;
4849 	    }
4850 	    else
4851 		return result;
4852 	}
4853 	/* break; notreached */
4854 
4855 #ifdef FEAT_MBYTE_IME
4856     case WM_IME_NOTIFY:
4857 	if (!_OnImeNotify(hwnd, (DWORD)wParam, (DWORD)lParam))
4858 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4859 	return 1L;
4860 
4861     case WM_IME_COMPOSITION:
4862 	if (!_OnImeComposition(hwnd, wParam, lParam))
4863 	    return MyWindowProc(hwnd, uMsg, wParam, lParam);
4864 	return 1L;
4865 #endif
4866 
4867     default:
4868 #ifdef MSWIN_FIND_REPLACE
4869 	if (uMsg == s_findrep_msg && s_findrep_msg != 0)
4870 	{
4871 	    _OnFindRepl();
4872 	}
4873 #endif
4874 	return MyWindowProc(hwnd, uMsg, wParam, lParam);
4875     }
4876 
4877     return DefWindowProc(hwnd, uMsg, wParam, lParam);
4878 }
4879 
4880 /*
4881  * End of call-back routines
4882  */
4883 
4884 /* parent window, if specified with -P */
4885 HWND vim_parent_hwnd = NULL;
4886 
4887     static BOOL CALLBACK
4888 FindWindowTitle(HWND hwnd, LPARAM lParam)
4889 {
4890     char	buf[2048];
4891     char	*title = (char *)lParam;
4892 
4893     if (GetWindowText(hwnd, buf, sizeof(buf)))
4894     {
4895 	if (strstr(buf, title) != NULL)
4896 	{
4897 	    /* Found it.  Store the window ref. and quit searching if MDI
4898 	     * works. */
4899 	    vim_parent_hwnd = FindWindowEx(hwnd, NULL, "MDIClient", NULL);
4900 	    if (vim_parent_hwnd != NULL)
4901 		return FALSE;
4902 	}
4903     }
4904     return TRUE;	/* continue searching */
4905 }
4906 
4907 /*
4908  * Invoked for '-P "title"' argument: search for parent application to open
4909  * our window in.
4910  */
4911     void
4912 gui_mch_set_parent(char *title)
4913 {
4914     EnumWindows(FindWindowTitle, (LPARAM)title);
4915     if (vim_parent_hwnd == NULL)
4916     {
4917 	semsg(_("E671: Cannot find window title \"%s\""), title);
4918 	mch_exit(2);
4919     }
4920 }
4921 
4922 #ifndef FEAT_OLE
4923     static void
4924 ole_error(char *arg)
4925 {
4926     char buf[IOSIZE];
4927 
4928     /* Can't use emsg() here, we have not finished initialisation yet. */
4929     vim_snprintf(buf, IOSIZE,
4930 	    _("E243: Argument not supported: \"-%s\"; Use the OLE version."),
4931 	    arg);
4932     mch_errmsg(buf);
4933 }
4934 #endif
4935 
4936 /*
4937  * Parse the GUI related command-line arguments.  Any arguments used are
4938  * deleted from argv, and *argc is decremented accordingly.  This is called
4939  * when vim is started, whether or not the GUI has been started.
4940  */
4941     void
4942 gui_mch_prepare(int *argc, char **argv)
4943 {
4944     int		silent = FALSE;
4945     int		idx;
4946 
4947     /* Check for special OLE command line parameters */
4948     if ((*argc == 2 || *argc == 3) && (argv[1][0] == '-' || argv[1][0] == '/'))
4949     {
4950 	/* Check for a "-silent" argument first. */
4951 	if (*argc == 3 && STRICMP(argv[1] + 1, "silent") == 0
4952 		&& (argv[2][0] == '-' || argv[2][0] == '/'))
4953 	{
4954 	    silent = TRUE;
4955 	    idx = 2;
4956 	}
4957 	else
4958 	    idx = 1;
4959 
4960 	/* Register Vim as an OLE Automation server */
4961 	if (STRICMP(argv[idx] + 1, "register") == 0)
4962 	{
4963 #ifdef FEAT_OLE
4964 	    RegisterMe(silent);
4965 	    mch_exit(0);
4966 #else
4967 	    if (!silent)
4968 		ole_error("register");
4969 	    mch_exit(2);
4970 #endif
4971 	}
4972 
4973 	/* Unregister Vim as an OLE Automation server */
4974 	if (STRICMP(argv[idx] + 1, "unregister") == 0)
4975 	{
4976 #ifdef FEAT_OLE
4977 	    UnregisterMe(!silent);
4978 	    mch_exit(0);
4979 #else
4980 	    if (!silent)
4981 		ole_error("unregister");
4982 	    mch_exit(2);
4983 #endif
4984 	}
4985 
4986 	/* Ignore an -embedding argument. It is only relevant if the
4987 	 * application wants to treat the case when it is started manually
4988 	 * differently from the case where it is started via automation (and
4989 	 * we don't).
4990 	 */
4991 	if (STRICMP(argv[idx] + 1, "embedding") == 0)
4992 	{
4993 #ifdef FEAT_OLE
4994 	    *argc = 1;
4995 #else
4996 	    ole_error("embedding");
4997 	    mch_exit(2);
4998 #endif
4999 	}
5000     }
5001 
5002 #ifdef FEAT_OLE
5003     {
5004 	int	bDoRestart = FALSE;
5005 
5006 	InitOLE(&bDoRestart);
5007 	/* automatically exit after registering */
5008 	if (bDoRestart)
5009 	    mch_exit(0);
5010     }
5011 #endif
5012 
5013 #ifdef FEAT_NETBEANS_INTG
5014     {
5015 	/* stolen from gui_x11.c */
5016 	int arg;
5017 
5018 	for (arg = 1; arg < *argc; arg++)
5019 	    if (strncmp("-nb", argv[arg], 3) == 0)
5020 	    {
5021 		netbeansArg = argv[arg];
5022 		mch_memmove(&argv[arg], &argv[arg + 1],
5023 					    (--*argc - arg) * sizeof(char *));
5024 		argv[*argc] = NULL;
5025 		break;	/* enough? */
5026 	    }
5027     }
5028 #endif
5029 }
5030 
5031 /*
5032  * Initialise the GUI.	Create all the windows, set up all the call-backs
5033  * etc.
5034  */
5035     int
5036 gui_mch_init(void)
5037 {
5038     const char szVimWndClass[] = VIM_CLASS;
5039     const char szTextAreaClass[] = "VimTextArea";
5040     WNDCLASS wndclass;
5041     const WCHAR szVimWndClassW[] = VIM_CLASSW;
5042     const WCHAR szTextAreaClassW[] = L"VimTextArea";
5043     WNDCLASSW wndclassw;
5044 #ifdef GLOBAL_IME
5045     ATOM	atom;
5046 #endif
5047 
5048     /* Return here if the window was already opened (happens when
5049      * gui_mch_dialog() is called early). */
5050     if (s_hwnd != NULL)
5051 	goto theend;
5052 
5053     /*
5054      * Load the tearoff bitmap
5055      */
5056 #ifdef FEAT_TEAROFF
5057     s_htearbitmap = LoadBitmap(s_hinst, "IDB_TEAROFF");
5058 #endif
5059 
5060     gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL);
5061     gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL);
5062 #ifdef FEAT_MENU
5063     gui.menu_height = 0;	/* Windows takes care of this */
5064 #endif
5065     gui.border_width = 0;
5066 
5067     s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
5068 
5069     /* First try using the wide version, so that we can use any title.
5070      * Otherwise only characters in the active codepage will work. */
5071     if (GetClassInfoW(s_hinst, szVimWndClassW, &wndclassw) == 0)
5072     {
5073 	wndclassw.style = CS_DBLCLKS;
5074 	wndclassw.lpfnWndProc = _WndProc;
5075 	wndclassw.cbClsExtra = 0;
5076 	wndclassw.cbWndExtra = 0;
5077 	wndclassw.hInstance = s_hinst;
5078 	wndclassw.hIcon = LoadIcon(wndclassw.hInstance, "IDR_VIM");
5079 	wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
5080 	wndclassw.hbrBackground = s_brush;
5081 	wndclassw.lpszMenuName = NULL;
5082 	wndclassw.lpszClassName = szVimWndClassW;
5083 
5084 	if ((
5085 #ifdef GLOBAL_IME
5086 		    atom =
5087 #endif
5088 		    RegisterClassW(&wndclassw)) == 0)
5089 	    return FAIL;
5090 	else
5091 	    wide_WindowProc = TRUE;
5092     }
5093 
5094     if (!wide_WindowProc)
5095 	if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0)
5096 	{
5097 	    wndclass.style = CS_DBLCLKS;
5098 	    wndclass.lpfnWndProc = _WndProc;
5099 	    wndclass.cbClsExtra = 0;
5100 	    wndclass.cbWndExtra = 0;
5101 	    wndclass.hInstance = s_hinst;
5102 	    wndclass.hIcon = LoadIcon(wndclass.hInstance, "IDR_VIM");
5103 	    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
5104 	    wndclass.hbrBackground = s_brush;
5105 	    wndclass.lpszMenuName = NULL;
5106 	    wndclass.lpszClassName = szVimWndClass;
5107 
5108 	    if ((
5109 #ifdef GLOBAL_IME
5110 			atom =
5111 #endif
5112 			RegisterClass(&wndclass)) == 0)
5113 		return FAIL;
5114 	}
5115 
5116     if (vim_parent_hwnd != NULL)
5117     {
5118 #ifdef HAVE_TRY_EXCEPT
5119 	__try
5120 	{
5121 #endif
5122 	    /* Open inside the specified parent window.
5123 	     * TODO: last argument should point to a CLIENTCREATESTRUCT
5124 	     * structure. */
5125 	    s_hwnd = CreateWindowEx(
5126 		WS_EX_MDICHILD,
5127 		szVimWndClass, "Vim MSWindows GUI",
5128 		WS_OVERLAPPEDWINDOW | WS_CHILD
5129 				 | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | 0xC000,
5130 		gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
5131 		gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
5132 		100,				/* Any value will do */
5133 		100,				/* Any value will do */
5134 		vim_parent_hwnd, NULL,
5135 		s_hinst, NULL);
5136 #ifdef HAVE_TRY_EXCEPT
5137 	}
5138 	__except(EXCEPTION_EXECUTE_HANDLER)
5139 	{
5140 	    /* NOP */
5141 	}
5142 #endif
5143 	if (s_hwnd == NULL)
5144 	{
5145 	    emsg(_("E672: Unable to open window inside MDI application"));
5146 	    mch_exit(2);
5147 	}
5148     }
5149     else
5150     {
5151 	/* If the provided windowid is not valid reset it to zero, so that it
5152 	 * is ignored and we open our own window. */
5153 	if (IsWindow((HWND)win_socket_id) <= 0)
5154 	    win_socket_id = 0;
5155 
5156 	/* Create a window.  If win_socket_id is not zero without border and
5157 	 * titlebar, it will be reparented below. */
5158 	s_hwnd = CreateWindow(
5159 		szVimWndClass, "Vim MSWindows GUI",
5160 		(win_socket_id == 0 ? WS_OVERLAPPEDWINDOW : WS_POPUP)
5161 					  | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
5162 		gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
5163 		gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
5164 		100,				/* Any value will do */
5165 		100,				/* Any value will do */
5166 		NULL, NULL,
5167 		s_hinst, NULL);
5168 	if (s_hwnd != NULL && win_socket_id != 0)
5169 	{
5170 	    SetParent(s_hwnd, (HWND)win_socket_id);
5171 	    ShowWindow(s_hwnd, SW_SHOWMAXIMIZED);
5172 	}
5173     }
5174 
5175     if (s_hwnd == NULL)
5176 	return FAIL;
5177 
5178 #ifdef GLOBAL_IME
5179     global_ime_init(atom, s_hwnd);
5180 #endif
5181 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
5182     dyn_imm_load();
5183 #endif
5184 
5185     /* Create the text area window */
5186     if (wide_WindowProc)
5187     {
5188 	if (GetClassInfoW(s_hinst, szTextAreaClassW, &wndclassw) == 0)
5189 	{
5190 	    wndclassw.style = CS_OWNDC;
5191 	    wndclassw.lpfnWndProc = _TextAreaWndProc;
5192 	    wndclassw.cbClsExtra = 0;
5193 	    wndclassw.cbWndExtra = 0;
5194 	    wndclassw.hInstance = s_hinst;
5195 	    wndclassw.hIcon = NULL;
5196 	    wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
5197 	    wndclassw.hbrBackground = NULL;
5198 	    wndclassw.lpszMenuName = NULL;
5199 	    wndclassw.lpszClassName = szTextAreaClassW;
5200 
5201 	    if (RegisterClassW(&wndclassw) == 0)
5202 		return FAIL;
5203 	}
5204 
5205 	s_textArea = CreateWindowExW(
5206 	    0,
5207 	    szTextAreaClassW, L"Vim text area",
5208 	    WS_CHILD | WS_VISIBLE, 0, 0,
5209 	    100,				// Any value will do for now
5210 	    100,				// Any value will do for now
5211 	    s_hwnd, NULL,
5212 	    s_hinst, NULL);
5213     }
5214     else if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0)
5215     {
5216 	wndclass.style = CS_OWNDC;
5217 	wndclass.lpfnWndProc = _TextAreaWndProc;
5218 	wndclass.cbClsExtra = 0;
5219 	wndclass.cbWndExtra = 0;
5220 	wndclass.hInstance = s_hinst;
5221 	wndclass.hIcon = NULL;
5222 	wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
5223 	wndclass.hbrBackground = NULL;
5224 	wndclass.lpszMenuName = NULL;
5225 	wndclass.lpszClassName = szTextAreaClass;
5226 
5227 	if (RegisterClass(&wndclass) == 0)
5228 	    return FAIL;
5229 
5230 	s_textArea = CreateWindowEx(
5231 	    0,
5232 	    szTextAreaClass, "Vim text area",
5233 	    WS_CHILD | WS_VISIBLE, 0, 0,
5234 	    100,				// Any value will do for now
5235 	    100,				// Any value will do for now
5236 	    s_hwnd, NULL,
5237 	    s_hinst, NULL);
5238     }
5239 
5240     if (s_textArea == NULL)
5241 	return FAIL;
5242 
5243 #ifdef FEAT_LIBCALL
5244     /* Try loading an icon from $RUNTIMEPATH/bitmaps/vim.ico. */
5245     {
5246 	HANDLE	hIcon = NULL;
5247 
5248 	if (mch_icon_load(&hIcon) == OK && hIcon != NULL)
5249 	    SendMessage(s_hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIcon);
5250     }
5251 #endif
5252 
5253 #ifdef FEAT_MENU
5254     s_menuBar = CreateMenu();
5255 #endif
5256     s_hdc = GetDC(s_textArea);
5257 
5258     DragAcceptFiles(s_hwnd, TRUE);
5259 
5260     /* Do we need to bother with this? */
5261     /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
5262 
5263     /* Get background/foreground colors from the system */
5264     gui_mch_def_colors();
5265 
5266     /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
5267      * file) */
5268     set_normal_colors();
5269 
5270     /*
5271      * Check that none of the colors are the same as the background color.
5272      * Then store the current values as the defaults.
5273      */
5274     gui_check_colors();
5275     gui.def_norm_pixel = gui.norm_pixel;
5276     gui.def_back_pixel = gui.back_pixel;
5277 
5278     /* Get the colors for the highlight groups (gui_check_colors() might have
5279      * changed them) */
5280     highlight_gui_started();
5281 
5282     /*
5283      * Start out by adding the configured border width into the border offset.
5284      */
5285     gui.border_offset = gui.border_width;
5286 
5287     /*
5288      * Set up for Intellimouse processing
5289      */
5290     init_mouse_wheel();
5291 
5292     /*
5293      * compute a couple of metrics used for the dialogs
5294      */
5295     get_dialog_font_metrics();
5296 #ifdef FEAT_TOOLBAR
5297     /*
5298      * Create the toolbar
5299      */
5300     initialise_toolbar();
5301 #endif
5302 #ifdef FEAT_GUI_TABLINE
5303     /*
5304      * Create the tabline
5305      */
5306     initialise_tabline();
5307 #endif
5308 #ifdef MSWIN_FIND_REPLACE
5309     /*
5310      * Initialise the dialog box stuff
5311      */
5312     s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING);
5313 
5314     /* Initialise the struct */
5315     s_findrep_struct.lStructSize = sizeof(s_findrep_struct);
5316     s_findrep_struct.lpstrFindWhat = (LPSTR)alloc(MSWIN_FR_BUFSIZE);
5317     s_findrep_struct.lpstrFindWhat[0] = NUL;
5318     s_findrep_struct.lpstrReplaceWith = (LPSTR)alloc(MSWIN_FR_BUFSIZE);
5319     s_findrep_struct.lpstrReplaceWith[0] = NUL;
5320     s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE;
5321     s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE;
5322     s_findrep_struct_w.lStructSize = sizeof(s_findrep_struct_w);
5323     s_findrep_struct_w.lpstrFindWhat =
5324 			      (LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
5325     s_findrep_struct_w.lpstrFindWhat[0] = NUL;
5326     s_findrep_struct_w.lpstrReplaceWith =
5327 			      (LPWSTR)alloc(MSWIN_FR_BUFSIZE * sizeof(WCHAR));
5328     s_findrep_struct_w.lpstrReplaceWith[0] = NUL;
5329     s_findrep_struct_w.wFindWhatLen = MSWIN_FR_BUFSIZE;
5330     s_findrep_struct_w.wReplaceWithLen = MSWIN_FR_BUFSIZE;
5331 #endif
5332 
5333 #ifdef FEAT_EVAL
5334 # if !defined(_MSC_VER) || (_MSC_VER < 1400)
5335 /* Define HandleToLong for old MS and non-MS compilers if not defined. */
5336 #  ifndef HandleToLong
5337 #   define HandleToLong(h) ((long)(intptr_t)(h))
5338 #  endif
5339 # endif
5340     /* set the v:windowid variable */
5341     set_vim_var_nr(VV_WINDOWID, HandleToLong(s_hwnd));
5342 #endif
5343 
5344 #ifdef FEAT_RENDER_OPTIONS
5345     if (p_rop)
5346 	(void)gui_mch_set_rendering_options(p_rop);
5347 #endif
5348 
5349 theend:
5350     /* Display any pending error messages */
5351     display_errors();
5352 
5353     return OK;
5354 }
5355 
5356 /*
5357  * Get the size of the screen, taking position on multiple monitors into
5358  * account (if supported).
5359  */
5360     static void
5361 get_work_area(RECT *spi_rect)
5362 {
5363     HMONITOR	    mon;
5364     MONITORINFO	    moninfo;
5365 
5366     /* work out which monitor the window is on, and get *its* work area */
5367     mon = MonitorFromWindow(s_hwnd, MONITOR_DEFAULTTOPRIMARY);
5368     if (mon != NULL)
5369     {
5370 	moninfo.cbSize = sizeof(MONITORINFO);
5371 	if (GetMonitorInfo(mon, &moninfo))
5372 	{
5373 	    *spi_rect = moninfo.rcWork;
5374 	    return;
5375 	}
5376     }
5377     /* this is the old method... */
5378     SystemParametersInfo(SPI_GETWORKAREA, 0, spi_rect, 0);
5379 }
5380 
5381 /*
5382  * Set the size of the window to the given width and height in pixels.
5383  */
5384     void
5385 gui_mch_set_shellsize(
5386 	int width,
5387 	int height,
5388 	int min_width UNUSED,
5389 	int min_height UNUSED,
5390 	int base_width UNUSED,
5391 	int base_height UNUSED,
5392 	int direction)
5393 {
5394     RECT	workarea_rect;
5395     int		win_width, win_height;
5396     WINDOWPLACEMENT wndpl;
5397 
5398     /* Try to keep window completely on screen. */
5399     /* Get position of the screen work area.  This is the part that is not
5400      * used by the taskbar or appbars. */
5401     get_work_area(&workarea_rect);
5402 
5403     /* Get current position of our window.  Note that the .left and .top are
5404      * relative to the work area.  */
5405     wndpl.length = sizeof(WINDOWPLACEMENT);
5406     GetWindowPlacement(s_hwnd, &wndpl);
5407 
5408     /* Resizing a maximized window looks very strange, unzoom it first.
5409      * But don't do it when still starting up, it may have been requested in
5410      * the shortcut. */
5411     if (wndpl.showCmd == SW_SHOWMAXIMIZED && starting == 0)
5412     {
5413 	ShowWindow(s_hwnd, SW_SHOWNORMAL);
5414 	/* Need to get the settings of the normal window. */
5415 	GetWindowPlacement(s_hwnd, &wndpl);
5416     }
5417 
5418     /* compute the size of the outside of the window */
5419     win_width = width + (GetSystemMetrics(SM_CXFRAME) +
5420 			 GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
5421     win_height = height + (GetSystemMetrics(SM_CYFRAME) +
5422 			   GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
5423 			+ GetSystemMetrics(SM_CYCAPTION)
5424 #ifdef FEAT_MENU
5425 			+ gui_mswin_get_menu_height(FALSE)
5426 #endif
5427 			;
5428 
5429     /* The following should take care of keeping Vim on the same monitor, no
5430      * matter if the secondary monitor is left or right of the primary
5431      * monitor. */
5432     wndpl.rcNormalPosition.right = wndpl.rcNormalPosition.left + win_width;
5433     wndpl.rcNormalPosition.bottom = wndpl.rcNormalPosition.top + win_height;
5434 
5435     /* If the window is going off the screen, move it on to the screen. */
5436     if ((direction & RESIZE_HOR)
5437 	    && wndpl.rcNormalPosition.right > workarea_rect.right)
5438 	OffsetRect(&wndpl.rcNormalPosition,
5439 		workarea_rect.right - wndpl.rcNormalPosition.right, 0);
5440 
5441     if ((direction & RESIZE_HOR)
5442 	    && wndpl.rcNormalPosition.left < workarea_rect.left)
5443 	OffsetRect(&wndpl.rcNormalPosition,
5444 		workarea_rect.left - wndpl.rcNormalPosition.left, 0);
5445 
5446     if ((direction & RESIZE_VERT)
5447 	    && wndpl.rcNormalPosition.bottom > workarea_rect.bottom)
5448 	OffsetRect(&wndpl.rcNormalPosition,
5449 		0, workarea_rect.bottom - wndpl.rcNormalPosition.bottom);
5450 
5451     if ((direction & RESIZE_VERT)
5452 	    && wndpl.rcNormalPosition.top < workarea_rect.top)
5453 	OffsetRect(&wndpl.rcNormalPosition,
5454 		0, workarea_rect.top - wndpl.rcNormalPosition.top);
5455 
5456     /* set window position - we should use SetWindowPlacement rather than
5457      * SetWindowPos as the MSDN docs say the coord systems returned by
5458      * these two are not compatible. */
5459     SetWindowPlacement(s_hwnd, &wndpl);
5460 
5461     SetActiveWindow(s_hwnd);
5462     SetFocus(s_hwnd);
5463 
5464 #ifdef FEAT_MENU
5465     /* Menu may wrap differently now */
5466     gui_mswin_get_menu_height(!gui.starting);
5467 #endif
5468 }
5469 
5470 
5471     void
5472 gui_mch_set_scrollbar_thumb(
5473     scrollbar_T *sb,
5474     long	val,
5475     long	size,
5476     long	max)
5477 {
5478     SCROLLINFO	info;
5479 
5480     sb->scroll_shift = 0;
5481     while (max > 32767)
5482     {
5483 	max = (max + 1) >> 1;
5484 	val  >>= 1;
5485 	size >>= 1;
5486 	++sb->scroll_shift;
5487     }
5488 
5489     if (sb->scroll_shift > 0)
5490 	++size;
5491 
5492     info.cbSize = sizeof(info);
5493     info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
5494     info.nPos = val;
5495     info.nMin = 0;
5496     info.nMax = max;
5497     info.nPage = size;
5498     SetScrollInfo(sb->id, SB_CTL, &info, TRUE);
5499 }
5500 
5501 
5502 /*
5503  * Set the current text font.
5504  */
5505     void
5506 gui_mch_set_font(GuiFont font)
5507 {
5508     gui.currFont = font;
5509 }
5510 
5511 
5512 /*
5513  * Set the current text foreground color.
5514  */
5515     void
5516 gui_mch_set_fg_color(guicolor_T color)
5517 {
5518     gui.currFgColor = color;
5519 }
5520 
5521 /*
5522  * Set the current text background color.
5523  */
5524     void
5525 gui_mch_set_bg_color(guicolor_T color)
5526 {
5527     gui.currBgColor = color;
5528 }
5529 
5530 /*
5531  * Set the current text special color.
5532  */
5533     void
5534 gui_mch_set_sp_color(guicolor_T color)
5535 {
5536     gui.currSpColor = color;
5537 }
5538 
5539 #ifdef FEAT_MBYTE_IME
5540 /*
5541  * Multi-byte handling, originally by Sung-Hoon Baek.
5542  * First static functions (no prototypes generated).
5543  */
5544 # ifdef _MSC_VER
5545 #  include <ime.h>   /* Apparently not needed for Cygwin, MingW or Borland. */
5546 # endif
5547 # include <imm.h>
5548 
5549 /*
5550  * handle WM_IME_NOTIFY message
5551  */
5552     static LRESULT
5553 _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData UNUSED)
5554 {
5555     LRESULT lResult = 0;
5556     HIMC hImc;
5557 
5558     if (!pImmGetContext || (hImc = pImmGetContext(hWnd)) == (HIMC)0)
5559 	return lResult;
5560     switch (dwCommand)
5561     {
5562 	case IMN_SETOPENSTATUS:
5563 	    if (pImmGetOpenStatus(hImc))
5564 	    {
5565 		pImmSetCompositionFont(hImc, &norm_logfont);
5566 		im_set_position(gui.row, gui.col);
5567 
5568 		/* Disable langmap */
5569 		State &= ~LANGMAP;
5570 		if (State & INSERT)
5571 		{
5572 #if defined(FEAT_KEYMAP)
5573 		    /* Unshown 'keymap' in status lines */
5574 		    if (curbuf->b_p_iminsert == B_IMODE_LMAP)
5575 		    {
5576 			/* Save cursor position */
5577 			int old_row = gui.row;
5578 			int old_col = gui.col;
5579 
5580 			// This must be called here before
5581 			// status_redraw_curbuf(), otherwise the mode
5582 			// message may appear in the wrong position.
5583 			showmode();
5584 			status_redraw_curbuf();
5585 			update_screen(0);
5586 			/* Restore cursor position */
5587 			gui.row = old_row;
5588 			gui.col = old_col;
5589 		    }
5590 #endif
5591 		}
5592 	    }
5593 	    gui_update_cursor(TRUE, FALSE);
5594 	    gui_mch_flush();
5595 	    lResult = 0;
5596 	    break;
5597     }
5598     pImmReleaseContext(hWnd, hImc);
5599     return lResult;
5600 }
5601 
5602     static LRESULT
5603 _OnImeComposition(HWND hwnd, WPARAM dbcs UNUSED, LPARAM param)
5604 {
5605     char_u	*ret;
5606     int		len;
5607 
5608     if ((param & GCS_RESULTSTR) == 0) /* Composition unfinished. */
5609 	return 0;
5610 
5611     ret = GetResultStr(hwnd, GCS_RESULTSTR, &len);
5612     if (ret != NULL)
5613     {
5614 	add_to_input_buf_csi(ret, len);
5615 	vim_free(ret);
5616 	return 1;
5617     }
5618     return 0;
5619 }
5620 
5621 /*
5622  * get the current composition string, in UCS-2; *lenp is the number of
5623  * *lenp is the number of Unicode characters.
5624  */
5625     static short_u *
5626 GetCompositionString_inUCS2(HIMC hIMC, DWORD GCS, int *lenp)
5627 {
5628     LONG	    ret;
5629     LPWSTR	    wbuf = NULL;
5630     char_u	    *buf;
5631 
5632     if (!pImmGetContext)
5633 	return NULL; /* no imm32.dll */
5634 
5635     /* Try Unicode; this'll always work on NT regardless of codepage. */
5636     ret = pImmGetCompositionStringW(hIMC, GCS, NULL, 0);
5637     if (ret == 0)
5638 	return NULL; /* empty */
5639 
5640     if (ret > 0)
5641     {
5642 	/* Allocate the requested buffer plus space for the NUL character. */
5643 	wbuf = (LPWSTR)alloc(ret + sizeof(WCHAR));
5644 	if (wbuf != NULL)
5645 	{
5646 	    pImmGetCompositionStringW(hIMC, GCS, wbuf, ret);
5647 	    *lenp = ret / sizeof(WCHAR);
5648 	}
5649 	return (short_u *)wbuf;
5650     }
5651 
5652     /* ret < 0; we got an error, so try the ANSI version.  This'll work
5653      * on 9x/ME, but only if the codepage happens to be set to whatever
5654      * we're inputting. */
5655     ret = pImmGetCompositionStringA(hIMC, GCS, NULL, 0);
5656     if (ret <= 0)
5657 	return NULL; /* empty or error */
5658 
5659     buf = alloc(ret);
5660     if (buf == NULL)
5661 	return NULL;
5662     pImmGetCompositionStringA(hIMC, GCS, buf, ret);
5663 
5664     /* convert from codepage to UCS-2 */
5665     MultiByteToWideChar_alloc(GetACP(), 0, (LPCSTR)buf, ret, &wbuf, lenp);
5666     vim_free(buf);
5667 
5668     return (short_u *)wbuf;
5669 }
5670 
5671 /*
5672  * void GetResultStr()
5673  *
5674  * This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
5675  * get complete composition string
5676  */
5677     static char_u *
5678 GetResultStr(HWND hwnd, int GCS, int *lenp)
5679 {
5680     HIMC	hIMC;		/* Input context handle. */
5681     short_u	*buf = NULL;
5682     char_u	*convbuf = NULL;
5683 
5684     if (!pImmGetContext || (hIMC = pImmGetContext(hwnd)) == (HIMC)0)
5685 	return NULL;
5686 
5687     /* Reads in the composition string. */
5688     buf = GetCompositionString_inUCS2(hIMC, GCS, lenp);
5689     if (buf == NULL)
5690 	return NULL;
5691 
5692     convbuf = utf16_to_enc(buf, lenp);
5693     pImmReleaseContext(hwnd, hIMC);
5694     vim_free(buf);
5695     return convbuf;
5696 }
5697 #endif
5698 
5699 /* For global functions we need prototypes. */
5700 #if defined(FEAT_MBYTE_IME) || defined(PROTO)
5701 
5702 /*
5703  * set font to IM.
5704  */
5705     void
5706 im_set_font(LOGFONT *lf)
5707 {
5708     HIMC hImc;
5709 
5710     if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
5711     {
5712 	pImmSetCompositionFont(hImc, lf);
5713 	pImmReleaseContext(s_hwnd, hImc);
5714     }
5715 }
5716 
5717 /*
5718  * Notify cursor position to IM.
5719  */
5720     void
5721 im_set_position(int row, int col)
5722 {
5723     HIMC hImc;
5724 
5725     if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
5726     {
5727 	COMPOSITIONFORM	cfs;
5728 
5729 	cfs.dwStyle = CFS_POINT;
5730 	cfs.ptCurrentPos.x = FILL_X(col);
5731 	cfs.ptCurrentPos.y = FILL_Y(row);
5732 	MapWindowPoints(s_textArea, s_hwnd, &cfs.ptCurrentPos, 1);
5733 	pImmSetCompositionWindow(hImc, &cfs);
5734 
5735 	pImmReleaseContext(s_hwnd, hImc);
5736     }
5737 }
5738 
5739 /*
5740  * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
5741  */
5742     void
5743 im_set_active(int active)
5744 {
5745     HIMC	hImc;
5746     static HIMC	hImcOld = (HIMC)0;
5747 
5748     if (pImmGetContext)	    /* if NULL imm32.dll wasn't loaded (yet) */
5749     {
5750 	if (p_imdisable)
5751 	{
5752 	    if (hImcOld == (HIMC)0)
5753 	    {
5754 		hImcOld = pImmGetContext(s_hwnd);
5755 		if (hImcOld)
5756 		    pImmAssociateContext(s_hwnd, (HIMC)0);
5757 	    }
5758 	    active = FALSE;
5759 	}
5760 	else if (hImcOld != (HIMC)0)
5761 	{
5762 	    pImmAssociateContext(s_hwnd, hImcOld);
5763 	    hImcOld = (HIMC)0;
5764 	}
5765 
5766 	hImc = pImmGetContext(s_hwnd);
5767 	if (hImc)
5768 	{
5769 	    /*
5770 	     * for Korean ime
5771 	     */
5772 	    HKL hKL = GetKeyboardLayout(0);
5773 
5774 	    if (LOWORD(hKL) == MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN))
5775 	    {
5776 		static DWORD dwConversionSaved = 0, dwSentenceSaved = 0;
5777 		static BOOL bSaved = FALSE;
5778 
5779 		if (active)
5780 		{
5781 		    /* if we have a saved conversion status, restore it */
5782 		    if (bSaved)
5783 			pImmSetConversionStatus(hImc, dwConversionSaved,
5784 							     dwSentenceSaved);
5785 		    bSaved = FALSE;
5786 		}
5787 		else
5788 		{
5789 		    /* save conversion status and disable korean */
5790 		    if (pImmGetConversionStatus(hImc, &dwConversionSaved,
5791 							    &dwSentenceSaved))
5792 		    {
5793 			bSaved = TRUE;
5794 			pImmSetConversionStatus(hImc,
5795 				dwConversionSaved & ~(IME_CMODE_NATIVE
5796 						       | IME_CMODE_FULLSHAPE),
5797 				dwSentenceSaved);
5798 		    }
5799 		}
5800 	    }
5801 
5802 	    pImmSetOpenStatus(hImc, active);
5803 	    pImmReleaseContext(s_hwnd, hImc);
5804 	}
5805     }
5806 }
5807 
5808 /*
5809  * Get IM status.  When IM is on, return not 0.  Else return 0.
5810  */
5811     int
5812 im_get_status(void)
5813 {
5814     int		status = 0;
5815     HIMC	hImc;
5816 
5817     if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
5818     {
5819 	status = pImmGetOpenStatus(hImc) ? 1 : 0;
5820 	pImmReleaseContext(s_hwnd, hImc);
5821     }
5822     return status;
5823 }
5824 
5825 #endif /* FEAT_MBYTE_IME */
5826 
5827 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
5828 /* Win32 with GLOBAL IME */
5829 
5830 /*
5831  * Notify cursor position to IM.
5832  */
5833     void
5834 im_set_position(int row, int col)
5835 {
5836     /* Win32 with GLOBAL IME */
5837     POINT p;
5838 
5839     p.x = FILL_X(col);
5840     p.y = FILL_Y(row);
5841     MapWindowPoints(s_textArea, s_hwnd, &p, 1);
5842     global_ime_set_position(&p);
5843 }
5844 
5845 /*
5846  * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
5847  */
5848     void
5849 im_set_active(int active)
5850 {
5851     global_ime_set_status(active);
5852 }
5853 
5854 /*
5855  * Get IM status.  When IM is on, return not 0.  Else return 0.
5856  */
5857     int
5858 im_get_status(void)
5859 {
5860     return global_ime_get_status();
5861 }
5862 #endif
5863 
5864 /*
5865  * Convert latin9 text "text[len]" to ucs-2 in "unicodebuf".
5866  */
5867     static void
5868 latin9_to_ucs(char_u *text, int len, WCHAR *unicodebuf)
5869 {
5870     int		c;
5871 
5872     while (--len >= 0)
5873     {
5874 	c = *text++;
5875 	switch (c)
5876 	{
5877 	    case 0xa4: c = 0x20ac; break;   /* euro */
5878 	    case 0xa6: c = 0x0160; break;   /* S hat */
5879 	    case 0xa8: c = 0x0161; break;   /* S -hat */
5880 	    case 0xb4: c = 0x017d; break;   /* Z hat */
5881 	    case 0xb8: c = 0x017e; break;   /* Z -hat */
5882 	    case 0xbc: c = 0x0152; break;   /* OE */
5883 	    case 0xbd: c = 0x0153; break;   /* oe */
5884 	    case 0xbe: c = 0x0178; break;   /* Y */
5885 	}
5886 	*unicodebuf++ = c;
5887     }
5888 }
5889 
5890 #ifdef FEAT_RIGHTLEFT
5891 /*
5892  * What is this for?  In the case where you are using Win98 or Win2K or later,
5893  * and you are using a Hebrew font (or Arabic!), Windows does you a favor and
5894  * reverses the string sent to the TextOut... family.  This sucks, because we
5895  * go to a lot of effort to do the right thing, and there doesn't seem to be a
5896  * way to tell Windblows not to do this!
5897  *
5898  * The short of it is that this 'RevOut' only gets called if you are running
5899  * one of the new, "improved" MS OSes, and only if you are running in
5900  * 'rightleft' mode.  It makes display take *slightly* longer, but not
5901  * noticeably so.
5902  */
5903     static void
5904 RevOut( HDC s_hdc,
5905 	int col,
5906 	int row,
5907 	UINT foptions,
5908 	CONST RECT *pcliprect,
5909 	LPCTSTR text,
5910 	UINT len,
5911 	CONST INT *padding)
5912 {
5913     int		ix;
5914 
5915     for (ix = 0; ix < (int)len; ++ix)
5916 	ExtTextOut(s_hdc, col + TEXT_X(ix), row, foptions,
5917 					pcliprect, text + ix, 1, padding);
5918 }
5919 #endif
5920 
5921     static void
5922 draw_line(
5923     int		x1,
5924     int		y1,
5925     int		x2,
5926     int		y2,
5927     COLORREF	color)
5928 {
5929 #if defined(FEAT_DIRECTX)
5930     if (IS_ENABLE_DIRECTX())
5931 	DWriteContext_DrawLine(s_dwc, x1, y1, x2, y2, color);
5932     else
5933 #endif
5934     {
5935 	HPEN	hpen = CreatePen(PS_SOLID, 1, color);
5936 	HPEN	old_pen = SelectObject(s_hdc, hpen);
5937 	MoveToEx(s_hdc, x1, y1, NULL);
5938 	/* Note: LineTo() excludes the last pixel in the line. */
5939 	LineTo(s_hdc, x2, y2);
5940 	DeleteObject(SelectObject(s_hdc, old_pen));
5941     }
5942 }
5943 
5944     static void
5945 set_pixel(
5946     int		x,
5947     int		y,
5948     COLORREF	color)
5949 {
5950 #if defined(FEAT_DIRECTX)
5951     if (IS_ENABLE_DIRECTX())
5952 	DWriteContext_SetPixel(s_dwc, x, y, color);
5953     else
5954 #endif
5955 	SetPixel(s_hdc, x, y, color);
5956 }
5957 
5958     static void
5959 fill_rect(
5960     const RECT	*rcp,
5961     HBRUSH	hbr,
5962     COLORREF	color)
5963 {
5964 #if defined(FEAT_DIRECTX)
5965     if (IS_ENABLE_DIRECTX())
5966 	DWriteContext_FillRect(s_dwc, rcp, color);
5967     else
5968 #endif
5969     {
5970 	HBRUSH	hbr2;
5971 
5972 	if (hbr == NULL)
5973 	    hbr2 = CreateSolidBrush(color);
5974 	else
5975 	    hbr2 = hbr;
5976 	FillRect(s_hdc, rcp, hbr2);
5977 	if (hbr == NULL)
5978 	    DeleteBrush(hbr2);
5979     }
5980 }
5981 
5982     void
5983 gui_mch_draw_string(
5984     int		row,
5985     int		col,
5986     char_u	*text,
5987     int		len,
5988     int		flags)
5989 {
5990     static int	*padding = NULL;
5991     static int	pad_size = 0;
5992     int		i;
5993     const RECT	*pcliprect = NULL;
5994     UINT	foptions = 0;
5995     static WCHAR *unicodebuf = NULL;
5996     static int   *unicodepdy = NULL;
5997     static int	unibuflen = 0;
5998     int		n = 0;
5999     int		y;
6000 
6001     /*
6002      * Italic and bold text seems to have an extra row of pixels at the bottom
6003      * (below where the bottom of the character should be).  If we draw the
6004      * characters with a solid background, the top row of pixels in the
6005      * character below will be overwritten.  We can fix this by filling in the
6006      * background ourselves, to the correct character proportions, and then
6007      * writing the character in transparent mode.  Still have a problem when
6008      * the character is "_", which gets written on to the character below.
6009      * New fix: set gui.char_ascent to -1.  This shifts all characters up one
6010      * pixel in their slots, which fixes the problem with the bottom row of
6011      * pixels.	We still need this code because otherwise the top row of pixels
6012      * becomes a problem. - webb.
6013      */
6014     static HBRUSH	hbr_cache[2] = {NULL, NULL};
6015     static guicolor_T	brush_color[2] = {INVALCOLOR, INVALCOLOR};
6016     static int		brush_lru = 0;
6017     HBRUSH		hbr;
6018     RECT		rc;
6019 
6020     if (!(flags & DRAW_TRANSP))
6021     {
6022 	/*
6023 	 * Clear background first.
6024 	 * Note: FillRect() excludes right and bottom of rectangle.
6025 	 */
6026 	rc.left = FILL_X(col);
6027 	rc.top = FILL_Y(row);
6028 	if (has_mbyte)
6029 	{
6030 	    /* Compute the length in display cells. */
6031 	    rc.right = FILL_X(col + mb_string2cells(text, len));
6032 	}
6033 	else
6034 	    rc.right = FILL_X(col + len);
6035 	rc.bottom = FILL_Y(row + 1);
6036 
6037 	/* Cache the created brush, that saves a lot of time.  We need two:
6038 	 * one for cursor background and one for the normal background. */
6039 	if (gui.currBgColor == brush_color[0])
6040 	{
6041 	    hbr = hbr_cache[0];
6042 	    brush_lru = 1;
6043 	}
6044 	else if (gui.currBgColor == brush_color[1])
6045 	{
6046 	    hbr = hbr_cache[1];
6047 	    brush_lru = 0;
6048 	}
6049 	else
6050 	{
6051 	    if (hbr_cache[brush_lru] != NULL)
6052 		DeleteBrush(hbr_cache[brush_lru]);
6053 	    hbr_cache[brush_lru] = CreateSolidBrush(gui.currBgColor);
6054 	    brush_color[brush_lru] = gui.currBgColor;
6055 	    hbr = hbr_cache[brush_lru];
6056 	    brush_lru = !brush_lru;
6057 	}
6058 
6059 	fill_rect(&rc, hbr, gui.currBgColor);
6060 
6061 	SetBkMode(s_hdc, TRANSPARENT);
6062 
6063 	/*
6064 	 * When drawing block cursor, prevent inverted character spilling
6065 	 * over character cell (can happen with bold/italic)
6066 	 */
6067 	if (flags & DRAW_CURSOR)
6068 	{
6069 	    pcliprect = &rc;
6070 	    foptions = ETO_CLIPPED;
6071 	}
6072     }
6073     SetTextColor(s_hdc, gui.currFgColor);
6074     SelectFont(s_hdc, gui.currFont);
6075 
6076 #ifdef FEAT_DIRECTX
6077     if (IS_ENABLE_DIRECTX())
6078 	DWriteContext_SetFont(s_dwc, (HFONT)gui.currFont);
6079 #endif
6080 
6081     if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
6082     {
6083 	vim_free(padding);
6084 	pad_size = Columns;
6085 
6086 	/* Don't give an out-of-memory message here, it would call us
6087 	 * recursively. */
6088 	padding = (int *)lalloc(pad_size * sizeof(int), FALSE);
6089 	if (padding != NULL)
6090 	    for (i = 0; i < pad_size; i++)
6091 		padding[i] = gui.char_width;
6092     }
6093 
6094     /*
6095      * We have to provide the padding argument because italic and bold versions
6096      * of fixed-width fonts are often one pixel or so wider than their normal
6097      * versions.
6098      * No check for DRAW_BOLD, Windows will have done it already.
6099      */
6100 
6101     /* Check if there are any UTF-8 characters.  If not, use normal text
6102      * output to speed up output. */
6103     if (enc_utf8)
6104 	for (n = 0; n < len; ++n)
6105 	    if (text[n] >= 0x80)
6106 		break;
6107 
6108 #if defined(FEAT_DIRECTX)
6109     /* Quick hack to enable DirectWrite.  To use DirectWrite (antialias), it is
6110      * required that unicode drawing routine, currently.  So this forces it
6111      * enabled. */
6112     if (IS_ENABLE_DIRECTX())
6113 	n = 0; /* Keep n < len, to enter block for unicode. */
6114 #endif
6115 
6116     /* Check if the Unicode buffer exists and is big enough.  Create it
6117      * with the same length as the multi-byte string, the number of wide
6118      * characters is always equal or smaller. */
6119     if ((enc_utf8
6120 		|| (enc_codepage > 0 && (int)GetACP() != enc_codepage)
6121 		|| enc_latin9)
6122 	    && (unicodebuf == NULL || len > unibuflen))
6123     {
6124 	vim_free(unicodebuf);
6125 	unicodebuf = (WCHAR *)lalloc(len * sizeof(WCHAR), FALSE);
6126 
6127 	vim_free(unicodepdy);
6128 	unicodepdy = (int *)lalloc(len * sizeof(int), FALSE);
6129 
6130 	unibuflen = len;
6131     }
6132 
6133     if (enc_utf8 && n < len && unicodebuf != NULL)
6134     {
6135 	/* Output UTF-8 characters.  Composing characters should be
6136 	 * handled here. */
6137 	int		i;
6138 	int		wlen;	/* string length in words */
6139 	int		clen;	/* string length in characters */
6140 	int		cells;	/* cell width of string up to composing char */
6141 	int		cw;	/* width of current cell */
6142 	int		c;
6143 
6144 	wlen = 0;
6145 	clen = 0;
6146 	cells = 0;
6147 	for (i = 0; i < len; )
6148 	{
6149 	    c = utf_ptr2char(text + i);
6150 	    if (c >= 0x10000)
6151 	    {
6152 		/* Turn into UTF-16 encoding. */
6153 		unicodebuf[wlen++] = ((c - 0x10000) >> 10) + 0xD800;
6154 		unicodebuf[wlen++] = ((c - 0x10000) & 0x3ff) + 0xDC00;
6155 	    }
6156 	    else
6157 	    {
6158 		unicodebuf[wlen++] = c;
6159 	    }
6160 
6161 	    if (utf_iscomposing(c))
6162 		cw = 0;
6163 	    else
6164 	    {
6165 		cw = utf_char2cells(c);
6166 		if (cw > 2)		/* don't use 4 for unprintable char */
6167 		    cw = 1;
6168 	    }
6169 
6170 	    if (unicodepdy != NULL)
6171 	    {
6172 		/* Use unicodepdy to make characters fit as we expect, even
6173 		 * when the font uses different widths (e.g., bold character
6174 		 * is wider).  */
6175 		if (c >= 0x10000)
6176 		{
6177 		    unicodepdy[wlen - 2] = cw * gui.char_width;
6178 		    unicodepdy[wlen - 1] = 0;
6179 		}
6180 		else
6181 		    unicodepdy[wlen - 1] = cw * gui.char_width;
6182 	    }
6183 	    cells += cw;
6184 	    i += utf_ptr2len_len(text + i, len - i);
6185 	    ++clen;
6186 	}
6187 #if defined(FEAT_DIRECTX)
6188 	if (IS_ENABLE_DIRECTX())
6189 	{
6190 	    /* Add one to "cells" for italics. */
6191 	    DWriteContext_DrawText(s_dwc, unicodebuf, wlen,
6192 		    TEXT_X(col), TEXT_Y(row),
6193 		    FILL_X(cells + 1), FILL_Y(1) - p_linespace,
6194 		    gui.char_width, gui.currFgColor,
6195 		    foptions, pcliprect, unicodepdy);
6196 	}
6197 	else
6198 #endif
6199 	    ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
6200 		    foptions, pcliprect, unicodebuf, wlen, unicodepdy);
6201 	len = cells;	/* used for underlining */
6202     }
6203     else if ((enc_codepage > 0 && (int)GetACP() != enc_codepage) || enc_latin9)
6204     {
6205 	/* If we want to display codepage data, and the current CP is not the
6206 	 * ANSI one, we need to go via Unicode. */
6207 	if (unicodebuf != NULL)
6208 	{
6209 	    if (enc_latin9)
6210 		latin9_to_ucs(text, len, unicodebuf);
6211 	    else
6212 		len = MultiByteToWideChar(enc_codepage,
6213 			MB_PRECOMPOSED,
6214 			(char *)text, len,
6215 			(LPWSTR)unicodebuf, unibuflen);
6216 	    if (len != 0)
6217 	    {
6218 		/* Use unicodepdy to make characters fit as we expect, even
6219 		 * when the font uses different widths (e.g., bold character
6220 		 * is wider). */
6221 		if (unicodepdy != NULL)
6222 		{
6223 		    int i;
6224 		    int cw;
6225 
6226 		    for (i = 0; i < len; ++i)
6227 		    {
6228 			cw = utf_char2cells(unicodebuf[i]);
6229 			if (cw > 2)
6230 			    cw = 1;
6231 			unicodepdy[i] = cw * gui.char_width;
6232 		    }
6233 		}
6234 		ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
6235 			    foptions, pcliprect, unicodebuf, len, unicodepdy);
6236 	    }
6237 	}
6238     }
6239     else
6240     {
6241 #ifdef FEAT_RIGHTLEFT
6242 	/* Windows will mess up RL text, so we have to draw it character by
6243 	 * character.  Only do this if RL is on, since it's slow. */
6244 	if (curwin->w_p_rl)
6245 	    RevOut(s_hdc, TEXT_X(col), TEXT_Y(row),
6246 			 foptions, pcliprect, (char *)text, len, padding);
6247 	else
6248 #endif
6249 	    ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row),
6250 			 foptions, pcliprect, (char *)text, len, padding);
6251     }
6252 
6253     /* Underline */
6254     if (flags & DRAW_UNDERL)
6255     {
6256 	/* When p_linespace is 0, overwrite the bottom row of pixels.
6257 	 * Otherwise put the line just below the character. */
6258 	y = FILL_Y(row + 1) - 1;
6259 	if (p_linespace > 1)
6260 	    y -= p_linespace - 1;
6261 	draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currFgColor);
6262     }
6263 
6264     /* Strikethrough */
6265     if (flags & DRAW_STRIKE)
6266     {
6267 	y = FILL_Y(row + 1) - gui.char_height/2;
6268 	draw_line(FILL_X(col), y, FILL_X(col + len), y, gui.currSpColor);
6269     }
6270 
6271     /* Undercurl */
6272     if (flags & DRAW_UNDERC)
6273     {
6274 	int			x;
6275 	int			offset;
6276 	static const int	val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
6277 
6278 	y = FILL_Y(row + 1) - 1;
6279 	for (x = FILL_X(col); x < FILL_X(col + len); ++x)
6280 	{
6281 	    offset = val[x % 8];
6282 	    set_pixel(x, y - offset, gui.currSpColor);
6283 	}
6284     }
6285 }
6286 
6287 
6288 /*
6289  * Output routines.
6290  */
6291 
6292 /* Flush any output to the screen */
6293     void
6294 gui_mch_flush(void)
6295 {
6296 #   if defined(__BORLANDC__)
6297     /*
6298      * The GdiFlush declaration (in Borland C 5.01 <wingdi.h>) is not a
6299      * prototype declaration.
6300      * The compiler complains if __stdcall is not used in both declarations.
6301      */
6302     BOOL  __stdcall GdiFlush(void);
6303 #   endif
6304 
6305 #if defined(FEAT_DIRECTX)
6306     if (IS_ENABLE_DIRECTX())
6307 	DWriteContext_Flush(s_dwc);
6308 #endif
6309 
6310     GdiFlush();
6311 }
6312 
6313     static void
6314 clear_rect(RECT *rcp)
6315 {
6316     fill_rect(rcp, NULL, gui.back_pixel);
6317 }
6318 
6319 
6320     void
6321 gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
6322 {
6323     RECT	workarea_rect;
6324 
6325     get_work_area(&workarea_rect);
6326 
6327     *screen_w = workarea_rect.right - workarea_rect.left
6328 		- (GetSystemMetrics(SM_CXFRAME) +
6329 		   GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
6330 
6331     /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
6332      * the menubar for MSwin, we subtract it from the screen height, so that
6333      * the window size can be made to fit on the screen. */
6334     *screen_h = workarea_rect.bottom - workarea_rect.top
6335 		- (GetSystemMetrics(SM_CYFRAME) +
6336 		   GetSystemMetrics(SM_CXPADDEDBORDER)) * 2
6337 		- GetSystemMetrics(SM_CYCAPTION)
6338 #ifdef FEAT_MENU
6339 		- gui_mswin_get_menu_height(FALSE)
6340 #endif
6341 		;
6342 }
6343 
6344 
6345 #if defined(FEAT_MENU) || defined(PROTO)
6346 /*
6347  * Add a sub menu to the menu bar.
6348  */
6349     void
6350 gui_mch_add_menu(
6351     vimmenu_T	*menu,
6352     int		pos)
6353 {
6354     vimmenu_T	*parent = menu->parent;
6355 
6356     menu->submenu_id = CreatePopupMenu();
6357     menu->id = s_menu_id++;
6358 
6359     if (menu_is_menubar(menu->name))
6360     {
6361 	WCHAR	*wn = NULL;
6362 
6363 	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6364 	{
6365 	    /* 'encoding' differs from active codepage: convert menu name
6366 	     * and use wide function */
6367 	    wn = enc_to_utf16(menu->name, NULL);
6368 	    if (wn != NULL)
6369 	    {
6370 		MENUITEMINFOW	infow;
6371 
6372 		infow.cbSize = sizeof(infow);
6373 		infow.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID
6374 		    | MIIM_SUBMENU;
6375 		infow.dwItemData = (long_u)menu;
6376 		infow.wID = menu->id;
6377 		infow.fType = MFT_STRING;
6378 		infow.dwTypeData = wn;
6379 		infow.cch = (UINT)wcslen(wn);
6380 		infow.hSubMenu = menu->submenu_id;
6381 		InsertMenuItemW((parent == NULL)
6382 			? s_menuBar : parent->submenu_id,
6383 			(UINT)pos, TRUE, &infow);
6384 		vim_free(wn);
6385 	    }
6386 	}
6387 
6388 	if (wn == NULL)
6389 	{
6390 	    MENUITEMINFO	info;
6391 
6392 	    info.cbSize = sizeof(info);
6393 	    info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU;
6394 	    info.dwItemData = (long_u)menu;
6395 	    info.wID = menu->id;
6396 	    info.fType = MFT_STRING;
6397 	    info.dwTypeData = (LPTSTR)menu->name;
6398 	    info.cch = (UINT)STRLEN(menu->name);
6399 	    info.hSubMenu = menu->submenu_id;
6400 	    InsertMenuItem((parent == NULL)
6401 		    ? s_menuBar : parent->submenu_id,
6402 		    (UINT)pos, TRUE, &info);
6403 	}
6404     }
6405 
6406     /* Fix window size if menu may have wrapped */
6407     if (parent == NULL)
6408 	gui_mswin_get_menu_height(!gui.starting);
6409 #ifdef FEAT_TEAROFF
6410     else if (IsWindow(parent->tearoff_handle))
6411 	rebuild_tearoff(parent);
6412 #endif
6413 }
6414 
6415     void
6416 gui_mch_show_popupmenu(vimmenu_T *menu)
6417 {
6418     POINT mp;
6419 
6420     (void)GetCursorPos((LPPOINT)&mp);
6421     gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y);
6422 }
6423 
6424     void
6425 gui_make_popup(char_u *path_name, int mouse_pos)
6426 {
6427     vimmenu_T	*menu = gui_find_menu(path_name);
6428 
6429     if (menu != NULL)
6430     {
6431 	POINT	p;
6432 
6433 	/* Find the position of the current cursor */
6434 	GetDCOrgEx(s_hdc, &p);
6435 	if (mouse_pos)
6436 	{
6437 	    int	mx, my;
6438 
6439 	    gui_mch_getmouse(&mx, &my);
6440 	    p.x += mx;
6441 	    p.y += my;
6442 	}
6443 	else if (curwin != NULL)
6444 	{
6445 	    p.x += TEXT_X(curwin->w_wincol + curwin->w_wcol + 1);
6446 	    p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1);
6447 	}
6448 	msg_scroll = FALSE;
6449 	gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y);
6450     }
6451 }
6452 
6453 #if defined(FEAT_TEAROFF) || defined(PROTO)
6454 /*
6455  * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
6456  * create it as a pseudo-"tearoff menu".
6457  */
6458     void
6459 gui_make_tearoff(char_u *path_name)
6460 {
6461     vimmenu_T	*menu = gui_find_menu(path_name);
6462 
6463     /* Found the menu, so tear it off. */
6464     if (menu != NULL)
6465 	gui_mch_tearoff(menu->dname, menu, 0xffffL, 0xffffL);
6466 }
6467 #endif
6468 
6469 /*
6470  * Add a menu item to a menu
6471  */
6472     void
6473 gui_mch_add_menu_item(
6474     vimmenu_T	*menu,
6475     int		idx)
6476 {
6477     vimmenu_T	*parent = menu->parent;
6478 
6479     menu->id = s_menu_id++;
6480     menu->submenu_id = NULL;
6481 
6482 #ifdef FEAT_TEAROFF
6483     if (STRNCMP(menu->name, TEAR_STRING, TEAR_LEN) == 0)
6484     {
6485 	InsertMenu(parent->submenu_id, (UINT)idx, MF_BITMAP|MF_BYPOSITION,
6486 		(UINT)menu->id, (LPCTSTR) s_htearbitmap);
6487     }
6488     else
6489 #endif
6490 #ifdef FEAT_TOOLBAR
6491     if (menu_is_toolbar(parent->name))
6492     {
6493 	TBBUTTON newtb;
6494 
6495 	vim_memset(&newtb, 0, sizeof(newtb));
6496 	if (menu_is_separator(menu->name))
6497 	{
6498 	    newtb.iBitmap = 0;
6499 	    newtb.fsStyle = TBSTYLE_SEP;
6500 	}
6501 	else
6502 	{
6503 	    newtb.iBitmap = get_toolbar_bitmap(menu);
6504 	    newtb.fsStyle = TBSTYLE_BUTTON;
6505 	}
6506 	newtb.idCommand = menu->id;
6507 	newtb.fsState = TBSTATE_ENABLED;
6508 	newtb.iString = 0;
6509 	SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx,
6510 							     (LPARAM)&newtb);
6511 	menu->submenu_id = (HMENU)-1;
6512     }
6513     else
6514 #endif
6515     {
6516 	WCHAR	*wn = NULL;
6517 
6518 	if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6519 	{
6520 	    /* 'encoding' differs from active codepage: convert menu item name
6521 	     * and use wide function */
6522 	    wn = enc_to_utf16(menu->name, NULL);
6523 	    if (wn != NULL)
6524 	    {
6525 		InsertMenuW(parent->submenu_id, (UINT)idx,
6526 			(menu_is_separator(menu->name)
6527 				 ? MF_SEPARATOR : MF_STRING) | MF_BYPOSITION,
6528 			(UINT)menu->id, wn);
6529 		vim_free(wn);
6530 	    }
6531 	}
6532 	if (wn == NULL)
6533 	    InsertMenu(parent->submenu_id, (UINT)idx,
6534 		(menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING)
6535 							      | MF_BYPOSITION,
6536 		(UINT)menu->id, (LPCTSTR)menu->name);
6537 #ifdef FEAT_TEAROFF
6538 	if (IsWindow(parent->tearoff_handle))
6539 	    rebuild_tearoff(parent);
6540 #endif
6541     }
6542 }
6543 
6544 /*
6545  * Destroy the machine specific menu widget.
6546  */
6547     void
6548 gui_mch_destroy_menu(vimmenu_T *menu)
6549 {
6550 #ifdef FEAT_TOOLBAR
6551     /*
6552      * is this a toolbar button?
6553      */
6554     if (menu->submenu_id == (HMENU)-1)
6555     {
6556 	int iButton;
6557 
6558 	iButton = (int)SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX,
6559 							 (WPARAM)menu->id, 0);
6560 	SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
6561     }
6562     else
6563 #endif
6564     {
6565 	if (menu->parent != NULL
6566 		&& menu_is_popup(menu->parent->dname)
6567 		&& menu->parent->submenu_id != NULL)
6568 	    RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND);
6569 	else
6570 	    RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
6571 	if (menu->submenu_id != NULL)
6572 	    DestroyMenu(menu->submenu_id);
6573 #ifdef FEAT_TEAROFF
6574 	if (IsWindow(menu->tearoff_handle))
6575 	    DestroyWindow(menu->tearoff_handle);
6576 	if (menu->parent != NULL
6577 		&& menu->parent->children != NULL
6578 		&& IsWindow(menu->parent->tearoff_handle))
6579 	{
6580 	    /* This menu must not show up when rebuilding the tearoff window. */
6581 	    menu->modes = 0;
6582 	    rebuild_tearoff(menu->parent);
6583 	}
6584 #endif
6585     }
6586 }
6587 
6588 #ifdef FEAT_TEAROFF
6589     static void
6590 rebuild_tearoff(vimmenu_T *menu)
6591 {
6592     /*hackish*/
6593     char_u	tbuf[128];
6594     RECT	trect;
6595     RECT	rct;
6596     RECT	roct;
6597     int		x, y;
6598 
6599     HWND thwnd = menu->tearoff_handle;
6600 
6601     GetWindowText(thwnd, (LPSTR)tbuf, 127);
6602     if (GetWindowRect(thwnd, &trect)
6603 	    && GetWindowRect(s_hwnd, &rct)
6604 	    && GetClientRect(s_hwnd, &roct))
6605     {
6606 	x = trect.left - rct.left;
6607 	y = (trect.top -  rct.bottom  + roct.bottom);
6608     }
6609     else
6610     {
6611 	x = y = 0xffffL;
6612     }
6613     DestroyWindow(thwnd);
6614     if (menu->children != NULL)
6615     {
6616 	gui_mch_tearoff(tbuf, menu, x, y);
6617 	if (IsWindow(menu->tearoff_handle))
6618 	    (void) SetWindowPos(menu->tearoff_handle,
6619 				NULL,
6620 				(int)trect.left,
6621 				(int)trect.top,
6622 				0, 0,
6623 				SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
6624     }
6625 }
6626 #endif /* FEAT_TEAROFF */
6627 
6628 /*
6629  * Make a menu either grey or not grey.
6630  */
6631     void
6632 gui_mch_menu_grey(
6633     vimmenu_T	*menu,
6634     int	    grey)
6635 {
6636 #ifdef FEAT_TOOLBAR
6637     /*
6638      * is this a toolbar button?
6639      */
6640     if (menu->submenu_id == (HMENU)-1)
6641     {
6642 	SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
6643 	    (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
6644     }
6645     else
6646 #endif
6647     (void)EnableMenuItem(menu->parent ? menu->parent->submenu_id : s_menuBar,
6648 		    menu->id, MF_BYCOMMAND | (grey ? MF_GRAYED : MF_ENABLED));
6649 
6650 #ifdef FEAT_TEAROFF
6651     if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
6652     {
6653 	WORD menuID;
6654 	HWND menuHandle;
6655 
6656 	/*
6657 	 * A tearoff button has changed state.
6658 	 */
6659 	if (menu->children == NULL)
6660 	    menuID = (WORD)(menu->id);
6661 	else
6662 	    menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
6663 	menuHandle = GetDlgItem(menu->parent->tearoff_handle, menuID);
6664 	if (menuHandle)
6665 	    EnableWindow(menuHandle, !grey);
6666 
6667     }
6668 #endif
6669 }
6670 
6671 #endif /* FEAT_MENU */
6672 
6673 
6674 /* define some macros used to make the dialogue creation more readable */
6675 
6676 #define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
6677 #define add_word(x)		*p++ = (x)
6678 #define add_long(x)		dwp = (DWORD *)p; *dwp++ = (x); p = (WORD *)dwp
6679 
6680 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
6681 /*
6682  * stuff for dialogs
6683  */
6684 
6685 /*
6686  * The callback routine used by all the dialogs.  Very simple.  First,
6687  * acknowledges the INITDIALOG message so that Windows knows to do standard
6688  * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
6689  * pressed, return that button's ID - IDCANCEL (2), which is the button's
6690  * number.
6691  */
6692     static LRESULT CALLBACK
6693 dialog_callback(
6694     HWND hwnd,
6695     UINT message,
6696     WPARAM wParam,
6697     LPARAM lParam UNUSED)
6698 {
6699     if (message == WM_INITDIALOG)
6700     {
6701 	CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
6702 	/* Set focus to the dialog.  Set the default button, if specified. */
6703 	(void)SetFocus(hwnd);
6704 	if (dialog_default_button > IDCANCEL)
6705 	    (void)SetFocus(GetDlgItem(hwnd, dialog_default_button));
6706 	else
6707 	    /* We don't have a default, set focus on another element of the
6708 	     * dialog window, probably the icon */
6709 	    (void)SetFocus(GetDlgItem(hwnd, DLG_NONBUTTON_CONTROL));
6710 	return FALSE;
6711     }
6712 
6713     if (message == WM_COMMAND)
6714     {
6715 	int	button = LOWORD(wParam);
6716 
6717 	/* Don't end the dialog if something was selected that was
6718 	 * not a button.
6719 	 */
6720 	if (button >= DLG_NONBUTTON_CONTROL)
6721 	    return TRUE;
6722 
6723 	/* If the edit box exists, copy the string. */
6724 	if (s_textfield != NULL)
6725 	{
6726 	    /* If the OS is Windows NT, and 'encoding' differs from active
6727 	     * codepage: use wide function and convert text. */
6728 	    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
6729 	    {
6730 	       WCHAR  *wp = (WCHAR *)alloc(IOSIZE * sizeof(WCHAR));
6731 	       char_u *p;
6732 
6733 	       GetDlgItemTextW(hwnd, DLG_NONBUTTON_CONTROL + 2, wp, IOSIZE);
6734 	       p = utf16_to_enc(wp, NULL);
6735 	       vim_strncpy(s_textfield, p, IOSIZE);
6736 	       vim_free(p);
6737 	       vim_free(wp);
6738 	    }
6739 	    else
6740 		GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
6741 						(LPSTR)s_textfield, IOSIZE);
6742 	}
6743 
6744 	/*
6745 	 * Need to check for IDOK because if the user just hits Return to
6746 	 * accept the default value, some reason this is what we get.
6747 	 */
6748 	if (button == IDOK)
6749 	{
6750 	    if (dialog_default_button > IDCANCEL)
6751 		EndDialog(hwnd, dialog_default_button);
6752 	}
6753 	else
6754 	    EndDialog(hwnd, button - IDCANCEL);
6755 	return TRUE;
6756     }
6757 
6758     if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
6759     {
6760 	EndDialog(hwnd, 0);
6761 	return TRUE;
6762     }
6763     return FALSE;
6764 }
6765 
6766 /*
6767  * Create a dialog dynamically from the parameter strings.
6768  * type		= type of dialog (question, alert, etc.)
6769  * title	= dialog title. may be NULL for default title.
6770  * message	= text to display. Dialog sizes to accommodate it.
6771  * buttons	= '\n' separated list of button captions, default first.
6772  * dfltbutton	= number of default button.
6773  *
6774  * This routine returns 1 if the first button is pressed,
6775  *			2 for the second, etc.
6776  *
6777  *			0 indicates Esc was pressed.
6778  *			-1 for unexpected error
6779  *
6780  * If stubbing out this fn, return 1.
6781  */
6782 
6783 static const char *dlg_icons[] = /* must match names in resource file */
6784 {
6785     "IDR_VIM",
6786     "IDR_VIM_ERROR",
6787     "IDR_VIM_ALERT",
6788     "IDR_VIM_INFO",
6789     "IDR_VIM_QUESTION"
6790 };
6791 
6792     int
6793 gui_mch_dialog(
6794     int		 type,
6795     char_u	*title,
6796     char_u	*message,
6797     char_u	*buttons,
6798     int		 dfltbutton,
6799     char_u	*textfield,
6800     int		ex_cmd)
6801 {
6802     WORD	*p, *pdlgtemplate, *pnumitems;
6803     DWORD	*dwp;
6804     int		numButtons;
6805     int		*buttonWidths, *buttonPositions;
6806     int		buttonYpos;
6807     int		nchar, i;
6808     DWORD	lStyle;
6809     int		dlgwidth = 0;
6810     int		dlgheight;
6811     int		editboxheight;
6812     int		horizWidth = 0;
6813     int		msgheight;
6814     char_u	*pstart;
6815     char_u	*pend;
6816     char_u	*last_white;
6817     char_u	*tbuffer;
6818     RECT	rect;
6819     HWND	hwnd;
6820     HDC		hdc;
6821     HFONT	font, oldFont;
6822     TEXTMETRIC	fontInfo;
6823     int		fontHeight;
6824     int		textWidth, minButtonWidth, messageWidth;
6825     int		maxDialogWidth;
6826     int		maxDialogHeight;
6827     int		scroll_flag = 0;
6828     int		vertical;
6829     int		dlgPaddingX;
6830     int		dlgPaddingY;
6831 #ifdef USE_SYSMENU_FONT
6832     LOGFONT	lfSysmenu;
6833     int		use_lfSysmenu = FALSE;
6834 #endif
6835     garray_T	ga;
6836     int		l;
6837 
6838 #ifndef NO_CONSOLE
6839     /* Don't output anything in silent mode ("ex -s") */
6840     if (silent_mode)
6841 	return dfltbutton;   /* return default option */
6842 #endif
6843 
6844     if (s_hwnd == NULL)
6845 	get_dialog_font_metrics();
6846 
6847     if ((type < 0) || (type > VIM_LAST_TYPE))
6848 	type = 0;
6849 
6850     /* allocate some memory for dialog template */
6851     /* TODO should compute this really */
6852     pdlgtemplate = p = (PWORD)LocalAlloc(LPTR,
6853 					DLG_ALLOC_SIZE + STRLEN(message) * 2);
6854 
6855     if (p == NULL)
6856 	return -1;
6857 
6858     /*
6859      * make a copy of 'buttons' to fiddle with it.  compiler grizzles because
6860      * vim_strsave() doesn't take a const arg (why not?), so cast away the
6861      * const.
6862      */
6863     tbuffer = vim_strsave(buttons);
6864     if (tbuffer == NULL)
6865 	return -1;
6866 
6867     --dfltbutton;   /* Change from one-based to zero-based */
6868 
6869     /* Count buttons */
6870     numButtons = 1;
6871     for (i = 0; tbuffer[i] != '\0'; i++)
6872     {
6873 	if (tbuffer[i] == DLG_BUTTON_SEP)
6874 	    numButtons++;
6875     }
6876     if (dfltbutton >= numButtons)
6877 	dfltbutton = -1;
6878 
6879     /* Allocate array to hold the width of each button */
6880     buttonWidths = (int *)lalloc(numButtons * sizeof(int), TRUE);
6881     if (buttonWidths == NULL)
6882 	return -1;
6883 
6884     /* Allocate array to hold the X position of each button */
6885     buttonPositions = (int *)lalloc(numButtons * sizeof(int), TRUE);
6886     if (buttonPositions == NULL)
6887 	return -1;
6888 
6889     /*
6890      * Calculate how big the dialog must be.
6891      */
6892     hwnd = GetDesktopWindow();
6893     hdc = GetWindowDC(hwnd);
6894 #ifdef USE_SYSMENU_FONT
6895     if (gui_w32_get_menu_font(&lfSysmenu) == OK)
6896     {
6897 	font = CreateFontIndirect(&lfSysmenu);
6898 	use_lfSysmenu = TRUE;
6899     }
6900     else
6901 #endif
6902     font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
6903 		      VARIABLE_PITCH , DLG_FONT_NAME);
6904     if (s_usenewlook)
6905     {
6906 	oldFont = SelectFont(hdc, font);
6907 	dlgPaddingX = DLG_PADDING_X;
6908 	dlgPaddingY = DLG_PADDING_Y;
6909     }
6910     else
6911     {
6912 	oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
6913 	dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
6914 	dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
6915     }
6916     GetTextMetrics(hdc, &fontInfo);
6917     fontHeight = fontInfo.tmHeight;
6918 
6919     /* Minimum width for horizontal button */
6920     minButtonWidth = GetTextWidth(hdc, (char_u *)"Cancel", 6);
6921 
6922     /* Maximum width of a dialog, if possible */
6923     if (s_hwnd == NULL)
6924     {
6925 	RECT	workarea_rect;
6926 
6927 	/* We don't have a window, use the desktop area. */
6928 	get_work_area(&workarea_rect);
6929 	maxDialogWidth = workarea_rect.right - workarea_rect.left - 100;
6930 	if (maxDialogWidth > 600)
6931 	    maxDialogWidth = 600;
6932 	/* Leave some room for the taskbar. */
6933 	maxDialogHeight = workarea_rect.bottom - workarea_rect.top - 150;
6934     }
6935     else
6936     {
6937 	/* Use our own window for the size, unless it's very small. */
6938 	GetWindowRect(s_hwnd, &rect);
6939 	maxDialogWidth = rect.right - rect.left
6940 				   - (GetSystemMetrics(SM_CXFRAME) +
6941 				      GetSystemMetrics(SM_CXPADDEDBORDER)) * 2;
6942 	if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
6943 	    maxDialogWidth = DLG_MIN_MAX_WIDTH;
6944 
6945 	maxDialogHeight = rect.bottom - rect.top
6946 				   - (GetSystemMetrics(SM_CYFRAME) +
6947 				      GetSystemMetrics(SM_CXPADDEDBORDER)) * 4
6948 				   - GetSystemMetrics(SM_CYCAPTION);
6949 	if (maxDialogHeight < DLG_MIN_MAX_HEIGHT)
6950 	    maxDialogHeight = DLG_MIN_MAX_HEIGHT;
6951     }
6952 
6953     /* Set dlgwidth to width of message.
6954      * Copy the message into "ga", changing NL to CR-NL and inserting line
6955      * breaks where needed. */
6956     pstart = message;
6957     messageWidth = 0;
6958     msgheight = 0;
6959     ga_init2(&ga, sizeof(char), 500);
6960     do
6961     {
6962 	msgheight += fontHeight;    /* at least one line */
6963 
6964 	/* Need to figure out where to break the string.  The system does it
6965 	 * at a word boundary, which would mean we can't compute the number of
6966 	 * wrapped lines. */
6967 	textWidth = 0;
6968 	last_white = NULL;
6969 	for (pend = pstart; *pend != NUL && *pend != '\n'; )
6970 	{
6971 	    l = (*mb_ptr2len)(pend);
6972 	    if (l == 1 && VIM_ISWHITE(*pend)
6973 					&& textWidth > maxDialogWidth * 3 / 4)
6974 		last_white = pend;
6975 	    textWidth += GetTextWidthEnc(hdc, pend, l);
6976 	    if (textWidth >= maxDialogWidth)
6977 	    {
6978 		/* Line will wrap. */
6979 		messageWidth = maxDialogWidth;
6980 		msgheight += fontHeight;
6981 		textWidth = 0;
6982 
6983 		if (last_white != NULL)
6984 		{
6985 		    /* break the line just after a space */
6986 		    ga.ga_len -= (int)(pend - (last_white + 1));
6987 		    pend = last_white + 1;
6988 		    last_white = NULL;
6989 		}
6990 		ga_append(&ga, '\r');
6991 		ga_append(&ga, '\n');
6992 		continue;
6993 	    }
6994 
6995 	    while (--l >= 0)
6996 		ga_append(&ga, *pend++);
6997 	}
6998 	if (textWidth > messageWidth)
6999 	    messageWidth = textWidth;
7000 
7001 	ga_append(&ga, '\r');
7002 	ga_append(&ga, '\n');
7003 	pstart = pend + 1;
7004     } while (*pend != NUL);
7005 
7006     if (ga.ga_data != NULL)
7007 	message = ga.ga_data;
7008 
7009     messageWidth += 10;		/* roundoff space */
7010 
7011     /* Add width of icon to dlgwidth, and some space */
7012     dlgwidth = messageWidth + DLG_ICON_WIDTH + 3 * dlgPaddingX
7013 					     + GetSystemMetrics(SM_CXVSCROLL);
7014 
7015     if (msgheight < DLG_ICON_HEIGHT)
7016 	msgheight = DLG_ICON_HEIGHT;
7017 
7018     /*
7019      * Check button names.  A long one will make the dialog wider.
7020      * When called early (-register error message) p_go isn't initialized.
7021      */
7022     vertical = (p_go != NULL && vim_strchr(p_go, GO_VERTICAL) != NULL);
7023     if (!vertical)
7024     {
7025 	// Place buttons horizontally if they fit.
7026 	horizWidth = dlgPaddingX;
7027 	pstart = tbuffer;
7028 	i = 0;
7029 	do
7030 	{
7031 	    pend = vim_strchr(pstart, DLG_BUTTON_SEP);
7032 	    if (pend == NULL)
7033 		pend = pstart + STRLEN(pstart);	// Last button name.
7034 	    textWidth = GetTextWidthEnc(hdc, pstart, (int)(pend - pstart));
7035 	    if (textWidth < minButtonWidth)
7036 		textWidth = minButtonWidth;
7037 	    textWidth += dlgPaddingX;	    /* Padding within button */
7038 	    buttonWidths[i] = textWidth;
7039 	    buttonPositions[i++] = horizWidth;
7040 	    horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
7041 	    pstart = pend + 1;
7042 	} while (*pend != NUL);
7043 
7044 	if (horizWidth > maxDialogWidth)
7045 	    vertical = TRUE;	// Too wide to fit on the screen.
7046 	else if (horizWidth > dlgwidth)
7047 	    dlgwidth = horizWidth;
7048     }
7049 
7050     if (vertical)
7051     {
7052 	// Stack buttons vertically.
7053 	pstart = tbuffer;
7054 	do
7055 	{
7056 	    pend = vim_strchr(pstart, DLG_BUTTON_SEP);
7057 	    if (pend == NULL)
7058 		pend = pstart + STRLEN(pstart);	// Last button name.
7059 	    textWidth = GetTextWidthEnc(hdc, pstart, (int)(pend - pstart));
7060 	    textWidth += dlgPaddingX;		/* Padding within button */
7061 	    textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
7062 	    if (textWidth > dlgwidth)
7063 		dlgwidth = textWidth;
7064 	    pstart = pend + 1;
7065 	} while (*pend != NUL);
7066     }
7067 
7068     if (dlgwidth < DLG_MIN_WIDTH)
7069 	dlgwidth = DLG_MIN_WIDTH;	/* Don't allow a really thin dialog!*/
7070 
7071     /* start to fill in the dlgtemplate information.  addressing by WORDs */
7072     if (s_usenewlook)
7073 	lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE |DS_SETFONT;
7074     else
7075 	lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE;
7076 
7077     add_long(lStyle);
7078     add_long(0);	// (lExtendedStyle)
7079     pnumitems = p;	/*save where the number of items must be stored*/
7080     add_word(0);	// NumberOfItems(will change later)
7081     add_word(10);	// x
7082     add_word(10);	// y
7083     add_word(PixelToDialogX(dlgwidth));	// cx
7084 
7085     // Dialog height.
7086     if (vertical)
7087 	dlgheight = msgheight + 2 * dlgPaddingY
7088 			   + DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons;
7089     else
7090 	dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight;
7091 
7092     // Dialog needs to be taller if contains an edit box.
7093     editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y;
7094     if (textfield != NULL)
7095 	dlgheight += editboxheight;
7096 
7097     /* Restrict the size to a maximum.  Causes a scrollbar to show up. */
7098     if (dlgheight > maxDialogHeight)
7099     {
7100 	msgheight = msgheight - (dlgheight - maxDialogHeight);
7101 	dlgheight = maxDialogHeight;
7102 	scroll_flag = WS_VSCROLL;
7103 	/* Make sure scrollbar doesn't appear in the middle of the dialog */
7104 	messageWidth = dlgwidth - DLG_ICON_WIDTH - 3 * dlgPaddingX;
7105     }
7106 
7107     add_word(PixelToDialogY(dlgheight));
7108 
7109     add_word(0);	// Menu
7110     add_word(0);	// Class
7111 
7112     /* copy the title of the dialog */
7113     nchar = nCopyAnsiToWideChar(p, (title ? (LPSTR)title
7114 				   : (LPSTR)("Vim "VIM_VERSION_MEDIUM)), TRUE);
7115     p += nchar;
7116 
7117     if (s_usenewlook)
7118     {
7119 	/* do the font, since DS_3DLOOK doesn't work properly */
7120 #ifdef USE_SYSMENU_FONT
7121 	if (use_lfSysmenu)
7122 	{
7123 	    /* point size */
7124 	    *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
7125 		    GetDeviceCaps(hdc, LOGPIXELSY));
7126 	    nchar = nCopyAnsiToWideChar(p, lfSysmenu.lfFaceName, FALSE);
7127 	}
7128 	else
7129 #endif
7130 	{
7131 	    *p++ = DLG_FONT_POINT_SIZE;		// point size
7132 	    nchar = nCopyAnsiToWideChar(p, DLG_FONT_NAME, FALSE);
7133 	}
7134 	p += nchar;
7135     }
7136 
7137     buttonYpos = msgheight + 2 * dlgPaddingY;
7138 
7139     if (textfield != NULL)
7140 	buttonYpos += editboxheight;
7141 
7142     pstart = tbuffer;
7143     if (!vertical)
7144 	horizWidth = (dlgwidth - horizWidth) / 2;	/* Now it's X offset */
7145     for (i = 0; i < numButtons; i++)
7146     {
7147 	/* get end of this button. */
7148 	for (	pend = pstart;
7149 		*pend && (*pend != DLG_BUTTON_SEP);
7150 		pend++)
7151 	    ;
7152 
7153 	if (*pend)
7154 	    *pend = '\0';
7155 
7156 	/*
7157 	 * old NOTE:
7158 	 * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
7159 	 * the focus to the first tab-able button and in so doing makes that
7160 	 * the default!! Grrr.  Workaround: Make the default button the only
7161 	 * one with WS_TABSTOP style. Means user can't tab between buttons, but
7162 	 * he/she can use arrow keys.
7163 	 *
7164 	 * new NOTE: BS_DEFPUSHBUTTON is required to be able to select the
7165 	 * right button when hitting <Enter>.  E.g., for the ":confirm quit"
7166 	 * dialog.  Also needed for when the textfield is the default control.
7167 	 * It appears to work now (perhaps not on Win95?).
7168 	 */
7169 	if (vertical)
7170 	{
7171 	    p = add_dialog_element(p,
7172 		    (i == dfltbutton
7173 			    ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
7174 		    PixelToDialogX(DLG_VERT_PADDING_X),
7175 		    PixelToDialogY(buttonYpos /* TBK */
7176 				   + 2 * fontHeight * i),
7177 		    PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
7178 		    (WORD)(PixelToDialogY(2 * fontHeight) - 1),
7179 		    (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, (char *)pstart);
7180 	}
7181 	else
7182 	{
7183 	    p = add_dialog_element(p,
7184 		    (i == dfltbutton
7185 			    ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
7186 		    PixelToDialogX(horizWidth + buttonPositions[i]),
7187 		    PixelToDialogY(buttonYpos), /* TBK */
7188 		    PixelToDialogX(buttonWidths[i]),
7189 		    (WORD)(PixelToDialogY(2 * fontHeight) - 1),
7190 		    (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, (char *)pstart);
7191 	}
7192 	pstart = pend + 1;	/*next button*/
7193     }
7194     *pnumitems += numButtons;
7195 
7196     /* Vim icon */
7197     p = add_dialog_element(p, SS_ICON,
7198 	    PixelToDialogX(dlgPaddingX),
7199 	    PixelToDialogY(dlgPaddingY),
7200 	    PixelToDialogX(DLG_ICON_WIDTH),
7201 	    PixelToDialogY(DLG_ICON_HEIGHT),
7202 	    DLG_NONBUTTON_CONTROL + 0, (WORD)0x0082,
7203 	    dlg_icons[type]);
7204 
7205     /* Dialog message */
7206     p = add_dialog_element(p, ES_LEFT|scroll_flag|ES_MULTILINE|ES_READONLY,
7207 	    PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
7208 	    PixelToDialogY(dlgPaddingY),
7209 	    (WORD)(PixelToDialogX(messageWidth) + 1),
7210 	    PixelToDialogY(msgheight),
7211 	    DLG_NONBUTTON_CONTROL + 1, (WORD)0x0081, (char *)message);
7212 
7213     /* Edit box */
7214     if (textfield != NULL)
7215     {
7216 	p = add_dialog_element(p, ES_LEFT|ES_AUTOHSCROLL|WS_TABSTOP|WS_BORDER,
7217 		PixelToDialogX(2 * dlgPaddingX),
7218 		PixelToDialogY(2 * dlgPaddingY + msgheight),
7219 		PixelToDialogX(dlgwidth - 4 * dlgPaddingX),
7220 		PixelToDialogY(fontHeight + dlgPaddingY),
7221 		DLG_NONBUTTON_CONTROL + 2, (WORD)0x0081, (char *)textfield);
7222 	*pnumitems += 1;
7223     }
7224 
7225     *pnumitems += 2;
7226 
7227     SelectFont(hdc, oldFont);
7228     DeleteObject(font);
7229     ReleaseDC(hwnd, hdc);
7230 
7231     /* Let the dialog_callback() function know which button to make default
7232      * If we have an edit box, make that the default. We also need to tell
7233      * dialog_callback() if this dialog contains an edit box or not. We do
7234      * this by setting s_textfield if it does.
7235      */
7236     if (textfield != NULL)
7237     {
7238 	dialog_default_button = DLG_NONBUTTON_CONTROL + 2;
7239 	s_textfield = textfield;
7240     }
7241     else
7242     {
7243 	dialog_default_button = IDCANCEL + 1 + dfltbutton;
7244 	s_textfield = NULL;
7245     }
7246 
7247     /* show the dialog box modally and get a return value */
7248     nchar = (int)DialogBoxIndirect(
7249 	    s_hinst,
7250 	    (LPDLGTEMPLATE)pdlgtemplate,
7251 	    s_hwnd,
7252 	    (DLGPROC)dialog_callback);
7253 
7254     LocalFree(LocalHandle(pdlgtemplate));
7255     vim_free(tbuffer);
7256     vim_free(buttonWidths);
7257     vim_free(buttonPositions);
7258     vim_free(ga.ga_data);
7259 
7260     /* Focus back to our window (for when MDI is used). */
7261     (void)SetFocus(s_hwnd);
7262 
7263     return nchar;
7264 }
7265 
7266 #endif /* FEAT_GUI_DIALOG */
7267 
7268 /*
7269  * Put a simple element (basic class) onto a dialog template in memory.
7270  * return a pointer to where the next item should be added.
7271  *
7272  * parameters:
7273  *  lStyle = additional style flags
7274  *		(be careful, NT3.51 & Win32s will ignore the new ones)
7275  *  x,y = x & y positions IN DIALOG UNITS
7276  *  w,h = width and height IN DIALOG UNITS
7277  *  Id  = ID used in messages
7278  *  clss  = class ID, e.g 0x0080 for a button, 0x0082 for a static
7279  *  caption = usually text or resource name
7280  *
7281  *  TODO: use the length information noted here to enable the dialog creation
7282  *  routines to work out more exactly how much memory they need to alloc.
7283  */
7284     static PWORD
7285 add_dialog_element(
7286     PWORD p,
7287     DWORD lStyle,
7288     WORD x,
7289     WORD y,
7290     WORD w,
7291     WORD h,
7292     WORD Id,
7293     WORD clss,
7294     const char *caption)
7295 {
7296     int nchar;
7297 
7298     p = lpwAlign(p);	/* Align to dword boundary*/
7299     lStyle = lStyle | WS_VISIBLE | WS_CHILD;
7300     *p++ = LOWORD(lStyle);
7301     *p++ = HIWORD(lStyle);
7302     *p++ = 0;		// LOWORD (lExtendedStyle)
7303     *p++ = 0;		// HIWORD (lExtendedStyle)
7304     *p++ = x;
7305     *p++ = y;
7306     *p++ = w;
7307     *p++ = h;
7308     *p++ = Id;		//9 or 10 words in all
7309 
7310     *p++ = (WORD)0xffff;
7311     *p++ = clss;			//2 more here
7312 
7313     nchar = nCopyAnsiToWideChar(p, (LPSTR)caption, TRUE); //strlen(caption)+1
7314     p += nchar;
7315 
7316     *p++ = 0;  // advance pointer over nExtraStuff WORD   - 2 more
7317 
7318     return p;	//total = 15+ (strlen(caption)) words
7319 		//	   = 30 + 2(strlen(caption) bytes reqd
7320 }
7321 
7322 
7323 /*
7324  * Helper routine.  Take an input pointer, return closest pointer that is
7325  * aligned on a DWORD (4 byte) boundary.  Taken from the Win32SDK samples.
7326  */
7327     static LPWORD
7328 lpwAlign(
7329     LPWORD lpIn)
7330 {
7331     long_u ul;
7332 
7333     ul = (long_u)lpIn;
7334     ul += 3;
7335     ul >>= 2;
7336     ul <<= 2;
7337     return (LPWORD)ul;
7338 }
7339 
7340 /*
7341  * Helper routine.  Takes second parameter as Ansi string, copies it to first
7342  * parameter as wide character (16-bits / char) string, and returns integer
7343  * number of wide characters (words) in string (including the trailing wide
7344  * char NULL).  Partly taken from the Win32SDK samples.
7345  * If "use_enc" is TRUE, 'encoding' is used for "lpAnsiIn". If FALSE, current
7346  * ACP is used for "lpAnsiIn". */
7347     static int
7348 nCopyAnsiToWideChar(
7349     LPWORD lpWCStr,
7350     LPSTR lpAnsiIn,
7351     BOOL use_enc)
7352 {
7353     int		nChar = 0;
7354     int		len = lstrlen(lpAnsiIn) + 1;	/* include NUL character */
7355     int		i;
7356     WCHAR	*wn;
7357 
7358     if (use_enc && enc_codepage >= 0 && (int)GetACP() != enc_codepage)
7359     {
7360 	/* Not a codepage, use our own conversion function. */
7361 	wn = enc_to_utf16((char_u *)lpAnsiIn, NULL);
7362 	if (wn != NULL)
7363 	{
7364 	    wcscpy(lpWCStr, wn);
7365 	    nChar = (int)wcslen(wn) + 1;
7366 	    vim_free(wn);
7367 	}
7368     }
7369     if (nChar == 0)
7370 	/* Use Win32 conversion function. */
7371 	nChar = MultiByteToWideChar(
7372 		enc_codepage > 0 ? enc_codepage : CP_ACP,
7373 		MB_PRECOMPOSED,
7374 		lpAnsiIn, len,
7375 		lpWCStr, len);
7376     for (i = 0; i < nChar; ++i)
7377 	if (lpWCStr[i] == (WORD)'\t')	/* replace tabs with spaces */
7378 	    lpWCStr[i] = (WORD)' ';
7379 
7380     return nChar;
7381 }
7382 
7383 
7384 #ifdef FEAT_TEAROFF
7385 /*
7386  * Lookup menu handle from "menu_id".
7387  */
7388     static HMENU
7389 tearoff_lookup_menuhandle(
7390     vimmenu_T *menu,
7391     WORD menu_id)
7392 {
7393     for ( ; menu != NULL; menu = menu->next)
7394     {
7395 	if (menu->modes == 0)	/* this menu has just been deleted */
7396 	    continue;
7397 	if (menu_is_separator(menu->dname))
7398 	    continue;
7399 	if ((WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000) == menu_id)
7400 	    return menu->submenu_id;
7401     }
7402     return NULL;
7403 }
7404 
7405 /*
7406  * The callback function for all the modeless dialogs that make up the
7407  * "tearoff menus" Very simple - forward button presses (to fool Vim into
7408  * thinking its menus have been clicked), and go away when closed.
7409  */
7410     static LRESULT CALLBACK
7411 tearoff_callback(
7412     HWND hwnd,
7413     UINT message,
7414     WPARAM wParam,
7415     LPARAM lParam)
7416 {
7417     if (message == WM_INITDIALOG)
7418     {
7419 	SetWindowLongPtr(hwnd, DWLP_USER, (LONG_PTR)lParam);
7420 	return (TRUE);
7421     }
7422 
7423     /* May show the mouse pointer again. */
7424     HandleMouseHide(message, lParam);
7425 
7426     if (message == WM_COMMAND)
7427     {
7428 	if ((WORD)(LOWORD(wParam)) & 0x8000)
7429 	{
7430 	    POINT   mp;
7431 	    RECT    rect;
7432 
7433 	    if (GetCursorPos(&mp) && GetWindowRect(hwnd, &rect))
7434 	    {
7435 		vimmenu_T *menu;
7436 
7437 		menu = (vimmenu_T*)GetWindowLongPtr(hwnd, DWLP_USER);
7438 		(void)TrackPopupMenu(
7439 			 tearoff_lookup_menuhandle(menu, LOWORD(wParam)),
7440 			 TPM_LEFTALIGN | TPM_LEFTBUTTON,
7441 			 (int)rect.right - 8,
7442 			 (int)mp.y,
7443 			 (int)0,	    /*reserved param*/
7444 			 s_hwnd,
7445 			 NULL);
7446 		/*
7447 		 * NOTE: The pop-up menu can eat the mouse up event.
7448 		 * We deal with this in normal.c.
7449 		 */
7450 	    }
7451 	}
7452 	else
7453 	    /* Pass on messages to the main Vim window */
7454 	    PostMessage(s_hwnd, WM_COMMAND, LOWORD(wParam), 0);
7455 	/*
7456 	 * Give main window the focus back: this is so after
7457 	 * choosing a tearoff button you can start typing again
7458 	 * straight away.
7459 	 */
7460 	(void)SetFocus(s_hwnd);
7461 	return TRUE;
7462     }
7463     if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
7464     {
7465 	DestroyWindow(hwnd);
7466 	return TRUE;
7467     }
7468 
7469     /* When moved around, give main window the focus back. */
7470     if (message == WM_EXITSIZEMOVE)
7471 	(void)SetActiveWindow(s_hwnd);
7472 
7473     return FALSE;
7474 }
7475 #endif
7476 
7477 
7478 /*
7479  * Decide whether to use the "new look" (small, non-bold font) or the "old
7480  * look" (big, clanky font) for dialogs, and work out a few values for use
7481  * later accordingly.
7482  */
7483     static void
7484 get_dialog_font_metrics(void)
7485 {
7486     HDC		    hdc;
7487     HFONT	    hfontTools = 0;
7488     DWORD	    dlgFontSize;
7489     SIZE	    size;
7490 #ifdef USE_SYSMENU_FONT
7491     LOGFONT	    lfSysmenu;
7492 #endif
7493 
7494     s_usenewlook = FALSE;
7495 
7496 #ifdef USE_SYSMENU_FONT
7497     if (gui_w32_get_menu_font(&lfSysmenu) == OK)
7498 	hfontTools = CreateFontIndirect(&lfSysmenu);
7499     else
7500 #endif
7501 	hfontTools = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0,
7502 				0, 0, 0, 0, VARIABLE_PITCH , DLG_FONT_NAME);
7503 
7504     if (hfontTools)
7505     {
7506 	hdc = GetDC(s_hwnd);
7507 	SelectObject(hdc, hfontTools);
7508 	/*
7509 	 * GetTextMetrics() doesn't return the right value in
7510 	 * tmAveCharWidth, so we have to figure out the dialog base units
7511 	 * ourselves.
7512 	 */
7513 	GetTextExtentPoint(hdc,
7514 		"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
7515 		52, &size);
7516 	ReleaseDC(s_hwnd, hdc);
7517 
7518 	s_dlgfntwidth = (WORD)((size.cx / 26 + 1) / 2);
7519 	s_dlgfntheight = (WORD)size.cy;
7520 	s_usenewlook = TRUE;
7521     }
7522 
7523     if (!s_usenewlook)
7524     {
7525 	dlgFontSize = GetDialogBaseUnits();	/* fall back to big old system*/
7526 	s_dlgfntwidth = LOWORD(dlgFontSize);
7527 	s_dlgfntheight = HIWORD(dlgFontSize);
7528     }
7529 }
7530 
7531 #if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
7532 /*
7533  * Create a pseudo-"tearoff menu" based on the child
7534  * items of a given menu pointer.
7535  */
7536     static void
7537 gui_mch_tearoff(
7538     char_u	*title,
7539     vimmenu_T	*menu,
7540     int		initX,
7541     int		initY)
7542 {
7543     WORD	*p, *pdlgtemplate, *pnumitems, *ptrueheight;
7544     int		template_len;
7545     int		nchar, textWidth, submenuWidth;
7546     DWORD	lStyle;
7547     DWORD	lExtendedStyle;
7548     WORD	dlgwidth;
7549     WORD	menuID;
7550     vimmenu_T	*pmenu;
7551     vimmenu_T	*top_menu;
7552     vimmenu_T	*the_menu = menu;
7553     HWND	hwnd;
7554     HDC		hdc;
7555     HFONT	font, oldFont;
7556     int		col, spaceWidth, len;
7557     int		columnWidths[2];
7558     char_u	*label, *text;
7559     int		acLen = 0;
7560     int		nameLen;
7561     int		padding0, padding1, padding2 = 0;
7562     int		sepPadding=0;
7563     int		x;
7564     int		y;
7565 #ifdef USE_SYSMENU_FONT
7566     LOGFONT	lfSysmenu;
7567     int		use_lfSysmenu = FALSE;
7568 #endif
7569 
7570     /*
7571      * If this menu is already torn off, move it to the mouse position.
7572      */
7573     if (IsWindow(menu->tearoff_handle))
7574     {
7575 	POINT mp;
7576 	if (GetCursorPos((LPPOINT)&mp))
7577 	{
7578 	    SetWindowPos(menu->tearoff_handle, NULL, mp.x, mp.y, 0, 0,
7579 		    SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
7580 	}
7581 	return;
7582     }
7583 
7584     /*
7585      * Create a new tearoff.
7586      */
7587     if (*title == MNU_HIDDEN_CHAR)
7588 	title++;
7589 
7590     /* Allocate memory to store the dialog template.  It's made bigger when
7591      * needed. */
7592     template_len = DLG_ALLOC_SIZE;
7593     pdlgtemplate = p = (WORD *)LocalAlloc(LPTR, template_len);
7594     if (p == NULL)
7595 	return;
7596 
7597     hwnd = GetDesktopWindow();
7598     hdc = GetWindowDC(hwnd);
7599 #ifdef USE_SYSMENU_FONT
7600     if (gui_w32_get_menu_font(&lfSysmenu) == OK)
7601     {
7602 	font = CreateFontIndirect(&lfSysmenu);
7603 	use_lfSysmenu = TRUE;
7604     }
7605     else
7606 #endif
7607     font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
7608 		      VARIABLE_PITCH , DLG_FONT_NAME);
7609     if (s_usenewlook)
7610 	oldFont = SelectFont(hdc, font);
7611     else
7612 	oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
7613 
7614     /* Calculate width of a single space.  Used for padding columns to the
7615      * right width. */
7616     spaceWidth = GetTextWidth(hdc, (char_u *)" ", 1);
7617 
7618     /* Figure out max width of the text column, the accelerator column and the
7619      * optional submenu column. */
7620     submenuWidth = 0;
7621     for (col = 0; col < 2; col++)
7622     {
7623 	columnWidths[col] = 0;
7624 	for (pmenu = menu->children; pmenu != NULL; pmenu = pmenu->next)
7625 	{
7626 	    /* Use "dname" here to compute the width of the visible text. */
7627 	    text = (col == 0) ? pmenu->dname : pmenu->actext;
7628 	    if (text != NULL && *text != NUL)
7629 	    {
7630 		textWidth = GetTextWidthEnc(hdc, text, (int)STRLEN(text));
7631 		if (textWidth > columnWidths[col])
7632 		    columnWidths[col] = textWidth;
7633 	    }
7634 	    if (pmenu->children != NULL)
7635 		submenuWidth = TEAROFF_COLUMN_PADDING * spaceWidth;
7636 	}
7637     }
7638     if (columnWidths[1] == 0)
7639     {
7640 	/* no accelerators */
7641 	if (submenuWidth != 0)
7642 	    columnWidths[0] += submenuWidth;
7643 	else
7644 	    columnWidths[0] += spaceWidth;
7645     }
7646     else
7647     {
7648 	/* there is an accelerator column */
7649 	columnWidths[0] += TEAROFF_COLUMN_PADDING * spaceWidth;
7650 	columnWidths[1] += submenuWidth;
7651     }
7652 
7653     /*
7654      * Now find the total width of our 'menu'.
7655      */
7656     textWidth = columnWidths[0] + columnWidths[1];
7657     if (submenuWidth != 0)
7658     {
7659 	submenuWidth = GetTextWidth(hdc, (char_u *)TEAROFF_SUBMENU_LABEL,
7660 					  (int)STRLEN(TEAROFF_SUBMENU_LABEL));
7661 	textWidth += submenuWidth;
7662     }
7663     dlgwidth = GetTextWidthEnc(hdc, title, (int)STRLEN(title));
7664     if (textWidth > dlgwidth)
7665 	dlgwidth = textWidth;
7666     dlgwidth += 2 * TEAROFF_PADDING_X + TEAROFF_BUTTON_PAD_X;
7667 
7668     /* start to fill in the dlgtemplate information.  addressing by WORDs */
7669     if (s_usenewlook)
7670 	lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU |DS_SETFONT| WS_VISIBLE;
7671     else
7672 	lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU | WS_VISIBLE;
7673 
7674     lExtendedStyle = WS_EX_TOOLWINDOW|WS_EX_STATICEDGE;
7675     *p++ = LOWORD(lStyle);
7676     *p++ = HIWORD(lStyle);
7677     *p++ = LOWORD(lExtendedStyle);
7678     *p++ = HIWORD(lExtendedStyle);
7679     pnumitems = p;	/* save where the number of items must be stored */
7680     *p++ = 0;		// NumberOfItems(will change later)
7681     gui_mch_getmouse(&x, &y);
7682     if (initX == 0xffffL)
7683 	*p++ = PixelToDialogX(x); // x
7684     else
7685 	*p++ = PixelToDialogX(initX); // x
7686     if (initY == 0xffffL)
7687 	*p++ = PixelToDialogY(y); // y
7688     else
7689 	*p++ = PixelToDialogY(initY); // y
7690     *p++ = PixelToDialogX(dlgwidth);    // cx
7691     ptrueheight = p;
7692     *p++ = 0;		// dialog height: changed later anyway
7693     *p++ = 0;		// Menu
7694     *p++ = 0;		// Class
7695 
7696     /* copy the title of the dialog */
7697     nchar = nCopyAnsiToWideChar(p, ((*title)
7698 			    ? (LPSTR)title
7699 			    : (LPSTR)("Vim "VIM_VERSION_MEDIUM)), TRUE);
7700     p += nchar;
7701 
7702     if (s_usenewlook)
7703     {
7704 	/* do the font, since DS_3DLOOK doesn't work properly */
7705 #ifdef USE_SYSMENU_FONT
7706 	if (use_lfSysmenu)
7707 	{
7708 	    /* point size */
7709 	    *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
7710 		    GetDeviceCaps(hdc, LOGPIXELSY));
7711 	    nchar = nCopyAnsiToWideChar(p, lfSysmenu.lfFaceName, FALSE);
7712 	}
7713 	else
7714 #endif
7715 	{
7716 	    *p++ = DLG_FONT_POINT_SIZE;		// point size
7717 	    nchar = nCopyAnsiToWideChar(p, DLG_FONT_NAME, FALSE);
7718 	}
7719 	p += nchar;
7720     }
7721 
7722     /*
7723      * Loop over all the items in the menu.
7724      * But skip over the tearbar.
7725      */
7726     if (STRCMP(menu->children->name, TEAR_STRING) == 0)
7727 	menu = menu->children->next;
7728     else
7729 	menu = menu->children;
7730     top_menu = menu;
7731     for ( ; menu != NULL; menu = menu->next)
7732     {
7733 	if (menu->modes == 0)	/* this menu has just been deleted */
7734 	    continue;
7735 	if (menu_is_separator(menu->dname))
7736 	{
7737 	    sepPadding += 3;
7738 	    continue;
7739 	}
7740 
7741 	/* Check if there still is plenty of room in the template.  Make it
7742 	 * larger when needed. */
7743 	if (((char *)p - (char *)pdlgtemplate) + 1000 > template_len)
7744 	{
7745 	    WORD    *newp;
7746 
7747 	    newp = (WORD *)LocalAlloc(LPTR, template_len + 4096);
7748 	    if (newp != NULL)
7749 	    {
7750 		template_len += 4096;
7751 		mch_memmove(newp, pdlgtemplate,
7752 					    (char *)p - (char *)pdlgtemplate);
7753 		p = newp + (p - pdlgtemplate);
7754 		pnumitems = newp + (pnumitems - pdlgtemplate);
7755 		ptrueheight = newp + (ptrueheight - pdlgtemplate);
7756 		LocalFree(LocalHandle(pdlgtemplate));
7757 		pdlgtemplate = newp;
7758 	    }
7759 	}
7760 
7761 	/* Figure out minimal length of this menu label.  Use "name" for the
7762 	 * actual text, "dname" for estimating the displayed size.  "name"
7763 	 * has "&a" for mnemonic and includes the accelerator. */
7764 	len = nameLen = (int)STRLEN(menu->name);
7765 	padding0 = (columnWidths[0] - GetTextWidthEnc(hdc, menu->dname,
7766 				      (int)STRLEN(menu->dname))) / spaceWidth;
7767 	len += padding0;
7768 
7769 	if (menu->actext != NULL)
7770 	{
7771 	    acLen = (int)STRLEN(menu->actext);
7772 	    len += acLen;
7773 	    textWidth = GetTextWidthEnc(hdc, menu->actext, acLen);
7774 	}
7775 	else
7776 	    textWidth = 0;
7777 	padding1 = (columnWidths[1] - textWidth) / spaceWidth;
7778 	len += padding1;
7779 
7780 	if (menu->children == NULL)
7781 	{
7782 	    padding2 = submenuWidth / spaceWidth;
7783 	    len += padding2;
7784 	    menuID = (WORD)(menu->id);
7785 	}
7786 	else
7787 	{
7788 	    len += (int)STRLEN(TEAROFF_SUBMENU_LABEL);
7789 	    menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
7790 	}
7791 
7792 	/* Allocate menu label and fill it in */
7793 	text = label = alloc((unsigned)len + 1);
7794 	if (label == NULL)
7795 	    break;
7796 
7797 	vim_strncpy(text, menu->name, nameLen);
7798 	text = vim_strchr(text, TAB);	    /* stop at TAB before actext */
7799 	if (text == NULL)
7800 	    text = label + nameLen;	    /* no actext, use whole name */
7801 	while (padding0-- > 0)
7802 	    *text++ = ' ';
7803 	if (menu->actext != NULL)
7804 	{
7805 	    STRNCPY(text, menu->actext, acLen);
7806 	    text += acLen;
7807 	}
7808 	while (padding1-- > 0)
7809 	    *text++ = ' ';
7810 	if (menu->children != NULL)
7811 	{
7812 	    STRCPY(text, TEAROFF_SUBMENU_LABEL);
7813 	    text += STRLEN(TEAROFF_SUBMENU_LABEL);
7814 	}
7815 	else
7816 	{
7817 	    while (padding2-- > 0)
7818 		*text++ = ' ';
7819 	}
7820 	*text = NUL;
7821 
7822 	/*
7823 	 * BS_LEFT will just be ignored on Win32s/NT3.5x - on
7824 	 * W95/NT4 it makes the tear-off look more like a menu.
7825 	 */
7826 	p = add_dialog_element(p,
7827 		BS_PUSHBUTTON|BS_LEFT,
7828 		(WORD)PixelToDialogX(TEAROFF_PADDING_X),
7829 		(WORD)(sepPadding + 1 + 13 * (*pnumitems)),
7830 		(WORD)PixelToDialogX(dlgwidth - 2 * TEAROFF_PADDING_X),
7831 		(WORD)12,
7832 		menuID, (WORD)0x0080, (char *)label);
7833 	vim_free(label);
7834 	(*pnumitems)++;
7835     }
7836 
7837     *ptrueheight = (WORD)(sepPadding + 1 + 13 * (*pnumitems));
7838 
7839 
7840     /* show modelessly */
7841     the_menu->tearoff_handle = CreateDialogIndirectParam(
7842 	    s_hinst,
7843 	    (LPDLGTEMPLATE)pdlgtemplate,
7844 	    s_hwnd,
7845 	    (DLGPROC)tearoff_callback,
7846 	    (LPARAM)top_menu);
7847 
7848     LocalFree(LocalHandle(pdlgtemplate));
7849     SelectFont(hdc, oldFont);
7850     DeleteObject(font);
7851     ReleaseDC(hwnd, hdc);
7852 
7853     /*
7854      * Reassert ourselves as the active window.  This is so that after creating
7855      * a tearoff, the user doesn't have to click with the mouse just to start
7856      * typing again!
7857      */
7858     (void)SetActiveWindow(s_hwnd);
7859 
7860     /* make sure the right buttons are enabled */
7861     force_menu_update = TRUE;
7862 }
7863 #endif
7864 
7865 #if defined(FEAT_TOOLBAR) || defined(PROTO)
7866 #include "gui_w32_rc.h"
7867 
7868 /* This not defined in older SDKs */
7869 # ifndef TBSTYLE_FLAT
7870 #  define TBSTYLE_FLAT		0x0800
7871 # endif
7872 
7873 /*
7874  * Create the toolbar, initially unpopulated.
7875  *  (just like the menu, there are no defaults, it's all
7876  *  set up through menu.vim)
7877  */
7878     static void
7879 initialise_toolbar(void)
7880 {
7881     InitCommonControls();
7882     s_toolbarhwnd = CreateToolbarEx(
7883 		    s_hwnd,
7884 		    WS_CHILD | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT,
7885 		    4000,		//any old big number
7886 		    31,			//number of images in initial bitmap
7887 		    s_hinst,
7888 		    IDR_TOOLBAR1,	// id of initial bitmap
7889 		    NULL,
7890 		    0,			// initial number of buttons
7891 		    TOOLBAR_BUTTON_WIDTH, //api guide is wrong!
7892 		    TOOLBAR_BUTTON_HEIGHT,
7893 		    TOOLBAR_BUTTON_WIDTH,
7894 		    TOOLBAR_BUTTON_HEIGHT,
7895 		    sizeof(TBBUTTON)
7896 		    );
7897     s_toolbar_wndproc = SubclassWindow(s_toolbarhwnd, toolbar_wndproc);
7898 
7899     gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL);
7900 }
7901 
7902     static LRESULT CALLBACK
7903 toolbar_wndproc(
7904     HWND hwnd,
7905     UINT uMsg,
7906     WPARAM wParam,
7907     LPARAM lParam)
7908 {
7909     HandleMouseHide(uMsg, lParam);
7910     return CallWindowProc(s_toolbar_wndproc, hwnd, uMsg, wParam, lParam);
7911 }
7912 
7913     static int
7914 get_toolbar_bitmap(vimmenu_T *menu)
7915 {
7916     int i = -1;
7917 
7918     /*
7919      * Check user bitmaps first, unless builtin is specified.
7920      */
7921     if (!menu->icon_builtin)
7922     {
7923 	char_u fname[MAXPATHL];
7924 	HANDLE hbitmap = NULL;
7925 
7926 	if (menu->iconfile != NULL)
7927 	{
7928 	    gui_find_iconfile(menu->iconfile, fname, "bmp");
7929 	    hbitmap = LoadImage(
7930 			NULL,
7931 			(LPCSTR)fname,
7932 			IMAGE_BITMAP,
7933 			TOOLBAR_BUTTON_WIDTH,
7934 			TOOLBAR_BUTTON_HEIGHT,
7935 			LR_LOADFROMFILE |
7936 			LR_LOADMAP3DCOLORS
7937 			);
7938 	}
7939 
7940 	/*
7941 	 * If the LoadImage call failed, or the "icon=" file
7942 	 * didn't exist or wasn't specified, try the menu name
7943 	 */
7944 	if (hbitmap == NULL
7945 		&& (gui_find_bitmap(
7946 #ifdef FEAT_MULTI_LANG
7947 			    menu->en_dname != NULL ? menu->en_dname :
7948 #endif
7949 					menu->dname, fname, "bmp") == OK))
7950 	    hbitmap = LoadImage(
7951 		    NULL,
7952 		    (LPCSTR)fname,
7953 		    IMAGE_BITMAP,
7954 		    TOOLBAR_BUTTON_WIDTH,
7955 		    TOOLBAR_BUTTON_HEIGHT,
7956 		    LR_LOADFROMFILE |
7957 		    LR_LOADMAP3DCOLORS
7958 		);
7959 
7960 	if (hbitmap != NULL)
7961 	{
7962 	    TBADDBITMAP tbAddBitmap;
7963 
7964 	    tbAddBitmap.hInst = NULL;
7965 	    tbAddBitmap.nID = (long_u)hbitmap;
7966 
7967 	    i = (int)SendMessage(s_toolbarhwnd, TB_ADDBITMAP,
7968 			    (WPARAM)1, (LPARAM)&tbAddBitmap);
7969 	    /* i will be set to -1 if it fails */
7970 	}
7971     }
7972     if (i == -1 && menu->iconidx >= 0 && menu->iconidx < TOOLBAR_BITMAP_COUNT)
7973 	i = menu->iconidx;
7974 
7975     return i;
7976 }
7977 #endif
7978 
7979 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
7980     static void
7981 initialise_tabline(void)
7982 {
7983     InitCommonControls();
7984 
7985     s_tabhwnd = CreateWindow(WC_TABCONTROL, "Vim tabline",
7986 	    WS_CHILD|TCS_FOCUSNEVER|TCS_TOOLTIPS,
7987 	    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
7988 	    CW_USEDEFAULT, s_hwnd, NULL, s_hinst, NULL);
7989     s_tabline_wndproc = SubclassWindow(s_tabhwnd, tabline_wndproc);
7990 
7991     gui.tabline_height = TABLINE_HEIGHT;
7992 
7993 # ifdef USE_SYSMENU_FONT
7994     set_tabline_font();
7995 # endif
7996 }
7997 
7998 /*
7999  * Get tabpage_T from POINT.
8000  */
8001     static tabpage_T *
8002 GetTabFromPoint(
8003     HWND    hWnd,
8004     POINT   pt)
8005 {
8006     tabpage_T	*ptp = NULL;
8007 
8008     if (gui_mch_showing_tabline())
8009     {
8010 	TCHITTESTINFO htinfo;
8011 	htinfo.pt = pt;
8012 	/* ignore if a window under cusor is not tabcontrol. */
8013 	if (s_tabhwnd == hWnd)
8014 	{
8015 	    int idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
8016 	    if (idx != -1)
8017 		ptp = find_tabpage(idx + 1);
8018 	}
8019     }
8020     return ptp;
8021 }
8022 
8023 static POINT	    s_pt = {0, 0};
8024 static HCURSOR      s_hCursor = NULL;
8025 
8026     static LRESULT CALLBACK
8027 tabline_wndproc(
8028     HWND hwnd,
8029     UINT uMsg,
8030     WPARAM wParam,
8031     LPARAM lParam)
8032 {
8033     POINT	pt;
8034     tabpage_T	*tp;
8035     RECT	rect;
8036     int		nCenter;
8037     int		idx0;
8038     int		idx1;
8039 
8040     HandleMouseHide(uMsg, lParam);
8041 
8042     switch (uMsg)
8043     {
8044 	case WM_LBUTTONDOWN:
8045 	    {
8046 		s_pt.x = GET_X_LPARAM(lParam);
8047 		s_pt.y = GET_Y_LPARAM(lParam);
8048 		SetCapture(hwnd);
8049 		s_hCursor = GetCursor(); /* backup default cursor */
8050 		break;
8051 	    }
8052 	case WM_MOUSEMOVE:
8053 	    if (GetCapture() == hwnd
8054 		    && ((wParam & MK_LBUTTON)) != 0)
8055 	    {
8056 		pt.x = GET_X_LPARAM(lParam);
8057 		pt.y = s_pt.y;
8058 		if (abs(pt.x - s_pt.x) > GetSystemMetrics(SM_CXDRAG))
8059 		{
8060 		    SetCursor(LoadCursor(NULL, IDC_SIZEWE));
8061 
8062 		    tp = GetTabFromPoint(hwnd, pt);
8063 		    if (tp != NULL)
8064 		    {
8065 			idx0 = tabpage_index(curtab) - 1;
8066 			idx1 = tabpage_index(tp) - 1;
8067 
8068 			TabCtrl_GetItemRect(hwnd, idx1, &rect);
8069 			nCenter = rect.left + (rect.right - rect.left) / 2;
8070 
8071 			/* Check if the mouse cursor goes over the center of
8072 			 * the next tab to prevent "flickering". */
8073 			if ((idx0 < idx1) && (nCenter < pt.x))
8074 			{
8075 			    tabpage_move(idx1 + 1);
8076 			    update_screen(0);
8077 			}
8078 			else if ((idx1 < idx0) && (pt.x < nCenter))
8079 			{
8080 			    tabpage_move(idx1);
8081 			    update_screen(0);
8082 			}
8083 		    }
8084 		}
8085 	    }
8086 	    break;
8087 	case WM_LBUTTONUP:
8088 	    {
8089 		if (GetCapture() == hwnd)
8090 		{
8091 		    SetCursor(s_hCursor);
8092 		    ReleaseCapture();
8093 		}
8094 		break;
8095 	    }
8096 	default:
8097 	    break;
8098     }
8099 
8100     return CallWindowProc(s_tabline_wndproc, hwnd, uMsg, wParam, lParam);
8101 }
8102 #endif
8103 
8104 #if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
8105 /*
8106  * Make the GUI window come to the foreground.
8107  */
8108     void
8109 gui_mch_set_foreground(void)
8110 {
8111     if (IsIconic(s_hwnd))
8112 	 SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
8113     SetForegroundWindow(s_hwnd);
8114 }
8115 #endif
8116 
8117 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
8118     static void
8119 dyn_imm_load(void)
8120 {
8121     hLibImm = vimLoadLib("imm32.dll");
8122     if (hLibImm == NULL)
8123 	return;
8124 
8125     pImmGetCompositionStringA
8126 	    = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringA");
8127     pImmGetCompositionStringW
8128 	    = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringW");
8129     pImmGetContext
8130 	    = (void *)GetProcAddress(hLibImm, "ImmGetContext");
8131     pImmAssociateContext
8132 	    = (void *)GetProcAddress(hLibImm, "ImmAssociateContext");
8133     pImmReleaseContext
8134 	    = (void *)GetProcAddress(hLibImm, "ImmReleaseContext");
8135     pImmGetOpenStatus
8136 	    = (void *)GetProcAddress(hLibImm, "ImmGetOpenStatus");
8137     pImmSetOpenStatus
8138 	    = (void *)GetProcAddress(hLibImm, "ImmSetOpenStatus");
8139     pImmGetCompositionFont
8140 	    = (void *)GetProcAddress(hLibImm, "ImmGetCompositionFontA");
8141     pImmSetCompositionFont
8142 	    = (void *)GetProcAddress(hLibImm, "ImmSetCompositionFontA");
8143     pImmSetCompositionWindow
8144 	    = (void *)GetProcAddress(hLibImm, "ImmSetCompositionWindow");
8145     pImmGetConversionStatus
8146 	    = (void *)GetProcAddress(hLibImm, "ImmGetConversionStatus");
8147     pImmSetConversionStatus
8148 	    = (void *)GetProcAddress(hLibImm, "ImmSetConversionStatus");
8149 
8150     if (       pImmGetCompositionStringA == NULL
8151 	    || pImmGetCompositionStringW == NULL
8152 	    || pImmGetContext == NULL
8153 	    || pImmAssociateContext == NULL
8154 	    || pImmReleaseContext == NULL
8155 	    || pImmGetOpenStatus == NULL
8156 	    || pImmSetOpenStatus == NULL
8157 	    || pImmGetCompositionFont == NULL
8158 	    || pImmSetCompositionFont == NULL
8159 	    || pImmSetCompositionWindow == NULL
8160 	    || pImmGetConversionStatus == NULL
8161 	    || pImmSetConversionStatus == NULL)
8162     {
8163 	FreeLibrary(hLibImm);
8164 	hLibImm = NULL;
8165 	pImmGetContext = NULL;
8166 	return;
8167     }
8168 
8169     return;
8170 }
8171 
8172 #endif
8173 
8174 #if defined(FEAT_SIGN_ICONS) || defined(PROTO)
8175 
8176 # ifdef FEAT_XPM_W32
8177 #  define IMAGE_XPM   100
8178 # endif
8179 
8180 typedef struct _signicon_t
8181 {
8182     HANDLE	hImage;
8183     UINT	uType;
8184 #ifdef FEAT_XPM_W32
8185     HANDLE	hShape;	/* Mask bitmap handle */
8186 #endif
8187 } signicon_t;
8188 
8189     void
8190 gui_mch_drawsign(int row, int col, int typenr)
8191 {
8192     signicon_t *sign;
8193     int x, y, w, h;
8194 
8195     if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
8196 	return;
8197 
8198 #if defined(FEAT_DIRECTX)
8199     if (IS_ENABLE_DIRECTX())
8200 	DWriteContext_Flush(s_dwc);
8201 #endif
8202 
8203     x = TEXT_X(col);
8204     y = TEXT_Y(row);
8205     w = gui.char_width * 2;
8206     h = gui.char_height;
8207     switch (sign->uType)
8208     {
8209 	case IMAGE_BITMAP:
8210 	    {
8211 		HDC hdcMem;
8212 		HBITMAP hbmpOld;
8213 
8214 		hdcMem = CreateCompatibleDC(s_hdc);
8215 		hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hImage);
8216 		BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCCOPY);
8217 		SelectObject(hdcMem, hbmpOld);
8218 		DeleteDC(hdcMem);
8219 	    }
8220 	    break;
8221 	case IMAGE_ICON:
8222 	case IMAGE_CURSOR:
8223 	    DrawIconEx(s_hdc, x, y, (HICON)sign->hImage, w, h, 0, NULL, DI_NORMAL);
8224 	    break;
8225 #ifdef FEAT_XPM_W32
8226 	case IMAGE_XPM:
8227 	    {
8228 		HDC hdcMem;
8229 		HBITMAP hbmpOld;
8230 
8231 		hdcMem = CreateCompatibleDC(s_hdc);
8232 		hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hShape);
8233 		/* Make hole */
8234 		BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCAND);
8235 
8236 		SelectObject(hdcMem, sign->hImage);
8237 		/* Paint sign */
8238 		BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCPAINT);
8239 		SelectObject(hdcMem, hbmpOld);
8240 		DeleteDC(hdcMem);
8241 	    }
8242 	    break;
8243 #endif
8244     }
8245 }
8246 
8247     static void
8248 close_signicon_image(signicon_t *sign)
8249 {
8250     if (sign)
8251 	switch (sign->uType)
8252 	{
8253 	    case IMAGE_BITMAP:
8254 		DeleteObject((HGDIOBJ)sign->hImage);
8255 		break;
8256 	    case IMAGE_CURSOR:
8257 		DestroyCursor((HCURSOR)sign->hImage);
8258 		break;
8259 	    case IMAGE_ICON:
8260 		DestroyIcon((HICON)sign->hImage);
8261 		break;
8262 #ifdef FEAT_XPM_W32
8263 	    case IMAGE_XPM:
8264 		DeleteObject((HBITMAP)sign->hImage);
8265 		DeleteObject((HBITMAP)sign->hShape);
8266 		break;
8267 #endif
8268 	}
8269 }
8270 
8271     void *
8272 gui_mch_register_sign(char_u *signfile)
8273 {
8274     signicon_t	sign, *psign;
8275     char_u	*ext;
8276 
8277     sign.hImage = NULL;
8278     ext = signfile + STRLEN(signfile) - 4; /* get extension */
8279     if (ext > signfile)
8280     {
8281 	int do_load = 1;
8282 
8283 	if (!STRICMP(ext, ".bmp"))
8284 	    sign.uType =  IMAGE_BITMAP;
8285 	else if (!STRICMP(ext, ".ico"))
8286 	    sign.uType =  IMAGE_ICON;
8287 	else if (!STRICMP(ext, ".cur") || !STRICMP(ext, ".ani"))
8288 	    sign.uType =  IMAGE_CURSOR;
8289 	else
8290 	    do_load = 0;
8291 
8292 	if (do_load)
8293 	    sign.hImage = (HANDLE)LoadImage(NULL, (LPCSTR)signfile, sign.uType,
8294 		    gui.char_width * 2, gui.char_height,
8295 		    LR_LOADFROMFILE | LR_CREATEDIBSECTION);
8296 #ifdef FEAT_XPM_W32
8297 	if (!STRICMP(ext, ".xpm"))
8298 	{
8299 	    sign.uType = IMAGE_XPM;
8300 	    LoadXpmImage((char *)signfile, (HBITMAP *)&sign.hImage,
8301 		    (HBITMAP *)&sign.hShape);
8302 	}
8303 #endif
8304     }
8305 
8306     psign = NULL;
8307     if (sign.hImage && (psign = (signicon_t *)alloc(sizeof(signicon_t)))
8308 								      != NULL)
8309 	*psign = sign;
8310 
8311     if (!psign)
8312     {
8313 	if (sign.hImage)
8314 	    close_signicon_image(&sign);
8315 	emsg(_(e_signdata));
8316     }
8317     return (void *)psign;
8318 
8319 }
8320 
8321     void
8322 gui_mch_destroy_sign(void *sign)
8323 {
8324     if (sign)
8325     {
8326 	close_signicon_image((signicon_t *)sign);
8327 	vim_free(sign);
8328     }
8329 }
8330 #endif
8331 
8332 #if defined(FEAT_BEVAL_GUI) || defined(PROTO)
8333 
8334 /* BALLOON-EVAL IMPLEMENTATION FOR WINDOWS.
8335  *  Added by Sergey Khorev <[email protected]>
8336  *
8337  * The only reused thing is beval.h and get_beval_info()
8338  * from gui_beval.c (note it uses x and y of the BalloonEval struct
8339  * to get current mouse position).
8340  *
8341  * Trying to use as more Windows services as possible, and as less
8342  * IE version as possible :)).
8343  *
8344  * 1) Don't create ToolTip in gui_mch_create_beval_area, only initialize
8345  * BalloonEval struct.
8346  * 2) Enable/Disable simply create/kill BalloonEval Timer
8347  * 3) When there was enough inactivity, timer procedure posts
8348  * async request to debugger
8349  * 4) gui_mch_post_balloon (invoked from netbeans.c) creates tooltip control
8350  * and performs some actions to show it ASAP
8351  * 5) WM_NOTIFY:TTN_POP destroys created tooltip
8352  */
8353 
8354 /*
8355  * determine whether installed Common Controls support multiline tooltips
8356  * (i.e. their version is >= 4.70
8357  */
8358     int
8359 multiline_balloon_available(void)
8360 {
8361     HINSTANCE hDll;
8362     static char comctl_dll[] = "comctl32.dll";
8363     static int multiline_tip = MAYBE;
8364 
8365     if (multiline_tip != MAYBE)
8366 	return multiline_tip;
8367 
8368     hDll = GetModuleHandle(comctl_dll);
8369     if (hDll != NULL)
8370     {
8371 	DLLGETVERSIONPROC pGetVer;
8372 	pGetVer = (DLLGETVERSIONPROC)GetProcAddress(hDll, "DllGetVersion");
8373 
8374 	if (pGetVer != NULL)
8375 	{
8376 	    DLLVERSIONINFO dvi;
8377 	    HRESULT hr;
8378 
8379 	    ZeroMemory(&dvi, sizeof(dvi));
8380 	    dvi.cbSize = sizeof(dvi);
8381 
8382 	    hr = (*pGetVer)(&dvi);
8383 
8384 	    if (SUCCEEDED(hr)
8385 		    && (dvi.dwMajorVersion > 4
8386 			|| (dvi.dwMajorVersion == 4
8387 						&& dvi.dwMinorVersion >= 70)))
8388 	    {
8389 		multiline_tip = TRUE;
8390 		return multiline_tip;
8391 	    }
8392 	}
8393 	else
8394 	{
8395 	    /* there is chance we have ancient CommCtl 4.70
8396 	       which doesn't export DllGetVersion */
8397 	    DWORD dwHandle = 0;
8398 	    DWORD len = GetFileVersionInfoSize(comctl_dll, &dwHandle);
8399 	    if (len > 0)
8400 	    {
8401 		VS_FIXEDFILEINFO *ver;
8402 		UINT vlen = 0;
8403 		void *data = alloc(len);
8404 
8405 		if ((data != NULL
8406 			&& GetFileVersionInfo(comctl_dll, 0, len, data)
8407 			&& VerQueryValue(data, "\\", (void **)&ver, &vlen)
8408 			&& vlen
8409 			&& HIWORD(ver->dwFileVersionMS) > 4)
8410 			|| ((HIWORD(ver->dwFileVersionMS) == 4
8411 			    && LOWORD(ver->dwFileVersionMS) >= 70)))
8412 		{
8413 		    vim_free(data);
8414 		    multiline_tip = TRUE;
8415 		    return multiline_tip;
8416 		}
8417 		vim_free(data);
8418 	    }
8419 	}
8420     }
8421     multiline_tip = FALSE;
8422     return multiline_tip;
8423 }
8424 
8425     static void
8426 make_tooltipw(BalloonEval *beval, char *text, POINT pt)
8427 {
8428     TOOLINFOW	*pti;
8429     int		ToolInfoSize;
8430 
8431     if (multiline_balloon_available() == TRUE)
8432 	ToolInfoSize = sizeof(TOOLINFOW_NEW);
8433     else
8434 	ToolInfoSize = sizeof(TOOLINFOW);
8435 
8436     pti = (TOOLINFOW *)alloc(ToolInfoSize);
8437     if (pti == NULL)
8438 	return;
8439 
8440     beval->balloon = CreateWindowExW(WS_EX_TOPMOST, TOOLTIPS_CLASSW,
8441 	    NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
8442 	    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
8443 	    beval->target, NULL, s_hinst, NULL);
8444 
8445     SetWindowPos(beval->balloon, HWND_TOPMOST, 0, 0, 0, 0,
8446 	    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
8447 
8448     pti->cbSize = ToolInfoSize;
8449     pti->uFlags = TTF_SUBCLASS;
8450     pti->hwnd = beval->target;
8451     pti->hinst = 0; // Don't use string resources
8452     pti->uId = ID_BEVAL_TOOLTIP;
8453 
8454     if (multiline_balloon_available() == TRUE)
8455     {
8456 	RECT rect;
8457 	TOOLINFOW_NEW *ptin = (TOOLINFOW_NEW *)pti;
8458 	pti->lpszText = LPSTR_TEXTCALLBACKW;
8459 	beval->tofree = enc_to_utf16((char_u*)text, NULL);
8460 	ptin->lParam = (LPARAM)beval->tofree;
8461 	// switch multiline tooltips on
8462 	if (GetClientRect(s_textArea, &rect))
8463 	    SendMessageW(beval->balloon, TTM_SETMAXTIPWIDTH, 0,
8464 		    (LPARAM)rect.right);
8465     }
8466     else
8467     {
8468 	// do this old way
8469 	beval->tofree = enc_to_utf16((char_u*)text, NULL);
8470 	pti->lpszText = (LPWSTR)beval->tofree;
8471     }
8472 
8473     // Limit ballooneval bounding rect to CursorPos neighbourhood.
8474     pti->rect.left = pt.x - 3;
8475     pti->rect.top = pt.y - 3;
8476     pti->rect.right = pt.x + 3;
8477     pti->rect.bottom = pt.y + 3;
8478 
8479     SendMessageW(beval->balloon, TTM_ADDTOOLW, 0, (LPARAM)pti);
8480     // Make tooltip appear sooner.
8481     SendMessageW(beval->balloon, TTM_SETDELAYTIME, TTDT_INITIAL, 10);
8482     // I've performed some tests and it seems the longest possible life time
8483     // of tooltip is 30 seconds.
8484     SendMessageW(beval->balloon, TTM_SETDELAYTIME, TTDT_AUTOPOP, 30000);
8485     /*
8486      * HACK: force tooltip to appear, because it'll not appear until
8487      * first mouse move. D*mn M$
8488      * Amazingly moving (2, 2) and then (-1, -1) the mouse doesn't move.
8489      */
8490     mouse_event(MOUSEEVENTF_MOVE, 2, 2, 0, 0);
8491     mouse_event(MOUSEEVENTF_MOVE, (DWORD)-1, (DWORD)-1, 0, 0);
8492     vim_free(pti);
8493 }
8494 
8495     static void
8496 make_tooltip(BalloonEval *beval, char *text, POINT pt)
8497 {
8498     TOOLINFO	*pti;
8499     int		ToolInfoSize;
8500 
8501     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
8502     {
8503 	make_tooltipw(beval, text, pt);
8504 	return;
8505     }
8506 
8507     if (multiline_balloon_available() == TRUE)
8508 	ToolInfoSize = sizeof(TOOLINFO_NEW);
8509     else
8510 	ToolInfoSize = sizeof(TOOLINFO);
8511 
8512     pti = (TOOLINFO *)alloc(ToolInfoSize);
8513     if (pti == NULL)
8514 	return;
8515 
8516     beval->balloon = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS,
8517 	    NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
8518 	    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
8519 	    beval->target, NULL, s_hinst, NULL);
8520 
8521     SetWindowPos(beval->balloon, HWND_TOPMOST, 0, 0, 0, 0,
8522 	    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
8523 
8524     pti->cbSize = ToolInfoSize;
8525     pti->uFlags = TTF_SUBCLASS;
8526     pti->hwnd = beval->target;
8527     pti->hinst = 0; /* Don't use string resources */
8528     pti->uId = ID_BEVAL_TOOLTIP;
8529 
8530     if (multiline_balloon_available() == TRUE)
8531     {
8532 	RECT rect;
8533 	TOOLINFO_NEW *ptin = (TOOLINFO_NEW *)pti;
8534 	pti->lpszText = LPSTR_TEXTCALLBACK;
8535 	beval->tofree = vim_strsave((char_u*)text);
8536 	ptin->lParam = (LPARAM)beval->tofree;
8537 	if (GetClientRect(s_textArea, &rect)) /* switch multiline tooltips on */
8538 	    SendMessage(beval->balloon, TTM_SETMAXTIPWIDTH, 0,
8539 		    (LPARAM)rect.right);
8540     }
8541     else
8542 	pti->lpszText = text; /* do this old way */
8543 
8544     /* Limit ballooneval bounding rect to CursorPos neighbourhood */
8545     pti->rect.left = pt.x - 3;
8546     pti->rect.top = pt.y - 3;
8547     pti->rect.right = pt.x + 3;
8548     pti->rect.bottom = pt.y + 3;
8549 
8550     SendMessage(beval->balloon, TTM_ADDTOOL, 0, (LPARAM)pti);
8551     /* Make tooltip appear sooner */
8552     SendMessage(beval->balloon, TTM_SETDELAYTIME, TTDT_INITIAL, 10);
8553     /* I've performed some tests and it seems the longest possible life time
8554      * of tooltip is 30 seconds */
8555     SendMessage(beval->balloon, TTM_SETDELAYTIME, TTDT_AUTOPOP, 30000);
8556     /*
8557      * HACK: force tooltip to appear, because it'll not appear until
8558      * first mouse move. D*mn M$
8559      * Amazingly moving (2, 2) and then (-1, -1) the mouse doesn't move.
8560      */
8561     mouse_event(MOUSEEVENTF_MOVE, 2, 2, 0, 0);
8562     mouse_event(MOUSEEVENTF_MOVE, (DWORD)-1, (DWORD)-1, 0, 0);
8563     vim_free(pti);
8564 }
8565 
8566     static void
8567 delete_tooltip(BalloonEval *beval)
8568 {
8569     PostMessage(beval->balloon, WM_CLOSE, 0, 0);
8570 }
8571 
8572     static VOID CALLBACK
8573 BevalTimerProc(
8574     HWND	hwnd UNUSED,
8575     UINT	uMsg UNUSED,
8576     UINT_PTR    idEvent UNUSED,
8577     DWORD	dwTime)
8578 {
8579     POINT	pt;
8580     RECT	rect;
8581 
8582     if (cur_beval == NULL || cur_beval->showState == ShS_SHOWING || !p_beval)
8583 	return;
8584 
8585     GetCursorPos(&pt);
8586     if (WindowFromPoint(pt) != s_textArea)
8587 	return;
8588 
8589     ScreenToClient(s_textArea, &pt);
8590     GetClientRect(s_textArea, &rect);
8591     if (!PtInRect(&rect, pt))
8592 	return;
8593 
8594     if (LastActivity > 0
8595 	    && (dwTime - LastActivity) >= (DWORD)p_bdlay
8596 	    && (cur_beval->showState != ShS_PENDING
8597 		|| abs(cur_beval->x - pt.x) > 3
8598 		|| abs(cur_beval->y - pt.y) > 3))
8599     {
8600 	/* Pointer resting in one place long enough, it's time to show
8601 	 * the tooltip. */
8602 	cur_beval->showState = ShS_PENDING;
8603 	cur_beval->x = pt.x;
8604 	cur_beval->y = pt.y;
8605 
8606 	// TRACE0("BevalTimerProc: sending request");
8607 
8608 	if (cur_beval->msgCB != NULL)
8609 	    (*cur_beval->msgCB)(cur_beval, 0);
8610     }
8611 }
8612 
8613     void
8614 gui_mch_disable_beval_area(BalloonEval *beval UNUSED)
8615 {
8616     // TRACE0("gui_mch_disable_beval_area {{{");
8617     KillTimer(s_textArea, BevalTimerId);
8618     // TRACE0("gui_mch_disable_beval_area }}}");
8619 }
8620 
8621     void
8622 gui_mch_enable_beval_area(BalloonEval *beval)
8623 {
8624     // TRACE0("gui_mch_enable_beval_area |||");
8625     if (beval == NULL)
8626 	return;
8627     // TRACE0("gui_mch_enable_beval_area {{{");
8628     BevalTimerId = SetTimer(s_textArea, 0, (UINT)(p_bdlay / 2), BevalTimerProc);
8629     // TRACE0("gui_mch_enable_beval_area }}}");
8630 }
8631 
8632     void
8633 gui_mch_post_balloon(BalloonEval *beval, char_u *mesg)
8634 {
8635     POINT   pt;
8636 
8637     // TRACE0("gui_mch_post_balloon {{{");
8638     if (beval->showState == ShS_SHOWING)
8639 	return;
8640     GetCursorPos(&pt);
8641     ScreenToClient(s_textArea, &pt);
8642 
8643     if (abs(beval->x - pt.x) < 3 && abs(beval->y - pt.y) < 3)
8644     {
8645 	/* cursor is still here */
8646 	gui_mch_disable_beval_area(cur_beval);
8647 	beval->showState = ShS_SHOWING;
8648 	make_tooltip(beval, (char *)mesg, pt);
8649     }
8650     // TRACE0("gui_mch_post_balloon }}}");
8651 }
8652 
8653     BalloonEval *
8654 gui_mch_create_beval_area(
8655     void	*target,	/* ignored, always use s_textArea */
8656     char_u	*mesg,
8657     void	(*mesgCB)(BalloonEval *, int),
8658     void	*clientData)
8659 {
8660     /* partially stolen from gui_beval.c */
8661     BalloonEval	*beval;
8662 
8663     if (mesg != NULL && mesgCB != NULL)
8664     {
8665 	iemsg(_("E232: Cannot create BalloonEval with both message and callback"));
8666 	return NULL;
8667     }
8668 
8669     beval = (BalloonEval *)alloc_clear(sizeof(BalloonEval));
8670     if (beval != NULL)
8671     {
8672 	beval->target = s_textArea;
8673 
8674 	beval->showState = ShS_NEUTRAL;
8675 	beval->msg = mesg;
8676 	beval->msgCB = mesgCB;
8677 	beval->clientData = clientData;
8678 
8679 	InitCommonControls();
8680 	cur_beval = beval;
8681 
8682 	if (p_beval)
8683 	    gui_mch_enable_beval_area(beval);
8684     }
8685     return beval;
8686 }
8687 
8688     static void
8689 Handle_WM_Notify(HWND hwnd UNUSED, LPNMHDR pnmh)
8690 {
8691     if (pnmh->idFrom != ID_BEVAL_TOOLTIP) /* it is not our tooltip */
8692 	return;
8693 
8694     if (cur_beval != NULL)
8695     {
8696 	switch (pnmh->code)
8697 	{
8698 	case TTN_SHOW:
8699 	    // TRACE0("TTN_SHOW {{{");
8700 	    // TRACE0("TTN_SHOW }}}");
8701 	    break;
8702 	case TTN_POP: /* Before tooltip disappear */
8703 	    // TRACE0("TTN_POP {{{");
8704 	    delete_tooltip(cur_beval);
8705 	    gui_mch_enable_beval_area(cur_beval);
8706 	    // TRACE0("TTN_POP }}}");
8707 
8708 	    cur_beval->showState = ShS_NEUTRAL;
8709 	    break;
8710 	case TTN_GETDISPINFO:
8711 	    {
8712 		/* if you get there then we have new common controls */
8713 		NMTTDISPINFO_NEW *info = (NMTTDISPINFO_NEW *)pnmh;
8714 		info->lpszText = (LPSTR)info->lParam;
8715 		info->uFlags |= TTF_DI_SETITEM;
8716 	    }
8717 	    break;
8718 	case TTN_GETDISPINFOW:
8719 	    {
8720 		// if we get here then we have new common controls
8721 		NMTTDISPINFOW_NEW *info = (NMTTDISPINFOW_NEW *)pnmh;
8722 		info->lpszText = (LPWSTR)info->lParam;
8723 		info->uFlags |= TTF_DI_SETITEM;
8724 	    }
8725 	    break;
8726 	}
8727     }
8728 }
8729 
8730     static void
8731 TrackUserActivity(UINT uMsg)
8732 {
8733     if ((uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
8734 	    || (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST))
8735 	LastActivity = GetTickCount();
8736 }
8737 
8738     void
8739 gui_mch_destroy_beval_area(BalloonEval *beval)
8740 {
8741 #ifdef FEAT_VARTABS
8742     vim_free(beval->vts);
8743 #endif
8744     vim_free(beval->tofree);
8745     vim_free(beval);
8746 }
8747 #endif /* FEAT_BEVAL_GUI */
8748 
8749 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
8750 /*
8751  * We have multiple signs to draw at the same location. Draw the
8752  * multi-sign indicator (down-arrow) instead. This is the Win32 version.
8753  */
8754     void
8755 netbeans_draw_multisign_indicator(int row)
8756 {
8757     int i;
8758     int y;
8759     int x;
8760 
8761     if (!netbeans_active())
8762 	return;
8763 
8764     x = 0;
8765     y = TEXT_Y(row);
8766 
8767 #if defined(FEAT_DIRECTX)
8768     if (IS_ENABLE_DIRECTX())
8769 	DWriteContext_Flush(s_dwc);
8770 #endif
8771 
8772     for (i = 0; i < gui.char_height - 3; i++)
8773 	SetPixel(s_hdc, x+2, y++, gui.currFgColor);
8774 
8775     SetPixel(s_hdc, x+0, y, gui.currFgColor);
8776     SetPixel(s_hdc, x+2, y, gui.currFgColor);
8777     SetPixel(s_hdc, x+4, y++, gui.currFgColor);
8778     SetPixel(s_hdc, x+1, y, gui.currFgColor);
8779     SetPixel(s_hdc, x+2, y, gui.currFgColor);
8780     SetPixel(s_hdc, x+3, y++, gui.currFgColor);
8781     SetPixel(s_hdc, x+2, y, gui.currFgColor);
8782 }
8783 #endif
8784