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 # if defined(FEAT_MBYTE) && defined(WIN3264)
157 static FINDREPLACEW s_findrep_struct_w
;
159 static HWND s_findrep_hwnd
= NULL
;
160 static int s_findrep_is_find
; /* TRUE for find dialog, FALSE
161 for find/replace dialog */
164 static HINSTANCE s_hinst
= NULL
;
165 #if !defined(FEAT_SNIFF) && !defined(FEAT_GUI)
169 static HDC s_hdc
= NULL
;
170 static HBRUSH s_brush
= NULL
;
173 static HWND s_toolbarhwnd
= NULL
;
176 #ifdef FEAT_GUI_TABLINE
177 static HWND s_tabhwnd
= NULL
;
178 static int showing_tabline
= 0;
181 static WPARAM s_wParam
= 0;
182 static LPARAM s_lParam
= 0;
184 static HWND s_textArea
= NULL
;
185 static UINT s_uMsg
= 0;
187 static char_u
*s_textfield
; /* Used by dialogs to pass back strings */
189 static int s_need_activate
= FALSE
;
191 /* This variable is set when waiting for an event, which is the only moment
192 * scrollbar dragging can be done directly. It's not allowed while commands
193 * are executed, because it may move the cursor and that may cause unexpected
194 * problems (e.g., while ":s" is working).
196 static int allow_scrollbar
= FALSE
;
199 # define MyTranslateMessage(x) global_ime_TranslateMessage(x)
201 # define MyTranslateMessage(x) TranslateMessage(x)
204 #if (defined(WIN3264) && defined(FEAT_MBYTE)) || defined(GLOBAL_IME)
205 /* use of WindowProc depends on wide_WindowProc */
206 # define MyWindowProc vim_WindowProc
208 /* use ordinary WindowProc */
209 # define MyWindowProc DefWindowProc
212 extern int current_font_height
; /* this is in os_mswin.c */
224 {VK_RIGHT
, 'k', 'r'},
249 #ifdef FEAT_NETBEANS_INTG
250 {VK_PAUSE
, 'F', 'B'}, /* Pause == F21 (see gui_gtk_x11.c) */
254 {VK_F24
, 'F', 'E'}, /* winuser.h defines up to F24 */
258 {VK_INSERT
, 'k', 'I'},
259 {VK_DELETE
, 'k', 'D'},
262 {VK_PRIOR
, 'k', 'P'},
264 {VK_PRINT
, '%', '9'},
266 {VK_SUBTRACT
, 'K', '7'},
267 {VK_DIVIDE
, 'K', '8'},
268 {VK_MULTIPLY
, 'K', '9'},
269 {VK_SEPARATOR
, 'K', 'A'}, /* Keypad Enter */
270 {VK_DECIMAL
, 'K', 'B'},
272 {VK_NUMPAD0
, 'K', 'C'},
273 {VK_NUMPAD1
, 'K', 'D'},
274 {VK_NUMPAD2
, 'K', 'E'},
275 {VK_NUMPAD3
, 'K', 'F'},
276 {VK_NUMPAD4
, 'K', 'G'},
277 {VK_NUMPAD5
, 'K', 'H'},
278 {VK_NUMPAD6
, 'K', 'I'},
279 {VK_NUMPAD7
, 'K', 'J'},
280 {VK_NUMPAD8
, 'K', 'K'},
281 {VK_NUMPAD9
, 'K', 'L'},
283 /* Keys that we want to be able to use any modifier with: */
284 {VK_SPACE
, ' ', NUL
},
286 {VK_ESCAPE
, ESC
, NUL
},
290 /* End of list marker: */
294 /* Local variables */
295 static int s_button_pending
= -1;
297 /* s_getting_focus is set when we got focus but didn't see mouse-up event yet,
298 * so don't reset s_button_pending. */
299 static int s_getting_focus
= FALSE
;
301 static int s_x_pending
;
302 static int s_y_pending
;
303 static UINT s_kFlags_pending
;
304 static UINT s_wait_timer
= 0; /* Timer for get char from user */
305 static int s_timed_out
= FALSE
;
306 static int dead_key
= 0; /* 0 - no dead key, 1 - dead key pressed */
309 static OSVERSIONINFO os_version
; /* like it says. Init in gui_mch_init() */
313 /* balloon-eval WM_NOTIFY_HANDLER */
314 static void Handle_WM_Notify
__ARGS((HWND hwnd
, LPNMHDR pnmh
));
315 static void TrackUserActivity
__ARGS((UINT uMsg
));
322 # ifdef USE_IM_CONTROL
323 static LOGFONT norm_logfont
;
327 #ifdef FEAT_MBYTE_IME
328 static LRESULT
_OnImeNotify(HWND hWnd
, DWORD dwCommand
, DWORD dwData
);
331 #ifdef DEBUG_PRINT_ERROR
333 * Print out the last Windows error message
336 print_windows_error(void)
340 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
341 NULL
, GetLastError(),
342 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
343 (LPTSTR
) &lpMsgBuf
, 0, NULL
);
344 TRACE1("Error: %s\n", lpMsgBuf
);
350 * Cursor blink functions.
352 * This is a simple state machine:
353 * BLINK_NONE not blinking at all
354 * BLINK_OFF blinking, cursor is not shown
355 * BLINK_ON blinking, cursor is shown
362 static int blink_state
= BLINK_NONE
;
363 static long_u blink_waittime
= 700;
364 static long_u blink_ontime
= 400;
365 static long_u blink_offtime
= 250;
366 static UINT blink_timer
= 0;
369 gui_mch_set_blinking(long wait
, long on
, long off
)
371 blink_waittime
= wait
;
387 TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
390 KillTimer(NULL
, idEvent
);
392 /* Eat spurious WM_TIMER messages */
393 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
396 if (blink_state
== BLINK_ON
)
399 blink_state
= BLINK_OFF
;
400 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_offtime
,
401 (TIMERPROC
)_OnBlinkTimer
);
405 gui_update_cursor(TRUE
, FALSE
);
406 blink_state
= BLINK_ON
;
407 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_ontime
,
408 (TIMERPROC
)_OnBlinkTimer
);
413 gui_mswin_rm_blink_timer(void)
417 if (blink_timer
!= 0)
419 KillTimer(NULL
, blink_timer
);
420 /* Eat spurious WM_TIMER messages */
421 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
428 * Stop the cursor blinking. Show the cursor if it wasn't shown.
431 gui_mch_stop_blink(void)
433 gui_mswin_rm_blink_timer();
434 if (blink_state
== BLINK_OFF
)
435 gui_update_cursor(TRUE
, FALSE
);
436 blink_state
= BLINK_NONE
;
440 * Start the cursor blinking. If it was already blinking, this restarts the
441 * waiting time and shows the cursor.
444 gui_mch_start_blink(void)
446 gui_mswin_rm_blink_timer();
448 /* Only switch blinking on if none of the times is zero */
449 if (blink_waittime
&& blink_ontime
&& blink_offtime
&& gui
.in_focus
)
451 blink_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)blink_waittime
,
452 (TIMERPROC
)_OnBlinkTimer
);
453 blink_state
= BLINK_ON
;
454 gui_update_cursor(TRUE
, FALSE
);
459 * Call-back routines.
473 TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
475 KillTimer(NULL
, idEvent
);
478 /* Eat spurious WM_TIMER messages */
479 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
481 if (idEvent
== s_wait_timer
)
496 * Convert Unicode character "ch" to bytes in "string[slen]".
497 * When "had_alt" is TRUE the ALT key was included in "ch".
501 char_to_string(int ch
, char_u
*string
, int slen
, int had_alt
)
509 if (os_version
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
)
511 /* On Windows 95/98 we apparently get the character in the active
512 * codepage, not in UCS-2. If conversion is needed convert it to
514 if ((int)GetACP() == enc_codepage
)
515 len
= 0; /* no conversion required */
519 len
= MultiByteToWideChar(GetACP(), 0, string
, 1, wstring
, 2);
530 /* "ch" is a UTF-16 character. Convert it to a string of bytes. When
531 * "enc_codepage" is non-zero use the standard Win32 function,
532 * otherwise use our own conversion function (e.g., for UTF-8). */
533 if (enc_codepage
> 0)
535 len
= WideCharToMultiByte(enc_codepage
, 0, wstring
, len
,
536 string
, slen
, 0, NULL
);
537 /* If we had included the ALT key into the character but now the
538 * upper bit is no longer set, that probably means the conversion
539 * failed. Convert the original character and set the upper bit
541 if (had_alt
&& len
== 1 && ch
>= 0x80 && string
[0] < 0x80)
543 wstring
[0] = ch
& 0x7f;
544 len
= WideCharToMultiByte(enc_codepage
, 0, wstring
, len
,
545 string
, slen
, 0, NULL
);
546 if (len
== 1) /* safety check */
553 ws
= utf16_to_enc(wstring
, &len
);
558 if (len
> slen
) /* just in case */
560 mch_memmove(string
, ws
, len
);
573 for (i
= 0; i
< len
; ++i
)
574 if (string
[i
] == CSI
&& len
<= slen
- 2)
576 /* Insert CSI as K_CSI. */
577 mch_memmove(string
+ i
+ 3, string
+ i
+ 1, len
- i
- 1);
578 string
[++i
] = KS_EXTRA
;
579 string
[++i
] = (int)KE_CSI
;
587 * Key hit, add it to the input buffer.
599 len
= char_to_string(ch
, string
, 40, FALSE
);
600 if (len
== 1 && string
[0] == Ctrl_C
&& ctrl_c_interrupts
)
606 add_to_input_buf(string
, len
);
610 * Alt-Key hit, add it to the input buffer.
619 char_u string
[40]; /* Enough for multibyte character */
622 int ch
= cch
; /* special keys are negative */
624 /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
626 /* OK, we have a character key (given by ch) which was entered with the
627 * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
628 * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
629 * CAPSLOCK is pressed) at this point.
631 modifiers
= MOD_MASK_ALT
;
632 if (GetKeyState(VK_SHIFT
) & 0x8000)
633 modifiers
|= MOD_MASK_SHIFT
;
634 if (GetKeyState(VK_CONTROL
) & 0x8000)
635 modifiers
|= MOD_MASK_CTRL
;
637 ch
= simplify_key(ch
, &modifiers
);
638 /* remove the SHIFT modifier for keys where it's already included, e.g.,
640 if (ch
< 0x100 && !isalpha(ch
) && isprint(ch
))
641 modifiers
&= ~MOD_MASK_SHIFT
;
643 /* Interpret the ALT key as making the key META, include SHIFT, etc. */
644 ch
= extract_modifiers(ch
, &modifiers
);
652 string
[len
++] = KS_MODIFIER
;
653 string
[len
++] = modifiers
;
656 if (IS_SPECIAL((int)ch
))
659 string
[len
++] = K_SECOND((int)ch
);
660 string
[len
++] = K_THIRD((int)ch
);
664 /* Although the documentation isn't clear about it, we assume "ch" is
665 * a Unicode character. */
666 len
+= char_to_string(ch
, string
+ len
, 40 - len
, TRUE
);
669 add_to_input_buf(string
, len
);
680 int vim_modifiers
= 0x0;
682 s_getting_focus
= FALSE
;
684 if (keyFlags
& MK_SHIFT
)
685 vim_modifiers
|= MOUSE_SHIFT
;
686 if (keyFlags
& MK_CONTROL
)
687 vim_modifiers
|= MOUSE_CTRL
;
688 if (GetKeyState(VK_MENU
) & 0x8000)
689 vim_modifiers
|= MOUSE_ALT
;
691 gui_send_mouse_event(button
, x
, y
, repeated_click
, vim_modifiers
);
703 static LONG s_prevTime
= 0;
705 LONG currentTime
= GetMessageTime();
709 /* Give main window the focus: this is so the cursor isn't hollow. */
710 (void)SetFocus(s_hwnd
);
712 if (s_uMsg
== WM_LBUTTONDOWN
|| s_uMsg
== WM_LBUTTONDBLCLK
)
714 else if (s_uMsg
== WM_MBUTTONDOWN
|| s_uMsg
== WM_MBUTTONDBLCLK
)
715 button
= MOUSE_MIDDLE
;
716 else if (s_uMsg
== WM_RBUTTONDOWN
|| s_uMsg
== WM_RBUTTONDBLCLK
)
717 button
= MOUSE_RIGHT
;
718 #ifndef WIN16 /*<VN>*/
719 else if (s_uMsg
== WM_XBUTTONDOWN
|| s_uMsg
== WM_XBUTTONDBLCLK
)
721 #ifndef GET_XBUTTON_WPARAM
722 # define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
724 button
= ((GET_XBUTTON_WPARAM(s_wParam
) == 1) ? MOUSE_X1
: MOUSE_X2
);
726 else if (s_uMsg
== WM_CAPTURECHANGED
)
728 /* on W95/NT4, somehow you get in here with an odd Msg
729 * if you press one button while holding down the other..*/
730 if (s_button_pending
== MOUSE_LEFT
)
731 button
= MOUSE_RIGHT
;
738 repeated_click
= ((int)(currentTime
- s_prevTime
) < p_mouset
);
741 * Holding down the left and right buttons simulates pushing the middle
745 && ((button
== MOUSE_LEFT
&& s_button_pending
== MOUSE_RIGHT
)
746 || (button
== MOUSE_RIGHT
747 && s_button_pending
== MOUSE_LEFT
)))
750 * Hmm, gui.c will ignore more than one button down at a time, so
751 * pretend we let go of it first.
753 gui_send_mouse_event(MOUSE_RELEASE
, x
, y
, FALSE
, 0x0);
754 button
= MOUSE_MIDDLE
;
755 repeated_click
= FALSE
;
756 s_button_pending
= -1;
757 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
759 else if ((repeated_click
)
760 || (mouse_model_popup() && (button
== MOUSE_RIGHT
)))
762 if (s_button_pending
> -1)
764 _OnMouseEvent(s_button_pending
, x
, y
, FALSE
, keyFlags
);
765 s_button_pending
= -1;
767 /* TRACE("Button down at x %d, y %d\n", x, y); */
768 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
773 * If this is the first press (i.e. not a multiple click) don't
774 * action immediately, but store and wait for:
777 * iii) another button press
779 * This enables us to make left+right simulate middle button,
780 * without left or right being actioned first. The side-effect is
781 * that if you click and hold the mouse without dragging, the
782 * cursor doesn't move until you release the button. In practice
783 * this is hardly a problem.
785 s_button_pending
= button
;
788 s_kFlags_pending
= keyFlags
;
791 s_prevTime
= currentTime
;
797 _OnMouseMoveOrRelease(
805 s_getting_focus
= FALSE
;
806 if (s_button_pending
> -1)
808 /* Delayed action for mouse down event */
809 _OnMouseEvent(s_button_pending
, s_x_pending
,
810 s_y_pending
, FALSE
, s_kFlags_pending
);
811 s_button_pending
= -1;
813 if (s_uMsg
== WM_MOUSEMOVE
)
816 * It's only a MOUSE_DRAG if one or more mouse buttons are being held
819 if (!(keyFlags
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
820 | MK_XBUTTON1
| MK_XBUTTON2
)))
822 gui_mouse_moved(x
, y
);
827 * While button is down, keep grabbing mouse move events when
828 * the mouse goes outside the window
830 SetCapture(s_textArea
);
832 /* TRACE(" move at x %d, y %d\n", x, y); */
837 button
= MOUSE_RELEASE
;
838 /* TRACE(" up at x %d, y %d\n", x, y); */
841 _OnMouseEvent(button
, x
, y
, FALSE
, keyFlags
);
846 * Find the vimmenu_T with the given id
853 vimmenu_T
*pChildMenu
;
857 if (pMenu
->id
== (UINT
)id
)
859 if (pMenu
->children
!= NULL
)
861 pChildMenu
= gui_mswin_find_menu(pMenu
->children
, id
);
883 pMenu
= gui_mswin_find_menu(root_menu
, id
);
889 #ifdef MSWIN_FIND_REPLACE
890 # if defined(FEAT_MBYTE) && defined(WIN3264)
892 * copy useful data from structure LPFINDREPLACE to structure LPFINDREPLACEW
895 findrep_atow(LPFINDREPLACEW lpfrw
, LPFINDREPLACE lpfr
)
899 lpfrw
->hwndOwner
= lpfr
->hwndOwner
;
900 lpfrw
->Flags
= lpfr
->Flags
;
902 wp
= enc_to_utf16(lpfr
->lpstrFindWhat
, NULL
);
903 wcsncpy(lpfrw
->lpstrFindWhat
, wp
, lpfrw
->wFindWhatLen
- 1);
906 /* the field "lpstrReplaceWith" doesn't need to be copied */
910 * copy useful data from structure LPFINDREPLACEW to structure LPFINDREPLACE
913 findrep_wtoa(LPFINDREPLACE lpfr
, LPFINDREPLACEW lpfrw
)
917 lpfr
->Flags
= lpfrw
->Flags
;
919 p
= utf16_to_enc(lpfrw
->lpstrFindWhat
, NULL
);
920 vim_strncpy(lpfr
->lpstrFindWhat
, p
, lpfr
->wFindWhatLen
- 1);
923 p
= utf16_to_enc(lpfrw
->lpstrReplaceWith
, NULL
);
924 vim_strncpy(lpfr
->lpstrReplaceWith
, p
, lpfr
->wReplaceWithLen
- 1);
930 * Handle a Find/Replace window message.
938 # if defined(FEAT_MBYTE) && defined(WIN3264)
939 /* If the OS is Windows NT, and 'encoding' differs from active codepage:
940 * convert text from wide string. */
941 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
942 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
944 findrep_wtoa(&s_findrep_struct
, &s_findrep_struct_w
);
948 if (s_findrep_struct
.Flags
& FR_DIALOGTERM
)
949 /* Give main window the focus back. */
950 (void)SetFocus(s_hwnd
);
952 if (s_findrep_struct
.Flags
& FR_FINDNEXT
)
954 flags
= FRD_FINDNEXT
;
956 /* Give main window the focus back: this is so the cursor isn't
958 (void)SetFocus(s_hwnd
);
960 else if (s_findrep_struct
.Flags
& FR_REPLACE
)
964 /* Give main window the focus back: this is so the cursor isn't
966 (void)SetFocus(s_hwnd
);
968 else if (s_findrep_struct
.Flags
& FR_REPLACEALL
)
970 flags
= FRD_REPLACEALL
;
975 /* Call the generic GUI function to do the actual work. */
976 if (s_findrep_struct
.Flags
& FR_WHOLEWORD
)
977 flags
|= FRD_WHOLE_WORD
;
978 if (s_findrep_struct
.Flags
& FR_MATCHCASE
)
979 flags
|= FRD_MATCH_CASE
;
980 down
= (s_findrep_struct
.Flags
& FR_DOWN
) != 0;
981 gui_do_findrepl(flags
, s_findrep_struct
.lpstrFindWhat
,
982 s_findrep_struct
.lpstrReplaceWith
, down
);
988 HandleMouseHide(UINT uMsg
, LPARAM lParam
)
990 static LPARAM last_lParam
= 0L;
992 /* We sometimes get a mousemove when the mouse didn't move... */
993 if (uMsg
== WM_MOUSEMOVE
)
995 if (lParam
== last_lParam
)
997 last_lParam
= lParam
;
1000 /* Handle specially, to centralise coding. We need to be sure we catch all
1001 * possible events which should cause us to restore the cursor (as it is a
1002 * shared resource, we take full responsibility for it).
1009 * blank out the pointer if necessary
1012 gui_mch_mousehide(TRUE
);
1015 case WM_SYSKEYUP
: /* show the pointer when a system-key is pressed */
1017 case WM_MOUSEMOVE
: /* show the pointer on any mouse action */
1018 case WM_LBUTTONDOWN
:
1020 case WM_MBUTTONDOWN
:
1022 case WM_RBUTTONDOWN
:
1024 case WM_XBUTTONDOWN
:
1026 case WM_NCMOUSEMOVE
:
1027 case WM_NCLBUTTONDOWN
:
1028 case WM_NCLBUTTONUP
:
1029 case WM_NCMBUTTONDOWN
:
1030 case WM_NCMBUTTONUP
:
1031 case WM_NCRBUTTONDOWN
:
1032 case WM_NCRBUTTONUP
:
1035 * if the pointer is currently hidden, then we should show it.
1037 gui_mch_mousehide(FALSE
);
1042 static LRESULT CALLBACK
1050 TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
1051 hwnd, uMsg, wParam, lParam);
1054 HandleMouseHide(uMsg
, lParam
);
1061 TrackUserActivity(uMsg
);
1066 HANDLE_MSG(hwnd
, WM_LBUTTONDBLCLK
,_OnMouseButtonDown
);
1067 HANDLE_MSG(hwnd
, WM_LBUTTONDOWN
,_OnMouseButtonDown
);
1068 HANDLE_MSG(hwnd
, WM_LBUTTONUP
, _OnMouseMoveOrRelease
);
1069 HANDLE_MSG(hwnd
, WM_MBUTTONDBLCLK
,_OnMouseButtonDown
);
1070 HANDLE_MSG(hwnd
, WM_MBUTTONDOWN
,_OnMouseButtonDown
);
1071 HANDLE_MSG(hwnd
, WM_MBUTTONUP
, _OnMouseMoveOrRelease
);
1072 HANDLE_MSG(hwnd
, WM_MOUSEMOVE
, _OnMouseMoveOrRelease
);
1073 HANDLE_MSG(hwnd
, WM_PAINT
, _OnPaint
);
1074 HANDLE_MSG(hwnd
, WM_RBUTTONDBLCLK
,_OnMouseButtonDown
);
1075 HANDLE_MSG(hwnd
, WM_RBUTTONDOWN
,_OnMouseButtonDown
);
1076 HANDLE_MSG(hwnd
, WM_RBUTTONUP
, _OnMouseMoveOrRelease
);
1077 #ifndef WIN16 /*<VN>*/
1078 HANDLE_MSG(hwnd
, WM_XBUTTONDBLCLK
,_OnMouseButtonDown
);
1079 HANDLE_MSG(hwnd
, WM_XBUTTONDOWN
,_OnMouseButtonDown
);
1080 HANDLE_MSG(hwnd
, WM_XBUTTONUP
, _OnMouseMoveOrRelease
);
1084 case WM_NOTIFY
: Handle_WM_Notify(hwnd
, (LPNMHDR
)lParam
);
1088 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1092 #if (defined(WIN3264) && defined(FEAT_MBYTE)) \
1093 || defined(GLOBAL_IME) \
1100 vim_WindowProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1103 return global_ime_DefWindowProc(hwnd
, message
, wParam
, lParam
);
1105 if (wide_WindowProc
)
1106 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
1107 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1113 * Called when the foreground or background color has been changed.
1116 gui_mch_new_colors(void)
1118 /* nothing to do? */
1122 * Set the colors to their default values.
1125 gui_mch_def_colors()
1127 gui
.norm_pixel
= GetSysColor(COLOR_WINDOWTEXT
);
1128 gui
.back_pixel
= GetSysColor(COLOR_WINDOW
);
1129 gui
.def_norm_pixel
= gui
.norm_pixel
;
1130 gui
.def_back_pixel
= gui
.back_pixel
;
1134 * Open the GUI window which was created by a call to gui_mch_init().
1139 #ifndef SW_SHOWDEFAULT
1140 # define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
1142 /* Actually open the window, if not already visible
1143 * (may be done already in gui_mch_set_shellsize) */
1144 if (!IsWindowVisible(s_hwnd
))
1145 ShowWindow(s_hwnd
, SW_SHOWDEFAULT
);
1147 #ifdef MSWIN_FIND_REPLACE
1148 /* Init replace string here, so that we keep it when re-opening the
1150 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1157 * Get the position of the top left corner of the window.
1160 gui_mch_get_winpos(int *x
, int *y
)
1164 GetWindowRect(s_hwnd
, &rect
);
1171 * Set the position of the top left corner of the window to the given
1175 gui_mch_set_winpos(int x
, int y
)
1177 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1178 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1181 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
1183 static int oldx
= 0;
1184 static int oldy
= 0;
1186 SetWindowPos(s_textArea
, NULL
, x
, y
, w
, h
, SWP_NOZORDER
| SWP_NOACTIVATE
);
1189 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1190 SendMessage(s_toolbarhwnd
, WM_SIZE
,
1191 (WPARAM
)0, (LPARAM
)(w
+ ((long)(TOOLBAR_BUTTON_HEIGHT
+8)<<16)));
1193 #if defined(FEAT_GUI_TABLINE)
1194 if (showing_tabline
)
1199 # ifdef FEAT_TOOLBAR
1200 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1201 top
= TOOLBAR_BUTTON_HEIGHT
+ TOOLBAR_BORDER_HEIGHT
;
1203 GetClientRect(s_hwnd
, &rect
);
1204 MoveWindow(s_tabhwnd
, 0, top
, rect
.right
, gui
.tabline_height
, TRUE
);
1208 /* When side scroll bar is unshown, the size of window will change.
1209 * then, the text area move left or right. thus client rect should be
1210 * forcely redraw. (Yasuhiro Matsumoto) */
1211 if (oldx
!= x
|| oldy
!= y
)
1213 InvalidateRect(s_hwnd
, NULL
, FALSE
);
1225 gui_mch_enable_scrollbar(
1229 ShowScrollBar(sb
->id
, SB_CTL
, flag
);
1231 /* TODO: When the window is maximized, the size of the window stays the
1232 * same, thus the size of the text area changes. On Win98 it's OK, on Win
1233 * NT 4.0 it's not... */
1237 gui_mch_set_scrollbar_pos(
1244 SetWindowPos(sb
->id
, NULL
, x
, y
, w
, h
,
1245 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1249 gui_mch_create_scrollbar(
1251 int orient
) /* SBAR_VERT or SBAR_HORIZ */
1253 sb
->id
= CreateWindow(
1254 "SCROLLBAR", "Scrollbar",
1255 WS_CHILD
| ((orient
== SBAR_VERT
) ? SBS_VERT
: SBS_HORZ
), 0, 0,
1256 10, /* Any value will do for now */
1257 10, /* Any value will do for now */
1263 * Find the scrollbar with the given hwnd.
1265 static scrollbar_T
*
1266 gui_mswin_find_scrollbar(HWND hwnd
)
1270 if (gui
.bottom_sbar
.id
== hwnd
)
1271 return &gui
.bottom_sbar
;
1274 if (wp
->w_scrollbars
[SBAR_LEFT
].id
== hwnd
)
1275 return &wp
->w_scrollbars
[SBAR_LEFT
];
1276 if (wp
->w_scrollbars
[SBAR_RIGHT
].id
== hwnd
)
1277 return &wp
->w_scrollbars
[SBAR_RIGHT
];
1283 * Get the character size of a font.
1286 GetFontSize(GuiFont font
)
1288 HWND hwnd
= GetDesktopWindow();
1289 HDC hdc
= GetWindowDC(hwnd
);
1290 HFONT hfntOld
= SelectFont(hdc
, (HFONT
)font
);
1293 GetTextMetrics(hdc
, &tm
);
1294 gui
.char_width
= tm
.tmAveCharWidth
+ tm
.tmOverhang
;
1296 gui
.char_height
= tm
.tmHeight
1297 #ifndef MSWIN16_FASTTEXT
1302 SelectFont(hdc
, hfntOld
);
1304 ReleaseDC(hwnd
, hdc
);
1308 * Adjust gui.char_height (after 'linespace' was changed).
1311 gui_mch_adjust_charheight(void)
1313 GetFontSize(gui
.norm_font
);
1318 get_font_handle(LOGFONT
*lf
)
1323 font
= CreateFontIndirect(lf
);
1328 return (GuiFont
)font
;
1332 pixels_to_points(int pixels
, int vertical
)
1338 hwnd
= GetDesktopWindow();
1339 hdc
= GetWindowDC(hwnd
);
1341 points
= MulDiv(pixels
, 72,
1342 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
));
1344 ReleaseDC(hwnd
, hdc
);
1352 int giveErrorIfMissing
)
1355 GuiFont font
= NOFONT
;
1357 if (get_logfont(&lf
, name
, NULL
, giveErrorIfMissing
) == OK
)
1358 font
= get_font_handle(&lf
);
1359 if (font
== NOFONT
&& giveErrorIfMissing
)
1360 EMSG2(_(e_font
), name
);
1364 #if defined(FEAT_EVAL) || defined(PROTO)
1366 * Return the name of font "font" in allocated memory.
1367 * Don't know how to get the actual name, thus use the provided name.
1371 gui_mch_get_fontname(font
, name
)
1377 return vim_strsave(name
);
1382 gui_mch_free_font(GuiFont font
)
1385 DeleteObject((HFONT
)font
);
1394 if (c
>= 'a' && c
<= 'f')
1395 return c
- 'a' + 10;
1399 * Return the Pixel value (color) for the given color name.
1400 * Return INVALCOLOR for error.
1403 gui_mch_get_color(char_u
*name
)
1405 typedef struct guicolor_tTable
1411 static guicolor_tTable table
[] =
1413 {"Black", RGB(0x00, 0x00, 0x00)},
1414 {"DarkGray", RGB(0x80, 0x80, 0x80)},
1415 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
1416 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
1417 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
1418 {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
1419 {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
1420 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
1421 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
1422 {"Gray20", RGB(0x33, 0x33, 0x33)},
1423 {"Grey20", RGB(0x33, 0x33, 0x33)},
1424 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
1425 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
1426 {"Gray40", RGB(0x66, 0x66, 0x66)},
1427 {"Grey40", RGB(0x66, 0x66, 0x66)},
1428 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
1429 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
1430 {"Gray60", RGB(0x99, 0x99, 0x99)},
1431 {"Grey60", RGB(0x99, 0x99, 0x99)},
1432 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
1433 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
1434 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
1435 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
1436 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
1437 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
1438 {"White", RGB(0xFF, 0xFF, 0xFF)},
1439 {"DarkRed", RGB(0x80, 0x00, 0x00)},
1440 {"Red", RGB(0xFF, 0x00, 0x00)},
1441 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
1442 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
1443 {"Blue", RGB(0x00, 0x00, 0xFF)},
1444 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
1445 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
1446 {"Green", RGB(0x00, 0xFF, 0x00)},
1447 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
1448 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
1449 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
1450 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
1451 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
1452 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
1453 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
1454 {"Brown", RGB(0x80, 0x40, 0x40)},
1455 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
1456 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
1457 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
1458 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
1459 {"Orange", RGB(0xFF, 0xA5, 0x00)},
1460 {"Purple", RGB(0xA0, 0x20, 0xF0)},
1461 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
1462 {"Violet", RGB(0xEE, 0x82, 0xEE)},
1465 typedef struct SysColorTable
1471 static SysColorTable sys_table
[] =
1474 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW
},
1475 {"SYS_3DHILIGHT", COLOR_3DHILIGHT
},
1477 {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT
},
1479 {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT
},
1480 {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT
},
1481 {"SYS_3DLIGHT", COLOR_3DLIGHT
},
1482 {"SYS_3DSHADOW", COLOR_3DSHADOW
},
1483 {"SYS_DESKTOP", COLOR_DESKTOP
},
1484 {"SYS_INFOBK", COLOR_INFOBK
},
1485 {"SYS_INFOTEXT", COLOR_INFOTEXT
},
1486 {"SYS_3DFACE", COLOR_3DFACE
},
1488 {"SYS_BTNFACE", COLOR_BTNFACE
},
1489 {"SYS_BTNSHADOW", COLOR_BTNSHADOW
},
1490 {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER
},
1491 {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION
},
1492 {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE
},
1493 {"SYS_BACKGROUND", COLOR_BACKGROUND
},
1494 {"SYS_BTNTEXT", COLOR_BTNTEXT
},
1495 {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT
},
1496 {"SYS_GRAYTEXT", COLOR_GRAYTEXT
},
1497 {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT
},
1498 {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT
},
1499 {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER
},
1500 {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION
},
1501 {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT
},
1502 {"SYS_MENU", COLOR_MENU
},
1503 {"SYS_MENUTEXT", COLOR_MENUTEXT
},
1504 {"SYS_SCROLLBAR", COLOR_SCROLLBAR
},
1505 {"SYS_WINDOW", COLOR_WINDOW
},
1506 {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME
},
1507 {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT
}
1513 if (name
[0] == '#' && strlen(name
) == 7)
1515 /* Name is in "#rrggbb" format */
1516 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
1517 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
1518 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
1519 if (r
< 0 || g
< 0 || b
< 0)
1521 return RGB(r
, g
, b
);
1525 /* Check if the name is one of the colors we know */
1526 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
1527 if (STRICMP(name
, table
[i
].name
) == 0)
1528 return table
[i
].color
;
1532 * Try to look up a system colour.
1534 for (i
= 0; i
< sizeof(sys_table
) / sizeof(sys_table
[0]); i
++)
1535 if (STRICMP(name
, sys_table
[i
].name
) == 0)
1536 return GetSysColor(sys_table
[i
].color
);
1539 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
1542 #define LINE_LEN 100
1544 char line
[LINE_LEN
];
1547 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
1551 fd
= mch_fopen((char *)fname
, "rt");
1562 fgets(line
, LINE_LEN
, fd
);
1563 len
= (int)STRLEN(line
);
1565 if (len
<= 1 || line
[len
-1] != '\n')
1570 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
1576 if (STRICMP(color
, name
) == 0)
1579 return (guicolor_T
) RGB(r
, g
, b
);
1589 * Return OK if the key with the termcap name "name" is supported.
1592 gui_mch_haskey(char_u
*name
)
1596 for (i
= 0; special_keys
[i
].vim_code1
!= NUL
; i
++)
1597 if (name
[0] == special_keys
[i
].vim_code0
&&
1598 name
[1] == special_keys
[i
].vim_code1
)
1609 * Invert a rectangle from row r, column c, for nr rows and nc columns.
1612 gui_mch_invert_rectangle(
1621 * Note: InvertRect() excludes right and bottom of rectangle.
1623 rc
.left
= FILL_X(c
);
1625 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
1626 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
1627 InvertRect(s_hdc
, &rc
);
1631 * Iconify the GUI window.
1634 gui_mch_iconify(void)
1636 ShowWindow(s_hwnd
, SW_MINIMIZE
);
1640 * Draw a cursor without focus.
1643 gui_mch_draw_hollow_cursor(guicolor_T color
)
1649 * Note: FrameRect() excludes right and bottom of rectangle.
1651 rc
.left
= FILL_X(gui
.col
);
1652 rc
.top
= FILL_Y(gui
.row
);
1653 rc
.right
= rc
.left
+ gui
.char_width
;
1655 if (mb_lefthalve(gui
.row
, gui
.col
))
1656 rc
.right
+= gui
.char_width
;
1658 rc
.bottom
= rc
.top
+ gui
.char_height
;
1659 hbr
= CreateSolidBrush(color
);
1660 FrameRect(s_hdc
, &rc
, hbr
);
1664 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1668 gui_mch_draw_part_cursor(
1677 * Note: FillRect() excludes right and bottom of rectangle.
1680 #ifdef FEAT_RIGHTLEFT
1681 /* vertical line should be on the right of current point */
1682 CURSOR_BAR_RIGHT
? FILL_X(gui
.col
+ 1) - w
:
1685 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
1686 rc
.right
= rc
.left
+ w
;
1687 rc
.bottom
= rc
.top
+ h
;
1688 hbr
= CreateSolidBrush(color
);
1689 FillRect(s_hdc
, &rc
, hbr
);
1694 * Process a single Windows message.
1695 * If one is not available we hang until one is.
1698 process_message(void)
1701 UINT vk
= 0; /* Virtual key */
1707 static char_u k10
[] = {K_SPECIAL
, 'k', ';', 0};
1710 GetMessage(&msg
, NULL
, 0, 0);
1713 /* Look after OLE Automation commands */
1714 if (msg
.message
== WM_OLE
)
1716 char_u
*str
= (char_u
*)msg
.lParam
;
1717 if (str
== NULL
|| *str
== NUL
)
1719 /* Message can't be ours, forward it. Fixes problem with Ultramon
1721 DispatchMessage(&msg
);
1725 add_to_input_buf(str
, (int)STRLEN(str
));
1726 vim_free(str
); /* was allocated in CVim::SendKeys() */
1732 #ifdef FEAT_NETBEANS_INTG
1733 if (msg
.message
== WM_NETBEANS
)
1735 messageFromNetbeansW32();
1741 if (sniff_request_waiting
&& want_sniff_request
)
1743 static char_u bytes
[3] = {CSI
, (char_u
)KS_EXTRA
, (char_u
)KE_SNIFF
};
1744 add_to_input_buf(bytes
, 3); /* K_SNIFF */
1745 sniff_request_waiting
= 0;
1746 want_sniff_request
= 0;
1747 /* request is handled in normal.c */
1749 if (msg
.message
== WM_USER
)
1751 MyTranslateMessage(&msg
);
1752 DispatchMessage(&msg
);
1757 #ifdef MSWIN_FIND_REPLACE
1758 /* Don't process messages used by the dialog */
1759 if (s_findrep_hwnd
!= NULL
&& IsDialogMessage(s_findrep_hwnd
, &msg
))
1761 HandleMouseHide(msg
.message
, msg
.lParam
);
1767 * Check if it's a special key that we recognise. If not, call
1768 * TranslateMessage().
1770 if (msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_SYSKEYDOWN
)
1772 vk
= (int) msg
.wParam
;
1773 /* handle key after dead key, but ignore shift, alt and control */
1774 if (dead_key
&& vk
!= VK_SHIFT
&& vk
!= VK_MENU
&& vk
!= VK_CONTROL
)
1777 /* handle non-alphabetic keys (ones that hopefully cannot generate
1778 * umlaut-characters), unless when control is down */
1779 if (vk
< 'A' || vk
> 'Z' || (GetKeyState(VK_CONTROL
) & 0x8000))
1783 dm
.message
= msg
.message
;
1785 dm
.wParam
= VK_SPACE
;
1786 MyTranslateMessage(&dm
); /* generate dead character */
1787 if (vk
!= VK_SPACE
) /* and send current character once more */
1788 PostMessage(msg
.hwnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
1793 /* Check for CTRL-BREAK */
1794 if (vk
== VK_CANCEL
)
1799 add_to_input_buf(string
, 1);
1802 for (i
= 0; special_keys
[i
].key_sym
!= 0; i
++)
1804 /* ignore VK_SPACE when ALT key pressed: system menu */
1805 if (special_keys
[i
].key_sym
== vk
1806 && (vk
!= VK_SPACE
|| !(GetKeyState(VK_MENU
) & 0x8000)))
1809 /* Check for <F10>: Windows selects the menu. When <F10> is
1810 * mapped we want to use the mapping instead. */
1812 && gui
.menu_is_active
1813 && check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1816 if (GetKeyState(VK_SHIFT
) & 0x8000)
1817 modifiers
|= MOD_MASK_SHIFT
;
1819 * Don't use caps-lock as shift, because these are special keys
1820 * being considered here, and we only want letters to get
1824 if (GetKeyState(VK_CAPITAL) & 0x0001)
1825 modifiers ^= MOD_MASK_SHIFT;
1827 if (GetKeyState(VK_CONTROL
) & 0x8000)
1828 modifiers
|= MOD_MASK_CTRL
;
1829 if (GetKeyState(VK_MENU
) & 0x8000)
1830 modifiers
|= MOD_MASK_ALT
;
1832 if (special_keys
[i
].vim_code1
== NUL
)
1833 key
= special_keys
[i
].vim_code0
;
1835 key
= TO_SPECIAL(special_keys
[i
].vim_code0
,
1836 special_keys
[i
].vim_code1
);
1837 key
= simplify_key(key
, &modifiers
);
1844 string
[1] = KS_MODIFIER
;
1845 string
[2] = modifiers
;
1846 add_to_input_buf(string
, 3);
1849 if (IS_SPECIAL(key
))
1852 string
[1] = K_SECOND(key
);
1853 string
[2] = K_THIRD(key
);
1854 add_to_input_buf(string
, 3);
1860 /* Handle "key" as a Unicode character. */
1861 len
= char_to_string(key
, string
, 40, FALSE
);
1862 add_to_input_buf(string
, len
);
1867 if (special_keys
[i
].key_sym
== 0)
1869 /* Some keys need C-S- where they should only need C-.
1870 * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1871 * system startup (Helmut Stiegler, 2003 Oct 3). */
1873 && (GetKeyState(VK_CONTROL
) & 0x8000)
1874 && !(GetKeyState(VK_SHIFT
) & 0x8000)
1875 && !(GetKeyState(VK_MENU
) & 0x8000))
1877 /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1878 if (vk
== '6' || MapVirtualKey(vk
, 2) == (UINT
)'^')
1880 string
[0] = Ctrl_HAT
;
1881 add_to_input_buf(string
, 1);
1883 /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
1884 else if (vk
== 0xBD) /* QWERTY for CTRL-'-' */
1887 add_to_input_buf(string
, 1);
1889 /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
1890 else if (vk
== '2' || MapVirtualKey(vk
, 2) == (UINT
)'@')
1892 string
[0] = Ctrl_AT
;
1893 add_to_input_buf(string
, 1);
1896 MyTranslateMessage(&msg
);
1899 MyTranslateMessage(&msg
);
1902 #ifdef FEAT_MBYTE_IME
1903 else if (msg
.message
== WM_IME_NOTIFY
)
1904 _OnImeNotify(msg
.hwnd
, (DWORD
)msg
.wParam
, (DWORD
)msg
.lParam
);
1905 else if (msg
.message
== WM_KEYUP
&& im_get_status())
1906 /* added for non-MS IME (Yasuhiro Matsumoto) */
1907 MyTranslateMessage(&msg
);
1909 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
1911 else if (msg
.message
== WM_IME_STARTCOMPOSITION
)
1915 global_ime_set_font(&norm_logfont
);
1916 point
.x
= FILL_X(gui
.col
);
1917 point
.y
= FILL_Y(gui
.row
);
1918 MapWindowPoints(s_textArea
, s_hwnd
, &point
, 1);
1919 global_ime_set_position(&point
);
1924 /* Check for <F10>: Default effect is to select the menu. When <F10> is
1925 * mapped we need to stop it here to avoid strange effects (e.g., for the
1927 if (vk
!= VK_F10
|| check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1929 DispatchMessage(&msg
);
1933 * Catch up with any queued events. This may put keyboard input into the
1934 * input buffer, call resize call-backs, trigger timers etc. If there is
1935 * nothing in the event queue (& no timers pending), then we return
1939 gui_mch_update(void)
1943 if (!s_busy_processing
)
1944 while (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
)
1945 && !vim_is_input_buf_full())
1950 * GUI input routine called by gui_wait_for_chars(). Waits for a character
1951 * from the keyboard.
1952 * wtime == -1 Wait forever.
1953 * wtime == 0 This should never happen.
1954 * wtime > 0 Wait wtime milliseconds for a character.
1955 * Returns OK if a character was found to be available within the given time,
1956 * or FAIL otherwise.
1959 gui_mch_wait_for_chars(int wtime
)
1964 s_timed_out
= FALSE
;
1968 /* Don't do anything while processing a (scroll) message. */
1969 if (s_busy_processing
)
1971 s_wait_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)wtime
,
1972 (TIMERPROC
)_OnTimer
);
1975 allow_scrollbar
= TRUE
;
1977 focus
= gui
.in_focus
;
1978 while (!s_timed_out
)
1980 /* Stop or start blinking when focus changes */
1981 if (gui
.in_focus
!= focus
)
1984 gui_mch_start_blink();
1986 gui_mch_stop_blink();
1987 focus
= gui
.in_focus
;
1990 if (s_need_activate
)
1993 (void)SetForegroundWindow(s_hwnd
);
1995 (void)SetActiveWindow(s_hwnd
);
1997 s_need_activate
= FALSE
;
2000 #ifdef FEAT_NETBEANS_INTG
2001 /* Process the queued netbeans messages. */
2002 netbeans_parse_messages();
2006 * Don't use gui_mch_update() because then we will spin-lock until a
2007 * char arrives, instead we use GetMessage() to hang until an
2008 * event arrives. No need to check for input_buf_full because we are
2009 * returning as soon as it contains a single char -- webb
2013 if (input_available())
2015 if (s_wait_timer
!= 0 && !s_timed_out
)
2017 KillTimer(NULL
, s_wait_timer
);
2019 /* Eat spurious WM_TIMER messages */
2020 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
2024 allow_scrollbar
= FALSE
;
2026 /* Clear pending mouse button, the release event may have been
2027 * taken by the dialog window. But don't do this when getting
2028 * focus, we need the mouse-up event then. */
2029 if (!s_getting_focus
)
2030 s_button_pending
= -1;
2035 allow_scrollbar
= FALSE
;
2040 * Clear a rectangular region of the screen from text pos (row1, col1) to
2041 * (row2, col2) inclusive.
2044 gui_mch_clear_block(
2053 * Clear one extra pixel at the far right, for when bold characters have
2054 * spilled over to the window border.
2055 * Note: FillRect() excludes right and bottom of rectangle.
2057 rc
.left
= FILL_X(col1
);
2058 rc
.top
= FILL_Y(row1
);
2059 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
2060 rc
.bottom
= FILL_Y(row2
+ 1);
2065 * Clear the whole text window.
2068 gui_mch_clear_all(void)
2074 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
2075 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
2083 gui_mch_enable_menu(int flag
)
2086 SetMenu(s_hwnd
, flag
? s_menuBar
: NULL
);
2092 gui_mch_set_menu_pos(
2098 /* It will be in the right place anyway */
2101 #if defined(FEAT_MENU) || defined(PROTO)
2103 * Make menu item hidden or not hidden
2106 gui_mch_menu_hidden(
2111 * This doesn't do what we want. Hmm, just grey the menu items for now.
2115 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2117 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2119 gui_mch_menu_grey(menu
, hidden
);
2123 * This is called after setting all the menus to grey/hidden or not.
2126 gui_mch_draw_menubar(void)
2128 DrawMenuBar(s_hwnd
);
2130 #endif /*FEAT_MENU*/
2138 SaveInst(HINSTANCE hInst
)
2145 * Return the RGB value of a pixel as a long.
2148 gui_mch_get_rgb(guicolor_T pixel
)
2150 return (GetRValue(pixel
) << 16) + (GetGValue(pixel
) << 8)
2154 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2155 /* Convert pixels in X to dialog units */
2157 PixelToDialogX(int numPixels
)
2159 return (WORD
)((numPixels
* 4) / s_dlgfntwidth
);
2162 /* Convert pixels in Y to dialog units */
2164 PixelToDialogY(int numPixels
)
2166 return (WORD
)((numPixels
* 8) / s_dlgfntheight
);
2169 /* Return the width in pixels of the given text in the given DC. */
2171 GetTextWidth(HDC hdc
, char_u
*str
, int len
)
2175 GetTextExtentPoint(hdc
, str
, len
, &size
);
2181 * Return the width in pixels of the given text in the given DC, taking care
2182 * of 'encoding' to active codepage conversion.
2185 GetTextWidthEnc(HDC hdc
, char_u
*str
, int len
)
2192 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2194 /* 'encoding' differs from active codepage: convert text and use wide
2196 wstr
= enc_to_utf16(str
, &wlen
);
2199 n
= GetTextExtentPointW(hdc
, wstr
, wlen
, &size
);
2206 return GetTextWidth(hdc
, str
, len
);
2209 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
2213 * A quick little routine that will center one window over another, handy for
2214 * dialog boxes. Taken from the Win32SDK samples.
2221 RECT rChild
, rParent
;
2222 int wChild
, hChild
, wParent
, hParent
;
2223 int wScreen
, hScreen
, xNew
, yNew
;
2226 GetWindowRect(hwndChild
, &rChild
);
2227 wChild
= rChild
.right
- rChild
.left
;
2228 hChild
= rChild
.bottom
- rChild
.top
;
2230 /* If Vim is minimized put the window in the middle of the screen. */
2231 if (hwndParent
== NULL
|| IsMinimized(hwndParent
))
2236 rParent
.right
= GetSystemMetrics(SM_CXSCREEN
);
2237 rParent
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
2239 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rParent
, 0);
2243 GetWindowRect(hwndParent
, &rParent
);
2244 wParent
= rParent
.right
- rParent
.left
;
2245 hParent
= rParent
.bottom
- rParent
.top
;
2247 hdc
= GetDC(hwndChild
);
2248 wScreen
= GetDeviceCaps (hdc
, HORZRES
);
2249 hScreen
= GetDeviceCaps (hdc
, VERTRES
);
2250 ReleaseDC(hwndChild
, hdc
);
2252 xNew
= rParent
.left
+ ((wParent
- wChild
) /2);
2257 else if ((xNew
+wChild
) > wScreen
)
2259 xNew
= wScreen
- wChild
;
2262 yNew
= rParent
.top
+ ((hParent
- hChild
) /2);
2265 else if ((yNew
+hChild
) > hScreen
)
2266 yNew
= hScreen
- hChild
;
2268 return SetWindowPos(hwndChild
, NULL
, xNew
, yNew
, 0, 0,
2269 SWP_NOSIZE
| SWP_NOZORDER
);
2271 #endif /* FEAT_GUI_DIALOG */
2274 gui_mch_activate_window(void)
2276 (void)SetActiveWindow(s_hwnd
);
2279 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2281 gui_mch_show_toolbar(int showit
)
2283 if (s_toolbarhwnd
== NULL
)
2289 # ifndef TB_SETUNICODEFORMAT
2290 /* For older compilers. We assume this never changes. */
2291 # define TB_SETUNICODEFORMAT 0x2005
2293 /* Enable/disable unicode support */
2294 int uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2295 SendMessage(s_toolbarhwnd
, TB_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2297 ShowWindow(s_toolbarhwnd
, SW_SHOW
);
2300 ShowWindow(s_toolbarhwnd
, SW_HIDE
);
2303 /* Then number of bitmaps is fixed. Exit is missing! */
2304 #define TOOLBAR_BITMAP_COUNT 31
2308 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2310 add_tabline_popup_menu_entry(HMENU pmenu
, UINT item_id
, char_u
*item_text
)
2316 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2318 /* 'encoding' differs from active codepage: convert menu name
2319 * and use wide function */
2320 wn
= enc_to_utf16(item_text
, NULL
);
2323 MENUITEMINFOW infow
;
2325 infow
.cbSize
= sizeof(infow
);
2326 infow
.fMask
= MIIM_TYPE
| MIIM_ID
;
2327 infow
.wID
= item_id
;
2328 infow
.fType
= MFT_STRING
;
2329 infow
.dwTypeData
= wn
;
2330 infow
.cch
= (UINT
)wcslen(wn
);
2331 n
= InsertMenuItemW(pmenu
, item_id
, FALSE
, &infow
);
2333 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2334 /* Failed, try using non-wide function. */
2344 info
.cbSize
= sizeof(info
);
2345 info
.fMask
= MIIM_TYPE
| MIIM_ID
;
2347 info
.fType
= MFT_STRING
;
2348 info
.dwTypeData
= item_text
;
2349 info
.cch
= (UINT
)STRLEN(item_text
);
2350 InsertMenuItem(pmenu
, item_id
, FALSE
, &info
);
2355 show_tabline_popup_menu(void)
2361 /* When ignoring events don't show the menu. */
2369 tab_pmenu
= CreatePopupMenu();
2370 if (tab_pmenu
== NULL
)
2373 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_CLOSE
, _("Close tab"));
2374 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_NEW
, _("New tab"));
2375 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_OPEN
,
2379 rval
= TrackPopupMenuEx(tab_pmenu
, TPM_RETURNCMD
, pt
.x
, pt
.y
, s_tabhwnd
,
2382 DestroyMenu(tab_pmenu
);
2384 /* Add the string cmd into input buffer */
2387 TCHITTESTINFO htinfo
;
2390 if (ScreenToClient(s_tabhwnd
, &pt
) == 0)
2395 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
2401 send_tabline_menu_event(idx
, (int)rval
);
2406 * Show or hide the tabline.
2409 gui_mch_show_tabline(int showit
)
2411 if (s_tabhwnd
== NULL
)
2414 if (!showit
!= !showing_tabline
)
2417 ShowWindow(s_tabhwnd
, SW_SHOW
);
2419 ShowWindow(s_tabhwnd
, SW_HIDE
);
2420 showing_tabline
= showit
;
2425 * Return TRUE when tabline is displayed.
2428 gui_mch_showing_tabline(void)
2430 return s_tabhwnd
!= NULL
&& showing_tabline
;
2434 * Update the labels of the tabline.
2437 gui_mch_update_tabline(void)
2445 static int use_unicode
= FALSE
;
2450 if (s_tabhwnd
== NULL
)
2453 #if defined(FEAT_MBYTE)
2454 # ifndef CCM_SETUNICODEFORMAT
2455 /* For older compilers. We assume this never changes. */
2456 # define CCM_SETUNICODEFORMAT 0x2005
2458 uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2459 if (uu
!= use_unicode
)
2461 /* Enable/disable unicode support */
2462 SendMessage(s_tabhwnd
, CCM_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2467 tie
.mask
= TCIF_TEXT
;
2470 /* Add a label for each tab page. They all contain the same text area. */
2471 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
2476 if (!TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2479 tie
.pszText
= "-Empty-";
2480 TabCtrl_InsertItem(s_tabhwnd
, nr
, &tie
);
2483 get_tabline_label(tp
, FALSE
);
2484 tie
.pszText
= NameBuff
;
2489 /* Need to go through Unicode. */
2490 wstr
= enc_to_utf16(NameBuff
, NULL
);
2495 tiw
.mask
= TCIF_TEXT
;
2498 SendMessage(s_tabhwnd
, TCM_SETITEMW
, (WPARAM
)nr
, (LPARAM
)&tiw
);
2505 TabCtrl_SetItem(s_tabhwnd
, nr
, &tie
);
2509 /* Remove any old labels. */
2510 while (TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2511 TabCtrl_DeleteItem(s_tabhwnd
, nr
);
2513 if (TabCtrl_GetCurSel(s_tabhwnd
) != curtabidx
)
2514 TabCtrl_SetCurSel(s_tabhwnd
, curtabidx
);
2518 * Set the current tab to "nr". First tab is 1.
2521 gui_mch_set_curtab(nr
)
2524 if (s_tabhwnd
== NULL
)
2527 if (TabCtrl_GetCurSel(s_tabhwnd
) != nr
-1)
2528 TabCtrl_SetCurSel(s_tabhwnd
, nr
-1);
2534 * ":simalt" command.
2537 ex_simalt(exarg_T
*eap
)
2539 char_u
*keys
= eap
->arg
;
2541 PostMessage(s_hwnd
, WM_SYSCOMMAND
, (WPARAM
)SC_KEYMENU
, (LPARAM
)0);
2545 *keys
= ' '; /* for showing system menu */
2546 PostMessage(s_hwnd
, WM_CHAR
, (WPARAM
)*keys
, (LPARAM
)0);
2552 * Create the find & replace dialogs.
2553 * You can't have both at once: ":find" when replace is showing, destroys
2554 * the replace dialog first, and the other way around.
2556 #ifdef MSWIN_FIND_REPLACE
2558 initialise_findrep(char_u
*initial_string
)
2564 /* Get the search string to use. */
2565 entry_text
= get_find_dialog_text(initial_string
, &wword
, &mcase
);
2567 s_findrep_struct
.hwndOwner
= s_hwnd
;
2568 s_findrep_struct
.Flags
= FR_DOWN
;
2570 s_findrep_struct
.Flags
|= FR_MATCHCASE
;
2572 s_findrep_struct
.Flags
|= FR_WHOLEWORD
;
2573 if (entry_text
!= NULL
&& *entry_text
!= NUL
)
2574 vim_strncpy(s_findrep_struct
.lpstrFindWhat
, entry_text
,
2575 s_findrep_struct
.wFindWhatLen
- 1);
2576 vim_free(entry_text
);
2581 set_window_title(HWND hwnd
, char *title
)
2584 if (title
!= NULL
&& enc_codepage
>= 0 && enc_codepage
!= (int)GetACP())
2589 /* Convert the title from 'encoding' to UTF-16. */
2590 wbuf
= (WCHAR
*)enc_to_utf16((char_u
*)title
, NULL
);
2593 n
= SetWindowTextW(hwnd
, wbuf
);
2595 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2597 /* Retry with non-wide function (for Windows 98). */
2601 (void)SetWindowText(hwnd
, (LPCSTR
)title
);
2605 gui_mch_find_dialog(exarg_T
*eap
)
2607 #ifdef MSWIN_FIND_REPLACE
2608 if (s_findrep_msg
!= 0)
2610 if (IsWindow(s_findrep_hwnd
) && !s_findrep_is_find
)
2611 DestroyWindow(s_findrep_hwnd
);
2613 if (!IsWindow(s_findrep_hwnd
))
2615 initialise_findrep(eap
->arg
);
2616 # if defined(FEAT_MBYTE) && defined(WIN3264)
2617 /* If the OS is Windows NT, and 'encoding' differs from active
2618 * codepage: convert text and use wide function. */
2619 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2620 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2622 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2623 s_findrep_hwnd
= FindTextW(
2624 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2628 s_findrep_hwnd
= FindText((LPFINDREPLACE
) &s_findrep_struct
);
2631 set_window_title(s_findrep_hwnd
,
2632 _("Find string (use '\\\\' to find a '\\')"));
2633 (void)SetFocus(s_findrep_hwnd
);
2635 s_findrep_is_find
= TRUE
;
2642 gui_mch_replace_dialog(exarg_T
*eap
)
2644 #ifdef MSWIN_FIND_REPLACE
2645 if (s_findrep_msg
!= 0)
2647 if (IsWindow(s_findrep_hwnd
) && s_findrep_is_find
)
2648 DestroyWindow(s_findrep_hwnd
);
2650 if (!IsWindow(s_findrep_hwnd
))
2652 initialise_findrep(eap
->arg
);
2653 # if defined(FEAT_MBYTE) && defined(WIN3264)
2654 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2655 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2657 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2658 s_findrep_hwnd
= ReplaceTextW(
2659 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2663 s_findrep_hwnd
= ReplaceText(
2664 (LPFINDREPLACE
) &s_findrep_struct
);
2667 set_window_title(s_findrep_hwnd
,
2668 _("Find & Replace (use '\\\\' to find a '\\')"));
2669 (void)SetFocus(s_findrep_hwnd
);
2671 s_findrep_is_find
= FALSE
;
2678 * Set visibility of the pointer.
2681 gui_mch_mousehide(int hide
)
2683 if (hide
!= gui
.pointer_hidden
)
2686 gui
.pointer_hidden
= hide
;
2692 gui_mch_show_popupmenu_at(vimmenu_T
*menu
, int x
, int y
)
2694 /* Unhide the mouse, we don't get move events here. */
2695 gui_mch_mousehide(FALSE
);
2697 (void)TrackPopupMenu(
2698 (HMENU
)menu
->submenu_id
,
2699 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2701 (int)0, /*reserved param*/
2705 * NOTE: The pop-up menu can eat the mouse up event.
2706 * We deal with this in normal.c.
2712 * Got a message when the system will go down.
2717 getout_preserve_modified(1);
2721 * Get this message when the user clicks on the cross in the top right corner
2722 * of a Windows95 window.
2733 * Get a message when the window is being destroyed.
2740 Ctl3dUnregister(s_hinst
);
2750 if (!IsMinimized(hwnd
))
2754 out_flush(); /* make sure all output has been processed */
2755 (void)BeginPaint(hwnd
, &ps
);
2758 /* prevent multi-byte characters from misprinting on an invalid
2764 GetClientRect(hwnd
, &rect
);
2765 ps
.rcPaint
.left
= rect
.left
;
2766 ps
.rcPaint
.right
= rect
.right
;
2770 if (!IsRectEmpty(&ps
.rcPaint
))
2771 gui_redraw(ps
.rcPaint
.left
, ps
.rcPaint
.top
,
2772 ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1,
2773 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1);
2774 EndPaint(hwnd
, &ps
);
2786 if (!IsMinimized(hwnd
))
2788 gui_resize_shell(cx
, cy
);
2791 /* Menu bar may wrap differently now */
2792 gui_mswin_get_menu_height(TRUE
);
2802 gui_focus_change(TRUE
);
2803 s_getting_focus
= TRUE
;
2804 (void)MyWindowProc(hwnd
, WM_SETFOCUS
, (WPARAM
)hwndOldFocus
, 0);
2812 gui_focus_change(FALSE
);
2813 s_getting_focus
= FALSE
;
2814 (void)MyWindowProc(hwnd
, WM_KILLFOCUS
, (WPARAM
)hwndNewFocus
, 0);
2818 * Get a message when the user switches back to vim
2835 /* we call gui_focus_change() in _OnSetFocus() */
2836 /* gui_focus_change((int)fActivate); */
2837 return MyWindowProc(hwnd
, WM_ACTIVATEAPP
, fActivate
, (DWORD
)dwThreadId
);
2840 #if defined(FEAT_WINDOWS) || defined(PROTO)
2842 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
2844 DestroyWindow(sb
->id
);
2849 * Get current mouse coordinates in text window.
2852 gui_mch_getmouse(int *x
, int *y
)
2857 (void)GetWindowRect(s_textArea
, &rct
);
2858 (void)GetCursorPos((LPPOINT
)&mp
);
2859 *x
= (int)(mp
.x
- rct
.left
);
2860 *y
= (int)(mp
.y
- rct
.top
);
2864 * Move mouse pointer to character at (x, y).
2867 gui_mch_setmouse(int x
, int y
)
2871 (void)GetWindowRect(s_textArea
, &rct
);
2872 (void)SetCursorPos(x
+ gui
.border_offset
+ rct
.left
,
2873 y
+ gui
.border_offset
+ rct
.top
);
2877 gui_mswin_get_valid_dimensions(
2883 int base_width
, base_height
;
2885 base_width
= gui_get_base_width()
2886 + GetSystemMetrics(SM_CXFRAME
) * 2;
2887 base_height
= gui_get_base_height()
2888 + GetSystemMetrics(SM_CYFRAME
) * 2
2889 + GetSystemMetrics(SM_CYCAPTION
)
2891 + gui_mswin_get_menu_height(FALSE
)
2894 *valid_w
= base_width
+
2895 ((w
- base_width
) / gui
.char_width
) * gui
.char_width
;
2896 *valid_h
= base_height
+
2897 ((h
- base_height
) / gui
.char_height
) * gui
.char_height
;
2901 gui_mch_flash(int msec
)
2906 * Note: InvertRect() excludes right and bottom of rectangle.
2910 rc
.right
= gui
.num_cols
* gui
.char_width
;
2911 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
2912 InvertRect(s_hdc
, &rc
);
2913 gui_mch_flush(); /* make sure it's displayed */
2915 ui_delay((long)msec
, TRUE
); /* wait for a few msec */
2917 InvertRect(s_hdc
, &rc
);
2921 * Return flags used for scrolling.
2922 * The SW_INVALIDATE is required when part of the window is covered or
2923 * off-screen. Refer to MS KB Q75236.
2926 get_scroll_flags(void)
2929 RECT rcVim
, rcOther
, rcDest
;
2931 GetWindowRect(s_hwnd
, &rcVim
);
2933 /* Check if the window is partly above or below the screen. We don't care
2934 * about partly left or right of the screen, it is not relevant when
2935 * scrolling up or down. */
2936 if (rcVim
.top
< 0 || rcVim
.bottom
> GetSystemMetrics(SM_CYFULLSCREEN
))
2937 return SW_INVALIDATE
;
2939 /* Check if there is an window (partly) on top of us. */
2940 for (hwnd
= s_hwnd
; (hwnd
= GetWindow(hwnd
, GW_HWNDPREV
)) != (HWND
)0; )
2941 if (IsWindowVisible(hwnd
))
2943 GetWindowRect(hwnd
, &rcOther
);
2944 if (IntersectRect(&rcDest
, &rcVim
, &rcOther
))
2945 return SW_INVALIDATE
;
2951 * Delete the given number of lines from the given row, scrolling up any
2952 * text further down within the scroll region.
2955 gui_mch_delete_lines(
2961 rc
.left
= FILL_X(gui
.scroll_region_left
);
2962 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2963 rc
.top
= FILL_Y(row
);
2964 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2966 ScrollWindowEx(s_textArea
, 0, -num_lines
* gui
.char_height
,
2967 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2969 UpdateWindow(s_textArea
);
2970 /* This seems to be required to avoid the cursor disappearing when
2971 * scrolling such that the cursor ends up in the top-left character on
2972 * the screen... But why? (Webb) */
2973 /* It's probably fixed by disabling drawing the cursor while scrolling. */
2974 /* gui.cursor_is_valid = FALSE; */
2976 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
2977 gui
.scroll_region_left
,
2978 gui
.scroll_region_bot
, gui
.scroll_region_right
);
2982 * Insert the given number of lines before the given row, scrolling down any
2983 * following text within the scroll region.
2986 gui_mch_insert_lines(
2992 rc
.left
= FILL_X(gui
.scroll_region_left
);
2993 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2994 rc
.top
= FILL_Y(row
);
2995 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2996 /* The SW_INVALIDATE is required when part of the window is covered or
2997 * off-screen. How do we avoid it when it's not needed? */
2998 ScrollWindowEx(s_textArea
, 0, num_lines
* gui
.char_height
,
2999 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
3001 UpdateWindow(s_textArea
);
3003 gui_clear_block(row
, gui
.scroll_region_left
,
3004 row
+ num_lines
- 1, gui
.scroll_region_right
);
3010 gui_mch_exit(int rc
)
3012 ReleaseDC(s_textArea
, s_hdc
);
3013 DeleteObject(s_brush
);
3016 /* Unload the tearoff bitmap */
3017 (void)DeleteObject((HGDIOBJ
)s_htearbitmap
);
3020 /* Destroy our window (if we have one). */
3023 destroying
= TRUE
; /* ignore WM_DESTROY message now */
3024 DestroyWindow(s_hwnd
);
3033 logfont2name(LOGFONT lf
)
3039 charset_name
= charset_id2name((int)lf
.lfCharSet
);
3040 res
= alloc((unsigned)(strlen(lf
.lfFaceName
) + 20
3041 + (charset_name
== NULL
? 0 : strlen(charset_name
) + 2)));
3045 /* make a normal font string out of the lf thing:*/
3046 sprintf((char *)p
, "%s:h%d", lf
.lfFaceName
, pixels_to_points(
3047 lf
.lfHeight
< 0 ? -lf
.lfHeight
: lf
.lfHeight
, TRUE
));
3054 #ifndef MSWIN16_FASTTEXT
3057 if (lf
.lfWeight
>= FW_BOLD
)
3064 if (charset_name
!= NULL
)
3067 STRCAT(p
, charset_name
);
3075 * Initialise vim to use the font with the given name.
3076 * Return FAIL if the font could not be loaded, OK otherwise.
3080 gui_mch_init_font(char_u
*font_name
, int fontset
)
3083 GuiFont font
= NOFONT
;
3087 if (get_logfont(&lf
, font_name
, NULL
, TRUE
) == OK
)
3088 font
= get_font_handle(&lf
);
3092 if (font_name
== NULL
)
3093 font_name
= lf
.lfFaceName
;
3094 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
3097 #ifdef FEAT_MBYTE_IME
3100 gui_mch_free_font(gui
.norm_font
);
3101 gui
.norm_font
= font
;
3102 current_font_height
= lf
.lfHeight
;
3105 p
= logfont2name(lf
);
3108 hl_set_font_name(p
);
3110 /* When setting 'guifont' to "*" replace it with the actual font name.
3112 if (STRCMP(font_name
, "*") == 0 && STRCMP(p_guifont
, "*") == 0)
3114 vim_free(p_guifont
);
3121 #ifndef MSWIN16_FASTTEXT
3122 gui_mch_free_font(gui
.ital_font
);
3123 gui
.ital_font
= NOFONT
;
3124 gui_mch_free_font(gui
.bold_font
);
3125 gui
.bold_font
= NOFONT
;
3126 gui_mch_free_font(gui
.boldital_font
);
3127 gui
.boldital_font
= NOFONT
;
3132 gui
.ital_font
= get_font_handle(&lf
);
3133 lf
.lfItalic
= FALSE
;
3135 if (lf
.lfWeight
< FW_BOLD
)
3137 lf
.lfWeight
= FW_BOLD
;
3138 gui
.bold_font
= get_font_handle(&lf
);
3142 gui
.boldital_font
= get_font_handle(&lf
);
3150 #ifndef WPF_RESTORETOMAXIMIZED
3151 # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
3155 * Return TRUE if the GUI window is maximized, filling the whole screen.
3162 wp
.length
= sizeof(WINDOWPLACEMENT
);
3163 if (GetWindowPlacement(s_hwnd
, &wp
))
3164 return wp
.showCmd
== SW_SHOWMAXIMIZED
3165 || (wp
.showCmd
== SW_SHOWMINIMIZED
3166 && wp
.flags
== WPF_RESTORETOMAXIMIZED
);
3172 * Called when the font changed while the window is maximized. Compute the
3173 * new Rows and Columns. This is like resizing the window.
3180 GetWindowRect(s_hwnd
, &rect
);
3181 gui_resize_shell(rect
.right
- rect
.left
3182 - GetSystemMetrics(SM_CXFRAME
) * 2,
3183 rect
.bottom
- rect
.top
3184 - GetSystemMetrics(SM_CYFRAME
) * 2
3185 - GetSystemMetrics(SM_CYCAPTION
)
3187 - gui_mswin_get_menu_height(FALSE
)
3193 * Set the window title
3201 set_window_title(s_hwnd
, (title
== NULL
? "VIM" : (char *)title
));
3204 #ifdef FEAT_MOUSESHAPE
3205 /* Table for shape IDCs. Keep in sync with the mshape_names[] table in
3207 static LPCSTR mshape_idcs
[] =
3209 MAKEINTRESOURCE(IDC_ARROW
), /* arrow */
3210 MAKEINTRESOURCE(0), /* blank */
3211 MAKEINTRESOURCE(IDC_IBEAM
), /* beam */
3212 MAKEINTRESOURCE(IDC_SIZENS
), /* updown */
3213 MAKEINTRESOURCE(IDC_SIZENS
), /* udsizing */
3214 MAKEINTRESOURCE(IDC_SIZEWE
), /* leftright */
3215 MAKEINTRESOURCE(IDC_SIZEWE
), /* lrsizing */
3216 MAKEINTRESOURCE(IDC_WAIT
), /* busy */
3218 MAKEINTRESOURCE(IDC_NO
), /* no */
3220 MAKEINTRESOURCE(IDC_ICON
), /* no */
3222 MAKEINTRESOURCE(IDC_ARROW
), /* crosshair */
3223 MAKEINTRESOURCE(IDC_ARROW
), /* hand1 */
3224 MAKEINTRESOURCE(IDC_ARROW
), /* hand2 */
3225 MAKEINTRESOURCE(IDC_ARROW
), /* pencil */
3226 MAKEINTRESOURCE(IDC_ARROW
), /* question */
3227 MAKEINTRESOURCE(IDC_ARROW
), /* right-arrow */
3228 MAKEINTRESOURCE(IDC_UPARROW
), /* up-arrow */
3229 MAKEINTRESOURCE(IDC_ARROW
) /* last one */
3233 mch_set_mouse_shape(int shape
)
3237 if (shape
== MSHAPE_HIDE
)
3241 if (shape
>= MSHAPE_NUMBERED
)
3242 idc
= MAKEINTRESOURCE(IDC_ARROW
);
3244 idc
= mshape_idcs
[shape
];
3245 #ifdef SetClassLongPtr
3246 SetClassLongPtr(s_textArea
, GCLP_HCURSOR
, (__int3264
)(LONG_PTR
)LoadCursor(NULL
, idc
));
3249 SetClassLong(s_textArea
, GCL_HCURSOR
, (long_u
)LoadCursor(NULL
, idc
));
3251 SetClassWord(s_textArea
, GCW_HCURSOR
, (WORD
)LoadCursor(NULL
, idc
));
3258 /* Set the position to make it redrawn with the new shape. */
3259 (void)GetCursorPos((LPPOINT
)&mp
);
3260 (void)SetCursorPos(mp
.x
, mp
.y
);
3269 * The file browser exists in two versions: with "W" uses wide characters,
3270 * without "W" the current codepage. When FEAT_MBYTE is defined and on
3271 * Windows NT/2000/XP the "W" functions are used.
3274 # if defined(FEAT_MBYTE) && defined(WIN3264)
3276 * Wide version of convert_filter(). Keep in sync!
3279 convert_filterW(char_u
*s
)
3282 unsigned s_len
= (unsigned)STRLEN(s
);
3285 res
= (WCHAR
*)alloc((s_len
+ 3) * sizeof(WCHAR
));
3288 for (i
= 0; i
< s_len
; ++i
)
3289 if (s
[i
] == '\t' || s
[i
] == '\n')
3294 /* Add two extra NULs to make sure it's properly terminated. */
3295 res
[s_len
+ 1] = NUL
;
3296 res
[s_len
+ 2] = NUL
;
3302 * Wide version of gui_mch_browse(). Keep in sync!
3313 /* We always use the wide function. This means enc_to_utf16() must work,
3314 * otherwise it fails miserably! */
3315 OPENFILENAMEW fileStruct
;
3316 WCHAR fileBuf
[MAXPATHL
];
3319 WCHAR
*titlep
= NULL
;
3321 WCHAR
*initdirp
= NULL
;
3329 wp
= enc_to_utf16(dflt
, NULL
);
3334 for (i
= 0; wp
[i
] != NUL
&& i
< MAXPATHL
- 1; ++i
)
3341 /* Convert the filter to Windows format. */
3342 filterp
= convert_filterW(filter
);
3344 memset(&fileStruct
, 0, sizeof(OPENFILENAMEW
));
3345 #ifdef OPENFILENAME_SIZE_VERSION_400
3346 /* be compatible with Windows NT 4.0 */
3347 /* TODO: what to use for OPENFILENAMEW??? */
3348 fileStruct
.lStructSize
= OPENFILENAME_SIZE_VERSION_400
;
3350 fileStruct
.lStructSize
= sizeof(fileStruct
);
3354 titlep
= enc_to_utf16(title
, NULL
);
3355 fileStruct
.lpstrTitle
= titlep
;
3358 extp
= enc_to_utf16(ext
, NULL
);
3359 fileStruct
.lpstrDefExt
= extp
;
3361 fileStruct
.lpstrFile
= fileBuf
;
3362 fileStruct
.nMaxFile
= MAXPATHL
;
3363 fileStruct
.lpstrFilter
= filterp
;
3364 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3365 /* has an initial dir been specified? */
3366 if (initdir
!= NULL
&& *initdir
!= NUL
)
3368 /* Must have backslashes here, no matter what 'shellslash' says */
3369 initdirp
= enc_to_utf16(initdir
, NULL
);
3370 if (initdirp
!= NULL
)
3372 for (wp
= initdirp
; *wp
!= NUL
; ++wp
)
3376 fileStruct
.lpstrInitialDir
= initdirp
;
3380 * TODO: Allow selection of multiple files. Needs another arg to this
3381 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3382 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3383 * files that don't exist yet, so I haven't put it in. What about
3384 * OFN_PATHMUSTEXIST?
3385 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3387 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3388 #ifdef FEAT_SHORTCUT
3389 if (curbuf
->b_p_bin
)
3390 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3394 if (!GetSaveFileNameW(&fileStruct
))
3399 if (!GetOpenFileNameW(&fileStruct
))
3408 /* Convert from UCS2 to 'encoding'. */
3409 p
= utf16_to_enc(fileBuf
, NULL
);
3411 /* when out of memory we get garbage for non-ASCII chars */
3415 /* Give focus back to main window (when using MDI). */
3418 /* Shorten the file name if possible */
3419 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3421 # endif /* FEAT_MBYTE */
3425 * Convert the string s to the proper format for a filter string by replacing
3426 * the \t and \n delimiters with \0.
3427 * Returns the converted string in allocated memory.
3429 * Keep in sync with convert_filterW() above!
3432 convert_filter(char_u
*s
)
3435 unsigned s_len
= (unsigned)STRLEN(s
);
3438 res
= alloc(s_len
+ 3);
3441 for (i
= 0; i
< s_len
; ++i
)
3442 if (s
[i
] == '\t' || s
[i
] == '\n')
3447 /* Add two extra NULs to make sure it's properly terminated. */
3448 res
[s_len
+ 1] = NUL
;
3449 res
[s_len
+ 2] = NUL
;
3455 * Select a directory.
3458 gui_mch_browsedir(char_u
*title
, char_u
*initdir
)
3460 /* We fake this: Use a filter that doesn't select anything and a default
3461 * file name that won't be used. */
3462 return gui_mch_browse(0, title
, (char_u
*)_("Not Used"), NULL
,
3463 initdir
, (char_u
*)_("Directory\t*.nothing\n"));
3467 * Pop open a file browser and return the file selected, in allocated memory,
3468 * or NULL if Cancel is hit.
3469 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
3470 * title - Title message for the file browser dialog.
3471 * dflt - Default name of file.
3472 * ext - Default extension to be added to files without extensions.
3473 * initdir - directory in which to open the browser (NULL = current dir)
3474 * filter - Filter for matched files to choose from.
3476 * Keep in sync with gui_mch_browseW() above!
3487 OPENFILENAME fileStruct
;
3488 char_u fileBuf
[MAXPATHL
];
3489 char_u
*initdirp
= NULL
;
3493 # if defined(FEAT_MBYTE) && defined(WIN3264)
3494 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
3495 return gui_mch_browseW(saving
, title
, dflt
, ext
, initdir
, filter
);
3501 vim_strncpy(fileBuf
, dflt
, MAXPATHL
- 1);
3503 /* Convert the filter to Windows format. */
3504 filterp
= convert_filter(filter
);
3506 memset(&fileStruct
, 0, sizeof(OPENFILENAME
));
3507 #ifdef OPENFILENAME_SIZE_VERSION_400
3508 /* be compatible with Windows NT 4.0 */
3509 fileStruct
.lStructSize
= OPENFILENAME_SIZE_VERSION_400
;
3511 fileStruct
.lStructSize
= sizeof(fileStruct
);
3514 fileStruct
.lpstrTitle
= title
;
3515 fileStruct
.lpstrDefExt
= ext
;
3517 fileStruct
.lpstrFile
= fileBuf
;
3518 fileStruct
.nMaxFile
= MAXPATHL
;
3519 fileStruct
.lpstrFilter
= filterp
;
3520 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3521 /* has an initial dir been specified? */
3522 if (initdir
!= NULL
&& *initdir
!= NUL
)
3524 /* Must have backslashes here, no matter what 'shellslash' says */
3525 initdirp
= vim_strsave(initdir
);
3526 if (initdirp
!= NULL
)
3527 for (p
= initdirp
; *p
!= NUL
; ++p
)
3530 fileStruct
.lpstrInitialDir
= initdirp
;
3534 * TODO: Allow selection of multiple files. Needs another arg to this
3535 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3536 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3537 * files that don't exist yet, so I haven't put it in. What about
3538 * OFN_PATHMUSTEXIST?
3539 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3541 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3542 #ifdef FEAT_SHORTCUT
3543 if (curbuf
->b_p_bin
)
3544 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3548 if (!GetSaveFileName(&fileStruct
))
3553 if (!GetOpenFileName(&fileStruct
))
3560 /* Give focus back to main window (when using MDI). */
3563 /* Shorten the file name if possible */
3564 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3566 #endif /* FEAT_BROWSE */
3576 # define BUFPATHLEN _MAX_PATH
3577 # define DRAGQVAL 0xFFFFFFFF
3579 # define BUFPATHLEN MAXPATHL
3580 # define DRAGQVAL 0xFFFF
3583 WCHAR wszFile
[BUFPATHLEN
];
3585 char szFile
[BUFPATHLEN
];
3586 UINT cFiles
= DragQueryFile(hDrop
, DRAGQVAL
, NULL
, 0);
3590 int_u modifiers
= 0;
3592 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3594 /* Obtain dropped position */
3595 DragQueryPoint(hDrop
, &pt
);
3596 MapWindowPoints(s_hwnd
, s_textArea
, &pt
, 1);
3602 fnames
= (char_u
**)alloc(cFiles
* sizeof(char_u
*));
3605 for (i
= 0; i
< cFiles
; ++i
)
3608 if (DragQueryFileW(hDrop
, i
, wszFile
, BUFPATHLEN
) > 0)
3609 fnames
[i
] = utf16_to_enc(wszFile
, NULL
);
3613 DragQueryFile(hDrop
, i
, szFile
, BUFPATHLEN
);
3614 fnames
[i
] = vim_strsave(szFile
);
3622 if ((GetKeyState(VK_SHIFT
) & 0x8000) != 0)
3623 modifiers
|= MOUSE_SHIFT
;
3624 if ((GetKeyState(VK_CONTROL
) & 0x8000) != 0)
3625 modifiers
|= MOUSE_CTRL
;
3626 if ((GetKeyState(VK_MENU
) & 0x8000) != 0)
3627 modifiers
|= MOUSE_ALT
;
3629 gui_handle_drop(pt
.x
, pt
.y
, modifiers
, fnames
, cFiles
);
3631 s_need_activate
= TRUE
;
3644 static UINT prev_code
= 0; /* code of previous call */
3645 scrollbar_T
*sb
, *sb_info
;
3647 int dragging
= FALSE
;
3648 int dont_scroll_save
= dont_scroll
;
3654 si
.cbSize
= sizeof(si
);
3658 sb
= gui_mswin_find_scrollbar(hwndCtl
);
3662 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
3665 * Careful: need to get scrollbar info out of first (left) scrollbar
3666 * for window, but keep real scrollbar too because we must pass it to
3667 * gui_drag_scrollbar().
3669 sb_info
= &sb
->wp
->w_scrollbars
[0];
3671 else /* Bottom scrollbar */
3673 val
= sb_info
->value
;
3680 if (sb
->scroll_shift
> 0)
3681 val
<<= sb
->scroll_shift
;
3690 val
+= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3693 val
-= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3702 if (prev_code
== SB_THUMBTRACK
)
3705 * "pos" only gives us 16-bit data. In case of large file,
3706 * use GetScrollPos() which returns 32-bit. Unfortunately it
3707 * is not valid while the scrollbar is being dragged.
3709 val
= GetScrollPos(hwndCtl
, SB_CTL
);
3710 if (sb
->scroll_shift
> 0)
3711 val
<<= sb
->scroll_shift
;
3716 /* TRACE("Unknown scrollbar event %d\n", code); */
3722 si
.nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3723 SetScrollInfo(hwndCtl
, SB_CTL
, &si
, TRUE
);
3725 nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3726 SetScrollPos(hwndCtl
, SB_CTL
, nPos
, TRUE
);
3730 * When moving a vertical scrollbar, move the other vertical scrollbar too.
3734 scrollbar_T
*sba
= sb
->wp
->w_scrollbars
;
3735 HWND id
= sba
[ (sb
== sba
+ SBAR_LEFT
) ? SBAR_RIGHT
: SBAR_LEFT
].id
;
3738 SetScrollInfo(id
, SB_CTL
, &si
, TRUE
);
3740 SetScrollPos(id
, SB_CTL
, nPos
, TRUE
);
3744 /* Don't let us be interrupted here by another message. */
3745 s_busy_processing
= TRUE
;
3747 /* When "allow_scrollbar" is FALSE still need to remember the new
3748 * position, but don't actually scroll by setting "dont_scroll". */
3749 dont_scroll
= !allow_scrollbar
;
3751 gui_drag_scrollbar(sb
, val
, dragging
);
3753 s_busy_processing
= FALSE
;
3754 dont_scroll
= dont_scroll_save
;
3761 * Get command line arguments.
3762 * Use "prog" as the name of the program and "cmdline" as the arguments.
3763 * Copy the arguments to allocated memory.
3764 * Return the number of arguments (including program name).
3765 * Return pointers to the arguments in "argvp". Memory is allocated with
3766 * malloc(), use free() instead of vim_free().
3767 * Return pointer to buffer in "tofree".
3768 * Returns zero when out of memory.
3772 get_cmd_args(char *prog
, char *cmdline
, char ***argvp
, char **tofree
)
3787 /* Try using the Unicode version first, it takes care of conversion when
3788 * 'encoding' is changed. */
3789 argc
= get_cmd_argsW(&argv
);
3794 /* Handle the program name. Remove the ".exe" extension, and find the 1st
3796 p
= strrchr(prog
, '.');
3799 for (progp
= prog
; *progp
== ' '; ++progp
)
3802 /* The command line is copied to allocated memory, so that we can change
3803 * it. Add the size of the string, the separating NUL and a terminating
3805 newcmdline
= malloc(STRLEN(cmdline
) + STRLEN(progp
) + 2);
3806 if (newcmdline
== NULL
)
3810 * First round: count the number of arguments ("pnew" == NULL).
3811 * Second round: produce the arguments.
3813 for (round
= 1; round
<= 2; ++round
)
3815 /* First argument is the program name. */
3819 strcpy(pnew
, progp
);
3820 pnew
+= strlen(pnew
);
3825 * Isolate each argument and put it in argv[].
3835 while (*p
!= NUL
&& (inquote
|| (*p
!= ' ' && *p
!= '\t')))
3837 /* Backslashes are only special when followed by a double
3839 i
= (int)strspn(p
, "\\");
3842 /* Halve the number of backslashes. */
3843 if (i
> 1 && pnew
!= NULL
)
3845 memset(pnew
, '\\', i
/ 2);
3849 /* Even nr of backslashes toggles quoting, uneven copies
3850 * the double quote. */
3853 else if (pnew
!= NULL
)
3859 /* Copy span of backslashes unmodified. */
3862 memset(pnew
, '\\', i
);
3872 /* Can't use mb_* functions, because 'encoding' is not
3873 * initialized yet here. */
3874 if (IsDBCSLeadByte(*p
))
3887 while (*p
== ' ' || *p
== '\t')
3888 ++p
; /* advance until a non-space */
3893 argv
= (char **)malloc((argc
+ 1) * sizeof(char *));
3897 return 0; /* malloc error */
3900 *tofree
= newcmdline
;
3905 argv
[argc
] = NULL
; /* NULL-terminated list */