1 /* vi:set ts=8 sts=4 sw=4:
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI support by Robert Webb
6 * Do ":help uganda" in Vim to read copying and usage conditions.
7 * Do ":help credits" in Vim to see a list of people who contributed.
8 * See README.txt for an overview of the Vim source code.
11 * gui_w48.c: This file is included in gui_w16.c and gui_w32.c.
13 * GUI support for Microsoft Windows (Win16 + Win32 = Win48 :-)
15 * The combined efforts of:
16 * George V. Reilly <george@reilly.org>
19 * ...and contributions from many others
24 #include "version.h" /* used by dialog box routine for default title */
29 # include <shellapi.h>
31 #if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL) || defined(FEAT_GUI_TABLINE)
32 # include <commctrl.h>
36 # include <shellapi.h>
44 # include "glbl_ime.h"
48 # define MENUHINTS /* show menu hints in command line */
51 /* Some parameters for dialog boxes. All in pixels. */
52 #define DLG_PADDING_X 10
53 #define DLG_PADDING_Y 10
54 #define DLG_OLD_STYLE_PADDING_X 5
55 #define DLG_OLD_STYLE_PADDING_Y 5
56 #define DLG_VERT_PADDING_X 4 /* For vertical buttons */
57 #define DLG_VERT_PADDING_Y 4
58 #define DLG_ICON_WIDTH 34
59 #define DLG_ICON_HEIGHT 34
60 #define DLG_MIN_WIDTH 150
61 #define DLG_FONT_NAME "MS Sans Serif"
62 #define DLG_FONT_POINT_SIZE 8
63 #define DLG_MIN_MAX_WIDTH 400
64 #define DLG_MIN_MAX_HEIGHT 400
66 #define DLG_NONBUTTON_CONTROL 5000 /* First ID of non-button controls */
68 #ifndef WM_XBUTTONDOWN /* For Win2K / winME ONLY */
69 # define WM_XBUTTONDOWN 0x020B
70 # define WM_XBUTTONUP 0x020C
71 # define WM_XBUTTONDBLCLK 0x020D
72 # define MK_XBUTTON1 0x0020
73 # define MK_XBUTTON2 0x0040
78 * Define a few things for generating prototypes. This is just to avoid
79 * syntax errors, the defines do not need to be correct.
91 typedef int ENUMLOGFONT
;
92 typedef int FINDREPLACE
;
98 typedef int LOGFONT
[];
100 typedef int LPCREATESTRUCT
;
105 typedef int LPWINDOWPOS
;
111 typedef int NEWTEXTMETRIC
;
112 typedef int OSVERSIONINFO
;
119 typedef void *HINSTANCE
;
129 # define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp))
132 static void _OnPaint( HWND hwnd
);
133 static void clear_rect(RECT
*rcp
);
134 static int gui_mswin_get_menu_height(int fix_window
);
136 static WORD s_dlgfntheight
; /* height of the dialog font */
137 static WORD s_dlgfntwidth
; /* width of the dialog font */
140 static HMENU s_menuBar
= NULL
;
143 static void rebuild_tearoff(vimmenu_T
*menu
);
144 static HBITMAP s_htearbitmap
; /* bitmap used to indicate tearoff */
147 /* Flag that is set while processing a message that must not be interrupted by
148 * processing another message. */
149 static int s_busy_processing
= FALSE
;
151 static int destroying
= FALSE
; /* call DestroyWindow() ourselves */
153 #ifdef MSWIN_FIND_REPLACE
154 static UINT s_findrep_msg
= 0; /* set in gui_w[16/32].c */
155 static FINDREPLACE s_findrep_struct
;
156 static HWND s_findrep_hwnd
= NULL
;
157 static int s_findrep_is_find
; /* TRUE for find dialog, FALSE
158 for find/replace dialog */
161 static HINSTANCE s_hinst
= NULL
;
162 #if !defined(FEAT_SNIFF) && !defined(FEAT_GUI)
166 static HDC s_hdc
= NULL
;
167 static HBRUSH s_brush
= NULL
;
170 static HWND s_toolbarhwnd
= NULL
;
173 #ifdef FEAT_GUI_TABLINE
174 static HWND s_tabhwnd
= NULL
;
175 static int showing_tabline
= 0;
178 static WPARAM s_wParam
= 0;
179 static LPARAM s_lParam
= 0;
181 static HWND s_textArea
= NULL
;
182 static UINT s_uMsg
= 0;
184 static char_u
*s_textfield
; /* Used by dialogs to pass back strings */
186 static int s_need_activate
= FALSE
;
188 /* This variable is set when waiting for an event, which is the only moment
189 * scrollbar dragging can be done directly. It's not allowed while commands
190 * are executed, because it may move the cursor and that may cause unexpected
191 * problems (e.g., while ":s" is working).
193 static int allow_scrollbar
= FALSE
;
196 # define MyTranslateMessage(x) global_ime_TranslateMessage(x)
198 # define MyTranslateMessage(x) TranslateMessage(x)
201 #if (defined(WIN3264) && defined(FEAT_MBYTE)) || defined(GLOBAL_IME)
202 /* use of WindowProc depends on wide_WindowProc */
203 # define MyWindowProc vim_WindowProc
205 /* use ordinary WindowProc */
206 # define MyWindowProc DefWindowProc
209 extern int current_font_height
; /* this is in os_mswin.c */
221 {VK_RIGHT
, 'k', 'r'},
246 #ifdef FEAT_NETBEANS_INTG
247 {VK_PAUSE
, 'F', 'B'}, /* Pause == F21 (see gui_gtk_x11.c) */
251 {VK_F24
, 'F', 'E'}, /* winuser.h defines up to F24 */
255 {VK_INSERT
, 'k', 'I'},
256 {VK_DELETE
, 'k', 'D'},
259 {VK_PRIOR
, 'k', 'P'},
261 {VK_PRINT
, '%', '9'},
263 {VK_SUBTRACT
, 'K', '7'},
264 {VK_DIVIDE
, 'K', '8'},
265 {VK_MULTIPLY
, 'K', '9'},
266 {VK_SEPARATOR
, 'K', 'A'}, /* Keypad Enter */
267 {VK_DECIMAL
, 'K', 'B'},
269 {VK_NUMPAD0
, 'K', 'C'},
270 {VK_NUMPAD1
, 'K', 'D'},
271 {VK_NUMPAD2
, 'K', 'E'},
272 {VK_NUMPAD3
, 'K', 'F'},
273 {VK_NUMPAD4
, 'K', 'G'},
274 {VK_NUMPAD5
, 'K', 'H'},
275 {VK_NUMPAD6
, 'K', 'I'},
276 {VK_NUMPAD7
, 'K', 'J'},
277 {VK_NUMPAD8
, 'K', 'K'},
278 {VK_NUMPAD9
, 'K', 'L'},
280 /* Keys that we want to be able to use any modifier with: */
281 {VK_SPACE
, ' ', NUL
},
283 {VK_ESCAPE
, ESC
, NUL
},
287 /* End of list marker: */
291 /* Local variables */
292 static int s_button_pending
= -1;
293 static int s_x_pending
;
294 static int s_y_pending
;
295 static UINT s_kFlags_pending
;
296 static UINT s_wait_timer
= 0; /* Timer for get char from user */
297 static int s_timed_out
= FALSE
;
298 static int dead_key
= 0; /* 0 - no dead key, 1 - dead key pressed */
301 static OSVERSIONINFO os_version
; /* like it says. Init in gui_mch_init() */
305 /* balloon-eval WM_NOTIFY_HANDLER */
306 static void Handle_WM_Notify
__ARGS((HWND hwnd
, LPNMHDR pnmh
));
307 static void TrackUserActivity
__ARGS((UINT uMsg
));
314 # ifdef USE_IM_CONTROL
315 static LOGFONT norm_logfont
;
319 #ifdef FEAT_MBYTE_IME
320 static LRESULT
_OnImeNotify(HWND hWnd
, DWORD dwCommand
, DWORD dwData
);
323 #ifdef DEBUG_PRINT_ERROR
325 * Print out the last Windows error message
328 print_windows_error(void)
332 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
,
333 NULL
, GetLastError(),
334 MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
),
335 (LPTSTR
) &lpMsgBuf
, 0, NULL
);
336 TRACE1("Error: %s\n", lpMsgBuf
);
342 * Cursor blink functions.
344 * This is a simple state machine:
345 * BLINK_NONE not blinking at all
346 * BLINK_OFF blinking, cursor is not shown
347 * BLINK_ON blinking, cursor is shown
354 static int blink_state
= BLINK_NONE
;
355 static long_u blink_waittime
= 700;
356 static long_u blink_ontime
= 400;
357 static long_u blink_offtime
= 250;
358 static UINT blink_timer
= 0;
361 gui_mch_set_blinking(long wait
, long on
, long off
)
363 blink_waittime
= wait
;
379 TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
382 KillTimer(NULL
, idEvent
);
384 /* Eat spurious WM_TIMER messages */
385 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
388 if (blink_state
== BLINK_ON
)
391 blink_state
= BLINK_OFF
;
392 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_offtime
,
393 (TIMERPROC
)_OnBlinkTimer
);
397 gui_update_cursor(TRUE
, FALSE
);
398 blink_state
= BLINK_ON
;
399 blink_timer
= (UINT
) SetTimer(NULL
, 0, (UINT
)blink_ontime
,
400 (TIMERPROC
)_OnBlinkTimer
);
405 gui_mswin_rm_blink_timer(void)
409 if (blink_timer
!= 0)
411 KillTimer(NULL
, blink_timer
);
412 /* Eat spurious WM_TIMER messages */
413 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
420 * Stop the cursor blinking. Show the cursor if it wasn't shown.
423 gui_mch_stop_blink(void)
425 gui_mswin_rm_blink_timer();
426 if (blink_state
== BLINK_OFF
)
427 gui_update_cursor(TRUE
, FALSE
);
428 blink_state
= BLINK_NONE
;
432 * Start the cursor blinking. If it was already blinking, this restarts the
433 * waiting time and shows the cursor.
436 gui_mch_start_blink(void)
438 gui_mswin_rm_blink_timer();
440 /* Only switch blinking on if none of the times is zero */
441 if (blink_waittime
&& blink_ontime
&& blink_offtime
&& gui
.in_focus
)
443 blink_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)blink_waittime
,
444 (TIMERPROC
)_OnBlinkTimer
);
445 blink_state
= BLINK_ON
;
446 gui_update_cursor(TRUE
, FALSE
);
451 * Call-back routines.
465 TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
467 KillTimer(NULL
, idEvent
);
470 /* Eat spurious WM_TIMER messages */
471 while (PeekMessage(&msg
, hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
473 if (idEvent
== s_wait_timer
)
488 * Convert Unicode character "ch" to bytes in "string[slen]".
492 char_to_string(int ch
, char_u
*string
, int slen
)
500 if (os_version
.dwPlatformId
!= VER_PLATFORM_WIN32_NT
)
502 /* On Windows 95/98 we apparently get the character in the active
503 * codepage, not in UCS-2. If conversion is needed convert it to
505 if ((int)GetACP() == enc_codepage
)
506 len
= 0; /* no conversion required */
510 len
= MultiByteToWideChar(GetACP(), 0, string
, 1, wstring
, 2);
521 /* "ch" is a UTF-16 character. Convert it to a string of bytes. When
522 * "enc_codepage" is non-zero use the standard Win32 function,
523 * otherwise use our own conversion function (e.g., for UTF-8). */
524 if (enc_codepage
> 0)
525 len
= WideCharToMultiByte(enc_codepage
, 0, wstring
, len
,
526 string
, slen
, 0, NULL
);
530 ws
= ucs2_to_enc(wstring
, &len
);
535 if (len
> slen
) /* just in case */
537 mch_memmove(string
, ws
, len
);
550 for (i
= 0; i
< len
; ++i
)
551 if (string
[i
] == CSI
&& len
<= slen
- 2)
553 /* Insert CSI as K_CSI. */
554 mch_memmove(string
+ i
+ 3, string
+ i
+ 1, len
- i
- 1);
555 string
[++i
] = KS_EXTRA
;
556 string
[++i
] = (int)KE_CSI
;
564 * Key hit, add it to the input buffer.
576 len
= char_to_string(ch
, string
, 40);
577 if (len
== 1 && string
[0] == Ctrl_C
&& ctrl_c_interrupts
)
583 add_to_input_buf(string
, len
);
587 * Alt-Key hit, add it to the input buffer.
596 char_u string
[40]; /* Enough for multibyte character */
599 int ch
= cch
; /* special keys are negative */
601 /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */
603 /* OK, we have a character key (given by ch) which was entered with the
604 * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note
605 * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless
606 * CAPSLOCK is pressed) at this point.
608 modifiers
= MOD_MASK_ALT
;
609 if (GetKeyState(VK_SHIFT
) & 0x8000)
610 modifiers
|= MOD_MASK_SHIFT
;
611 if (GetKeyState(VK_CONTROL
) & 0x8000)
612 modifiers
|= MOD_MASK_CTRL
;
614 ch
= simplify_key(ch
, &modifiers
);
615 /* remove the SHIFT modifier for keys where it's already included, e.g.,
617 if (ch
< 0x100 && !isalpha(ch
) && isprint(ch
))
618 modifiers
&= ~MOD_MASK_SHIFT
;
620 /* Interpret the ALT key as making the key META, include SHIFT, etc. */
621 ch
= extract_modifiers(ch
, &modifiers
);
629 string
[len
++] = KS_MODIFIER
;
630 string
[len
++] = modifiers
;
633 if (IS_SPECIAL((int)ch
))
636 string
[len
++] = K_SECOND((int)ch
);
637 string
[len
++] = K_THIRD((int)ch
);
641 /* Although the documentation isn't clear about it, we assume "ch" is
642 * a Unicode character. */
643 len
+= char_to_string(ch
, string
+ len
, 40 - len
);
646 add_to_input_buf(string
, len
);
657 int vim_modifiers
= 0x0;
659 if (keyFlags
& MK_SHIFT
)
660 vim_modifiers
|= MOUSE_SHIFT
;
661 if (keyFlags
& MK_CONTROL
)
662 vim_modifiers
|= MOUSE_CTRL
;
663 if (GetKeyState(VK_MENU
) & 0x8000)
664 vim_modifiers
|= MOUSE_ALT
;
666 gui_send_mouse_event(button
, x
, y
, repeated_click
, vim_modifiers
);
678 static LONG s_prevTime
= 0;
680 LONG currentTime
= GetMessageTime();
684 /* Give main window the focus: this is so the cursor isn't hollow. */
685 (void)SetFocus(s_hwnd
);
687 if (s_uMsg
== WM_LBUTTONDOWN
|| s_uMsg
== WM_LBUTTONDBLCLK
)
689 else if (s_uMsg
== WM_MBUTTONDOWN
|| s_uMsg
== WM_MBUTTONDBLCLK
)
690 button
= MOUSE_MIDDLE
;
691 else if (s_uMsg
== WM_RBUTTONDOWN
|| s_uMsg
== WM_RBUTTONDBLCLK
)
692 button
= MOUSE_RIGHT
;
693 #ifndef WIN16 /*<VN>*/
694 else if (s_uMsg
== WM_XBUTTONDOWN
|| s_uMsg
== WM_XBUTTONDBLCLK
)
696 #ifndef GET_XBUTTON_WPARAM
697 # define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam))
699 button
= ((GET_XBUTTON_WPARAM(s_wParam
) == 1) ? MOUSE_X1
: MOUSE_X2
);
701 else if (s_uMsg
== WM_CAPTURECHANGED
)
703 /* on W95/NT4, somehow you get in here with an odd Msg
704 * if you press one button while holding down the other..*/
705 if (s_button_pending
== MOUSE_LEFT
)
706 button
= MOUSE_RIGHT
;
713 repeated_click
= ((int)(currentTime
- s_prevTime
) < p_mouset
);
716 * Holding down the left and right buttons simulates pushing the middle
720 && ((button
== MOUSE_LEFT
&& s_button_pending
== MOUSE_RIGHT
)
721 || (button
== MOUSE_RIGHT
722 && s_button_pending
== MOUSE_LEFT
)))
725 * Hmm, gui.c will ignore more than one button down at a time, so
726 * pretend we let go of it first.
728 gui_send_mouse_event(MOUSE_RELEASE
, x
, y
, FALSE
, 0x0);
729 button
= MOUSE_MIDDLE
;
730 repeated_click
= FALSE
;
731 s_button_pending
= -1;
732 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
734 else if ((repeated_click
)
735 || (mouse_model_popup() && (button
== MOUSE_RIGHT
)))
737 if (s_button_pending
> -1)
739 _OnMouseEvent(s_button_pending
, x
, y
, FALSE
, keyFlags
);
740 s_button_pending
= -1;
742 /* TRACE("Button down at x %d, y %d\n", x, y); */
743 _OnMouseEvent(button
, x
, y
, repeated_click
, keyFlags
);
748 * If this is the first press (i.e. not a multiple click) don't
749 * action immediately, but store and wait for:
752 * iii) another button press
754 * This enables us to make left+right simulate middle button,
755 * without left or right being actioned first. The side-effect is
756 * that if you click and hold the mouse without dragging, the
757 * cursor doesn't move until you release the button. In practice
758 * this is hardly a problem.
760 s_button_pending
= button
;
763 s_kFlags_pending
= keyFlags
;
766 s_prevTime
= currentTime
;
772 _OnMouseMoveOrRelease(
780 if (s_button_pending
> -1)
782 /* Delayed action for mouse down event */
783 _OnMouseEvent(s_button_pending
, s_x_pending
,
784 s_y_pending
, FALSE
, s_kFlags_pending
);
785 s_button_pending
= -1;
787 if (s_uMsg
== WM_MOUSEMOVE
)
790 * It's only a MOUSE_DRAG if one or more mouse buttons are being held
793 if (!(keyFlags
& (MK_LBUTTON
| MK_MBUTTON
| MK_RBUTTON
794 | MK_XBUTTON1
| MK_XBUTTON2
)))
796 gui_mouse_moved(x
, y
);
801 * While button is down, keep grabbing mouse move events when
802 * the mouse goes outside the window
804 SetCapture(s_textArea
);
806 /* TRACE(" move at x %d, y %d\n", x, y); */
811 button
= MOUSE_RELEASE
;
812 /* TRACE(" up at x %d, y %d\n", x, y); */
815 _OnMouseEvent(button
, x
, y
, FALSE
, keyFlags
);
820 * Find the vimmenu_T with the given id
827 vimmenu_T
*pChildMenu
;
831 if (pMenu
->id
== (UINT
)id
)
833 if (pMenu
->children
!= NULL
)
835 pChildMenu
= gui_mswin_find_menu(pMenu
->children
, id
);
857 pMenu
= gui_mswin_find_menu(root_menu
, id
);
863 #ifdef MSWIN_FIND_REPLACE
865 * Handle a Find/Replace window message.
873 if (s_findrep_struct
.Flags
& FR_DIALOGTERM
)
874 /* Give main window the focus back. */
875 (void)SetFocus(s_hwnd
);
877 if (s_findrep_struct
.Flags
& FR_FINDNEXT
)
879 flags
= FRD_FINDNEXT
;
881 /* Give main window the focus back: this is so the cursor isn't
883 (void)SetFocus(s_hwnd
);
885 else if (s_findrep_struct
.Flags
& FR_REPLACE
)
889 /* Give main window the focus back: this is so the cursor isn't
891 (void)SetFocus(s_hwnd
);
893 else if (s_findrep_struct
.Flags
& FR_REPLACEALL
)
895 flags
= FRD_REPLACEALL
;
900 /* Call the generic GUI function to do the actual work. */
901 if (s_findrep_struct
.Flags
& FR_WHOLEWORD
)
902 flags
|= FRD_WHOLE_WORD
;
903 if (s_findrep_struct
.Flags
& FR_MATCHCASE
)
904 flags
|= FRD_MATCH_CASE
;
905 down
= (s_findrep_struct
.Flags
& FR_DOWN
) != 0;
906 gui_do_findrepl(flags
, s_findrep_struct
.lpstrFindWhat
,
907 s_findrep_struct
.lpstrReplaceWith
, down
);
913 HandleMouseHide(UINT uMsg
, LPARAM lParam
)
915 static LPARAM last_lParam
= 0L;
917 /* We sometimes get a mousemove when the mouse didn't move... */
918 if (uMsg
== WM_MOUSEMOVE
)
920 if (lParam
== last_lParam
)
922 last_lParam
= lParam
;
925 /* Handle specially, to centralise coding. We need to be sure we catch all
926 * possible events which should cause us to restore the cursor (as it is a
927 * shared resource, we take full responsibility for it).
934 * blank out the pointer if necessary
937 gui_mch_mousehide(TRUE
);
940 case WM_SYSKEYUP
: /* show the pointer when a system-key is pressed */
942 case WM_MOUSEMOVE
: /* show the pointer on any mouse action */
952 case WM_NCLBUTTONDOWN
:
954 case WM_NCMBUTTONDOWN
:
956 case WM_NCRBUTTONDOWN
:
960 * if the pointer is currently hidden, then we should show it.
962 gui_mch_mousehide(FALSE
);
967 static LRESULT CALLBACK
975 TRACE("TextAreaWndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
976 hwnd, uMsg, wParam, lParam);
979 HandleMouseHide(uMsg
, lParam
);
986 TrackUserActivity(uMsg
);
991 HANDLE_MSG(hwnd
, WM_LBUTTONDBLCLK
,_OnMouseButtonDown
);
992 HANDLE_MSG(hwnd
, WM_LBUTTONDOWN
,_OnMouseButtonDown
);
993 HANDLE_MSG(hwnd
, WM_LBUTTONUP
, _OnMouseMoveOrRelease
);
994 HANDLE_MSG(hwnd
, WM_MBUTTONDBLCLK
,_OnMouseButtonDown
);
995 HANDLE_MSG(hwnd
, WM_MBUTTONDOWN
,_OnMouseButtonDown
);
996 HANDLE_MSG(hwnd
, WM_MBUTTONUP
, _OnMouseMoveOrRelease
);
997 HANDLE_MSG(hwnd
, WM_MOUSEMOVE
, _OnMouseMoveOrRelease
);
998 HANDLE_MSG(hwnd
, WM_PAINT
, _OnPaint
);
999 HANDLE_MSG(hwnd
, WM_RBUTTONDBLCLK
,_OnMouseButtonDown
);
1000 HANDLE_MSG(hwnd
, WM_RBUTTONDOWN
,_OnMouseButtonDown
);
1001 HANDLE_MSG(hwnd
, WM_RBUTTONUP
, _OnMouseMoveOrRelease
);
1002 #ifndef WIN16 /*<VN>*/
1003 HANDLE_MSG(hwnd
, WM_XBUTTONDBLCLK
,_OnMouseButtonDown
);
1004 HANDLE_MSG(hwnd
, WM_XBUTTONDOWN
,_OnMouseButtonDown
);
1005 HANDLE_MSG(hwnd
, WM_XBUTTONUP
, _OnMouseMoveOrRelease
);
1009 case WM_NOTIFY
: Handle_WM_Notify(hwnd
, (LPNMHDR
)lParam
);
1014 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1018 #if (defined(WIN3264) && defined(FEAT_MBYTE)) \
1019 || defined(GLOBAL_IME) \
1026 vim_WindowProc(HWND hwnd
, UINT message
, WPARAM wParam
, LPARAM lParam
)
1029 return global_ime_DefWindowProc(hwnd
, message
, wParam
, lParam
);
1031 if (wide_WindowProc
)
1032 return DefWindowProcW(hwnd
, message
, wParam
, lParam
);
1033 return DefWindowProc(hwnd
, message
, wParam
, lParam
);
1039 * Called when the foreground or background color has been changed.
1042 gui_mch_new_colors(void)
1044 /* nothing to do? */
1048 * Set the colors to their default values.
1051 gui_mch_def_colors()
1053 gui
.norm_pixel
= GetSysColor(COLOR_WINDOWTEXT
);
1054 gui
.back_pixel
= GetSysColor(COLOR_WINDOW
);
1055 gui
.def_norm_pixel
= gui
.norm_pixel
;
1056 gui
.def_back_pixel
= gui
.back_pixel
;
1060 * Open the GUI window which was created by a call to gui_mch_init().
1065 #ifndef SW_SHOWDEFAULT
1066 # define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */
1068 /* Actually open the window, if not already visible
1069 * (may be done already in gui_mch_set_shellsize) */
1070 if (!IsWindowVisible(s_hwnd
))
1071 ShowWindow(s_hwnd
, SW_SHOWDEFAULT
);
1073 #ifdef MSWIN_FIND_REPLACE
1074 /* Init replace string here, so that we keep it when re-opening the
1076 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1083 * Get the position of the top left corner of the window.
1086 gui_mch_get_winpos(int *x
, int *y
)
1090 GetWindowRect(s_hwnd
, &rect
);
1097 * Set the position of the top left corner of the window to the given
1101 gui_mch_set_winpos(int x
, int y
)
1103 SetWindowPos(s_hwnd
, NULL
, x
, y
, 0, 0,
1104 SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
1107 gui_mch_set_text_area_pos(int x
, int y
, int w
, int h
)
1109 static int oldx
= 0;
1110 static int oldy
= 0;
1112 SetWindowPos(s_textArea
, NULL
, x
, y
, w
, h
, SWP_NOZORDER
| SWP_NOACTIVATE
);
1115 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1116 SendMessage(s_toolbarhwnd
, WM_SIZE
,
1117 (WPARAM
)0, (LPARAM
)(w
+ ((long)(TOOLBAR_BUTTON_HEIGHT
+8)<<16)));
1119 #if defined(FEAT_GUI_TABLINE)
1120 if (showing_tabline
)
1125 # ifdef FEAT_TOOLBAR
1126 if (vim_strchr(p_go
, GO_TOOLBAR
) != NULL
)
1127 top
= TOOLBAR_BUTTON_HEIGHT
+ TOOLBAR_BORDER_HEIGHT
;
1129 GetClientRect(s_hwnd
, &rect
);
1130 MoveWindow(s_tabhwnd
, 0, top
, rect
.right
, gui
.tabline_height
, TRUE
);
1134 /* When side scroll bar is unshown, the size of window will change.
1135 * then, the text area move left or right. thus client rect should be
1136 * forcely redraw. (Yasuhiro Matsumoto) */
1137 if (oldx
!= x
|| oldy
!= y
)
1139 InvalidateRect(s_hwnd
, NULL
, FALSE
);
1151 gui_mch_enable_scrollbar(
1155 ShowScrollBar(sb
->id
, SB_CTL
, flag
);
1157 /* TODO: When the window is maximized, the size of the window stays the
1158 * same, thus the size of the text area changes. On Win98 it's OK, on Win
1159 * NT 4.0 it's not... */
1163 gui_mch_set_scrollbar_pos(
1170 SetWindowPos(sb
->id
, NULL
, x
, y
, w
, h
,
1171 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_SHOWWINDOW
);
1175 gui_mch_create_scrollbar(
1177 int orient
) /* SBAR_VERT or SBAR_HORIZ */
1179 sb
->id
= CreateWindow(
1180 "SCROLLBAR", "Scrollbar",
1181 WS_CHILD
| ((orient
== SBAR_VERT
) ? SBS_VERT
: SBS_HORZ
), 0, 0,
1182 10, /* Any value will do for now */
1183 10, /* Any value will do for now */
1189 * Find the scrollbar with the given hwnd.
1191 static scrollbar_T
*
1192 gui_mswin_find_scrollbar(HWND hwnd
)
1196 if (gui
.bottom_sbar
.id
== hwnd
)
1197 return &gui
.bottom_sbar
;
1200 if (wp
->w_scrollbars
[SBAR_LEFT
].id
== hwnd
)
1201 return &wp
->w_scrollbars
[SBAR_LEFT
];
1202 if (wp
->w_scrollbars
[SBAR_RIGHT
].id
== hwnd
)
1203 return &wp
->w_scrollbars
[SBAR_RIGHT
];
1209 * Get the character size of a font.
1212 GetFontSize(GuiFont font
)
1214 HWND hwnd
= GetDesktopWindow();
1215 HDC hdc
= GetWindowDC(hwnd
);
1216 HFONT hfntOld
= SelectFont(hdc
, (HFONT
)font
);
1219 GetTextMetrics(hdc
, &tm
);
1220 gui
.char_width
= tm
.tmAveCharWidth
+ tm
.tmOverhang
;
1222 gui
.char_height
= tm
.tmHeight
1223 #ifndef MSWIN16_FASTTEXT
1228 SelectFont(hdc
, hfntOld
);
1230 ReleaseDC(hwnd
, hdc
);
1234 * Adjust gui.char_height (after 'linespace' was changed).
1237 gui_mch_adjust_charheight(void)
1239 GetFontSize(gui
.norm_font
);
1244 get_font_handle(LOGFONT
*lf
)
1249 font
= CreateFontIndirect(lf
);
1254 return (GuiFont
)font
;
1258 pixels_to_points(int pixels
, int vertical
)
1264 hwnd
= GetDesktopWindow();
1265 hdc
= GetWindowDC(hwnd
);
1267 points
= MulDiv(pixels
, 72,
1268 GetDeviceCaps(hdc
, vertical
? LOGPIXELSY
: LOGPIXELSX
));
1270 ReleaseDC(hwnd
, hdc
);
1278 int giveErrorIfMissing
)
1281 GuiFont font
= NOFONT
;
1283 if (get_logfont(&lf
, name
, NULL
, giveErrorIfMissing
) == OK
)
1284 font
= get_font_handle(&lf
);
1285 if (font
== NOFONT
&& giveErrorIfMissing
)
1286 EMSG2(_(e_font
), name
);
1290 #if defined(FEAT_EVAL) || defined(PROTO)
1292 * Return the name of font "font" in allocated memory.
1293 * Don't know how to get the actual name, thus use the provided name.
1297 gui_mch_get_fontname(font
, name
)
1303 return vim_strsave(name
);
1308 gui_mch_free_font(GuiFont font
)
1311 DeleteObject((HFONT
)font
);
1320 if (c
>= 'a' && c
<= 'f')
1321 return c
- 'a' + 10;
1325 * Return the Pixel value (color) for the given color name.
1326 * Return INVALCOLOR for error.
1329 gui_mch_get_color(char_u
*name
)
1331 typedef struct guicolor_tTable
1337 static guicolor_tTable table
[] =
1339 {"Black", RGB(0x00, 0x00, 0x00)},
1340 {"DarkGray", RGB(0x80, 0x80, 0x80)},
1341 {"DarkGrey", RGB(0x80, 0x80, 0x80)},
1342 {"Gray", RGB(0xC0, 0xC0, 0xC0)},
1343 {"Grey", RGB(0xC0, 0xC0, 0xC0)},
1344 {"LightGray", RGB(0xE0, 0xE0, 0xE0)},
1345 {"LightGrey", RGB(0xE0, 0xE0, 0xE0)},
1346 {"Gray10", RGB(0x1A, 0x1A, 0x1A)},
1347 {"Grey10", RGB(0x1A, 0x1A, 0x1A)},
1348 {"Gray20", RGB(0x33, 0x33, 0x33)},
1349 {"Grey20", RGB(0x33, 0x33, 0x33)},
1350 {"Gray30", RGB(0x4D, 0x4D, 0x4D)},
1351 {"Grey30", RGB(0x4D, 0x4D, 0x4D)},
1352 {"Gray40", RGB(0x66, 0x66, 0x66)},
1353 {"Grey40", RGB(0x66, 0x66, 0x66)},
1354 {"Gray50", RGB(0x7F, 0x7F, 0x7F)},
1355 {"Grey50", RGB(0x7F, 0x7F, 0x7F)},
1356 {"Gray60", RGB(0x99, 0x99, 0x99)},
1357 {"Grey60", RGB(0x99, 0x99, 0x99)},
1358 {"Gray70", RGB(0xB3, 0xB3, 0xB3)},
1359 {"Grey70", RGB(0xB3, 0xB3, 0xB3)},
1360 {"Gray80", RGB(0xCC, 0xCC, 0xCC)},
1361 {"Grey80", RGB(0xCC, 0xCC, 0xCC)},
1362 {"Gray90", RGB(0xE5, 0xE5, 0xE5)},
1363 {"Grey90", RGB(0xE5, 0xE5, 0xE5)},
1364 {"White", RGB(0xFF, 0xFF, 0xFF)},
1365 {"DarkRed", RGB(0x80, 0x00, 0x00)},
1366 {"Red", RGB(0xFF, 0x00, 0x00)},
1367 {"LightRed", RGB(0xFF, 0xA0, 0xA0)},
1368 {"DarkBlue", RGB(0x00, 0x00, 0x80)},
1369 {"Blue", RGB(0x00, 0x00, 0xFF)},
1370 {"LightBlue", RGB(0xA0, 0xA0, 0xFF)},
1371 {"DarkGreen", RGB(0x00, 0x80, 0x00)},
1372 {"Green", RGB(0x00, 0xFF, 0x00)},
1373 {"LightGreen", RGB(0xA0, 0xFF, 0xA0)},
1374 {"DarkCyan", RGB(0x00, 0x80, 0x80)},
1375 {"Cyan", RGB(0x00, 0xFF, 0xFF)},
1376 {"LightCyan", RGB(0xA0, 0xFF, 0xFF)},
1377 {"DarkMagenta", RGB(0x80, 0x00, 0x80)},
1378 {"Magenta", RGB(0xFF, 0x00, 0xFF)},
1379 {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)},
1380 {"Brown", RGB(0x80, 0x40, 0x40)},
1381 {"Yellow", RGB(0xFF, 0xFF, 0x00)},
1382 {"LightYellow", RGB(0xFF, 0xFF, 0xA0)},
1383 {"DarkYellow", RGB(0xBB, 0xBB, 0x00)},
1384 {"SeaGreen", RGB(0x2E, 0x8B, 0x57)},
1385 {"Orange", RGB(0xFF, 0xA5, 0x00)},
1386 {"Purple", RGB(0xA0, 0x20, 0xF0)},
1387 {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)},
1388 {"Violet", RGB(0xEE, 0x82, 0xEE)},
1391 typedef struct SysColorTable
1397 static SysColorTable sys_table
[] =
1400 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW
},
1401 {"SYS_3DHILIGHT", COLOR_3DHILIGHT
},
1403 {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT
},
1405 {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT
},
1406 {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT
},
1407 {"SYS_3DLIGHT", COLOR_3DLIGHT
},
1408 {"SYS_3DSHADOW", COLOR_3DSHADOW
},
1409 {"SYS_DESKTOP", COLOR_DESKTOP
},
1410 {"SYS_INFOBK", COLOR_INFOBK
},
1411 {"SYS_INFOTEXT", COLOR_INFOTEXT
},
1412 {"SYS_3DFACE", COLOR_3DFACE
},
1414 {"SYS_BTNFACE", COLOR_BTNFACE
},
1415 {"SYS_BTNSHADOW", COLOR_BTNSHADOW
},
1416 {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER
},
1417 {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION
},
1418 {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE
},
1419 {"SYS_BACKGROUND", COLOR_BACKGROUND
},
1420 {"SYS_BTNTEXT", COLOR_BTNTEXT
},
1421 {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT
},
1422 {"SYS_GRAYTEXT", COLOR_GRAYTEXT
},
1423 {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT
},
1424 {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT
},
1425 {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER
},
1426 {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION
},
1427 {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT
},
1428 {"SYS_MENU", COLOR_MENU
},
1429 {"SYS_MENUTEXT", COLOR_MENUTEXT
},
1430 {"SYS_SCROLLBAR", COLOR_SCROLLBAR
},
1431 {"SYS_WINDOW", COLOR_WINDOW
},
1432 {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME
},
1433 {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT
}
1439 if (name
[0] == '#' && strlen(name
) == 7)
1441 /* Name is in "#rrggbb" format */
1442 r
= hex_digit(name
[1]) * 16 + hex_digit(name
[2]);
1443 g
= hex_digit(name
[3]) * 16 + hex_digit(name
[4]);
1444 b
= hex_digit(name
[5]) * 16 + hex_digit(name
[6]);
1445 if (r
< 0 || g
< 0 || b
< 0)
1447 return RGB(r
, g
, b
);
1451 /* Check if the name is one of the colors we know */
1452 for (i
= 0; i
< sizeof(table
) / sizeof(table
[0]); i
++)
1453 if (STRICMP(name
, table
[i
].name
) == 0)
1454 return table
[i
].color
;
1458 * Try to look up a system colour.
1460 for (i
= 0; i
< sizeof(sys_table
) / sizeof(sys_table
[0]); i
++)
1461 if (STRICMP(name
, sys_table
[i
].name
) == 0)
1462 return GetSysColor(sys_table
[i
].color
);
1465 * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt".
1468 #define LINE_LEN 100
1470 char line
[LINE_LEN
];
1473 fname
= expand_env_save((char_u
*)"$VIMRUNTIME/rgb.txt");
1477 fd
= mch_fopen((char *)fname
, "rt");
1488 fgets(line
, LINE_LEN
, fd
);
1489 len
= (int)STRLEN(line
);
1491 if (len
<= 1 || line
[len
-1] != '\n')
1496 i
= sscanf(line
, "%d %d %d %n", &r
, &g
, &b
, &pos
);
1502 if (STRICMP(color
, name
) == 0)
1505 return (guicolor_T
) RGB(r
, g
, b
);
1515 * Return OK if the key with the termcap name "name" is supported.
1518 gui_mch_haskey(char_u
*name
)
1522 for (i
= 0; special_keys
[i
].vim_code1
!= NUL
; i
++)
1523 if (name
[0] == special_keys
[i
].vim_code0
&&
1524 name
[1] == special_keys
[i
].vim_code1
)
1535 * Invert a rectangle from row r, column c, for nr rows and nc columns.
1538 gui_mch_invert_rectangle(
1547 * Note: InvertRect() excludes right and bottom of rectangle.
1549 rc
.left
= FILL_X(c
);
1551 rc
.right
= rc
.left
+ nc
* gui
.char_width
;
1552 rc
.bottom
= rc
.top
+ nr
* gui
.char_height
;
1553 InvertRect(s_hdc
, &rc
);
1557 * Iconify the GUI window.
1560 gui_mch_iconify(void)
1562 ShowWindow(s_hwnd
, SW_MINIMIZE
);
1566 * Draw a cursor without focus.
1569 gui_mch_draw_hollow_cursor(guicolor_T color
)
1575 * Note: FrameRect() excludes right and bottom of rectangle.
1577 rc
.left
= FILL_X(gui
.col
);
1578 rc
.top
= FILL_Y(gui
.row
);
1579 rc
.right
= rc
.left
+ gui
.char_width
;
1581 if (mb_lefthalve(gui
.row
, gui
.col
))
1582 rc
.right
+= gui
.char_width
;
1584 rc
.bottom
= rc
.top
+ gui
.char_height
;
1585 hbr
= CreateSolidBrush(color
);
1586 FrameRect(s_hdc
, &rc
, hbr
);
1590 * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using
1594 gui_mch_draw_part_cursor(
1603 * Note: FillRect() excludes right and bottom of rectangle.
1606 #ifdef FEAT_RIGHTLEFT
1607 /* vertical line should be on the right of current point */
1608 CURSOR_BAR_RIGHT
? FILL_X(gui
.col
+ 1) - w
:
1611 rc
.top
= FILL_Y(gui
.row
) + gui
.char_height
- h
;
1612 rc
.right
= rc
.left
+ w
;
1613 rc
.bottom
= rc
.top
+ h
;
1614 hbr
= CreateSolidBrush(color
);
1615 FillRect(s_hdc
, &rc
, hbr
);
1620 * Process a single Windows message.
1621 * If one is not available we hang until one is.
1624 process_message(void)
1627 UINT vk
= 0; /* Virtual key */
1633 static char_u k10
[] = {K_SPECIAL
, 'k', ';', 0};
1636 GetMessage(&msg
, NULL
, 0, 0);
1639 /* Look after OLE Automation commands */
1640 if (msg
.message
== WM_OLE
)
1642 char_u
*str
= (char_u
*)msg
.lParam
;
1643 add_to_input_buf(str
, (int)STRLEN(str
));
1649 #ifdef FEAT_NETBEANS_INTG
1650 if (msg
.message
== WM_NETBEANS
)
1652 messageFromNetbeansW32();
1658 if (sniff_request_waiting
&& want_sniff_request
)
1660 static char_u bytes
[3] = {CSI
, (char_u
)KS_EXTRA
, (char_u
)KE_SNIFF
};
1661 add_to_input_buf(bytes
, 3); /* K_SNIFF */
1662 sniff_request_waiting
= 0;
1663 want_sniff_request
= 0;
1664 /* request is handled in normal.c */
1666 if (msg
.message
== WM_USER
)
1668 MyTranslateMessage(&msg
);
1669 DispatchMessage(&msg
);
1674 #ifdef MSWIN_FIND_REPLACE
1675 /* Don't process messages used by the dialog */
1676 if (s_findrep_hwnd
!= NULL
&& IsDialogMessage(s_findrep_hwnd
, &msg
))
1678 HandleMouseHide(msg
.message
, msg
.lParam
);
1684 * Check if it's a special key that we recognise. If not, call
1685 * TranslateMessage().
1687 if (msg
.message
== WM_KEYDOWN
|| msg
.message
== WM_SYSKEYDOWN
)
1689 vk
= (int) msg
.wParam
;
1690 /* handle key after dead key, but ignore shift, alt and control */
1691 if (dead_key
&& vk
!= VK_SHIFT
&& vk
!= VK_MENU
&& vk
!= VK_CONTROL
)
1694 /* handle non-alphabetic keys (ones that hopefully cannot generate
1695 * umlaut-characters), unless when control is down */
1696 if (vk
< 'A' || vk
> 'Z' || (GetKeyState(VK_CONTROL
) & 0x8000))
1700 dm
.message
= msg
.message
;
1702 dm
.wParam
= VK_SPACE
;
1703 MyTranslateMessage(&dm
); /* generate dead character */
1704 if (vk
!= VK_SPACE
) /* and send current character once more */
1705 PostMessage(msg
.hwnd
, msg
.message
, msg
.wParam
, msg
.lParam
);
1710 /* Check for CTRL-BREAK */
1711 if (vk
== VK_CANCEL
)
1716 add_to_input_buf(string
, 1);
1719 for (i
= 0; special_keys
[i
].key_sym
!= 0; i
++)
1721 /* ignore VK_SPACE when ALT key pressed: system menu */
1722 if (special_keys
[i
].key_sym
== vk
1723 && (vk
!= VK_SPACE
|| !(GetKeyState(VK_MENU
) & 0x8000)))
1726 /* Check for <F10>: Windows selects the menu. When <F10> is
1727 * mapped we want to use the mapping instead. */
1729 && gui
.menu_is_active
1730 && check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1733 if (GetKeyState(VK_SHIFT
) & 0x8000)
1734 modifiers
|= MOD_MASK_SHIFT
;
1736 * Don't use caps-lock as shift, because these are special keys
1737 * being considered here, and we only want letters to get
1741 if (GetKeyState(VK_CAPITAL) & 0x0001)
1742 modifiers ^= MOD_MASK_SHIFT;
1744 if (GetKeyState(VK_CONTROL
) & 0x8000)
1745 modifiers
|= MOD_MASK_CTRL
;
1746 if (GetKeyState(VK_MENU
) & 0x8000)
1747 modifiers
|= MOD_MASK_ALT
;
1749 if (special_keys
[i
].vim_code1
== NUL
)
1750 key
= special_keys
[i
].vim_code0
;
1752 key
= TO_SPECIAL(special_keys
[i
].vim_code0
,
1753 special_keys
[i
].vim_code1
);
1754 key
= simplify_key(key
, &modifiers
);
1761 string
[1] = KS_MODIFIER
;
1762 string
[2] = modifiers
;
1763 add_to_input_buf(string
, 3);
1766 if (IS_SPECIAL(key
))
1769 string
[1] = K_SECOND(key
);
1770 string
[2] = K_THIRD(key
);
1771 add_to_input_buf(string
, 3);
1777 /* Handle "key" as a Unicode character. */
1778 len
= char_to_string(key
, string
, 40);
1779 add_to_input_buf(string
, len
);
1784 if (special_keys
[i
].key_sym
== 0)
1786 /* Some keys need C-S- where they should only need C-.
1787 * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since
1788 * system startup (Helmut Stiegler, 2003 Oct 3). */
1790 && (GetKeyState(VK_CONTROL
) & 0x8000)
1791 && !(GetKeyState(VK_SHIFT
) & 0x8000)
1792 && !(GetKeyState(VK_MENU
) & 0x8000))
1794 /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */
1795 if (vk
== '6' || MapVirtualKey(vk
, 2) == (UINT
)'^')
1797 string
[0] = Ctrl_HAT
;
1798 add_to_input_buf(string
, 1);
1800 /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */
1801 else if (vk
== 0xBD) /* QWERTY for CTRL-'-' */
1804 add_to_input_buf(string
, 1);
1806 /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */
1807 else if (vk
== '2' || MapVirtualKey(vk
, 2) == (UINT
)'@')
1809 string
[0] = Ctrl_AT
;
1810 add_to_input_buf(string
, 1);
1813 MyTranslateMessage(&msg
);
1816 MyTranslateMessage(&msg
);
1819 #ifdef FEAT_MBYTE_IME
1820 else if (msg
.message
== WM_IME_NOTIFY
)
1821 _OnImeNotify(msg
.hwnd
, (DWORD
)msg
.wParam
, (DWORD
)msg
.lParam
);
1822 else if (msg
.message
== WM_KEYUP
&& im_get_status())
1823 /* added for non-MS IME (Yasuhiro Matsumoto) */
1824 MyTranslateMessage(&msg
);
1826 #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
1828 else if (msg
.message
== WM_IME_STARTCOMPOSITION
)
1832 global_ime_set_font(&norm_logfont
);
1833 point
.x
= FILL_X(gui
.col
);
1834 point
.y
= FILL_Y(gui
.row
);
1835 MapWindowPoints(s_textArea
, s_hwnd
, &point
, 1);
1836 global_ime_set_position(&point
);
1841 /* Check for <F10>: Default effect is to select the menu. When <F10> is
1842 * mapped we need to stop it here to avoid strange effects (e.g., for the
1844 if (vk
!= VK_F10
|| check_map(k10
, State
, FALSE
, TRUE
, FALSE
) == NULL
)
1846 DispatchMessage(&msg
);
1850 * Catch up with any queued events. This may put keyboard input into the
1851 * input buffer, call resize call-backs, trigger timers etc. If there is
1852 * nothing in the event queue (& no timers pending), then we return
1856 gui_mch_update(void)
1860 if (!s_busy_processing
)
1861 while (PeekMessage(&msg
, NULL
, 0, 0, PM_NOREMOVE
)
1862 && !vim_is_input_buf_full())
1867 * GUI input routine called by gui_wait_for_chars(). Waits for a character
1868 * from the keyboard.
1869 * wtime == -1 Wait forever.
1870 * wtime == 0 This should never happen.
1871 * wtime > 0 Wait wtime milliseconds for a character.
1872 * Returns OK if a character was found to be available within the given time,
1873 * or FAIL otherwise.
1876 gui_mch_wait_for_chars(int wtime
)
1881 s_timed_out
= FALSE
;
1885 /* Don't do anything while processing a (scroll) message. */
1886 if (s_busy_processing
)
1888 s_wait_timer
= (UINT
)SetTimer(NULL
, 0, (UINT
)wtime
,
1889 (TIMERPROC
)_OnTimer
);
1892 allow_scrollbar
= TRUE
;
1894 focus
= gui
.in_focus
;
1895 while (!s_timed_out
)
1897 /* Stop or start blinking when focus changes */
1898 if (gui
.in_focus
!= focus
)
1901 gui_mch_start_blink();
1903 gui_mch_stop_blink();
1904 focus
= gui
.in_focus
;
1907 if (s_need_activate
)
1910 (void)SetForegroundWindow(s_hwnd
);
1912 (void)SetActiveWindow(s_hwnd
);
1914 s_need_activate
= FALSE
;
1918 * Don't use gui_mch_update() because then we will spin-lock until a
1919 * char arrives, instead we use GetMessage() to hang until an
1920 * event arrives. No need to check for input_buf_full because we are
1921 * returning as soon as it contains a single char -- webb
1925 if (input_available())
1927 if (s_wait_timer
!= 0 && !s_timed_out
)
1929 KillTimer(NULL
, s_wait_timer
);
1931 /* Eat spurious WM_TIMER messages */
1932 while (PeekMessage(&msg
, s_hwnd
, WM_TIMER
, WM_TIMER
, PM_REMOVE
))
1936 allow_scrollbar
= FALSE
;
1938 /* Clear pending mouse button, the release event may have been
1939 * taken by the dialog window. */
1940 s_button_pending
= -1;
1945 allow_scrollbar
= FALSE
;
1950 * Clear a rectangular region of the screen from text pos (row1, col1) to
1951 * (row2, col2) inclusive.
1954 gui_mch_clear_block(
1963 * Clear one extra pixel at the far right, for when bold characters have
1964 * spilled over to the window border.
1965 * Note: FillRect() excludes right and bottom of rectangle.
1967 rc
.left
= FILL_X(col1
);
1968 rc
.top
= FILL_Y(row1
);
1969 rc
.right
= FILL_X(col2
+ 1) + (col2
== Columns
- 1);
1970 rc
.bottom
= FILL_Y(row2
+ 1);
1975 * Clear the whole text window.
1978 gui_mch_clear_all(void)
1984 rc
.right
= Columns
* gui
.char_width
+ 2 * gui
.border_width
;
1985 rc
.bottom
= Rows
* gui
.char_height
+ 2 * gui
.border_width
;
1993 gui_mch_enable_menu(int flag
)
1996 SetMenu(s_hwnd
, flag
? s_menuBar
: NULL
);
2002 gui_mch_set_menu_pos(
2008 /* It will be in the right place anyway */
2011 #if defined(FEAT_MENU) || defined(PROTO)
2013 * Make menu item hidden or not hidden
2016 gui_mch_menu_hidden(
2021 * This doesn't do what we want. Hmm, just grey the menu items for now.
2025 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED);
2027 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2029 gui_mch_menu_grey(menu
, hidden
);
2033 * This is called after setting all the menus to grey/hidden or not.
2036 gui_mch_draw_menubar(void)
2038 DrawMenuBar(s_hwnd
);
2040 #endif /*FEAT_MENU*/
2048 SaveInst(HINSTANCE hInst
)
2055 * Return the RGB value of a pixel as a long.
2058 gui_mch_get_rgb(guicolor_T pixel
)
2060 return (GetRValue(pixel
) << 16) + (GetGValue(pixel
) << 8)
2064 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2065 /* Convert pixels in X to dialog units */
2067 PixelToDialogX(int numPixels
)
2069 return (WORD
)((numPixels
* 4) / s_dlgfntwidth
);
2072 /* Convert pixels in Y to dialog units */
2074 PixelToDialogY(int numPixels
)
2076 return (WORD
)((numPixels
* 8) / s_dlgfntheight
);
2079 /* Return the width in pixels of the given text in the given DC. */
2081 GetTextWidth(HDC hdc
, char_u
*str
, int len
)
2085 GetTextExtentPoint(hdc
, str
, len
, &size
);
2091 * Return the width in pixels of the given text in the given DC, taking care
2092 * of 'encoding' to active codepage conversion.
2095 GetTextWidthEnc(HDC hdc
, char_u
*str
, int len
)
2102 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2104 /* 'encoding' differs from active codepage: convert text and use wide
2106 wstr
= enc_to_ucs2(str
, &wlen
);
2109 n
= GetTextExtentPointW(hdc
, wstr
, wlen
, &size
);
2116 return GetTextWidth(hdc
, str
, len
);
2119 # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l))
2123 * A quick little routine that will center one window over another, handy for
2124 * dialog boxes. Taken from the Win32SDK samples.
2131 RECT rChild
, rParent
;
2132 int wChild
, hChild
, wParent
, hParent
;
2133 int wScreen
, hScreen
, xNew
, yNew
;
2136 GetWindowRect(hwndChild
, &rChild
);
2137 wChild
= rChild
.right
- rChild
.left
;
2138 hChild
= rChild
.bottom
- rChild
.top
;
2140 /* If Vim is minimized put the window in the middle of the screen. */
2141 if (hwndParent
== NULL
|| IsMinimized(hwndParent
))
2146 rParent
.right
= GetSystemMetrics(SM_CXSCREEN
);
2147 rParent
.bottom
= GetSystemMetrics(SM_CYFULLSCREEN
);
2149 SystemParametersInfo(SPI_GETWORKAREA
, 0, &rParent
, 0);
2153 GetWindowRect(hwndParent
, &rParent
);
2154 wParent
= rParent
.right
- rParent
.left
;
2155 hParent
= rParent
.bottom
- rParent
.top
;
2157 hdc
= GetDC(hwndChild
);
2158 wScreen
= GetDeviceCaps (hdc
, HORZRES
);
2159 hScreen
= GetDeviceCaps (hdc
, VERTRES
);
2160 ReleaseDC(hwndChild
, hdc
);
2162 xNew
= rParent
.left
+ ((wParent
- wChild
) /2);
2167 else if ((xNew
+wChild
) > wScreen
)
2169 xNew
= wScreen
- wChild
;
2172 yNew
= rParent
.top
+ ((hParent
- hChild
) /2);
2175 else if ((yNew
+hChild
) > hScreen
)
2176 yNew
= hScreen
- hChild
;
2178 return SetWindowPos(hwndChild
, NULL
, xNew
, yNew
, 0, 0,
2179 SWP_NOSIZE
| SWP_NOZORDER
);
2181 #endif /* FEAT_GUI_DIALOG */
2184 gui_mch_activate_window(void)
2186 (void)SetActiveWindow(s_hwnd
);
2189 #if defined(FEAT_TOOLBAR) || defined(PROTO)
2191 gui_mch_show_toolbar(int showit
)
2193 if (s_toolbarhwnd
== NULL
)
2199 # ifndef TB_SETUNICODEFORMAT
2200 /* For older compilers. We assume this never changes. */
2201 # define TB_SETUNICODEFORMAT 0x2005
2203 /* Enable/disable unicode support */
2204 int uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2205 SendMessage(s_toolbarhwnd
, TB_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2207 ShowWindow(s_toolbarhwnd
, SW_SHOW
);
2210 ShowWindow(s_toolbarhwnd
, SW_HIDE
);
2213 /* Then number of bitmaps is fixed. Exit is missing! */
2214 #define TOOLBAR_BITMAP_COUNT 31
2218 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
2220 add_tabline_popup_menu_entry(HMENU pmenu
, UINT item_id
, char_u
*item_text
)
2226 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2228 /* 'encoding' differs from active codepage: convert menu name
2229 * and use wide function */
2230 wn
= enc_to_ucs2(item_text
, NULL
);
2233 MENUITEMINFOW infow
;
2235 infow
.cbSize
= sizeof(infow
);
2236 infow
.fMask
= MIIM_TYPE
| MIIM_ID
;
2237 infow
.wID
= item_id
;
2238 infow
.fType
= MFT_STRING
;
2239 infow
.dwTypeData
= wn
;
2240 infow
.cch
= (UINT
)wcslen(wn
);
2241 n
= InsertMenuItemW(pmenu
, item_id
, FALSE
, &infow
);
2243 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2244 /* Failed, try using non-wide function. */
2254 info
.cbSize
= sizeof(info
);
2255 info
.fMask
= MIIM_TYPE
| MIIM_ID
;
2257 info
.fType
= MFT_STRING
;
2258 info
.dwTypeData
= item_text
;
2259 info
.cch
= (UINT
)STRLEN(item_text
);
2260 InsertMenuItem(pmenu
, item_id
, FALSE
, &info
);
2265 show_tabline_popup_menu(void)
2271 /* When ignoring events don't show the menu. */
2279 tab_pmenu
= CreatePopupMenu();
2280 if (tab_pmenu
== NULL
)
2283 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_CLOSE
, _("Close tab"));
2284 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_NEW
, _("New tab"));
2285 add_tabline_popup_menu_entry(tab_pmenu
, TABLINE_MENU_OPEN
,
2289 rval
= TrackPopupMenuEx(tab_pmenu
, TPM_RETURNCMD
, pt
.x
, pt
.y
, s_tabhwnd
,
2292 DestroyMenu(tab_pmenu
);
2294 /* Add the string cmd into input buffer */
2297 TCHITTESTINFO htinfo
;
2300 if (ScreenToClient(s_tabhwnd
, &pt
) == 0)
2305 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
2311 send_tabline_menu_event(idx
, (int)rval
);
2316 * Show or hide the tabline.
2319 gui_mch_show_tabline(int showit
)
2321 if (s_tabhwnd
== NULL
)
2324 if (!showit
!= !showing_tabline
)
2327 ShowWindow(s_tabhwnd
, SW_SHOW
);
2329 ShowWindow(s_tabhwnd
, SW_HIDE
);
2330 showing_tabline
= showit
;
2335 * Return TRUE when tabline is displayed.
2338 gui_mch_showing_tabline(void)
2340 return s_tabhwnd
!= NULL
&& showing_tabline
;
2344 * Update the labels of the tabline.
2347 gui_mch_update_tabline(void)
2355 static int use_unicode
= FALSE
;
2360 if (s_tabhwnd
== NULL
)
2363 #if defined(FEAT_MBYTE)
2364 # ifndef CCM_SETUNICODEFORMAT
2365 /* For older compilers. We assume this never changes. */
2366 # define CCM_SETUNICODEFORMAT 0x2005
2368 uu
= (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
);
2369 if (uu
!= use_unicode
)
2371 /* Enable/disable unicode support */
2372 SendMessage(s_tabhwnd
, CCM_SETUNICODEFORMAT
, (WPARAM
)uu
, (LPARAM
)0);
2377 tie
.mask
= TCIF_TEXT
;
2380 /* Add a label for each tab page. They all contain the same text area. */
2381 for (tp
= first_tabpage
; tp
!= NULL
; tp
= tp
->tp_next
, ++nr
)
2386 if (!TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2389 tie
.pszText
= "-Empty-";
2390 TabCtrl_InsertItem(s_tabhwnd
, nr
, &tie
);
2393 get_tabline_label(tp
, FALSE
);
2394 tie
.pszText
= NameBuff
;
2399 /* Need to go through Unicode. */
2400 wstr
= enc_to_ucs2(NameBuff
, NULL
);
2405 tiw
.mask
= TCIF_TEXT
;
2408 SendMessage(s_tabhwnd
, TCM_SETITEMW
, (WPARAM
)nr
, (LPARAM
)&tiw
);
2415 TabCtrl_SetItem(s_tabhwnd
, nr
, &tie
);
2419 /* Remove any old labels. */
2420 while (TabCtrl_GetItemRect(s_tabhwnd
, nr
, &rc
))
2421 TabCtrl_DeleteItem(s_tabhwnd
, nr
);
2423 if (TabCtrl_GetCurSel(s_tabhwnd
) != curtabidx
)
2424 TabCtrl_SetCurSel(s_tabhwnd
, curtabidx
);
2428 * Set the current tab to "nr". First tab is 1.
2431 gui_mch_set_curtab(nr
)
2434 if (s_tabhwnd
== NULL
)
2437 if (TabCtrl_GetCurSel(s_tabhwnd
) != nr
-1)
2438 TabCtrl_SetCurSel(s_tabhwnd
, nr
-1);
2444 * ":simalt" command.
2447 ex_simalt(exarg_T
*eap
)
2449 char_u
*keys
= eap
->arg
;
2451 PostMessage(s_hwnd
, WM_SYSCOMMAND
, (WPARAM
)SC_KEYMENU
, (LPARAM
)0);
2455 *keys
= ' '; /* for showing system menu */
2456 PostMessage(s_hwnd
, WM_CHAR
, (WPARAM
)*keys
, (LPARAM
)0);
2462 * Create the find & replace dialogs.
2463 * You can't have both at once: ":find" when replace is showing, destroys
2464 * the replace dialog first, and the other way around.
2466 #ifdef MSWIN_FIND_REPLACE
2468 initialise_findrep(char_u
*initial_string
)
2474 /* Get the search string to use. */
2475 entry_text
= get_find_dialog_text(initial_string
, &wword
, &mcase
);
2477 s_findrep_struct
.hwndOwner
= s_hwnd
;
2478 s_findrep_struct
.Flags
= FR_DOWN
;
2480 s_findrep_struct
.Flags
|= FR_MATCHCASE
;
2482 s_findrep_struct
.Flags
|= FR_WHOLEWORD
;
2483 if (entry_text
!= NULL
&& *entry_text
!= NUL
)
2484 vim_strncpy(s_findrep_struct
.lpstrFindWhat
, entry_text
,
2485 s_findrep_struct
.wFindWhatLen
- 1);
2486 vim_free(entry_text
);
2491 set_window_title(HWND hwnd
, char *title
)
2494 if (title
!= NULL
&& enc_codepage
>= 0 && enc_codepage
!= (int)GetACP())
2499 /* Convert the title from 'encoding' to ucs2. */
2500 wbuf
= (WCHAR
*)enc_to_ucs2((char_u
*)title
, NULL
);
2503 n
= SetWindowTextW(hwnd
, wbuf
);
2505 if (n
!= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
2507 /* Retry with non-wide function (for Windows 98). */
2511 (void)SetWindowText(hwnd
, (LPCSTR
)title
);
2515 gui_mch_find_dialog(exarg_T
*eap
)
2517 #ifdef MSWIN_FIND_REPLACE
2518 if (s_findrep_msg
!= 0)
2520 if (IsWindow(s_findrep_hwnd
) && !s_findrep_is_find
)
2521 DestroyWindow(s_findrep_hwnd
);
2523 if (!IsWindow(s_findrep_hwnd
))
2525 initialise_findrep(eap
->arg
);
2526 s_findrep_hwnd
= FindText((LPFINDREPLACE
) &s_findrep_struct
);
2529 set_window_title(s_findrep_hwnd
,
2530 _("Find string (use '\\\\' to find a '\\')"));
2531 (void)SetFocus(s_findrep_hwnd
);
2533 s_findrep_is_find
= TRUE
;
2540 gui_mch_replace_dialog(exarg_T
*eap
)
2542 #ifdef MSWIN_FIND_REPLACE
2543 if (s_findrep_msg
!= 0)
2545 if (IsWindow(s_findrep_hwnd
) && s_findrep_is_find
)
2546 DestroyWindow(s_findrep_hwnd
);
2548 if (!IsWindow(s_findrep_hwnd
))
2550 initialise_findrep(eap
->arg
);
2551 s_findrep_hwnd
= ReplaceText((LPFINDREPLACE
) &s_findrep_struct
);
2554 set_window_title(s_findrep_hwnd
,
2555 _("Find & Replace (use '\\\\' to find a '\\')"));
2556 (void)SetFocus(s_findrep_hwnd
);
2558 s_findrep_is_find
= FALSE
;
2565 * Set visibility of the pointer.
2568 gui_mch_mousehide(int hide
)
2570 if (hide
!= gui
.pointer_hidden
)
2573 gui
.pointer_hidden
= hide
;
2579 gui_mch_show_popupmenu_at(vimmenu_T
*menu
, int x
, int y
)
2581 /* Unhide the mouse, we don't get move events here. */
2582 gui_mch_mousehide(FALSE
);
2584 (void)TrackPopupMenu(
2585 (HMENU
)menu
->submenu_id
,
2586 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
2588 (int)0, /*reserved param*/
2592 * NOTE: The pop-up menu can eat the mouse up event.
2593 * We deal with this in normal.c.
2599 * Got a message when the system will go down.
2604 getout_preserve_modified(1);
2608 * Get this message when the user clicks on the cross in the top right corner
2609 * of a Windows95 window.
2620 * Get a message when the window is being destroyed.
2627 Ctl3dUnregister(s_hinst
);
2637 if (!IsMinimized(hwnd
))
2641 out_flush(); /* make sure all output has been processed */
2642 (void)BeginPaint(hwnd
, &ps
);
2645 /* prevent multi-byte characters from misprinting on an invalid
2651 GetClientRect(hwnd
, &rect
);
2652 ps
.rcPaint
.left
= rect
.left
;
2653 ps
.rcPaint
.right
= rect
.right
;
2657 if (!IsRectEmpty(&ps
.rcPaint
))
2658 gui_redraw(ps
.rcPaint
.left
, ps
.rcPaint
.top
,
2659 ps
.rcPaint
.right
- ps
.rcPaint
.left
+ 1,
2660 ps
.rcPaint
.bottom
- ps
.rcPaint
.top
+ 1);
2661 EndPaint(hwnd
, &ps
);
2673 if (!IsMinimized(hwnd
))
2675 gui_resize_shell(cx
, cy
);
2678 /* Menu bar may wrap differently now */
2679 gui_mswin_get_menu_height(TRUE
);
2689 gui_focus_change(TRUE
);
2690 (void)MyWindowProc(hwnd
, WM_SETFOCUS
, (WPARAM
)hwndOldFocus
, 0);
2698 gui_focus_change(FALSE
);
2699 (void)MyWindowProc(hwnd
, WM_KILLFOCUS
, (WPARAM
)hwndNewFocus
, 0);
2703 * Get a message when the user switches back to vim
2720 /* we call gui_focus_change() in _OnSetFocus() */
2721 /* gui_focus_change((int)fActivate); */
2722 return MyWindowProc(hwnd
, WM_ACTIVATEAPP
, fActivate
, (DWORD
)dwThreadId
);
2725 #if defined(FEAT_WINDOWS) || defined(PROTO)
2727 gui_mch_destroy_scrollbar(scrollbar_T
*sb
)
2729 DestroyWindow(sb
->id
);
2734 * Get current mouse coordinates in text window.
2737 gui_mch_getmouse(int *x
, int *y
)
2742 (void)GetWindowRect(s_textArea
, &rct
);
2743 (void)GetCursorPos((LPPOINT
)&mp
);
2744 *x
= (int)(mp
.x
- rct
.left
);
2745 *y
= (int)(mp
.y
- rct
.top
);
2749 * Move mouse pointer to character at (x, y).
2752 gui_mch_setmouse(int x
, int y
)
2756 (void)GetWindowRect(s_textArea
, &rct
);
2757 (void)SetCursorPos(x
+ gui
.border_offset
+ rct
.left
,
2758 y
+ gui
.border_offset
+ rct
.top
);
2762 gui_mswin_get_valid_dimensions(
2768 int base_width
, base_height
;
2770 base_width
= gui_get_base_width()
2771 + GetSystemMetrics(SM_CXFRAME
) * 2;
2772 base_height
= gui_get_base_height()
2773 + GetSystemMetrics(SM_CYFRAME
) * 2
2774 + GetSystemMetrics(SM_CYCAPTION
)
2776 + gui_mswin_get_menu_height(FALSE
)
2779 *valid_w
= base_width
+
2780 ((w
- base_width
) / gui
.char_width
) * gui
.char_width
;
2781 *valid_h
= base_height
+
2782 ((h
- base_height
) / gui
.char_height
) * gui
.char_height
;
2786 gui_mch_flash(int msec
)
2791 * Note: InvertRect() excludes right and bottom of rectangle.
2795 rc
.right
= gui
.num_cols
* gui
.char_width
;
2796 rc
.bottom
= gui
.num_rows
* gui
.char_height
;
2797 InvertRect(s_hdc
, &rc
);
2798 gui_mch_flush(); /* make sure it's displayed */
2800 ui_delay((long)msec
, TRUE
); /* wait for a few msec */
2802 InvertRect(s_hdc
, &rc
);
2806 * Return flags used for scrolling.
2807 * The SW_INVALIDATE is required when part of the window is covered or
2808 * off-screen. Refer to MS KB Q75236.
2811 get_scroll_flags(void)
2814 RECT rcVim
, rcOther
, rcDest
;
2816 GetWindowRect(s_hwnd
, &rcVim
);
2818 /* Check if the window is partly above or below the screen. We don't care
2819 * about partly left or right of the screen, it is not relevant when
2820 * scrolling up or down. */
2821 if (rcVim
.top
< 0 || rcVim
.bottom
> GetSystemMetrics(SM_CYFULLSCREEN
))
2822 return SW_INVALIDATE
;
2824 /* Check if there is an window (partly) on top of us. */
2825 for (hwnd
= s_hwnd
; (hwnd
= GetWindow(hwnd
, GW_HWNDPREV
)) != (HWND
)0; )
2826 if (IsWindowVisible(hwnd
))
2828 GetWindowRect(hwnd
, &rcOther
);
2829 if (IntersectRect(&rcDest
, &rcVim
, &rcOther
))
2830 return SW_INVALIDATE
;
2836 * Delete the given number of lines from the given row, scrolling up any
2837 * text further down within the scroll region.
2840 gui_mch_delete_lines(
2846 rc
.left
= FILL_X(gui
.scroll_region_left
);
2847 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2848 rc
.top
= FILL_Y(row
);
2849 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2851 ScrollWindowEx(s_textArea
, 0, -num_lines
* gui
.char_height
,
2852 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2854 UpdateWindow(s_textArea
);
2855 /* This seems to be required to avoid the cursor disappearing when
2856 * scrolling such that the cursor ends up in the top-left character on
2857 * the screen... But why? (Webb) */
2858 /* It's probably fixed by disabling drawing the cursor while scrolling. */
2859 /* gui.cursor_is_valid = FALSE; */
2861 gui_clear_block(gui
.scroll_region_bot
- num_lines
+ 1,
2862 gui
.scroll_region_left
,
2863 gui
.scroll_region_bot
, gui
.scroll_region_right
);
2867 * Insert the given number of lines before the given row, scrolling down any
2868 * following text within the scroll region.
2871 gui_mch_insert_lines(
2877 rc
.left
= FILL_X(gui
.scroll_region_left
);
2878 rc
.right
= FILL_X(gui
.scroll_region_right
+ 1);
2879 rc
.top
= FILL_Y(row
);
2880 rc
.bottom
= FILL_Y(gui
.scroll_region_bot
+ 1);
2881 /* The SW_INVALIDATE is required when part of the window is covered or
2882 * off-screen. How do we avoid it when it's not needed? */
2883 ScrollWindowEx(s_textArea
, 0, num_lines
* gui
.char_height
,
2884 &rc
, &rc
, NULL
, NULL
, get_scroll_flags());
2886 UpdateWindow(s_textArea
);
2888 gui_clear_block(row
, gui
.scroll_region_left
,
2889 row
+ num_lines
- 1, gui
.scroll_region_right
);
2895 gui_mch_exit(int rc
)
2897 ReleaseDC(s_textArea
, s_hdc
);
2898 DeleteObject(s_brush
);
2901 /* Unload the tearoff bitmap */
2902 (void)DeleteObject((HGDIOBJ
)s_htearbitmap
);
2905 /* Destroy our window (if we have one). */
2908 destroying
= TRUE
; /* ignore WM_DESTROY message now */
2909 DestroyWindow(s_hwnd
);
2918 logfont2name(LOGFONT lf
)
2924 charset_name
= charset_id2name((int)lf
.lfCharSet
);
2925 res
= alloc((unsigned)(strlen(lf
.lfFaceName
) + 20
2926 + (charset_name
== NULL
? 0 : strlen(charset_name
) + 2)));
2930 /* make a normal font string out of the lf thing:*/
2931 sprintf((char *)p
, "%s:h%d", lf
.lfFaceName
, pixels_to_points(
2932 lf
.lfHeight
< 0 ? -lf
.lfHeight
: lf
.lfHeight
, TRUE
));
2939 #ifndef MSWIN16_FASTTEXT
2942 if (lf
.lfWeight
>= FW_BOLD
)
2949 if (charset_name
!= NULL
)
2952 STRCAT(p
, charset_name
);
2960 * Initialise vim to use the font with the given name.
2961 * Return FAIL if the font could not be loaded, OK otherwise.
2965 gui_mch_init_font(char_u
*font_name
, int fontset
)
2968 GuiFont font
= NOFONT
;
2972 if (get_logfont(&lf
, font_name
, NULL
, TRUE
) == OK
)
2973 font
= get_font_handle(&lf
);
2977 if (font_name
== NULL
)
2978 font_name
= lf
.lfFaceName
;
2979 #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME)
2982 #ifdef FEAT_MBYTE_IME
2985 gui_mch_free_font(gui
.norm_font
);
2986 gui
.norm_font
= font
;
2987 current_font_height
= lf
.lfHeight
;
2990 p
= logfont2name(lf
);
2993 hl_set_font_name(p
);
2995 /* When setting 'guifont' to "*" replace it with the actual font name.
2997 if (STRCMP(font_name
, "*") == 0 && STRCMP(p_guifont
, "*") == 0)
2999 vim_free(p_guifont
);
3006 #ifndef MSWIN16_FASTTEXT
3007 gui_mch_free_font(gui
.ital_font
);
3008 gui
.ital_font
= NOFONT
;
3009 gui_mch_free_font(gui
.bold_font
);
3010 gui
.bold_font
= NOFONT
;
3011 gui_mch_free_font(gui
.boldital_font
);
3012 gui
.boldital_font
= NOFONT
;
3017 gui
.ital_font
= get_font_handle(&lf
);
3018 lf
.lfItalic
= FALSE
;
3020 if (lf
.lfWeight
< FW_BOLD
)
3022 lf
.lfWeight
= FW_BOLD
;
3023 gui
.bold_font
= get_font_handle(&lf
);
3027 gui
.boldital_font
= get_font_handle(&lf
);
3035 #ifndef WPF_RESTORETOMAXIMIZED
3036 # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */
3040 * Return TRUE if the GUI window is maximized, filling the whole screen.
3047 wp
.length
= sizeof(WINDOWPLACEMENT
);
3048 if (GetWindowPlacement(s_hwnd
, &wp
))
3049 return wp
.showCmd
== SW_SHOWMAXIMIZED
3050 || (wp
.showCmd
== SW_SHOWMINIMIZED
3051 && wp
.flags
== WPF_RESTORETOMAXIMIZED
);
3057 * Called when the font changed while the window is maximized. Compute the
3058 * new Rows and Columns. This is like resizing the window.
3065 GetWindowRect(s_hwnd
, &rect
);
3066 gui_resize_shell(rect
.right
- rect
.left
3067 - GetSystemMetrics(SM_CXFRAME
) * 2,
3068 rect
.bottom
- rect
.top
3069 - GetSystemMetrics(SM_CYFRAME
) * 2
3070 - GetSystemMetrics(SM_CYCAPTION
)
3072 - gui_mswin_get_menu_height(FALSE
)
3078 * Set the window title
3086 set_window_title(s_hwnd
, (title
== NULL
? "VIM" : (char *)title
));
3089 #ifdef FEAT_MOUSESHAPE
3090 /* Table for shape IDCs. Keep in sync with the mshape_names[] table in
3092 static LPCSTR mshape_idcs
[] =
3094 MAKEINTRESOURCE(IDC_ARROW
), /* arrow */
3095 MAKEINTRESOURCE(0), /* blank */
3096 MAKEINTRESOURCE(IDC_IBEAM
), /* beam */
3097 MAKEINTRESOURCE(IDC_SIZENS
), /* updown */
3098 MAKEINTRESOURCE(IDC_SIZENS
), /* udsizing */
3099 MAKEINTRESOURCE(IDC_SIZEWE
), /* leftright */
3100 MAKEINTRESOURCE(IDC_SIZEWE
), /* lrsizing */
3101 MAKEINTRESOURCE(IDC_WAIT
), /* busy */
3103 MAKEINTRESOURCE(IDC_NO
), /* no */
3105 MAKEINTRESOURCE(IDC_ICON
), /* no */
3107 MAKEINTRESOURCE(IDC_ARROW
), /* crosshair */
3108 MAKEINTRESOURCE(IDC_ARROW
), /* hand1 */
3109 MAKEINTRESOURCE(IDC_ARROW
), /* hand2 */
3110 MAKEINTRESOURCE(IDC_ARROW
), /* pencil */
3111 MAKEINTRESOURCE(IDC_ARROW
), /* question */
3112 MAKEINTRESOURCE(IDC_ARROW
), /* right-arrow */
3113 MAKEINTRESOURCE(IDC_UPARROW
), /* up-arrow */
3114 MAKEINTRESOURCE(IDC_ARROW
) /* last one */
3118 mch_set_mouse_shape(int shape
)
3122 if (shape
== MSHAPE_HIDE
)
3126 if (shape
>= MSHAPE_NUMBERED
)
3127 idc
= MAKEINTRESOURCE(IDC_ARROW
);
3129 idc
= mshape_idcs
[shape
];
3131 SetClassLongPtr(s_textArea
, GCLP_HCURSOR
, (LONG_PTR
)LoadCursor(NULL
, idc
));
3134 SetClassLong(s_textArea
, GCL_HCURSOR
, (LONG
)LoadCursor(NULL
, idc
));
3136 SetClassWord(s_textArea
, GCW_HCURSOR
, (WORD
)LoadCursor(NULL
, idc
));
3143 /* Set the position to make it redrawn with the new shape. */
3144 (void)GetCursorPos((LPPOINT
)&mp
);
3145 (void)SetCursorPos(mp
.x
, mp
.y
);
3154 * The file browser exists in two versions: with "W" uses wide characters,
3155 * without "W" the current codepage. When FEAT_MBYTE is defined and on
3156 * Windows NT/2000/XP the "W" functions are used.
3159 # if defined(FEAT_MBYTE) && defined(WIN3264)
3161 * Wide version of convert_filter(). Keep in sync!
3164 convert_filterW(char_u
*s
)
3167 unsigned s_len
= (unsigned)STRLEN(s
);
3170 res
= (WCHAR
*)alloc((s_len
+ 3) * sizeof(WCHAR
));
3173 for (i
= 0; i
< s_len
; ++i
)
3174 if (s
[i
] == '\t' || s
[i
] == '\n')
3179 /* Add two extra NULs to make sure it's properly terminated. */
3180 res
[s_len
+ 1] = NUL
;
3181 res
[s_len
+ 2] = NUL
;
3187 * Wide version of gui_mch_browse(). Keep in sync!
3198 /* We always use the wide function. This means enc_to_ucs2() must work,
3199 * otherwise it fails miserably! */
3200 OPENFILENAMEW fileStruct
;
3201 WCHAR fileBuf
[MAXPATHL
];
3204 WCHAR
*titlep
= NULL
;
3206 WCHAR
*initdirp
= NULL
;
3214 wp
= enc_to_ucs2(dflt
, NULL
);
3219 for (i
= 0; wp
[i
] != NUL
&& i
< MAXPATHL
- 1; ++i
)
3226 /* Convert the filter to Windows format. */
3227 filterp
= convert_filterW(filter
);
3229 memset(&fileStruct
, 0, sizeof(OPENFILENAMEW
));
3230 #ifdef OPENFILENAME_SIZE_VERSION_400
3231 /* be compatible with Windows NT 4.0 */
3232 /* TODO: what to use for OPENFILENAMEW??? */
3233 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3235 fileStruct
.lStructSize
= sizeof(fileStruct
);
3239 titlep
= enc_to_ucs2(title
, NULL
);
3240 fileStruct
.lpstrTitle
= titlep
;
3243 extp
= enc_to_ucs2(ext
, NULL
);
3244 fileStruct
.lpstrDefExt
= extp
;
3246 fileStruct
.lpstrFile
= fileBuf
;
3247 fileStruct
.nMaxFile
= MAXPATHL
;
3248 fileStruct
.lpstrFilter
= filterp
;
3249 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3250 /* has an initial dir been specified? */
3251 if (initdir
!= NULL
&& *initdir
!= NUL
)
3253 /* Must have backslashes here, no matter what 'shellslash' says */
3254 initdirp
= enc_to_ucs2(initdir
, NULL
);
3255 if (initdirp
!= NULL
)
3257 for (wp
= initdirp
; *wp
!= NUL
; ++wp
)
3261 fileStruct
.lpstrInitialDir
= initdirp
;
3265 * TODO: Allow selection of multiple files. Needs another arg to this
3266 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3267 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3268 * files that don't exist yet, so I haven't put it in. What about
3269 * OFN_PATHMUSTEXIST?
3270 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3272 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3273 #ifdef FEAT_SHORTCUT
3274 if (curbuf
->b_p_bin
)
3275 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3279 if (!GetSaveFileNameW(&fileStruct
))
3284 if (!GetOpenFileNameW(&fileStruct
))
3293 /* Convert from UCS2 to 'encoding'. */
3294 p
= ucs2_to_enc(fileBuf
, NULL
);
3296 /* when out of memory we get garbage for non-ASCII chars */
3300 /* Give focus back to main window (when using MDI). */
3303 /* Shorten the file name if possible */
3304 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3306 # endif /* FEAT_MBYTE */
3310 * Convert the string s to the proper format for a filter string by replacing
3311 * the \t and \n delimeters with \0.
3312 * Returns the converted string in allocated memory.
3314 * Keep in sync with convert_filterW() above!
3317 convert_filter(char_u
*s
)
3320 unsigned s_len
= (unsigned)STRLEN(s
);
3323 res
= alloc(s_len
+ 3);
3326 for (i
= 0; i
< s_len
; ++i
)
3327 if (s
[i
] == '\t' || s
[i
] == '\n')
3332 /* Add two extra NULs to make sure it's properly terminated. */
3333 res
[s_len
+ 1] = NUL
;
3334 res
[s_len
+ 2] = NUL
;
3340 * Select a directory.
3343 gui_mch_browsedir(char_u
*title
, char_u
*initdir
)
3345 /* We fake this: Use a filter that doesn't select anything and a default
3346 * file name that won't be used. */
3347 return gui_mch_browse(0, title
, (char_u
*)_("Not Used"), NULL
,
3348 initdir
, (char_u
*)_("Directory\t*.nothing\n"));
3352 * Pop open a file browser and return the file selected, in allocated memory,
3353 * or NULL if Cancel is hit.
3354 * saving - TRUE if the file will be saved to, FALSE if it will be opened.
3355 * title - Title message for the file browser dialog.
3356 * dflt - Default name of file.
3357 * ext - Default extension to be added to files without extensions.
3358 * initdir - directory in which to open the browser (NULL = current dir)
3359 * filter - Filter for matched files to choose from.
3361 * Keep in sync with gui_mch_browseW() above!
3372 OPENFILENAME fileStruct
;
3373 char_u fileBuf
[MAXPATHL
];
3374 char_u
*initdirp
= NULL
;
3378 # if defined(FEAT_MBYTE) && defined(WIN3264)
3379 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
3380 return gui_mch_browseW(saving
, title
, dflt
, ext
, initdir
, filter
);
3386 vim_strncpy(fileBuf
, dflt
, MAXPATHL
- 1);
3388 /* Convert the filter to Windows format. */
3389 filterp
= convert_filter(filter
);
3391 memset(&fileStruct
, 0, sizeof(OPENFILENAME
));
3392 #ifdef OPENFILENAME_SIZE_VERSION_400
3393 /* be compatible with Windows NT 4.0 */
3394 fileStruct
.lStructSize
= sizeof(OPENFILENAME_SIZE_VERSION_400
);
3396 fileStruct
.lStructSize
= sizeof(fileStruct
);
3399 fileStruct
.lpstrTitle
= title
;
3400 fileStruct
.lpstrDefExt
= ext
;
3402 fileStruct
.lpstrFile
= fileBuf
;
3403 fileStruct
.nMaxFile
= MAXPATHL
;
3404 fileStruct
.lpstrFilter
= filterp
;
3405 fileStruct
.hwndOwner
= s_hwnd
; /* main Vim window is owner*/
3406 /* has an initial dir been specified? */
3407 if (initdir
!= NULL
&& *initdir
!= NUL
)
3409 /* Must have backslashes here, no matter what 'shellslash' says */
3410 initdirp
= vim_strsave(initdir
);
3411 if (initdirp
!= NULL
)
3412 for (p
= initdirp
; *p
!= NUL
; ++p
)
3415 fileStruct
.lpstrInitialDir
= initdirp
;
3419 * TODO: Allow selection of multiple files. Needs another arg to this
3420 * function to ask for it, and need to use OFN_ALLOWMULTISELECT below.
3421 * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on
3422 * files that don't exist yet, so I haven't put it in. What about
3423 * OFN_PATHMUSTEXIST?
3424 * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog.
3426 fileStruct
.Flags
= (OFN_NOCHANGEDIR
| OFN_PATHMUSTEXIST
| OFN_HIDEREADONLY
);
3427 #ifdef FEAT_SHORTCUT
3428 if (curbuf
->b_p_bin
)
3429 fileStruct
.Flags
|= OFN_NODEREFERENCELINKS
;
3433 if (!GetSaveFileName(&fileStruct
))
3438 if (!GetOpenFileName(&fileStruct
))
3445 /* Give focus back to main window (when using MDI). */
3448 /* Shorten the file name if possible */
3449 return vim_strsave(shorten_fname1((char_u
*)fileBuf
));
3451 #endif /* FEAT_BROWSE */
3461 # define BUFPATHLEN _MAX_PATH
3462 # define DRAGQVAL 0xFFFFFFFF
3464 # define BUFPATHLEN MAXPATHL
3465 # define DRAGQVAL 0xFFFF
3468 WCHAR wszFile
[BUFPATHLEN
];
3470 char szFile
[BUFPATHLEN
];
3471 UINT cFiles
= DragQueryFile(hDrop
, DRAGQVAL
, NULL
, 0);
3475 int_u modifiers
= 0;
3477 /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */
3479 /* Obtain dropped position */
3480 DragQueryPoint(hDrop
, &pt
);
3481 MapWindowPoints(s_hwnd
, s_textArea
, &pt
, 1);
3487 fnames
= (char_u
**)alloc(cFiles
* sizeof(char_u
*));
3490 for (i
= 0; i
< cFiles
; ++i
)
3493 if (DragQueryFileW(hDrop
, i
, wszFile
, BUFPATHLEN
) > 0)
3494 fnames
[i
] = ucs2_to_enc(wszFile
, NULL
);
3498 DragQueryFile(hDrop
, i
, szFile
, BUFPATHLEN
);
3499 fnames
[i
] = vim_strsave(szFile
);
3507 if ((GetKeyState(VK_SHIFT
) & 0x8000) != 0)
3508 modifiers
|= MOUSE_SHIFT
;
3509 if ((GetKeyState(VK_CONTROL
) & 0x8000) != 0)
3510 modifiers
|= MOUSE_CTRL
;
3511 if ((GetKeyState(VK_MENU
) & 0x8000) != 0)
3512 modifiers
|= MOUSE_ALT
;
3514 gui_handle_drop(pt
.x
, pt
.y
, modifiers
, fnames
, cFiles
);
3516 s_need_activate
= TRUE
;
3529 static UINT prev_code
= 0; /* code of previous call */
3530 scrollbar_T
*sb
, *sb_info
;
3532 int dragging
= FALSE
;
3533 int dont_scroll_save
= dont_scroll
;
3539 si
.cbSize
= sizeof(si
);
3543 sb
= gui_mswin_find_scrollbar(hwndCtl
);
3547 if (sb
->wp
!= NULL
) /* Left or right scrollbar */
3550 * Careful: need to get scrollbar info out of first (left) scrollbar
3551 * for window, but keep real scrollbar too because we must pass it to
3552 * gui_drag_scrollbar().
3554 sb_info
= &sb
->wp
->w_scrollbars
[0];
3556 else /* Bottom scrollbar */
3558 val
= sb_info
->value
;
3565 if (sb
->scroll_shift
> 0)
3566 val
<<= sb
->scroll_shift
;
3575 val
+= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3578 val
-= (sb_info
->size
> 2 ? sb_info
->size
- 2 : 1);
3587 if (prev_code
== SB_THUMBTRACK
)
3590 * "pos" only gives us 16-bit data. In case of large file,
3591 * use GetScrollPos() which returns 32-bit. Unfortunately it
3592 * is not valid while the scrollbar is being dragged.
3594 val
= GetScrollPos(hwndCtl
, SB_CTL
);
3595 if (sb
->scroll_shift
> 0)
3596 val
<<= sb
->scroll_shift
;
3601 /* TRACE("Unknown scrollbar event %d\n", code); */
3607 si
.nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3608 SetScrollInfo(hwndCtl
, SB_CTL
, &si
, TRUE
);
3610 nPos
= (sb
->scroll_shift
> 0) ? val
>> sb
->scroll_shift
: val
;
3611 SetScrollPos(hwndCtl
, SB_CTL
, nPos
, TRUE
);
3615 * When moving a vertical scrollbar, move the other vertical scrollbar too.
3619 scrollbar_T
*sba
= sb
->wp
->w_scrollbars
;
3620 HWND id
= sba
[ (sb
== sba
+ SBAR_LEFT
) ? SBAR_RIGHT
: SBAR_LEFT
].id
;
3623 SetScrollInfo(id
, SB_CTL
, &si
, TRUE
);
3625 SetScrollPos(id
, SB_CTL
, nPos
, TRUE
);
3629 /* Don't let us be interrupted here by another message. */
3630 s_busy_processing
= TRUE
;
3632 /* When "allow_scrollbar" is FALSE still need to remember the new
3633 * position, but don't actually scroll by setting "dont_scroll". */
3634 dont_scroll
= !allow_scrollbar
;
3636 gui_drag_scrollbar(sb
, val
, dragging
);
3638 s_busy_processing
= FALSE
;
3639 dont_scroll
= dont_scroll_save
;
3646 * Get command line arguments.
3647 * Use "prog" as the name of the program and "cmdline" as the arguments.
3648 * Copy the arguments to allocated memory.
3649 * Return the number of arguments (including program name).
3650 * Return pointers to the arguments in "argvp".
3651 * Return pointer to buffer in "tofree".
3652 * Returns zero when out of memory.
3656 get_cmd_args(char *prog
, char *cmdline
, char ***argvp
, char **tofree
)
3669 /* Try using the Unicode version first, it takes care of conversion when
3670 * 'encoding' is changed. */
3671 argc
= get_cmd_argsW(&argv
);
3676 /* Handle the program name. Remove the ".exe" extension, and find the 1st
3678 p
= strrchr(prog
, '.');
3681 for (progp
= prog
; *progp
== ' '; ++progp
)
3684 /* The command line is copied to allocated memory, so that we can change
3685 * it. Add the size of the string, the separating NUL and a terminating
3687 newcmdline
= malloc(STRLEN(cmdline
) + STRLEN(progp
) + 2);
3688 if (newcmdline
== NULL
)
3692 * First round: count the number of arguments ("pnew" == NULL).
3693 * Second round: produce the arguments.
3695 for (round
= 1; round
<= 2; ++round
)
3697 /* First argument is the program name. */
3701 strcpy(pnew
, progp
);
3702 pnew
+= strlen(pnew
);
3707 * Isolate each argument and put it in argv[].
3717 while (*p
!= NUL
&& (inquote
|| (*p
!= ' ' && *p
!= '\t')))
3719 /* Backslashes are only special when followed by a double
3721 i
= (int)strspn(p
, "\\");
3724 /* Halve the number of backslashes. */
3725 if (i
> 1 && pnew
!= NULL
)
3727 memset(pnew
, '\\', i
/ 2);
3731 /* Even nr of backslashes toggles quoting, uneven copies
3732 * the double quote. */
3735 else if (pnew
!= NULL
)
3741 /* Copy span of backslashes unmodified. */
3744 memset(pnew
, '\\', i
);
3754 /* Can't use mb_* functions, because 'encoding' is not
3755 * initialized yet here. */
3756 if (IsDBCSLeadByte(*p
))
3769 while (*p
== ' ' || *p
== '\t')
3770 ++p
; /* advance until a non-space */
3775 argv
= (char **)malloc((argc
+ 1) * sizeof(char *));
3778 vim_free(newcmdline
);
3779 return 0; /* malloc error */
3787 argv
[argc
] = NULL
; /* NULL-terminated list */