1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI support by Robert Webb
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.
11 * gui_w48.c: This file is included in gui_w16.c and gui_w32.c.
13 * GUI support for Microsoft Windows (Win16 + Win32 = Win48 :-)
15 * The combined efforts of:
16 * George V. Reilly <george@reilly.org>
19 * ...and contributions from many others
24 #include "version.h" /* used by dialog box routine for default title */
29 # include <shellapi.h>
31 #if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL) || defined(FEAT_GUI_TABLINE)
32 # include <commctrl.h>
36 # include <shellapi.h>
44 # include "glbl_ime.h"
48 # define MENUHINTS /* show menu hints in command line */
51 /* Some parameters for dialog boxes. All in pixels. */
52 #define DLG_PADDING_X 10
53 #define DLG_PADDING_Y 10
54 #define DLG_OLD_STYLE_PADDING_X 5
55 #define DLG_OLD_STYLE_PADDING_Y 5
56 #define DLG_VERT_PADDING_X 4 /* For vertical buttons */
57 #define DLG_VERT_PADDING_Y 4
58 #define DLG_ICON_WIDTH 34
59 #define DLG_ICON_HEIGHT 34
60 #define DLG_MIN_WIDTH 150
61 #define DLG_FONT_NAME "MS Sans Serif"
62 #define DLG_FONT_POINT_SIZE 8
63 #define DLG_MIN_MAX_WIDTH 400
64 #define DLG_MIN_MAX_HEIGHT 400
66 #define DLG_NONBUTTON_CONTROL 5000 /* First ID of non-button controls */
68 #ifndef WM_XBUTTONDOWN /* For Win2K / winME ONLY */
69 # define WM_XBUTTONDOWN 0x020B
70 # define WM_XBUTTONUP 0x020C
71 # define WM_XBUTTONDBLCLK 0x020D
72 # define MK_XBUTTON1 0x0020
73 # define MK_XBUTTON2 0x0040
78 * Define a few things for generating prototypes. This is just to avoid
79 * syntax errors, the defines do not need to be correct.
91 typedef int ENUMLOGFONT
;
92 typedef int FINDREPLACE
;
98 typedef int LOGFONT
[];
100 typedef int LPCREATESTRUCT
;
105 typedef int LPWINDOWPOS
;
111 typedef int NEWTEXTMETRIC
;
112 typedef int OSVERSIONINFO
;
119 typedef void *HINSTANCE
;
129 # define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
132 static void _OnPaint( HWND hwnd
);
133 static void clear_rect(RECT
*rcp
);
134 static int gui_mswin_get_menu_height(int fix_window
);
136 static WORD s_dlgfntheight
; /* height of the dialog font */
137 static WORD s_dlgfntwidth
; /* width of the dialog font */
140 static HMENU s_menuBar
= NULL
;
143 static void rebuild_tearoff(vimmenu_T
*menu
);
144 static HBITMAP s_htearbitmap
; /* bitmap used to indicate tearoff */
147 /* Flag that is set while processing a message that must not be interrupted by
148 * processing another message. */
149 static int s_busy_processing
= FALSE
;
151 static int destroying
= FALSE
; /* call DestroyWindow() ourselves */
153 #ifdef MSWIN_FIND_REPLACE
154 static UINT s_findrep_msg
= 0; /* set in gui_w[16/32].c */
155 static FINDREPLACE s_findrep_struct
;
156 static HWND s_findrep_hwnd
= NULL
;
157 static int s_findrep_is_find
; /* TRUE for find dialog, FALSE
158 for find/replace dialog */
161 static HINSTANCE s_hinst
= NULL
;
162 #if !defined(FEAT_SNIFF) && !defined(FEAT_GUI)
166 static HDC s_hdc
= NULL
;
167 static HBRUSH s_brush
= NULL
;
170 static HWND s_toolbarhwnd
= NULL
;
173 #ifdef FEAT_GUI_TABLINE
174 static HWND s_tabhwnd
= NULL
;
175 static int showing_tabline
= 0;
178 static WPARAM s_wParam
= 0;
179 static LPARAM s_lParam
= 0;
181 static HWND s_textArea
= NULL
;
182 static UINT s_uMsg
= 0;
184 static char_u
*s_textfield
; /* Used by dialogs to pass back strings */
186 static int s_need_activate
= FALSE
;
188 /* This variable is set when waiting for an event, which is the only moment
189 * scrollbar dragging can be done directly. It's not allowed while commands
190 * are executed, because it may move the cursor and that may cause unexpected
191 * problems (e.g., while ":s" is working).
193 static int allow_scrollbar
= FALSE
;
196 # define MyTranslateMessage(x) global_ime_TranslateMessage(x)
198 # define MyTranslateMessage(x) TranslateMessage(x)
201 #if (defined(WIN3264) && defined(FEAT_MBYTE)) || defined(GLOBAL_IME)
202 /* use of WindowProc depends on wide_WindowProc */
203 # define MyWindowProc vim_WindowProc
205 /* use ordinary WindowProc */
206 # define MyWindowProc DefWindowProc
209 extern int current_font_height
; /* this is in os_mswin.c */
221 {VK_RIGHT
, 'k', 'r'},
246 #ifdef FEAT_NETBEANS_INTG
247 {VK_PAUSE
, 'F', 'B'}, /* Pause == F21 (see gui_gtk_x11.c) */
251 {VK_F24
, 'F', 'E'}, /* winuser.h defines up to F24 */
255 {VK_INSERT
, 'k', 'I'},
256 {VK_DELETE
, 'k', 'D'},
259 {VK_PRIOR
, 'k', 'P'},
261 {VK_PRINT
, '%', '9'},
263 {VK_SUBTRACT
, 'K', '7'},
264 {VK_DIVIDE
, 'K', '8'},
265 {VK_MULTIPLY
, 'K', '9'},
266 {VK_SEPARATOR
, 'K', 'A'}, /* Keypad Enter */
267 {VK_DECIMAL
, 'K', 'B'},
269 {VK_NUMPAD0
, 'K', 'C'},
270 {VK_NUMPAD1
, 'K', 'D'},
271 {VK_NUMPAD2
, 'K', 'E'},
272 {VK_NUMPAD3
, 'K', 'F'},
273 {VK_NUMPAD4
, 'K', 'G'},
274 {VK_NUMPAD5
, 'K', 'H'},
275 {VK_NUMPAD6
, 'K', 'I'},
276 {VK_NUMPAD7
, 'K', 'J'},
277 {VK_NUMPAD8
, 'K', 'K'},
278 {VK_NUMPAD9
, 'K', 'L'},
280 /* Keys that we want to be able to use any modifier with: */
281 {VK_SPACE
, ' ', NUL
},
283 {VK_ESCAPE
, ESC
, NUL
},
287 /* End of list marker: */
291 /* Local variables */
292 static int s_button_pending
= -1;
294 /* s_getting_focus is set when we got focus but didn't see mouse-up event yet,
295 * so don't reset s_button_pending. */
296 static int s_getting_focus
= FALSE
;
298 static int s_x_pending
;
299 static int s_y_pending
;
300 static UINT s_kFlags_pending
;
301 static UINT s_wait_timer
= 0; /* Timer for get char from user */
302 static int s_timed_out
= FALSE
;
303 static int dead_key
= 0; /* 0 - no dead key, 1 - dead key pressed */
306 static OSVERSIONINFO os_version
; /* like it says. Init in gui_mch_init() */
310 /* balloon-eval WM_NOTIFY_HANDLER */
311 static void Handle_WM_Notify
__ARGS((HWND hwnd
, LPNMHDR pnmh
));
312 static void TrackUserActivity
__ARGS((UINT uMsg
));
319 # ifdef USE_IM_CONTROL
320 static LOGFONT norm_logfont
;
324 #ifdef FEAT_MBYTE_IME
325 static LRESULT
_OnImeNotify(HWND hWnd
, DWORD dwCommand
, DWORD dwData
);
328 #ifdef DEBUG_PRINT_ERROR
330 * Print out the last Windows error message
333 print_windows_error(void)
337 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
338 NULL
, GetLastError(),
339 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
340 (LPTSTR
) &lpMsgBuf
, 0, NULL
);
341 TRACE1("Error: %s\n", lpMsgBuf
);
347 * Cursor blink functions.
349 * This is a simple state machine:
350 * BLINK_NONE not blinking at all
351 * BLINK_OFF blinking, cursor is not shown
352 * BLINK_ON blinking, cursor is shown
359 static int blink_state
= BLINK_NONE
;
360 static long_u blink_waittime
= 700;
361 static long_u blink_ontime
= 400;
362 static long_u blink_offtime
= 250;
363 static UINT blink_timer
= 0;
366 gui_mch_set_blinking(long wait
, long on
, long off
)
368 blink_waittime
= wait
;
384 TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
387 KillTimer(NULL
, idEvent
);
389 /* Eat spurious WM_TIMER messages */
390 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
393 if (blink_state
== BLINK_ON
)
396 blink_state
= BLINK_OFF
;
397 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_offtime
,
398 (TIMERPROC
)_OnBlinkTimer
);
402 gui_update_cursor(TRUE
, FALSE
);
403 blink_state
= BLINK_ON
;
404 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_ontime
,
405 (TIMERPROC
)_OnBlinkTimer
);
410 gui_mswin_rm_blink_timer(void)
414 if (blink_timer
!= 0)
416 KillTimer(NULL
, blink_timer
);
417 /* Eat spurious WM_TIMER messages */
418 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
425 * Stop the cursor blinking. Show the cursor if it wasn't shown.
428 gui_mch_stop_blink(void)
430 gui_mswin_rm_blink_timer();
431 if (blink_state
== BLINK_OFF
)
432 gui_update_cursor(TRUE
, FALSE
);
433 blink_state
= BLINK_NONE
;
437 * Start the cursor blinking. If it was already blinking, this restarts the
438 * waiting time and shows the cursor.
441 gui_mch_start_blink(void)
443 gui_mswin_rm_blink_timer();
445 /* Only switch blinking on if none of the times is zero */
446 if (blink_waittime
&& blink_ontime
&& blink_offtime
&& gui
.in_focus
)
448 blink_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)blink_waittime
,
449 (TIMERPROC
)_OnBlinkTimer
);
450 blink_state
= BLINK_ON
;
451 gui_update_cursor(TRUE
, FALSE
);
456 * Call-back routines.
470 TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
472 KillTimer(NULL
, idEvent
);
475 /* Eat spurious WM_TIMER messages */
476 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
478 if (idEvent
== s_wait_timer
)
493 * Convert Unicode character "ch" to bytes in "string[slen]".
494 * When "had_alt" is TRUE the ALT key was included in "ch".
498 char_to_string(int ch
, char_u
*string
, int slen
, int had_alt
)
506 if (os_version
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
)
508 /* On Windows 95/98 we apparently get the character in the active
509 * codepage, not in UCS-2. If conversion is needed convert it to
511 if ((int)GetACP() == enc_codepage
)
512 len
= 0; /* no conversion required */
516 len
= MultiByteToWideChar(GetACP(), 0, string
, 1, wstring
, 2);
527 /* "ch" is a UTF-16 character. Convert it to a string of bytes. When
528 * "enc_codepage" is non-zero use the standard Win32 function,
529 * otherwise use our own conversion function (e.g., for UTF-8). */
530 if (enc_codepage
> 0)
532 len
= WideCharToMultiByte(enc_codepage
, 0, wstring
, len
,
533 string
, slen
, 0, NULL
);
534 /* If we had included the ALT key into the character but now the
535 * upper bit is no longer set, that probably means the conversion
536 * failed. Convert the original character and set the upper bit
538 if (had_alt
&& len
== 1 && ch
>= 0x80 && string
[0] < 0x80)
540 wstring
[0] = ch
& 0x7f;
541 len
= WideCharToMultiByte(enc_codepage
, 0, wstring
, len
,
542 string
, slen
, 0, NULL
);
543 if (len
== 1) /* safety check */
550 ws
= ucs2_to_enc(wstring
, &len
);
555 if (len
> slen
) /* just in case */
557 mch_memmove(string
, ws
, len
);
570 for (i
= 0; i
< len
; ++i
)
571 if (string
[i
] == CSI
&& len
<= slen
- 2)
573 /* Insert CSI as K_CSI. */
574 mch_memmove(string
+ i
+ 3, string
+ i
+ 1, len
- i
- 1);
575 string
[++i
] = KS_EXTRA
;
576 string
[++i
] = (int)KE_CSI
;
584 * Key hit, add it to the input buffer.
596 len
= char_to_string(ch
, string
, 40, FALSE
);
597 if (len
== 1 && string
[0] == Ctrl_C
&& ctrl_c_interrupts
)
603 add_to_input_buf(string
, len
);
607 * Alt-Key hit, add it to the input buffer.
616 char_u string
[40]; /* Enough for multibyte character */
619 int ch
= cch
; /* special keys are negative */
621 /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
623 /* OK, we have a character key (given by ch) which was entered with the
624 * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
625 * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
626 * CAPSLOCK is pressed) at this point.
628 modifiers
= MOD_MASK_ALT
;
629 if (GetKeyState(VK_SHIFT
) & 0x8000)
630 modifiers
|= MOD_MASK_SHIFT
;
631 if (GetKeyState(VK_CONTROL
) & 0x8000)
632 modifiers
|= MOD_MASK_CTRL
;
634 ch
= simplify_key(ch
, &modifiers
);
635 /* remove the SHIFT modifier for keys where it's already included, e.g.,
637 if (ch
< 0x100 && !isalpha(ch
) && isprint(ch
))
638 modifiers
&= ~MOD_MASK_SHIFT
;
640 /* Interpret the ALT key as making the key META, include SHIFT, etc. */
641 ch
= extract_modifiers(ch
, &modifiers
);
649 string
[len
++] = KS_MODIFIER
;
650 string
[len
++] = modifiers
;
653 if (IS_SPECIAL((int)ch
))
656 string
[len
++] = K_SECOND((int)ch
);
657 string
[len
++] = K_THIRD((int)ch
);
661 /* Although the documentation isn't clear about it, we assume "ch" is
662 * a Unicode character. */
663 len
+= char_to_string(ch
, string
+ len
, 40 - len
, TRUE
);
666 add_to_input_buf(string
, len
);
677 int vim_modifiers
= 0x0;
679 s_getting_focus
= FALSE
;
681 if (keyFlags
& MK_SHIFT
)
682 vim_modifiers
|= MOUSE_SHIFT
;
683 if (keyFlags
& MK_CONTROL
)
684 vim_modifiers
|= MOUSE_CTRL
;
685 if (GetKeyState(VK_MENU
) & 0x8000)
686 vim_modifiers
|= MOUSE_ALT
;
688 gui_send_mouse_event(button
, x
, y
, repeated_click
, vim_modifiers
);
700 static LONG s_prevTime
= 0;
702 LONG currentTime
= GetMessageTime();
706 /* Give main window the focus: this is so the cursor isn't hollow. */
707 (void)SetFocus(s_hwnd
);
709 if (s_uMsg
== WM_LBUTTONDOWN
|| s_uMsg
== WM_LBUTTONDBLCLK
)
711 else if (s_uMsg
== WM_MBUTTONDOWN
|| s_uMsg
== WM_MBUTTONDBLCLK
)
712 button
= MOUSE_MIDDLE
;
713 else if (s_uMsg
== WM_RBUTTONDOWN
|| s_uMsg
== WM_RBUTTONDBLCLK
)
714 button
= MOUSE_RIGHT
;
715 #ifndef WIN16 /*<VN>*/
716 else if (s_uMsg
== WM_XBUTTONDOWN
|| s_uMsg
== WM_XBUTTONDBLCLK
)
718 #ifndef GET_XBUTTON_WPARAM
719 # define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
721 button
= ((GET_XBUTTON_WPARAM(s_wParam
) == 1) ? MOUSE_X1
: MOUSE_X2
);
723 else if (s_uMsg
== WM_CAPTURECHANGED
)
725 /* on W95/NT4, somehow you get in here with an odd Msg
726 * if you press one button while holding down the other..*/
727 if (s_button_pending
== MOUSE_LEFT
)
728 button
= MOUSE_RIGHT
;
735 repeated_click
= ((int)(currentTime
- s_prevTime
) < p_mouset
);
738 * Holding down the left and right buttons simulates pushing the middle
742 && ((button
== MOUSE_LEFT
&& s_button_pending
== MOUSE_RIGHT
)
743 || (button
== MOUSE_RIGHT
744 && s_button_pending
== MOUSE_LEFT
)))
747 * Hmm, gui.c will ignore more than one button down at a time, so
748 * pretend we let go of it first.
750 gui_send_mouse_event(MOUSE_RELEASE
, x
, y
, FALSE
, 0x0);
751 button
= MOUSE_MIDDLE
;
752 repeated_click
= FALSE
;
753 s_button_pending
= -1;
754 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
756 else if ((repeated_click
)
757 || (mouse_model_popup() && (button
== MOUSE_RIGHT
)))
759 if (s_button_pending
> -1)
761 _OnMouseEvent(s_button_pending
, x
, y
, FALSE
, keyFlags
);
762 s_button_pending
= -1;
764 /* TRACE("Button down at x %d, y %d\n", x, y); */
765 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
770 * If this is the first press (i.e. not a multiple click) don't
771 * action immediately, but store and wait for:
774 * iii) another button press
776 * This enables us to make left+right simulate middle button,
777 * without left or right being actioned first. The side-effect is
778 * that if you click and hold the mouse without dragging, the
779 * cursor doesn't move until you release the button. In practice
780 * this is hardly a problem.
782 s_button_pending
= button
;
785 s_kFlags_pending
= keyFlags
;
788 s_prevTime
= currentTime
;
794 _OnMouseMoveOrRelease(
802 s_getting_focus
= FALSE
;
803 if (s_button_pending
> -1)
805 /* Delayed action for mouse down event */
806 _OnMouseEvent(s_button_pending
, s_x_pending
,
807 s_y_pending
, FALSE
, s_kFlags_pending
);
808 s_button_pending
= -1;
810 if (s_uMsg
== WM_MOUSEMOVE
)
813 * It's only a MOUSE_DRAG if one or more mouse buttons are being held
816 if (!(keyFlags
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
817 | MK_XBUTTON1
| MK_XBUTTON2
)))
819 gui_mouse_moved(x
, y
);
824 * While button is down, keep grabbing mouse move events when
825 * the mouse goes outside the window
827 SetCapture(s_textArea
);
829 /* TRACE(" move at x %d, y %d\n", x, y); */
834 button
= MOUSE_RELEASE
;
835 /* TRACE(" up at x %d, y %d\n", x, y); */
838 _OnMouseEvent(button
, x
, y
, FALSE
, keyFlags
);
843 * Find the vimmenu_T with the given id
850 vimmenu_T
*pChildMenu
;
854 if (pMenu
->id
== (UINT
)id
)
856 if (pMenu
->children
!= NULL
)
858 pChildMenu
= gui_mswin_find_menu(pMenu
->children
, id
);
880 pMenu
= gui_mswin_find_menu(root_menu
, id
);
886 #ifdef MSWIN_FIND_REPLACE
888 * Handle a Find/Replace window message.
896 if (s_findrep_struct
.Flags
& FR_DIALOGTERM
)
897 /* Give main window the focus back. */
898 (void)SetFocus(s_hwnd
);
900 if (s_findrep_struct
.Flags
& FR_FINDNEXT
)
902 flags
= FRD_FINDNEXT
;
904 /* Give main window the focus back: this is so the cursor isn't
906 (void)SetFocus(s_hwnd
);
908 else if (s_findrep_struct
.Flags
& FR_REPLACE
)
912 /* Give main window the focus back: this is so the cursor isn't
914 (void)SetFocus(s_hwnd
);
916 else if (s_findrep_struct
.Flags
& FR_REPLACEALL
)
918 flags
= FRD_REPLACEALL
;
923 /* Call the generic GUI function to do the actual work. */
924 if (s_findrep_struct
.Flags
& FR_WHOLEWORD
)
925 flags
|= FRD_WHOLE_WORD
;
926 if (s_findrep_struct
.Flags
& FR_MATCHCASE
)
927 flags
|= FRD_MATCH_CASE
;
928 down
= (s_findrep_struct
.Flags
& FR_DOWN
) != 0;
929 gui_do_findrepl(flags
, s_findrep_struct
.lpstrFindWhat
,
930 s_findrep_struct
.lpstrReplaceWith
, down
);
936 HandleMouseHide(UINT uMsg
, LPARAM lParam
)
938 static LPARAM last_lParam
= 0L;
940 /* We sometimes get a mousemove when the mouse didn't move... */
941 if (uMsg
== WM_MOUSEMOVE
)
943 if (lParam
== last_lParam
)
945 last_lParam
= lParam
;
948 /* Handle specially, to centralise coding. We need to be sure we catch all
949 * possible events which should cause us to restore the cursor (as it is a
950 * shared resource, we take full responsibility for it).
957 * blank out the pointer if necessary
960 gui_mch_mousehide(TRUE
);
963 case WM_SYSKEYUP
: /* show the pointer when a system-key is pressed */
965 case WM_MOUSEMOVE
: /* show the pointer on any mouse action */
975 case WM_NCLBUTTONDOWN
:
977 case WM_NCMBUTTONDOWN
:
979 case WM_NCRBUTTONDOWN
:
983 * if the pointer is currently hidden, then we should show it.
985 gui_mch_mousehide(FALSE
);
990 static LRESULT CALLBACK
998 TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
999 hwnd, uMsg, wParam, lParam);
1002 HandleMouseHide(uMsg
, lParam
);
1009 TrackUserActivity(uMsg
);
1014 HANDLE_MSG(hwnd
, WM_LBUTTONDBLCLK
,_OnMouseButtonDown
);
1015 HANDLE_MSG(hwnd
, WM_LBUTTONDOWN
,_OnMouseButtonDown
);
1016 HANDLE_MSG(hwnd
, WM_LBUTTONUP
, _OnMouseMoveOrRelease
);
1017 HANDLE_MSG(hwnd
, WM_MBUTTONDBLCLK
,_OnMouseButtonDown
);
1018 HANDLE_MSG(hwnd
, WM_MBUTTONDOWN
,_OnMouseButtonDown
);
1019 HANDLE_MSG(hwnd
, WM_MBUTTONUP
, _OnMouseMoveOrRelease
);
1020 HANDLE_MSG(hwnd
, WM_MOUSEMOVE
, _OnMouseMoveOrRelease
);
1021 HANDLE_MSG(hwnd
, WM_PAINT
, _OnPaint
);
1022 HANDLE_MSG(hwnd
, WM_RBUTTONDBLCLK
,_OnMouseButtonDown
);
1023 HANDLE_MSG(hwnd
, WM_RBUTTONDOWN
,_OnMouseButtonDown
);
1024 HANDLE_MSG(hwnd
, WM_RBUTTONUP
, _OnMouseMoveOrRelease
);
1025 #ifndef WIN16 /*<VN>*/
1026 HANDLE_MSG(hwnd
, WM_XBUTTONDBLCLK
,_OnMouseButtonDown
);
1027 HANDLE_MSG(hwnd
, WM_XBUTTONDOWN
,_OnMouseButtonDown
);
1028 HANDLE_MSG(hwnd
, WM_XBUTTONUP
, _OnMouseMoveOrRelease
);
1032 case WM_NOTIFY
: Handle_WM_Notify(hwnd
, (LPNMHDR
)lParam
);
1037 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1041 #if (defined(WIN3264) && defined(FEAT_MBYTE)) \
1042 || defined(GLOBAL_IME) \
1049 vim_WindowProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1052 return global_ime_DefWindowProc(hwnd
, message
, wParam
, lParam
);
1054 if (wide_WindowProc
)
1055 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
1056 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1062 * Called when the foreground or background color has been changed.
1065 gui_mch_new_colors(void)
1067 /* nothing to do? */
1071 * Set the colors to their default values.
1074 gui_mch_def_colors()
1076 gui
.norm_pixel
= GetSysColor(COLOR_WINDOWTEXT
);
1077 gui
.back_pixel
= GetSysColor(COLOR_WINDOW
);
1078 gui
.def_norm_pixel
= gui
.norm_pixel
;
1079 gui
.def_back_pixel
= gui
.back_pixel
;
1083 * Open the GUI window which was created by a call to gui_mch_init().
1088 #ifndef SW_SHOWDEFAULT
1089 # define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
1091 /* Actually open the window, if not already visible
1092 * (may be done already in gui_mch_set_shellsize) */
1093 if (!IsWindowVisible(s_hwnd
))
1094 ShowWindow(s_hwnd
, SW_SHOWDEFAULT
);
1096 #ifdef MSWIN_FIND_REPLACE
1097 /* Init replace string here, so that we keep it when re-opening the
1099 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1106 * Get the position of the top left corner of the window.
1109 gui_mch_get_winpos(int *x
, int *y
)
1113 GetWindowRect(s_hwnd
, &rect
);
1120 * Set the position of the top left corner of the window to the given
1124 gui_mch_set_winpos(int x
, int y
)
1126 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1127 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1130 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
1132 static int oldx
= 0;
1133 static int oldy
= 0;
1135 SetWindowPos(s_textArea
, NULL
, x
, y
, w
, h
, SWP_NOZORDER
| SWP_NOACTIVATE
);
1138 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1139 SendMessage(s_toolbarhwnd
, WM_SIZE
,
1140 (WPARAM
)0, (LPARAM
)(w
+ ((long)(TOOLBAR_BUTTON_HEIGHT
+8)<<16)));
1142 #if defined(FEAT_GUI_TABLINE)
1143 if (showing_tabline
)
1148 # ifdef FEAT_TOOLBAR
1149 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1150 top
= TOOLBAR_BUTTON_HEIGHT
+ TOOLBAR_BORDER_HEIGHT
;
1152 GetClientRect(s_hwnd
, &rect
);
1153 MoveWindow(s_tabhwnd
, 0, top
, rect
.right
, gui
.tabline_height
, TRUE
);
1157 /* When side scroll bar is unshown, the size of window will change.
1158 * then, the text area move left or right. thus client rect should be
1159 * forcely redraw. (Yasuhiro Matsumoto) */
1160 if (oldx
!= x
|| oldy
!= y
)
1162 InvalidateRect(s_hwnd
, NULL
, FALSE
);
1174 gui_mch_enable_scrollbar(
1178 ShowScrollBar(sb
->id
, SB_CTL
, flag
);
1180 /* TODO: When the window is maximized, the size of the window stays the
1181 * same, thus the size of the text area changes. On Win98 it's OK, on Win
1182 * NT 4.0 it's not... */
1186 gui_mch_set_scrollbar_pos(
1193 SetWindowPos(sb
->id
, NULL
, x
, y
, w
, h
,
1194 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1198 gui_mch_create_scrollbar(
1200 int orient
) /* SBAR_VERT or SBAR_HORIZ */
1202 sb
->id
= CreateWindow(
1203 "SCROLLBAR", "Scrollbar",
1204 WS_CHILD
| ((orient
== SBAR_VERT
) ? SBS_VERT
: SBS_HORZ
), 0, 0,
1205 10, /* Any value will do for now */
1206 10, /* Any value will do for now */
1212 * Find the scrollbar with the given hwnd.
1214 static scrollbar_T
*
1215 gui_mswin_find_scrollbar(HWND hwnd
)
1219 if (gui
.bottom_sbar
.id
== hwnd
)
1220 return &gui
.bottom_sbar
;
1223 if (wp
->w_scrollbars
[SBAR_LEFT
].id
== hwnd
)
1224 return &wp
->w_scrollbars
[SBAR_LEFT
];
1225 if (wp
->w_scrollbars
[SBAR_RIGHT
].id
== hwnd
)
1226 return &wp
->w_scrollbars
[SBAR_RIGHT
];
1232 * Get the character size of a font.
1235 GetFontSize(GuiFont font
)
1237 HWND hwnd
= GetDesktopWindow();
1238 HDC hdc
= GetWindowDC(hwnd
);
1239 HFONT hfntOld
= SelectFont(hdc
, (HFONT
)font
);
1242 GetTextMetrics(hdc
, &tm
);
1243 gui
.char_width
= tm
.tmAveCharWidth
+ tm
.tmOverhang
;
1245 gui
.char_height
= tm
.tmHeight
1246 #ifndef MSWIN16_FASTTEXT
1251 SelectFont(hdc
, hfntOld
);
1253 ReleaseDC(hwnd
, hdc
);
1257 * Adjust gui.char_height (after 'linespace' was changed).
1260 gui_mch_adjust_charheight(void)
1262 GetFontSize(gui
.norm_font
);
1267 get_font_handle(LOGFONT
*lf
)
1272 font
= CreateFontIndirect(lf
);
1277 return (GuiFont
)font
;
1281 pixels_to_points(int pixels
, int vertical
)
1287 hwnd
= GetDesktopWindow();
1288 hdc
= GetWindowDC(hwnd
);
1290 points
= MulDiv(pixels
, 72,
1291 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
));
1293 ReleaseDC(hwnd
, hdc
);
1301 int giveErrorIfMissing
)
1304 GuiFont font
= NOFONT
;
1306 if (get_logfont(&lf
, name
, NULL
, giveErrorIfMissing
) == OK
)
1307 font
= get_font_handle(&lf
);
1308 if (font
== NOFONT
&& giveErrorIfMissing
)
1309 EMSG2(_(e_font
), name
);
1313 #if defined(FEAT_EVAL) || defined(PROTO)
1315 * Return the name of font "font" in allocated memory.
1316 * Don't know how to get the actual name, thus use the provided name.
1320 gui_mch_get_fontname(font
, name
)
1326 return vim_strsave(name
);
1331 gui_mch_free_font(GuiFont font
)
1334 DeleteObject((HFONT
)font
);
1343 if (c
>= 'a' && c
<= 'f')
1344 return c
- 'a' + 10;
1348 * Return the Pixel value (color) for the given color name.
1349 * Return INVALCOLOR for error.
1352 gui_mch_get_color(char_u
*name
)
1354 typedef struct guicolor_tTable
1360 static guicolor_tTable table
[] =
1362 {"Black", RGB(0x00, 0x00, 0x00)},
1363 {"DarkGray", RGB(0x80, 0x80, 0x80)},
1364 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
1365 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
1366 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
1367 {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
1368 {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
1369 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
1370 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
1371 {"Gray20", RGB(0x33, 0x33, 0x33)},
1372 {"Grey20", RGB(0x33, 0x33, 0x33)},
1373 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
1374 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
1375 {"Gray40", RGB(0x66, 0x66, 0x66)},
1376 {"Grey40", RGB(0x66, 0x66, 0x66)},
1377 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
1378 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
1379 {"Gray60", RGB(0x99, 0x99, 0x99)},
1380 {"Grey60", RGB(0x99, 0x99, 0x99)},
1381 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
1382 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
1383 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
1384 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
1385 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
1386 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
1387 {"White", RGB(0xFF, 0xFF, 0xFF)},
1388 {"DarkRed", RGB(0x80, 0x00, 0x00)},
1389 {"Red", RGB(0xFF, 0x00, 0x00)},
1390 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
1391 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
1392 {"Blue", RGB(0x00, 0x00, 0xFF)},
1393 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
1394 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
1395 {"Green", RGB(0x00, 0xFF, 0x00)},
1396 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
1397 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
1398 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
1399 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
1400 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
1401 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
1402 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
1403 {"Brown", RGB(0x80, 0x40, 0x40)},
1404 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
1405 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
1406 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
1407 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
1408 {"Orange", RGB(0xFF, 0xA5, 0x00)},
1409 {"Purple", RGB(0xA0, 0x20, 0xF0)},
1410 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
1411 {"Violet", RGB(0xEE, 0x82, 0xEE)},
1414 typedef struct SysColorTable
1420 static SysColorTable sys_table
[] =
1423 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW
},
1424 {"SYS_3DHILIGHT", COLOR_3DHILIGHT
},
1426 {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT
},
1428 {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT
},
1429 {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT
},
1430 {"SYS_3DLIGHT", COLOR_3DLIGHT
},
1431 {"SYS_3DSHADOW", COLOR_3DSHADOW
},
1432 {"SYS_DESKTOP", COLOR_DESKTOP
},
1433 {"SYS_INFOBK", COLOR_INFOBK
},
1434 {"SYS_INFOTEXT", COLOR_INFOTEXT
},
1435 {"SYS_3DFACE", COLOR_3DFACE
},
1437 {"SYS_BTNFACE", COLOR_BTNFACE
},
1438 {"SYS_BTNSHADOW", COLOR_BTNSHADOW
},
1439 {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER
},
1440 {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION
},
1441 {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE
},
1442 {"SYS_BACKGROUND", COLOR_BACKGROUND
},
1443 {"SYS_BTNTEXT", COLOR_BTNTEXT
},
1444 {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT
},
1445 {"SYS_GRAYTEXT", COLOR_GRAYTEXT
},
1446 {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT
},
1447 {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT
},
1448 {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER
},
1449 {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION
},
1450 {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT
},
1451 {"SYS_MENU", COLOR_MENU
},
1452 {"SYS_MENUTEXT", COLOR_MENUTEXT
},
1453 {"SYS_SCROLLBAR", COLOR_SCROLLBAR
},
1454 {"SYS_WINDOW", COLOR_WINDOW
},
1455 {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME
},
1456 {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT
}
1462 if (name
[0] == '#' && strlen(name
) == 7)
1464 /* Name is in "#rrggbb" format */
1465 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
1466 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
1467 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
1468 if (r
< 0 || g
< 0 || b
< 0)
1470 return RGB(r
, g
, b
);
1474 /* Check if the name is one of the colors we know */
1475 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
1476 if (STRICMP(name
, table
[i
].name
) == 0)
1477 return table
[i
].color
;
1481 * Try to look up a system colour.
1483 for (i
= 0; i
< sizeof(sys_table
) / sizeof(sys_table
[0]); i
++)
1484 if (STRICMP(name
, sys_table
[i
].name
) == 0)
1485 return GetSysColor(sys_table
[i
].color
);
1488 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
1491 #define LINE_LEN 100
1493 char line
[LINE_LEN
];
1496 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
1500 fd
= mch_fopen((char *)fname
, "rt");
1511 fgets(line
, LINE_LEN
, fd
);
1512 len
= (int)STRLEN(line
);
1514 if (len
<= 1 || line
[len
-1] != '\n')
1519 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
1525 if (STRICMP(color
, name
) == 0)
1528 return (guicolor_T
) RGB(r
, g
, b
);
1538 * Return OK if the key with the termcap name "name" is supported.
1541 gui_mch_haskey(char_u
*name
)
1545 for (i
= 0; special_keys
[i
].vim_code1
!= NUL
; i
++)
1546 if (name
[0] == special_keys
[i
].vim_code0
&&
1547 name
[1] == special_keys
[i
].vim_code1
)
1558 * Invert a rectangle from row r, column c, for nr rows and nc columns.
1561 gui_mch_invert_rectangle(
1570 * Note: InvertRect() excludes right and bottom of rectangle.
1572 rc
.left
= FILL_X(c
);
1574 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
1575 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
1576 InvertRect(s_hdc
, &rc
);
1580 * Iconify the GUI window.
1583 gui_mch_iconify(void)
1585 ShowWindow(s_hwnd
, SW_MINIMIZE
);
1589 * Draw a cursor without focus.
1592 gui_mch_draw_hollow_cursor(guicolor_T color
)
1598 * Note: FrameRect() excludes right and bottom of rectangle.
1600 rc
.left
= FILL_X(gui
.col
);
1601 rc
.top
= FILL_Y(gui
.row
);
1602 rc
.right
= rc
.left
+ gui
.char_width
;
1604 if (mb_lefthalve(gui
.row
, gui
.col
))
1605 rc
.right
+= gui
.char_width
;
1607 rc
.bottom
= rc
.top
+ gui
.char_height
;
1608 hbr
= CreateSolidBrush(color
);
1609 FrameRect(s_hdc
, &rc
, hbr
);
1613 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1617 gui_mch_draw_part_cursor(
1626 * Note: FillRect() excludes right and bottom of rectangle.
1629 #ifdef FEAT_RIGHTLEFT
1630 /* vertical line should be on the right of current point */
1631 CURSOR_BAR_RIGHT
? FILL_X(gui
.col
+ 1) - w
:
1634 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
1635 rc
.right
= rc
.left
+ w
;
1636 rc
.bottom
= rc
.top
+ h
;
1637 hbr
= CreateSolidBrush(color
);
1638 FillRect(s_hdc
, &rc
, hbr
);
1643 * Process a single Windows message.
1644 * If one is not available we hang until one is.
1647 process_message(void)
1650 UINT vk
= 0; /* Virtual key */
1656 static char_u k10
[] = {K_SPECIAL
, 'k', ';', 0};
1659 GetMessage(&msg
, NULL
, 0, 0);
1662 /* Look after OLE Automation commands */
1663 if (msg
.message
== WM_OLE
)
1665 char_u
*str
= (char_u
*)msg
.lParam
;
1666 add_to_input_buf(str
, (int)STRLEN(str
));
1672 #ifdef FEAT_NETBEANS_INTG
1673 if (msg
.message
== WM_NETBEANS
)
1675 messageFromNetbeansW32();
1681 if (sniff_request_waiting
&& want_sniff_request
)
1683 static char_u bytes
[3] = {CSI
, (char_u
)KS_EXTRA
, (char_u
)KE_SNIFF
};
1684 add_to_input_buf(bytes
, 3); /* K_SNIFF */
1685 sniff_request_waiting
= 0;
1686 want_sniff_request
= 0;
1687 /* request is handled in normal.c */
1689 if (msg
.message
== WM_USER
)
1691 MyTranslateMessage(&msg
);
1692 DispatchMessage(&msg
);
1697 #ifdef MSWIN_FIND_REPLACE
1698 /* Don't process messages used by the dialog */
1699 if (s_findrep_hwnd
!= NULL
&& IsDialogMessage(s_findrep_hwnd
, &msg
))
1701 HandleMouseHide(msg
.message
, msg
.lParam
);
1707 * Check if it's a special key that we recognise. If not, call
1708 * TranslateMessage().
1710 if (msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_SYSKEYDOWN
)
1712 vk
= (int) msg
.wParam
;
1713 /* handle key after dead key, but ignore shift, alt and control */
1714 if (dead_key
&& vk
!= VK_SHIFT
&& vk
!= VK_MENU
&& vk
!= VK_CONTROL
)
1717 /* handle non-alphabetic keys (ones that hopefully cannot generate
1718 * umlaut-characters), unless when control is down */
1719 if (vk
< 'A' || vk
> 'Z' || (GetKeyState(VK_CONTROL
) & 0x8000))
1723 dm
.message
= msg
.message
;
1725 dm
.wParam
= VK_SPACE
;
1726 MyTranslateMessage(&dm
); /* generate dead character */
1727 if (vk
!= VK_SPACE
) /* and send current character once more */
1728 PostMessage(msg
.hwnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
1733 /* Check for CTRL-BREAK */
1734 if (vk
== VK_CANCEL
)
1739 add_to_input_buf(string
, 1);
1742 for (i
= 0; special_keys
[i
].key_sym
!= 0; i
++)
1744 /* ignore VK_SPACE when ALT key pressed: system menu */
1745 if (special_keys
[i
].key_sym
== vk
1746 && (vk
!= VK_SPACE
|| !(GetKeyState(VK_MENU
) & 0x8000)))
1749 /* Check for <F10>: Windows selects the menu. When <F10> is
1750 * mapped we want to use the mapping instead. */
1752 && gui
.menu_is_active
1753 && check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1756 if (GetKeyState(VK_SHIFT
) & 0x8000)
1757 modifiers
|= MOD_MASK_SHIFT
;
1759 * Don't use caps-lock as shift, because these are special keys
1760 * being considered here, and we only want letters to get
1764 if (GetKeyState(VK_CAPITAL) & 0x0001)
1765 modifiers ^= MOD_MASK_SHIFT;
1767 if (GetKeyState(VK_CONTROL
) & 0x8000)
1768 modifiers
|= MOD_MASK_CTRL
;
1769 if (GetKeyState(VK_MENU
) & 0x8000)
1770 modifiers
|= MOD_MASK_ALT
;
1772 if (special_keys
[i
].vim_code1
== NUL
)
1773 key
= special_keys
[i
].vim_code0
;
1775 key
= TO_SPECIAL(special_keys
[i
].vim_code0
,
1776 special_keys
[i
].vim_code1
);
1777 key
= simplify_key(key
, &modifiers
);
1784 string
[1] = KS_MODIFIER
;
1785 string
[2] = modifiers
;
1786 add_to_input_buf(string
, 3);
1789 if (IS_SPECIAL(key
))
1792 string
[1] = K_SECOND(key
);
1793 string
[2] = K_THIRD(key
);
1794 add_to_input_buf(string
, 3);
1800 /* Handle "key" as a Unicode character. */
1801 len
= char_to_string(key
, string
, 40, FALSE
);
1802 add_to_input_buf(string
, len
);
1807 if (special_keys
[i
].key_sym
== 0)
1809 /* Some keys need C-S- where they should only need C-.
1810 * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1811 * system startup (Helmut Stiegler, 2003 Oct 3). */
1813 && (GetKeyState(VK_CONTROL
) & 0x8000)
1814 && !(GetKeyState(VK_SHIFT
) & 0x8000)
1815 && !(GetKeyState(VK_MENU
) & 0x8000))
1817 /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1818 if (vk
== '6' || MapVirtualKey(vk
, 2) == (UINT
)'^')
1820 string
[0] = Ctrl_HAT
;
1821 add_to_input_buf(string
, 1);
1823 /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
1824 else if (vk
== 0xBD) /* QWERTY for CTRL-'-' */
1827 add_to_input_buf(string
, 1);
1829 /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
1830 else if (vk
== '2' || MapVirtualKey(vk
, 2) == (UINT
)'@')
1832 string
[0] = Ctrl_AT
;
1833 add_to_input_buf(string
, 1);
1836 MyTranslateMessage(&msg
);
1839 MyTranslateMessage(&msg
);
1842 #ifdef FEAT_MBYTE_IME
1843 else if (msg
.message
== WM_IME_NOTIFY
)
1844 _OnImeNotify(msg
.hwnd
, (DWORD
)msg
.wParam
, (DWORD
)msg
.lParam
);
1845 else if (msg
.message
== WM_KEYUP
&& im_get_status())
1846 /* added for non-MS IME (Yasuhiro Matsumoto) */
1847 MyTranslateMessage(&msg
);
1849 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
1851 else if (msg
.message
== WM_IME_STARTCOMPOSITION
)
1855 global_ime_set_font(&norm_logfont
);
1856 point
.x
= FILL_X(gui
.col
);
1857 point
.y
= FILL_Y(gui
.row
);
1858 MapWindowPoints(s_textArea
, s_hwnd
, &point
, 1);
1859 global_ime_set_position(&point
);
1864 /* Check for <F10>: Default effect is to select the menu. When <F10> is
1865 * mapped we need to stop it here to avoid strange effects (e.g., for the
1867 if (vk
!= VK_F10
|| check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1869 DispatchMessage(&msg
);
1873 * Catch up with any queued events. This may put keyboard input into the
1874 * input buffer, call resize call-backs, trigger timers etc. If there is
1875 * nothing in the event queue (& no timers pending), then we return
1879 gui_mch_update(void)
1883 if (!s_busy_processing
)
1884 while (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
)
1885 && !vim_is_input_buf_full())
1890 * GUI input routine called by gui_wait_for_chars(). Waits for a character
1891 * from the keyboard.
1892 * wtime == -1 Wait forever.
1893 * wtime == 0 This should never happen.
1894 * wtime > 0 Wait wtime milliseconds for a character.
1895 * Returns OK if a character was found to be available within the given time,
1896 * or FAIL otherwise.
1899 gui_mch_wait_for_chars(int wtime
)
1904 s_timed_out
= FALSE
;
1908 /* Don't do anything while processing a (scroll) message. */
1909 if (s_busy_processing
)
1911 s_wait_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)wtime
,
1912 (TIMERPROC
)_OnTimer
);
1915 allow_scrollbar
= TRUE
;
1917 focus
= gui
.in_focus
;
1918 while (!s_timed_out
)
1920 /* Stop or start blinking when focus changes */
1921 if (gui
.in_focus
!= focus
)
1924 gui_mch_start_blink();
1926 gui_mch_stop_blink();
1927 focus
= gui
.in_focus
;
1930 if (s_need_activate
)
1933 (void)SetForegroundWindow(s_hwnd
);
1935 (void)SetActiveWindow(s_hwnd
);
1937 s_need_activate
= FALSE
;
1941 * Don't use gui_mch_update() because then we will spin-lock until a
1942 * char arrives, instead we use GetMessage() to hang until an
1943 * event arrives. No need to check for input_buf_full because we are
1944 * returning as soon as it contains a single char -- webb
1948 if (input_available())
1950 if (s_wait_timer
!= 0 && !s_timed_out
)
1952 KillTimer(NULL
, s_wait_timer
);
1954 /* Eat spurious WM_TIMER messages */
1955 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
1959 allow_scrollbar
= FALSE
;
1961 /* Clear pending mouse button, the release event may have been
1962 * taken by the dialog window. But don't do this when getting
1963 * focus, we need the mouse-up event then. */
1964 if (!s_getting_focus
)
1965 s_button_pending
= -1;
1970 allow_scrollbar
= FALSE
;
1975 * Clear a rectangular region of the screen from text pos (row1, col1) to
1976 * (row2, col2) inclusive.
1979 gui_mch_clear_block(
1988 * Clear one extra pixel at the far right, for when bold characters have
1989 * spilled over to the window border.
1990 * Note: FillRect() excludes right and bottom of rectangle.
1992 rc
.left
= FILL_X(col1
);
1993 rc
.top
= FILL_Y(row1
);
1994 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
1995 rc
.bottom
= FILL_Y(row2
+ 1);
2000 * Clear the whole text window.
2003 gui_mch_clear_all(void)
2009 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
2010 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
2018 gui_mch_enable_menu(int flag
)
2021 SetMenu(s_hwnd
, flag
? s_menuBar
: NULL
);
2027 gui_mch_set_menu_pos(
2033 /* It will be in the right place anyway */
2036 #if defined(FEAT_MENU) || defined(PROTO)
2038 * Make menu item hidden or not hidden
2041 gui_mch_menu_hidden(
2046 * This doesn't do what we want. Hmm, just grey the menu items for now.
2050 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2052 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2054 gui_mch_menu_grey(menu
, hidden
);
2058 * This is called after setting all the menus to grey/hidden or not.
2061 gui_mch_draw_menubar(void)
2063 DrawMenuBar(s_hwnd
);
2065 #endif /*FEAT_MENU*/
2073 SaveInst(HINSTANCE hInst
)
2080 * Return the RGB value of a pixel as a long.
2083 gui_mch_get_rgb(guicolor_T pixel
)
2085 return (GetRValue(pixel
) << 16) + (GetGValue(pixel
) << 8)
2089 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2090 /* Convert pixels in X to dialog units */
2092 PixelToDialogX(int numPixels
)
2094 return (WORD
)((numPixels
* 4) / s_dlgfntwidth
);
2097 /* Convert pixels in Y to dialog units */
2099 PixelToDialogY(int numPixels
)
2101 return (WORD
)((numPixels
* 8) / s_dlgfntheight
);
2104 /* Return the width in pixels of the given text in the given DC. */
2106 GetTextWidth(HDC hdc
, char_u
*str
, int len
)
2110 GetTextExtentPoint(hdc
, str
, len
, &size
);
2116 * Return the width in pixels of the given text in the given DC, taking care
2117 * of 'encoding' to active codepage conversion.
2120 GetTextWidthEnc(HDC hdc
, char_u
*str
, int len
)
2127 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2129 /* 'encoding' differs from active codepage: convert text and use wide
2131 wstr
= enc_to_ucs2(str
, &wlen
);
2134 n
= GetTextExtentPointW(hdc
, wstr
, wlen
, &size
);
2141 return GetTextWidth(hdc
, str
, len
);
2144 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
2148 * A quick little routine that will center one window over another, handy for
2149 * dialog boxes. Taken from the Win32SDK samples.
2156 RECT rChild
, rParent
;
2157 int wChild
, hChild
, wParent
, hParent
;
2158 int wScreen
, hScreen
, xNew
, yNew
;
2161 GetWindowRect(hwndChild
, &rChild
);
2162 wChild
= rChild
.right
- rChild
.left
;
2163 hChild
= rChild
.bottom
- rChild
.top
;
2165 /* If Vim is minimized put the window in the middle of the screen. */
2166 if (hwndParent
== NULL
|| IsMinimized(hwndParent
))
2171 rParent
.right
= GetSystemMetrics(SM_CXSCREEN
);
2172 rParent
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
2174 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rParent
, 0);
2178 GetWindowRect(hwndParent
, &rParent
);
2179 wParent
= rParent
.right
- rParent
.left
;
2180 hParent
= rParent
.bottom
- rParent
.top
;
2182 hdc
= GetDC(hwndChild
);
2183 wScreen
= GetDeviceCaps (hdc
, HORZRES
);
2184 hScreen
= GetDeviceCaps (hdc
, VERTRES
);
2185 ReleaseDC(hwndChild
, hdc
);
2187 xNew
= rParent
.left
+ ((wParent
- wChild
) /2);
2192 else if ((xNew
+wChild
) > wScreen
)
2194 xNew
= wScreen
- wChild
;
2197 yNew
= rParent
.top
+ ((hParent
- hChild
) /2);
2200 else if ((yNew
+hChild
) > hScreen
)
2201 yNew
= hScreen
- hChild
;
2203 return SetWindowPos(hwndChild
, NULL
, xNew
, yNew
, 0, 0,
2204 SWP_NOSIZE
| SWP_NOZORDER
);
2206 #endif /* FEAT_GUI_DIALOG */
2209 gui_mch_activate_window(void)
2211 (void)SetActiveWindow(s_hwnd
);
2214 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2216 gui_mch_show_toolbar(int showit
)
2218 if (s_toolbarhwnd
== NULL
)
2224 # ifndef TB_SETUNICODEFORMAT
2225 /* For older compilers. We assume this never changes. */
2226 # define TB_SETUNICODEFORMAT 0x2005
2228 /* Enable/disable unicode support */
2229 int uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2230 SendMessage(s_toolbarhwnd
, TB_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2232 ShowWindow(s_toolbarhwnd
, SW_SHOW
);
2235 ShowWindow(s_toolbarhwnd
, SW_HIDE
);
2238 /* Then number of bitmaps is fixed. Exit is missing! */
2239 #define TOOLBAR_BITMAP_COUNT 31
2243 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2245 add_tabline_popup_menu_entry(HMENU pmenu
, UINT item_id
, char_u
*item_text
)
2251 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2253 /* 'encoding' differs from active codepage: convert menu name
2254 * and use wide function */
2255 wn
= enc_to_ucs2(item_text
, NULL
);
2258 MENUITEMINFOW infow
;
2260 infow
.cbSize
= sizeof(infow
);
2261 infow
.fMask
= MIIM_TYPE
| MIIM_ID
;
2262 infow
.wID
= item_id
;
2263 infow
.fType
= MFT_STRING
;
2264 infow
.dwTypeData
= wn
;
2265 infow
.cch
= (UINT
)wcslen(wn
);
2266 n
= InsertMenuItemW(pmenu
, item_id
, FALSE
, &infow
);
2268 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2269 /* Failed, try using non-wide function. */
2279 info
.cbSize
= sizeof(info
);
2280 info
.fMask
= MIIM_TYPE
| MIIM_ID
;
2282 info
.fType
= MFT_STRING
;
2283 info
.dwTypeData
= item_text
;
2284 info
.cch
= (UINT
)STRLEN(item_text
);
2285 InsertMenuItem(pmenu
, item_id
, FALSE
, &info
);
2290 show_tabline_popup_menu(void)
2296 /* When ignoring events don't show the menu. */
2304 tab_pmenu
= CreatePopupMenu();
2305 if (tab_pmenu
== NULL
)
2308 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_CLOSE
, _("Close tab"));
2309 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_NEW
, _("New tab"));
2310 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_OPEN
,
2314 rval
= TrackPopupMenuEx(tab_pmenu
, TPM_RETURNCMD
, pt
.x
, pt
.y
, s_tabhwnd
,
2317 DestroyMenu(tab_pmenu
);
2319 /* Add the string cmd into input buffer */
2322 TCHITTESTINFO htinfo
;
2325 if (ScreenToClient(s_tabhwnd
, &pt
) == 0)
2330 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
2336 send_tabline_menu_event(idx
, (int)rval
);
2341 * Show or hide the tabline.
2344 gui_mch_show_tabline(int showit
)
2346 if (s_tabhwnd
== NULL
)
2349 if (!showit
!= !showing_tabline
)
2352 ShowWindow(s_tabhwnd
, SW_SHOW
);
2354 ShowWindow(s_tabhwnd
, SW_HIDE
);
2355 showing_tabline
= showit
;
2360 * Return TRUE when tabline is displayed.
2363 gui_mch_showing_tabline(void)
2365 return s_tabhwnd
!= NULL
&& showing_tabline
;
2369 * Update the labels of the tabline.
2372 gui_mch_update_tabline(void)
2380 static int use_unicode
= FALSE
;
2385 if (s_tabhwnd
== NULL
)
2388 #if defined(FEAT_MBYTE)
2389 # ifndef CCM_SETUNICODEFORMAT
2390 /* For older compilers. We assume this never changes. */
2391 # define CCM_SETUNICODEFORMAT 0x2005
2393 uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2394 if (uu
!= use_unicode
)
2396 /* Enable/disable unicode support */
2397 SendMessage(s_tabhwnd
, CCM_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2402 tie
.mask
= TCIF_TEXT
;
2405 /* Add a label for each tab page. They all contain the same text area. */
2406 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
2411 if (!TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2414 tie
.pszText
= "-Empty-";
2415 TabCtrl_InsertItem(s_tabhwnd
, nr
, &tie
);
2418 get_tabline_label(tp
, FALSE
);
2419 tie
.pszText
= NameBuff
;
2424 /* Need to go through Unicode. */
2425 wstr
= enc_to_ucs2(NameBuff
, NULL
);
2430 tiw
.mask
= TCIF_TEXT
;
2433 SendMessage(s_tabhwnd
, TCM_SETITEMW
, (WPARAM
)nr
, (LPARAM
)&tiw
);
2440 TabCtrl_SetItem(s_tabhwnd
, nr
, &tie
);
2444 /* Remove any old labels. */
2445 while (TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2446 TabCtrl_DeleteItem(s_tabhwnd
, nr
);
2448 if (TabCtrl_GetCurSel(s_tabhwnd
) != curtabidx
)
2449 TabCtrl_SetCurSel(s_tabhwnd
, curtabidx
);
2453 * Set the current tab to "nr". First tab is 1.
2456 gui_mch_set_curtab(nr
)
2459 if (s_tabhwnd
== NULL
)
2462 if (TabCtrl_GetCurSel(s_tabhwnd
) != nr
-1)
2463 TabCtrl_SetCurSel(s_tabhwnd
, nr
-1);
2469 * ":simalt" command.
2472 ex_simalt(exarg_T
*eap
)
2474 char_u
*keys
= eap
->arg
;
2476 PostMessage(s_hwnd
, WM_SYSCOMMAND
, (WPARAM
)SC_KEYMENU
, (LPARAM
)0);
2480 *keys
= ' '; /* for showing system menu */
2481 PostMessage(s_hwnd
, WM_CHAR
, (WPARAM
)*keys
, (LPARAM
)0);
2487 * Create the find & replace dialogs.
2488 * You can't have both at once: ":find" when replace is showing, destroys
2489 * the replace dialog first, and the other way around.
2491 #ifdef MSWIN_FIND_REPLACE
2493 initialise_findrep(char_u
*initial_string
)
2499 /* Get the search string to use. */
2500 entry_text
= get_find_dialog_text(initial_string
, &wword
, &mcase
);
2502 s_findrep_struct
.hwndOwner
= s_hwnd
;
2503 s_findrep_struct
.Flags
= FR_DOWN
;
2505 s_findrep_struct
.Flags
|= FR_MATCHCASE
;
2507 s_findrep_struct
.Flags
|= FR_WHOLEWORD
;
2508 if (entry_text
!= NULL
&& *entry_text
!= NUL
)
2509 vim_strncpy(s_findrep_struct
.lpstrFindWhat
, entry_text
,
2510 s_findrep_struct
.wFindWhatLen
- 1);
2511 vim_free(entry_text
);
2516 set_window_title(HWND hwnd
, char *title
)
2519 if (title
!= NULL
&& enc_codepage
>= 0 && enc_codepage
!= (int)GetACP())
2524 /* Convert the title from 'encoding' to ucs2. */
2525 wbuf
= (WCHAR
*)enc_to_ucs2((char_u
*)title
, NULL
);
2528 n
= SetWindowTextW(hwnd
, wbuf
);
2530 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2532 /* Retry with non-wide function (for Windows 98). */
2536 (void)SetWindowText(hwnd
, (LPCSTR
)title
);
2540 gui_mch_find_dialog(exarg_T
*eap
)
2542 #ifdef MSWIN_FIND_REPLACE
2543 if (s_findrep_msg
!= 0)
2545 if (IsWindow(s_findrep_hwnd
) && !s_findrep_is_find
)
2546 DestroyWindow(s_findrep_hwnd
);
2548 if (!IsWindow(s_findrep_hwnd
))
2550 initialise_findrep(eap
->arg
);
2551 s_findrep_hwnd
= FindText((LPFINDREPLACE
) &s_findrep_struct
);
2554 set_window_title(s_findrep_hwnd
,
2555 _("Find string (use '\\\\' to find a '\\')"));
2556 (void)SetFocus(s_findrep_hwnd
);
2558 s_findrep_is_find
= TRUE
;
2565 gui_mch_replace_dialog(exarg_T
*eap
)
2567 #ifdef MSWIN_FIND_REPLACE
2568 if (s_findrep_msg
!= 0)
2570 if (IsWindow(s_findrep_hwnd
) && s_findrep_is_find
)
2571 DestroyWindow(s_findrep_hwnd
);
2573 if (!IsWindow(s_findrep_hwnd
))
2575 initialise_findrep(eap
->arg
);
2576 s_findrep_hwnd
= ReplaceText((LPFINDREPLACE
) &s_findrep_struct
);
2579 set_window_title(s_findrep_hwnd
,
2580 _("Find & Replace (use '\\\\' to find a '\\')"));
2581 (void)SetFocus(s_findrep_hwnd
);
2583 s_findrep_is_find
= FALSE
;
2590 * Set visibility of the pointer.
2593 gui_mch_mousehide(int hide
)
2595 if (hide
!= gui
.pointer_hidden
)
2598 gui
.pointer_hidden
= hide
;
2604 gui_mch_show_popupmenu_at(vimmenu_T
*menu
, int x
, int y
)
2606 /* Unhide the mouse, we don't get move events here. */
2607 gui_mch_mousehide(FALSE
);
2609 (void)TrackPopupMenu(
2610 (HMENU
)menu
->submenu_id
,
2611 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2613 (int)0, /*reserved param*/
2617 * NOTE: The pop-up menu can eat the mouse up event.
2618 * We deal with this in normal.c.
2624 * Got a message when the system will go down.
2629 getout_preserve_modified(1);
2633 * Get this message when the user clicks on the cross in the top right corner
2634 * of a Windows95 window.
2645 * Get a message when the window is being destroyed.
2652 Ctl3dUnregister(s_hinst
);
2662 if (!IsMinimized(hwnd
))
2666 out_flush(); /* make sure all output has been processed */
2667 (void)BeginPaint(hwnd
, &ps
);
2670 /* prevent multi-byte characters from misprinting on an invalid
2676 GetClientRect(hwnd
, &rect
);
2677 ps
.rcPaint
.left
= rect
.left
;
2678 ps
.rcPaint
.right
= rect
.right
;
2682 if (!IsRectEmpty(&ps
.rcPaint
))
2683 gui_redraw(ps
.rcPaint
.left
, ps
.rcPaint
.top
,
2684 ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1,
2685 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1);
2686 EndPaint(hwnd
, &ps
);
2698 if (!IsMinimized(hwnd
))
2700 gui_resize_shell(cx
, cy
);
2703 /* Menu bar may wrap differently now */
2704 gui_mswin_get_menu_height(TRUE
);
2714 gui_focus_change(TRUE
);
2715 s_getting_focus
= TRUE
;
2716 (void)MyWindowProc(hwnd
, WM_SETFOCUS
, (WPARAM
)hwndOldFocus
, 0);
2724 gui_focus_change(FALSE
);
2725 s_getting_focus
= FALSE
;
2726 (void)MyWindowProc(hwnd
, WM_KILLFOCUS
, (WPARAM
)hwndNewFocus
, 0);
2730 * Get a message when the user switches back to vim
2747 /* we call gui_focus_change() in _OnSetFocus() */
2748 /* gui_focus_change((int)fActivate); */
2749 return MyWindowProc(hwnd
, WM_ACTIVATEAPP
, fActivate
, (DWORD
)dwThreadId
);
2752 #if defined(FEAT_WINDOWS) || defined(PROTO)
2754 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
2756 DestroyWindow(sb
->id
);
2761 * Get current mouse coordinates in text window.
2764 gui_mch_getmouse(int *x
, int *y
)
2769 (void)GetWindowRect(s_textArea
, &rct
);
2770 (void)GetCursorPos((LPPOINT
)&mp
);
2771 *x
= (int)(mp
.x
- rct
.left
);
2772 *y
= (int)(mp
.y
- rct
.top
);
2776 * Move mouse pointer to character at (x, y).
2779 gui_mch_setmouse(int x
, int y
)
2783 (void)GetWindowRect(s_textArea
, &rct
);
2784 (void)SetCursorPos(x
+ gui
.border_offset
+ rct
.left
,
2785 y
+ gui
.border_offset
+ rct
.top
);
2789 gui_mswin_get_valid_dimensions(
2795 int base_width
, base_height
;
2797 base_width
= gui_get_base_width()
2798 + GetSystemMetrics(SM_CXFRAME
) * 2;
2799 base_height
= gui_get_base_height()
2800 + GetSystemMetrics(SM_CYFRAME
) * 2
2801 + GetSystemMetrics(SM_CYCAPTION
)
2803 + gui_mswin_get_menu_height(FALSE
)
2806 *valid_w
= base_width
+
2807 ((w
- base_width
) / gui
.char_width
) * gui
.char_width
;
2808 *valid_h
= base_height
+
2809 ((h
- base_height
) / gui
.char_height
) * gui
.char_height
;
2813 gui_mch_flash(int msec
)
2818 * Note: InvertRect() excludes right and bottom of rectangle.
2822 rc
.right
= gui
.num_cols
* gui
.char_width
;
2823 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
2824 InvertRect(s_hdc
, &rc
);
2825 gui_mch_flush(); /* make sure it's displayed */
2827 ui_delay((long)msec
, TRUE
); /* wait for a few msec */
2829 InvertRect(s_hdc
, &rc
);
2833 * Return flags used for scrolling.
2834 * The SW_INVALIDATE is required when part of the window is covered or
2835 * off-screen. Refer to MS KB Q75236.
2838 get_scroll_flags(void)
2841 RECT rcVim
, rcOther
, rcDest
;
2843 GetWindowRect(s_hwnd
, &rcVim
);
2845 /* Check if the window is partly above or below the screen. We don't care
2846 * about partly left or right of the screen, it is not relevant when
2847 * scrolling up or down. */
2848 if (rcVim
.top
< 0 || rcVim
.bottom
> GetSystemMetrics(SM_CYFULLSCREEN
))
2849 return SW_INVALIDATE
;
2851 /* Check if there is an window (partly) on top of us. */
2852 for (hwnd
= s_hwnd
; (hwnd
= GetWindow(hwnd
, GW_HWNDPREV
)) != (HWND
)0; )
2853 if (IsWindowVisible(hwnd
))
2855 GetWindowRect(hwnd
, &rcOther
);
2856 if (IntersectRect(&rcDest
, &rcVim
, &rcOther
))
2857 return SW_INVALIDATE
;
2863 * Delete the given number of lines from the given row, scrolling up any
2864 * text further down within the scroll region.
2867 gui_mch_delete_lines(
2873 rc
.left
= FILL_X(gui
.scroll_region_left
);
2874 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2875 rc
.top
= FILL_Y(row
);
2876 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2878 ScrollWindowEx(s_textArea
, 0, -num_lines
* gui
.char_height
,
2879 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2881 UpdateWindow(s_textArea
);
2882 /* This seems to be required to avoid the cursor disappearing when
2883 * scrolling such that the cursor ends up in the top-left character on
2884 * the screen... But why? (Webb) */
2885 /* It's probably fixed by disabling drawing the cursor while scrolling. */
2886 /* gui.cursor_is_valid = FALSE; */
2888 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
2889 gui
.scroll_region_left
,
2890 gui
.scroll_region_bot
, gui
.scroll_region_right
);
2894 * Insert the given number of lines before the given row, scrolling down any
2895 * following text within the scroll region.
2898 gui_mch_insert_lines(
2904 rc
.left
= FILL_X(gui
.scroll_region_left
);
2905 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2906 rc
.top
= FILL_Y(row
);
2907 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2908 /* The SW_INVALIDATE is required when part of the window is covered or
2909 * off-screen. How do we avoid it when it's not needed? */
2910 ScrollWindowEx(s_textArea
, 0, num_lines
* gui
.char_height
,
2911 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2913 UpdateWindow(s_textArea
);
2915 gui_clear_block(row
, gui
.scroll_region_left
,
2916 row
+ num_lines
- 1, gui
.scroll_region_right
);
2922 gui_mch_exit(int rc
)
2924 ReleaseDC(s_textArea
, s_hdc
);
2925 DeleteObject(s_brush
);
2928 /* Unload the tearoff bitmap */
2929 (void)DeleteObject((HGDIOBJ
)s_htearbitmap
);
2932 /* Destroy our window (if we have one). */
2935 destroying
= TRUE
; /* ignore WM_DESTROY message now */
2936 DestroyWindow(s_hwnd
);
2945 logfont2name(LOGFONT lf
)
2951 charset_name
= charset_id2name((int)lf
.lfCharSet
);
2952 res
= alloc((unsigned)(strlen(lf
.lfFaceName
) + 20
2953 + (charset_name
== NULL
? 0 : strlen(charset_name
) + 2)));
2957 /* make a normal font string out of the lf thing:*/
2958 sprintf((char *)p
, "%s:h%d", lf
.lfFaceName
, pixels_to_points(
2959 lf
.lfHeight
< 0 ? -lf
.lfHeight
: lf
.lfHeight
, TRUE
));
2966 #ifndef MSWIN16_FASTTEXT
2969 if (lf
.lfWeight
>= FW_BOLD
)
2976 if (charset_name
!= NULL
)
2979 STRCAT(p
, charset_name
);
2987 * Initialise vim to use the font with the given name.
2988 * Return FAIL if the font could not be loaded, OK otherwise.
2992 gui_mch_init_font(char_u
*font_name
, int fontset
)
2995 GuiFont font
= NOFONT
;
2999 if (get_logfont(&lf
, font_name
, NULL
, TRUE
) == OK
)
3000 font
= get_font_handle(&lf
);
3004 if (font_name
== NULL
)
3005 font_name
= lf
.lfFaceName
;
3006 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
3009 #ifdef FEAT_MBYTE_IME
3012 gui_mch_free_font(gui
.norm_font
);
3013 gui
.norm_font
= font
;
3014 current_font_height
= lf
.lfHeight
;
3017 p
= logfont2name(lf
);
3020 hl_set_font_name(p
);
3022 /* When setting 'guifont' to "*" replace it with the actual font name.
3024 if (STRCMP(font_name
, "*") == 0 && STRCMP(p_guifont
, "*") == 0)
3026 vim_free(p_guifont
);
3033 #ifndef MSWIN16_FASTTEXT
3034 gui_mch_free_font(gui
.ital_font
);
3035 gui
.ital_font
= NOFONT
;
3036 gui_mch_free_font(gui
.bold_font
);
3037 gui
.bold_font
= NOFONT
;
3038 gui_mch_free_font(gui
.boldital_font
);
3039 gui
.boldital_font
= NOFONT
;
3044 gui
.ital_font
= get_font_handle(&lf
);
3045 lf
.lfItalic
= FALSE
;
3047 if (lf
.lfWeight
< FW_BOLD
)
3049 lf
.lfWeight
= FW_BOLD
;
3050 gui
.bold_font
= get_font_handle(&lf
);
3054 gui
.boldital_font
= get_font_handle(&lf
);
3062 #ifndef WPF_RESTORETOMAXIMIZED
3063 # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
3067 * Return TRUE if the GUI window is maximized, filling the whole screen.
3074 wp
.length
= sizeof(WINDOWPLACEMENT
);
3075 if (GetWindowPlacement(s_hwnd
, &wp
))
3076 return wp
.showCmd
== SW_SHOWMAXIMIZED
3077 || (wp
.showCmd
== SW_SHOWMINIMIZED
3078 && wp
.flags
== WPF_RESTORETOMAXIMIZED
);
3084 * Called when the font changed while the window is maximized. Compute the
3085 * new Rows and Columns. This is like resizing the window.
3092 GetWindowRect(s_hwnd
, &rect
);
3093 gui_resize_shell(rect
.right
- rect
.left
3094 - GetSystemMetrics(SM_CXFRAME
) * 2,
3095 rect
.bottom
- rect
.top
3096 - GetSystemMetrics(SM_CYFRAME
) * 2
3097 - GetSystemMetrics(SM_CYCAPTION
)
3099 - gui_mswin_get_menu_height(FALSE
)
3105 * Set the window title
3113 set_window_title(s_hwnd
, (title
== NULL
? "VIM" : (char *)title
));
3116 #ifdef FEAT_MOUSESHAPE
3117 /* Table for shape IDCs. Keep in sync with the mshape_names[] table in
3119 static LPCSTR mshape_idcs
[] =
3121 MAKEINTRESOURCE(IDC_ARROW
), /* arrow */
3122 MAKEINTRESOURCE(0), /* blank */
3123 MAKEINTRESOURCE(IDC_IBEAM
), /* beam */
3124 MAKEINTRESOURCE(IDC_SIZENS
), /* updown */
3125 MAKEINTRESOURCE(IDC_SIZENS
), /* udsizing */
3126 MAKEINTRESOURCE(IDC_SIZEWE
), /* leftright */
3127 MAKEINTRESOURCE(IDC_SIZEWE
), /* lrsizing */
3128 MAKEINTRESOURCE(IDC_WAIT
), /* busy */
3130 MAKEINTRESOURCE(IDC_NO
), /* no */
3132 MAKEINTRESOURCE(IDC_ICON
), /* no */
3134 MAKEINTRESOURCE(IDC_ARROW
), /* crosshair */
3135 MAKEINTRESOURCE(IDC_ARROW
), /* hand1 */
3136 MAKEINTRESOURCE(IDC_ARROW
), /* hand2 */
3137 MAKEINTRESOURCE(IDC_ARROW
), /* pencil */
3138 MAKEINTRESOURCE(IDC_ARROW
), /* question */
3139 MAKEINTRESOURCE(IDC_ARROW
), /* right-arrow */
3140 MAKEINTRESOURCE(IDC_UPARROW
), /* up-arrow */
3141 MAKEINTRESOURCE(IDC_ARROW
) /* last one */
3145 mch_set_mouse_shape(int shape
)
3149 if (shape
== MSHAPE_HIDE
)
3153 if (shape
>= MSHAPE_NUMBERED
)
3154 idc
= MAKEINTRESOURCE(IDC_ARROW
);
3156 idc
= mshape_idcs
[shape
];
3158 SetClassLongPtr(s_textArea
, GCLP_HCURSOR
, (LONG_PTR
)LoadCursor(NULL
, idc
));
3161 SetClassLong(s_textArea
, GCL_HCURSOR
, (LONG
)LoadCursor(NULL
, idc
));
3163 SetClassWord(s_textArea
, GCW_HCURSOR
, (WORD
)LoadCursor(NULL
, idc
));
3170 /* Set the position to make it redrawn with the new shape. */
3171 (void)GetCursorPos((LPPOINT
)&mp
);
3172 (void)SetCursorPos(mp
.x
, mp
.y
);
3181 * The file browser exists in two versions: with "W" uses wide characters,
3182 * without "W" the current codepage. When FEAT_MBYTE is defined and on
3183 * Windows NT/2000/XP the "W" functions are used.
3186 # if defined(FEAT_MBYTE) && defined(WIN3264)
3188 * Wide version of convert_filter(). Keep in sync!
3191 convert_filterW(char_u
*s
)
3194 unsigned s_len
= (unsigned)STRLEN(s
);
3197 res
= (WCHAR
*)alloc((s_len
+ 3) * sizeof(WCHAR
));
3200 for (i
= 0; i
< s_len
; ++i
)
3201 if (s
[i
] == '\t' || s
[i
] == '\n')
3206 /* Add two extra NULs to make sure it's properly terminated. */
3207 res
[s_len
+ 1] = NUL
;
3208 res
[s_len
+ 2] = NUL
;
3214 * Wide version of gui_mch_browse(). Keep in sync!
3225 /* We always use the wide function. This means enc_to_ucs2() must work,
3226 * otherwise it fails miserably! */
3227 OPENFILENAMEW fileStruct
;
3228 WCHAR fileBuf
[MAXPATHL
];
3231 WCHAR
*titlep
= NULL
;
3233 WCHAR
*initdirp
= NULL
;
3241 wp
= enc_to_ucs2(dflt
, NULL
);
3246 for (i
= 0; wp
[i
] != NUL
&& i
< MAXPATHL
- 1; ++i
)
3253 /* Convert the filter to Windows format. */
3254 filterp
= convert_filterW(filter
);
3256 memset(&fileStruct
, 0, sizeof(OPENFILENAMEW
));
3257 #ifdef OPENFILENAME_SIZE_VERSION_400
3258 /* be compatible with Windows NT 4.0 */
3259 /* TODO: what to use for OPENFILENAMEW??? */
3260 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3262 fileStruct
.lStructSize
= sizeof(fileStruct
);
3266 titlep
= enc_to_ucs2(title
, NULL
);
3267 fileStruct
.lpstrTitle
= titlep
;
3270 extp
= enc_to_ucs2(ext
, NULL
);
3271 fileStruct
.lpstrDefExt
= extp
;
3273 fileStruct
.lpstrFile
= fileBuf
;
3274 fileStruct
.nMaxFile
= MAXPATHL
;
3275 fileStruct
.lpstrFilter
= filterp
;
3276 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3277 /* has an initial dir been specified? */
3278 if (initdir
!= NULL
&& *initdir
!= NUL
)
3280 /* Must have backslashes here, no matter what 'shellslash' says */
3281 initdirp
= enc_to_ucs2(initdir
, NULL
);
3282 if (initdirp
!= NULL
)
3284 for (wp
= initdirp
; *wp
!= NUL
; ++wp
)
3288 fileStruct
.lpstrInitialDir
= initdirp
;
3292 * TODO: Allow selection of multiple files. Needs another arg to this
3293 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3294 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3295 * files that don't exist yet, so I haven't put it in. What about
3296 * OFN_PATHMUSTEXIST?
3297 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3299 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3300 #ifdef FEAT_SHORTCUT
3301 if (curbuf
->b_p_bin
)
3302 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3306 if (!GetSaveFileNameW(&fileStruct
))
3311 if (!GetOpenFileNameW(&fileStruct
))
3320 /* Convert from UCS2 to 'encoding'. */
3321 p
= ucs2_to_enc(fileBuf
, NULL
);
3323 /* when out of memory we get garbage for non-ASCII chars */
3327 /* Give focus back to main window (when using MDI). */
3330 /* Shorten the file name if possible */
3331 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3333 # endif /* FEAT_MBYTE */
3337 * Convert the string s to the proper format for a filter string by replacing
3338 * the \t and \n delimeters with \0.
3339 * Returns the converted string in allocated memory.
3341 * Keep in sync with convert_filterW() above!
3344 convert_filter(char_u
*s
)
3347 unsigned s_len
= (unsigned)STRLEN(s
);
3350 res
= alloc(s_len
+ 3);
3353 for (i
= 0; i
< s_len
; ++i
)
3354 if (s
[i
] == '\t' || s
[i
] == '\n')
3359 /* Add two extra NULs to make sure it's properly terminated. */
3360 res
[s_len
+ 1] = NUL
;
3361 res
[s_len
+ 2] = NUL
;
3367 * Select a directory.
3370 gui_mch_browsedir(char_u
*title
, char_u
*initdir
)
3372 /* We fake this: Use a filter that doesn't select anything and a default
3373 * file name that won't be used. */
3374 return gui_mch_browse(0, title
, (char_u
*)_("Not Used"), NULL
,
3375 initdir
, (char_u
*)_("Directory\t*.nothing\n"));
3379 * Pop open a file browser and return the file selected, in allocated memory,
3380 * or NULL if Cancel is hit.
3381 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
3382 * title - Title message for the file browser dialog.
3383 * dflt - Default name of file.
3384 * ext - Default extension to be added to files without extensions.
3385 * initdir - directory in which to open the browser (NULL = current dir)
3386 * filter - Filter for matched files to choose from.
3388 * Keep in sync with gui_mch_browseW() above!
3399 OPENFILENAME fileStruct
;
3400 char_u fileBuf
[MAXPATHL
];
3401 char_u
*initdirp
= NULL
;
3405 # if defined(FEAT_MBYTE) && defined(WIN3264)
3406 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
3407 return gui_mch_browseW(saving
, title
, dflt
, ext
, initdir
, filter
);
3413 vim_strncpy(fileBuf
, dflt
, MAXPATHL
- 1);
3415 /* Convert the filter to Windows format. */
3416 filterp
= convert_filter(filter
);
3418 memset(&fileStruct
, 0, sizeof(OPENFILENAME
));
3419 #ifdef OPENFILENAME_SIZE_VERSION_400
3420 /* be compatible with Windows NT 4.0 */
3421 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3423 fileStruct
.lStructSize
= sizeof(fileStruct
);
3426 fileStruct
.lpstrTitle
= title
;
3427 fileStruct
.lpstrDefExt
= ext
;
3429 fileStruct
.lpstrFile
= fileBuf
;
3430 fileStruct
.nMaxFile
= MAXPATHL
;
3431 fileStruct
.lpstrFilter
= filterp
;
3432 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3433 /* has an initial dir been specified? */
3434 if (initdir
!= NULL
&& *initdir
!= NUL
)
3436 /* Must have backslashes here, no matter what 'shellslash' says */
3437 initdirp
= vim_strsave(initdir
);
3438 if (initdirp
!= NULL
)
3439 for (p
= initdirp
; *p
!= NUL
; ++p
)
3442 fileStruct
.lpstrInitialDir
= initdirp
;
3446 * TODO: Allow selection of multiple files. Needs another arg to this
3447 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3448 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3449 * files that don't exist yet, so I haven't put it in. What about
3450 * OFN_PATHMUSTEXIST?
3451 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3453 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3454 #ifdef FEAT_SHORTCUT
3455 if (curbuf
->b_p_bin
)
3456 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3460 if (!GetSaveFileName(&fileStruct
))
3465 if (!GetOpenFileName(&fileStruct
))
3472 /* Give focus back to main window (when using MDI). */
3475 /* Shorten the file name if possible */
3476 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3478 #endif /* FEAT_BROWSE */
3488 # define BUFPATHLEN _MAX_PATH
3489 # define DRAGQVAL 0xFFFFFFFF
3491 # define BUFPATHLEN MAXPATHL
3492 # define DRAGQVAL 0xFFFF
3495 WCHAR wszFile
[BUFPATHLEN
];
3497 char szFile
[BUFPATHLEN
];
3498 UINT cFiles
= DragQueryFile(hDrop
, DRAGQVAL
, NULL
, 0);
3502 int_u modifiers
= 0;
3504 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3506 /* Obtain dropped position */
3507 DragQueryPoint(hDrop
, &pt
);
3508 MapWindowPoints(s_hwnd
, s_textArea
, &pt
, 1);
3514 fnames
= (char_u
**)alloc(cFiles
* sizeof(char_u
*));
3517 for (i
= 0; i
< cFiles
; ++i
)
3520 if (DragQueryFileW(hDrop
, i
, wszFile
, BUFPATHLEN
) > 0)
3521 fnames
[i
] = ucs2_to_enc(wszFile
, NULL
);
3525 DragQueryFile(hDrop
, i
, szFile
, BUFPATHLEN
);
3526 fnames
[i
] = vim_strsave(szFile
);
3534 if ((GetKeyState(VK_SHIFT
) & 0x8000) != 0)
3535 modifiers
|= MOUSE_SHIFT
;
3536 if ((GetKeyState(VK_CONTROL
) & 0x8000) != 0)
3537 modifiers
|= MOUSE_CTRL
;
3538 if ((GetKeyState(VK_MENU
) & 0x8000) != 0)
3539 modifiers
|= MOUSE_ALT
;
3541 gui_handle_drop(pt
.x
, pt
.y
, modifiers
, fnames
, cFiles
);
3543 s_need_activate
= TRUE
;
3556 static UINT prev_code
= 0; /* code of previous call */
3557 scrollbar_T
*sb
, *sb_info
;
3559 int dragging
= FALSE
;
3560 int dont_scroll_save
= dont_scroll
;
3566 si
.cbSize
= sizeof(si
);
3570 sb
= gui_mswin_find_scrollbar(hwndCtl
);
3574 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
3577 * Careful: need to get scrollbar info out of first (left) scrollbar
3578 * for window, but keep real scrollbar too because we must pass it to
3579 * gui_drag_scrollbar().
3581 sb_info
= &sb
->wp
->w_scrollbars
[0];
3583 else /* Bottom scrollbar */
3585 val
= sb_info
->value
;
3592 if (sb
->scroll_shift
> 0)
3593 val
<<= sb
->scroll_shift
;
3602 val
+= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3605 val
-= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3614 if (prev_code
== SB_THUMBTRACK
)
3617 * "pos" only gives us 16-bit data. In case of large file,
3618 * use GetScrollPos() which returns 32-bit. Unfortunately it
3619 * is not valid while the scrollbar is being dragged.
3621 val
= GetScrollPos(hwndCtl
, SB_CTL
);
3622 if (sb
->scroll_shift
> 0)
3623 val
<<= sb
->scroll_shift
;
3628 /* TRACE("Unknown scrollbar event %d\n", code); */
3634 si
.nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3635 SetScrollInfo(hwndCtl
, SB_CTL
, &si
, TRUE
);
3637 nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3638 SetScrollPos(hwndCtl
, SB_CTL
, nPos
, TRUE
);
3642 * When moving a vertical scrollbar, move the other vertical scrollbar too.
3646 scrollbar_T
*sba
= sb
->wp
->w_scrollbars
;
3647 HWND id
= sba
[ (sb
== sba
+ SBAR_LEFT
) ? SBAR_RIGHT
: SBAR_LEFT
].id
;
3650 SetScrollInfo(id
, SB_CTL
, &si
, TRUE
);
3652 SetScrollPos(id
, SB_CTL
, nPos
, TRUE
);
3656 /* Don't let us be interrupted here by another message. */
3657 s_busy_processing
= TRUE
;
3659 /* When "allow_scrollbar" is FALSE still need to remember the new
3660 * position, but don't actually scroll by setting "dont_scroll". */
3661 dont_scroll
= !allow_scrollbar
;
3663 gui_drag_scrollbar(sb
, val
, dragging
);
3665 s_busy_processing
= FALSE
;
3666 dont_scroll
= dont_scroll_save
;
3673 * Get command line arguments.
3674 * Use "prog" as the name of the program and "cmdline" as the arguments.
3675 * Copy the arguments to allocated memory.
3676 * Return the number of arguments (including program name).
3677 * Return pointers to the arguments in "argvp".
3678 * Return pointer to buffer in "tofree".
3679 * Returns zero when out of memory.
3683 get_cmd_args(char *prog
, char *cmdline
, char ***argvp
, char **tofree
)
3696 /* Try using the Unicode version first, it takes care of conversion when
3697 * 'encoding' is changed. */
3698 argc
= get_cmd_argsW(&argv
);
3703 /* Handle the program name. Remove the ".exe" extension, and find the 1st
3705 p
= strrchr(prog
, '.');
3708 for (progp
= prog
; *progp
== ' '; ++progp
)
3711 /* The command line is copied to allocated memory, so that we can change
3712 * it. Add the size of the string, the separating NUL and a terminating
3714 newcmdline
= malloc(STRLEN(cmdline
) + STRLEN(progp
) + 2);
3715 if (newcmdline
== NULL
)
3719 * First round: count the number of arguments ("pnew" == NULL).
3720 * Second round: produce the arguments.
3722 for (round
= 1; round
<= 2; ++round
)
3724 /* First argument is the program name. */
3728 strcpy(pnew
, progp
);
3729 pnew
+= strlen(pnew
);
3734 * Isolate each argument and put it in argv[].
3744 while (*p
!= NUL
&& (inquote
|| (*p
!= ' ' && *p
!= '\t')))
3746 /* Backslashes are only special when followed by a double
3748 i
= (int)strspn(p
, "\\");
3751 /* Halve the number of backslashes. */
3752 if (i
> 1 && pnew
!= NULL
)
3754 memset(pnew
, '\\', i
/ 2);
3758 /* Even nr of backslashes toggles quoting, uneven copies
3759 * the double quote. */
3762 else if (pnew
!= NULL
)
3768 /* Copy span of backslashes unmodified. */
3771 memset(pnew
, '\\', i
);
3781 /* Can't use mb_* functions, because 'encoding' is not
3782 * initialized yet here. */
3783 if (IsDBCSLeadByte(*p
))
3796 while (*p
== ' ' || *p
== '\t')
3797 ++p
; /* advance until a non-space */
3802 argv
= (char **)malloc((argc
+ 1) * sizeof(char *));
3805 vim_free(newcmdline
);
3806 return 0; /* malloc error */
3814 argv
[argc
] = NULL
; /* NULL-terminated list */