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
);
1089 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1093 #if (defined(WIN3264) && defined(FEAT_MBYTE)) \
1094 || defined(GLOBAL_IME) \
1101 vim_WindowProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1104 return global_ime_DefWindowProc(hwnd
, message
, wParam
, lParam
);
1106 if (wide_WindowProc
)
1107 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
1108 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1114 * Called when the foreground or background color has been changed.
1117 gui_mch_new_colors(void)
1119 /* nothing to do? */
1123 * Set the colors to their default values.
1126 gui_mch_def_colors()
1128 gui
.norm_pixel
= GetSysColor(COLOR_WINDOWTEXT
);
1129 gui
.back_pixel
= GetSysColor(COLOR_WINDOW
);
1130 gui
.def_norm_pixel
= gui
.norm_pixel
;
1131 gui
.def_back_pixel
= gui
.back_pixel
;
1135 * Open the GUI window which was created by a call to gui_mch_init().
1140 #ifndef SW_SHOWDEFAULT
1141 # define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
1143 /* Actually open the window, if not already visible
1144 * (may be done already in gui_mch_set_shellsize) */
1145 if (!IsWindowVisible(s_hwnd
))
1146 ShowWindow(s_hwnd
, SW_SHOWDEFAULT
);
1148 #ifdef MSWIN_FIND_REPLACE
1149 /* Init replace string here, so that we keep it when re-opening the
1151 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1158 * Get the position of the top left corner of the window.
1161 gui_mch_get_winpos(int *x
, int *y
)
1165 GetWindowRect(s_hwnd
, &rect
);
1172 * Set the position of the top left corner of the window to the given
1176 gui_mch_set_winpos(int x
, int y
)
1178 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1179 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1182 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
1184 static int oldx
= 0;
1185 static int oldy
= 0;
1187 SetWindowPos(s_textArea
, NULL
, x
, y
, w
, h
, SWP_NOZORDER
| SWP_NOACTIVATE
);
1190 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1191 SendMessage(s_toolbarhwnd
, WM_SIZE
,
1192 (WPARAM
)0, (LPARAM
)(w
+ ((long)(TOOLBAR_BUTTON_HEIGHT
+8)<<16)));
1194 #if defined(FEAT_GUI_TABLINE)
1195 if (showing_tabline
)
1200 # ifdef FEAT_TOOLBAR
1201 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1202 top
= TOOLBAR_BUTTON_HEIGHT
+ TOOLBAR_BORDER_HEIGHT
;
1204 GetClientRect(s_hwnd
, &rect
);
1205 MoveWindow(s_tabhwnd
, 0, top
, rect
.right
, gui
.tabline_height
, TRUE
);
1209 /* When side scroll bar is unshown, the size of window will change.
1210 * then, the text area move left or right. thus client rect should be
1211 * forcely redraw. (Yasuhiro Matsumoto) */
1212 if (oldx
!= x
|| oldy
!= y
)
1214 InvalidateRect(s_hwnd
, NULL
, FALSE
);
1226 gui_mch_enable_scrollbar(
1230 ShowScrollBar(sb
->id
, SB_CTL
, flag
);
1232 /* TODO: When the window is maximized, the size of the window stays the
1233 * same, thus the size of the text area changes. On Win98 it's OK, on Win
1234 * NT 4.0 it's not... */
1238 gui_mch_set_scrollbar_pos(
1245 SetWindowPos(sb
->id
, NULL
, x
, y
, w
, h
,
1246 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1250 gui_mch_create_scrollbar(
1252 int orient
) /* SBAR_VERT or SBAR_HORIZ */
1254 sb
->id
= CreateWindow(
1255 "SCROLLBAR", "Scrollbar",
1256 WS_CHILD
| ((orient
== SBAR_VERT
) ? SBS_VERT
: SBS_HORZ
), 0, 0,
1257 10, /* Any value will do for now */
1258 10, /* Any value will do for now */
1264 * Find the scrollbar with the given hwnd.
1266 static scrollbar_T
*
1267 gui_mswin_find_scrollbar(HWND hwnd
)
1271 if (gui
.bottom_sbar
.id
== hwnd
)
1272 return &gui
.bottom_sbar
;
1275 if (wp
->w_scrollbars
[SBAR_LEFT
].id
== hwnd
)
1276 return &wp
->w_scrollbars
[SBAR_LEFT
];
1277 if (wp
->w_scrollbars
[SBAR_RIGHT
].id
== hwnd
)
1278 return &wp
->w_scrollbars
[SBAR_RIGHT
];
1284 * Get the character size of a font.
1287 GetFontSize(GuiFont font
)
1289 HWND hwnd
= GetDesktopWindow();
1290 HDC hdc
= GetWindowDC(hwnd
);
1291 HFONT hfntOld
= SelectFont(hdc
, (HFONT
)font
);
1294 GetTextMetrics(hdc
, &tm
);
1295 gui
.char_width
= tm
.tmAveCharWidth
+ tm
.tmOverhang
;
1297 gui
.char_height
= tm
.tmHeight
1298 #ifndef MSWIN16_FASTTEXT
1303 SelectFont(hdc
, hfntOld
);
1305 ReleaseDC(hwnd
, hdc
);
1309 * Adjust gui.char_height (after 'linespace' was changed).
1312 gui_mch_adjust_charheight(void)
1314 GetFontSize(gui
.norm_font
);
1319 get_font_handle(LOGFONT
*lf
)
1324 font
= CreateFontIndirect(lf
);
1329 return (GuiFont
)font
;
1333 pixels_to_points(int pixels
, int vertical
)
1339 hwnd
= GetDesktopWindow();
1340 hdc
= GetWindowDC(hwnd
);
1342 points
= MulDiv(pixels
, 72,
1343 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
));
1345 ReleaseDC(hwnd
, hdc
);
1353 int giveErrorIfMissing
)
1356 GuiFont font
= NOFONT
;
1358 if (get_logfont(&lf
, name
, NULL
, giveErrorIfMissing
) == OK
)
1359 font
= get_font_handle(&lf
);
1360 if (font
== NOFONT
&& giveErrorIfMissing
)
1361 EMSG2(_(e_font
), name
);
1365 #if defined(FEAT_EVAL) || defined(PROTO)
1367 * Return the name of font "font" in allocated memory.
1368 * Don't know how to get the actual name, thus use the provided name.
1372 gui_mch_get_fontname(font
, name
)
1378 return vim_strsave(name
);
1383 gui_mch_free_font(GuiFont font
)
1386 DeleteObject((HFONT
)font
);
1395 if (c
>= 'a' && c
<= 'f')
1396 return c
- 'a' + 10;
1400 * Return the Pixel value (color) for the given color name.
1401 * Return INVALCOLOR for error.
1404 gui_mch_get_color(char_u
*name
)
1406 typedef struct guicolor_tTable
1412 static guicolor_tTable table
[] =
1414 {"Black", RGB(0x00, 0x00, 0x00)},
1415 {"DarkGray", RGB(0x80, 0x80, 0x80)},
1416 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
1417 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
1418 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
1419 {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
1420 {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
1421 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
1422 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
1423 {"Gray20", RGB(0x33, 0x33, 0x33)},
1424 {"Grey20", RGB(0x33, 0x33, 0x33)},
1425 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
1426 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
1427 {"Gray40", RGB(0x66, 0x66, 0x66)},
1428 {"Grey40", RGB(0x66, 0x66, 0x66)},
1429 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
1430 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
1431 {"Gray60", RGB(0x99, 0x99, 0x99)},
1432 {"Grey60", RGB(0x99, 0x99, 0x99)},
1433 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
1434 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
1435 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
1436 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
1437 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
1438 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
1439 {"White", RGB(0xFF, 0xFF, 0xFF)},
1440 {"DarkRed", RGB(0x80, 0x00, 0x00)},
1441 {"Red", RGB(0xFF, 0x00, 0x00)},
1442 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
1443 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
1444 {"Blue", RGB(0x00, 0x00, 0xFF)},
1445 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
1446 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
1447 {"Green", RGB(0x00, 0xFF, 0x00)},
1448 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
1449 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
1450 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
1451 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
1452 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
1453 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
1454 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
1455 {"Brown", RGB(0x80, 0x40, 0x40)},
1456 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
1457 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
1458 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
1459 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
1460 {"Orange", RGB(0xFF, 0xA5, 0x00)},
1461 {"Purple", RGB(0xA0, 0x20, 0xF0)},
1462 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
1463 {"Violet", RGB(0xEE, 0x82, 0xEE)},
1466 typedef struct SysColorTable
1472 static SysColorTable sys_table
[] =
1475 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW
},
1476 {"SYS_3DHILIGHT", COLOR_3DHILIGHT
},
1478 {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT
},
1480 {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT
},
1481 {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT
},
1482 {"SYS_3DLIGHT", COLOR_3DLIGHT
},
1483 {"SYS_3DSHADOW", COLOR_3DSHADOW
},
1484 {"SYS_DESKTOP", COLOR_DESKTOP
},
1485 {"SYS_INFOBK", COLOR_INFOBK
},
1486 {"SYS_INFOTEXT", COLOR_INFOTEXT
},
1487 {"SYS_3DFACE", COLOR_3DFACE
},
1489 {"SYS_BTNFACE", COLOR_BTNFACE
},
1490 {"SYS_BTNSHADOW", COLOR_BTNSHADOW
},
1491 {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER
},
1492 {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION
},
1493 {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE
},
1494 {"SYS_BACKGROUND", COLOR_BACKGROUND
},
1495 {"SYS_BTNTEXT", COLOR_BTNTEXT
},
1496 {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT
},
1497 {"SYS_GRAYTEXT", COLOR_GRAYTEXT
},
1498 {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT
},
1499 {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT
},
1500 {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER
},
1501 {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION
},
1502 {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT
},
1503 {"SYS_MENU", COLOR_MENU
},
1504 {"SYS_MENUTEXT", COLOR_MENUTEXT
},
1505 {"SYS_SCROLLBAR", COLOR_SCROLLBAR
},
1506 {"SYS_WINDOW", COLOR_WINDOW
},
1507 {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME
},
1508 {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT
}
1514 if (name
[0] == '#' && strlen(name
) == 7)
1516 /* Name is in "#rrggbb" format */
1517 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
1518 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
1519 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
1520 if (r
< 0 || g
< 0 || b
< 0)
1522 return RGB(r
, g
, b
);
1526 /* Check if the name is one of the colors we know */
1527 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
1528 if (STRICMP(name
, table
[i
].name
) == 0)
1529 return table
[i
].color
;
1533 * Try to look up a system colour.
1535 for (i
= 0; i
< sizeof(sys_table
) / sizeof(sys_table
[0]); i
++)
1536 if (STRICMP(name
, sys_table
[i
].name
) == 0)
1537 return GetSysColor(sys_table
[i
].color
);
1540 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
1543 #define LINE_LEN 100
1545 char line
[LINE_LEN
];
1548 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
1552 fd
= mch_fopen((char *)fname
, "rt");
1563 fgets(line
, LINE_LEN
, fd
);
1564 len
= (int)STRLEN(line
);
1566 if (len
<= 1 || line
[len
-1] != '\n')
1571 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
1577 if (STRICMP(color
, name
) == 0)
1580 return (guicolor_T
) RGB(r
, g
, b
);
1590 * Return OK if the key with the termcap name "name" is supported.
1593 gui_mch_haskey(char_u
*name
)
1597 for (i
= 0; special_keys
[i
].vim_code1
!= NUL
; i
++)
1598 if (name
[0] == special_keys
[i
].vim_code0
&&
1599 name
[1] == special_keys
[i
].vim_code1
)
1610 * Invert a rectangle from row r, column c, for nr rows and nc columns.
1613 gui_mch_invert_rectangle(
1622 * Note: InvertRect() excludes right and bottom of rectangle.
1624 rc
.left
= FILL_X(c
);
1626 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
1627 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
1628 InvertRect(s_hdc
, &rc
);
1632 * Iconify the GUI window.
1635 gui_mch_iconify(void)
1637 ShowWindow(s_hwnd
, SW_MINIMIZE
);
1641 * Draw a cursor without focus.
1644 gui_mch_draw_hollow_cursor(guicolor_T color
)
1650 * Note: FrameRect() excludes right and bottom of rectangle.
1652 rc
.left
= FILL_X(gui
.col
);
1653 rc
.top
= FILL_Y(gui
.row
);
1654 rc
.right
= rc
.left
+ gui
.char_width
;
1656 if (mb_lefthalve(gui
.row
, gui
.col
))
1657 rc
.right
+= gui
.char_width
;
1659 rc
.bottom
= rc
.top
+ gui
.char_height
;
1660 hbr
= CreateSolidBrush(color
);
1661 FrameRect(s_hdc
, &rc
, hbr
);
1665 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1669 gui_mch_draw_part_cursor(
1678 * Note: FillRect() excludes right and bottom of rectangle.
1681 #ifdef FEAT_RIGHTLEFT
1682 /* vertical line should be on the right of current point */
1683 CURSOR_BAR_RIGHT
? FILL_X(gui
.col
+ 1) - w
:
1686 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
1687 rc
.right
= rc
.left
+ w
;
1688 rc
.bottom
= rc
.top
+ h
;
1689 hbr
= CreateSolidBrush(color
);
1690 FillRect(s_hdc
, &rc
, hbr
);
1695 * Process a single Windows message.
1696 * If one is not available we hang until one is.
1699 process_message(void)
1702 UINT vk
= 0; /* Virtual key */
1708 static char_u k10
[] = {K_SPECIAL
, 'k', ';', 0};
1711 GetMessage(&msg
, NULL
, 0, 0);
1714 /* Look after OLE Automation commands */
1715 if (msg
.message
== WM_OLE
)
1717 char_u
*str
= (char_u
*)msg
.lParam
;
1718 if (str
== NULL
|| *str
== NUL
)
1720 /* Message can't be ours, forward it. Fixes problem with Ultramon
1722 DispatchMessage(&msg
);
1726 add_to_input_buf(str
, (int)STRLEN(str
));
1727 vim_free(str
); /* was allocated in CVim::SendKeys() */
1733 #ifdef FEAT_NETBEANS_INTG
1734 if (msg
.message
== WM_NETBEANS
)
1736 messageFromNetbeansW32();
1742 if (sniff_request_waiting
&& want_sniff_request
)
1744 static char_u bytes
[3] = {CSI
, (char_u
)KS_EXTRA
, (char_u
)KE_SNIFF
};
1745 add_to_input_buf(bytes
, 3); /* K_SNIFF */
1746 sniff_request_waiting
= 0;
1747 want_sniff_request
= 0;
1748 /* request is handled in normal.c */
1750 if (msg
.message
== WM_USER
)
1752 MyTranslateMessage(&msg
);
1753 DispatchMessage(&msg
);
1758 #ifdef MSWIN_FIND_REPLACE
1759 /* Don't process messages used by the dialog */
1760 if (s_findrep_hwnd
!= NULL
&& IsDialogMessage(s_findrep_hwnd
, &msg
))
1762 HandleMouseHide(msg
.message
, msg
.lParam
);
1768 * Check if it's a special key that we recognise. If not, call
1769 * TranslateMessage().
1771 if (msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_SYSKEYDOWN
)
1773 vk
= (int) msg
.wParam
;
1774 /* handle key after dead key, but ignore shift, alt and control */
1775 if (dead_key
&& vk
!= VK_SHIFT
&& vk
!= VK_MENU
&& vk
!= VK_CONTROL
)
1778 /* handle non-alphabetic keys (ones that hopefully cannot generate
1779 * umlaut-characters), unless when control is down */
1780 if (vk
< 'A' || vk
> 'Z' || (GetKeyState(VK_CONTROL
) & 0x8000))
1784 dm
.message
= msg
.message
;
1786 dm
.wParam
= VK_SPACE
;
1787 MyTranslateMessage(&dm
); /* generate dead character */
1788 if (vk
!= VK_SPACE
) /* and send current character once more */
1789 PostMessage(msg
.hwnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
1794 /* Check for CTRL-BREAK */
1795 if (vk
== VK_CANCEL
)
1800 add_to_input_buf(string
, 1);
1803 for (i
= 0; special_keys
[i
].key_sym
!= 0; i
++)
1805 /* ignore VK_SPACE when ALT key pressed: system menu */
1806 if (special_keys
[i
].key_sym
== vk
1807 && (vk
!= VK_SPACE
|| !(GetKeyState(VK_MENU
) & 0x8000)))
1810 /* Check for <F10>: Windows selects the menu. When <F10> is
1811 * mapped we want to use the mapping instead. */
1813 && gui
.menu_is_active
1814 && check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1817 if (GetKeyState(VK_SHIFT
) & 0x8000)
1818 modifiers
|= MOD_MASK_SHIFT
;
1820 * Don't use caps-lock as shift, because these are special keys
1821 * being considered here, and we only want letters to get
1825 if (GetKeyState(VK_CAPITAL) & 0x0001)
1826 modifiers ^= MOD_MASK_SHIFT;
1828 if (GetKeyState(VK_CONTROL
) & 0x8000)
1829 modifiers
|= MOD_MASK_CTRL
;
1830 if (GetKeyState(VK_MENU
) & 0x8000)
1831 modifiers
|= MOD_MASK_ALT
;
1833 if (special_keys
[i
].vim_code1
== NUL
)
1834 key
= special_keys
[i
].vim_code0
;
1836 key
= TO_SPECIAL(special_keys
[i
].vim_code0
,
1837 special_keys
[i
].vim_code1
);
1838 key
= simplify_key(key
, &modifiers
);
1845 string
[1] = KS_MODIFIER
;
1846 string
[2] = modifiers
;
1847 add_to_input_buf(string
, 3);
1850 if (IS_SPECIAL(key
))
1853 string
[1] = K_SECOND(key
);
1854 string
[2] = K_THIRD(key
);
1855 add_to_input_buf(string
, 3);
1861 /* Handle "key" as a Unicode character. */
1862 len
= char_to_string(key
, string
, 40, FALSE
);
1863 add_to_input_buf(string
, len
);
1868 if (special_keys
[i
].key_sym
== 0)
1870 /* Some keys need C-S- where they should only need C-.
1871 * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1872 * system startup (Helmut Stiegler, 2003 Oct 3). */
1874 && (GetKeyState(VK_CONTROL
) & 0x8000)
1875 && !(GetKeyState(VK_SHIFT
) & 0x8000)
1876 && !(GetKeyState(VK_MENU
) & 0x8000))
1878 /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1879 if (vk
== '6' || MapVirtualKey(vk
, 2) == (UINT
)'^')
1881 string
[0] = Ctrl_HAT
;
1882 add_to_input_buf(string
, 1);
1884 /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
1885 else if (vk
== 0xBD) /* QWERTY for CTRL-'-' */
1888 add_to_input_buf(string
, 1);
1890 /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
1891 else if (vk
== '2' || MapVirtualKey(vk
, 2) == (UINT
)'@')
1893 string
[0] = Ctrl_AT
;
1894 add_to_input_buf(string
, 1);
1897 MyTranslateMessage(&msg
);
1900 MyTranslateMessage(&msg
);
1903 #ifdef FEAT_MBYTE_IME
1904 else if (msg
.message
== WM_IME_NOTIFY
)
1905 _OnImeNotify(msg
.hwnd
, (DWORD
)msg
.wParam
, (DWORD
)msg
.lParam
);
1906 else if (msg
.message
== WM_KEYUP
&& im_get_status())
1907 /* added for non-MS IME (Yasuhiro Matsumoto) */
1908 MyTranslateMessage(&msg
);
1910 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
1912 else if (msg
.message
== WM_IME_STARTCOMPOSITION
)
1916 global_ime_set_font(&norm_logfont
);
1917 point
.x
= FILL_X(gui
.col
);
1918 point
.y
= FILL_Y(gui
.row
);
1919 MapWindowPoints(s_textArea
, s_hwnd
, &point
, 1);
1920 global_ime_set_position(&point
);
1925 /* Check for <F10>: Default effect is to select the menu. When <F10> is
1926 * mapped we need to stop it here to avoid strange effects (e.g., for the
1928 if (vk
!= VK_F10
|| check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1930 DispatchMessage(&msg
);
1934 * Catch up with any queued events. This may put keyboard input into the
1935 * input buffer, call resize call-backs, trigger timers etc. If there is
1936 * nothing in the event queue (& no timers pending), then we return
1940 gui_mch_update(void)
1944 if (!s_busy_processing
)
1945 while (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
)
1946 && !vim_is_input_buf_full())
1951 * GUI input routine called by gui_wait_for_chars(). Waits for a character
1952 * from the keyboard.
1953 * wtime == -1 Wait forever.
1954 * wtime == 0 This should never happen.
1955 * wtime > 0 Wait wtime milliseconds for a character.
1956 * Returns OK if a character was found to be available within the given time,
1957 * or FAIL otherwise.
1960 gui_mch_wait_for_chars(int wtime
)
1965 s_timed_out
= FALSE
;
1969 /* Don't do anything while processing a (scroll) message. */
1970 if (s_busy_processing
)
1972 s_wait_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)wtime
,
1973 (TIMERPROC
)_OnTimer
);
1976 allow_scrollbar
= TRUE
;
1978 focus
= gui
.in_focus
;
1979 while (!s_timed_out
)
1981 /* Stop or start blinking when focus changes */
1982 if (gui
.in_focus
!= focus
)
1985 gui_mch_start_blink();
1987 gui_mch_stop_blink();
1988 focus
= gui
.in_focus
;
1991 if (s_need_activate
)
1994 (void)SetForegroundWindow(s_hwnd
);
1996 (void)SetActiveWindow(s_hwnd
);
1998 s_need_activate
= FALSE
;
2001 #ifdef FEAT_NETBEANS_INTG
2002 /* Process the queued netbeans messages. */
2003 netbeans_parse_messages();
2007 * Don't use gui_mch_update() because then we will spin-lock until a
2008 * char arrives, instead we use GetMessage() to hang until an
2009 * event arrives. No need to check for input_buf_full because we are
2010 * returning as soon as it contains a single char -- webb
2014 if (input_available())
2016 if (s_wait_timer
!= 0 && !s_timed_out
)
2018 KillTimer(NULL
, s_wait_timer
);
2020 /* Eat spurious WM_TIMER messages */
2021 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
2025 allow_scrollbar
= FALSE
;
2027 /* Clear pending mouse button, the release event may have been
2028 * taken by the dialog window. But don't do this when getting
2029 * focus, we need the mouse-up event then. */
2030 if (!s_getting_focus
)
2031 s_button_pending
= -1;
2036 allow_scrollbar
= FALSE
;
2041 * Clear a rectangular region of the screen from text pos (row1, col1) to
2042 * (row2, col2) inclusive.
2045 gui_mch_clear_block(
2054 * Clear one extra pixel at the far right, for when bold characters have
2055 * spilled over to the window border.
2056 * Note: FillRect() excludes right and bottom of rectangle.
2058 rc
.left
= FILL_X(col1
);
2059 rc
.top
= FILL_Y(row1
);
2060 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
2061 rc
.bottom
= FILL_Y(row2
+ 1);
2066 * Clear the whole text window.
2069 gui_mch_clear_all(void)
2075 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
2076 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
2084 gui_mch_enable_menu(int flag
)
2087 SetMenu(s_hwnd
, flag
? s_menuBar
: NULL
);
2093 gui_mch_set_menu_pos(
2099 /* It will be in the right place anyway */
2102 #if defined(FEAT_MENU) || defined(PROTO)
2104 * Make menu item hidden or not hidden
2107 gui_mch_menu_hidden(
2112 * This doesn't do what we want. Hmm, just grey the menu items for now.
2116 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2118 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2120 gui_mch_menu_grey(menu
, hidden
);
2124 * This is called after setting all the menus to grey/hidden or not.
2127 gui_mch_draw_menubar(void)
2129 DrawMenuBar(s_hwnd
);
2131 #endif /*FEAT_MENU*/
2139 SaveInst(HINSTANCE hInst
)
2146 * Return the RGB value of a pixel as a long.
2149 gui_mch_get_rgb(guicolor_T pixel
)
2151 return (GetRValue(pixel
) << 16) + (GetGValue(pixel
) << 8)
2155 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2156 /* Convert pixels in X to dialog units */
2158 PixelToDialogX(int numPixels
)
2160 return (WORD
)((numPixels
* 4) / s_dlgfntwidth
);
2163 /* Convert pixels in Y to dialog units */
2165 PixelToDialogY(int numPixels
)
2167 return (WORD
)((numPixels
* 8) / s_dlgfntheight
);
2170 /* Return the width in pixels of the given text in the given DC. */
2172 GetTextWidth(HDC hdc
, char_u
*str
, int len
)
2176 GetTextExtentPoint(hdc
, str
, len
, &size
);
2182 * Return the width in pixels of the given text in the given DC, taking care
2183 * of 'encoding' to active codepage conversion.
2186 GetTextWidthEnc(HDC hdc
, char_u
*str
, int len
)
2193 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2195 /* 'encoding' differs from active codepage: convert text and use wide
2197 wstr
= enc_to_utf16(str
, &wlen
);
2200 n
= GetTextExtentPointW(hdc
, wstr
, wlen
, &size
);
2207 return GetTextWidth(hdc
, str
, len
);
2210 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
2214 * A quick little routine that will center one window over another, handy for
2215 * dialog boxes. Taken from the Win32SDK samples.
2222 RECT rChild
, rParent
;
2223 int wChild
, hChild
, wParent
, hParent
;
2224 int wScreen
, hScreen
, xNew
, yNew
;
2227 GetWindowRect(hwndChild
, &rChild
);
2228 wChild
= rChild
.right
- rChild
.left
;
2229 hChild
= rChild
.bottom
- rChild
.top
;
2231 /* If Vim is minimized put the window in the middle of the screen. */
2232 if (hwndParent
== NULL
|| IsMinimized(hwndParent
))
2237 rParent
.right
= GetSystemMetrics(SM_CXSCREEN
);
2238 rParent
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
2240 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rParent
, 0);
2244 GetWindowRect(hwndParent
, &rParent
);
2245 wParent
= rParent
.right
- rParent
.left
;
2246 hParent
= rParent
.bottom
- rParent
.top
;
2248 hdc
= GetDC(hwndChild
);
2249 wScreen
= GetDeviceCaps (hdc
, HORZRES
);
2250 hScreen
= GetDeviceCaps (hdc
, VERTRES
);
2251 ReleaseDC(hwndChild
, hdc
);
2253 xNew
= rParent
.left
+ ((wParent
- wChild
) /2);
2258 else if ((xNew
+wChild
) > wScreen
)
2260 xNew
= wScreen
- wChild
;
2263 yNew
= rParent
.top
+ ((hParent
- hChild
) /2);
2266 else if ((yNew
+hChild
) > hScreen
)
2267 yNew
= hScreen
- hChild
;
2269 return SetWindowPos(hwndChild
, NULL
, xNew
, yNew
, 0, 0,
2270 SWP_NOSIZE
| SWP_NOZORDER
);
2272 #endif /* FEAT_GUI_DIALOG */
2275 gui_mch_activate_window(void)
2277 (void)SetActiveWindow(s_hwnd
);
2280 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2282 gui_mch_show_toolbar(int showit
)
2284 if (s_toolbarhwnd
== NULL
)
2290 # ifndef TB_SETUNICODEFORMAT
2291 /* For older compilers. We assume this never changes. */
2292 # define TB_SETUNICODEFORMAT 0x2005
2294 /* Enable/disable unicode support */
2295 int uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2296 SendMessage(s_toolbarhwnd
, TB_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2298 ShowWindow(s_toolbarhwnd
, SW_SHOW
);
2301 ShowWindow(s_toolbarhwnd
, SW_HIDE
);
2304 /* Then number of bitmaps is fixed. Exit is missing! */
2305 #define TOOLBAR_BITMAP_COUNT 31
2309 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2311 add_tabline_popup_menu_entry(HMENU pmenu
, UINT item_id
, char_u
*item_text
)
2317 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2319 /* 'encoding' differs from active codepage: convert menu name
2320 * and use wide function */
2321 wn
= enc_to_utf16(item_text
, NULL
);
2324 MENUITEMINFOW infow
;
2326 infow
.cbSize
= sizeof(infow
);
2327 infow
.fMask
= MIIM_TYPE
| MIIM_ID
;
2328 infow
.wID
= item_id
;
2329 infow
.fType
= MFT_STRING
;
2330 infow
.dwTypeData
= wn
;
2331 infow
.cch
= (UINT
)wcslen(wn
);
2332 n
= InsertMenuItemW(pmenu
, item_id
, FALSE
, &infow
);
2334 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2335 /* Failed, try using non-wide function. */
2345 info
.cbSize
= sizeof(info
);
2346 info
.fMask
= MIIM_TYPE
| MIIM_ID
;
2348 info
.fType
= MFT_STRING
;
2349 info
.dwTypeData
= item_text
;
2350 info
.cch
= (UINT
)STRLEN(item_text
);
2351 InsertMenuItem(pmenu
, item_id
, FALSE
, &info
);
2356 show_tabline_popup_menu(void)
2362 /* When ignoring events don't show the menu. */
2370 tab_pmenu
= CreatePopupMenu();
2371 if (tab_pmenu
== NULL
)
2374 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_CLOSE
, _("Close tab"));
2375 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_NEW
, _("New tab"));
2376 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_OPEN
,
2380 rval
= TrackPopupMenuEx(tab_pmenu
, TPM_RETURNCMD
, pt
.x
, pt
.y
, s_tabhwnd
,
2383 DestroyMenu(tab_pmenu
);
2385 /* Add the string cmd into input buffer */
2388 TCHITTESTINFO htinfo
;
2391 if (ScreenToClient(s_tabhwnd
, &pt
) == 0)
2396 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
2402 send_tabline_menu_event(idx
, (int)rval
);
2407 * Show or hide the tabline.
2410 gui_mch_show_tabline(int showit
)
2412 if (s_tabhwnd
== NULL
)
2415 if (!showit
!= !showing_tabline
)
2418 ShowWindow(s_tabhwnd
, SW_SHOW
);
2420 ShowWindow(s_tabhwnd
, SW_HIDE
);
2421 showing_tabline
= showit
;
2426 * Return TRUE when tabline is displayed.
2429 gui_mch_showing_tabline(void)
2431 return s_tabhwnd
!= NULL
&& showing_tabline
;
2435 * Update the labels of the tabline.
2438 gui_mch_update_tabline(void)
2446 static int use_unicode
= FALSE
;
2451 if (s_tabhwnd
== NULL
)
2454 #if defined(FEAT_MBYTE)
2455 # ifndef CCM_SETUNICODEFORMAT
2456 /* For older compilers. We assume this never changes. */
2457 # define CCM_SETUNICODEFORMAT 0x2005
2459 uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2460 if (uu
!= use_unicode
)
2462 /* Enable/disable unicode support */
2463 SendMessage(s_tabhwnd
, CCM_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2468 tie
.mask
= TCIF_TEXT
;
2471 /* Add a label for each tab page. They all contain the same text area. */
2472 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
2477 if (!TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2480 tie
.pszText
= "-Empty-";
2481 TabCtrl_InsertItem(s_tabhwnd
, nr
, &tie
);
2484 get_tabline_label(tp
, FALSE
);
2485 tie
.pszText
= NameBuff
;
2490 /* Need to go through Unicode. */
2491 wstr
= enc_to_utf16(NameBuff
, NULL
);
2496 tiw
.mask
= TCIF_TEXT
;
2499 SendMessage(s_tabhwnd
, TCM_SETITEMW
, (WPARAM
)nr
, (LPARAM
)&tiw
);
2506 TabCtrl_SetItem(s_tabhwnd
, nr
, &tie
);
2510 /* Remove any old labels. */
2511 while (TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2512 TabCtrl_DeleteItem(s_tabhwnd
, nr
);
2514 if (TabCtrl_GetCurSel(s_tabhwnd
) != curtabidx
)
2515 TabCtrl_SetCurSel(s_tabhwnd
, curtabidx
);
2519 * Set the current tab to "nr". First tab is 1.
2522 gui_mch_set_curtab(nr
)
2525 if (s_tabhwnd
== NULL
)
2528 if (TabCtrl_GetCurSel(s_tabhwnd
) != nr
-1)
2529 TabCtrl_SetCurSel(s_tabhwnd
, nr
-1);
2535 * ":simalt" command.
2538 ex_simalt(exarg_T
*eap
)
2540 char_u
*keys
= eap
->arg
;
2542 PostMessage(s_hwnd
, WM_SYSCOMMAND
, (WPARAM
)SC_KEYMENU
, (LPARAM
)0);
2546 *keys
= ' '; /* for showing system menu */
2547 PostMessage(s_hwnd
, WM_CHAR
, (WPARAM
)*keys
, (LPARAM
)0);
2553 * Create the find & replace dialogs.
2554 * You can't have both at once: ":find" when replace is showing, destroys
2555 * the replace dialog first, and the other way around.
2557 #ifdef MSWIN_FIND_REPLACE
2559 initialise_findrep(char_u
*initial_string
)
2565 /* Get the search string to use. */
2566 entry_text
= get_find_dialog_text(initial_string
, &wword
, &mcase
);
2568 s_findrep_struct
.hwndOwner
= s_hwnd
;
2569 s_findrep_struct
.Flags
= FR_DOWN
;
2571 s_findrep_struct
.Flags
|= FR_MATCHCASE
;
2573 s_findrep_struct
.Flags
|= FR_WHOLEWORD
;
2574 if (entry_text
!= NULL
&& *entry_text
!= NUL
)
2575 vim_strncpy(s_findrep_struct
.lpstrFindWhat
, entry_text
,
2576 s_findrep_struct
.wFindWhatLen
- 1);
2577 vim_free(entry_text
);
2582 set_window_title(HWND hwnd
, char *title
)
2585 if (title
!= NULL
&& enc_codepage
>= 0 && enc_codepage
!= (int)GetACP())
2590 /* Convert the title from 'encoding' to UTF-16. */
2591 wbuf
= (WCHAR
*)enc_to_utf16((char_u
*)title
, NULL
);
2594 n
= SetWindowTextW(hwnd
, wbuf
);
2596 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2598 /* Retry with non-wide function (for Windows 98). */
2602 (void)SetWindowText(hwnd
, (LPCSTR
)title
);
2606 gui_mch_find_dialog(exarg_T
*eap
)
2608 #ifdef MSWIN_FIND_REPLACE
2609 if (s_findrep_msg
!= 0)
2611 if (IsWindow(s_findrep_hwnd
) && !s_findrep_is_find
)
2612 DestroyWindow(s_findrep_hwnd
);
2614 if (!IsWindow(s_findrep_hwnd
))
2616 initialise_findrep(eap
->arg
);
2617 # if defined(FEAT_MBYTE) && defined(WIN3264)
2618 /* If the OS is Windows NT, and 'encoding' differs from active
2619 * codepage: convert text and use wide function. */
2620 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2621 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2623 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2624 s_findrep_hwnd
= FindTextW(
2625 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2629 s_findrep_hwnd
= FindText((LPFINDREPLACE
) &s_findrep_struct
);
2632 set_window_title(s_findrep_hwnd
,
2633 _("Find string (use '\\\\' to find a '\\')"));
2634 (void)SetFocus(s_findrep_hwnd
);
2636 s_findrep_is_find
= TRUE
;
2643 gui_mch_replace_dialog(exarg_T
*eap
)
2645 #ifdef MSWIN_FIND_REPLACE
2646 if (s_findrep_msg
!= 0)
2648 if (IsWindow(s_findrep_hwnd
) && s_findrep_is_find
)
2649 DestroyWindow(s_findrep_hwnd
);
2651 if (!IsWindow(s_findrep_hwnd
))
2653 initialise_findrep(eap
->arg
);
2654 # if defined(FEAT_MBYTE) && defined(WIN3264)
2655 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2656 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2658 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2659 s_findrep_hwnd
= ReplaceTextW(
2660 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2664 s_findrep_hwnd
= ReplaceText(
2665 (LPFINDREPLACE
) &s_findrep_struct
);
2668 set_window_title(s_findrep_hwnd
,
2669 _("Find & Replace (use '\\\\' to find a '\\')"));
2670 (void)SetFocus(s_findrep_hwnd
);
2672 s_findrep_is_find
= FALSE
;
2679 * Set visibility of the pointer.
2682 gui_mch_mousehide(int hide
)
2684 if (hide
!= gui
.pointer_hidden
)
2687 gui
.pointer_hidden
= hide
;
2693 gui_mch_show_popupmenu_at(vimmenu_T
*menu
, int x
, int y
)
2695 /* Unhide the mouse, we don't get move events here. */
2696 gui_mch_mousehide(FALSE
);
2698 (void)TrackPopupMenu(
2699 (HMENU
)menu
->submenu_id
,
2700 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2702 (int)0, /*reserved param*/
2706 * NOTE: The pop-up menu can eat the mouse up event.
2707 * We deal with this in normal.c.
2713 * Got a message when the system will go down.
2718 getout_preserve_modified(1);
2722 * Get this message when the user clicks on the cross in the top right corner
2723 * of a Windows95 window.
2734 * Get a message when the window is being destroyed.
2741 Ctl3dUnregister(s_hinst
);
2751 if (!IsMinimized(hwnd
))
2755 out_flush(); /* make sure all output has been processed */
2756 (void)BeginPaint(hwnd
, &ps
);
2759 /* prevent multi-byte characters from misprinting on an invalid
2765 GetClientRect(hwnd
, &rect
);
2766 ps
.rcPaint
.left
= rect
.left
;
2767 ps
.rcPaint
.right
= rect
.right
;
2771 if (!IsRectEmpty(&ps
.rcPaint
))
2772 gui_redraw(ps
.rcPaint
.left
, ps
.rcPaint
.top
,
2773 ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1,
2774 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1);
2775 EndPaint(hwnd
, &ps
);
2787 if (!IsMinimized(hwnd
))
2789 gui_resize_shell(cx
, cy
);
2792 /* Menu bar may wrap differently now */
2793 gui_mswin_get_menu_height(TRUE
);
2803 gui_focus_change(TRUE
);
2804 s_getting_focus
= TRUE
;
2805 (void)MyWindowProc(hwnd
, WM_SETFOCUS
, (WPARAM
)hwndOldFocus
, 0);
2813 gui_focus_change(FALSE
);
2814 s_getting_focus
= FALSE
;
2815 (void)MyWindowProc(hwnd
, WM_KILLFOCUS
, (WPARAM
)hwndNewFocus
, 0);
2819 * Get a message when the user switches back to vim
2836 /* we call gui_focus_change() in _OnSetFocus() */
2837 /* gui_focus_change((int)fActivate); */
2838 return MyWindowProc(hwnd
, WM_ACTIVATEAPP
, fActivate
, (DWORD
)dwThreadId
);
2841 #if defined(FEAT_WINDOWS) || defined(PROTO)
2843 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
2845 DestroyWindow(sb
->id
);
2850 * Get current mouse coordinates in text window.
2853 gui_mch_getmouse(int *x
, int *y
)
2858 (void)GetWindowRect(s_textArea
, &rct
);
2859 (void)GetCursorPos((LPPOINT
)&mp
);
2860 *x
= (int)(mp
.x
- rct
.left
);
2861 *y
= (int)(mp
.y
- rct
.top
);
2865 * Move mouse pointer to character at (x, y).
2868 gui_mch_setmouse(int x
, int y
)
2872 (void)GetWindowRect(s_textArea
, &rct
);
2873 (void)SetCursorPos(x
+ gui
.border_offset
+ rct
.left
,
2874 y
+ gui
.border_offset
+ rct
.top
);
2878 gui_mswin_get_valid_dimensions(
2884 int base_width
, base_height
;
2886 base_width
= gui_get_base_width()
2887 + GetSystemMetrics(SM_CXFRAME
) * 2;
2888 base_height
= gui_get_base_height()
2889 + GetSystemMetrics(SM_CYFRAME
) * 2
2890 + GetSystemMetrics(SM_CYCAPTION
)
2892 + gui_mswin_get_menu_height(FALSE
)
2895 *valid_w
= base_width
+
2896 ((w
- base_width
) / gui
.char_width
) * gui
.char_width
;
2897 *valid_h
= base_height
+
2898 ((h
- base_height
) / gui
.char_height
) * gui
.char_height
;
2902 gui_mch_flash(int msec
)
2907 * Note: InvertRect() excludes right and bottom of rectangle.
2911 rc
.right
= gui
.num_cols
* gui
.char_width
;
2912 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
2913 InvertRect(s_hdc
, &rc
);
2914 gui_mch_flush(); /* make sure it's displayed */
2916 ui_delay((long)msec
, TRUE
); /* wait for a few msec */
2918 InvertRect(s_hdc
, &rc
);
2922 * Return flags used for scrolling.
2923 * The SW_INVALIDATE is required when part of the window is covered or
2924 * off-screen. Refer to MS KB Q75236.
2927 get_scroll_flags(void)
2930 RECT rcVim
, rcOther
, rcDest
;
2932 GetWindowRect(s_hwnd
, &rcVim
);
2934 /* Check if the window is partly above or below the screen. We don't care
2935 * about partly left or right of the screen, it is not relevant when
2936 * scrolling up or down. */
2937 if (rcVim
.top
< 0 || rcVim
.bottom
> GetSystemMetrics(SM_CYFULLSCREEN
))
2938 return SW_INVALIDATE
;
2940 /* Check if there is an window (partly) on top of us. */
2941 for (hwnd
= s_hwnd
; (hwnd
= GetWindow(hwnd
, GW_HWNDPREV
)) != (HWND
)0; )
2942 if (IsWindowVisible(hwnd
))
2944 GetWindowRect(hwnd
, &rcOther
);
2945 if (IntersectRect(&rcDest
, &rcVim
, &rcOther
))
2946 return SW_INVALIDATE
;
2952 * Delete the given number of lines from the given row, scrolling up any
2953 * text further down within the scroll region.
2956 gui_mch_delete_lines(
2962 rc
.left
= FILL_X(gui
.scroll_region_left
);
2963 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2964 rc
.top
= FILL_Y(row
);
2965 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2967 ScrollWindowEx(s_textArea
, 0, -num_lines
* gui
.char_height
,
2968 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2970 UpdateWindow(s_textArea
);
2971 /* This seems to be required to avoid the cursor disappearing when
2972 * scrolling such that the cursor ends up in the top-left character on
2973 * the screen... But why? (Webb) */
2974 /* It's probably fixed by disabling drawing the cursor while scrolling. */
2975 /* gui.cursor_is_valid = FALSE; */
2977 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
2978 gui
.scroll_region_left
,
2979 gui
.scroll_region_bot
, gui
.scroll_region_right
);
2983 * Insert the given number of lines before the given row, scrolling down any
2984 * following text within the scroll region.
2987 gui_mch_insert_lines(
2993 rc
.left
= FILL_X(gui
.scroll_region_left
);
2994 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2995 rc
.top
= FILL_Y(row
);
2996 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2997 /* The SW_INVALIDATE is required when part of the window is covered or
2998 * off-screen. How do we avoid it when it's not needed? */
2999 ScrollWindowEx(s_textArea
, 0, num_lines
* gui
.char_height
,
3000 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
3002 UpdateWindow(s_textArea
);
3004 gui_clear_block(row
, gui
.scroll_region_left
,
3005 row
+ num_lines
- 1, gui
.scroll_region_right
);
3011 gui_mch_exit(int rc
)
3013 ReleaseDC(s_textArea
, s_hdc
);
3014 DeleteObject(s_brush
);
3017 /* Unload the tearoff bitmap */
3018 (void)DeleteObject((HGDIOBJ
)s_htearbitmap
);
3021 /* Destroy our window (if we have one). */
3024 destroying
= TRUE
; /* ignore WM_DESTROY message now */
3025 DestroyWindow(s_hwnd
);
3034 logfont2name(LOGFONT lf
)
3040 charset_name
= charset_id2name((int)lf
.lfCharSet
);
3041 res
= alloc((unsigned)(strlen(lf
.lfFaceName
) + 20
3042 + (charset_name
== NULL
? 0 : strlen(charset_name
) + 2)));
3046 /* make a normal font string out of the lf thing:*/
3047 sprintf((char *)p
, "%s:h%d", lf
.lfFaceName
, pixels_to_points(
3048 lf
.lfHeight
< 0 ? -lf
.lfHeight
: lf
.lfHeight
, TRUE
));
3055 #ifndef MSWIN16_FASTTEXT
3058 if (lf
.lfWeight
>= FW_BOLD
)
3065 if (charset_name
!= NULL
)
3068 STRCAT(p
, charset_name
);
3076 * Initialise vim to use the font with the given name.
3077 * Return FAIL if the font could not be loaded, OK otherwise.
3081 gui_mch_init_font(char_u
*font_name
, int fontset
)
3084 GuiFont font
= NOFONT
;
3088 if (get_logfont(&lf
, font_name
, NULL
, TRUE
) == OK
)
3089 font
= get_font_handle(&lf
);
3093 if (font_name
== NULL
)
3094 font_name
= lf
.lfFaceName
;
3095 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
3098 #ifdef FEAT_MBYTE_IME
3101 gui_mch_free_font(gui
.norm_font
);
3102 gui
.norm_font
= font
;
3103 current_font_height
= lf
.lfHeight
;
3106 p
= logfont2name(lf
);
3109 hl_set_font_name(p
);
3111 /* When setting 'guifont' to "*" replace it with the actual font name.
3113 if (STRCMP(font_name
, "*") == 0 && STRCMP(p_guifont
, "*") == 0)
3115 vim_free(p_guifont
);
3122 #ifndef MSWIN16_FASTTEXT
3123 gui_mch_free_font(gui
.ital_font
);
3124 gui
.ital_font
= NOFONT
;
3125 gui_mch_free_font(gui
.bold_font
);
3126 gui
.bold_font
= NOFONT
;
3127 gui_mch_free_font(gui
.boldital_font
);
3128 gui
.boldital_font
= NOFONT
;
3133 gui
.ital_font
= get_font_handle(&lf
);
3134 lf
.lfItalic
= FALSE
;
3136 if (lf
.lfWeight
< FW_BOLD
)
3138 lf
.lfWeight
= FW_BOLD
;
3139 gui
.bold_font
= get_font_handle(&lf
);
3143 gui
.boldital_font
= get_font_handle(&lf
);
3151 #ifndef WPF_RESTORETOMAXIMIZED
3152 # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
3156 * Return TRUE if the GUI window is maximized, filling the whole screen.
3163 wp
.length
= sizeof(WINDOWPLACEMENT
);
3164 if (GetWindowPlacement(s_hwnd
, &wp
))
3165 return wp
.showCmd
== SW_SHOWMAXIMIZED
3166 || (wp
.showCmd
== SW_SHOWMINIMIZED
3167 && wp
.flags
== WPF_RESTORETOMAXIMIZED
);
3173 * Called when the font changed while the window is maximized. Compute the
3174 * new Rows and Columns. This is like resizing the window.
3181 GetWindowRect(s_hwnd
, &rect
);
3182 gui_resize_shell(rect
.right
- rect
.left
3183 - GetSystemMetrics(SM_CXFRAME
) * 2,
3184 rect
.bottom
- rect
.top
3185 - GetSystemMetrics(SM_CYFRAME
) * 2
3186 - GetSystemMetrics(SM_CYCAPTION
)
3188 - gui_mswin_get_menu_height(FALSE
)
3194 * Set the window title
3202 set_window_title(s_hwnd
, (title
== NULL
? "VIM" : (char *)title
));
3205 #ifdef FEAT_MOUSESHAPE
3206 /* Table for shape IDCs. Keep in sync with the mshape_names[] table in
3208 static LPCSTR mshape_idcs
[] =
3210 MAKEINTRESOURCE(IDC_ARROW
), /* arrow */
3211 MAKEINTRESOURCE(0), /* blank */
3212 MAKEINTRESOURCE(IDC_IBEAM
), /* beam */
3213 MAKEINTRESOURCE(IDC_SIZENS
), /* updown */
3214 MAKEINTRESOURCE(IDC_SIZENS
), /* udsizing */
3215 MAKEINTRESOURCE(IDC_SIZEWE
), /* leftright */
3216 MAKEINTRESOURCE(IDC_SIZEWE
), /* lrsizing */
3217 MAKEINTRESOURCE(IDC_WAIT
), /* busy */
3219 MAKEINTRESOURCE(IDC_NO
), /* no */
3221 MAKEINTRESOURCE(IDC_ICON
), /* no */
3223 MAKEINTRESOURCE(IDC_ARROW
), /* crosshair */
3224 MAKEINTRESOURCE(IDC_ARROW
), /* hand1 */
3225 MAKEINTRESOURCE(IDC_ARROW
), /* hand2 */
3226 MAKEINTRESOURCE(IDC_ARROW
), /* pencil */
3227 MAKEINTRESOURCE(IDC_ARROW
), /* question */
3228 MAKEINTRESOURCE(IDC_ARROW
), /* right-arrow */
3229 MAKEINTRESOURCE(IDC_UPARROW
), /* up-arrow */
3230 MAKEINTRESOURCE(IDC_ARROW
) /* last one */
3234 mch_set_mouse_shape(int shape
)
3238 if (shape
== MSHAPE_HIDE
)
3242 if (shape
>= MSHAPE_NUMBERED
)
3243 idc
= MAKEINTRESOURCE(IDC_ARROW
);
3245 idc
= mshape_idcs
[shape
];
3246 #ifdef SetClassLongPtr
3247 SetClassLongPtr(s_textArea
, GCLP_HCURSOR
, (__int3264
)(LONG_PTR
)LoadCursor(NULL
, idc
));
3250 SetClassLong(s_textArea
, GCL_HCURSOR
, (long_u
)LoadCursor(NULL
, idc
));
3252 SetClassWord(s_textArea
, GCW_HCURSOR
, (WORD
)LoadCursor(NULL
, idc
));
3259 /* Set the position to make it redrawn with the new shape. */
3260 (void)GetCursorPos((LPPOINT
)&mp
);
3261 (void)SetCursorPos(mp
.x
, mp
.y
);
3270 * The file browser exists in two versions: with "W" uses wide characters,
3271 * without "W" the current codepage. When FEAT_MBYTE is defined and on
3272 * Windows NT/2000/XP the "W" functions are used.
3275 # if defined(FEAT_MBYTE) && defined(WIN3264)
3277 * Wide version of convert_filter(). Keep in sync!
3280 convert_filterW(char_u
*s
)
3283 unsigned s_len
= (unsigned)STRLEN(s
);
3286 res
= (WCHAR
*)alloc((s_len
+ 3) * sizeof(WCHAR
));
3289 for (i
= 0; i
< s_len
; ++i
)
3290 if (s
[i
] == '\t' || s
[i
] == '\n')
3295 /* Add two extra NULs to make sure it's properly terminated. */
3296 res
[s_len
+ 1] = NUL
;
3297 res
[s_len
+ 2] = NUL
;
3303 * Wide version of gui_mch_browse(). Keep in sync!
3314 /* We always use the wide function. This means enc_to_utf16() must work,
3315 * otherwise it fails miserably! */
3316 OPENFILENAMEW fileStruct
;
3317 WCHAR fileBuf
[MAXPATHL
];
3320 WCHAR
*titlep
= NULL
;
3322 WCHAR
*initdirp
= NULL
;
3330 wp
= enc_to_utf16(dflt
, NULL
);
3335 for (i
= 0; wp
[i
] != NUL
&& i
< MAXPATHL
- 1; ++i
)
3342 /* Convert the filter to Windows format. */
3343 filterp
= convert_filterW(filter
);
3345 memset(&fileStruct
, 0, sizeof(OPENFILENAMEW
));
3346 #ifdef OPENFILENAME_SIZE_VERSION_400
3347 /* be compatible with Windows NT 4.0 */
3348 /* TODO: what to use for OPENFILENAMEW??? */
3349 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3351 fileStruct
.lStructSize
= sizeof(fileStruct
);
3355 titlep
= enc_to_utf16(title
, NULL
);
3356 fileStruct
.lpstrTitle
= titlep
;
3359 extp
= enc_to_utf16(ext
, NULL
);
3360 fileStruct
.lpstrDefExt
= extp
;
3362 fileStruct
.lpstrFile
= fileBuf
;
3363 fileStruct
.nMaxFile
= MAXPATHL
;
3364 fileStruct
.lpstrFilter
= filterp
;
3365 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3366 /* has an initial dir been specified? */
3367 if (initdir
!= NULL
&& *initdir
!= NUL
)
3369 /* Must have backslashes here, no matter what 'shellslash' says */
3370 initdirp
= enc_to_utf16(initdir
, NULL
);
3371 if (initdirp
!= NULL
)
3373 for (wp
= initdirp
; *wp
!= NUL
; ++wp
)
3377 fileStruct
.lpstrInitialDir
= initdirp
;
3381 * TODO: Allow selection of multiple files. Needs another arg to this
3382 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3383 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3384 * files that don't exist yet, so I haven't put it in. What about
3385 * OFN_PATHMUSTEXIST?
3386 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3388 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3389 #ifdef FEAT_SHORTCUT
3390 if (curbuf
->b_p_bin
)
3391 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3395 if (!GetSaveFileNameW(&fileStruct
))
3400 if (!GetOpenFileNameW(&fileStruct
))
3409 /* Convert from UCS2 to 'encoding'. */
3410 p
= utf16_to_enc(fileBuf
, NULL
);
3412 /* when out of memory we get garbage for non-ASCII chars */
3416 /* Give focus back to main window (when using MDI). */
3419 /* Shorten the file name if possible */
3420 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3422 # endif /* FEAT_MBYTE */
3426 * Convert the string s to the proper format for a filter string by replacing
3427 * the \t and \n delimiters with \0.
3428 * Returns the converted string in allocated memory.
3430 * Keep in sync with convert_filterW() above!
3433 convert_filter(char_u
*s
)
3436 unsigned s_len
= (unsigned)STRLEN(s
);
3439 res
= alloc(s_len
+ 3);
3442 for (i
= 0; i
< s_len
; ++i
)
3443 if (s
[i
] == '\t' || s
[i
] == '\n')
3448 /* Add two extra NULs to make sure it's properly terminated. */
3449 res
[s_len
+ 1] = NUL
;
3450 res
[s_len
+ 2] = NUL
;
3456 * Select a directory.
3459 gui_mch_browsedir(char_u
*title
, char_u
*initdir
)
3461 /* We fake this: Use a filter that doesn't select anything and a default
3462 * file name that won't be used. */
3463 return gui_mch_browse(0, title
, (char_u
*)_("Not Used"), NULL
,
3464 initdir
, (char_u
*)_("Directory\t*.nothing\n"));
3468 * Pop open a file browser and return the file selected, in allocated memory,
3469 * or NULL if Cancel is hit.
3470 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
3471 * title - Title message for the file browser dialog.
3472 * dflt - Default name of file.
3473 * ext - Default extension to be added to files without extensions.
3474 * initdir - directory in which to open the browser (NULL = current dir)
3475 * filter - Filter for matched files to choose from.
3477 * Keep in sync with gui_mch_browseW() above!
3488 OPENFILENAME fileStruct
;
3489 char_u fileBuf
[MAXPATHL
];
3490 char_u
*initdirp
= NULL
;
3494 # if defined(FEAT_MBYTE) && defined(WIN3264)
3495 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
3496 return gui_mch_browseW(saving
, title
, dflt
, ext
, initdir
, filter
);
3502 vim_strncpy(fileBuf
, dflt
, MAXPATHL
- 1);
3504 /* Convert the filter to Windows format. */
3505 filterp
= convert_filter(filter
);
3507 memset(&fileStruct
, 0, sizeof(OPENFILENAME
));
3508 #ifdef OPENFILENAME_SIZE_VERSION_400
3509 /* be compatible with Windows NT 4.0 */
3510 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3512 fileStruct
.lStructSize
= sizeof(fileStruct
);
3515 fileStruct
.lpstrTitle
= title
;
3516 fileStruct
.lpstrDefExt
= ext
;
3518 fileStruct
.lpstrFile
= fileBuf
;
3519 fileStruct
.nMaxFile
= MAXPATHL
;
3520 fileStruct
.lpstrFilter
= filterp
;
3521 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3522 /* has an initial dir been specified? */
3523 if (initdir
!= NULL
&& *initdir
!= NUL
)
3525 /* Must have backslashes here, no matter what 'shellslash' says */
3526 initdirp
= vim_strsave(initdir
);
3527 if (initdirp
!= NULL
)
3528 for (p
= initdirp
; *p
!= NUL
; ++p
)
3531 fileStruct
.lpstrInitialDir
= initdirp
;
3535 * TODO: Allow selection of multiple files. Needs another arg to this
3536 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3537 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3538 * files that don't exist yet, so I haven't put it in. What about
3539 * OFN_PATHMUSTEXIST?
3540 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3542 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3543 #ifdef FEAT_SHORTCUT
3544 if (curbuf
->b_p_bin
)
3545 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3549 if (!GetSaveFileName(&fileStruct
))
3554 if (!GetOpenFileName(&fileStruct
))
3561 /* Give focus back to main window (when using MDI). */
3564 /* Shorten the file name if possible */
3565 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3567 #endif /* FEAT_BROWSE */
3577 # define BUFPATHLEN _MAX_PATH
3578 # define DRAGQVAL 0xFFFFFFFF
3580 # define BUFPATHLEN MAXPATHL
3581 # define DRAGQVAL 0xFFFF
3584 WCHAR wszFile
[BUFPATHLEN
];
3586 char szFile
[BUFPATHLEN
];
3587 UINT cFiles
= DragQueryFile(hDrop
, DRAGQVAL
, NULL
, 0);
3591 int_u modifiers
= 0;
3593 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3595 /* Obtain dropped position */
3596 DragQueryPoint(hDrop
, &pt
);
3597 MapWindowPoints(s_hwnd
, s_textArea
, &pt
, 1);
3603 fnames
= (char_u
**)alloc(cFiles
* sizeof(char_u
*));
3606 for (i
= 0; i
< cFiles
; ++i
)
3609 if (DragQueryFileW(hDrop
, i
, wszFile
, BUFPATHLEN
) > 0)
3610 fnames
[i
] = utf16_to_enc(wszFile
, NULL
);
3614 DragQueryFile(hDrop
, i
, szFile
, BUFPATHLEN
);
3615 fnames
[i
] = vim_strsave(szFile
);
3623 if ((GetKeyState(VK_SHIFT
) & 0x8000) != 0)
3624 modifiers
|= MOUSE_SHIFT
;
3625 if ((GetKeyState(VK_CONTROL
) & 0x8000) != 0)
3626 modifiers
|= MOUSE_CTRL
;
3627 if ((GetKeyState(VK_MENU
) & 0x8000) != 0)
3628 modifiers
|= MOUSE_ALT
;
3630 gui_handle_drop(pt
.x
, pt
.y
, modifiers
, fnames
, cFiles
);
3632 s_need_activate
= TRUE
;
3645 static UINT prev_code
= 0; /* code of previous call */
3646 scrollbar_T
*sb
, *sb_info
;
3648 int dragging
= FALSE
;
3649 int dont_scroll_save
= dont_scroll
;
3655 si
.cbSize
= sizeof(si
);
3659 sb
= gui_mswin_find_scrollbar(hwndCtl
);
3663 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
3666 * Careful: need to get scrollbar info out of first (left) scrollbar
3667 * for window, but keep real scrollbar too because we must pass it to
3668 * gui_drag_scrollbar().
3670 sb_info
= &sb
->wp
->w_scrollbars
[0];
3672 else /* Bottom scrollbar */
3674 val
= sb_info
->value
;
3681 if (sb
->scroll_shift
> 0)
3682 val
<<= sb
->scroll_shift
;
3691 val
+= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3694 val
-= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3703 if (prev_code
== SB_THUMBTRACK
)
3706 * "pos" only gives us 16-bit data. In case of large file,
3707 * use GetScrollPos() which returns 32-bit. Unfortunately it
3708 * is not valid while the scrollbar is being dragged.
3710 val
= GetScrollPos(hwndCtl
, SB_CTL
);
3711 if (sb
->scroll_shift
> 0)
3712 val
<<= sb
->scroll_shift
;
3717 /* TRACE("Unknown scrollbar event %d\n", code); */
3723 si
.nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3724 SetScrollInfo(hwndCtl
, SB_CTL
, &si
, TRUE
);
3726 nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3727 SetScrollPos(hwndCtl
, SB_CTL
, nPos
, TRUE
);
3731 * When moving a vertical scrollbar, move the other vertical scrollbar too.
3735 scrollbar_T
*sba
= sb
->wp
->w_scrollbars
;
3736 HWND id
= sba
[ (sb
== sba
+ SBAR_LEFT
) ? SBAR_RIGHT
: SBAR_LEFT
].id
;
3739 SetScrollInfo(id
, SB_CTL
, &si
, TRUE
);
3741 SetScrollPos(id
, SB_CTL
, nPos
, TRUE
);
3745 /* Don't let us be interrupted here by another message. */
3746 s_busy_processing
= TRUE
;
3748 /* When "allow_scrollbar" is FALSE still need to remember the new
3749 * position, but don't actually scroll by setting "dont_scroll". */
3750 dont_scroll
= !allow_scrollbar
;
3752 gui_drag_scrollbar(sb
, val
, dragging
);
3754 s_busy_processing
= FALSE
;
3755 dont_scroll
= dont_scroll_save
;
3762 * Get command line arguments.
3763 * Use "prog" as the name of the program and "cmdline" as the arguments.
3764 * Copy the arguments to allocated memory.
3765 * Return the number of arguments (including program name).
3766 * Return pointers to the arguments in "argvp". Memory is allocated with
3767 * malloc(), use free() instead of vim_free().
3768 * Return pointer to buffer in "tofree".
3769 * Returns zero when out of memory.
3773 get_cmd_args(char *prog
, char *cmdline
, char ***argvp
, char **tofree
)
3788 /* Try using the Unicode version first, it takes care of conversion when
3789 * 'encoding' is changed. */
3790 argc
= get_cmd_argsW(&argv
);
3795 /* Handle the program name. Remove the ".exe" extension, and find the 1st
3797 p
= strrchr(prog
, '.');
3800 for (progp
= prog
; *progp
== ' '; ++progp
)
3803 /* The command line is copied to allocated memory, so that we can change
3804 * it. Add the size of the string, the separating NUL and a terminating
3806 newcmdline
= malloc(STRLEN(cmdline
) + STRLEN(progp
) + 2);
3807 if (newcmdline
== NULL
)
3811 * First round: count the number of arguments ("pnew" == NULL).
3812 * Second round: produce the arguments.
3814 for (round
= 1; round
<= 2; ++round
)
3816 /* First argument is the program name. */
3820 strcpy(pnew
, progp
);
3821 pnew
+= strlen(pnew
);
3826 * Isolate each argument and put it in argv[].
3836 while (*p
!= NUL
&& (inquote
|| (*p
!= ' ' && *p
!= '\t')))
3838 /* Backslashes are only special when followed by a double
3840 i
= (int)strspn(p
, "\\");
3843 /* Halve the number of backslashes. */
3844 if (i
> 1 && pnew
!= NULL
)
3846 memset(pnew
, '\\', i
/ 2);
3850 /* Even nr of backslashes toggles quoting, uneven copies
3851 * the double quote. */
3854 else if (pnew
!= NULL
)
3860 /* Copy span of backslashes unmodified. */
3863 memset(pnew
, '\\', i
);
3873 /* Can't use mb_* functions, because 'encoding' is not
3874 * initialized yet here. */
3875 if (IsDBCSLeadByte(*p
))
3888 while (*p
== ' ' || *p
== '\t')
3889 ++p
; /* advance until a non-space */
3894 argv
= (char **)malloc((argc
+ 1) * sizeof(char *));
3898 return 0; /* malloc error */
3901 *tofree
= newcmdline
;
3906 argv
[argc
] = NULL
; /* NULL-terminated list */