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
);
1087 /* Workaround for the problem that MyWindowProc() returns FALSE on 64
1088 * bit windows when cross-compiled using Mingw libraries. (Andy
1091 MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1095 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1099 #if (defined(WIN3264) && defined(FEAT_MBYTE)) \
1100 || defined(GLOBAL_IME) \
1107 vim_WindowProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1110 return global_ime_DefWindowProc(hwnd
, message
, wParam
, lParam
);
1112 if (wide_WindowProc
)
1113 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
1114 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1120 * Called when the foreground or background color has been changed.
1123 gui_mch_new_colors(void)
1125 /* nothing to do? */
1129 * Set the colors to their default values.
1132 gui_mch_def_colors()
1134 gui
.norm_pixel
= GetSysColor(COLOR_WINDOWTEXT
);
1135 gui
.back_pixel
= GetSysColor(COLOR_WINDOW
);
1136 gui
.def_norm_pixel
= gui
.norm_pixel
;
1137 gui
.def_back_pixel
= gui
.back_pixel
;
1141 * Open the GUI window which was created by a call to gui_mch_init().
1146 #ifndef SW_SHOWDEFAULT
1147 # define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
1149 /* Actually open the window, if not already visible
1150 * (may be done already in gui_mch_set_shellsize) */
1151 if (!IsWindowVisible(s_hwnd
))
1152 ShowWindow(s_hwnd
, SW_SHOWDEFAULT
);
1154 #ifdef MSWIN_FIND_REPLACE
1155 /* Init replace string here, so that we keep it when re-opening the
1157 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1164 * Get the position of the top left corner of the window.
1167 gui_mch_get_winpos(int *x
, int *y
)
1171 GetWindowRect(s_hwnd
, &rect
);
1178 * Set the position of the top left corner of the window to the given
1182 gui_mch_set_winpos(int x
, int y
)
1184 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1185 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1188 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
1190 static int oldx
= 0;
1191 static int oldy
= 0;
1193 SetWindowPos(s_textArea
, NULL
, x
, y
, w
, h
, SWP_NOZORDER
| SWP_NOACTIVATE
);
1196 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1197 SendMessage(s_toolbarhwnd
, WM_SIZE
,
1198 (WPARAM
)0, (LPARAM
)(w
+ ((long)(TOOLBAR_BUTTON_HEIGHT
+8)<<16)));
1200 #if defined(FEAT_GUI_TABLINE)
1201 if (showing_tabline
)
1206 # ifdef FEAT_TOOLBAR
1207 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1208 top
= TOOLBAR_BUTTON_HEIGHT
+ TOOLBAR_BORDER_HEIGHT
;
1210 GetClientRect(s_hwnd
, &rect
);
1211 MoveWindow(s_tabhwnd
, 0, top
, rect
.right
, gui
.tabline_height
, TRUE
);
1215 /* When side scroll bar is unshown, the size of window will change.
1216 * then, the text area move left or right. thus client rect should be
1217 * forcely redraw. (Yasuhiro Matsumoto) */
1218 if (oldx
!= x
|| oldy
!= y
)
1220 InvalidateRect(s_hwnd
, NULL
, FALSE
);
1232 gui_mch_enable_scrollbar(
1236 ShowScrollBar(sb
->id
, SB_CTL
, flag
);
1238 /* TODO: When the window is maximized, the size of the window stays the
1239 * same, thus the size of the text area changes. On Win98 it's OK, on Win
1240 * NT 4.0 it's not... */
1244 gui_mch_set_scrollbar_pos(
1251 SetWindowPos(sb
->id
, NULL
, x
, y
, w
, h
,
1252 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1256 gui_mch_create_scrollbar(
1258 int orient
) /* SBAR_VERT or SBAR_HORIZ */
1260 sb
->id
= CreateWindow(
1261 "SCROLLBAR", "Scrollbar",
1262 WS_CHILD
| ((orient
== SBAR_VERT
) ? SBS_VERT
: SBS_HORZ
), 0, 0,
1263 10, /* Any value will do for now */
1264 10, /* Any value will do for now */
1270 * Find the scrollbar with the given hwnd.
1272 static scrollbar_T
*
1273 gui_mswin_find_scrollbar(HWND hwnd
)
1277 if (gui
.bottom_sbar
.id
== hwnd
)
1278 return &gui
.bottom_sbar
;
1281 if (wp
->w_scrollbars
[SBAR_LEFT
].id
== hwnd
)
1282 return &wp
->w_scrollbars
[SBAR_LEFT
];
1283 if (wp
->w_scrollbars
[SBAR_RIGHT
].id
== hwnd
)
1284 return &wp
->w_scrollbars
[SBAR_RIGHT
];
1290 * Get the character size of a font.
1293 GetFontSize(GuiFont font
)
1295 HWND hwnd
= GetDesktopWindow();
1296 HDC hdc
= GetWindowDC(hwnd
);
1297 HFONT hfntOld
= SelectFont(hdc
, (HFONT
)font
);
1300 GetTextMetrics(hdc
, &tm
);
1301 gui
.char_width
= tm
.tmAveCharWidth
+ tm
.tmOverhang
;
1303 gui
.char_height
= tm
.tmHeight
1304 #ifndef MSWIN16_FASTTEXT
1309 SelectFont(hdc
, hfntOld
);
1311 ReleaseDC(hwnd
, hdc
);
1315 * Adjust gui.char_height (after 'linespace' was changed).
1318 gui_mch_adjust_charheight(void)
1320 GetFontSize(gui
.norm_font
);
1325 get_font_handle(LOGFONT
*lf
)
1330 font
= CreateFontIndirect(lf
);
1335 return (GuiFont
)font
;
1339 pixels_to_points(int pixels
, int vertical
)
1345 hwnd
= GetDesktopWindow();
1346 hdc
= GetWindowDC(hwnd
);
1348 points
= MulDiv(pixels
, 72,
1349 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
));
1351 ReleaseDC(hwnd
, hdc
);
1359 int giveErrorIfMissing
)
1362 GuiFont font
= NOFONT
;
1364 if (get_logfont(&lf
, name
, NULL
, giveErrorIfMissing
) == OK
)
1365 font
= get_font_handle(&lf
);
1366 if (font
== NOFONT
&& giveErrorIfMissing
)
1367 EMSG2(_(e_font
), name
);
1371 #if defined(FEAT_EVAL) || defined(PROTO)
1373 * Return the name of font "font" in allocated memory.
1374 * Don't know how to get the actual name, thus use the provided name.
1378 gui_mch_get_fontname(font
, name
)
1384 return vim_strsave(name
);
1389 gui_mch_free_font(GuiFont font
)
1392 DeleteObject((HFONT
)font
);
1401 if (c
>= 'a' && c
<= 'f')
1402 return c
- 'a' + 10;
1406 * Return the Pixel value (color) for the given color name.
1407 * Return INVALCOLOR for error.
1410 gui_mch_get_color(char_u
*name
)
1412 typedef struct guicolor_tTable
1418 static guicolor_tTable table
[] =
1420 {"Black", RGB(0x00, 0x00, 0x00)},
1421 {"DarkGray", RGB(0x80, 0x80, 0x80)},
1422 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
1423 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
1424 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
1425 {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
1426 {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
1427 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
1428 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
1429 {"Gray20", RGB(0x33, 0x33, 0x33)},
1430 {"Grey20", RGB(0x33, 0x33, 0x33)},
1431 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
1432 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
1433 {"Gray40", RGB(0x66, 0x66, 0x66)},
1434 {"Grey40", RGB(0x66, 0x66, 0x66)},
1435 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
1436 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
1437 {"Gray60", RGB(0x99, 0x99, 0x99)},
1438 {"Grey60", RGB(0x99, 0x99, 0x99)},
1439 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
1440 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
1441 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
1442 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
1443 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
1444 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
1445 {"White", RGB(0xFF, 0xFF, 0xFF)},
1446 {"DarkRed", RGB(0x80, 0x00, 0x00)},
1447 {"Red", RGB(0xFF, 0x00, 0x00)},
1448 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
1449 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
1450 {"Blue", RGB(0x00, 0x00, 0xFF)},
1451 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
1452 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
1453 {"Green", RGB(0x00, 0xFF, 0x00)},
1454 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
1455 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
1456 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
1457 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
1458 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
1459 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
1460 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
1461 {"Brown", RGB(0x80, 0x40, 0x40)},
1462 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
1463 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
1464 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
1465 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
1466 {"Orange", RGB(0xFF, 0xA5, 0x00)},
1467 {"Purple", RGB(0xA0, 0x20, 0xF0)},
1468 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
1469 {"Violet", RGB(0xEE, 0x82, 0xEE)},
1472 typedef struct SysColorTable
1478 static SysColorTable sys_table
[] =
1481 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW
},
1482 {"SYS_3DHILIGHT", COLOR_3DHILIGHT
},
1484 {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT
},
1486 {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT
},
1487 {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT
},
1488 {"SYS_3DLIGHT", COLOR_3DLIGHT
},
1489 {"SYS_3DSHADOW", COLOR_3DSHADOW
},
1490 {"SYS_DESKTOP", COLOR_DESKTOP
},
1491 {"SYS_INFOBK", COLOR_INFOBK
},
1492 {"SYS_INFOTEXT", COLOR_INFOTEXT
},
1493 {"SYS_3DFACE", COLOR_3DFACE
},
1495 {"SYS_BTNFACE", COLOR_BTNFACE
},
1496 {"SYS_BTNSHADOW", COLOR_BTNSHADOW
},
1497 {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER
},
1498 {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION
},
1499 {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE
},
1500 {"SYS_BACKGROUND", COLOR_BACKGROUND
},
1501 {"SYS_BTNTEXT", COLOR_BTNTEXT
},
1502 {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT
},
1503 {"SYS_GRAYTEXT", COLOR_GRAYTEXT
},
1504 {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT
},
1505 {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT
},
1506 {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER
},
1507 {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION
},
1508 {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT
},
1509 {"SYS_MENU", COLOR_MENU
},
1510 {"SYS_MENUTEXT", COLOR_MENUTEXT
},
1511 {"SYS_SCROLLBAR", COLOR_SCROLLBAR
},
1512 {"SYS_WINDOW", COLOR_WINDOW
},
1513 {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME
},
1514 {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT
}
1520 if (name
[0] == '#' && strlen(name
) == 7)
1522 /* Name is in "#rrggbb" format */
1523 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
1524 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
1525 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
1526 if (r
< 0 || g
< 0 || b
< 0)
1528 return RGB(r
, g
, b
);
1532 /* Check if the name is one of the colors we know */
1533 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
1534 if (STRICMP(name
, table
[i
].name
) == 0)
1535 return table
[i
].color
;
1539 * Try to look up a system colour.
1541 for (i
= 0; i
< sizeof(sys_table
) / sizeof(sys_table
[0]); i
++)
1542 if (STRICMP(name
, sys_table
[i
].name
) == 0)
1543 return GetSysColor(sys_table
[i
].color
);
1546 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
1549 #define LINE_LEN 100
1551 char line
[LINE_LEN
];
1554 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
1558 fd
= mch_fopen((char *)fname
, "rt");
1569 fgets(line
, LINE_LEN
, fd
);
1570 len
= (int)STRLEN(line
);
1572 if (len
<= 1 || line
[len
-1] != '\n')
1577 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
1583 if (STRICMP(color
, name
) == 0)
1586 return (guicolor_T
) RGB(r
, g
, b
);
1596 * Return OK if the key with the termcap name "name" is supported.
1599 gui_mch_haskey(char_u
*name
)
1603 for (i
= 0; special_keys
[i
].vim_code1
!= NUL
; i
++)
1604 if (name
[0] == special_keys
[i
].vim_code0
&&
1605 name
[1] == special_keys
[i
].vim_code1
)
1616 * Invert a rectangle from row r, column c, for nr rows and nc columns.
1619 gui_mch_invert_rectangle(
1628 * Note: InvertRect() excludes right and bottom of rectangle.
1630 rc
.left
= FILL_X(c
);
1632 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
1633 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
1634 InvertRect(s_hdc
, &rc
);
1638 * Iconify the GUI window.
1641 gui_mch_iconify(void)
1643 ShowWindow(s_hwnd
, SW_MINIMIZE
);
1647 * Draw a cursor without focus.
1650 gui_mch_draw_hollow_cursor(guicolor_T color
)
1656 * Note: FrameRect() excludes right and bottom of rectangle.
1658 rc
.left
= FILL_X(gui
.col
);
1659 rc
.top
= FILL_Y(gui
.row
);
1660 rc
.right
= rc
.left
+ gui
.char_width
;
1662 if (mb_lefthalve(gui
.row
, gui
.col
))
1663 rc
.right
+= gui
.char_width
;
1665 rc
.bottom
= rc
.top
+ gui
.char_height
;
1666 hbr
= CreateSolidBrush(color
);
1667 FrameRect(s_hdc
, &rc
, hbr
);
1671 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1675 gui_mch_draw_part_cursor(
1684 * Note: FillRect() excludes right and bottom of rectangle.
1687 #ifdef FEAT_RIGHTLEFT
1688 /* vertical line should be on the right of current point */
1689 CURSOR_BAR_RIGHT
? FILL_X(gui
.col
+ 1) - w
:
1692 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
1693 rc
.right
= rc
.left
+ w
;
1694 rc
.bottom
= rc
.top
+ h
;
1695 hbr
= CreateSolidBrush(color
);
1696 FillRect(s_hdc
, &rc
, hbr
);
1701 * Process a single Windows message.
1702 * If one is not available we hang until one is.
1705 process_message(void)
1708 UINT vk
= 0; /* Virtual key */
1714 static char_u k10
[] = {K_SPECIAL
, 'k', ';', 0};
1717 GetMessage(&msg
, NULL
, 0, 0);
1720 /* Look after OLE Automation commands */
1721 if (msg
.message
== WM_OLE
)
1723 char_u
*str
= (char_u
*)msg
.lParam
;
1724 if (str
== NULL
|| *str
== NUL
)
1726 /* Message can't be ours, forward it. Fixes problem with Ultramon
1728 DispatchMessage(&msg
);
1732 add_to_input_buf(str
, (int)STRLEN(str
));
1733 vim_free(str
); /* was allocated in CVim::SendKeys() */
1739 #ifdef FEAT_NETBEANS_INTG
1740 if (msg
.message
== WM_NETBEANS
)
1742 messageFromNetbeansW32();
1748 if (sniff_request_waiting
&& want_sniff_request
)
1750 static char_u bytes
[3] = {CSI
, (char_u
)KS_EXTRA
, (char_u
)KE_SNIFF
};
1751 add_to_input_buf(bytes
, 3); /* K_SNIFF */
1752 sniff_request_waiting
= 0;
1753 want_sniff_request
= 0;
1754 /* request is handled in normal.c */
1756 if (msg
.message
== WM_USER
)
1758 MyTranslateMessage(&msg
);
1759 DispatchMessage(&msg
);
1764 #ifdef MSWIN_FIND_REPLACE
1765 /* Don't process messages used by the dialog */
1766 if (s_findrep_hwnd
!= NULL
&& IsDialogMessage(s_findrep_hwnd
, &msg
))
1768 HandleMouseHide(msg
.message
, msg
.lParam
);
1774 * Check if it's a special key that we recognise. If not, call
1775 * TranslateMessage().
1777 if (msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_SYSKEYDOWN
)
1779 vk
= (int) msg
.wParam
;
1780 /* handle key after dead key, but ignore shift, alt and control */
1781 if (dead_key
&& vk
!= VK_SHIFT
&& vk
!= VK_MENU
&& vk
!= VK_CONTROL
)
1784 /* handle non-alphabetic keys (ones that hopefully cannot generate
1785 * umlaut-characters), unless when control is down */
1786 if (vk
< 'A' || vk
> 'Z' || (GetKeyState(VK_CONTROL
) & 0x8000))
1790 dm
.message
= msg
.message
;
1792 dm
.wParam
= VK_SPACE
;
1793 MyTranslateMessage(&dm
); /* generate dead character */
1794 if (vk
!= VK_SPACE
) /* and send current character once more */
1795 PostMessage(msg
.hwnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
1800 /* Check for CTRL-BREAK */
1801 if (vk
== VK_CANCEL
)
1806 add_to_input_buf(string
, 1);
1809 for (i
= 0; special_keys
[i
].key_sym
!= 0; i
++)
1811 /* ignore VK_SPACE when ALT key pressed: system menu */
1812 if (special_keys
[i
].key_sym
== vk
1813 && (vk
!= VK_SPACE
|| !(GetKeyState(VK_MENU
) & 0x8000)))
1816 /* Check for <F10>: Windows selects the menu. When <F10> is
1817 * mapped we want to use the mapping instead. */
1819 && gui
.menu_is_active
1820 && check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1823 if (GetKeyState(VK_SHIFT
) & 0x8000)
1824 modifiers
|= MOD_MASK_SHIFT
;
1826 * Don't use caps-lock as shift, because these are special keys
1827 * being considered here, and we only want letters to get
1831 if (GetKeyState(VK_CAPITAL) & 0x0001)
1832 modifiers ^= MOD_MASK_SHIFT;
1834 if (GetKeyState(VK_CONTROL
) & 0x8000)
1835 modifiers
|= MOD_MASK_CTRL
;
1836 if (GetKeyState(VK_MENU
) & 0x8000)
1837 modifiers
|= MOD_MASK_ALT
;
1839 if (special_keys
[i
].vim_code1
== NUL
)
1840 key
= special_keys
[i
].vim_code0
;
1842 key
= TO_SPECIAL(special_keys
[i
].vim_code0
,
1843 special_keys
[i
].vim_code1
);
1844 key
= simplify_key(key
, &modifiers
);
1851 string
[1] = KS_MODIFIER
;
1852 string
[2] = modifiers
;
1853 add_to_input_buf(string
, 3);
1856 if (IS_SPECIAL(key
))
1859 string
[1] = K_SECOND(key
);
1860 string
[2] = K_THIRD(key
);
1861 add_to_input_buf(string
, 3);
1867 /* Handle "key" as a Unicode character. */
1868 len
= char_to_string(key
, string
, 40, FALSE
);
1869 add_to_input_buf(string
, len
);
1874 if (special_keys
[i
].key_sym
== 0)
1876 /* Some keys need C-S- where they should only need C-.
1877 * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1878 * system startup (Helmut Stiegler, 2003 Oct 3). */
1880 && (GetKeyState(VK_CONTROL
) & 0x8000)
1881 && !(GetKeyState(VK_SHIFT
) & 0x8000)
1882 && !(GetKeyState(VK_MENU
) & 0x8000))
1884 /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1885 if (vk
== '6' || MapVirtualKey(vk
, 2) == (UINT
)'^')
1887 string
[0] = Ctrl_HAT
;
1888 add_to_input_buf(string
, 1);
1890 /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
1891 else if (vk
== 0xBD) /* QWERTY for CTRL-'-' */
1894 add_to_input_buf(string
, 1);
1896 /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
1897 else if (vk
== '2' || MapVirtualKey(vk
, 2) == (UINT
)'@')
1899 string
[0] = Ctrl_AT
;
1900 add_to_input_buf(string
, 1);
1903 MyTranslateMessage(&msg
);
1906 MyTranslateMessage(&msg
);
1909 #ifdef FEAT_MBYTE_IME
1910 else if (msg
.message
== WM_IME_NOTIFY
)
1911 _OnImeNotify(msg
.hwnd
, (DWORD
)msg
.wParam
, (DWORD
)msg
.lParam
);
1912 else if (msg
.message
== WM_KEYUP
&& im_get_status())
1913 /* added for non-MS IME (Yasuhiro Matsumoto) */
1914 MyTranslateMessage(&msg
);
1916 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
1918 else if (msg
.message
== WM_IME_STARTCOMPOSITION
)
1922 global_ime_set_font(&norm_logfont
);
1923 point
.x
= FILL_X(gui
.col
);
1924 point
.y
= FILL_Y(gui
.row
);
1925 MapWindowPoints(s_textArea
, s_hwnd
, &point
, 1);
1926 global_ime_set_position(&point
);
1931 /* Check for <F10>: Default effect is to select the menu. When <F10> is
1932 * mapped we need to stop it here to avoid strange effects (e.g., for the
1934 if (vk
!= VK_F10
|| check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1936 DispatchMessage(&msg
);
1940 * Catch up with any queued events. This may put keyboard input into the
1941 * input buffer, call resize call-backs, trigger timers etc. If there is
1942 * nothing in the event queue (& no timers pending), then we return
1946 gui_mch_update(void)
1950 if (!s_busy_processing
)
1951 while (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
)
1952 && !vim_is_input_buf_full())
1957 * GUI input routine called by gui_wait_for_chars(). Waits for a character
1958 * from the keyboard.
1959 * wtime == -1 Wait forever.
1960 * wtime == 0 This should never happen.
1961 * wtime > 0 Wait wtime milliseconds for a character.
1962 * Returns OK if a character was found to be available within the given time,
1963 * or FAIL otherwise.
1966 gui_mch_wait_for_chars(int wtime
)
1971 s_timed_out
= FALSE
;
1975 /* Don't do anything while processing a (scroll) message. */
1976 if (s_busy_processing
)
1978 s_wait_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)wtime
,
1979 (TIMERPROC
)_OnTimer
);
1982 allow_scrollbar
= TRUE
;
1984 focus
= gui
.in_focus
;
1985 while (!s_timed_out
)
1987 /* Stop or start blinking when focus changes */
1988 if (gui
.in_focus
!= focus
)
1991 gui_mch_start_blink();
1993 gui_mch_stop_blink();
1994 focus
= gui
.in_focus
;
1997 if (s_need_activate
)
2000 (void)SetForegroundWindow(s_hwnd
);
2002 (void)SetActiveWindow(s_hwnd
);
2004 s_need_activate
= FALSE
;
2007 #ifdef FEAT_NETBEANS_INTG
2008 /* Process the queued netbeans messages. */
2009 netbeans_parse_messages();
2013 * Don't use gui_mch_update() because then we will spin-lock until a
2014 * char arrives, instead we use GetMessage() to hang until an
2015 * event arrives. No need to check for input_buf_full because we are
2016 * returning as soon as it contains a single char -- webb
2020 if (input_available())
2022 if (s_wait_timer
!= 0 && !s_timed_out
)
2024 KillTimer(NULL
, s_wait_timer
);
2026 /* Eat spurious WM_TIMER messages */
2027 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
2031 allow_scrollbar
= FALSE
;
2033 /* Clear pending mouse button, the release event may have been
2034 * taken by the dialog window. But don't do this when getting
2035 * focus, we need the mouse-up event then. */
2036 if (!s_getting_focus
)
2037 s_button_pending
= -1;
2042 allow_scrollbar
= FALSE
;
2047 * Clear a rectangular region of the screen from text pos (row1, col1) to
2048 * (row2, col2) inclusive.
2051 gui_mch_clear_block(
2060 * Clear one extra pixel at the far right, for when bold characters have
2061 * spilled over to the window border.
2062 * Note: FillRect() excludes right and bottom of rectangle.
2064 rc
.left
= FILL_X(col1
);
2065 rc
.top
= FILL_Y(row1
);
2066 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
2067 rc
.bottom
= FILL_Y(row2
+ 1);
2072 * Clear the whole text window.
2075 gui_mch_clear_all(void)
2081 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
2082 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
2090 gui_mch_enable_menu(int flag
)
2093 SetMenu(s_hwnd
, flag
? s_menuBar
: NULL
);
2099 gui_mch_set_menu_pos(
2105 /* It will be in the right place anyway */
2108 #if defined(FEAT_MENU) || defined(PROTO)
2110 * Make menu item hidden or not hidden
2113 gui_mch_menu_hidden(
2118 * This doesn't do what we want. Hmm, just grey the menu items for now.
2122 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2124 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2126 gui_mch_menu_grey(menu
, hidden
);
2130 * This is called after setting all the menus to grey/hidden or not.
2133 gui_mch_draw_menubar(void)
2135 DrawMenuBar(s_hwnd
);
2137 #endif /*FEAT_MENU*/
2145 SaveInst(HINSTANCE hInst
)
2152 * Return the RGB value of a pixel as a long.
2155 gui_mch_get_rgb(guicolor_T pixel
)
2157 return (GetRValue(pixel
) << 16) + (GetGValue(pixel
) << 8)
2161 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2162 /* Convert pixels in X to dialog units */
2164 PixelToDialogX(int numPixels
)
2166 return (WORD
)((numPixels
* 4) / s_dlgfntwidth
);
2169 /* Convert pixels in Y to dialog units */
2171 PixelToDialogY(int numPixels
)
2173 return (WORD
)((numPixels
* 8) / s_dlgfntheight
);
2176 /* Return the width in pixels of the given text in the given DC. */
2178 GetTextWidth(HDC hdc
, char_u
*str
, int len
)
2182 GetTextExtentPoint(hdc
, str
, len
, &size
);
2188 * Return the width in pixels of the given text in the given DC, taking care
2189 * of 'encoding' to active codepage conversion.
2192 GetTextWidthEnc(HDC hdc
, char_u
*str
, int len
)
2199 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2201 /* 'encoding' differs from active codepage: convert text and use wide
2203 wstr
= enc_to_utf16(str
, &wlen
);
2206 n
= GetTextExtentPointW(hdc
, wstr
, wlen
, &size
);
2213 return GetTextWidth(hdc
, str
, len
);
2216 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
2220 * A quick little routine that will center one window over another, handy for
2221 * dialog boxes. Taken from the Win32SDK samples.
2228 RECT rChild
, rParent
;
2229 int wChild
, hChild
, wParent
, hParent
;
2230 int wScreen
, hScreen
, xNew
, yNew
;
2233 GetWindowRect(hwndChild
, &rChild
);
2234 wChild
= rChild
.right
- rChild
.left
;
2235 hChild
= rChild
.bottom
- rChild
.top
;
2237 /* If Vim is minimized put the window in the middle of the screen. */
2238 if (hwndParent
== NULL
|| IsMinimized(hwndParent
))
2243 rParent
.right
= GetSystemMetrics(SM_CXSCREEN
);
2244 rParent
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
2246 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rParent
, 0);
2250 GetWindowRect(hwndParent
, &rParent
);
2251 wParent
= rParent
.right
- rParent
.left
;
2252 hParent
= rParent
.bottom
- rParent
.top
;
2254 hdc
= GetDC(hwndChild
);
2255 wScreen
= GetDeviceCaps (hdc
, HORZRES
);
2256 hScreen
= GetDeviceCaps (hdc
, VERTRES
);
2257 ReleaseDC(hwndChild
, hdc
);
2259 xNew
= rParent
.left
+ ((wParent
- wChild
) /2);
2264 else if ((xNew
+wChild
) > wScreen
)
2266 xNew
= wScreen
- wChild
;
2269 yNew
= rParent
.top
+ ((hParent
- hChild
) /2);
2272 else if ((yNew
+hChild
) > hScreen
)
2273 yNew
= hScreen
- hChild
;
2275 return SetWindowPos(hwndChild
, NULL
, xNew
, yNew
, 0, 0,
2276 SWP_NOSIZE
| SWP_NOZORDER
);
2278 #endif /* FEAT_GUI_DIALOG */
2281 gui_mch_activate_window(void)
2283 (void)SetActiveWindow(s_hwnd
);
2286 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2288 gui_mch_show_toolbar(int showit
)
2290 if (s_toolbarhwnd
== NULL
)
2296 # ifndef TB_SETUNICODEFORMAT
2297 /* For older compilers. We assume this never changes. */
2298 # define TB_SETUNICODEFORMAT 0x2005
2300 /* Enable/disable unicode support */
2301 int uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2302 SendMessage(s_toolbarhwnd
, TB_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2304 ShowWindow(s_toolbarhwnd
, SW_SHOW
);
2307 ShowWindow(s_toolbarhwnd
, SW_HIDE
);
2310 /* Then number of bitmaps is fixed. Exit is missing! */
2311 #define TOOLBAR_BITMAP_COUNT 31
2315 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2317 add_tabline_popup_menu_entry(HMENU pmenu
, UINT item_id
, char_u
*item_text
)
2323 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2325 /* 'encoding' differs from active codepage: convert menu name
2326 * and use wide function */
2327 wn
= enc_to_utf16(item_text
, NULL
);
2330 MENUITEMINFOW infow
;
2332 infow
.cbSize
= sizeof(infow
);
2333 infow
.fMask
= MIIM_TYPE
| MIIM_ID
;
2334 infow
.wID
= item_id
;
2335 infow
.fType
= MFT_STRING
;
2336 infow
.dwTypeData
= wn
;
2337 infow
.cch
= (UINT
)wcslen(wn
);
2338 n
= InsertMenuItemW(pmenu
, item_id
, FALSE
, &infow
);
2340 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2341 /* Failed, try using non-wide function. */
2351 info
.cbSize
= sizeof(info
);
2352 info
.fMask
= MIIM_TYPE
| MIIM_ID
;
2354 info
.fType
= MFT_STRING
;
2355 info
.dwTypeData
= item_text
;
2356 info
.cch
= (UINT
)STRLEN(item_text
);
2357 InsertMenuItem(pmenu
, item_id
, FALSE
, &info
);
2362 show_tabline_popup_menu(void)
2368 /* When ignoring events don't show the menu. */
2376 tab_pmenu
= CreatePopupMenu();
2377 if (tab_pmenu
== NULL
)
2380 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_CLOSE
, _("Close tab"));
2381 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_NEW
, _("New tab"));
2382 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_OPEN
,
2386 rval
= TrackPopupMenuEx(tab_pmenu
, TPM_RETURNCMD
, pt
.x
, pt
.y
, s_tabhwnd
,
2389 DestroyMenu(tab_pmenu
);
2391 /* Add the string cmd into input buffer */
2394 TCHITTESTINFO htinfo
;
2397 if (ScreenToClient(s_tabhwnd
, &pt
) == 0)
2402 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
2408 send_tabline_menu_event(idx
, (int)rval
);
2413 * Show or hide the tabline.
2416 gui_mch_show_tabline(int showit
)
2418 if (s_tabhwnd
== NULL
)
2421 if (!showit
!= !showing_tabline
)
2424 ShowWindow(s_tabhwnd
, SW_SHOW
);
2426 ShowWindow(s_tabhwnd
, SW_HIDE
);
2427 showing_tabline
= showit
;
2432 * Return TRUE when tabline is displayed.
2435 gui_mch_showing_tabline(void)
2437 return s_tabhwnd
!= NULL
&& showing_tabline
;
2441 * Update the labels of the tabline.
2444 gui_mch_update_tabline(void)
2452 static int use_unicode
= FALSE
;
2457 if (s_tabhwnd
== NULL
)
2460 #if defined(FEAT_MBYTE)
2461 # ifndef CCM_SETUNICODEFORMAT
2462 /* For older compilers. We assume this never changes. */
2463 # define CCM_SETUNICODEFORMAT 0x2005
2465 uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2466 if (uu
!= use_unicode
)
2468 /* Enable/disable unicode support */
2469 SendMessage(s_tabhwnd
, CCM_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2474 tie
.mask
= TCIF_TEXT
;
2477 /* Add a label for each tab page. They all contain the same text area. */
2478 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
2483 if (!TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2486 tie
.pszText
= "-Empty-";
2487 TabCtrl_InsertItem(s_tabhwnd
, nr
, &tie
);
2490 get_tabline_label(tp
, FALSE
);
2491 tie
.pszText
= NameBuff
;
2496 /* Need to go through Unicode. */
2497 wstr
= enc_to_utf16(NameBuff
, NULL
);
2502 tiw
.mask
= TCIF_TEXT
;
2505 SendMessage(s_tabhwnd
, TCM_SETITEMW
, (WPARAM
)nr
, (LPARAM
)&tiw
);
2512 TabCtrl_SetItem(s_tabhwnd
, nr
, &tie
);
2516 /* Remove any old labels. */
2517 while (TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2518 TabCtrl_DeleteItem(s_tabhwnd
, nr
);
2520 if (TabCtrl_GetCurSel(s_tabhwnd
) != curtabidx
)
2521 TabCtrl_SetCurSel(s_tabhwnd
, curtabidx
);
2525 * Set the current tab to "nr". First tab is 1.
2528 gui_mch_set_curtab(nr
)
2531 if (s_tabhwnd
== NULL
)
2534 if (TabCtrl_GetCurSel(s_tabhwnd
) != nr
-1)
2535 TabCtrl_SetCurSel(s_tabhwnd
, nr
-1);
2541 * ":simalt" command.
2544 ex_simalt(exarg_T
*eap
)
2546 char_u
*keys
= eap
->arg
;
2548 PostMessage(s_hwnd
, WM_SYSCOMMAND
, (WPARAM
)SC_KEYMENU
, (LPARAM
)0);
2552 *keys
= ' '; /* for showing system menu */
2553 PostMessage(s_hwnd
, WM_CHAR
, (WPARAM
)*keys
, (LPARAM
)0);
2559 * Create the find & replace dialogs.
2560 * You can't have both at once: ":find" when replace is showing, destroys
2561 * the replace dialog first, and the other way around.
2563 #ifdef MSWIN_FIND_REPLACE
2565 initialise_findrep(char_u
*initial_string
)
2571 /* Get the search string to use. */
2572 entry_text
= get_find_dialog_text(initial_string
, &wword
, &mcase
);
2574 s_findrep_struct
.hwndOwner
= s_hwnd
;
2575 s_findrep_struct
.Flags
= FR_DOWN
;
2577 s_findrep_struct
.Flags
|= FR_MATCHCASE
;
2579 s_findrep_struct
.Flags
|= FR_WHOLEWORD
;
2580 if (entry_text
!= NULL
&& *entry_text
!= NUL
)
2581 vim_strncpy(s_findrep_struct
.lpstrFindWhat
, entry_text
,
2582 s_findrep_struct
.wFindWhatLen
- 1);
2583 vim_free(entry_text
);
2588 set_window_title(HWND hwnd
, char *title
)
2591 if (title
!= NULL
&& enc_codepage
>= 0 && enc_codepage
!= (int)GetACP())
2596 /* Convert the title from 'encoding' to UTF-16. */
2597 wbuf
= (WCHAR
*)enc_to_utf16((char_u
*)title
, NULL
);
2600 n
= SetWindowTextW(hwnd
, wbuf
);
2602 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2604 /* Retry with non-wide function (for Windows 98). */
2608 (void)SetWindowText(hwnd
, (LPCSTR
)title
);
2612 gui_mch_find_dialog(exarg_T
*eap
)
2614 #ifdef MSWIN_FIND_REPLACE
2615 if (s_findrep_msg
!= 0)
2617 if (IsWindow(s_findrep_hwnd
) && !s_findrep_is_find
)
2618 DestroyWindow(s_findrep_hwnd
);
2620 if (!IsWindow(s_findrep_hwnd
))
2622 initialise_findrep(eap
->arg
);
2623 # if defined(FEAT_MBYTE) && defined(WIN3264)
2624 /* If the OS is Windows NT, and 'encoding' differs from active
2625 * codepage: convert text and use wide function. */
2626 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2627 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2629 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2630 s_findrep_hwnd
= FindTextW(
2631 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2635 s_findrep_hwnd
= FindText((LPFINDREPLACE
) &s_findrep_struct
);
2638 set_window_title(s_findrep_hwnd
,
2639 _("Find string (use '\\\\' to find a '\\')"));
2640 (void)SetFocus(s_findrep_hwnd
);
2642 s_findrep_is_find
= TRUE
;
2649 gui_mch_replace_dialog(exarg_T
*eap
)
2651 #ifdef MSWIN_FIND_REPLACE
2652 if (s_findrep_msg
!= 0)
2654 if (IsWindow(s_findrep_hwnd
) && s_findrep_is_find
)
2655 DestroyWindow(s_findrep_hwnd
);
2657 if (!IsWindow(s_findrep_hwnd
))
2659 initialise_findrep(eap
->arg
);
2660 # if defined(FEAT_MBYTE) && defined(WIN3264)
2661 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2662 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2664 findrep_atow(&s_findrep_struct_w
, &s_findrep_struct
);
2665 s_findrep_hwnd
= ReplaceTextW(
2666 (LPFINDREPLACEW
) &s_findrep_struct_w
);
2670 s_findrep_hwnd
= ReplaceText(
2671 (LPFINDREPLACE
) &s_findrep_struct
);
2674 set_window_title(s_findrep_hwnd
,
2675 _("Find & Replace (use '\\\\' to find a '\\')"));
2676 (void)SetFocus(s_findrep_hwnd
);
2678 s_findrep_is_find
= FALSE
;
2685 * Set visibility of the pointer.
2688 gui_mch_mousehide(int hide
)
2690 if (hide
!= gui
.pointer_hidden
)
2693 gui
.pointer_hidden
= hide
;
2699 gui_mch_show_popupmenu_at(vimmenu_T
*menu
, int x
, int y
)
2701 /* Unhide the mouse, we don't get move events here. */
2702 gui_mch_mousehide(FALSE
);
2704 (void)TrackPopupMenu(
2705 (HMENU
)menu
->submenu_id
,
2706 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2708 (int)0, /*reserved param*/
2712 * NOTE: The pop-up menu can eat the mouse up event.
2713 * We deal with this in normal.c.
2719 * Got a message when the system will go down.
2724 getout_preserve_modified(1);
2728 * Get this message when the user clicks on the cross in the top right corner
2729 * of a Windows95 window.
2740 * Get a message when the window is being destroyed.
2747 Ctl3dUnregister(s_hinst
);
2757 if (!IsMinimized(hwnd
))
2761 out_flush(); /* make sure all output has been processed */
2762 (void)BeginPaint(hwnd
, &ps
);
2765 /* prevent multi-byte characters from misprinting on an invalid
2771 GetClientRect(hwnd
, &rect
);
2772 ps
.rcPaint
.left
= rect
.left
;
2773 ps
.rcPaint
.right
= rect
.right
;
2777 if (!IsRectEmpty(&ps
.rcPaint
))
2778 gui_redraw(ps
.rcPaint
.left
, ps
.rcPaint
.top
,
2779 ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1,
2780 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1);
2781 EndPaint(hwnd
, &ps
);
2793 if (!IsMinimized(hwnd
))
2795 gui_resize_shell(cx
, cy
);
2798 /* Menu bar may wrap differently now */
2799 gui_mswin_get_menu_height(TRUE
);
2809 gui_focus_change(TRUE
);
2810 s_getting_focus
= TRUE
;
2811 (void)MyWindowProc(hwnd
, WM_SETFOCUS
, (WPARAM
)hwndOldFocus
, 0);
2819 gui_focus_change(FALSE
);
2820 s_getting_focus
= FALSE
;
2821 (void)MyWindowProc(hwnd
, WM_KILLFOCUS
, (WPARAM
)hwndNewFocus
, 0);
2825 * Get a message when the user switches back to vim
2842 /* we call gui_focus_change() in _OnSetFocus() */
2843 /* gui_focus_change((int)fActivate); */
2844 return MyWindowProc(hwnd
, WM_ACTIVATEAPP
, fActivate
, (DWORD
)dwThreadId
);
2847 #if defined(FEAT_WINDOWS) || defined(PROTO)
2849 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
2851 DestroyWindow(sb
->id
);
2856 * Get current mouse coordinates in text window.
2859 gui_mch_getmouse(int *x
, int *y
)
2864 (void)GetWindowRect(s_textArea
, &rct
);
2865 (void)GetCursorPos((LPPOINT
)&mp
);
2866 *x
= (int)(mp
.x
- rct
.left
);
2867 *y
= (int)(mp
.y
- rct
.top
);
2871 * Move mouse pointer to character at (x, y).
2874 gui_mch_setmouse(int x
, int y
)
2878 (void)GetWindowRect(s_textArea
, &rct
);
2879 (void)SetCursorPos(x
+ gui
.border_offset
+ rct
.left
,
2880 y
+ gui
.border_offset
+ rct
.top
);
2884 gui_mswin_get_valid_dimensions(
2890 int base_width
, base_height
;
2892 base_width
= gui_get_base_width()
2893 + GetSystemMetrics(SM_CXFRAME
) * 2;
2894 base_height
= gui_get_base_height()
2895 + GetSystemMetrics(SM_CYFRAME
) * 2
2896 + GetSystemMetrics(SM_CYCAPTION
)
2898 + gui_mswin_get_menu_height(FALSE
)
2901 *valid_w
= base_width
+
2902 ((w
- base_width
) / gui
.char_width
) * gui
.char_width
;
2903 *valid_h
= base_height
+
2904 ((h
- base_height
) / gui
.char_height
) * gui
.char_height
;
2908 gui_mch_flash(int msec
)
2913 * Note: InvertRect() excludes right and bottom of rectangle.
2917 rc
.right
= gui
.num_cols
* gui
.char_width
;
2918 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
2919 InvertRect(s_hdc
, &rc
);
2920 gui_mch_flush(); /* make sure it's displayed */
2922 ui_delay((long)msec
, TRUE
); /* wait for a few msec */
2924 InvertRect(s_hdc
, &rc
);
2928 * Return flags used for scrolling.
2929 * The SW_INVALIDATE is required when part of the window is covered or
2930 * off-screen. Refer to MS KB Q75236.
2933 get_scroll_flags(void)
2936 RECT rcVim
, rcOther
, rcDest
;
2938 GetWindowRect(s_hwnd
, &rcVim
);
2940 /* Check if the window is partly above or below the screen. We don't care
2941 * about partly left or right of the screen, it is not relevant when
2942 * scrolling up or down. */
2943 if (rcVim
.top
< 0 || rcVim
.bottom
> GetSystemMetrics(SM_CYFULLSCREEN
))
2944 return SW_INVALIDATE
;
2946 /* Check if there is an window (partly) on top of us. */
2947 for (hwnd
= s_hwnd
; (hwnd
= GetWindow(hwnd
, GW_HWNDPREV
)) != (HWND
)0; )
2948 if (IsWindowVisible(hwnd
))
2950 GetWindowRect(hwnd
, &rcOther
);
2951 if (IntersectRect(&rcDest
, &rcVim
, &rcOther
))
2952 return SW_INVALIDATE
;
2958 * Delete the given number of lines from the given row, scrolling up any
2959 * text further down within the scroll region.
2962 gui_mch_delete_lines(
2968 rc
.left
= FILL_X(gui
.scroll_region_left
);
2969 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2970 rc
.top
= FILL_Y(row
);
2971 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2973 ScrollWindowEx(s_textArea
, 0, -num_lines
* gui
.char_height
,
2974 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2976 UpdateWindow(s_textArea
);
2977 /* This seems to be required to avoid the cursor disappearing when
2978 * scrolling such that the cursor ends up in the top-left character on
2979 * the screen... But why? (Webb) */
2980 /* It's probably fixed by disabling drawing the cursor while scrolling. */
2981 /* gui.cursor_is_valid = FALSE; */
2983 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
2984 gui
.scroll_region_left
,
2985 gui
.scroll_region_bot
, gui
.scroll_region_right
);
2989 * Insert the given number of lines before the given row, scrolling down any
2990 * following text within the scroll region.
2993 gui_mch_insert_lines(
2999 rc
.left
= FILL_X(gui
.scroll_region_left
);
3000 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
3001 rc
.top
= FILL_Y(row
);
3002 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
3003 /* The SW_INVALIDATE is required when part of the window is covered or
3004 * off-screen. How do we avoid it when it's not needed? */
3005 ScrollWindowEx(s_textArea
, 0, num_lines
* gui
.char_height
,
3006 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
3008 UpdateWindow(s_textArea
);
3010 gui_clear_block(row
, gui
.scroll_region_left
,
3011 row
+ num_lines
- 1, gui
.scroll_region_right
);
3017 gui_mch_exit(int rc
)
3019 ReleaseDC(s_textArea
, s_hdc
);
3020 DeleteObject(s_brush
);
3023 /* Unload the tearoff bitmap */
3024 (void)DeleteObject((HGDIOBJ
)s_htearbitmap
);
3027 /* Destroy our window (if we have one). */
3030 destroying
= TRUE
; /* ignore WM_DESTROY message now */
3031 DestroyWindow(s_hwnd
);
3040 logfont2name(LOGFONT lf
)
3046 charset_name
= charset_id2name((int)lf
.lfCharSet
);
3047 res
= alloc((unsigned)(strlen(lf
.lfFaceName
) + 20
3048 + (charset_name
== NULL
? 0 : strlen(charset_name
) + 2)));
3052 /* make a normal font string out of the lf thing:*/
3053 sprintf((char *)p
, "%s:h%d", lf
.lfFaceName
, pixels_to_points(
3054 lf
.lfHeight
< 0 ? -lf
.lfHeight
: lf
.lfHeight
, TRUE
));
3061 #ifndef MSWIN16_FASTTEXT
3064 if (lf
.lfWeight
>= FW_BOLD
)
3071 if (charset_name
!= NULL
)
3074 STRCAT(p
, charset_name
);
3082 * Initialise vim to use the font with the given name.
3083 * Return FAIL if the font could not be loaded, OK otherwise.
3087 gui_mch_init_font(char_u
*font_name
, int fontset
)
3090 GuiFont font
= NOFONT
;
3094 if (get_logfont(&lf
, font_name
, NULL
, TRUE
) == OK
)
3095 font
= get_font_handle(&lf
);
3099 if (font_name
== NULL
)
3100 font_name
= lf
.lfFaceName
;
3101 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
3104 #ifdef FEAT_MBYTE_IME
3107 gui_mch_free_font(gui
.norm_font
);
3108 gui
.norm_font
= font
;
3109 current_font_height
= lf
.lfHeight
;
3112 p
= logfont2name(lf
);
3115 hl_set_font_name(p
);
3117 /* When setting 'guifont' to "*" replace it with the actual font name.
3119 if (STRCMP(font_name
, "*") == 0 && STRCMP(p_guifont
, "*") == 0)
3121 vim_free(p_guifont
);
3128 #ifndef MSWIN16_FASTTEXT
3129 gui_mch_free_font(gui
.ital_font
);
3130 gui
.ital_font
= NOFONT
;
3131 gui_mch_free_font(gui
.bold_font
);
3132 gui
.bold_font
= NOFONT
;
3133 gui_mch_free_font(gui
.boldital_font
);
3134 gui
.boldital_font
= NOFONT
;
3139 gui
.ital_font
= get_font_handle(&lf
);
3140 lf
.lfItalic
= FALSE
;
3142 if (lf
.lfWeight
< FW_BOLD
)
3144 lf
.lfWeight
= FW_BOLD
;
3145 gui
.bold_font
= get_font_handle(&lf
);
3149 gui
.boldital_font
= get_font_handle(&lf
);
3157 #ifndef WPF_RESTORETOMAXIMIZED
3158 # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
3162 * Return TRUE if the GUI window is maximized, filling the whole screen.
3169 wp
.length
= sizeof(WINDOWPLACEMENT
);
3170 if (GetWindowPlacement(s_hwnd
, &wp
))
3171 return wp
.showCmd
== SW_SHOWMAXIMIZED
3172 || (wp
.showCmd
== SW_SHOWMINIMIZED
3173 && wp
.flags
== WPF_RESTORETOMAXIMIZED
);
3179 * Called when the font changed while the window is maximized. Compute the
3180 * new Rows and Columns. This is like resizing the window.
3187 GetWindowRect(s_hwnd
, &rect
);
3188 gui_resize_shell(rect
.right
- rect
.left
3189 - GetSystemMetrics(SM_CXFRAME
) * 2,
3190 rect
.bottom
- rect
.top
3191 - GetSystemMetrics(SM_CYFRAME
) * 2
3192 - GetSystemMetrics(SM_CYCAPTION
)
3194 - gui_mswin_get_menu_height(FALSE
)
3200 * Set the window title
3208 set_window_title(s_hwnd
, (title
== NULL
? "VIM" : (char *)title
));
3211 #ifdef FEAT_MOUSESHAPE
3212 /* Table for shape IDCs. Keep in sync with the mshape_names[] table in
3214 static LPCSTR mshape_idcs
[] =
3216 MAKEINTRESOURCE(IDC_ARROW
), /* arrow */
3217 MAKEINTRESOURCE(0), /* blank */
3218 MAKEINTRESOURCE(IDC_IBEAM
), /* beam */
3219 MAKEINTRESOURCE(IDC_SIZENS
), /* updown */
3220 MAKEINTRESOURCE(IDC_SIZENS
), /* udsizing */
3221 MAKEINTRESOURCE(IDC_SIZEWE
), /* leftright */
3222 MAKEINTRESOURCE(IDC_SIZEWE
), /* lrsizing */
3223 MAKEINTRESOURCE(IDC_WAIT
), /* busy */
3225 MAKEINTRESOURCE(IDC_NO
), /* no */
3227 MAKEINTRESOURCE(IDC_ICON
), /* no */
3229 MAKEINTRESOURCE(IDC_ARROW
), /* crosshair */
3230 MAKEINTRESOURCE(IDC_ARROW
), /* hand1 */
3231 MAKEINTRESOURCE(IDC_ARROW
), /* hand2 */
3232 MAKEINTRESOURCE(IDC_ARROW
), /* pencil */
3233 MAKEINTRESOURCE(IDC_ARROW
), /* question */
3234 MAKEINTRESOURCE(IDC_ARROW
), /* right-arrow */
3235 MAKEINTRESOURCE(IDC_UPARROW
), /* up-arrow */
3236 MAKEINTRESOURCE(IDC_ARROW
) /* last one */
3240 mch_set_mouse_shape(int shape
)
3244 if (shape
== MSHAPE_HIDE
)
3248 if (shape
>= MSHAPE_NUMBERED
)
3249 idc
= MAKEINTRESOURCE(IDC_ARROW
);
3251 idc
= mshape_idcs
[shape
];
3252 #ifdef SetClassLongPtr
3253 SetClassLongPtr(s_textArea
, GCLP_HCURSOR
, (__int3264
)(LONG_PTR
)LoadCursor(NULL
, idc
));
3256 SetClassLong(s_textArea
, GCL_HCURSOR
, (long_u
)LoadCursor(NULL
, idc
));
3258 SetClassWord(s_textArea
, GCW_HCURSOR
, (WORD
)LoadCursor(NULL
, idc
));
3265 /* Set the position to make it redrawn with the new shape. */
3266 (void)GetCursorPos((LPPOINT
)&mp
);
3267 (void)SetCursorPos(mp
.x
, mp
.y
);
3276 * The file browser exists in two versions: with "W" uses wide characters,
3277 * without "W" the current codepage. When FEAT_MBYTE is defined and on
3278 * Windows NT/2000/XP the "W" functions are used.
3281 # if defined(FEAT_MBYTE) && defined(WIN3264)
3283 * Wide version of convert_filter(). Keep in sync!
3286 convert_filterW(char_u
*s
)
3289 unsigned s_len
= (unsigned)STRLEN(s
);
3292 res
= (WCHAR
*)alloc((s_len
+ 3) * sizeof(WCHAR
));
3295 for (i
= 0; i
< s_len
; ++i
)
3296 if (s
[i
] == '\t' || s
[i
] == '\n')
3301 /* Add two extra NULs to make sure it's properly terminated. */
3302 res
[s_len
+ 1] = NUL
;
3303 res
[s_len
+ 2] = NUL
;
3309 * Wide version of gui_mch_browse(). Keep in sync!
3320 /* We always use the wide function. This means enc_to_utf16() must work,
3321 * otherwise it fails miserably! */
3322 OPENFILENAMEW fileStruct
;
3323 WCHAR fileBuf
[MAXPATHL
];
3326 WCHAR
*titlep
= NULL
;
3328 WCHAR
*initdirp
= NULL
;
3336 wp
= enc_to_utf16(dflt
, NULL
);
3341 for (i
= 0; wp
[i
] != NUL
&& i
< MAXPATHL
- 1; ++i
)
3348 /* Convert the filter to Windows format. */
3349 filterp
= convert_filterW(filter
);
3351 memset(&fileStruct
, 0, sizeof(OPENFILENAMEW
));
3352 #ifdef OPENFILENAME_SIZE_VERSION_400
3353 /* be compatible with Windows NT 4.0 */
3354 /* TODO: what to use for OPENFILENAMEW??? */
3355 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3357 fileStruct
.lStructSize
= sizeof(fileStruct
);
3361 titlep
= enc_to_utf16(title
, NULL
);
3362 fileStruct
.lpstrTitle
= titlep
;
3365 extp
= enc_to_utf16(ext
, NULL
);
3366 fileStruct
.lpstrDefExt
= extp
;
3368 fileStruct
.lpstrFile
= fileBuf
;
3369 fileStruct
.nMaxFile
= MAXPATHL
;
3370 fileStruct
.lpstrFilter
= filterp
;
3371 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3372 /* has an initial dir been specified? */
3373 if (initdir
!= NULL
&& *initdir
!= NUL
)
3375 /* Must have backslashes here, no matter what 'shellslash' says */
3376 initdirp
= enc_to_utf16(initdir
, NULL
);
3377 if (initdirp
!= NULL
)
3379 for (wp
= initdirp
; *wp
!= NUL
; ++wp
)
3383 fileStruct
.lpstrInitialDir
= initdirp
;
3387 * TODO: Allow selection of multiple files. Needs another arg to this
3388 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3389 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3390 * files that don't exist yet, so I haven't put it in. What about
3391 * OFN_PATHMUSTEXIST?
3392 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3394 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3395 #ifdef FEAT_SHORTCUT
3396 if (curbuf
->b_p_bin
)
3397 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3401 if (!GetSaveFileNameW(&fileStruct
))
3406 if (!GetOpenFileNameW(&fileStruct
))
3415 /* Convert from UCS2 to 'encoding'. */
3416 p
= utf16_to_enc(fileBuf
, NULL
);
3418 /* when out of memory we get garbage for non-ASCII chars */
3422 /* Give focus back to main window (when using MDI). */
3425 /* Shorten the file name if possible */
3426 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3428 # endif /* FEAT_MBYTE */
3432 * Convert the string s to the proper format for a filter string by replacing
3433 * the \t and \n delimiters with \0.
3434 * Returns the converted string in allocated memory.
3436 * Keep in sync with convert_filterW() above!
3439 convert_filter(char_u
*s
)
3442 unsigned s_len
= (unsigned)STRLEN(s
);
3445 res
= alloc(s_len
+ 3);
3448 for (i
= 0; i
< s_len
; ++i
)
3449 if (s
[i
] == '\t' || s
[i
] == '\n')
3454 /* Add two extra NULs to make sure it's properly terminated. */
3455 res
[s_len
+ 1] = NUL
;
3456 res
[s_len
+ 2] = NUL
;
3462 * Select a directory.
3465 gui_mch_browsedir(char_u
*title
, char_u
*initdir
)
3467 /* We fake this: Use a filter that doesn't select anything and a default
3468 * file name that won't be used. */
3469 return gui_mch_browse(0, title
, (char_u
*)_("Not Used"), NULL
,
3470 initdir
, (char_u
*)_("Directory\t*.nothing\n"));
3474 * Pop open a file browser and return the file selected, in allocated memory,
3475 * or NULL if Cancel is hit.
3476 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
3477 * title - Title message for the file browser dialog.
3478 * dflt - Default name of file.
3479 * ext - Default extension to be added to files without extensions.
3480 * initdir - directory in which to open the browser (NULL = current dir)
3481 * filter - Filter for matched files to choose from.
3483 * Keep in sync with gui_mch_browseW() above!
3494 OPENFILENAME fileStruct
;
3495 char_u fileBuf
[MAXPATHL
];
3496 char_u
*initdirp
= NULL
;
3500 # if defined(FEAT_MBYTE) && defined(WIN3264)
3501 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
3502 return gui_mch_browseW(saving
, title
, dflt
, ext
, initdir
, filter
);
3508 vim_strncpy(fileBuf
, dflt
, MAXPATHL
- 1);
3510 /* Convert the filter to Windows format. */
3511 filterp
= convert_filter(filter
);
3513 memset(&fileStruct
, 0, sizeof(OPENFILENAME
));
3514 #ifdef OPENFILENAME_SIZE_VERSION_400
3515 /* be compatible with Windows NT 4.0 */
3516 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3518 fileStruct
.lStructSize
= sizeof(fileStruct
);
3521 fileStruct
.lpstrTitle
= title
;
3522 fileStruct
.lpstrDefExt
= ext
;
3524 fileStruct
.lpstrFile
= fileBuf
;
3525 fileStruct
.nMaxFile
= MAXPATHL
;
3526 fileStruct
.lpstrFilter
= filterp
;
3527 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3528 /* has an initial dir been specified? */
3529 if (initdir
!= NULL
&& *initdir
!= NUL
)
3531 /* Must have backslashes here, no matter what 'shellslash' says */
3532 initdirp
= vim_strsave(initdir
);
3533 if (initdirp
!= NULL
)
3534 for (p
= initdirp
; *p
!= NUL
; ++p
)
3537 fileStruct
.lpstrInitialDir
= initdirp
;
3541 * TODO: Allow selection of multiple files. Needs another arg to this
3542 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3543 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3544 * files that don't exist yet, so I haven't put it in. What about
3545 * OFN_PATHMUSTEXIST?
3546 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3548 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3549 #ifdef FEAT_SHORTCUT
3550 if (curbuf
->b_p_bin
)
3551 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3555 if (!GetSaveFileName(&fileStruct
))
3560 if (!GetOpenFileName(&fileStruct
))
3567 /* Give focus back to main window (when using MDI). */
3570 /* Shorten the file name if possible */
3571 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3573 #endif /* FEAT_BROWSE */
3583 # define BUFPATHLEN _MAX_PATH
3584 # define DRAGQVAL 0xFFFFFFFF
3586 # define BUFPATHLEN MAXPATHL
3587 # define DRAGQVAL 0xFFFF
3590 WCHAR wszFile
[BUFPATHLEN
];
3592 char szFile
[BUFPATHLEN
];
3593 UINT cFiles
= DragQueryFile(hDrop
, DRAGQVAL
, NULL
, 0);
3597 int_u modifiers
= 0;
3599 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3601 /* Obtain dropped position */
3602 DragQueryPoint(hDrop
, &pt
);
3603 MapWindowPoints(s_hwnd
, s_textArea
, &pt
, 1);
3609 fnames
= (char_u
**)alloc(cFiles
* sizeof(char_u
*));
3612 for (i
= 0; i
< cFiles
; ++i
)
3615 if (DragQueryFileW(hDrop
, i
, wszFile
, BUFPATHLEN
) > 0)
3616 fnames
[i
] = utf16_to_enc(wszFile
, NULL
);
3620 DragQueryFile(hDrop
, i
, szFile
, BUFPATHLEN
);
3621 fnames
[i
] = vim_strsave(szFile
);
3629 if ((GetKeyState(VK_SHIFT
) & 0x8000) != 0)
3630 modifiers
|= MOUSE_SHIFT
;
3631 if ((GetKeyState(VK_CONTROL
) & 0x8000) != 0)
3632 modifiers
|= MOUSE_CTRL
;
3633 if ((GetKeyState(VK_MENU
) & 0x8000) != 0)
3634 modifiers
|= MOUSE_ALT
;
3636 gui_handle_drop(pt
.x
, pt
.y
, modifiers
, fnames
, cFiles
);
3638 s_need_activate
= TRUE
;
3651 static UINT prev_code
= 0; /* code of previous call */
3652 scrollbar_T
*sb
, *sb_info
;
3654 int dragging
= FALSE
;
3655 int dont_scroll_save
= dont_scroll
;
3661 si
.cbSize
= sizeof(si
);
3665 sb
= gui_mswin_find_scrollbar(hwndCtl
);
3669 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
3672 * Careful: need to get scrollbar info out of first (left) scrollbar
3673 * for window, but keep real scrollbar too because we must pass it to
3674 * gui_drag_scrollbar().
3676 sb_info
= &sb
->wp
->w_scrollbars
[0];
3678 else /* Bottom scrollbar */
3680 val
= sb_info
->value
;
3687 if (sb
->scroll_shift
> 0)
3688 val
<<= sb
->scroll_shift
;
3697 val
+= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3700 val
-= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3709 if (prev_code
== SB_THUMBTRACK
)
3712 * "pos" only gives us 16-bit data. In case of large file,
3713 * use GetScrollPos() which returns 32-bit. Unfortunately it
3714 * is not valid while the scrollbar is being dragged.
3716 val
= GetScrollPos(hwndCtl
, SB_CTL
);
3717 if (sb
->scroll_shift
> 0)
3718 val
<<= sb
->scroll_shift
;
3723 /* TRACE("Unknown scrollbar event %d\n", code); */
3729 si
.nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3730 SetScrollInfo(hwndCtl
, SB_CTL
, &si
, TRUE
);
3732 nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3733 SetScrollPos(hwndCtl
, SB_CTL
, nPos
, TRUE
);
3737 * When moving a vertical scrollbar, move the other vertical scrollbar too.
3741 scrollbar_T
*sba
= sb
->wp
->w_scrollbars
;
3742 HWND id
= sba
[ (sb
== sba
+ SBAR_LEFT
) ? SBAR_RIGHT
: SBAR_LEFT
].id
;
3745 SetScrollInfo(id
, SB_CTL
, &si
, TRUE
);
3747 SetScrollPos(id
, SB_CTL
, nPos
, TRUE
);
3751 /* Don't let us be interrupted here by another message. */
3752 s_busy_processing
= TRUE
;
3754 /* When "allow_scrollbar" is FALSE still need to remember the new
3755 * position, but don't actually scroll by setting "dont_scroll". */
3756 dont_scroll
= !allow_scrollbar
;
3758 gui_drag_scrollbar(sb
, val
, dragging
);
3760 s_busy_processing
= FALSE
;
3761 dont_scroll
= dont_scroll_save
;
3768 * Get command line arguments.
3769 * Use "prog" as the name of the program and "cmdline" as the arguments.
3770 * Copy the arguments to allocated memory.
3771 * Return the number of arguments (including program name).
3772 * Return pointers to the arguments in "argvp". Memory is allocated with
3773 * malloc(), use free() instead of vim_free().
3774 * Return pointer to buffer in "tofree".
3775 * Returns zero when out of memory.
3779 get_cmd_args(char *prog
, char *cmdline
, char ***argvp
, char **tofree
)
3794 /* Try using the Unicode version first, it takes care of conversion when
3795 * 'encoding' is changed. */
3796 argc
= get_cmd_argsW(&argv
);
3801 /* Handle the program name. Remove the ".exe" extension, and find the 1st
3803 p
= strrchr(prog
, '.');
3806 for (progp
= prog
; *progp
== ' '; ++progp
)
3809 /* The command line is copied to allocated memory, so that we can change
3810 * it. Add the size of the string, the separating NUL and a terminating
3812 newcmdline
= malloc(STRLEN(cmdline
) + STRLEN(progp
) + 2);
3813 if (newcmdline
== NULL
)
3817 * First round: count the number of arguments ("pnew" == NULL).
3818 * Second round: produce the arguments.
3820 for (round
= 1; round
<= 2; ++round
)
3822 /* First argument is the program name. */
3826 strcpy(pnew
, progp
);
3827 pnew
+= strlen(pnew
);
3832 * Isolate each argument and put it in argv[].
3842 while (*p
!= NUL
&& (inquote
|| (*p
!= ' ' && *p
!= '\t')))
3844 /* Backslashes are only special when followed by a double
3846 i
= (int)strspn(p
, "\\");
3849 /* Halve the number of backslashes. */
3850 if (i
> 1 && pnew
!= NULL
)
3852 memset(pnew
, '\\', i
/ 2);
3856 /* Even nr of backslashes toggles quoting, uneven copies
3857 * the double quote. */
3860 else if (pnew
!= NULL
)
3866 /* Copy span of backslashes unmodified. */
3869 memset(pnew
, '\\', i
);
3879 /* Can't use mb_* functions, because 'encoding' is not
3880 * initialized yet here. */
3881 if (IsDBCSLeadByte(*p
))
3894 while (*p
== ' ' || *p
== '\t')
3895 ++p
; /* advance until a non-space */
3900 argv
= (char **)malloc((argc
+ 1) * sizeof(char *));
3904 return 0; /* malloc error */
3907 *tofree
= newcmdline
;
3912 argv
[argc
] = NULL
; /* NULL-terminated list */