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.
13 * GUI support for Microsoft Windows. Win32 initially; maybe Win16 later
15 * George V. Reilly <george@reilly.org> wrote the original Win32 GUI.
16 * Robert Webb reworked it to use the existing GUI stuff and added menu,
19 * Note: Clipboard stuff, for cutting and pasting text to other windows, is in
20 * os_win32.c. (It can also be done from the terminal version).
22 * TODO: Some of the function signatures ought to be updated for Win64;
23 * e.g., replace LONG with LONG_PTR, etc.
29 * These are new in Windows ME/XP, only defined in recent compilers.
31 #ifndef HANDLE_WM_XBUTTONUP
32 # define HANDLE_WM_XBUTTONUP(hwnd, wParam, lParam, fn) \
33 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
35 #ifndef HANDLE_WM_XBUTTONDOWN
36 # define HANDLE_WM_XBUTTONDOWN(hwnd, wParam, lParam, fn) \
37 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
39 #ifndef HANDLE_WM_XBUTTONDBLCLK
40 # define HANDLE_WM_XBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
41 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
45 * Include the common stuff for MS-Windows GUI.
59 * Add a lot of missing defines.
60 * They are not always missing, we need the #ifndef's.
66 # define IsMinimized(hwnd) IsIconic(hwnd)
69 # define IsMaximized(hwnd) IsZoomed(hwnd)
72 # define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
74 # ifndef GetStockBrush
75 # define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
78 # define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
81 # ifndef HANDLE_WM_RBUTTONDBLCLK
82 # define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
83 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
85 # ifndef HANDLE_WM_MBUTTONUP
86 # define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
87 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
89 # ifndef HANDLE_WM_MBUTTONDBLCLK
90 # define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
91 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
93 # ifndef HANDLE_WM_LBUTTONDBLCLK
94 # define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
95 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
97 # ifndef HANDLE_WM_RBUTTONDOWN
98 # define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
99 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
101 # ifndef HANDLE_WM_MOUSEMOVE
102 # define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
103 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
105 # ifndef HANDLE_WM_RBUTTONUP
106 # define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
107 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
109 # ifndef HANDLE_WM_MBUTTONDOWN
110 # define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
111 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
113 # ifndef HANDLE_WM_LBUTTONUP
114 # define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
115 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
117 # ifndef HANDLE_WM_LBUTTONDOWN
118 # define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
119 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
121 # ifndef HANDLE_WM_SYSCHAR
122 # define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
123 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
125 # ifndef HANDLE_WM_ACTIVATEAPP
126 # define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
127 ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
129 # ifndef HANDLE_WM_WINDOWPOSCHANGING
130 # define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
131 (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
133 # ifndef HANDLE_WM_VSCROLL
134 # define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
135 ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
137 # ifndef HANDLE_WM_SETFOCUS
138 # define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
139 ((fn)((hwnd), (HWND)(wParam)), 0L)
141 # ifndef HANDLE_WM_KILLFOCUS
142 # define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
143 ((fn)((hwnd), (HWND)(wParam)), 0L)
145 # ifndef HANDLE_WM_HSCROLL
146 # define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
147 ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
149 # ifndef HANDLE_WM_DROPFILES
150 # define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
151 ((fn)((hwnd), (HDROP)(wParam)), 0L)
153 # ifndef HANDLE_WM_CHAR
154 # define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
155 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
157 # ifndef HANDLE_WM_SYSDEADCHAR
158 # define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
159 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
161 # ifndef HANDLE_WM_DEADCHAR
162 # define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
163 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
165 #endif /* __MINGW32__ */
168 /* Some parameters for tearoff menus. All in pixels. */
169 #define TEAROFF_PADDING_X 2
170 #define TEAROFF_BUTTON_PAD_X 8
171 #define TEAROFF_MIN_WIDTH 200
172 #define TEAROFF_SUBMENU_LABEL ">>"
173 #define TEAROFF_COLUMN_PADDING 3 // # spaces to pad column with.
176 /* For the Intellimouse: */
177 #ifndef WM_MOUSEWHEEL
178 #define WM_MOUSEWHEEL 0x20a
183 # define ID_BEVAL_TOOLTIP 200
184 # define BEVAL_TEXT_LEN MAXPATHL
187 /* Work around old versions of basetsd.h which wrongly declares
188 * UINT_PTR as unsigned long. */
189 # define UINT_PTR UINT
192 static void make_tooltip
__ARGS((BalloonEval
*beval
, char *text
, POINT pt
));
193 static void delete_tooltip
__ARGS((BalloonEval
*beval
));
194 static VOID CALLBACK BevalTimerProc
__ARGS((HWND hwnd
, UINT uMsg
, UINT_PTR idEvent
, DWORD dwTime
));
196 static BalloonEval
*cur_beval
= NULL
;
197 static UINT_PTR BevalTimerId
= 0;
198 static DWORD LastActivity
= 0;
201 * excerpts from headers since this may not be presented
202 * in the extremely old compilers
204 #include <pshpack1.h>
206 typedef struct _DllVersionInfo
209 DWORD dwMajorVersion
;
210 DWORD dwMinorVersion
;
217 typedef struct tagTOOLINFOA_NEW
229 typedef struct tagNMTTDISPINFO_NEW
239 typedef HRESULT (WINAPI
* DLLGETVERSIONPROC
)(DLLVERSIONINFO
*);
240 #ifndef TTM_SETMAXTIPWIDTH
241 # define TTM_SETMAXTIPWIDTH (WM_USER+24)
244 #ifndef TTF_DI_SETITEM
245 # define TTF_DI_SETITEM 0x8000
248 #ifndef TTN_GETDISPINFO
249 # define TTN_GETDISPINFO (TTN_FIRST - 0)
252 #endif /* defined(FEAT_BEVAL) */
254 #if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
255 /* Older MSVC compilers don't have LPNMTTDISPINFO[AW] thus we need to define
256 * it here if LPNMTTDISPINFO isn't defined.
257 * MingW doesn't define LPNMTTDISPINFO but typedefs it. Thus we need to check
259 # if !defined(LPNMTTDISPINFO) && defined(_MSC_VER)
260 typedef struct tagNMTTDISPINFOA
{
267 } NMTTDISPINFOA
, *LPNMTTDISPINFOA
;
268 # define LPNMTTDISPINFO LPNMTTDISPINFOA
271 typedef struct tagNMTTDISPINFOW
{
278 } NMTTDISPINFOW
, *LPNMTTDISPINFOW
;
283 #ifndef TTN_GETDISPINFOW
284 # define TTN_GETDISPINFOW (TTN_FIRST - 10)
287 /* Local variables: */
290 static UINT s_menu_id
= 100;
293 * Use the system font for dialogs and tear-off menus. Remove this line to
296 # define USE_SYSMENU_FONT
299 #define VIM_NAME "vim"
300 #define VIM_CLASS "Vim"
301 #define VIM_CLASSW L"Vim"
303 /* Initial size for the dialog template. For gui_mch_dialog() it's fixed,
304 * thus there should be room for every dialog. For tearoffs it's made bigger
306 #define DLG_ALLOC_SIZE 16 * 1024
309 * stuff for dialogs, menus, tearoffs etc.
311 static LRESULT APIENTRY
dialog_callback(HWND
, UINT
, WPARAM
, LPARAM
);
312 static LRESULT APIENTRY
tearoff_callback(HWND
, UINT
, WPARAM
, LPARAM
);
323 const char *caption
);
324 static LPWORD
lpwAlign(LPWORD
);
325 static int nCopyAnsiToWideChar(LPWORD
, LPSTR
);
326 static void gui_mch_tearoff(char_u
*title
, vimmenu_T
*menu
, int initX
, int initY
);
327 static void get_dialog_font_metrics(void);
329 static int dialog_default_button
= -1;
331 /* Intellimouse support */
332 static int mouse_scroll_lines
= 0;
333 static UINT msh_msgmousewheel
= 0;
335 static int s_usenewlook
; /* emulate W95/NT4 non-bold dialogs */
337 static void initialise_toolbar(void);
338 static int get_toolbar_bitmap(vimmenu_T
*menu
);
341 #ifdef FEAT_GUI_TABLINE
342 static void initialise_tabline(void);
345 #ifdef FEAT_MBYTE_IME
346 static LRESULT
_OnImeComposition(HWND hwnd
, WPARAM dbcs
, LPARAM param
);
347 static char_u
*GetResultStr(HWND hwnd
, int GCS
, int *lenp
);
349 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
351 typedef struct tagCOMPOSITIONFORM
{
355 } COMPOSITIONFORM
, *PCOMPOSITIONFORM
, NEAR
*NPCOMPOSITIONFORM
, FAR
*LPCOMPOSITIONFORM
;
359 static HINSTANCE hLibImm
= NULL
;
360 static LONG (WINAPI
*pImmGetCompositionStringA
)(HIMC
, DWORD
, LPVOID
, DWORD
);
361 static LONG (WINAPI
*pImmGetCompositionStringW
)(HIMC
, DWORD
, LPVOID
, DWORD
);
362 static HIMC (WINAPI
*pImmGetContext
)(HWND
);
363 static HIMC (WINAPI
*pImmAssociateContext
)(HWND
, HIMC
);
364 static BOOL (WINAPI
*pImmReleaseContext
)(HWND
, HIMC
);
365 static BOOL (WINAPI
*pImmGetOpenStatus
)(HIMC
);
366 static BOOL (WINAPI
*pImmSetOpenStatus
)(HIMC
, BOOL
);
367 static BOOL (WINAPI
*pImmGetCompositionFont
)(HIMC
, LPLOGFONTA
);
368 static BOOL (WINAPI
*pImmSetCompositionFont
)(HIMC
, LPLOGFONTA
);
369 static BOOL (WINAPI
*pImmSetCompositionWindow
)(HIMC
, LPCOMPOSITIONFORM
);
370 static BOOL (WINAPI
*pImmGetConversionStatus
)(HIMC
, LPDWORD
, LPDWORD
);
371 static BOOL (WINAPI
*pImmSetConversionStatus
)(HIMC
, DWORD
, DWORD
);
372 static void dyn_imm_load(void);
374 # define pImmGetCompositionStringA ImmGetCompositionStringA
375 # define pImmGetCompositionStringW ImmGetCompositionStringW
376 # define pImmGetContext ImmGetContext
377 # define pImmAssociateContext ImmAssociateContext
378 # define pImmReleaseContext ImmReleaseContext
379 # define pImmGetOpenStatus ImmGetOpenStatus
380 # define pImmSetOpenStatus ImmSetOpenStatus
381 # define pImmGetCompositionFont ImmGetCompositionFontA
382 # define pImmSetCompositionFont ImmSetCompositionFontA
383 # define pImmSetCompositionWindow ImmSetCompositionWindow
384 # define pImmGetConversionStatus ImmGetConversionStatus
385 # define pImmSetConversionStatus ImmSetConversionStatus
388 #ifndef ETO_IGNORELANGUAGE
389 # define ETO_IGNORELANGUAGE 0x1000
392 /* multi monitor support */
393 typedef struct _MONITORINFOstruct
401 typedef HANDLE _HMONITOR
;
402 typedef _HMONITOR (WINAPI
*TMonitorFromWindow
)(HWND
, DWORD
);
403 typedef BOOL (WINAPI
*TGetMonitorInfo
)(_HMONITOR
, _MONITORINFO
*);
405 static TMonitorFromWindow pMonitorFromWindow
= NULL
;
406 static TGetMonitorInfo pGetMonitorInfo
= NULL
;
407 static HANDLE user32_lib
= NULL
;
408 #ifdef FEAT_NETBEANS_INTG
409 int WSInitialized
= FALSE
; /* WinSock is initialized */
413 * For Transparent Window (for only Windows 2000)
415 #define USE_LAYERED_WINDOW 1
416 #if USE_LAYERED_WINDOW
417 # define WS_EX_LAYERED 0x80000
419 typedef DWORD (WINAPI
*FWINLAYER
)(HWND hwnd
, DWORD crKey
, BYTE bAlpha
,
421 static void w32_set_transparency(HWND hwnd
, BYTE bAlpha
);
422 #endif /* USE_LAYERED_WINDOW */
425 * Return TRUE when running under Windows NT 3.x or Win32s, both of which have
426 * less fancy GUI APIs.
431 return ((os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
432 && os_version
.dwMajorVersion
== 3)
433 || (os_version
.dwPlatformId
== VER_PLATFORM_WIN32s
));
437 * Return TRUE when running under Win32s.
442 return (os_version
.dwPlatformId
== VER_PLATFORM_WIN32s
);
446 get_caption_height(void)
449 * A window's caption includes extra 1 dot margin. When caption is
450 * removed the margin also be removed. So we must return -1 when
451 * caption is diabled.
453 return GetWindowLong(s_hwnd
, GWL_STYLE
) & WS_CAPTION
?
454 GetSystemMetrics(SM_CYCAPTION
) : -1;
458 gui_mch_show_caption(int show
)
460 LONG style
, newstyle
;
462 /* Remove caption when title is null. */
463 style
= newstyle
= GetWindowLong(s_hwnd
, GWL_STYLE
);
464 if (show
&& !(style
& WS_CAPTION
))
465 newstyle
= style
| WS_CAPTION
;
466 else if (!show
&& (style
& WS_CAPTION
))
467 newstyle
= style
& ~WS_CAPTION
;
468 if (newstyle
!= style
)
470 SetWindowLong(s_hwnd
, GWL_STYLE
, newstyle
);
471 SetWindowPos(s_hwnd
, NULL
, 0, 0, 0, 0,
472 SWP_FRAMECHANGED
| SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOZORDER
);
473 gui_set_shellsize(FALSE
, FALSE
, RESIZE_BOTH
);
479 * Figure out how high the menu bar is at the moment.
482 gui_mswin_get_menu_height(
483 int fix_window
) /* If TRUE, resize window if menu height changed */
485 static int old_menu_height
= -1;
491 if (gui
.menu_is_active
)
492 num
= GetMenuItemCount(s_menuBar
);
500 if (is_winnt_3()) /* for NT 3.xx */
503 menu_height
= GetSystemMetrics(SM_CYMENU
);
507 int frameht
= GetSystemMetrics(SM_CYFRAME
);
508 int capht
= get_caption_height();
510 /* get window rect of s_hwnd
511 * get client rect of s_hwnd
513 * subtract from window rect, the sum of client height,
514 * (if not maximized)frame thickness, and caption height.
516 GetWindowRect(s_hwnd
, &r1
);
517 GetClientRect(s_hwnd
, &r2
);
518 menu_height
= r1
.bottom
- r1
.top
- (r2
.bottom
- r2
.top
519 + 2 * frameht
* (!IsZoomed(s_hwnd
)) + capht
);
522 else /* win95 and variants (NT 4.0, I guess) */
525 * In case 'lines' is set in _vimrc/_gvimrc window width doesn't
526 * seem to have been set yet, so menu wraps in default window
527 * width which is very narrow. Instead just return height of a
528 * single menu item. Will still be wrong when the menu really
529 * should wrap over more than one line.
531 GetMenuItemRect(s_hwnd
, s_menuBar
, 0, &rc1
);
533 menu_height
= rc1
.bottom
- rc1
.top
+ 1;
536 GetMenuItemRect(s_hwnd
, s_menuBar
, num
- 1, &rc2
);
537 menu_height
= rc2
.bottom
- rc1
.top
+ 1;
542 if (fix_window
&& menu_height
!= old_menu_height
)
544 old_menu_height
= menu_height
;
545 gui_set_shellsize(FALSE
, FALSE
, RESIZE_VERT
);
554 * Setup for the Intellimouse
557 init_mouse_wheel(void)
560 #ifndef SPI_GETWHEELSCROLLLINES
561 # define SPI_GETWHEELSCROLLLINES 104
563 #ifndef SPI_SETWHEELSCROLLLINES
564 # define SPI_SETWHEELSCROLLLINES 105
567 #define VMOUSEZ_CLASSNAME "MouseZ" /* hidden wheel window class */
568 #define VMOUSEZ_TITLE "Magellan MSWHEEL" /* hidden wheel window title */
569 #define VMSH_MOUSEWHEEL "MSWHEEL_ROLLMSG"
570 #define VMSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG"
573 UINT msh_msgscrolllines
;
575 msh_msgmousewheel
= 0;
576 mouse_scroll_lines
= 3; /* reasonable default */
578 if ((os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
579 && os_version
.dwMajorVersion
>= 4)
580 || (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
581 && ((os_version
.dwMajorVersion
== 4
582 && os_version
.dwMinorVersion
>= 10)
583 || os_version
.dwMajorVersion
>= 5)))
585 /* if NT 4.0+ (or Win98) get scroll lines directly from system */
586 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0,
587 &mouse_scroll_lines
, 0);
589 else if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
590 || (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
591 && os_version
.dwMajorVersion
< 4))
593 * If Win95 or NT 3.51,
594 * try to find the hidden point32 window.
596 hdl_mswheel
= FindWindow(VMOUSEZ_CLASSNAME
, VMOUSEZ_TITLE
);
599 msh_msgscrolllines
= RegisterWindowMessage(VMSH_SCROLL_LINES
);
600 if (msh_msgscrolllines
)
602 mouse_scroll_lines
= (int)SendMessage(hdl_mswheel
,
603 msh_msgscrolllines
, 0, 0);
604 msh_msgmousewheel
= RegisterWindowMessage(VMSH_MOUSEWHEEL
);
611 /* Intellimouse wheel handler */
617 /* Treat a mouse wheel event as if it were a scroll request */
622 if (curwin
->w_scrollbars
[SBAR_RIGHT
].id
!= 0)
624 hwndCtl
= curwin
->w_scrollbars
[SBAR_RIGHT
].id
;
625 size
= curwin
->w_scrollbars
[SBAR_RIGHT
].size
;
627 else if (curwin
->w_scrollbars
[SBAR_LEFT
].id
!= 0)
629 hwndCtl
= curwin
->w_scrollbars
[SBAR_LEFT
].id
;
630 size
= curwin
->w_scrollbars
[SBAR_LEFT
].size
;
635 size
= curwin
->w_height
;
636 if (mouse_scroll_lines
== 0)
639 if (mouse_scroll_lines
> 0
640 && mouse_scroll_lines
< (size
> 2 ? size
- 2 : 1))
642 for (i
= mouse_scroll_lines
; i
> 0; --i
)
643 _OnScroll(hwnd
, hwndCtl
, zDelta
>= 0 ? SB_LINEUP
: SB_LINEDOWN
, 0);
646 _OnScroll(hwnd
, hwndCtl
, zDelta
>= 0 ? SB_PAGEUP
: SB_PAGEDOWN
, 0);
649 #ifdef USE_SYSMENU_FONT
655 gui_w32_get_menu_font(LOGFONT
*lf
)
659 nm
.cbSize
= sizeof(NONCLIENTMETRICS
);
660 if (!SystemParametersInfo(
661 SPI_GETNONCLIENTMETRICS
,
662 sizeof(NONCLIENTMETRICS
),
672 #if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
674 * Set the GUI tabline font to the system menu font
677 set_tabline_font(void)
686 if (gui_w32_get_menu_font(&lfSysmenu
) != OK
)
689 font
= CreateFontIndirect(&lfSysmenu
);
691 SendMessage(s_tabhwnd
, WM_SETFONT
, (WPARAM
)font
, TRUE
);
694 * Compute the height of the font used for the tab text
696 hwnd
= GetDesktopWindow();
697 hdc
= GetWindowDC(hwnd
);
698 hfntOld
= SelectFont(hdc
, font
);
700 GetTextMetrics(hdc
, &tm
);
702 SelectFont(hdc
, hfntOld
);
703 ReleaseDC(hwnd
, hdc
);
706 * The space used by the tab border and the space between the tab label
707 * and the tab border is included as 7.
709 gui
.tabline_height
= tm
.tmHeight
+ tm
.tmInternalLeading
+ 7;
714 * Invoked when a setting was changed.
716 static LRESULT CALLBACK
717 _OnSettingChange(UINT n
)
719 if (n
== SPI_SETWHEELSCROLLLINES
)
720 SystemParametersInfo(SPI_GETWHEELSCROLLLINES
, 0,
721 &mouse_scroll_lines
, 0);
722 #if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
723 if (n
== SPI_SETNONCLIENTMETRICS
)
729 #if 0 /* disabled, a gap appears below and beside the window, and the window
730 can be moved (in a strange way) */
732 * Even though we have _DuringSizing() which makes the rubber band a valid
733 * size, we need this for when the user maximises the window.
734 * TODO: Doesn't seem to adjust the width though for some reason.
737 _OnWindowPosChanging(
743 if (!(lpwpos
->flags
& SWP_NOSIZE
))
745 if (IsMaximized(hwnd
)
746 && (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
747 || (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
748 && os_version
.dwMajorVersion
>= 4)))
750 SystemParametersInfo(SPI_GETWORKAREA
, 0, &workarea_rect
, 0);
751 lpwpos
->x
= workarea_rect
.left
;
752 lpwpos
->y
= workarea_rect
.top
;
753 lpwpos
->cx
= workarea_rect
.right
- workarea_rect
.left
;
754 lpwpos
->cy
= workarea_rect
.bottom
- workarea_rect
.top
;
756 gui_mswin_get_valid_dimensions(lpwpos
->cx
, lpwpos
->cy
,
757 &lpwpos
->cx
, &lpwpos
->cy
);
763 #ifdef FEAT_NETBEANS_INTG
767 const LPWINDOWPOS lpwpos
)
769 static int x
= 0, y
= 0, cx
= 0, cy
= 0;
771 if (WSInitialized
&& (lpwpos
->x
!= x
|| lpwpos
->y
!= y
772 || lpwpos
->cx
!= cx
|| lpwpos
->cy
!= cy
))
778 netbeans_frame_moved(x
, y
);
780 /* Allow to send WM_SIZE and WM_MOVE */
781 FORWARD_WM_WINDOWPOSCHANGED(hwnd
, lpwpos
, MyWindowProc
);
791 int valid_w
, valid_h
;
792 int w_offset
, h_offset
;
794 w
= lprc
->right
- lprc
->left
;
795 h
= lprc
->bottom
- lprc
->top
;
796 gui_mswin_get_valid_dimensions(w
, h
, &valid_w
, &valid_h
);
797 w_offset
= w
- valid_w
;
798 h_offset
= h
- valid_h
;
800 if (fwSide
== WMSZ_LEFT
|| fwSide
== WMSZ_TOPLEFT
801 || fwSide
== WMSZ_BOTTOMLEFT
)
802 lprc
->left
+= w_offset
;
803 else if (fwSide
== WMSZ_RIGHT
|| fwSide
== WMSZ_TOPRIGHT
804 || fwSide
== WMSZ_BOTTOMRIGHT
)
805 lprc
->right
-= w_offset
;
807 if (fwSide
== WMSZ_TOP
|| fwSide
== WMSZ_TOPLEFT
808 || fwSide
== WMSZ_TOPRIGHT
)
809 lprc
->top
+= h_offset
;
810 else if (fwSide
== WMSZ_BOTTOM
|| fwSide
== WMSZ_BOTTOMLEFT
811 || fwSide
== WMSZ_BOTTOMRIGHT
)
812 lprc
->bottom
-= h_offset
;
818 static LRESULT CALLBACK
826 TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
827 hwnd, uMsg, wParam, lParam);
830 HandleMouseHide(uMsg
, lParam
);
838 HANDLE_MSG(hwnd
, WM_DEADCHAR
, _OnDeadChar
);
839 HANDLE_MSG(hwnd
, WM_SYSDEADCHAR
, _OnDeadChar
);
840 /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */
841 HANDLE_MSG(hwnd
, WM_CLOSE
, _OnClose
);
842 /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */
843 HANDLE_MSG(hwnd
, WM_DESTROY
, _OnDestroy
);
844 HANDLE_MSG(hwnd
, WM_DROPFILES
, _OnDropFiles
);
845 HANDLE_MSG(hwnd
, WM_HSCROLL
, _OnScroll
);
846 HANDLE_MSG(hwnd
, WM_KILLFOCUS
, _OnKillFocus
);
848 HANDLE_MSG(hwnd
, WM_COMMAND
, _OnMenu
);
850 /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */
851 /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */
852 HANDLE_MSG(hwnd
, WM_SETFOCUS
, _OnSetFocus
);
853 HANDLE_MSG(hwnd
, WM_SIZE
, _OnSize
);
854 /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */
855 /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */
856 HANDLE_MSG(hwnd
, WM_VSCROLL
, _OnScroll
);
857 // HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging);
858 HANDLE_MSG(hwnd
, WM_ACTIVATEAPP
, _OnActivateApp
);
859 #ifdef FEAT_NETBEANS_INTG
860 HANDLE_MSG(hwnd
, WM_WINDOWPOSCHANGED
, _OnWindowPosChanged
);
863 #ifdef FEAT_GUI_TABLINE
866 if (gui_mch_showing_tabline())
872 * If the cursor is on the tabline, display the tab menu
874 GetCursorPos((LPPOINT
)&pt
);
875 GetWindowRect(s_textArea
, &rect
);
878 show_tabline_popup_menu();
882 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
884 case WM_LBUTTONDBLCLK
:
887 * If the user double clicked the tabline, create a new tab
889 if (gui_mch_showing_tabline())
894 GetCursorPos((LPPOINT
)&pt
);
895 GetWindowRect(s_textArea
, &rect
);
897 send_tabline_menu_event(0, TABLINE_MENU_NEW
);
899 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
903 case WM_QUERYENDSESSION
: /* System wants to go down. */
904 gui_shell_closed(); /* Will exit when no changed buffers. */
905 return FALSE
; /* Do NOT allow system to go down. */
908 if (wParam
) /* system only really goes down when wParam is TRUE */
913 /* Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
914 * byte while we want the UTF-16 character value. */
915 _OnChar(hwnd
, (UINT
)wParam
, (int)(short)LOWORD(lParam
));
920 * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
921 * shortcut key, handle like a typed ALT key, otherwise call Windows
925 if ( !gui
.menu_is_active
927 || (p_wak
[0] == 'm' && !gui_is_menu_shortcut((int)wParam
))
931 _OnSysChar(hwnd
, (UINT
)wParam
, (int)(short)LOWORD(lParam
));
936 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
941 /* This used to be done only when menu is active: ALT key is used for
942 * that. But that caused problems when menu is disabled and using
943 * Alt-Tab-Esc: get into a strange state where no mouse-moved events
944 * are received, mouse pointer remains hidden. */
945 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
950 case WM_SIZING
: /* HANDLE_MSG doesn't seem to handle this one */
951 return _DuringSizing((UINT
)wParam
, (LPRECT
)lParam
);
954 _OnMouseWheel(hwnd
, HIWORD(wParam
));
957 /* Notification for change in SystemParametersInfo() */
958 case WM_SETTINGCHANGE
:
959 return _OnSettingChange((UINT
)wParam
);
961 #if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
963 switch (((LPNMHDR
) lParam
)->code
)
966 case TTN_GETDISPINFOW
:
968 case TTN_GETDISPINFO
:
970 LPNMHDR hdr
= (LPNMHDR
)lParam
;
972 static void *tt_text
= NULL
;
977 # ifdef FEAT_GUI_TABLINE
978 if (gui_mch_showing_tabline()
979 && hdr
->hwndFrom
== TabCtrl_GetToolTips(s_tabhwnd
))
983 * Mouse is over the GUI tabline. Display the
984 * tooltip for the tab under the cursor
986 * Get the cursor position within the tab control
989 if (ScreenToClient(s_tabhwnd
, &pt
) != 0)
991 TCHITTESTINFO htinfo
;
995 * Get the tab under the cursor
999 idx
= TabCtrl_HitTest(s_tabhwnd
, &htinfo
);
1004 tp
= find_tabpage(idx
+ 1);
1007 get_tabline_label(tp
, TRUE
);
1014 # ifdef FEAT_TOOLBAR
1015 # ifdef FEAT_GUI_TABLINE
1022 idButton
= (UINT
) hdr
->idFrom
;
1023 pMenu
= gui_mswin_find_menu(root_menu
, idButton
);
1025 str
= pMenu
->strings
[MENU_INDEX_TIP
];
1031 if (hdr
->code
== TTN_GETDISPINFOW
)
1033 LPNMTTDISPINFOW lpdi
= (LPNMTTDISPINFOW
)lParam
;
1035 /* Set the maximum width, this also enables using
1036 * \n for line break. */
1037 SendMessage(lpdi
->hdr
.hwndFrom
, TTM_SETMAXTIPWIDTH
,
1040 tt_text
= enc_to_utf16(str
, NULL
);
1041 lpdi
->lpszText
= tt_text
;
1042 /* can't show tooltip if failed */
1047 LPNMTTDISPINFO lpdi
= (LPNMTTDISPINFO
)lParam
;
1049 /* Set the maximum width, this also enables using
1050 * \n for line break. */
1051 SendMessage(lpdi
->hdr
.hwndFrom
, TTM_SETMAXTIPWIDTH
,
1054 if (STRLEN(str
) < sizeof(lpdi
->szText
)
1055 || ((tt_text
= vim_strsave(str
)) == NULL
))
1056 vim_strncpy(lpdi
->szText
, str
,
1057 sizeof(lpdi
->szText
) - 1);
1059 lpdi
->lpszText
= tt_text
;
1064 # ifdef FEAT_GUI_TABLINE
1066 if (gui_mch_showing_tabline()
1067 && ((LPNMHDR
)lParam
)->hwndFrom
== s_tabhwnd
)
1068 send_tabline_event(TabCtrl_GetCurSel(s_tabhwnd
) + 1);
1072 if (gui_mch_showing_tabline()
1073 && ((LPNMHDR
)lParam
)->hwndFrom
== s_tabhwnd
)
1074 show_tabline_popup_menu();
1078 # ifdef FEAT_GUI_TABLINE
1079 if (gui_mch_showing_tabline()
1080 && ((LPNMHDR
)lParam
)->hwndFrom
== s_tabhwnd
)
1081 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1087 #if defined(MENUHINTS) && defined(FEAT_MENU)
1089 if (((UINT
) HIWORD(wParam
)
1090 & (0xffff ^ (MF_MOUSESELECT
+ MF_BITMAP
+ MF_POPUP
)))
1092 && (State
& CMDLINE
) == 0)
1096 static int did_menu_tip
= FALSE
;
1103 did_menu_tip
= FALSE
;
1106 idButton
= (UINT
)LOWORD(wParam
);
1107 pMenu
= gui_mswin_find_menu(root_menu
, idButton
);
1108 if (pMenu
!= NULL
&& pMenu
->strings
[MENU_INDEX_TIP
] != 0
1109 && GetMenuState(s_menuBar
, pMenu
->id
, MF_BYCOMMAND
) != -1)
1112 msg(pMenu
->strings
[MENU_INDEX_TIP
]);
1116 did_menu_tip
= TRUE
;
1125 int xPos
= GET_X_LPARAM(lParam
);
1127 result
= MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1128 if (result
== HTCLIENT
)
1130 #ifdef FEAT_GUI_TABLINE
1131 if (gui_mch_showing_tabline())
1133 int yPos
= GET_Y_LPARAM(lParam
);
1136 /* If the cursor is on the GUI tabline, don't process this
1138 GetWindowRect(s_textArea
, &rct
);
1143 gui_mch_get_winpos(&x
, &y
);
1146 if (xPos
< 48) /* <VN> TODO should use system metric? */
1147 return HTBOTTOMLEFT
;
1149 return HTBOTTOMRIGHT
;
1154 /* break; notreached */
1156 #ifdef FEAT_MBYTE_IME
1158 if (!_OnImeNotify(hwnd
, (DWORD
)wParam
, (DWORD
)lParam
))
1159 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1161 case WM_IME_COMPOSITION
:
1162 if (!_OnImeComposition(hwnd
, wParam
, lParam
))
1163 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1168 if (uMsg
== msh_msgmousewheel
&& msh_msgmousewheel
!= 0)
1169 { /* handle MSH_MOUSEWHEEL messages for Intellimouse */
1170 _OnMouseWheel(hwnd
, HIWORD(wParam
));
1173 #ifdef MSWIN_FIND_REPLACE
1174 else if (uMsg
== s_findrep_msg
&& s_findrep_msg
!= 0)
1179 return MyWindowProc(hwnd
, uMsg
, wParam
, lParam
);
1186 * End of call-back routines
1189 /* parent window, if specified with -P */
1190 HWND vim_parent_hwnd
= NULL
;
1192 static BOOL CALLBACK
1193 FindWindowTitle(HWND hwnd
, LPARAM lParam
)
1196 char *title
= (char *)lParam
;
1198 if (GetWindowText(hwnd
, buf
, sizeof(buf
)))
1200 if (strstr(buf
, title
) != NULL
)
1202 /* Found it. Store the window ref. and quit searching if MDI
1204 vim_parent_hwnd
= FindWindowEx(hwnd
, NULL
, "MDIClient", NULL
);
1205 if (vim_parent_hwnd
!= NULL
)
1209 return TRUE
; /* continue searching */
1213 * Invoked for '-P "title"' argument: search for parent application to open
1217 gui_mch_set_parent(char *title
)
1219 EnumWindows(FindWindowTitle
, (LPARAM
)title
);
1220 if (vim_parent_hwnd
== NULL
)
1222 EMSG2(_("E671: Cannot find window title \"%s\""), title
);
1229 ole_error(char *arg
)
1233 /* Can't use EMSG() here, we have not finished initialisation yet. */
1234 vim_snprintf(buf
, IOSIZE
,
1235 _("E243: Argument not supported: \"-%s\"; Use the OLE version."),
1242 * Parse the GUI related command-line arguments. Any arguments used are
1243 * deleted from argv, and *argc is decremented accordingly. This is called
1244 * when vim is started, whether or not the GUI has been started.
1247 gui_mch_prepare(int *argc
, char **argv
)
1252 /* Check for special OLE command line parameters */
1253 if ((*argc
== 2 || *argc
== 3) && (argv
[1][0] == '-' || argv
[1][0] == '/'))
1255 /* Check for a "-silent" argument first. */
1256 if (*argc
== 3 && STRICMP(argv
[1] + 1, "silent") == 0
1257 && (argv
[2][0] == '-' || argv
[2][0] == '/'))
1265 /* Register Vim as an OLE Automation server */
1266 if (STRICMP(argv
[idx
] + 1, "register") == 0)
1273 ole_error("register");
1278 /* Unregister Vim as an OLE Automation server */
1279 if (STRICMP(argv
[idx
] + 1, "unregister") == 0)
1282 UnregisterMe(!silent
);
1286 ole_error("unregister");
1291 /* Ignore an -embedding argument. It is only relevant if the
1292 * application wants to treat the case when it is started manually
1293 * differently from the case where it is started via automation (and
1296 if (STRICMP(argv
[idx
] + 1, "embedding") == 0)
1301 ole_error("embedding");
1309 int bDoRestart
= FALSE
;
1311 InitOLE(&bDoRestart
);
1312 /* automatically exit after registering */
1318 #ifdef FEAT_NETBEANS_INTG
1320 /* stolen from gui_x11.x */
1323 for (arg
= 1; arg
< *argc
; arg
++)
1324 if (strncmp("-nb", argv
[arg
], 3) == 0)
1327 netbeansArg
= argv
[arg
];
1328 mch_memmove(&argv
[arg
], &argv
[arg
+ 1],
1329 (--*argc
- arg
) * sizeof(char *));
1331 break; /* enough? */
1339 wsaerr
= WSAStartup(MAKEWORD(2, 2), &wsaData
);
1341 WSInitialized
= TRUE
;
1346 /* get the OS version info */
1347 os_version
.dwOSVersionInfoSize
= sizeof(os_version
);
1348 GetVersionEx(&os_version
); /* this call works on Win32s, Win95 and WinNT */
1350 /* try and load the user32.dll library and get the entry points for
1351 * multi-monitor-support. */
1352 if ((user32_lib
= LoadLibrary("User32.dll")) != NULL
)
1354 pMonitorFromWindow
= (TMonitorFromWindow
)GetProcAddress(user32_lib
,
1355 "MonitorFromWindow");
1357 /* there are ...A and ...W version of GetMonitorInfo - looking at
1358 * winuser.h, they have exactly the same declaration. */
1359 pGetMonitorInfo
= (TGetMonitorInfo
)GetProcAddress(user32_lib
,
1365 * Initialise the GUI. Create all the windows, set up all the call-backs
1371 const char szVimWndClass
[] = VIM_CLASS
;
1372 const char szTextAreaClass
[] = "VimTextArea";
1375 const WCHAR szVimWndClassW
[] = VIM_CLASSW
;
1376 const WCHAR szTextAreaClassW
[] = L
"VimTextArea";
1377 WNDCLASSW wndclassw
;
1383 /* Return here if the window was already opened (happens when
1384 * gui_mch_dialog() is called early). */
1389 * Load the tearoff bitmap
1392 s_htearbitmap
= LoadBitmap(s_hinst
, "IDB_TEAROFF");
1395 gui
.scrollbar_width
= GetSystemMetrics(SM_CXVSCROLL
);
1396 gui
.scrollbar_height
= GetSystemMetrics(SM_CYHSCROLL
);
1398 gui
.menu_height
= 0; /* Windows takes care of this */
1400 gui
.border_width
= 0;
1402 s_brush
= CreateSolidBrush(GetSysColor(COLOR_BTNFACE
));
1405 /* First try using the wide version, so that we can use any title.
1406 * Otherwise only characters in the active codepage will work. */
1407 if (GetClassInfoW(s_hinst
, szVimWndClassW
, &wndclassw
) == 0)
1409 wndclassw
.style
= CS_DBLCLKS
;
1410 wndclassw
.lpfnWndProc
= _WndProc
;
1411 wndclassw
.cbClsExtra
= 0;
1412 wndclassw
.cbWndExtra
= 0;
1413 wndclassw
.hInstance
= s_hinst
;
1414 wndclassw
.hIcon
= LoadIcon(wndclassw
.hInstance
, "IDR_VIM");
1415 wndclassw
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1416 wndclassw
.hbrBackground
= s_brush
;
1417 wndclassw
.lpszMenuName
= NULL
;
1418 wndclassw
.lpszClassName
= szVimWndClassW
;
1424 RegisterClassW(&wndclassw
)) == 0)
1426 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED
)
1429 /* Must be Windows 98, fall back to non-wide function. */
1432 wide_WindowProc
= TRUE
;
1435 if (!wide_WindowProc
)
1438 if (GetClassInfo(s_hinst
, szVimWndClass
, &wndclass
) == 0)
1440 wndclass
.style
= CS_DBLCLKS
;
1441 wndclass
.lpfnWndProc
= _WndProc
;
1442 wndclass
.cbClsExtra
= 0;
1443 wndclass
.cbWndExtra
= 0;
1444 wndclass
.hInstance
= s_hinst
;
1445 wndclass
.hIcon
= LoadIcon(wndclass
.hInstance
, "IDR_VIM");
1446 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1447 wndclass
.hbrBackground
= s_brush
;
1448 wndclass
.lpszMenuName
= NULL
;
1449 wndclass
.lpszClassName
= szVimWndClass
;
1455 RegisterClass(&wndclass
)) == 0)
1459 if (vim_parent_hwnd
!= NULL
)
1461 #ifdef HAVE_TRY_EXCEPT
1465 /* Open inside the specified parent window.
1466 * TODO: last argument should point to a CLIENTCREATESTRUCT
1468 s_hwnd
= CreateWindowEx(
1470 szVimWndClass
, "Vim MSWindows GUI",
1471 WS_OVERLAPPEDWINDOW
| WS_CHILD
| WS_CLIPSIBLINGS
| 0xC000,
1472 gui_win_x
== -1 ? CW_USEDEFAULT
: gui_win_x
,
1473 gui_win_y
== -1 ? CW_USEDEFAULT
: gui_win_y
,
1474 100, /* Any value will do */
1475 100, /* Any value will do */
1476 vim_parent_hwnd
, NULL
,
1478 #ifdef HAVE_TRY_EXCEPT
1480 __except(EXCEPTION_EXECUTE_HANDLER
)
1487 EMSG(_("E672: Unable to open window inside MDI application"));
1493 /* If the provided windowid is not valid reset it to zero, so that it
1494 * is ignored and we open our own window. */
1495 if (IsWindow((HWND
)win_socket_id
) <= 0)
1498 /* Create a window. If win_socket_id is not zero without border and
1499 * titlebar, it will be reparented below. */
1500 s_hwnd
= CreateWindow(
1501 szVimWndClass
, "Vim MSWindows GUI",
1502 win_socket_id
== 0 ? WS_OVERLAPPEDWINDOW
: WS_POPUP
,
1503 gui_win_x
== -1 ? CW_USEDEFAULT
: gui_win_x
,
1504 gui_win_y
== -1 ? CW_USEDEFAULT
: gui_win_y
,
1505 100, /* Any value will do */
1506 100, /* Any value will do */
1509 if (s_hwnd
!= NULL
&& win_socket_id
!= 0)
1511 SetParent(s_hwnd
, (HWND
)win_socket_id
);
1512 ShowWindow(s_hwnd
, SW_SHOWMAXIMIZED
);
1519 w32_set_transparency(s_hwnd
, 255);
1522 global_ime_init(atom
, s_hwnd
);
1524 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
1528 /* Create the text area window */
1530 if (wide_WindowProc
)
1532 if (GetClassInfoW(s_hinst
, szTextAreaClassW
, &wndclassw
) == 0)
1534 wndclassw
.style
= CS_OWNDC
;
1535 wndclassw
.lpfnWndProc
= _TextAreaWndProc
;
1536 wndclassw
.cbClsExtra
= 0;
1537 wndclassw
.cbWndExtra
= 0;
1538 wndclassw
.hInstance
= s_hinst
;
1539 wndclassw
.hIcon
= NULL
;
1540 wndclassw
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1541 wndclassw
.hbrBackground
= NULL
;
1542 wndclassw
.lpszMenuName
= NULL
;
1543 wndclassw
.lpszClassName
= szTextAreaClassW
;
1545 if (RegisterClassW(&wndclassw
) == 0)
1551 if (GetClassInfo(s_hinst
, szTextAreaClass
, &wndclass
) == 0)
1553 wndclass
.style
= CS_OWNDC
;
1554 wndclass
.lpfnWndProc
= _TextAreaWndProc
;
1555 wndclass
.cbClsExtra
= 0;
1556 wndclass
.cbWndExtra
= 0;
1557 wndclass
.hInstance
= s_hinst
;
1558 wndclass
.hIcon
= NULL
;
1559 wndclass
.hCursor
= LoadCursor(NULL
, IDC_ARROW
);
1560 wndclass
.hbrBackground
= NULL
;
1561 wndclass
.lpszMenuName
= NULL
;
1562 wndclass
.lpszClassName
= szTextAreaClass
;
1564 if (RegisterClass(&wndclass
) == 0)
1567 s_textArea
= CreateWindowEx(
1569 szTextAreaClass
, "Vim text area",
1570 WS_CHILD
| WS_VISIBLE
, 0, 0,
1571 100, /* Any value will do for now */
1572 100, /* Any value will do for now */
1576 if (s_textArea
== NULL
)
1580 s_menuBar
= CreateMenu();
1582 s_hdc
= GetDC(s_textArea
);
1584 #ifdef MSWIN16_FASTTEXT
1585 SetBkMode(s_hdc
, OPAQUE
);
1589 DragAcceptFiles(s_hwnd
, TRUE
);
1592 /* Do we need to bother with this? */
1593 /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
1595 /* Get background/foreground colors from the system */
1596 gui_mch_def_colors();
1598 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
1600 set_normal_colors();
1603 * Check that none of the colors are the same as the background color.
1604 * Then store the current values as the defaults.
1607 gui
.def_norm_pixel
= gui
.norm_pixel
;
1608 gui
.def_back_pixel
= gui
.back_pixel
;
1610 /* Get the colors for the highlight groups (gui_check_colors() might have
1612 highlight_gui_started();
1615 * Start out by adding the configured border width into the border offset
1617 gui
.border_offset
= gui
.border_width
+ 2; /*CLIENT EDGE*/
1620 * Set up for Intellimouse processing
1625 * compute a couple of metrics used for the dialogs
1627 get_dialog_font_metrics();
1630 * Create the toolbar
1632 initialise_toolbar();
1634 #ifdef FEAT_GUI_TABLINE
1636 * Create the tabline
1638 initialise_tabline();
1640 #ifdef MSWIN_FIND_REPLACE
1642 * Initialise the dialog box stuff
1644 s_findrep_msg
= RegisterWindowMessage(FINDMSGSTRING
);
1646 /* Initialise the struct */
1647 s_findrep_struct
.lStructSize
= sizeof(s_findrep_struct
);
1648 s_findrep_struct
.lpstrFindWhat
= alloc(MSWIN_FR_BUFSIZE
);
1649 s_findrep_struct
.lpstrFindWhat
[0] = NUL
;
1650 s_findrep_struct
.lpstrReplaceWith
= alloc(MSWIN_FR_BUFSIZE
);
1651 s_findrep_struct
.lpstrReplaceWith
[0] = NUL
;
1652 s_findrep_struct
.wFindWhatLen
= MSWIN_FR_BUFSIZE
;
1653 s_findrep_struct
.wReplaceWithLen
= MSWIN_FR_BUFSIZE
;
1654 # if defined(FEAT_MBYTE) && defined(WIN3264)
1655 s_findrep_struct_w
.lStructSize
= sizeof(s_findrep_struct_w
);
1656 s_findrep_struct_w
.lpstrFindWhat
=
1657 (LPWSTR
)alloc(MSWIN_FR_BUFSIZE
* sizeof(WCHAR
));
1658 s_findrep_struct_w
.lpstrFindWhat
[0] = NUL
;
1659 s_findrep_struct_w
.lpstrReplaceWith
=
1660 (LPWSTR
)alloc(MSWIN_FR_BUFSIZE
* sizeof(WCHAR
));
1661 s_findrep_struct_w
.lpstrReplaceWith
[0] = NUL
;
1662 s_findrep_struct_w
.wFindWhatLen
= MSWIN_FR_BUFSIZE
;
1663 s_findrep_struct_w
.wReplaceWithLen
= MSWIN_FR_BUFSIZE
;
1668 /* Display any pending error messages */
1675 * Get the size of the screen, taking position on multiple monitors into
1676 * account (if supported).
1679 get_work_area(RECT
*spi_rect
)
1682 _MONITORINFO moninfo
;
1684 /* use these functions only if available */
1685 if (pMonitorFromWindow
!= NULL
&& pGetMonitorInfo
!= NULL
)
1687 /* work out which monitor the window is on, and get *it's* work area */
1688 mon
= pMonitorFromWindow(s_hwnd
, 1 /*MONITOR_DEFAULTTOPRIMARY*/);
1691 moninfo
.cbSize
= sizeof(_MONITORINFO
);
1692 if (pGetMonitorInfo(mon
, &moninfo
))
1694 *spi_rect
= moninfo
.rcWork
;
1699 /* this is the old method... */
1700 SystemParametersInfo(SPI_GETWORKAREA
, 0, spi_rect
, 0);
1704 * Set the size of the window to the given width and height in pixels.
1708 gui_mch_set_shellsize(int width
, int height
,
1709 int min_width
, int min_height
, int base_width
, int base_height
,
1713 int win_width
, win_height
;
1714 int win_xpos
, win_ypos
;
1715 WINDOWPLACEMENT wndpl
;
1718 /* Try to keep window completely on screen. */
1719 /* Get position of the screen work area. This is the part that is not
1720 * used by the taskbar or appbars. */
1721 get_work_area(&workarea_rect
);
1723 /* Get current posision of our window. Note that the .left and .top are
1724 * relative to the work area. */
1725 wndpl
.length
= sizeof(WINDOWPLACEMENT
);
1726 GetWindowPlacement(s_hwnd
, &wndpl
);
1728 /* Resizing a maximized window looks very strange, unzoom it first.
1729 * But don't do it when still starting up, it may have been requested in
1731 if (wndpl
.showCmd
== SW_SHOWMAXIMIZED
&& starting
== 0)
1733 ShowWindow(s_hwnd
, SW_SHOWNORMAL
);
1734 /* Need to get the settings of the normal window. */
1735 GetWindowPlacement(s_hwnd
, &wndpl
);
1738 win_xpos
= wndpl
.rcNormalPosition
.left
;
1739 win_ypos
= wndpl
.rcNormalPosition
.top
;
1741 /* compute the size of the outside of the window */
1742 win_width
= width
+ GetSystemMetrics(SM_CXFRAME
) * 2;
1743 win_height
= height
+ GetSystemMetrics(SM_CYFRAME
) * 2
1744 + get_caption_height()
1746 + gui_mswin_get_menu_height(FALSE
)
1750 /* There is an inconsistency when using two monitors and Vim is on the
1751 * second (right) one: win_xpos will be the offset from the workarea of
1752 * the left monitor. While with one monitor it's the offset from the
1753 * workarea (including a possible taskbar on the left). Detect the second
1754 * monitor by checking for the left offset to be quite big. */
1755 if (workarea_rect
.left
> 300)
1758 workarea_left
= workarea_rect
.left
;
1760 /* If the window is going off the screen, move it on to the screen.
1761 * win_xpos and win_ypos are relative to the workarea. */
1762 if ((direction
& RESIZE_HOR
)
1763 && workarea_left
+ win_xpos
+ win_width
> workarea_rect
.right
)
1764 win_xpos
= workarea_rect
.right
- win_width
- workarea_left
;
1766 if ((direction
& RESIZE_HOR
) && win_xpos
< 0)
1769 if ((direction
& RESIZE_VERT
)
1770 && workarea_rect
.top
+ win_ypos
+ win_height
> workarea_rect
.bottom
)
1771 win_ypos
= workarea_rect
.bottom
- win_height
- workarea_rect
.top
;
1773 if ((direction
& RESIZE_VERT
) && win_ypos
< 0)
1776 wndpl
.rcNormalPosition
.left
= win_xpos
;
1777 wndpl
.rcNormalPosition
.right
= win_xpos
+ win_width
;
1778 wndpl
.rcNormalPosition
.top
= win_ypos
;
1779 wndpl
.rcNormalPosition
.bottom
= win_ypos
+ win_height
;
1781 /* set window position - we should use SetWindowPlacement rather than
1782 * SetWindowPos as the MSDN docs say the coord systems returned by
1783 * these two are not compatible. */
1784 SetWindowPlacement(s_hwnd
, &wndpl
);
1786 SetActiveWindow(s_hwnd
);
1790 /* Menu may wrap differently now */
1791 gui_mswin_get_menu_height(!gui
.starting
);
1797 gui_mch_set_scrollbar_thumb(
1805 sb
->scroll_shift
= 0;
1808 max
= (max
+ 1) >> 1;
1814 if (sb
->scroll_shift
> 0)
1817 info
.cbSize
= sizeof(info
);
1818 info
.fMask
= SIF_POS
| SIF_RANGE
| SIF_PAGE
;
1823 SetScrollInfo(sb
->id
, SB_CTL
, &info
, TRUE
);
1828 * Set the current text font.
1831 gui_mch_set_font(GuiFont font
)
1833 gui
.currFont
= font
;
1838 * Set the current text foreground color.
1841 gui_mch_set_fg_color(guicolor_T color
)
1843 gui
.currFgColor
= color
;
1847 * Set the current text background color.
1850 gui_mch_set_bg_color(guicolor_T color
)
1852 gui
.currBgColor
= color
;
1856 * Set the current text special color.
1859 gui_mch_set_sp_color(guicolor_T color
)
1861 gui
.currSpColor
= color
;
1864 #if USE_LAYERED_WINDOW
1866 w32_set_transparency(HWND hwnd
, BYTE bAlpha
)
1874 /* Turn off transpareny */
1877 SetWindowLong(hwnd
, GWL_EXSTYLE
, ~WS_EX_LAYERED
&
1878 GetWindowLong(hwnd
, GWL_EXSTYLE
));
1882 /* Obtain pointer to function set transparecy rate */
1883 if (!(hDll
= LoadLibrary("user32.dll")))
1885 pfLayer
= (FWINLAYER
)GetProcAddress(hDll
, "SetLayeredWindowAttributes");
1889 SetWindowLong(hwnd
, GWL_EXSTYLE
, WS_EX_LAYERED
|
1890 GetWindowLong(hwnd
, GWL_EXSTYLE
));
1891 pfLayer(hwnd
, 0, bAlpha
, LWA_ALPHA
);
1898 gui_mch_set_transparency(int alpha
)
1900 w32_set_transparency(NULL
, (BYTE
)alpha
);
1902 #endif /* USE_LAYERED_WINDOW */
1904 #if defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)
1906 * Multi-byte handling, originally by Sung-Hoon Baek.
1907 * First static functions (no prototypes generated).
1910 # include <ime.h> /* Apparently not needed for Cygwin, MingW or Borland. */
1915 * handle WM_IME_NOTIFY message
1919 _OnImeNotify(HWND hWnd
, DWORD dwCommand
, DWORD dwData
)
1921 LRESULT lResult
= 0;
1924 if (!pImmGetContext
|| (hImc
= pImmGetContext(hWnd
)) == (HIMC
)0)
1928 case IMN_SETOPENSTATUS
:
1929 if (pImmGetOpenStatus(hImc
))
1931 pImmSetCompositionFont(hImc
, &norm_logfont
);
1932 im_set_position(gui
.row
, gui
.col
);
1934 /* Disable langmap */
1938 #if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
1939 /* Unshown 'keymap' in status lines */
1940 if (curbuf
->b_p_iminsert
== B_IMODE_LMAP
)
1942 /* Save cursor position */
1943 int old_row
= gui
.row
;
1944 int old_col
= gui
.col
;
1946 // This must be called here before
1947 // status_redraw_curbuf(), otherwise the mode
1948 // message may appear in the wrong position.
1950 status_redraw_curbuf();
1952 /* Restore cursor position */
1959 gui_update_cursor(TRUE
, FALSE
);
1963 pImmReleaseContext(hWnd
, hImc
);
1969 _OnImeComposition(HWND hwnd
, WPARAM dbcs
, LPARAM param
)
1974 if ((param
& GCS_RESULTSTR
) == 0) /* Composition unfinished. */
1977 ret
= GetResultStr(hwnd
, GCS_RESULTSTR
, &len
);
1980 add_to_input_buf_csi(ret
, len
);
1988 * get the current composition string, in UCS-2; *lenp is the number of
1989 * *lenp is the number of Unicode characters.
1992 GetCompositionString_inUCS2(HIMC hIMC
, DWORD GCS
, int *lenp
)
1998 if (!pImmGetContext
)
1999 return NULL
; /* no imm32.dll */
2001 /* Try Unicode; this'll always work on NT regardless of codepage. */
2002 ret
= pImmGetCompositionStringW(hIMC
, GCS
, NULL
, 0);
2004 return NULL
; /* empty */
2008 /* Allocate the requested buffer plus space for the NUL character. */
2009 wbuf
= (LPWSTR
)alloc(ret
+ sizeof(WCHAR
));
2012 pImmGetCompositionStringW(hIMC
, GCS
, wbuf
, ret
);
2013 *lenp
= ret
/ sizeof(WCHAR
);
2015 return (short_u
*)wbuf
;
2018 /* ret < 0; we got an error, so try the ANSI version. This'll work
2019 * on 9x/ME, but only if the codepage happens to be set to whatever
2020 * we're inputting. */
2021 ret
= pImmGetCompositionStringA(hIMC
, GCS
, NULL
, 0);
2023 return NULL
; /* empty or error */
2028 pImmGetCompositionStringA(hIMC
, GCS
, buf
, ret
);
2030 /* convert from codepage to UCS-2 */
2031 MultiByteToWideChar_alloc(GetACP(), 0, buf
, ret
, &wbuf
, lenp
);
2034 return (short_u
*)wbuf
;
2038 * void GetResultStr()
2040 * This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
2041 * get complete composition string
2044 GetResultStr(HWND hwnd
, int GCS
, int *lenp
)
2046 HIMC hIMC
; /* Input context handle. */
2047 short_u
*buf
= NULL
;
2048 char_u
*convbuf
= NULL
;
2050 if (!pImmGetContext
|| (hIMC
= pImmGetContext(hwnd
)) == (HIMC
)0)
2053 /* Reads in the composition string. */
2054 buf
= GetCompositionString_inUCS2(hIMC
, GCS
, lenp
);
2058 convbuf
= utf16_to_enc(buf
, lenp
);
2059 pImmReleaseContext(hwnd
, hIMC
);
2065 /* For global functions we need prototypes. */
2066 #if (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) || defined(PROTO)
2072 im_set_font(LOGFONT
*lf
)
2076 if (pImmGetContext
&& (hImc
= pImmGetContext(s_hwnd
)) != (HIMC
)0)
2078 pImmSetCompositionFont(hImc
, lf
);
2079 pImmReleaseContext(s_hwnd
, hImc
);
2084 * Notify cursor position to IM.
2087 im_set_position(int row
, int col
)
2091 if (pImmGetContext
&& (hImc
= pImmGetContext(s_hwnd
)) != (HIMC
)0)
2093 COMPOSITIONFORM cfs
;
2095 cfs
.dwStyle
= CFS_POINT
;
2096 cfs
.ptCurrentPos
.x
= FILL_X(col
);
2097 cfs
.ptCurrentPos
.y
= FILL_Y(row
);
2098 MapWindowPoints(s_textArea
, s_hwnd
, &cfs
.ptCurrentPos
, 1);
2099 pImmSetCompositionWindow(hImc
, &cfs
);
2101 pImmReleaseContext(s_hwnd
, hImc
);
2106 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
2109 im_set_active(int active
)
2112 static HIMC hImcOld
= (HIMC
)0;
2114 if (pImmGetContext
) /* if NULL imm32.dll wasn't loaded (yet) */
2118 if (hImcOld
== (HIMC
)0)
2120 hImcOld
= pImmGetContext(s_hwnd
);
2122 pImmAssociateContext(s_hwnd
, (HIMC
)0);
2126 else if (hImcOld
!= (HIMC
)0)
2128 pImmAssociateContext(s_hwnd
, hImcOld
);
2132 hImc
= pImmGetContext(s_hwnd
);
2138 HKL hKL
= GetKeyboardLayout(0);
2140 if (LOWORD(hKL
) == MAKELANGID(LANG_KOREAN
, SUBLANG_KOREAN
))
2142 static DWORD dwConversionSaved
= 0, dwSentenceSaved
= 0;
2143 static BOOL bSaved
= FALSE
;
2147 /* if we have a saved conversion status, restore it */
2149 pImmSetConversionStatus(hImc
, dwConversionSaved
,
2155 /* save conversion status and disable korean */
2156 if (pImmGetConversionStatus(hImc
, &dwConversionSaved
,
2160 pImmSetConversionStatus(hImc
,
2161 dwConversionSaved
& ~(IME_CMODE_NATIVE
2162 | IME_CMODE_FULLSHAPE
),
2168 pImmSetOpenStatus(hImc
, active
);
2169 pImmReleaseContext(s_hwnd
, hImc
);
2175 * Get IM status. When IM is on, return not 0. Else return 0.
2183 if (pImmGetContext
&& (hImc
= pImmGetContext(s_hwnd
)) != (HIMC
)0)
2185 status
= pImmGetOpenStatus(hImc
) ? 1 : 0;
2186 pImmReleaseContext(s_hwnd
, hImc
);
2191 #endif /* FEAT_MBYTE && FEAT_MBYTE_IME */
2193 #if defined(FEAT_MBYTE) && !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
2194 /* Win32 with GLOBAL IME */
2197 * Notify cursor position to IM.
2200 im_set_position(int row
, int col
)
2202 /* Win32 with GLOBAL IME */
2207 MapWindowPoints(s_textArea
, s_hwnd
, &p
, 1);
2208 global_ime_set_position(&p
);
2212 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
2215 im_set_active(int active
)
2217 global_ime_set_status(active
);
2221 * Get IM status. When IM is on, return not 0. Else return 0.
2226 return global_ime_get_status();
2232 * Convert latin9 text "text[len]" to ucs-2 in "unicodebuf".
2235 latin9_to_ucs(char_u
*text
, int len
, WCHAR
*unicodebuf
)
2244 case 0xa4: c
= 0x20ac; break; /* euro */
2245 case 0xa6: c
= 0x0160; break; /* S hat */
2246 case 0xa8: c
= 0x0161; break; /* S -hat */
2247 case 0xb4: c
= 0x017d; break; /* Z hat */
2248 case 0xb8: c
= 0x017e; break; /* Z -hat */
2249 case 0xbc: c
= 0x0152; break; /* OE */
2250 case 0xbd: c
= 0x0153; break; /* oe */
2251 case 0xbe: c
= 0x0178; break; /* Y */
2258 #ifdef FEAT_RIGHTLEFT
2260 * What is this for? In the case where you are using Win98 or Win2K or later,
2261 * and you are using a Hebrew font (or Arabic!), Windows does you a favor and
2262 * reverses the string sent to the TextOut... family. This sucks, because we
2263 * go to a lot of effort to do the right thing, and there doesn't seem to be a
2264 * way to tell Windblows not to do this!
2266 * The short of it is that this 'RevOut' only gets called if you are running
2267 * one of the new, "improved" MS OSes, and only if you are running in
2268 * 'rightleft' mode. It makes display take *slightly* longer, but not
2276 CONST RECT
*pcliprect
,
2282 static int special
= -1;
2286 /* Check windows version: special treatment is needed if it is NT 5 or
2287 * Win98 or higher. */
2288 if ((os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
2289 && os_version
.dwMajorVersion
>= 5)
2290 || (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_WINDOWS
2291 && (os_version
.dwMajorVersion
> 4
2292 || (os_version
.dwMajorVersion
== 4
2293 && os_version
.dwMinorVersion
> 0))))
2300 for (ix
= 0; ix
< (int)len
; ++ix
)
2301 ExtTextOut(s_hdc
, col
+ TEXT_X(ix
), row
, foptions
,
2302 pcliprect
, text
+ ix
, 1, padding
);
2304 ExtTextOut(s_hdc
, col
, row
, foptions
, pcliprect
, text
, len
, padding
);
2309 gui_mch_draw_string(
2316 static int *padding
= NULL
;
2317 static int pad_size
= 0;
2319 const RECT
*pcliprect
= NULL
;
2322 static WCHAR
*unicodebuf
= NULL
;
2323 static int *unicodepdy
= NULL
;
2324 static int unibuflen
= 0;
2330 #ifndef MSWIN16_FASTTEXT
2332 * Italic and bold text seems to have an extra row of pixels at the bottom
2333 * (below where the bottom of the character should be). If we draw the
2334 * characters with a solid background, the top row of pixels in the
2335 * character below will be overwritten. We can fix this by filling in the
2336 * background ourselves, to the correct character proportions, and then
2337 * writing the character in transparent mode. Still have a problem when
2338 * the character is "_", which gets written on to the character below.
2339 * New fix: set gui.char_ascent to -1. This shifts all characters up one
2340 * pixel in their slots, which fixes the problem with the bottom row of
2341 * pixels. We still need this code because otherwise the top row of pixels
2342 * becomes a problem. - webb.
2344 static HBRUSH hbr_cache
[2] = {NULL
, NULL
};
2345 static guicolor_T brush_color
[2] = {INVALCOLOR
, INVALCOLOR
};
2346 static int brush_lru
= 0;
2350 if (!(flags
& DRAW_TRANSP
))
2353 * Clear background first.
2354 * Note: FillRect() excludes right and bottom of rectangle.
2356 rc
.left
= FILL_X(col
);
2357 rc
.top
= FILL_Y(row
);
2363 /* Compute the length in display cells. */
2364 for (n
= 0; n
< len
; n
+= MB_BYTE2LEN(text
[n
]))
2365 cell_len
+= (*mb_ptr2cells
)(text
+ n
);
2366 rc
.right
= FILL_X(col
+ cell_len
);
2370 rc
.right
= FILL_X(col
+ len
);
2371 rc
.bottom
= FILL_Y(row
+ 1);
2373 /* Cache the created brush, that saves a lot of time. We need two:
2374 * one for cursor background and one for the normal background. */
2375 if (gui
.currBgColor
== brush_color
[0])
2380 else if (gui
.currBgColor
== brush_color
[1])
2387 if (hbr_cache
[brush_lru
] != NULL
)
2388 DeleteBrush(hbr_cache
[brush_lru
]);
2389 hbr_cache
[brush_lru
] = CreateSolidBrush(gui
.currBgColor
);
2390 brush_color
[brush_lru
] = gui
.currBgColor
;
2391 hbr
= hbr_cache
[brush_lru
];
2392 brush_lru
= !brush_lru
;
2394 FillRect(s_hdc
, &rc
, hbr
);
2396 SetBkMode(s_hdc
, TRANSPARENT
);
2399 * When drawing block cursor, prevent inverted character spilling
2400 * over character cell (can happen with bold/italic)
2402 if (flags
& DRAW_CURSOR
)
2405 foptions
= ETO_CLIPPED
;
2410 * The alternative would be to write the characters in opaque mode, but
2411 * when the text is not exactly the same proportions as normal text, too
2412 * big or too little a rectangle gets drawn for the background.
2414 SetBkMode(s_hdc
, OPAQUE
);
2415 SetBkColor(s_hdc
, gui
.currBgColor
);
2417 SetTextColor(s_hdc
, gui
.currFgColor
);
2418 SelectFont(s_hdc
, gui
.currFont
);
2420 if (pad_size
!= Columns
|| padding
== NULL
|| padding
[0] != gui
.char_width
)
2425 /* Don't give an out-of-memory message here, it would call us
2427 padding
= (int *)lalloc(pad_size
* sizeof(int), FALSE
);
2428 if (padding
!= NULL
)
2429 for (i
= 0; i
< pad_size
; i
++)
2430 padding
[i
] = gui
.char_width
;
2433 /* On NT, tell the font renderer not to "help" us with Hebrew and Arabic
2434 * text. This doesn't work in 9x, so we have to deal with it manually on
2436 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
2437 foptions
|= ETO_IGNORELANGUAGE
;
2440 * We have to provide the padding argument because italic and bold versions
2441 * of fixed-width fonts are often one pixel or so wider than their normal
2443 * No check for DRAW_BOLD, Windows will have done it already.
2447 /* Check if there are any UTF-8 characters. If not, use normal text
2448 * output to speed up output. */
2450 for (n
= 0; n
< len
; ++n
)
2451 if (text
[n
] >= 0x80)
2454 /* Check if the Unicode buffer exists and is big enough. Create it
2455 * with the same length as the multi-byte string, the number of wide
2456 * characters is always equal or smaller. */
2458 || (enc_codepage
> 0 && (int)GetACP() != enc_codepage
)
2460 && (unicodebuf
== NULL
|| len
> unibuflen
))
2462 vim_free(unicodebuf
);
2463 unicodebuf
= (WCHAR
*)lalloc(len
* sizeof(WCHAR
), FALSE
);
2465 vim_free(unicodepdy
);
2466 unicodepdy
= (int *)lalloc(len
* sizeof(int), FALSE
);
2471 if (enc_utf8
&& n
< len
&& unicodebuf
!= NULL
)
2473 /* Output UTF-8 characters. Caller has already separated
2474 * composing characters. */
2476 int wlen
; /* string length in words */
2477 int clen
; /* string length in characters */
2478 int cells
; /* cell width of string up to composing char */
2479 int cw
; /* width of current cell */
2485 for (i
= 0; i
< len
; )
2487 c
= utf_ptr2char(text
+ i
);
2490 /* Turn into UTF-16 encoding. */
2491 unicodebuf
[wlen
++] = ((c
- 0x10000) >> 10) + 0xD800;
2492 unicodebuf
[wlen
++] = ((c
- 0x10000) & 0x3ff) + 0xDC00;
2496 unicodebuf
[wlen
++] = c
;
2498 cw
= utf_char2cells(c
);
2499 if (cw
> 2) /* don't use 4 for unprintable char */
2501 if (unicodepdy
!= NULL
)
2503 /* Use unicodepdy to make characters fit as we expect, even
2504 * when the font uses different widths (e.g., bold character
2506 unicodepdy
[clen
] = cw
* gui
.char_width
;
2509 i
+= utfc_ptr2len_len(text
+ i
, len
- i
);
2512 ExtTextOutW(s_hdc
, TEXT_X(col
), TEXT_Y(row
),
2513 foptions
, pcliprect
, unicodebuf
, wlen
, unicodepdy
);
2514 len
= cells
; /* used for underlining */
2516 else if ((enc_codepage
> 0 && (int)GetACP() != enc_codepage
) || enc_latin9
)
2518 /* If we want to display codepage data, and the current CP is not the
2519 * ANSI one, we need to go via Unicode. */
2520 if (unicodebuf
!= NULL
)
2523 latin9_to_ucs(text
, len
, unicodebuf
);
2525 len
= MultiByteToWideChar(enc_codepage
,
2528 (LPWSTR
)unicodebuf
, unibuflen
);
2531 /* Use unicodepdy to make characters fit as we expect, even
2532 * when the font uses different widths (e.g., bold character
2534 if (unicodepdy
!= NULL
)
2539 for (i
= 0; i
< len
; ++i
)
2541 cw
= utf_char2cells(unicodebuf
[i
]);
2544 unicodepdy
[i
] = cw
* gui
.char_width
;
2547 ExtTextOutW(s_hdc
, TEXT_X(col
), TEXT_Y(row
),
2548 foptions
, pcliprect
, unicodebuf
, len
, unicodepdy
);
2555 #ifdef FEAT_RIGHTLEFT
2556 /* If we can't use ETO_IGNORELANGUAGE, we can't tell Windows not to
2557 * mess up RL text, so we have to draw it character-by-character.
2558 * Only do this if RL is on, since it's slow. */
2559 if (curwin
->w_p_rl
&& !(foptions
& ETO_IGNORELANGUAGE
))
2560 RevOut(s_hdc
, TEXT_X(col
), TEXT_Y(row
),
2561 foptions
, pcliprect
, (char *)text
, len
, padding
);
2564 ExtTextOut(s_hdc
, TEXT_X(col
), TEXT_Y(row
),
2565 foptions
, pcliprect
, (char *)text
, len
, padding
);
2569 if (flags
& DRAW_UNDERL
)
2571 hpen
= CreatePen(PS_SOLID
, 1, gui
.currFgColor
);
2572 old_pen
= SelectObject(s_hdc
, hpen
);
2573 /* When p_linespace is 0, overwrite the bottom row of pixels.
2574 * Otherwise put the line just below the character. */
2575 y
= FILL_Y(row
+ 1) - 1;
2576 #ifndef MSWIN16_FASTTEXT
2577 if (p_linespace
> 1)
2578 y
-= p_linespace
- 1;
2580 MoveToEx(s_hdc
, FILL_X(col
), y
, NULL
);
2581 /* Note: LineTo() excludes the last pixel in the line. */
2582 LineTo(s_hdc
, FILL_X(col
+ len
), y
);
2583 DeleteObject(SelectObject(s_hdc
, old_pen
));
2587 if (flags
& DRAW_UNDERC
)
2591 static const int val
[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
2593 y
= FILL_Y(row
+ 1) - 1;
2594 for (x
= FILL_X(col
); x
< FILL_X(col
+ len
); ++x
)
2596 offset
= val
[x
% 8];
2597 SetPixel(s_hdc
, x
, y
- offset
, gui
.currSpColor
);
2607 /* Flush any output to the screen */
2611 # if defined(__BORLANDC__)
2613 * The GdiFlush declaration (in Borland C 5.01 <wingdi.h>) is not a
2614 * prototype declaration.
2615 * The compiler complains if __stdcall is not used in both declarations.
2617 BOOL __stdcall
GdiFlush(void);
2624 clear_rect(RECT
*rcp
)
2628 hbr
= CreateSolidBrush(gui
.back_pixel
);
2629 FillRect(s_hdc
, rcp
, hbr
);
2635 gui_mch_get_screen_dimensions(int *screen_w
, int *screen_h
)
2639 get_work_area(&workarea_rect
);
2641 *screen_w
= workarea_rect
.right
- workarea_rect
.left
2642 - GetSystemMetrics(SM_CXFRAME
) * 2;
2644 /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
2645 * the menubar for MSwin, we subtract it from the screen height, so that
2646 * the window size can be made to fit on the screen. */
2647 *screen_h
= workarea_rect
.bottom
- workarea_rect
.top
2648 - GetSystemMetrics(SM_CYFRAME
) * 2
2649 - get_caption_height()
2651 - gui_mswin_get_menu_height(FALSE
)
2657 #if defined(FEAT_MENU) || defined(PROTO)
2659 * Add a sub menu to the menu bar.
2666 vimmenu_T
*parent
= menu
->parent
;
2668 menu
->submenu_id
= CreatePopupMenu();
2669 menu
->id
= s_menu_id
++;
2671 if (menu_is_menubar(menu
->name
))
2675 InsertMenu((parent
== NULL
) ? s_menuBar
: parent
->submenu_id
,
2676 (UINT
)pos
, MF_POPUP
| MF_STRING
| MF_BYPOSITION
,
2677 (long_u
)menu
->submenu_id
, (LPCTSTR
) menu
->name
);
2685 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2687 /* 'encoding' differs from active codepage: convert menu name
2688 * and use wide function */
2689 wn
= enc_to_utf16(menu
->name
, NULL
);
2692 MENUITEMINFOW infow
;
2694 infow
.cbSize
= sizeof(infow
);
2695 infow
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_ID
2697 infow
.dwItemData
= (long_u
)menu
;
2698 infow
.wID
= menu
->id
;
2699 infow
.fType
= MFT_STRING
;
2700 infow
.dwTypeData
= wn
;
2701 infow
.cch
= (UINT
)wcslen(wn
);
2702 infow
.hSubMenu
= menu
->submenu_id
;
2703 n
= InsertMenuItemW((parent
== NULL
)
2704 ? s_menuBar
: parent
->submenu_id
,
2705 (UINT
)pos
, TRUE
, &infow
);
2707 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2708 /* Failed, try using non-wide function. */
2718 info
.cbSize
= sizeof(info
);
2719 info
.fMask
= MIIM_DATA
| MIIM_TYPE
| MIIM_ID
| MIIM_SUBMENU
;
2720 info
.dwItemData
= (long_u
)menu
;
2721 info
.wID
= menu
->id
;
2722 info
.fType
= MFT_STRING
;
2723 info
.dwTypeData
= (LPTSTR
)menu
->name
;
2724 info
.cch
= (UINT
)STRLEN(menu
->name
);
2725 info
.hSubMenu
= menu
->submenu_id
;
2726 InsertMenuItem((parent
== NULL
)
2727 ? s_menuBar
: parent
->submenu_id
,
2728 (UINT
)pos
, TRUE
, &info
);
2733 /* Fix window size if menu may have wrapped */
2735 gui_mswin_get_menu_height(!gui
.starting
);
2737 else if (IsWindow(parent
->tearoff_handle
))
2738 rebuild_tearoff(parent
);
2743 gui_mch_show_popupmenu(vimmenu_T
*menu
)
2747 (void)GetCursorPos((LPPOINT
)&mp
);
2748 gui_mch_show_popupmenu_at(menu
, (int)mp
.x
, (int)mp
.y
);
2752 gui_make_popup(char_u
*path_name
, int mouse_pos
)
2754 vimmenu_T
*menu
= gui_find_menu(path_name
);
2760 /* Find the position of the current cursor */
2761 GetDCOrgEx(s_hdc
, &p
);
2766 gui_mch_getmouse(&mx
, &my
);
2770 else if (curwin
!= NULL
)
2772 p
.x
+= TEXT_X(W_WINCOL(curwin
) + curwin
->w_wcol
+ 1);
2773 p
.y
+= TEXT_Y(W_WINROW(curwin
) + curwin
->w_wrow
+ 1);
2776 gui_mch_show_popupmenu_at(menu
, (int)p
.x
, (int)p
.y
);
2780 #if defined(FEAT_TEAROFF) || defined(PROTO)
2782 * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
2783 * create it as a pseudo-"tearoff menu".
2786 gui_make_tearoff(char_u
*path_name
)
2788 vimmenu_T
*menu
= gui_find_menu(path_name
);
2790 /* Found the menu, so tear it off. */
2792 gui_mch_tearoff(menu
->dname
, menu
, 0xffffL
, 0xffffL
);
2797 * Add a menu item to a menu
2800 gui_mch_add_menu_item(
2804 vimmenu_T
*parent
= menu
->parent
;
2806 menu
->id
= s_menu_id
++;
2807 menu
->submenu_id
= NULL
;
2810 if (STRNCMP(menu
->name
, TEAR_STRING
, TEAR_LEN
) == 0)
2812 InsertMenu(parent
->submenu_id
, (UINT
)idx
, MF_BITMAP
|MF_BYPOSITION
,
2813 (UINT
)menu
->id
, (LPCTSTR
) s_htearbitmap
);
2818 if (menu_is_toolbar(parent
->name
))
2822 vim_memset(&newtb
, 0, sizeof(newtb
));
2823 if (menu_is_separator(menu
->name
))
2826 newtb
.fsStyle
= TBSTYLE_SEP
;
2830 newtb
.iBitmap
= get_toolbar_bitmap(menu
);
2831 newtb
.fsStyle
= TBSTYLE_BUTTON
;
2833 newtb
.idCommand
= menu
->id
;
2834 newtb
.fsState
= TBSTATE_ENABLED
;
2836 SendMessage(s_toolbarhwnd
, TB_INSERTBUTTON
, (WPARAM
)idx
,
2838 menu
->submenu_id
= (HMENU
)-1;
2847 if (enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
2849 /* 'encoding' differs from active codepage: convert menu item name
2850 * and use wide function */
2851 wn
= enc_to_utf16(menu
->name
, NULL
);
2854 n
= InsertMenuW(parent
->submenu_id
, (UINT
)idx
,
2855 (menu_is_separator(menu
->name
)
2856 ? MF_SEPARATOR
: MF_STRING
) | MF_BYPOSITION
,
2857 (UINT
)menu
->id
, wn
);
2859 if (n
== 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED
)
2860 /* Failed, try using non-wide function. */
2866 InsertMenu(parent
->submenu_id
, (UINT
)idx
,
2867 (menu_is_separator(menu
->name
) ? MF_SEPARATOR
: MF_STRING
)
2869 (UINT
)menu
->id
, (LPCTSTR
)menu
->name
);
2871 if (IsWindow(parent
->tearoff_handle
))
2872 rebuild_tearoff(parent
);
2878 * Destroy the machine specific menu widget.
2881 gui_mch_destroy_menu(vimmenu_T
*menu
)
2885 * is this a toolbar button?
2887 if (menu
->submenu_id
== (HMENU
)-1)
2891 iButton
= (int)SendMessage(s_toolbarhwnd
, TB_COMMANDTOINDEX
,
2892 (WPARAM
)menu
->id
, 0);
2893 SendMessage(s_toolbarhwnd
, TB_DELETEBUTTON
, (WPARAM
)iButton
, 0);
2898 if (menu
->parent
!= NULL
2899 && menu_is_popup(menu
->parent
->dname
)
2900 && menu
->parent
->submenu_id
!= NULL
)
2901 RemoveMenu(menu
->parent
->submenu_id
, menu
->id
, MF_BYCOMMAND
);
2903 RemoveMenu(s_menuBar
, menu
->id
, MF_BYCOMMAND
);
2904 if (menu
->submenu_id
!= NULL
)
2905 DestroyMenu(menu
->submenu_id
);
2907 if (IsWindow(menu
->tearoff_handle
))
2908 DestroyWindow(menu
->tearoff_handle
);
2909 if (menu
->parent
!= NULL
2910 && menu
->parent
->children
!= NULL
2911 && IsWindow(menu
->parent
->tearoff_handle
))
2913 /* This menu must not show up when rebuilding the tearoff window. */
2915 rebuild_tearoff(menu
->parent
);
2923 rebuild_tearoff(vimmenu_T
*menu
)
2932 HWND thwnd
= menu
->tearoff_handle
;
2934 GetWindowText(thwnd
, tbuf
, 127);
2935 if (GetWindowRect(thwnd
, &trect
)
2936 && GetWindowRect(s_hwnd
, &rct
)
2937 && GetClientRect(s_hwnd
, &roct
))
2939 x
= trect
.left
- rct
.left
;
2940 y
= (trect
.top
- rct
.bottom
+ roct
.bottom
);
2946 DestroyWindow(thwnd
);
2947 if (menu
->children
!= NULL
)
2949 gui_mch_tearoff(tbuf
, menu
, x
, y
);
2950 if (IsWindow(menu
->tearoff_handle
))
2951 (void) SetWindowPos(menu
->tearoff_handle
,
2956 SWP_NOSIZE
| SWP_NOZORDER
| SWP_NOACTIVATE
);
2959 #endif /* FEAT_TEAROFF */
2962 * Make a menu either grey or not grey.
2971 * is this a toolbar button?
2973 if (menu
->submenu_id
== (HMENU
)-1)
2975 SendMessage(s_toolbarhwnd
, TB_ENABLEBUTTON
,
2976 (WPARAM
)menu
->id
, (LPARAM
) MAKELONG((grey
? FALSE
: TRUE
), 0) );
2981 EnableMenuItem(s_menuBar
, menu
->id
, MF_BYCOMMAND
| MF_GRAYED
);
2983 EnableMenuItem(s_menuBar
, menu
->id
, MF_BYCOMMAND
| MF_ENABLED
);
2986 if ((menu
->parent
!= NULL
) && (IsWindow(menu
->parent
->tearoff_handle
)))
2992 * A tearoff button has changed state.
2994 if (menu
->children
== NULL
)
2995 menuID
= (WORD
)(menu
->id
);
2997 menuID
= (WORD
)((long_u
)(menu
->submenu_id
) | (DWORD
)0x8000);
2998 menuHandle
= GetDlgItem(menu
->parent
->tearoff_handle
, menuID
);
3000 EnableWindow(menuHandle
, !grey
);
3006 #endif /* FEAT_MENU */
3009 /* define some macros used to make the dialogue creation more readable */
3011 #define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
3012 #define add_word(x) *p++ = (x)
3013 #define add_long(x) dwp = (DWORD *)p; *dwp++ = (x); p = (WORD *)dwp
3015 #if defined(FEAT_GUI_DIALOG) || defined(PROTO)
3021 * The callback routine used by all the dialogs. Very simple. First,
3022 * acknowledges the INITDIALOG message so that Windows knows to do standard
3023 * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
3024 * pressed, return that button's ID - IDCANCEL (2), which is the button's
3028 static LRESULT CALLBACK
3035 if (message
== WM_INITDIALOG
)
3037 CenterWindow(hwnd
, GetWindow(hwnd
, GW_OWNER
));
3038 /* Set focus to the dialog. Set the default button, if specified. */
3039 (void)SetFocus(hwnd
);
3040 if (dialog_default_button
> IDCANCEL
)
3041 (void)SetFocus(GetDlgItem(hwnd
, dialog_default_button
));
3043 /* We don't have a default, set focus on another element of the
3044 * dialog window, probably the icon */
3045 (void)SetFocus(GetDlgItem(hwnd
, DLG_NONBUTTON_CONTROL
));
3049 if (message
== WM_COMMAND
)
3051 int button
= LOWORD(wParam
);
3053 /* Don't end the dialog if something was selected that was
3056 if (button
>= DLG_NONBUTTON_CONTROL
)
3059 /* If the edit box exists, copy the string. */
3060 if (s_textfield
!= NULL
)
3062 # if defined(FEAT_MBYTE) && defined(WIN3264)
3063 /* If the OS is Windows NT, and 'encoding' differs from active
3064 * codepage: use wide function and convert text. */
3065 if (os_version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
3066 && enc_codepage
>= 0 && (int)GetACP() != enc_codepage
)
3068 WCHAR
*wp
= (WCHAR
*)alloc(IOSIZE
* sizeof(WCHAR
));
3071 GetDlgItemTextW(hwnd
, DLG_NONBUTTON_CONTROL
+ 2, wp
, IOSIZE
);
3072 p
= utf16_to_enc(wp
, NULL
);
3073 vim_strncpy(s_textfield
, p
, IOSIZE
);
3079 GetDlgItemText(hwnd
, DLG_NONBUTTON_CONTROL
+ 2,
3080 s_textfield
, IOSIZE
);
3084 * Need to check for IDOK because if the user just hits Return to
3085 * accept the default value, some reason this is what we get.
3089 if (dialog_default_button
> IDCANCEL
)
3090 EndDialog(hwnd
, dialog_default_button
);
3093 EndDialog(hwnd
, button
- IDCANCEL
);
3097 if ((message
== WM_SYSCOMMAND
) && (wParam
== SC_CLOSE
))
3106 * Create a dialog dynamically from the parameter strings.
3107 * type = type of dialog (question, alert, etc.)
3108 * title = dialog title. may be NULL for default title.
3109 * message = text to display. Dialog sizes to accommodate it.
3110 * buttons = '\n' separated list of button captions, default first.
3111 * dfltbutton = number of default button.
3113 * This routine returns 1 if the first button is pressed,
3114 * 2 for the second, etc.
3116 * 0 indicates Esc was pressed.
3117 * -1 for unexpected error
3119 * If stubbing out this fn, return 1.
3122 static const char_u
*dlg_icons
[] = /* must match names in resource file */
3140 WORD
*p
, *pdlgtemplate
, *pnumitems
;
3143 int *buttonWidths
, *buttonPositions
;
3159 HFONT font
, oldFont
;
3160 TEXTMETRIC fontInfo
;
3162 int textWidth
, minButtonWidth
, messageWidth
;
3164 int maxDialogHeight
;
3165 int scroll_flag
= 0;
3169 #ifdef USE_SYSMENU_FONT
3171 int use_lfSysmenu
= FALSE
;
3177 /* Don't output anything in silent mode ("ex -s") */
3179 return dfltbutton
; /* return default option */
3183 /* If there is no window yet, open it. */
3184 if (s_hwnd
== NULL
&& gui_mch_init() == FAIL
)
3188 get_dialog_font_metrics();
3191 if ((type
< 0) || (type
> VIM_LAST_TYPE
))
3194 /* allocate some memory for dialog template */
3195 /* TODO should compute this really */
3196 pdlgtemplate
= p
= (PWORD
)LocalAlloc(LPTR
,
3197 DLG_ALLOC_SIZE
+ STRLEN(message
) * 2);
3203 * make a copy of 'buttons' to fiddle with it. complier grizzles because
3204 * vim_strsave() doesn't take a const arg (why not?), so cast away the
3207 tbuffer
= vim_strsave(buttons
);
3208 if (tbuffer
== NULL
)
3211 --dfltbutton
; /* Change from one-based to zero-based */
3215 for (i
= 0; tbuffer
[i
] != '\0'; i
++)
3217 if (tbuffer
[i
] == DLG_BUTTON_SEP
)
3220 if (dfltbutton
>= numButtons
)
3223 /* Allocate array to hold the width of each button */
3224 buttonWidths
= (int *)lalloc(numButtons
* sizeof(int), TRUE
);
3225 if (buttonWidths
== NULL
)
3228 /* Allocate array to hold the X position of each button */
3229 buttonPositions
= (int *)lalloc(numButtons
* sizeof(int), TRUE
);
3230 if (buttonPositions
== NULL
)
3234 * Calculate how big the dialog must be.
3236 hwnd
= GetDesktopWindow();
3237 hdc
= GetWindowDC(hwnd
);
3238 #ifdef USE_SYSMENU_FONT
3239 if (gui_w32_get_menu_font(&lfSysmenu
) == OK
)
3241 font
= CreateFontIndirect(&lfSysmenu
);
3242 use_lfSysmenu
= TRUE
;
3246 font
= CreateFont(-DLG_FONT_POINT_SIZE
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3247 VARIABLE_PITCH
, DLG_FONT_NAME
);
3250 oldFont
= SelectFont(hdc
, font
);
3251 dlgPaddingX
= DLG_PADDING_X
;
3252 dlgPaddingY
= DLG_PADDING_Y
;
3256 oldFont
= SelectFont(hdc
, GetStockObject(SYSTEM_FONT
));
3257 dlgPaddingX
= DLG_OLD_STYLE_PADDING_X
;
3258 dlgPaddingY
= DLG_OLD_STYLE_PADDING_Y
;
3260 GetTextMetrics(hdc
, &fontInfo
);
3261 fontHeight
= fontInfo
.tmHeight
;
3263 /* Minimum width for horizontal button */
3264 minButtonWidth
= GetTextWidth(hdc
, "Cancel", 6);
3266 /* Maximum width of a dialog, if possible */
3271 /* We don't have a window, use the desktop area. */
3272 get_work_area(&workarea_rect
);
3273 maxDialogWidth
= workarea_rect
.right
- workarea_rect
.left
- 100;
3274 if (maxDialogWidth
> 600)
3275 maxDialogWidth
= 600;
3276 maxDialogHeight
= workarea_rect
.bottom
- workarea_rect
.top
- 100;
3280 /* Use our own window for the size, unless it's very small. */
3281 GetWindowRect(s_hwnd
, &rect
);
3282 maxDialogWidth
= rect
.right
- rect
.left
3283 - GetSystemMetrics(SM_CXFRAME
) * 2;
3284 if (maxDialogWidth
< DLG_MIN_MAX_WIDTH
)
3285 maxDialogWidth
= DLG_MIN_MAX_WIDTH
;
3287 maxDialogHeight
= rect
.bottom
- rect
.top
3288 - GetSystemMetrics(SM_CXFRAME
) * 2;
3289 if (maxDialogHeight
< DLG_MIN_MAX_HEIGHT
)
3290 maxDialogHeight
= DLG_MIN_MAX_HEIGHT
;
3293 /* Set dlgwidth to width of message.
3294 * Copy the message into "ga", changing NL to CR-NL and inserting line
3295 * breaks where needed. */
3299 ga_init2(&ga
, sizeof(char), 500);
3302 msgheight
+= fontHeight
; /* at least one line */
3304 /* Need to figure out where to break the string. The system does it
3305 * at a word boundary, which would mean we can't compute the number of
3309 for (pend
= pstart
; *pend
!= NUL
&& *pend
!= '\n'; )
3312 l
= (*mb_ptr2len
)(pend
);
3316 if (l
== 1 && vim_iswhite(*pend
)
3317 && textWidth
> maxDialogWidth
* 3 / 4)
3319 textWidth
+= GetTextWidth(hdc
, pend
, l
);
3320 if (textWidth
>= maxDialogWidth
)
3322 /* Line will wrap. */
3323 messageWidth
= maxDialogWidth
;
3324 msgheight
+= fontHeight
;
3327 if (last_white
!= NULL
)
3329 /* break the line just after a space */
3330 ga
.ga_len
-= (int)(pend
- (last_white
+ 1));
3331 pend
= last_white
+ 1;
3334 ga_append(&ga
, '\r');
3335 ga_append(&ga
, '\n');
3340 ga_append(&ga
, *pend
++);
3342 if (textWidth
> messageWidth
)
3343 messageWidth
= textWidth
;
3345 ga_append(&ga
, '\r');
3346 ga_append(&ga
, '\n');
3348 } while (*pend
!= NUL
);
3350 if (ga
.ga_data
!= NULL
)
3351 message
= ga
.ga_data
;
3353 messageWidth
+= 10; /* roundoff space */
3355 /* Restrict the size to a maximum. Causes a scrollbar to show up. */
3356 if (msgheight
> maxDialogHeight
)
3358 msgheight
= maxDialogHeight
;
3359 scroll_flag
= WS_VSCROLL
;
3360 messageWidth
+= GetSystemMetrics(SM_CXVSCROLL
);
3363 /* Add width of icon to dlgwidth, and some space */
3364 dlgwidth
= messageWidth
+ DLG_ICON_WIDTH
+ 3 * dlgPaddingX
;
3366 if (msgheight
< DLG_ICON_HEIGHT
)
3367 msgheight
= DLG_ICON_HEIGHT
;
3370 * Check button names. A long one will make the dialog wider.
3371 * When called early (-register error message) p_go isn't initialized.
3373 vertical
= (p_go
!= NULL
&& vim_strchr(p_go
, GO_VERTICAL
) != NULL
);
3376 // Place buttons horizontally if they fit.
3377 horizWidth
= dlgPaddingX
;
3382 pend
= vim_strchr(pstart
, DLG_BUTTON_SEP
);
3384 pend
= pstart
+ STRLEN(pstart
); // Last button name.
3385 textWidth
= GetTextWidth(hdc
, pstart
, (int)(pend
- pstart
));
3386 if (textWidth
< minButtonWidth
)
3387 textWidth
= minButtonWidth
;
3388 textWidth
+= dlgPaddingX
; /* Padding within button */
3389 buttonWidths
[i
] = textWidth
;
3390 buttonPositions
[i
++] = horizWidth
;
3391 horizWidth
+= textWidth
+ dlgPaddingX
; /* Pad between buttons */
3393 } while (*pend
!= NUL
);
3395 if (horizWidth
> maxDialogWidth
)
3396 vertical
= TRUE
; // Too wide to fit on the screen.
3397 else if (horizWidth
> dlgwidth
)
3398 dlgwidth
= horizWidth
;
3403 // Stack buttons vertically.
3407 pend
= vim_strchr(pstart
, DLG_BUTTON_SEP
);
3409 pend
= pstart
+ STRLEN(pstart
); // Last button name.
3410 textWidth
= GetTextWidth(hdc
, pstart
, (int)(pend
- pstart
));
3411 textWidth
+= dlgPaddingX
; /* Padding within button */
3412 textWidth
+= DLG_VERT_PADDING_X
* 2; /* Padding around button */
3413 if (textWidth
> dlgwidth
)
3414 dlgwidth
= textWidth
;
3416 } while (*pend
!= NUL
);
3419 if (dlgwidth
< DLG_MIN_WIDTH
)
3420 dlgwidth
= DLG_MIN_WIDTH
; /* Don't allow a really thin dialog!*/
3422 /* start to fill in the dlgtemplate information. addressing by WORDs */
3424 lStyle
= DS_MODALFRAME
| WS_CAPTION
|DS_3DLOOK
| WS_VISIBLE
|DS_SETFONT
;
3426 lStyle
= DS_MODALFRAME
| WS_CAPTION
|DS_3DLOOK
| WS_VISIBLE
;
3429 add_long(0); // (lExtendedStyle)
3430 pnumitems
= p
; /*save where the number of items must be stored*/
3431 add_word(0); // NumberOfItems(will change later)
3434 add_word(PixelToDialogX(dlgwidth
)); // cx
3438 dlgheight
= msgheight
+ 2 * dlgPaddingY
+
3439 DLG_VERT_PADDING_Y
+ 2 * fontHeight
* numButtons
;
3441 dlgheight
= msgheight
+ 3 * dlgPaddingY
+ 2 * fontHeight
;
3443 // Dialog needs to be taller if contains an edit box.
3444 editboxheight
= fontHeight
+ dlgPaddingY
+ 4 * DLG_VERT_PADDING_Y
;
3445 if (textfield
!= NULL
)
3446 dlgheight
+= editboxheight
;
3448 add_word(PixelToDialogY(dlgheight
));
3450 add_word(0); // Menu
3451 add_word(0); // Class
3453 /* copy the title of the dialog */
3454 nchar
= nCopyAnsiToWideChar(p
, (title
?
3456 (LPSTR
)("Vim "VIM_VERSION_MEDIUM
)));
3461 /* do the font, since DS_3DLOOK doesn't work properly */
3462 #ifdef USE_SYSMENU_FONT
3466 *p
++ = -MulDiv(lfSysmenu
.lfHeight
, 72,
3467 GetDeviceCaps(hdc
, LOGPIXELSY
));
3468 nchar
= nCopyAnsiToWideChar(p
, TEXT(lfSysmenu
.lfFaceName
));
3473 *p
++ = DLG_FONT_POINT_SIZE
; // point size
3474 nchar
= nCopyAnsiToWideChar(p
, TEXT(DLG_FONT_NAME
));
3479 buttonYpos
= msgheight
+ 2 * dlgPaddingY
;
3481 if (textfield
!= NULL
)
3482 buttonYpos
+= editboxheight
;
3486 horizWidth
= (dlgwidth
- horizWidth
) / 2; /* Now it's X offset */
3487 for (i
= 0; i
< numButtons
; i
++)
3489 /* get end of this button. */
3490 for ( pend
= pstart
;
3491 *pend
&& (*pend
!= DLG_BUTTON_SEP
);
3500 * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
3501 * the focus to the first tab-able button and in so doing makes that
3502 * the default!! Grrr. Workaround: Make the default button the only
3503 * one with WS_TABSTOP style. Means user can't tab between buttons, but
3504 * he/she can use arrow keys.
3506 * new NOTE: BS_DEFPUSHBUTTON is required to be able to select the
3507 * right button when hitting <Enter>. E.g., for the ":confirm quit"
3508 * dialog. Also needed for when the textfield is the default control.
3509 * It appears to work now (perhaps not on Win95?).
3513 p
= add_dialog_element(p
,
3515 ? BS_DEFPUSHBUTTON
: BS_PUSHBUTTON
) | WS_TABSTOP
,
3516 PixelToDialogX(DLG_VERT_PADDING_X
),
3517 PixelToDialogY(buttonYpos
/* TBK */
3518 + 2 * fontHeight
* i
),
3519 PixelToDialogX(dlgwidth
- 2 * DLG_VERT_PADDING_X
),
3520 (WORD
)(PixelToDialogY(2 * fontHeight
) - 1),
3521 (WORD
)(IDCANCEL
+ 1 + i
), (WORD
)0x0080, pstart
);
3525 p
= add_dialog_element(p
,
3527 ? BS_DEFPUSHBUTTON
: BS_PUSHBUTTON
) | WS_TABSTOP
,
3528 PixelToDialogX(horizWidth
+ buttonPositions
[i
]),
3529 PixelToDialogY(buttonYpos
), /* TBK */
3530 PixelToDialogX(buttonWidths
[i
]),
3531 (WORD
)(PixelToDialogY(2 * fontHeight
) - 1),
3532 (WORD
)(IDCANCEL
+ 1 + i
), (WORD
)0x0080, pstart
);
3534 pstart
= pend
+ 1; /*next button*/
3536 *pnumitems
+= numButtons
;
3539 p
= add_dialog_element(p
, SS_ICON
,
3540 PixelToDialogX(dlgPaddingX
),
3541 PixelToDialogY(dlgPaddingY
),
3542 PixelToDialogX(DLG_ICON_WIDTH
),
3543 PixelToDialogY(DLG_ICON_HEIGHT
),
3544 DLG_NONBUTTON_CONTROL
+ 0, (WORD
)0x0082,
3548 /* Dialog message */
3549 p
= add_dialog_element(p
, SS_LEFT
,
3550 PixelToDialogX(2 * dlgPaddingX
+ DLG_ICON_WIDTH
),
3551 PixelToDialogY(dlgPaddingY
),
3552 (WORD
)(PixelToDialogX(messageWidth
) + 1),
3553 PixelToDialogY(msgheight
),
3554 DLG_NONBUTTON_CONTROL
+ 1, (WORD
)0x0082, message
);
3556 /* Dialog message */
3557 p
= add_dialog_element(p
, ES_LEFT
|scroll_flag
|ES_MULTILINE
|ES_READONLY
,
3558 PixelToDialogX(2 * dlgPaddingX
+ DLG_ICON_WIDTH
),
3559 PixelToDialogY(dlgPaddingY
),
3560 (WORD
)(PixelToDialogX(messageWidth
) + 1),
3561 PixelToDialogY(msgheight
),
3562 DLG_NONBUTTON_CONTROL
+ 1, (WORD
)0x0081, message
);
3566 if (textfield
!= NULL
)
3568 p
= add_dialog_element(p
, ES_LEFT
|ES_AUTOHSCROLL
|WS_TABSTOP
|WS_BORDER
,
3569 PixelToDialogX(2 * dlgPaddingX
),
3570 PixelToDialogY(2 * dlgPaddingY
+ msgheight
),
3571 PixelToDialogX(dlgwidth
- 4 * dlgPaddingX
),
3572 PixelToDialogY(fontHeight
+ dlgPaddingY
),
3573 DLG_NONBUTTON_CONTROL
+ 2, (WORD
)0x0081, textfield
);
3579 SelectFont(hdc
, oldFont
);
3581 ReleaseDC(hwnd
, hdc
);
3583 /* Let the dialog_callback() function know which button to make default
3584 * If we have an edit box, make that the default. We also need to tell
3585 * dialog_callback() if this dialog contains an edit box or not. We do
3586 * this by setting s_textfield if it does.
3588 if (textfield
!= NULL
)
3590 dialog_default_button
= DLG_NONBUTTON_CONTROL
+ 2;
3591 s_textfield
= textfield
;
3595 dialog_default_button
= IDCANCEL
+ 1 + dfltbutton
;
3599 /* show the dialog box modally and get a return value */
3600 nchar
= (int)DialogBoxIndirect(
3602 (LPDLGTEMPLATE
)pdlgtemplate
,
3604 (DLGPROC
)dialog_callback
);
3606 LocalFree(LocalHandle(pdlgtemplate
));
3608 vim_free(buttonWidths
);
3609 vim_free(buttonPositions
);
3610 vim_free(ga
.ga_data
);
3612 /* Focus back to our window (for when MDI is used). */
3613 (void)SetFocus(s_hwnd
);
3618 #endif /* FEAT_GUI_DIALOG */
3621 * Put a simple element (basic class) onto a dialog template in memory.
3622 * return a pointer to where the next item should be added.
3625 * lStyle = additional style flags
3626 * (be careful, NT3.51 & Win32s will ignore the new ones)
3627 * x,y = x & y positions IN DIALOG UNITS
3628 * w,h = width and height IN DIALOG UNITS
3629 * Id = ID used in messages
3630 * clss = class ID, e.g 0x0080 for a button, 0x0082 for a static
3631 * caption = usually text or resource name
3633 * TODO: use the length information noted here to enable the dialog creation
3634 * routines to work out more exactly how much memory they need to alloc.
3646 const char *caption
)
3650 p
= lpwAlign(p
); /* Align to dword boundary*/
3651 lStyle
= lStyle
| WS_VISIBLE
| WS_CHILD
;
3652 *p
++ = LOWORD(lStyle
);
3653 *p
++ = HIWORD(lStyle
);
3654 *p
++ = 0; // LOWORD (lExtendedStyle)
3655 *p
++ = 0; // HIWORD (lExtendedStyle)
3660 *p
++ = Id
; //9 or 10 words in all
3662 *p
++ = (WORD
)0xffff;
3663 *p
++ = clss
; //2 more here
3665 nchar
= nCopyAnsiToWideChar(p
, (LPSTR
)caption
); //strlen(caption)+1
3668 *p
++ = 0; // advance pointer over nExtraStuff WORD - 2 more
3670 return p
; //total = 15+ (strlen(caption)) words
3671 // = 30 + 2(strlen(caption) bytes reqd
3676 * Helper routine. Take an input pointer, return closest pointer that is
3677 * aligned on a DWORD (4 byte) boundary. Taken from the Win32SDK samples.
3693 * Helper routine. Takes second parameter as Ansi string, copies it to first
3694 * parameter as wide character (16-bits / char) string, and returns integer
3695 * number of wide characters (words) in string (including the trailing wide
3696 * char NULL). Partly taken from the Win32SDK samples.
3699 nCopyAnsiToWideChar(
3705 int len
= lstrlen(lpAnsiIn
) + 1; /* include NUL character */
3709 if (enc_codepage
== 0 && (int)GetACP() != enc_codepage
)
3711 /* Not a codepage, use our own conversion function. */
3712 wn
= enc_to_utf16(lpAnsiIn
, NULL
);
3715 wcscpy(lpWCStr
, wn
);
3716 nChar
= (int)wcslen(wn
) + 1;
3721 /* Use Win32 conversion function. */
3722 nChar
= MultiByteToWideChar(
3723 enc_codepage
> 0 ? enc_codepage
: CP_ACP
,
3727 for (i
= 0; i
< nChar
; ++i
)
3728 if (lpWCStr
[i
] == (WORD
)'\t') /* replace tabs with spaces */
3729 lpWCStr
[i
] = (WORD
)' ';
3733 if (*lpAnsiIn
== '\t')
3734 *lpWCStr
++ = (WORD
)' ';
3736 *lpWCStr
++ = (WORD
)*lpAnsiIn
;
3738 } while (*lpAnsiIn
++);
3747 * The callback function for all the modeless dialogs that make up the
3748 * "tearoff menus" Very simple - forward button presses (to fool Vim into
3749 * thinking its menus have been clicked), and go away when closed.
3751 static LRESULT CALLBACK
3758 if (message
== WM_INITDIALOG
)
3761 /* May show the mouse pointer again. */
3762 HandleMouseHide(message
, lParam
);
3764 if (message
== WM_COMMAND
)
3766 if ((WORD
)(LOWORD(wParam
)) & 0x8000)
3771 if (GetCursorPos(&mp
) && GetWindowRect(hwnd
, &rect
))
3773 (void)TrackPopupMenu(
3774 (HMENU
)(long_u
)(LOWORD(wParam
) ^ 0x8000),
3775 TPM_LEFTALIGN
| TPM_LEFTBUTTON
,
3776 (int)rect
.right
- 8,
3778 (int)0, /*reserved param*/
3782 * NOTE: The pop-up menu can eat the mouse up event.
3783 * We deal with this in normal.c.
3788 /* Pass on messages to the main Vim window */
3789 PostMessage(s_hwnd
, WM_COMMAND
, LOWORD(wParam
), 0);
3791 * Give main window the focus back: this is so after
3792 * choosing a tearoff button you can start typing again
3795 (void)SetFocus(s_hwnd
);
3798 if ((message
== WM_SYSCOMMAND
) && (wParam
== SC_CLOSE
))
3800 DestroyWindow(hwnd
);
3804 /* When moved around, give main window the focus back. */
3805 if (message
== WM_EXITSIZEMOVE
)
3806 (void)SetActiveWindow(s_hwnd
);
3814 * Decide whether to use the "new look" (small, non-bold font) or the "old
3815 * look" (big, clanky font) for dialogs, and work out a few values for use
3816 * later accordingly.
3819 get_dialog_font_metrics(void)
3822 HFONT hfontTools
= 0;
3825 #ifdef USE_SYSMENU_FONT
3829 s_usenewlook
= FALSE
;
3832 * For NT3.51 and Win32s, we stick with the old look
3833 * because it matches everything else.
3837 #ifdef USE_SYSMENU_FONT
3838 if (gui_w32_get_menu_font(&lfSysmenu
) == OK
)
3839 hfontTools
= CreateFontIndirect(&lfSysmenu
);
3842 hfontTools
= CreateFont(-DLG_FONT_POINT_SIZE
, 0, 0, 0, 0, 0, 0, 0,
3843 0, 0, 0, 0, VARIABLE_PITCH
, DLG_FONT_NAME
);
3847 hdc
= GetDC(s_hwnd
);
3848 SelectObject(hdc
, hfontTools
);
3850 * GetTextMetrics() doesn't return the right value in
3851 * tmAveCharWidth, so we have to figure out the dialog base units
3854 GetTextExtentPoint(hdc
,
3855 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
3857 ReleaseDC(s_hwnd
, hdc
);
3859 s_dlgfntwidth
= (WORD
)((size
.cx
/ 26 + 1) / 2);
3860 s_dlgfntheight
= (WORD
)size
.cy
;
3861 s_usenewlook
= TRUE
;
3867 dlgFontSize
= GetDialogBaseUnits(); /* fall back to big old system*/
3868 s_dlgfntwidth
= LOWORD(dlgFontSize
);
3869 s_dlgfntheight
= HIWORD(dlgFontSize
);
3873 #if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
3875 * Create a pseudo-"tearoff menu" based on the child
3876 * items of a given menu pointer.
3885 WORD
*p
, *pdlgtemplate
, *pnumitems
, *ptrueheight
;
3887 int nchar
, textWidth
, submenuWidth
;
3889 DWORD lExtendedStyle
;
3893 vimmenu_T
*the_menu
= menu
;
3896 HFONT font
, oldFont
;
3897 int col
, spaceWidth
, len
;
3898 int columnWidths
[2];
3899 char_u
*label
, *text
;
3902 int padding0
, padding1
, padding2
= 0;
3906 #ifdef USE_SYSMENU_FONT
3908 int use_lfSysmenu
= FALSE
;
3912 * If this menu is already torn off, move it to the mouse position.
3914 if (IsWindow(menu
->tearoff_handle
))
3917 if (GetCursorPos((LPPOINT
)&mp
))
3919 SetWindowPos(menu
->tearoff_handle
, NULL
, mp
.x
, mp
.y
, 0, 0,
3920 SWP_NOACTIVATE
| SWP_NOSIZE
| SWP_NOZORDER
);
3926 * Create a new tearoff.
3928 if (*title
== MNU_HIDDEN_CHAR
)
3931 /* Allocate memory to store the dialog template. It's made bigger when
3933 template_len
= DLG_ALLOC_SIZE
;
3934 pdlgtemplate
= p
= (WORD
*)LocalAlloc(LPTR
, template_len
);
3938 hwnd
= GetDesktopWindow();
3939 hdc
= GetWindowDC(hwnd
);
3940 #ifdef USE_SYSMENU_FONT
3941 if (gui_w32_get_menu_font(&lfSysmenu
) == OK
)
3943 font
= CreateFontIndirect(&lfSysmenu
);
3944 use_lfSysmenu
= TRUE
;
3948 font
= CreateFont(-DLG_FONT_POINT_SIZE
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3949 VARIABLE_PITCH
, DLG_FONT_NAME
);
3951 oldFont
= SelectFont(hdc
, font
);
3953 oldFont
= SelectFont(hdc
, GetStockObject(SYSTEM_FONT
));
3955 /* Calculate width of a single space. Used for padding columns to the
3957 spaceWidth
= GetTextWidth(hdc
, " ", 1);
3959 /* Figure out max width of the text column, the accelerator column and the
3960 * optional submenu column. */
3962 for (col
= 0; col
< 2; col
++)
3964 columnWidths
[col
] = 0;
3965 for (pmenu
= menu
->children
; pmenu
!= NULL
; pmenu
= pmenu
->next
)
3967 /* Use "dname" here to compute the width of the visible text. */
3968 text
= (col
== 0) ? pmenu
->dname
: pmenu
->actext
;
3969 if (text
!= NULL
&& *text
!= NUL
)
3971 textWidth
= GetTextWidthEnc(hdc
, text
, (int)STRLEN(text
));
3972 if (textWidth
> columnWidths
[col
])
3973 columnWidths
[col
] = textWidth
;
3975 if (pmenu
->children
!= NULL
)
3976 submenuWidth
= TEAROFF_COLUMN_PADDING
* spaceWidth
;
3979 if (columnWidths
[1] == 0)
3981 /* no accelerators */
3982 if (submenuWidth
!= 0)
3983 columnWidths
[0] += submenuWidth
;
3985 columnWidths
[0] += spaceWidth
;
3989 /* there is an accelerator column */
3990 columnWidths
[0] += TEAROFF_COLUMN_PADDING
* spaceWidth
;
3991 columnWidths
[1] += submenuWidth
;
3995 * Now find the total width of our 'menu'.
3997 textWidth
= columnWidths
[0] + columnWidths
[1];
3998 if (submenuWidth
!= 0)
4000 submenuWidth
= GetTextWidth(hdc
, TEAROFF_SUBMENU_LABEL
,
4001 (int)STRLEN(TEAROFF_SUBMENU_LABEL
));
4002 textWidth
+= submenuWidth
;
4004 dlgwidth
= GetTextWidthEnc(hdc
, title
, (int)STRLEN(title
));
4005 if (textWidth
> dlgwidth
)
4006 dlgwidth
= textWidth
;
4007 dlgwidth
+= 2 * TEAROFF_PADDING_X
+ TEAROFF_BUTTON_PAD_X
;
4009 /* W95 can't do thin dialogs, they look v. weird! */
4010 if (mch_windows95() && dlgwidth
< TEAROFF_MIN_WIDTH
)
4011 dlgwidth
= TEAROFF_MIN_WIDTH
;
4013 /* start to fill in the dlgtemplate information. addressing by WORDs */
4015 lStyle
= DS_MODALFRAME
| WS_CAPTION
| WS_SYSMENU
|DS_SETFONT
| WS_VISIBLE
;
4017 lStyle
= DS_MODALFRAME
| WS_CAPTION
| WS_SYSMENU
| WS_VISIBLE
;
4019 lExtendedStyle
= WS_EX_TOOLWINDOW
|WS_EX_STATICEDGE
;
4020 *p
++ = LOWORD(lStyle
);
4021 *p
++ = HIWORD(lStyle
);
4022 *p
++ = LOWORD(lExtendedStyle
);
4023 *p
++ = HIWORD(lExtendedStyle
);
4024 pnumitems
= p
; /* save where the number of items must be stored */
4025 *p
++ = 0; // NumberOfItems(will change later)
4026 gui_mch_getmouse(&x
, &y
);
4027 if (initX
== 0xffffL
)
4028 *p
++ = PixelToDialogX(x
); // x
4030 *p
++ = PixelToDialogX(initX
); // x
4031 if (initY
== 0xffffL
)
4032 *p
++ = PixelToDialogY(y
); // y
4034 *p
++ = PixelToDialogY(initY
); // y
4035 *p
++ = PixelToDialogX(dlgwidth
); // cx
4037 *p
++ = 0; // dialog height: changed later anyway
4041 /* copy the title of the dialog */
4042 nchar
= nCopyAnsiToWideChar(p
, ((*title
)
4044 : (LPSTR
)("Vim "VIM_VERSION_MEDIUM
)));
4049 /* do the font, since DS_3DLOOK doesn't work properly */
4050 #ifdef USE_SYSMENU_FONT
4054 *p
++ = -MulDiv(lfSysmenu
.lfHeight
, 72,
4055 GetDeviceCaps(hdc
, LOGPIXELSY
));
4056 nchar
= nCopyAnsiToWideChar(p
, TEXT(lfSysmenu
.lfFaceName
));
4061 *p
++ = DLG_FONT_POINT_SIZE
; // point size
4062 nchar
= nCopyAnsiToWideChar (p
, TEXT(DLG_FONT_NAME
));
4068 * Loop over all the items in the menu.
4069 * But skip over the tearbar.
4071 if (STRCMP(menu
->children
->name
, TEAR_STRING
) == 0)
4072 menu
= menu
->children
->next
;
4074 menu
= menu
->children
;
4075 for ( ; menu
!= NULL
; menu
= menu
->next
)
4077 if (menu
->modes
== 0) /* this menu has just been deleted */
4079 if (menu_is_separator(menu
->dname
))
4085 /* Check if there still is plenty of room in the template. Make it
4086 * larger when needed. */
4087 if (((char *)p
- (char *)pdlgtemplate
) + 1000 > template_len
)
4091 newp
= (WORD
*)LocalAlloc(LPTR
, template_len
+ 4096);
4094 template_len
+= 4096;
4095 mch_memmove(newp
, pdlgtemplate
,
4096 (char *)p
- (char *)pdlgtemplate
);
4097 p
= newp
+ (p
- pdlgtemplate
);
4098 pnumitems
= newp
+ (pnumitems
- pdlgtemplate
);
4099 ptrueheight
= newp
+ (ptrueheight
- pdlgtemplate
);
4100 LocalFree(LocalHandle(pdlgtemplate
));
4101 pdlgtemplate
= newp
;
4105 /* Figure out minimal length of this menu label. Use "name" for the
4106 * actual text, "dname" for estimating the displayed size. "name"
4107 * has "&a" for mnemonic and includes the accelerator. */
4108 len
= nameLen
= (int)STRLEN(menu
->name
);
4109 padding0
= (columnWidths
[0] - GetTextWidthEnc(hdc
, menu
->dname
,
4110 (int)STRLEN(menu
->dname
))) / spaceWidth
;
4113 if (menu
->actext
!= NULL
)
4115 acLen
= (int)STRLEN(menu
->actext
);
4117 textWidth
= GetTextWidthEnc(hdc
, menu
->actext
, acLen
);
4121 padding1
= (columnWidths
[1] - textWidth
) / spaceWidth
;
4124 if (menu
->children
== NULL
)
4126 padding2
= submenuWidth
/ spaceWidth
;
4128 menuID
= (WORD
)(menu
->id
);
4132 len
+= (int)STRLEN(TEAROFF_SUBMENU_LABEL
);
4133 menuID
= (WORD
)((long_u
)(menu
->submenu_id
) | (DWORD
)0x8000);
4136 /* Allocate menu label and fill it in */
4137 text
= label
= alloc((unsigned)len
+ 1);
4141 vim_strncpy(text
, menu
->name
, nameLen
);
4142 text
= vim_strchr(text
, TAB
); /* stop at TAB before actext */
4144 text
= label
+ nameLen
; /* no actext, use whole name */
4145 while (padding0
-- > 0)
4147 if (menu
->actext
!= NULL
)
4149 STRNCPY(text
, menu
->actext
, acLen
);
4152 while (padding1
-- > 0)
4154 if (menu
->children
!= NULL
)
4156 STRCPY(text
, TEAROFF_SUBMENU_LABEL
);
4157 text
+= STRLEN(TEAROFF_SUBMENU_LABEL
);
4161 while (padding2
-- > 0)
4167 * BS_LEFT will just be ignored on Win32s/NT3.5x - on
4168 * W95/NT4 it makes the tear-off look more like a menu.
4170 p
= add_dialog_element(p
,
4171 BS_PUSHBUTTON
|BS_LEFT
,
4172 (WORD
)PixelToDialogX(TEAROFF_PADDING_X
),
4173 (WORD
)(sepPadding
+ 1 + 13 * (*pnumitems
)),
4174 (WORD
)PixelToDialogX(dlgwidth
- 2 * TEAROFF_PADDING_X
),
4176 menuID
, (WORD
)0x0080, label
);
4181 *ptrueheight
= (WORD
)(sepPadding
+ 1 + 13 * (*pnumitems
));
4184 /* show modelessly */
4185 the_menu
->tearoff_handle
= CreateDialogIndirect(
4187 (LPDLGTEMPLATE
)pdlgtemplate
,
4189 (DLGPROC
)tearoff_callback
);
4191 LocalFree(LocalHandle(pdlgtemplate
));
4192 SelectFont(hdc
, oldFont
);
4194 ReleaseDC(hwnd
, hdc
);
4197 * Reassert ourselves as the active window. This is so that after creating
4198 * a tearoff, the user doesn't have to click with the mouse just to start
4201 (void)SetActiveWindow(s_hwnd
);
4203 /* make sure the right buttons are enabled */
4204 force_menu_update
= TRUE
;
4208 #if defined(FEAT_TOOLBAR) || defined(PROTO)
4209 #include "gui_w32_rc.h"
4211 /* This not defined in older SDKs */
4212 # ifndef TBSTYLE_FLAT
4213 # define TBSTYLE_FLAT 0x0800
4217 * Create the toolbar, initially unpopulated.
4218 * (just like the menu, there are no defaults, it's all
4219 * set up through menu.vim)
4222 initialise_toolbar(void)
4224 InitCommonControls();
4225 s_toolbarhwnd
= CreateToolbarEx(
4227 WS_CHILD
| TBSTYLE_TOOLTIPS
| TBSTYLE_FLAT
,
4228 4000, //any old big number
4229 31, //number of images in initial bitmap
4231 IDR_TOOLBAR1
, // id of initial bitmap
4233 0, // initial number of buttons
4234 TOOLBAR_BUTTON_WIDTH
, //api guide is wrong!
4235 TOOLBAR_BUTTON_HEIGHT
,
4236 TOOLBAR_BUTTON_WIDTH
,
4237 TOOLBAR_BUTTON_HEIGHT
,
4241 gui_mch_show_toolbar(vim_strchr(p_go
, GO_TOOLBAR
) != NULL
);
4245 get_toolbar_bitmap(vimmenu_T
*menu
)
4250 * Check user bitmaps first, unless builtin is specified.
4252 if (!is_winnt_3() && !menu
->icon_builtin
)
4254 char_u fname
[MAXPATHL
];
4255 HANDLE hbitmap
= NULL
;
4257 if (menu
->iconfile
!= NULL
)
4259 gui_find_iconfile(menu
->iconfile
, fname
, "bmp");
4260 hbitmap
= LoadImage(
4264 TOOLBAR_BUTTON_WIDTH
,
4265 TOOLBAR_BUTTON_HEIGHT
,
4272 * If the LoadImage call failed, or the "icon=" file
4273 * didn't exist or wasn't specified, try the menu name
4276 && (gui_find_bitmap(menu
->name
, fname
, "bmp") == OK
))
4277 hbitmap
= LoadImage(
4281 TOOLBAR_BUTTON_WIDTH
,
4282 TOOLBAR_BUTTON_HEIGHT
,
4287 if (hbitmap
!= NULL
)
4289 TBADDBITMAP tbAddBitmap
;
4291 tbAddBitmap
.hInst
= NULL
;
4292 tbAddBitmap
.nID
= (long_u
)hbitmap
;
4294 i
= (int)SendMessage(s_toolbarhwnd
, TB_ADDBITMAP
,
4295 (WPARAM
)1, (LPARAM
)&tbAddBitmap
);
4296 /* i will be set to -1 if it fails */
4299 if (i
== -1 && menu
->iconidx
>= 0 && menu
->iconidx
< TOOLBAR_BITMAP_COUNT
)
4306 #if defined(FEAT_GUI_TABLINE) || defined(PROTO)
4308 initialise_tabline(void)
4310 InitCommonControls();
4312 s_tabhwnd
= CreateWindow(WC_TABCONTROL
, "Vim tabline",
4313 WS_CHILD
|TCS_FOCUSNEVER
|TCS_TOOLTIPS
,
4314 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
4315 CW_USEDEFAULT
, s_hwnd
, NULL
, s_hinst
, NULL
);
4317 gui
.tabline_height
= TABLINE_HEIGHT
;
4319 # ifdef USE_SYSMENU_FONT
4325 #if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
4327 * Make the GUI window come to the foreground.
4330 gui_mch_set_foreground(void)
4332 if (IsIconic(s_hwnd
))
4333 SendMessage(s_hwnd
, WM_SYSCOMMAND
, SC_RESTORE
, 0);
4334 SetForegroundWindow(s_hwnd
);
4338 #if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
4342 hLibImm
= LoadLibrary("imm32.dll");
4343 if (hLibImm
== NULL
)
4346 pImmGetCompositionStringA
4347 = (void *)GetProcAddress(hLibImm
, "ImmGetCompositionStringA");
4348 pImmGetCompositionStringW
4349 = (void *)GetProcAddress(hLibImm
, "ImmGetCompositionStringW");
4351 = (void *)GetProcAddress(hLibImm
, "ImmGetContext");
4352 pImmAssociateContext
4353 = (void *)GetProcAddress(hLibImm
, "ImmAssociateContext");
4355 = (void *)GetProcAddress(hLibImm
, "ImmReleaseContext");
4357 = (void *)GetProcAddress(hLibImm
, "ImmGetOpenStatus");
4359 = (void *)GetProcAddress(hLibImm
, "ImmSetOpenStatus");
4360 pImmGetCompositionFont
4361 = (void *)GetProcAddress(hLibImm
, "ImmGetCompositionFontA");
4362 pImmSetCompositionFont
4363 = (void *)GetProcAddress(hLibImm
, "ImmSetCompositionFontA");
4364 pImmSetCompositionWindow
4365 = (void *)GetProcAddress(hLibImm
, "ImmSetCompositionWindow");
4366 pImmGetConversionStatus
4367 = (void *)GetProcAddress(hLibImm
, "ImmGetConversionStatus");
4368 pImmSetConversionStatus
4369 = (void *)GetProcAddress(hLibImm
, "ImmSetConversionStatus");
4371 if ( pImmGetCompositionStringA
== NULL
4372 || pImmGetCompositionStringW
== NULL
4373 || pImmGetContext
== NULL
4374 || pImmAssociateContext
== NULL
4375 || pImmReleaseContext
== NULL
4376 || pImmGetOpenStatus
== NULL
4377 || pImmSetOpenStatus
== NULL
4378 || pImmGetCompositionFont
== NULL
4379 || pImmSetCompositionFont
== NULL
4380 || pImmSetCompositionWindow
== NULL
4381 || pImmGetConversionStatus
== NULL
4382 || pImmSetConversionStatus
== NULL
)
4384 FreeLibrary(hLibImm
);
4386 pImmGetContext
= NULL
;
4393 # if 0 /* not used */
4395 dyn_imm_unload(void)
4399 FreeLibrary(hLibImm
);
4407 #if defined(FEAT_SIGN_ICONS) || defined(PROTO)
4409 # ifdef FEAT_XPM_W32
4410 # define IMAGE_XPM 100
4413 typedef struct _signicon_t
4418 HANDLE hShape
; /* Mask bitmap handle */
4423 gui_mch_drawsign(row
, col
, typenr
)
4431 if (!gui
.in_use
|| (sign
= (signicon_t
*)sign_get_image(typenr
)) == NULL
)
4436 w
= gui
.char_width
* 2;
4437 h
= gui
.char_height
;
4438 switch (sign
->uType
)
4445 hdcMem
= CreateCompatibleDC(s_hdc
);
4446 hbmpOld
= (HBITMAP
)SelectObject(hdcMem
, sign
->hImage
);
4447 BitBlt(s_hdc
, x
, y
, w
, h
, hdcMem
, 0, 0, SRCCOPY
);
4448 SelectObject(hdcMem
, hbmpOld
);
4454 DrawIconEx(s_hdc
, x
, y
, (HICON
)sign
->hImage
, w
, h
, 0, NULL
, DI_NORMAL
);
4462 hdcMem
= CreateCompatibleDC(s_hdc
);
4463 hbmpOld
= (HBITMAP
)SelectObject(hdcMem
, sign
->hShape
);
4465 BitBlt(s_hdc
, x
, y
, w
, h
, hdcMem
, 0, 0, SRCAND
);
4467 SelectObject(hdcMem
, sign
->hImage
);
4469 BitBlt(s_hdc
, x
, y
, w
, h
, hdcMem
, 0, 0, SRCPAINT
);
4470 SelectObject(hdcMem
, hbmpOld
);
4479 close_signicon_image(signicon_t
*sign
)
4482 switch (sign
->uType
)
4485 DeleteObject((HGDIOBJ
)sign
->hImage
);
4488 DestroyCursor((HCURSOR
)sign
->hImage
);
4491 DestroyIcon((HICON
)sign
->hImage
);
4495 DeleteObject((HBITMAP
)sign
->hImage
);
4496 DeleteObject((HBITMAP
)sign
->hShape
);
4503 gui_mch_register_sign(signfile
)
4506 signicon_t sign
, *psign
;
4511 EMSG(_(e_signdata
));
4516 ext
= signfile
+ STRLEN(signfile
) - 4; /* get extention */
4521 if (!STRICMP(ext
, ".bmp"))
4522 sign
.uType
= IMAGE_BITMAP
;
4523 else if (!STRICMP(ext
, ".ico"))
4524 sign
.uType
= IMAGE_ICON
;
4525 else if (!STRICMP(ext
, ".cur") || !STRICMP(ext
, ".ani"))
4526 sign
.uType
= IMAGE_CURSOR
;
4531 sign
.hImage
= (HANDLE
)LoadImage(NULL
, signfile
, sign
.uType
,
4532 gui
.char_width
* 2, gui
.char_height
,
4533 LR_LOADFROMFILE
| LR_CREATEDIBSECTION
);
4535 if (!STRICMP(ext
, ".xpm"))
4537 sign
.uType
= IMAGE_XPM
;
4538 LoadXpmImage(signfile
, (HBITMAP
*)&sign
.hImage
, (HBITMAP
*)&sign
.hShape
);
4544 if (sign
.hImage
&& (psign
= (signicon_t
*)alloc(sizeof(signicon_t
)))
4551 close_signicon_image(&sign
);
4552 EMSG(_(e_signdata
));
4554 return (void *)psign
;
4559 gui_mch_destroy_sign(sign
)
4564 close_signicon_image((signicon_t
*)sign
);
4570 #if defined(FEAT_BEVAL) || defined(PROTO)
4572 /* BALLOON-EVAL IMPLEMENTATION FOR WINDOWS.
4573 * Added by Sergey Khorev <sergey.khorev@gmail.com>
4575 * The only reused thing is gui_beval.h and get_beval_info()
4576 * from gui_beval.c (note it uses x and y of the BalloonEval struct
4577 * to get current mouse position).
4579 * Trying to use as more Windows services as possible, and as less
4580 * IE version as possible :)).
4582 * 1) Don't create ToolTip in gui_mch_create_beval_area, only initialize
4583 * BalloonEval struct.
4584 * 2) Enable/Disable simply create/kill BalloonEval Timer
4585 * 3) When there was enough inactivity, timer procedure posts
4586 * async request to debugger
4587 * 4) gui_mch_post_balloon (invoked from netbeans.c) creates tooltip control
4588 * and performs some actions to show it ASAP
4589 * 5) WM_NOTIFY:TTN_POP destroys created tooltip
4593 * determine whether installed Common Controls support multiline tooltips
4594 * (i.e. their version is >= 4.70
4597 multiline_balloon_available(void)
4600 static char comctl_dll
[] = "comctl32.dll";
4601 static int multiline_tip
= MAYBE
;
4603 if (multiline_tip
!= MAYBE
)
4604 return multiline_tip
;
4606 hDll
= GetModuleHandle(comctl_dll
);
4609 DLLGETVERSIONPROC pGetVer
;
4610 pGetVer
= (DLLGETVERSIONPROC
)GetProcAddress(hDll
, "DllGetVersion");
4612 if (pGetVer
!= NULL
)
4617 ZeroMemory(&dvi
, sizeof(dvi
));
4618 dvi
.cbSize
= sizeof(dvi
);
4620 hr
= (*pGetVer
)(&dvi
);
4623 && (dvi
.dwMajorVersion
> 4
4624 || (dvi
.dwMajorVersion
== 4
4625 && dvi
.dwMinorVersion
>= 70)))
4627 multiline_tip
= TRUE
;
4628 return multiline_tip
;
4633 /* there is chance we have ancient CommCtl 4.70
4634 which doesn't export DllGetVersion */
4636 DWORD len
= GetFileVersionInfoSize(comctl_dll
, &dwHandle
);
4639 VS_FIXEDFILEINFO
*ver
;
4641 void *data
= alloc(len
);
4644 && GetFileVersionInfo(comctl_dll
, 0, len
, data
)
4645 && VerQueryValue(data
, "\\", (void **)&ver
, &vlen
)
4647 && HIWORD(ver
->dwFileVersionMS
) > 4
4648 || (HIWORD(ver
->dwFileVersionMS
) == 4
4649 && LOWORD(ver
->dwFileVersionMS
) >= 70))
4652 multiline_tip
= TRUE
;
4653 return multiline_tip
;
4659 multiline_tip
= FALSE
;
4660 return multiline_tip
;
4664 make_tooltip(beval
, text
, pt
)
4672 if (multiline_balloon_available() == TRUE
)
4673 ToolInfoSize
= sizeof(TOOLINFO_NEW
);
4675 ToolInfoSize
= sizeof(TOOLINFO
);
4677 pti
= (TOOLINFO
*)alloc(ToolInfoSize
);
4681 beval
->balloon
= CreateWindowEx(WS_EX_TOPMOST
, TOOLTIPS_CLASS
,
4682 NULL
, WS_POPUP
| TTS_NOPREFIX
| TTS_ALWAYSTIP
,
4683 CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
, CW_USEDEFAULT
,
4684 beval
->target
, NULL
, s_hinst
, NULL
);
4686 SetWindowPos(beval
->balloon
, HWND_TOPMOST
, 0, 0, 0, 0,
4687 SWP_NOMOVE
| SWP_NOSIZE
| SWP_NOACTIVATE
);
4689 pti
->cbSize
= ToolInfoSize
;
4690 pti
->uFlags
= TTF_SUBCLASS
;
4691 pti
->hwnd
= beval
->target
;
4692 pti
->hinst
= 0; /* Don't use string resources */
4693 pti
->uId
= ID_BEVAL_TOOLTIP
;
4695 if (multiline_balloon_available() == TRUE
)
4698 TOOLINFO_NEW
*ptin
= (TOOLINFO_NEW
*)pti
;
4699 pti
->lpszText
= LPSTR_TEXTCALLBACK
;
4700 ptin
->lParam
= (LPARAM
)text
;
4701 if (GetClientRect(s_textArea
, &rect
)) /* switch multiline tooltips on */
4702 SendMessage(beval
->balloon
, TTM_SETMAXTIPWIDTH
, 0,
4703 (LPARAM
)rect
.right
);
4706 pti
->lpszText
= text
; /* do this old way */
4708 /* Limit ballooneval bounding rect to CursorPos neighbourhood */
4709 pti
->rect
.left
= pt
.x
- 3;
4710 pti
->rect
.top
= pt
.y
- 3;
4711 pti
->rect
.right
= pt
.x
+ 3;
4712 pti
->rect
.bottom
= pt
.y
+ 3;
4714 SendMessage(beval
->balloon
, TTM_ADDTOOL
, 0, (LPARAM
)pti
);
4715 /* Make tooltip appear sooner */
4716 SendMessage(beval
->balloon
, TTM_SETDELAYTIME
, TTDT_INITIAL
, 10);
4717 /* I've performed some tests and it seems the longest possible life time
4718 * of tooltip is 30 seconds */
4719 SendMessage(beval
->balloon
, TTM_SETDELAYTIME
, TTDT_AUTOPOP
, 30000);
4721 * HACK: force tooltip to appear, because it'll not appear until
4722 * first mouse move. D*mn M$
4723 * Amazingly moving (2, 2) and then (-1, -1) the mouse doesn't move.
4725 mouse_event(MOUSEEVENTF_MOVE
, 2, 2, 0, 0);
4726 mouse_event(MOUSEEVENTF_MOVE
, (DWORD
)-1, (DWORD
)-1, 0, 0);
4731 delete_tooltip(beval
)
4734 DestroyWindow(beval
->balloon
);
4738 static VOID CALLBACK
4739 BevalTimerProc(hwnd
, uMsg
, idEvent
, dwTime
)
4748 if (cur_beval
== NULL
|| cur_beval
->showState
== ShS_SHOWING
|| !p_beval
)
4752 if (WindowFromPoint(pt
) != s_textArea
)
4755 ScreenToClient(s_textArea
, &pt
);
4756 GetClientRect(s_textArea
, &rect
);
4757 if (!PtInRect(&rect
, pt
))
4760 if (LastActivity
> 0
4761 && (dwTime
- LastActivity
) >= (DWORD
)p_bdlay
4762 && (cur_beval
->showState
!= ShS_PENDING
4763 || abs(cur_beval
->x
- pt
.x
) > 3
4764 || abs(cur_beval
->y
- pt
.y
) > 3))
4766 /* Pointer resting in one place long enough, it's time to show
4768 cur_beval
->showState
= ShS_PENDING
;
4769 cur_beval
->x
= pt
.x
;
4770 cur_beval
->y
= pt
.y
;
4772 // TRACE0("BevalTimerProc: sending request");
4774 if (cur_beval
->msgCB
!= NULL
)
4775 (*cur_beval
->msgCB
)(cur_beval
, 0);
4781 gui_mch_disable_beval_area(beval
)
4784 // TRACE0("gui_mch_disable_beval_area {{{");
4785 KillTimer(s_textArea
, BevalTimerId
);
4786 // TRACE0("gui_mch_disable_beval_area }}}");
4791 gui_mch_enable_beval_area(beval
)
4794 // TRACE0("gui_mch_enable_beval_area |||");
4797 // TRACE0("gui_mch_enable_beval_area {{{");
4798 BevalTimerId
= SetTimer(s_textArea
, 0, p_bdlay
/ 2, BevalTimerProc
);
4799 // TRACE0("gui_mch_enable_beval_area }}}");
4803 gui_mch_post_balloon(beval
, mesg
)
4808 // TRACE0("gui_mch_post_balloon {{{");
4809 if (beval
->showState
== ShS_SHOWING
)
4812 ScreenToClient(s_textArea
, &pt
);
4814 if (abs(beval
->x
- pt
.x
) < 3 && abs(beval
->y
- pt
.y
) < 3)
4815 /* cursor is still here */
4817 gui_mch_disable_beval_area(cur_beval
);
4818 beval
->showState
= ShS_SHOWING
;
4819 make_tooltip(beval
, mesg
, pt
);
4821 // TRACE0("gui_mch_post_balloon }}}");
4826 gui_mch_create_beval_area(target
, mesg
, mesgCB
, clientData
)
4827 void *target
; /* ignored, always use s_textArea */
4829 void (*mesgCB
)__ARGS((BalloonEval
*, int));
4832 /* partially stolen from gui_beval.c */
4835 if (mesg
!= NULL
&& mesgCB
!= NULL
)
4837 EMSG(_("E232: Cannot create BalloonEval with both message and callback"));
4841 beval
= (BalloonEval
*)alloc(sizeof(BalloonEval
));
4844 beval
->target
= s_textArea
;
4845 beval
->balloon
= NULL
;
4847 beval
->showState
= ShS_NEUTRAL
;
4851 beval
->msgCB
= mesgCB
;
4852 beval
->clientData
= clientData
;
4854 InitCommonControls();
4858 gui_mch_enable_beval_area(beval
);
4866 Handle_WM_Notify(hwnd
, pnmh
)
4870 if (pnmh
->idFrom
!= ID_BEVAL_TOOLTIP
) /* it is not our tooltip */
4873 if (cur_beval
!= NULL
)
4878 // TRACE0("TTN_SHOW {{{");
4879 // TRACE0("TTN_SHOW }}}");
4881 case TTN_POP
: /* Before tooltip disappear */
4882 // TRACE0("TTN_POP {{{");
4883 delete_tooltip(cur_beval
);
4884 gui_mch_enable_beval_area(cur_beval
);
4885 // TRACE0("TTN_POP }}}");
4887 cur_beval
->showState
= ShS_NEUTRAL
;
4889 case TTN_GETDISPINFO
:
4891 /* if you get there then we have new common controls */
4892 NMTTDISPINFO_NEW
*info
= (NMTTDISPINFO_NEW
*)pnmh
;
4893 info
->lpszText
= (LPSTR
)info
->lParam
;
4894 info
->uFlags
|= TTF_DI_SETITEM
;
4902 TrackUserActivity(UINT uMsg
)
4904 if ((uMsg
>= WM_MOUSEFIRST
&& uMsg
<= WM_MOUSELAST
)
4905 || (uMsg
>= WM_KEYFIRST
&& uMsg
<= WM_KEYLAST
))
4906 LastActivity
= GetTickCount();
4910 gui_mch_destroy_beval_area(beval
)
4915 #endif /* FEAT_BEVAL */
4917 #if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
4919 * We have multiple signs to draw at the same location. Draw the
4920 * multi-sign indicator (down-arrow) instead. This is the Win32 version.
4923 netbeans_draw_multisign_indicator(int row
)
4932 for (i
= 0; i
< gui
.char_height
- 3; i
++)
4933 SetPixel(s_hdc
, x
+2, y
++, gui
.currFgColor
);
4935 SetPixel(s_hdc
, x
+0, y
, gui
.currFgColor
);
4936 SetPixel(s_hdc
, x
+2, y
, gui
.currFgColor
);
4937 SetPixel(s_hdc
, x
+4, y
++, gui
.currFgColor
);
4938 SetPixel(s_hdc
, x
+1, y
, gui
.currFgColor
);
4939 SetPixel(s_hdc
, x
+2, y
, gui
.currFgColor
);
4940 SetPixel(s_hdc
, x
+3, y
++, gui
.currFgColor
);
4941 SetPixel(s_hdc
, x
+2, y
, gui
.currFgColor
);
4945 #ifdef USE_AMBIWIDTH_AUTO
4946 #define CHARWIDE_CACHESIZE 65536
4947 static GuiFont last_font
= 0;
4950 gui_mch_get_charwidth(int c
)
4952 static char cache
[CHARWIDE_CACHESIZE
];
4953 GuiFont usingfont
= gui
.wide_font
? gui
.wide_font
: gui
.norm_font
;
4955 /* Check validity of charwide cache */
4956 if (last_font
!= usingfont
)
4958 /* Update cache. -1 is mark for uninitialized cell */
4959 TRACE("Charwide cache will be updated (base=%d)\n", gui
.char_width
);
4960 last_font
= usingfont
;
4961 memset(cache
, -1, sizeof(cache
));
4963 if (usingfont
&& 0 <= c
&& c
< CHARWIDE_CACHESIZE
)
4966 return cache
[c
]; /* Use cached value */
4970 * Get true character width in dot, convert to cells and save
4975 HFONT hfntOld
= SelectFont(s_hdc
, usingfont
);
4977 if (!GetCharABCWidthsW(s_hdc
, c
, c
, &fontABC
) ||
4978 (len
= fontABC
.abcA
+ fontABC
.abcB
+ fontABC
.abcC
) <= 0)
4980 TRACE("GetCharABCWidthsW() failed for %08X\n", c
);
4984 cache
[c
] = (char)((len
+ (gui
.char_width
>> 1))
4986 SelectFont(s_hdc
, hfntOld
);