blob: 092d8d516ed1dee5782190e86ba695d1a3a83816 [file] [log] [blame]
Bram Moolenaar060f1f02007-05-10 20:17:29 +00001/* vi:set ts=8 sts=4 sw=4:
Bram Moolenaar071d4272004-06-13 20:20:40 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 * GUI support by Robert Webb
5 *
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.
9 */
10/*
11 * Windows GUI.
12 *
13 * GUI support for Microsoft Windows. Win32 initially; maybe Win16 later
14 *
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,
17 * scrollbars, etc.
18 *
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).
21 *
22 * TODO: Some of the function signatures ought to be updated for Win64;
23 * e.g., replace LONG with LONG_PTR, etc.
24 */
25
26/*
27 * These are new in Windows ME/XP, only defined in recent compilers.
28 */
29#ifndef HANDLE_WM_XBUTTONUP
30# define HANDLE_WM_XBUTTONUP(hwnd, wParam, lParam, fn) \
31 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
32#endif
33#ifndef HANDLE_WM_XBUTTONDOWN
34# define HANDLE_WM_XBUTTONDOWN(hwnd, wParam, lParam, fn) \
35 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
36#endif
37#ifndef HANDLE_WM_XBUTTONDBLCLK
38# define HANDLE_WM_XBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
39 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
40#endif
41
42/*
43 * Include the common stuff for MS-Windows GUI.
44 */
45#include "gui_w48.c"
46
47#ifdef FEAT_XPM_W32
48# include "xpm_w32.h"
49#endif
50
51#ifdef PROTO
52# define WINAPI
53#endif
54
55#ifdef __MINGW32__
56/*
57 * Add a lot of missing defines.
58 * They are not always missing, we need the #ifndef's.
59 */
60# ifndef _cdecl
61# define _cdecl
62# endif
63# ifndef IsMinimized
64# define IsMinimized(hwnd) IsIconic(hwnd)
65# endif
66# ifndef IsMaximized
67# define IsMaximized(hwnd) IsZoomed(hwnd)
68# endif
69# ifndef SelectFont
70# define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont)))
71# endif
72# ifndef GetStockBrush
73# define GetStockBrush(i) ((HBRUSH)GetStockObject(i))
74# endif
75# ifndef DeleteBrush
76# define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr))
77# endif
78
79# ifndef HANDLE_WM_RBUTTONDBLCLK
80# define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
81 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
82# endif
83# ifndef HANDLE_WM_MBUTTONUP
84# define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \
85 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
86# endif
87# ifndef HANDLE_WM_MBUTTONDBLCLK
88# define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
89 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
90# endif
91# ifndef HANDLE_WM_LBUTTONDBLCLK
92# define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \
93 ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
94# endif
95# ifndef HANDLE_WM_RBUTTONDOWN
96# define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \
97 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
98# endif
99# ifndef HANDLE_WM_MOUSEMOVE
100# define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \
101 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
102# endif
103# ifndef HANDLE_WM_RBUTTONUP
104# define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \
105 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
106# endif
107# ifndef HANDLE_WM_MBUTTONDOWN
108# define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \
109 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
110# endif
111# ifndef HANDLE_WM_LBUTTONUP
112# define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \
113 ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
114# endif
115# ifndef HANDLE_WM_LBUTTONDOWN
116# define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
117 ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)
118# endif
119# ifndef HANDLE_WM_SYSCHAR
120# define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \
121 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
122# endif
123# ifndef HANDLE_WM_ACTIVATEAPP
124# define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \
125 ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L)
126# endif
127# ifndef HANDLE_WM_WINDOWPOSCHANGING
128# define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \
129 (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam))
130# endif
131# ifndef HANDLE_WM_VSCROLL
132# define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \
133 ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
134# endif
135# ifndef HANDLE_WM_SETFOCUS
136# define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \
137 ((fn)((hwnd), (HWND)(wParam)), 0L)
138# endif
139# ifndef HANDLE_WM_KILLFOCUS
140# define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \
141 ((fn)((hwnd), (HWND)(wParam)), 0L)
142# endif
143# ifndef HANDLE_WM_HSCROLL
144# define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \
145 ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L)
146# endif
147# ifndef HANDLE_WM_DROPFILES
148# define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \
149 ((fn)((hwnd), (HDROP)(wParam)), 0L)
150# endif
151# ifndef HANDLE_WM_CHAR
152# define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \
153 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
154# endif
155# ifndef HANDLE_WM_SYSDEADCHAR
156# define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \
157 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
158# endif
159# ifndef HANDLE_WM_DEADCHAR
160# define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \
161 ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L)
162# endif
163#endif /* __MINGW32__ */
164
165
166/* Some parameters for tearoff menus. All in pixels. */
167#define TEAROFF_PADDING_X 2
168#define TEAROFF_BUTTON_PAD_X 8
169#define TEAROFF_MIN_WIDTH 200
170#define TEAROFF_SUBMENU_LABEL ">>"
171#define TEAROFF_COLUMN_PADDING 3 // # spaces to pad column with.
172
173
174/* For the Intellimouse: */
175#ifndef WM_MOUSEWHEEL
176#define WM_MOUSEWHEEL 0x20a
177#endif
178
179
180#ifdef FEAT_BEVAL
181# define ID_BEVAL_TOOLTIP 200
182# define BEVAL_TEXT_LEN MAXPATHL
183
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000184#if _MSC_VER < 1300
185/* Work around old versions of basetsd.h which wrongly declare
186 * UINT_PTR as unsigned long */
Bram Moolenaar8424a622006-04-19 21:23:36 +0000187# define UINT_PTR UINT
188#endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000189
190static void make_tooltip __ARGS((BalloonEval *beval, char *text, POINT pt));
191static void delete_tooltip __ARGS((BalloonEval *beval));
192static VOID CALLBACK BevalTimerProc __ARGS((HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime));
193
Bram Moolenaar071d4272004-06-13 20:20:40 +0000194static BalloonEval *cur_beval = NULL;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000195static UINT_PTR BevalTimerId = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +0000196static DWORD LastActivity = 0;
Bram Moolenaar45360022005-07-21 21:08:21 +0000197
198/*
199 * excerpts from headers since this may not be presented
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000200 * in the extremely old compilers
Bram Moolenaar45360022005-07-21 21:08:21 +0000201 */
202#include <pshpack1.h>
203
204typedef struct _DllVersionInfo
205{
206 DWORD cbSize;
207 DWORD dwMajorVersion;
208 DWORD dwMinorVersion;
209 DWORD dwBuildNumber;
210 DWORD dwPlatformID;
211} DLLVERSIONINFO;
212
213typedef struct tagTOOLINFOA_NEW
214{
215 UINT cbSize;
216 UINT uFlags;
217 HWND hwnd;
218 UINT uId;
219 RECT rect;
220 HINSTANCE hinst;
221 LPSTR lpszText;
222 LPARAM lParam;
223} TOOLINFO_NEW;
224
225typedef struct tagNMTTDISPINFO_NEW
226{
227 NMHDR hdr;
228 LPTSTR lpszText;
229 char szText[80];
230 HINSTANCE hinst;
231 UINT uFlags;
232 LPARAM lParam;
233} NMTTDISPINFO_NEW;
234
235#include <poppack.h>
236
237typedef HRESULT (WINAPI* DLLGETVERSIONPROC)(DLLVERSIONINFO *);
238#ifndef TTM_SETMAXTIPWIDTH
Bram Moolenaarf9393ef2006-04-24 19:47:27 +0000239# define TTM_SETMAXTIPWIDTH (WM_USER+24)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000240#endif
241
Bram Moolenaar45360022005-07-21 21:08:21 +0000242#ifndef TTF_DI_SETITEM
Bram Moolenaarf9393ef2006-04-24 19:47:27 +0000243# define TTF_DI_SETITEM 0x8000
Bram Moolenaar45360022005-07-21 21:08:21 +0000244#endif
245
246#ifndef TTN_GETDISPINFO
Bram Moolenaarf9393ef2006-04-24 19:47:27 +0000247# define TTN_GETDISPINFO (TTN_FIRST - 0)
Bram Moolenaar45360022005-07-21 21:08:21 +0000248#endif
249
250#endif /* defined(FEAT_BEVAL) */
251
Bram Moolenaar2c7a7632007-05-10 18:19:11 +0000252#if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
253/* Older MSVC compilers don't have LPNMTTDISPINFO[AW] thus we need to define
254 * it here if LPNMTTDISPINFO isn't defined.
255 * MingW doesn't define LPNMTTDISPINFO but typedefs it. Thus we need to check
256 * _MSC_VER. */
257# if !defined(LPNMTTDISPINFO) && defined(_MSC_VER)
258typedef struct tagNMTTDISPINFOA {
259 NMHDR hdr;
260 LPSTR lpszText;
261 char szText[80];
262 HINSTANCE hinst;
263 UINT uFlags;
264 LPARAM lParam;
265} NMTTDISPINFOA, *LPNMTTDISPINFOA;
266# define LPNMTTDISPINFO LPNMTTDISPINFOA
267
268# ifdef FEAT_MBYTE
269typedef struct tagNMTTDISPINFOW {
270 NMHDR hdr;
271 LPWSTR lpszText;
272 WCHAR szText[80];
273 HINSTANCE hinst;
274 UINT uFlags;
275 LPARAM lParam;
276} NMTTDISPINFOW, *LPNMTTDISPINFOW;
277# endif
278# endif
279#endif
280
Bram Moolenaarf9393ef2006-04-24 19:47:27 +0000281#ifndef TTN_GETDISPINFOW
282# define TTN_GETDISPINFOW (TTN_FIRST - 10)
283#endif
284
Bram Moolenaar071d4272004-06-13 20:20:40 +0000285/* Local variables: */
286
287#ifdef FEAT_MENU
288static UINT s_menu_id = 100;
289
290/*
291 * Use the system font for dialogs and tear-off menus. Remove this line to
292 * use DLG_FONT_NAME.
293 */
294# define USE_SYSMENU_FONT
295#endif
296
297#define VIM_NAME "vim"
298#define VIM_CLASS "Vim"
299#define VIM_CLASSW L"Vim"
300
301/* Initial size for the dialog template. For gui_mch_dialog() it's fixed,
302 * thus there should be room for every dialog. For tearoffs it's made bigger
303 * when needed. */
304#define DLG_ALLOC_SIZE 16 * 1024
305
306/*
307 * stuff for dialogs, menus, tearoffs etc.
308 */
309static LRESULT APIENTRY dialog_callback(HWND, UINT, WPARAM, LPARAM);
310static LRESULT APIENTRY tearoff_callback(HWND, UINT, WPARAM, LPARAM);
311static PWORD
312add_dialog_element(
313 PWORD p,
314 DWORD lStyle,
315 WORD x,
316 WORD y,
317 WORD w,
318 WORD h,
319 WORD Id,
320 WORD clss,
321 const char *caption);
322static LPWORD lpwAlign(LPWORD);
323static int nCopyAnsiToWideChar(LPWORD, LPSTR);
324static void gui_mch_tearoff(char_u *title, vimmenu_T *menu, int initX, int initY);
325static void get_dialog_font_metrics(void);
326
327static int dialog_default_button = -1;
328
329/* Intellimouse support */
330static int mouse_scroll_lines = 0;
331static UINT msh_msgmousewheel = 0;
332
333static int s_usenewlook; /* emulate W95/NT4 non-bold dialogs */
334#ifdef FEAT_TOOLBAR
335static void initialise_toolbar(void);
336static int get_toolbar_bitmap(vimmenu_T *menu);
337#endif
338
Bram Moolenaar3991dab2006-03-27 17:01:56 +0000339#ifdef FEAT_GUI_TABLINE
340static void initialise_tabline(void);
341#endif
342
Bram Moolenaar071d4272004-06-13 20:20:40 +0000343#ifdef FEAT_MBYTE_IME
344static LRESULT _OnImeComposition(HWND hwnd, WPARAM dbcs, LPARAM param);
345static char_u *GetResultStr(HWND hwnd, int GCS, int *lenp);
346#endif
347#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
348# ifdef NOIME
349typedef struct tagCOMPOSITIONFORM {
350 DWORD dwStyle;
351 POINT ptCurrentPos;
352 RECT rcArea;
353} COMPOSITIONFORM, *PCOMPOSITIONFORM, NEAR *NPCOMPOSITIONFORM, FAR *LPCOMPOSITIONFORM;
354typedef HANDLE HIMC;
355# endif
356
Bram Moolenaard857f0e2005-06-21 22:37:39 +0000357static HINSTANCE hLibImm = NULL;
358static LONG (WINAPI *pImmGetCompositionStringA)(HIMC, DWORD, LPVOID, DWORD);
359static LONG (WINAPI *pImmGetCompositionStringW)(HIMC, DWORD, LPVOID, DWORD);
360static HIMC (WINAPI *pImmGetContext)(HWND);
361static HIMC (WINAPI *pImmAssociateContext)(HWND, HIMC);
362static BOOL (WINAPI *pImmReleaseContext)(HWND, HIMC);
363static BOOL (WINAPI *pImmGetOpenStatus)(HIMC);
364static BOOL (WINAPI *pImmSetOpenStatus)(HIMC, BOOL);
365static BOOL (WINAPI *pImmGetCompositionFont)(HIMC, LPLOGFONTA);
366static BOOL (WINAPI *pImmSetCompositionFont)(HIMC, LPLOGFONTA);
367static BOOL (WINAPI *pImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM);
368static BOOL (WINAPI *pImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD);
Bram Moolenaarca003e12006-03-17 23:19:38 +0000369static BOOL (WINAPI *pImmSetConversionStatus)(HIMC, DWORD, DWORD);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000370static void dyn_imm_load(void);
371#else
372# define pImmGetCompositionStringA ImmGetCompositionStringA
373# define pImmGetCompositionStringW ImmGetCompositionStringW
374# define pImmGetContext ImmGetContext
375# define pImmAssociateContext ImmAssociateContext
376# define pImmReleaseContext ImmReleaseContext
377# define pImmGetOpenStatus ImmGetOpenStatus
378# define pImmSetOpenStatus ImmSetOpenStatus
379# define pImmGetCompositionFont ImmGetCompositionFontA
380# define pImmSetCompositionFont ImmSetCompositionFontA
381# define pImmSetCompositionWindow ImmSetCompositionWindow
382# define pImmGetConversionStatus ImmGetConversionStatus
Bram Moolenaarca003e12006-03-17 23:19:38 +0000383# define pImmSetConversionStatus ImmSetConversionStatus
Bram Moolenaar071d4272004-06-13 20:20:40 +0000384#endif
385
386#ifndef ETO_IGNORELANGUAGE
387# define ETO_IGNORELANGUAGE 0x1000
388#endif
389
390/* multi monitor support */
391typedef struct _MONITORINFOstruct
392{
393 DWORD cbSize;
394 RECT rcMonitor;
395 RECT rcWork;
396 DWORD dwFlags;
397} _MONITORINFO;
398
399typedef HANDLE _HMONITOR;
400typedef _HMONITOR (WINAPI *TMonitorFromWindow)(HWND, DWORD);
401typedef BOOL (WINAPI *TGetMonitorInfo)(_HMONITOR, _MONITORINFO *);
402
403static TMonitorFromWindow pMonitorFromWindow = NULL;
404static TGetMonitorInfo pGetMonitorInfo = NULL;
405static HANDLE user32_lib = NULL;
406#ifdef FEAT_NETBEANS_INTG
407int WSInitialized = FALSE; /* WinSock is initialized */
408#endif
409/*
410 * Return TRUE when running under Windows NT 3.x or Win32s, both of which have
411 * less fancy GUI APIs.
412 */
413 static int
414is_winnt_3(void)
415{
416 return ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
417 && os_version.dwMajorVersion == 3)
418 || (os_version.dwPlatformId == VER_PLATFORM_WIN32s));
419}
420
421/*
422 * Return TRUE when running under Win32s.
423 */
424 int
425gui_is_win32s(void)
426{
427 return (os_version.dwPlatformId == VER_PLATFORM_WIN32s);
428}
429
430#ifdef FEAT_MENU
431/*
432 * Figure out how high the menu bar is at the moment.
433 */
434 static int
435gui_mswin_get_menu_height(
436 int fix_window) /* If TRUE, resize window if menu height changed */
437{
438 static int old_menu_height = -1;
439
440 RECT rc1, rc2;
441 int num;
442 int menu_height;
443
444 if (gui.menu_is_active)
445 num = GetMenuItemCount(s_menuBar);
446 else
447 num = 0;
448
449 if (num == 0)
450 menu_height = 0;
451 else
452 {
453 if (is_winnt_3()) /* for NT 3.xx */
454 {
455 if (gui.starting)
456 menu_height = GetSystemMetrics(SM_CYMENU);
457 else
458 {
459 RECT r1, r2;
460 int frameht = GetSystemMetrics(SM_CYFRAME);
461 int capht = GetSystemMetrics(SM_CYCAPTION);
462
463 /* get window rect of s_hwnd
464 * get client rect of s_hwnd
465 * get cap height
466 * subtract from window rect, the sum of client height,
467 * (if not maximized)frame thickness, and caption height.
468 */
469 GetWindowRect(s_hwnd, &r1);
470 GetClientRect(s_hwnd, &r2);
471 menu_height = r1.bottom - r1.top - (r2.bottom - r2.top
472 + 2 * frameht * (!IsZoomed(s_hwnd)) + capht);
473 }
474 }
475 else /* win95 and variants (NT 4.0, I guess) */
476 {
477 /*
478 * In case 'lines' is set in _vimrc/_gvimrc window width doesn't
479 * seem to have been set yet, so menu wraps in default window
480 * width which is very narrow. Instead just return height of a
481 * single menu item. Will still be wrong when the menu really
482 * should wrap over more than one line.
483 */
484 GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1);
485 if (gui.starting)
486 menu_height = rc1.bottom - rc1.top + 1;
487 else
488 {
489 GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2);
490 menu_height = rc2.bottom - rc1.top + 1;
491 }
492 }
493 }
494
495 if (fix_window && menu_height != old_menu_height)
496 {
497 old_menu_height = menu_height;
Bram Moolenaarafa24992006-03-27 20:58:26 +0000498 gui_set_shellsize(FALSE, FALSE, RESIZE_VERT);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000499 }
500
501 return menu_height;
502}
503#endif /*FEAT_MENU*/
504
505
506/*
507 * Setup for the Intellimouse
508 */
509 static void
510init_mouse_wheel(void)
511{
512
513#ifndef SPI_GETWHEELSCROLLLINES
514# define SPI_GETWHEELSCROLLLINES 104
515#endif
Bram Moolenaare7566042005-06-17 22:00:15 +0000516#ifndef SPI_SETWHEELSCROLLLINES
517# define SPI_SETWHEELSCROLLLINES 105
518#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000519
520#define VMOUSEZ_CLASSNAME "MouseZ" /* hidden wheel window class */
521#define VMOUSEZ_TITLE "Magellan MSWHEEL" /* hidden wheel window title */
522#define VMSH_MOUSEWHEEL "MSWHEEL_ROLLMSG"
523#define VMSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG"
524
525 HWND hdl_mswheel;
526 UINT msh_msgscrolllines;
527
528 msh_msgmousewheel = 0;
529 mouse_scroll_lines = 3; /* reasonable default */
530
531 if ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
532 && os_version.dwMajorVersion >= 4)
533 || (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
534 && ((os_version.dwMajorVersion == 4
535 && os_version.dwMinorVersion >= 10)
536 || os_version.dwMajorVersion >= 5)))
537 {
538 /* if NT 4.0+ (or Win98) get scroll lines directly from system */
539 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
540 &mouse_scroll_lines, 0);
541 }
542 else if (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
543 || (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
544 && os_version.dwMajorVersion < 4))
545 { /*
546 * If Win95 or NT 3.51,
547 * try to find the hidden point32 window.
548 */
549 hdl_mswheel = FindWindow(VMOUSEZ_CLASSNAME, VMOUSEZ_TITLE);
550 if (hdl_mswheel)
551 {
552 msh_msgscrolllines = RegisterWindowMessage(VMSH_SCROLL_LINES);
553 if (msh_msgscrolllines)
554 {
555 mouse_scroll_lines = (int)SendMessage(hdl_mswheel,
556 msh_msgscrolllines, 0, 0);
557 msh_msgmousewheel = RegisterWindowMessage(VMSH_MOUSEWHEEL);
558 }
559 }
560 }
561}
562
563
564/* Intellimouse wheel handler */
565 static void
566_OnMouseWheel(
567 HWND hwnd,
568 short zDelta)
569{
570/* Treat a mouse wheel event as if it were a scroll request */
571 int i;
572 int size;
573 HWND hwndCtl;
574
575 if (curwin->w_scrollbars[SBAR_RIGHT].id != 0)
576 {
577 hwndCtl = curwin->w_scrollbars[SBAR_RIGHT].id;
578 size = curwin->w_scrollbars[SBAR_RIGHT].size;
579 }
580 else if (curwin->w_scrollbars[SBAR_LEFT].id != 0)
581 {
582 hwndCtl = curwin->w_scrollbars[SBAR_LEFT].id;
583 size = curwin->w_scrollbars[SBAR_LEFT].size;
584 }
585 else
586 return;
587
588 size = curwin->w_height;
589 if (mouse_scroll_lines == 0)
590 init_mouse_wheel();
591
592 if (mouse_scroll_lines > 0
593 && mouse_scroll_lines < (size > 2 ? size - 2 : 1))
594 {
595 for (i = mouse_scroll_lines; i > 0; --i)
596 _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_LINEUP : SB_LINEDOWN, 0);
597 }
598 else
599 _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0);
600}
601
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000602#ifdef USE_SYSMENU_FONT
603/*
604 * Get Menu Font.
605 * Return OK or FAIL.
606 */
607 static int
608gui_w32_get_menu_font(LOGFONT *lf)
609{
610 NONCLIENTMETRICS nm;
611
612 nm.cbSize = sizeof(NONCLIENTMETRICS);
613 if (!SystemParametersInfo(
614 SPI_GETNONCLIENTMETRICS,
615 sizeof(NONCLIENTMETRICS),
616 &nm,
617 0))
618 return FAIL;
619 *lf = nm.lfMenuFont;
620 return OK;
621}
622#endif
623
624
625#if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
626/*
627 * Set the GUI tabline font to the system menu font
628 */
629 static void
630set_tabline_font(void)
631{
632 LOGFONT lfSysmenu;
633 HFONT font;
634 HWND hwnd;
635 HDC hdc;
636 HFONT hfntOld;
637 TEXTMETRIC tm;
638
639 if (gui_w32_get_menu_font(&lfSysmenu) != OK)
640 return;
641
642 font = CreateFontIndirect(&lfSysmenu);
643
644 SendMessage(s_tabhwnd, WM_SETFONT, (WPARAM)font, TRUE);
645
646 /*
647 * Compute the height of the font used for the tab text
648 */
649 hwnd = GetDesktopWindow();
650 hdc = GetWindowDC(hwnd);
651 hfntOld = SelectFont(hdc, font);
652
653 GetTextMetrics(hdc, &tm);
654
655 SelectFont(hdc, hfntOld);
656 ReleaseDC(hwnd, hdc);
657
658 /*
659 * The space used by the tab border and the space between the tab label
660 * and the tab border is included as 7.
661 */
662 gui.tabline_height = tm.tmHeight + tm.tmInternalLeading + 7;
663}
664#endif
665
Bram Moolenaar520470a2005-06-16 21:59:56 +0000666/*
667 * Invoked when a setting was changed.
668 */
669 static LRESULT CALLBACK
670_OnSettingChange(UINT n)
671{
672 if (n == SPI_SETWHEELSCROLLLINES)
673 SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0,
674 &mouse_scroll_lines, 0);
Bram Moolenaar551dbcc2006-04-25 22:13:59 +0000675#if defined(FEAT_GUI_TABLINE) && defined(USE_SYSMENU_FONT)
676 if (n == SPI_SETNONCLIENTMETRICS)
677 set_tabline_font();
678#endif
Bram Moolenaar520470a2005-06-16 21:59:56 +0000679 return 0;
680}
681
Bram Moolenaar071d4272004-06-13 20:20:40 +0000682#if 0 /* disabled, a gap appears below and beside the window, and the window
683 can be moved (in a strange way) */
684/*
685 * Even though we have _DuringSizing() which makes the rubber band a valid
686 * size, we need this for when the user maximises the window.
687 * TODO: Doesn't seem to adjust the width though for some reason.
688 */
689 static BOOL
690_OnWindowPosChanging(
691 HWND hwnd,
692 LPWINDOWPOS lpwpos)
693{
694 RECT workarea_rect;
695
696 if (!(lpwpos->flags & SWP_NOSIZE))
697 {
698 if (IsMaximized(hwnd)
699 && (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
700 || (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
701 && os_version.dwMajorVersion >= 4)))
702 {
703 SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rect, 0);
704 lpwpos->x = workarea_rect.left;
705 lpwpos->y = workarea_rect.top;
706 lpwpos->cx = workarea_rect.right - workarea_rect.left;
707 lpwpos->cy = workarea_rect.bottom - workarea_rect.top;
708 }
709 gui_mswin_get_valid_dimensions(lpwpos->cx, lpwpos->cy,
710 &lpwpos->cx, &lpwpos->cy);
711 }
712 return 0;
713}
714#endif
715
716#ifdef FEAT_NETBEANS_INTG
717 static void
718_OnWindowPosChanged(
719 HWND hwnd,
720 const LPWINDOWPOS lpwpos)
721{
722 static int x = 0, y = 0, cx = 0, cy = 0;
723
724 if (WSInitialized && (lpwpos->x != x || lpwpos->y != y
725 || lpwpos->cx != cx || lpwpos->cy != cy))
726 {
727 x = lpwpos->x;
728 y = lpwpos->y;
729 cx = lpwpos->cx;
730 cy = lpwpos->cy;
731 netbeans_frame_moved(x, y);
732 }
733 /* Allow to send WM_SIZE and WM_MOVE */
734 FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, MyWindowProc);
735}
736#endif
737
738 static int
739_DuringSizing(
Bram Moolenaar071d4272004-06-13 20:20:40 +0000740 UINT fwSide,
741 LPRECT lprc)
742{
743 int w, h;
744 int valid_w, valid_h;
745 int w_offset, h_offset;
746
747 w = lprc->right - lprc->left;
748 h = lprc->bottom - lprc->top;
749 gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h);
750 w_offset = w - valid_w;
751 h_offset = h - valid_h;
752
753 if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT
754 || fwSide == WMSZ_BOTTOMLEFT)
755 lprc->left += w_offset;
756 else if (fwSide == WMSZ_RIGHT || fwSide == WMSZ_TOPRIGHT
757 || fwSide == WMSZ_BOTTOMRIGHT)
758 lprc->right -= w_offset;
759
760 if (fwSide == WMSZ_TOP || fwSide == WMSZ_TOPLEFT
761 || fwSide == WMSZ_TOPRIGHT)
762 lprc->top += h_offset;
763 else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT
764 || fwSide == WMSZ_BOTTOMRIGHT)
765 lprc->bottom -= h_offset;
766 return TRUE;
767}
768
769
770
771 static LRESULT CALLBACK
772_WndProc(
773 HWND hwnd,
774 UINT uMsg,
775 WPARAM wParam,
776 LPARAM lParam)
777{
778 /*
779 TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n",
780 hwnd, uMsg, wParam, lParam);
781 */
782
783 HandleMouseHide(uMsg, lParam);
784
785 s_uMsg = uMsg;
786 s_wParam = wParam;
787 s_lParam = lParam;
788
789 switch (uMsg)
790 {
791 HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar);
792 HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar);
793 /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */
794 HANDLE_MSG(hwnd, WM_CLOSE, _OnClose);
795 /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */
796 HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy);
797 HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles);
798 HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll);
799 HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus);
800#ifdef FEAT_MENU
801 HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu);
802#endif
803 /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */
804 /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */
805 HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus);
806 HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
807 /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */
808 /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */
809 HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll);
810 // HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging);
811 HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp);
812#ifdef FEAT_NETBEANS_INTG
813 HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, _OnWindowPosChanged);
814#endif
815
Bram Moolenaarafa24992006-03-27 20:58:26 +0000816#ifdef FEAT_GUI_TABLINE
817 case WM_RBUTTONUP:
818 {
819 if (gui_mch_showing_tabline())
820 {
821 POINT pt;
822 RECT rect;
823
824 /*
825 * If the cursor is on the tabline, display the tab menu
826 */
827 GetCursorPos((LPPOINT)&pt);
828 GetWindowRect(s_textArea, &rect);
829 if (pt.y < rect.top)
830 {
831 show_tabline_popup_menu();
832 return 0;
833 }
834 }
835 return MyWindowProc(hwnd, uMsg, wParam, lParam);
836 }
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000837 case WM_LBUTTONDBLCLK:
838 {
839 /*
840 * If the user double clicked the tabline, create a new tab
841 */
842 if (gui_mch_showing_tabline())
843 {
844 POINT pt;
845 RECT rect;
846
847 GetCursorPos((LPPOINT)&pt);
848 GetWindowRect(s_textArea, &rect);
849 if (pt.y < rect.top)
Bram Moolenaarc6fe9192006-04-09 21:54:49 +0000850 send_tabline_menu_event(0, TABLINE_MENU_NEW);
Bram Moolenaar910f66f2006-04-05 20:41:53 +0000851 }
852 return MyWindowProc(hwnd, uMsg, wParam, lParam);
853 }
Bram Moolenaarafa24992006-03-27 20:58:26 +0000854#endif
855
Bram Moolenaar071d4272004-06-13 20:20:40 +0000856 case WM_QUERYENDSESSION: /* System wants to go down. */
857 gui_shell_closed(); /* Will exit when no changed buffers. */
858 return FALSE; /* Do NOT allow system to go down. */
859
860 case WM_ENDSESSION:
861 if (wParam) /* system only really goes down when wParam is TRUE */
862 _OnEndSession();
863 break;
864
865 case WM_CHAR:
866 /* Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single
867 * byte while we want the UTF-16 character value. */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000868 _OnChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000869 return 0L;
870
871 case WM_SYSCHAR:
872 /*
873 * if 'winaltkeys' is "no", or it's "menu" and it's not a menu
874 * shortcut key, handle like a typed ALT key, otherwise call Windows
875 * ALT key handling.
876 */
877#ifdef FEAT_MENU
878 if ( !gui.menu_is_active
879 || p_wak[0] == 'n'
880 || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam))
881 )
882#endif
883 {
Bram Moolenaara93fa7e2006-04-17 22:14:47 +0000884 _OnSysChar(hwnd, (UINT)wParam, (int)(short)LOWORD(lParam));
Bram Moolenaar071d4272004-06-13 20:20:40 +0000885 return 0L;
886 }
887#ifdef FEAT_MENU
888 else
889 return MyWindowProc(hwnd, uMsg, wParam, lParam);
890#endif
891
892 case WM_SYSKEYUP:
893#ifdef FEAT_MENU
894 /* This used to be done only when menu is active: ALT key is used for
895 * that. But that caused problems when menu is disabled and using
896 * Alt-Tab-Esc: get into a strange state where no mouse-moved events
897 * are received, mouse pointer remains hidden. */
898 return MyWindowProc(hwnd, uMsg, wParam, lParam);
899#else
900 return 0;
901#endif
902
903 case WM_SIZING: /* HANDLE_MSG doesn't seem to handle this one */
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +0000904 return _DuringSizing((UINT)wParam, (LPRECT)lParam);
Bram Moolenaar071d4272004-06-13 20:20:40 +0000905
906 case WM_MOUSEWHEEL:
907 _OnMouseWheel(hwnd, HIWORD(wParam));
908 break;
909
Bram Moolenaar520470a2005-06-16 21:59:56 +0000910 /* Notification for change in SystemParametersInfo() */
911 case WM_SETTINGCHANGE:
912 return _OnSettingChange((UINT)wParam);
913
Bram Moolenaar3991dab2006-03-27 17:01:56 +0000914#if defined(FEAT_TOOLBAR) || defined(FEAT_GUI_TABLINE)
Bram Moolenaar071d4272004-06-13 20:20:40 +0000915 case WM_NOTIFY:
916 switch (((LPNMHDR) lParam)->code)
917 {
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000918# ifdef FEAT_MBYTE
919 case TTN_GETDISPINFOW:
920# endif
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000921 case TTN_GETDISPINFO:
Bram Moolenaar071d4272004-06-13 20:20:40 +0000922 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000923 LPNMHDR hdr = (LPNMHDR)lParam;
924 char_u *str = NULL;
925 static void *tt_text = NULL;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000926
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000927 vim_free(tt_text);
928 tt_text = NULL;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000929
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000930# ifdef FEAT_GUI_TABLINE
931 if (gui_mch_showing_tabline()
932 && hdr->hwndFrom == TabCtrl_GetToolTips(s_tabhwnd))
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000933 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000934 POINT pt;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000935 /*
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000936 * Mouse is over the GUI tabline. Display the
937 * tooltip for the tab under the cursor
938 *
939 * Get the cursor position within the tab control
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000940 */
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000941 GetCursorPos(&pt);
942 if (ScreenToClient(s_tabhwnd, &pt) != 0)
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000943 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000944 TCHITTESTINFO htinfo;
945 int idx;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000946
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000947 /*
948 * Get the tab under the cursor
949 */
950 htinfo.pt.x = pt.x;
951 htinfo.pt.y = pt.y;
952 idx = TabCtrl_HitTest(s_tabhwnd, &htinfo);
953 if (idx != -1)
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000954 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000955 tabpage_T *tp;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000956
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000957 tp = find_tabpage(idx + 1);
958 if (tp != NULL)
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000959 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000960 get_tabline_label(tp, TRUE);
961 str = NameBuff;
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000962 }
963 }
964 }
965 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000966# endif
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000967# ifdef FEAT_TOOLBAR
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000968# ifdef FEAT_GUI_TABLINE
969 else
970# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +0000971 {
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000972 UINT idButton;
973 vimmenu_T *pMenu;
974
975 idButton = (UINT) hdr->idFrom;
976 pMenu = gui_mswin_find_menu(root_menu, idButton);
977 if (pMenu)
978 str = pMenu->strings[MENU_INDEX_TIP];
Bram Moolenaar071d4272004-06-13 20:20:40 +0000979 }
Bram Moolenaareb3593b2006-04-22 22:33:57 +0000980# endif
Bram Moolenaar8f2ff9f2006-08-29 19:26:50 +0000981 if (str != NULL)
982 {
983# ifdef FEAT_MBYTE
984 if (hdr->code == TTN_GETDISPINFOW)
985 {
986 LPNMTTDISPINFOW lpdi = (LPNMTTDISPINFOW)lParam;
987
988 tt_text = enc_to_ucs2(str, NULL);
989 lpdi->lpszText = tt_text;
990 /* can't show tooltip if failed */
991 }
992 else
993# endif
994 {
995 LPNMTTDISPINFO lpdi = (LPNMTTDISPINFO)lParam;
996
997 if (STRLEN(str) < sizeof(lpdi->szText)
998 || ((tt_text = vim_strsave(str)) == NULL))
999 vim_strncpy(lpdi->szText, str,
1000 sizeof(lpdi->szText) - 1);
1001 else
1002 lpdi->lpszText = tt_text;
1003 }
1004 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00001005 }
1006 break;
Bram Moolenaar3991dab2006-03-27 17:01:56 +00001007# ifdef FEAT_GUI_TABLINE
1008 case TCN_SELCHANGE:
1009 if (gui_mch_showing_tabline()
1010 && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
1011 send_tabline_event(TabCtrl_GetCurSel(s_tabhwnd) + 1);
1012 break;
Bram Moolenaarafa24992006-03-27 20:58:26 +00001013
1014 case NM_RCLICK:
1015 if (gui_mch_showing_tabline()
1016 && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
1017 show_tabline_popup_menu();
1018 break;
Bram Moolenaar3991dab2006-03-27 17:01:56 +00001019# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001020 default:
Bram Moolenaar3991dab2006-03-27 17:01:56 +00001021# ifdef FEAT_GUI_TABLINE
1022 if (gui_mch_showing_tabline()
1023 && ((LPNMHDR)lParam)->hwndFrom == s_tabhwnd)
1024 return MyWindowProc(hwnd, uMsg, wParam, lParam);
1025# endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001026 break;
1027 }
1028 break;
1029#endif
1030#if defined(MENUHINTS) && defined(FEAT_MENU)
1031 case WM_MENUSELECT:
1032 if (((UINT) HIWORD(wParam)
1033 & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP)))
1034 == MF_HILITE
1035 && (State & CMDLINE) == 0)
1036 {
1037 UINT idButton;
1038 vimmenu_T *pMenu;
1039 static int did_menu_tip = FALSE;
1040
1041 if (did_menu_tip)
1042 {
1043 msg_clr_cmdline();
1044 setcursor();
1045 out_flush();
1046 did_menu_tip = FALSE;
1047 }
1048
1049 idButton = (UINT)LOWORD(wParam);
1050 pMenu = gui_mswin_find_menu(root_menu, idButton);
1051 if (pMenu != NULL && pMenu->strings[MENU_INDEX_TIP] != 0
1052 && GetMenuState(s_menuBar, pMenu->id, MF_BYCOMMAND) != -1)
1053 {
Bram Moolenaar2d8ab992007-06-19 08:06:18 +00001054 ++msg_hist_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001055 msg(pMenu->strings[MENU_INDEX_TIP]);
Bram Moolenaar2d8ab992007-06-19 08:06:18 +00001056 --msg_hist_off;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001057 setcursor();
1058 out_flush();
1059 did_menu_tip = TRUE;
1060 }
1061 }
1062 break;
1063#endif
1064 case WM_NCHITTEST:
1065 {
1066 LRESULT result;
1067 int x, y;
1068 int xPos = GET_X_LPARAM(lParam);
1069
1070 result = MyWindowProc(hwnd, uMsg, wParam, lParam);
1071 if (result == HTCLIENT)
1072 {
Bram Moolenaar3991dab2006-03-27 17:01:56 +00001073#ifdef FEAT_GUI_TABLINE
1074 if (gui_mch_showing_tabline())
1075 {
1076 int yPos = GET_Y_LPARAM(lParam);
1077 RECT rct;
1078
1079 /* If the cursor is on the GUI tabline, don't process this
1080 * event */
1081 GetWindowRect(s_textArea, &rct);
1082 if (yPos < rct.top)
1083 return result;
1084 }
1085#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001086 gui_mch_get_winpos(&x, &y);
1087 xPos -= x;
1088
1089 if (xPos < 48) /* <VN> TODO should use system metric? */
1090 return HTBOTTOMLEFT;
1091 else
1092 return HTBOTTOMRIGHT;
1093 }
1094 else
1095 return result;
1096 }
1097 /* break; notreached */
1098
1099#ifdef FEAT_MBYTE_IME
1100 case WM_IME_NOTIFY:
1101 if (!_OnImeNotify(hwnd, (DWORD)wParam, (DWORD)lParam))
1102 return MyWindowProc(hwnd, uMsg, wParam, lParam);
1103 break;
1104 case WM_IME_COMPOSITION:
1105 if (!_OnImeComposition(hwnd, wParam, lParam))
1106 return MyWindowProc(hwnd, uMsg, wParam, lParam);
1107 break;
1108#endif
1109
1110 default:
1111 if (uMsg == msh_msgmousewheel && msh_msgmousewheel != 0)
1112 { /* handle MSH_MOUSEWHEEL messages for Intellimouse */
1113 _OnMouseWheel(hwnd, HIWORD(wParam));
1114 break;
1115 }
1116#ifdef MSWIN_FIND_REPLACE
Bram Moolenaar293ee4d2004-12-09 21:34:53 +00001117 else if (uMsg == s_findrep_msg && s_findrep_msg != 0)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001118 {
1119 _OnFindRepl();
1120 }
1121#endif
1122 return MyWindowProc(hwnd, uMsg, wParam, lParam);
1123 }
1124
1125 return 1;
1126}
1127
1128/*
1129 * End of call-back routines
1130 */
1131
1132/* parent window, if specified with -P */
1133HWND vim_parent_hwnd = NULL;
1134
1135 static BOOL CALLBACK
1136FindWindowTitle(HWND hwnd, LPARAM lParam)
1137{
1138 char buf[2048];
1139 char *title = (char *)lParam;
1140
1141 if (GetWindowText(hwnd, buf, sizeof(buf)))
1142 {
1143 if (strstr(buf, title) != NULL)
1144 {
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001145 /* Found it. Store the window ref. and quit searching if MDI
1146 * works. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001147 vim_parent_hwnd = FindWindowEx(hwnd, NULL, "MDIClient", NULL);
Bram Moolenaar69a7cb42004-06-20 12:51:53 +00001148 if (vim_parent_hwnd != NULL)
1149 return FALSE;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001150 }
1151 }
1152 return TRUE; /* continue searching */
1153}
1154
1155/*
1156 * Invoked for '-P "title"' argument: search for parent application to open
1157 * our window in.
1158 */
1159 void
1160gui_mch_set_parent(char *title)
1161{
1162 EnumWindows(FindWindowTitle, (LPARAM)title);
1163 if (vim_parent_hwnd == NULL)
1164 {
1165 EMSG2(_("E671: Cannot find window title \"%s\""), title);
1166 mch_exit(2);
1167 }
1168}
1169
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00001170#ifndef FEAT_OLE
Bram Moolenaar071d4272004-06-13 20:20:40 +00001171 static void
1172ole_error(char *arg)
1173{
Bram Moolenaaraea02fa2007-05-04 20:29:09 +00001174 char buf[IOSIZE];
1175
1176 /* Can't use EMSG() here, we have not finished initialisation yet. */
1177 vim_snprintf(buf, IOSIZE,
1178 _("E243: Argument not supported: \"-%s\"; Use the OLE version."),
1179 arg);
1180 mch_errmsg(buf);
Bram Moolenaar071d4272004-06-13 20:20:40 +00001181}
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00001182#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001183
1184/*
1185 * Parse the GUI related command-line arguments. Any arguments used are
1186 * deleted from argv, and *argc is decremented accordingly. This is called
1187 * when vim is started, whether or not the GUI has been started.
1188 */
1189 void
1190gui_mch_prepare(int *argc, char **argv)
1191{
1192 int silent = FALSE;
1193 int idx;
1194
1195 /* Check for special OLE command line parameters */
1196 if ((*argc == 2 || *argc == 3) && (argv[1][0] == '-' || argv[1][0] == '/'))
1197 {
1198 /* Check for a "-silent" argument first. */
1199 if (*argc == 3 && STRICMP(argv[1] + 1, "silent") == 0
1200 && (argv[2][0] == '-' || argv[2][0] == '/'))
1201 {
1202 silent = TRUE;
1203 idx = 2;
1204 }
1205 else
1206 idx = 1;
1207
1208 /* Register Vim as an OLE Automation server */
1209 if (STRICMP(argv[idx] + 1, "register") == 0)
1210 {
1211#ifdef FEAT_OLE
1212 RegisterMe(silent);
1213 mch_exit(0);
1214#else
1215 if (!silent)
1216 ole_error("register");
1217 mch_exit(2);
1218#endif
1219 }
1220
1221 /* Unregister Vim as an OLE Automation server */
1222 if (STRICMP(argv[idx] + 1, "unregister") == 0)
1223 {
1224#ifdef FEAT_OLE
1225 UnregisterMe(!silent);
1226 mch_exit(0);
1227#else
1228 if (!silent)
1229 ole_error("unregister");
1230 mch_exit(2);
1231#endif
1232 }
1233
1234 /* Ignore an -embedding argument. It is only relevant if the
1235 * application wants to treat the case when it is started manually
1236 * differently from the case where it is started via automation (and
1237 * we don't).
1238 */
1239 if (STRICMP(argv[idx] + 1, "embedding") == 0)
1240 {
1241#ifdef FEAT_OLE
1242 *argc = 1;
1243#else
1244 ole_error("embedding");
1245 mch_exit(2);
1246#endif
1247 }
1248 }
1249
1250#ifdef FEAT_OLE
1251 {
1252 int bDoRestart = FALSE;
1253
1254 InitOLE(&bDoRestart);
1255 /* automatically exit after registering */
1256 if (bDoRestart)
1257 mch_exit(0);
1258 }
1259#endif
1260
1261#ifdef FEAT_NETBEANS_INTG
1262 {
1263 /* stolen from gui_x11.x */
1264 int arg;
1265
1266 for (arg = 1; arg < *argc; arg++)
1267 if (strncmp("-nb", argv[arg], 3) == 0)
1268 {
1269 usingNetbeans++;
1270 netbeansArg = argv[arg];
1271 mch_memmove(&argv[arg], &argv[arg + 1],
1272 (--*argc - arg) * sizeof(char *));
1273 argv[*argc] = NULL;
1274 break; /* enough? */
1275 }
1276
1277 if (usingNetbeans)
1278 {
1279 WSADATA wsaData;
1280 int wsaerr;
1281
1282 /* Init WinSock */
1283 wsaerr = WSAStartup(MAKEWORD(2, 2), &wsaData);
1284 if (wsaerr == 0)
1285 WSInitialized = TRUE;
1286 }
1287 }
1288#endif
1289
1290 /* get the OS version info */
1291 os_version.dwOSVersionInfoSize = sizeof(os_version);
1292 GetVersionEx(&os_version); /* this call works on Win32s, Win95 and WinNT */
1293
1294 /* try and load the user32.dll library and get the entry points for
1295 * multi-monitor-support. */
1296 if ((user32_lib = LoadLibrary("User32.dll")) != NULL)
1297 {
1298 pMonitorFromWindow = (TMonitorFromWindow)GetProcAddress(user32_lib,
1299 "MonitorFromWindow");
1300
1301 /* there are ...A and ...W version of GetMonitorInfo - looking at
1302 * winuser.h, they have exactly the same declaration. */
1303 pGetMonitorInfo = (TGetMonitorInfo)GetProcAddress(user32_lib,
1304 "GetMonitorInfoA");
1305 }
1306}
1307
1308/*
1309 * Initialise the GUI. Create all the windows, set up all the call-backs
1310 * etc.
1311 */
1312 int
1313gui_mch_init(void)
1314{
1315 const char szVimWndClass[] = VIM_CLASS;
1316 const char szTextAreaClass[] = "VimTextArea";
1317 WNDCLASS wndclass;
1318#ifdef FEAT_MBYTE
1319 const WCHAR szVimWndClassW[] = VIM_CLASSW;
1320 WNDCLASSW wndclassw;
1321#endif
1322#ifdef GLOBAL_IME
1323 ATOM atom;
1324#endif
1325
Bram Moolenaar071d4272004-06-13 20:20:40 +00001326 /* Return here if the window was already opened (happens when
1327 * gui_mch_dialog() is called early). */
1328 if (s_hwnd != NULL)
Bram Moolenaar748bf032005-02-02 23:04:36 +00001329 goto theend;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001330
1331 /*
1332 * Load the tearoff bitmap
1333 */
1334#ifdef FEAT_TEAROFF
1335 s_htearbitmap = LoadBitmap(s_hinst, "IDB_TEAROFF");
1336#endif
1337
1338 gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL);
1339 gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL);
1340#ifdef FEAT_MENU
1341 gui.menu_height = 0; /* Windows takes care of this */
1342#endif
1343 gui.border_width = 0;
1344
1345 s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));
1346
1347#ifdef FEAT_MBYTE
1348 /* First try using the wide version, so that we can use any title.
1349 * Otherwise only characters in the active codepage will work. */
1350 if (GetClassInfoW(s_hinst, szVimWndClassW, &wndclassw) == 0)
1351 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001352 wndclassw.style = CS_DBLCLKS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001353 wndclassw.lpfnWndProc = _WndProc;
1354 wndclassw.cbClsExtra = 0;
1355 wndclassw.cbWndExtra = 0;
1356 wndclassw.hInstance = s_hinst;
1357 wndclassw.hIcon = LoadIcon(wndclassw.hInstance, "IDR_VIM");
1358 wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW);
1359 wndclassw.hbrBackground = s_brush;
1360 wndclassw.lpszMenuName = NULL;
1361 wndclassw.lpszClassName = szVimWndClassW;
1362
1363 if ((
1364#ifdef GLOBAL_IME
1365 atom =
1366#endif
1367 RegisterClassW(&wndclassw)) == 0)
1368 {
1369 if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
1370 return FAIL;
1371
1372 /* Must be Windows 98, fall back to non-wide function. */
1373 }
1374 else
1375 wide_WindowProc = TRUE;
1376 }
1377
1378 if (!wide_WindowProc)
1379#endif
1380
1381 if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0)
1382 {
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001383 wndclass.style = CS_DBLCLKS;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001384 wndclass.lpfnWndProc = _WndProc;
1385 wndclass.cbClsExtra = 0;
1386 wndclass.cbWndExtra = 0;
1387 wndclass.hInstance = s_hinst;
1388 wndclass.hIcon = LoadIcon(wndclass.hInstance, "IDR_VIM");
1389 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
1390 wndclass.hbrBackground = s_brush;
1391 wndclass.lpszMenuName = NULL;
1392 wndclass.lpszClassName = szVimWndClass;
1393
1394 if ((
1395#ifdef GLOBAL_IME
1396 atom =
1397#endif
1398 RegisterClass(&wndclass)) == 0)
1399 return FAIL;
1400 }
1401
1402 if (vim_parent_hwnd != NULL)
1403 {
1404#ifdef HAVE_TRY_EXCEPT
1405 __try
1406 {
1407#endif
1408 /* Open inside the specified parent window.
1409 * TODO: last argument should point to a CLIENTCREATESTRUCT
1410 * structure. */
1411 s_hwnd = CreateWindowEx(
1412 WS_EX_MDICHILD,
1413 szVimWndClass, "Vim MSWindows GUI",
1414 WS_OVERLAPPEDWINDOW | WS_CHILD | WS_CLIPSIBLINGS | 0xC000,
1415 gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
1416 gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
1417 100, /* Any value will do */
1418 100, /* Any value will do */
1419 vim_parent_hwnd, NULL,
1420 s_hinst, NULL);
1421#ifdef HAVE_TRY_EXCEPT
1422 }
1423 __except(EXCEPTION_EXECUTE_HANDLER)
1424 {
1425 /* NOP */
1426 }
1427#endif
1428 if (s_hwnd == NULL)
1429 {
1430 EMSG(_("E672: Unable to open window inside MDI application"));
1431 mch_exit(2);
1432 }
1433 }
1434 else
1435 /* Open toplevel window. */
1436 s_hwnd = CreateWindow(
1437 szVimWndClass, "Vim MSWindows GUI",
1438 WS_OVERLAPPEDWINDOW,
1439 gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x,
1440 gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y,
1441 100, /* Any value will do */
1442 100, /* Any value will do */
1443 NULL, NULL,
1444 s_hinst, NULL);
1445
1446 if (s_hwnd == NULL)
1447 return FAIL;
1448
1449#ifdef GLOBAL_IME
1450 global_ime_init(atom, s_hwnd);
1451#endif
1452#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
1453 dyn_imm_load();
1454#endif
1455
1456 /* Create the text area window */
1457 if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0)
1458 {
1459 wndclass.style = CS_OWNDC;
1460 wndclass.lpfnWndProc = _TextAreaWndProc;
1461 wndclass.cbClsExtra = 0;
1462 wndclass.cbWndExtra = 0;
1463 wndclass.hInstance = s_hinst;
1464 wndclass.hIcon = NULL;
1465 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
1466 wndclass.hbrBackground = NULL;
1467 wndclass.lpszMenuName = NULL;
1468 wndclass.lpszClassName = szTextAreaClass;
1469
1470 if (RegisterClass(&wndclass) == 0)
1471 return FAIL;
1472 }
1473 s_textArea = CreateWindowEx(
1474 WS_EX_CLIENTEDGE,
1475 szTextAreaClass, "Vim text area",
1476 WS_CHILD | WS_VISIBLE, 0, 0,
1477 100, /* Any value will do for now */
1478 100, /* Any value will do for now */
1479 s_hwnd, NULL,
1480 s_hinst, NULL);
1481
1482 if (s_textArea == NULL)
1483 return FAIL;
1484
1485#ifdef FEAT_MENU
1486 s_menuBar = CreateMenu();
1487#endif
1488 s_hdc = GetDC(s_textArea);
1489
1490#ifdef MSWIN16_FASTTEXT
1491 SetBkMode(s_hdc, OPAQUE);
1492#endif
1493
1494#ifdef FEAT_WINDOWS
1495 DragAcceptFiles(s_hwnd, TRUE);
1496#endif
1497
1498 /* Do we need to bother with this? */
1499 /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */
1500
1501 /* Get background/foreground colors from the system */
1502 gui_mch_def_colors();
1503
1504 /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc
1505 * file) */
1506 set_normal_colors();
1507
1508 /*
1509 * Check that none of the colors are the same as the background color.
1510 * Then store the current values as the defaults.
1511 */
1512 gui_check_colors();
1513 gui.def_norm_pixel = gui.norm_pixel;
1514 gui.def_back_pixel = gui.back_pixel;
1515
1516 /* Get the colors for the highlight groups (gui_check_colors() might have
1517 * changed them) */
1518 highlight_gui_started();
1519
1520 /*
1521 * Start out by adding the configured border width into the border offset
1522 */
1523 gui.border_offset = gui.border_width + 2; /*CLIENT EDGE*/
1524
1525 /*
1526 * Set up for Intellimouse processing
1527 */
1528 init_mouse_wheel();
1529
1530 /*
1531 * compute a couple of metrics used for the dialogs
1532 */
1533 get_dialog_font_metrics();
1534#ifdef FEAT_TOOLBAR
1535 /*
1536 * Create the toolbar
1537 */
1538 initialise_toolbar();
1539#endif
Bram Moolenaar3991dab2006-03-27 17:01:56 +00001540#ifdef FEAT_GUI_TABLINE
1541 /*
1542 * Create the tabline
1543 */
1544 initialise_tabline();
1545#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001546#ifdef MSWIN_FIND_REPLACE
1547 /*
1548 * Initialise the dialog box stuff
1549 */
1550 s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING);
1551
1552 /* Initialise the struct */
1553 s_findrep_struct.lStructSize = sizeof(s_findrep_struct);
1554 s_findrep_struct.lpstrFindWhat = alloc(MSWIN_FR_BUFSIZE);
1555 s_findrep_struct.lpstrFindWhat[0] = NUL;
1556 s_findrep_struct.lpstrReplaceWith = alloc(MSWIN_FR_BUFSIZE);
1557 s_findrep_struct.lpstrReplaceWith[0] = NUL;
1558 s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE;
1559 s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE;
1560#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00001561
Bram Moolenaar748bf032005-02-02 23:04:36 +00001562theend:
1563 /* Display any pending error messages */
1564 display_errors();
1565
Bram Moolenaar071d4272004-06-13 20:20:40 +00001566 return OK;
1567}
1568
1569/*
1570 * Get the size of the screen, taking position on multiple monitors into
1571 * account (if supported).
1572 */
1573 static void
1574get_work_area(RECT *spi_rect)
1575{
1576 _HMONITOR mon;
1577 _MONITORINFO moninfo;
1578
1579 /* use these functions only if available */
1580 if (pMonitorFromWindow != NULL && pGetMonitorInfo != NULL)
1581 {
1582 /* work out which monitor the window is on, and get *it's* work area */
1583 mon = pMonitorFromWindow(s_hwnd, 1 /*MONITOR_DEFAULTTOPRIMARY*/);
1584 if (mon != NULL)
1585 {
1586 moninfo.cbSize = sizeof(_MONITORINFO);
1587 if (pGetMonitorInfo(mon, &moninfo))
1588 {
1589 *spi_rect = moninfo.rcWork;
1590 return;
1591 }
1592 }
1593 }
1594 /* this is the old method... */
1595 SystemParametersInfo(SPI_GETWORKAREA, 0, spi_rect, 0);
1596}
1597
1598/*
1599 * Set the size of the window to the given width and height in pixels.
1600 */
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00001601/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001602 void
1603gui_mch_set_shellsize(int width, int height,
Bram Moolenaarafa24992006-03-27 20:58:26 +00001604 int min_width, int min_height, int base_width, int base_height,
1605 int direction)
Bram Moolenaar071d4272004-06-13 20:20:40 +00001606{
1607 RECT workarea_rect;
1608 int win_width, win_height;
1609 int win_xpos, win_ypos;
1610 WINDOWPLACEMENT wndpl;
Bram Moolenaar56a907a2006-05-06 21:44:30 +00001611 int workarea_left;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001612
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001613 /* Try to keep window completely on screen. */
1614 /* Get position of the screen work area. This is the part that is not
1615 * used by the taskbar or appbars. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001616 get_work_area(&workarea_rect);
1617
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001618 /* Get current posision of our window. Note that the .left and .top are
1619 * relative to the work area. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00001620 wndpl.length = sizeof(WINDOWPLACEMENT);
1621 GetWindowPlacement(s_hwnd, &wndpl);
1622
1623 /* Resizing a maximized window looks very strange, unzoom it first.
1624 * But don't do it when still starting up, it may have been requested in
1625 * the shortcut. */
1626 if (wndpl.showCmd == SW_SHOWMAXIMIZED && starting == 0)
1627 {
1628 ShowWindow(s_hwnd, SW_SHOWNORMAL);
1629 /* Need to get the settings of the normal window. */
1630 GetWindowPlacement(s_hwnd, &wndpl);
1631 }
1632
1633 win_xpos = wndpl.rcNormalPosition.left;
1634 win_ypos = wndpl.rcNormalPosition.top;
1635
1636 /* compute the size of the outside of the window */
1637 win_width = width + GetSystemMetrics(SM_CXFRAME) * 2;
1638 win_height = height + GetSystemMetrics(SM_CYFRAME) * 2
1639 + GetSystemMetrics(SM_CYCAPTION)
1640#ifdef FEAT_MENU
1641 + gui_mswin_get_menu_height(FALSE)
1642#endif
1643 ;
1644
Bram Moolenaar56a907a2006-05-06 21:44:30 +00001645 /* There is an inconsistency when using two monitors and Vim is on the
1646 * second (right) one: win_xpos will be the offset from the workarea of
1647 * the left monitor. While with one monitor it's the offset from the
1648 * workarea (including a possible taskbar on the left). Detect the second
1649 * monitor by checking for the left offset to be quite big. */
1650 if (workarea_rect.left > 300)
1651 workarea_left = 0;
1652 else
1653 workarea_left = workarea_rect.left;
1654
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001655 /* If the window is going off the screen, move it on to the screen.
1656 * win_xpos and win_ypos are relative to the workarea. */
1657 if ((direction & RESIZE_HOR)
Bram Moolenaar56a907a2006-05-06 21:44:30 +00001658 && workarea_left + win_xpos + win_width > workarea_rect.right)
1659 win_xpos = workarea_rect.right - win_width - workarea_left;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001660
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001661 if ((direction & RESIZE_HOR) && win_xpos < 0)
1662 win_xpos = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001663
Bram Moolenaarafa24992006-03-27 20:58:26 +00001664 if ((direction & RESIZE_VERT)
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001665 && workarea_rect.top + win_ypos + win_height > workarea_rect.bottom)
1666 win_ypos = workarea_rect.bottom - win_height - workarea_rect.top;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001667
Bram Moolenaar910f66f2006-04-05 20:41:53 +00001668 if ((direction & RESIZE_VERT) && win_ypos < 0)
1669 win_ypos = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00001670
1671 wndpl.rcNormalPosition.left = win_xpos;
1672 wndpl.rcNormalPosition.right = win_xpos + win_width;
1673 wndpl.rcNormalPosition.top = win_ypos;
1674 wndpl.rcNormalPosition.bottom = win_ypos + win_height;
1675
1676 /* set window position - we should use SetWindowPlacement rather than
1677 * SetWindowPos as the MSDN docs say the coord systems returned by
1678 * these two are not compatible. */
1679 SetWindowPlacement(s_hwnd, &wndpl);
1680
1681 SetActiveWindow(s_hwnd);
1682 SetFocus(s_hwnd);
1683
1684#ifdef FEAT_MENU
1685 /* Menu may wrap differently now */
1686 gui_mswin_get_menu_height(!gui.starting);
1687#endif
1688}
1689
1690
1691 void
1692gui_mch_set_scrollbar_thumb(
1693 scrollbar_T *sb,
1694 long val,
1695 long size,
1696 long max)
1697{
1698 SCROLLINFO info;
1699
1700 sb->scroll_shift = 0;
1701 while (max > 32767)
1702 {
1703 max = (max + 1) >> 1;
1704 val >>= 1;
1705 size >>= 1;
1706 ++sb->scroll_shift;
1707 }
1708
1709 if (sb->scroll_shift > 0)
1710 ++size;
1711
1712 info.cbSize = sizeof(info);
1713 info.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;
1714 info.nPos = val;
1715 info.nMin = 0;
1716 info.nMax = max;
1717 info.nPage = size;
1718 SetScrollInfo(sb->id, SB_CTL, &info, TRUE);
1719}
1720
1721
1722/*
1723 * Set the current text font.
1724 */
1725 void
1726gui_mch_set_font(GuiFont font)
1727{
1728 gui.currFont = font;
1729}
1730
1731
1732/*
1733 * Set the current text foreground color.
1734 */
1735 void
1736gui_mch_set_fg_color(guicolor_T color)
1737{
1738 gui.currFgColor = color;
1739}
1740
1741/*
1742 * Set the current text background color.
1743 */
1744 void
1745gui_mch_set_bg_color(guicolor_T color)
1746{
1747 gui.currBgColor = color;
1748}
1749
Bram Moolenaare2cc9702005-03-15 22:43:58 +00001750/*
1751 * Set the current text special color.
1752 */
1753 void
1754gui_mch_set_sp_color(guicolor_T color)
1755{
1756 gui.currSpColor = color;
1757}
1758
Bram Moolenaar071d4272004-06-13 20:20:40 +00001759#if defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)
1760/*
1761 * Multi-byte handling, originally by Sung-Hoon Baek.
1762 * First static functions (no prototypes generated).
1763 */
1764#ifdef _MSC_VER
1765# include <ime.h> /* Apparently not needed for Cygwin, MingW or Borland. */
1766#endif
1767#include <imm.h>
1768
1769/*
Bram Moolenaar071d4272004-06-13 20:20:40 +00001770 * handle WM_IME_NOTIFY message
1771 */
Bram Moolenaard857f0e2005-06-21 22:37:39 +00001772/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001773 static LRESULT
1774_OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData)
1775{
1776 LRESULT lResult = 0;
1777 HIMC hImc;
1778
1779 if (!pImmGetContext || (hImc = pImmGetContext(hWnd)) == (HIMC)0)
1780 return lResult;
1781 switch (dwCommand)
1782 {
1783 case IMN_SETOPENSTATUS:
1784 if (pImmGetOpenStatus(hImc))
1785 {
1786 pImmSetCompositionFont(hImc, &norm_logfont);
1787 im_set_position(gui.row, gui.col);
1788
1789 /* Disable langmap */
1790 State &= ~LANGMAP;
1791 if (State & INSERT)
1792 {
1793#if defined(FEAT_WINDOWS) && defined(FEAT_KEYMAP)
1794 /* Unshown 'keymap' in status lines */
1795 if (curbuf->b_p_iminsert == B_IMODE_LMAP)
1796 {
1797 /* Save cursor position */
1798 int old_row = gui.row;
1799 int old_col = gui.col;
1800
1801 // This must be called here before
1802 // status_redraw_curbuf(), otherwise the mode
1803 // message may appear in the wrong position.
1804 showmode();
1805 status_redraw_curbuf();
1806 update_screen(0);
1807 /* Restore cursor position */
1808 gui.row = old_row;
1809 gui.col = old_col;
1810 }
1811#endif
1812 }
1813 }
1814 gui_update_cursor(TRUE, FALSE);
1815 lResult = 0;
1816 break;
1817 }
1818 pImmReleaseContext(hWnd, hImc);
1819 return lResult;
1820}
1821
Bram Moolenaard857f0e2005-06-21 22:37:39 +00001822/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00001823 static LRESULT
1824_OnImeComposition(HWND hwnd, WPARAM dbcs, LPARAM param)
1825{
1826 char_u *ret;
1827 int len;
1828
1829 if ((param & GCS_RESULTSTR) == 0) /* Composition unfinished. */
1830 return 0;
1831
1832 ret = GetResultStr(hwnd, GCS_RESULTSTR, &len);
1833 if (ret != NULL)
1834 {
1835 add_to_input_buf_csi(ret, len);
1836 vim_free(ret);
1837 return 1;
1838 }
1839 return 0;
1840}
1841
1842/*
1843 * get the current composition string, in UCS-2; *lenp is the number of
1844 * *lenp is the number of Unicode characters.
1845 */
1846 static short_u *
1847GetCompositionString_inUCS2(HIMC hIMC, DWORD GCS, int *lenp)
1848{
1849 LONG ret;
1850 LPWSTR wbuf = NULL;
1851 char_u *buf;
1852
1853 if (!pImmGetContext)
1854 return NULL; /* no imm32.dll */
1855
1856 /* Try Unicode; this'll always work on NT regardless of codepage. */
1857 ret = pImmGetCompositionStringW(hIMC, GCS, NULL, 0);
1858 if (ret == 0)
1859 return NULL; /* empty */
1860
1861 if (ret > 0)
1862 {
1863 /* Allocate the requested buffer plus space for the NUL character. */
1864 wbuf = (LPWSTR)alloc(ret + sizeof(WCHAR));
1865 if (wbuf != NULL)
1866 {
1867 pImmGetCompositionStringW(hIMC, GCS, wbuf, ret);
1868 *lenp = ret / sizeof(WCHAR);
1869 }
1870 return (short_u *)wbuf;
1871 }
1872
1873 /* ret < 0; we got an error, so try the ANSI version. This'll work
1874 * on 9x/ME, but only if the codepage happens to be set to whatever
1875 * we're inputting. */
1876 ret = pImmGetCompositionStringA(hIMC, GCS, NULL, 0);
1877 if (ret <= 0)
1878 return NULL; /* empty or error */
1879
1880 buf = alloc(ret);
1881 if (buf == NULL)
1882 return NULL;
1883 pImmGetCompositionStringA(hIMC, GCS, buf, ret);
1884
1885 /* convert from codepage to UCS-2 */
1886 MultiByteToWideChar_alloc(GetACP(), 0, buf, ret, &wbuf, lenp);
1887 vim_free(buf);
1888
1889 return (short_u *)wbuf;
1890}
1891
1892/*
1893 * void GetResultStr()
1894 *
1895 * This handles WM_IME_COMPOSITION with GCS_RESULTSTR flag on.
1896 * get complete composition string
1897 */
1898 static char_u *
1899GetResultStr(HWND hwnd, int GCS, int *lenp)
1900{
1901 HIMC hIMC; /* Input context handle. */
1902 short_u *buf = NULL;
1903 char_u *convbuf = NULL;
1904
1905 if (!pImmGetContext || (hIMC = pImmGetContext(hwnd)) == (HIMC)0)
1906 return NULL;
1907
1908 /* Reads in the composition string. */
1909 buf = GetCompositionString_inUCS2(hIMC, GCS, lenp);
1910 if (buf == NULL)
1911 return NULL;
1912
1913 convbuf = ucs2_to_enc(buf, lenp);
1914 pImmReleaseContext(hwnd, hIMC);
1915 vim_free(buf);
1916 return convbuf;
1917}
1918#endif
1919
1920/* For global functions we need prototypes. */
1921#if (defined(FEAT_MBYTE) && defined(FEAT_MBYTE_IME)) || defined(PROTO)
1922
1923/*
1924 * set font to IM.
1925 */
1926 void
1927im_set_font(LOGFONT *lf)
1928{
1929 HIMC hImc;
1930
1931 if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
1932 {
1933 pImmSetCompositionFont(hImc, lf);
1934 pImmReleaseContext(s_hwnd, hImc);
1935 }
1936}
1937
1938/*
1939 * Notify cursor position to IM.
1940 */
1941 void
1942im_set_position(int row, int col)
1943{
1944 HIMC hImc;
1945
1946 if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
1947 {
1948 COMPOSITIONFORM cfs;
1949
1950 cfs.dwStyle = CFS_POINT;
1951 cfs.ptCurrentPos.x = FILL_X(col);
1952 cfs.ptCurrentPos.y = FILL_Y(row);
1953 MapWindowPoints(s_textArea, s_hwnd, &cfs.ptCurrentPos, 1);
1954 pImmSetCompositionWindow(hImc, &cfs);
1955
1956 pImmReleaseContext(s_hwnd, hImc);
1957 }
1958}
1959
1960/*
1961 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
1962 */
1963 void
1964im_set_active(int active)
1965{
1966 HIMC hImc;
1967 static HIMC hImcOld = (HIMC)0;
1968
1969 if (pImmGetContext) /* if NULL imm32.dll wasn't loaded (yet) */
1970 {
1971 if (p_imdisable)
1972 {
1973 if (hImcOld == (HIMC)0)
1974 {
1975 hImcOld = pImmGetContext(s_hwnd);
1976 if (hImcOld)
1977 pImmAssociateContext(s_hwnd, (HIMC)0);
1978 }
1979 active = FALSE;
1980 }
1981 else if (hImcOld != (HIMC)0)
1982 {
1983 pImmAssociateContext(s_hwnd, hImcOld);
1984 hImcOld = (HIMC)0;
1985 }
1986
1987 hImc = pImmGetContext(s_hwnd);
1988 if (hImc)
1989 {
Bram Moolenaarca003e12006-03-17 23:19:38 +00001990 /*
1991 * for Korean ime
1992 */
1993 HKL hKL = GetKeyboardLayout(0);
1994
1995 if (LOWORD(hKL) == MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN))
1996 {
1997 static DWORD dwConversionSaved = 0, dwSentenceSaved = 0;
1998 static BOOL bSaved = FALSE;
1999
2000 if (active)
2001 {
2002 /* if we have a saved conversion status, restore it */
2003 if (bSaved)
2004 pImmSetConversionStatus(hImc, dwConversionSaved,
2005 dwSentenceSaved);
2006 bSaved = FALSE;
2007 }
2008 else
2009 {
2010 /* save conversion status and disable korean */
2011 if (pImmGetConversionStatus(hImc, &dwConversionSaved,
2012 &dwSentenceSaved))
2013 {
2014 bSaved = TRUE;
2015 pImmSetConversionStatus(hImc,
2016 dwConversionSaved & ~(IME_CMODE_NATIVE
2017 | IME_CMODE_FULLSHAPE),
2018 dwSentenceSaved);
2019 }
2020 }
2021 }
2022
Bram Moolenaar071d4272004-06-13 20:20:40 +00002023 pImmSetOpenStatus(hImc, active);
2024 pImmReleaseContext(s_hwnd, hImc);
2025 }
2026 }
2027}
2028
2029/*
2030 * Get IM status. When IM is on, return not 0. Else return 0.
2031 */
2032 int
2033im_get_status()
2034{
2035 int status = 0;
2036 HIMC hImc;
2037
2038 if (pImmGetContext && (hImc = pImmGetContext(s_hwnd)) != (HIMC)0)
2039 {
2040 status = pImmGetOpenStatus(hImc) ? 1 : 0;
2041 pImmReleaseContext(s_hwnd, hImc);
2042 }
2043 return status;
2044}
2045
2046#endif /* FEAT_MBYTE && FEAT_MBYTE_IME */
2047
2048#if defined(FEAT_MBYTE) && !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME)
2049/* Win32 with GLOBAL IME */
2050
2051/*
2052 * Notify cursor position to IM.
2053 */
2054 void
2055im_set_position(int row, int col)
2056{
2057 /* Win32 with GLOBAL IME */
2058 POINT p;
2059
2060 p.x = FILL_X(col);
2061 p.y = FILL_Y(row);
2062 MapWindowPoints(s_textArea, s_hwnd, &p, 1);
2063 global_ime_set_position(&p);
2064}
2065
2066/*
2067 * Set IM status on ("active" is TRUE) or off ("active" is FALSE).
2068 */
2069 void
2070im_set_active(int active)
2071{
2072 global_ime_set_status(active);
2073}
2074
2075/*
2076 * Get IM status. When IM is on, return not 0. Else return 0.
2077 */
2078 int
2079im_get_status()
2080{
2081 return global_ime_get_status();
2082}
2083#endif
2084
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002085#ifdef FEAT_MBYTE
2086/*
Bram Moolenaar39f05632006-03-19 22:15:26 +00002087 * Convert latin9 text "text[len]" to ucs-2 in "unicodebuf".
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002088 */
2089 static void
2090latin9_to_ucs(char_u *text, int len, WCHAR *unicodebuf)
2091{
2092 int c;
2093
Bram Moolenaarca003e12006-03-17 23:19:38 +00002094 while (--len >= 0)
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002095 {
2096 c = *text++;
2097 switch (c)
2098 {
2099 case 0xa4: c = 0x20ac; break; /* euro */
2100 case 0xa6: c = 0x0160; break; /* S hat */
2101 case 0xa8: c = 0x0161; break; /* S -hat */
2102 case 0xb4: c = 0x017d; break; /* Z hat */
2103 case 0xb8: c = 0x017e; break; /* Z -hat */
2104 case 0xbc: c = 0x0152; break; /* OE */
2105 case 0xbd: c = 0x0153; break; /* oe */
2106 case 0xbe: c = 0x0178; break; /* Y */
2107 }
2108 *unicodebuf++ = c;
2109 }
2110}
2111#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00002112
2113#ifdef FEAT_RIGHTLEFT
2114/*
2115 * What is this for? In the case where you are using Win98 or Win2K or later,
2116 * and you are using a Hebrew font (or Arabic!), Windows does you a favor and
2117 * reverses the string sent to the TextOut... family. This sucks, because we
2118 * go to a lot of effort to do the right thing, and there doesn't seem to be a
2119 * way to tell Windblows not to do this!
2120 *
2121 * The short of it is that this 'RevOut' only gets called if you are running
2122 * one of the new, "improved" MS OSes, and only if you are running in
2123 * 'rightleft' mode. It makes display take *slightly* longer, but not
2124 * noticeably so.
2125 */
2126 static void
2127RevOut( HDC s_hdc,
2128 int col,
2129 int row,
2130 UINT foptions,
2131 CONST RECT *pcliprect,
2132 LPCTSTR text,
2133 UINT len,
2134 CONST INT *padding)
2135{
2136 int ix;
2137 static int special = -1;
2138
2139 if (special == -1)
2140 {
2141 /* Check windows version: special treatment is needed if it is NT 5 or
2142 * Win98 or higher. */
2143 if ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
2144 && os_version.dwMajorVersion >= 5)
2145 || (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS
2146 && (os_version.dwMajorVersion > 4
2147 || (os_version.dwMajorVersion == 4
2148 && os_version.dwMinorVersion > 0))))
2149 special = 1;
2150 else
2151 special = 0;
2152 }
2153
2154 if (special)
2155 for (ix = 0; ix < (int)len; ++ix)
2156 ExtTextOut(s_hdc, col + TEXT_X(ix), row, foptions,
2157 pcliprect, text + ix, 1, padding);
2158 else
2159 ExtTextOut(s_hdc, col, row, foptions, pcliprect, text, len, padding);
2160}
2161#endif
2162
2163 void
2164gui_mch_draw_string(
2165 int row,
2166 int col,
2167 char_u *text,
2168 int len,
2169 int flags)
2170{
2171 static int *padding = NULL;
2172 static int pad_size = 0;
2173 int i;
2174 const RECT *pcliprect = NULL;
2175 UINT foptions = 0;
2176#ifdef FEAT_MBYTE
2177 static WCHAR *unicodebuf = NULL;
2178 static int *unicodepdy = NULL;
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002179 static int unibuflen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002180 int n = 0;
2181#endif
2182 HPEN hpen, old_pen;
2183 int y;
2184
2185#ifndef MSWIN16_FASTTEXT
2186 /*
2187 * Italic and bold text seems to have an extra row of pixels at the bottom
2188 * (below where the bottom of the character should be). If we draw the
2189 * characters with a solid background, the top row of pixels in the
2190 * character below will be overwritten. We can fix this by filling in the
2191 * background ourselves, to the correct character proportions, and then
2192 * writing the character in transparent mode. Still have a problem when
2193 * the character is "_", which gets written on to the character below.
2194 * New fix: set gui.char_ascent to -1. This shifts all characters up one
2195 * pixel in their slots, which fixes the problem with the bottom row of
2196 * pixels. We still need this code because otherwise the top row of pixels
2197 * becomes a problem. - webb.
2198 */
2199 static HBRUSH hbr_cache[2] = {NULL, NULL};
2200 static guicolor_T brush_color[2] = {INVALCOLOR, INVALCOLOR};
2201 static int brush_lru = 0;
2202 HBRUSH hbr;
2203 RECT rc;
2204
2205 if (!(flags & DRAW_TRANSP))
2206 {
2207 /*
2208 * Clear background first.
2209 * Note: FillRect() excludes right and bottom of rectangle.
2210 */
2211 rc.left = FILL_X(col);
2212 rc.top = FILL_Y(row);
2213#ifdef FEAT_MBYTE
2214 if (has_mbyte)
2215 {
2216 int cell_len = 0;
2217
2218 /* Compute the length in display cells. */
2219 for (n = 0; n < len; n += MB_BYTE2LEN(text[n]))
2220 cell_len += (*mb_ptr2cells)(text + n);
2221 rc.right = FILL_X(col + cell_len);
2222 }
2223 else
2224#endif
2225 rc.right = FILL_X(col + len);
2226 rc.bottom = FILL_Y(row + 1);
2227
2228 /* Cache the created brush, that saves a lot of time. We need two:
2229 * one for cursor background and one for the normal background. */
2230 if (gui.currBgColor == brush_color[0])
2231 {
2232 hbr = hbr_cache[0];
2233 brush_lru = 1;
2234 }
2235 else if (gui.currBgColor == brush_color[1])
2236 {
2237 hbr = hbr_cache[1];
2238 brush_lru = 0;
2239 }
2240 else
2241 {
2242 if (hbr_cache[brush_lru] != NULL)
2243 DeleteBrush(hbr_cache[brush_lru]);
2244 hbr_cache[brush_lru] = CreateSolidBrush(gui.currBgColor);
2245 brush_color[brush_lru] = gui.currBgColor;
2246 hbr = hbr_cache[brush_lru];
2247 brush_lru = !brush_lru;
2248 }
2249 FillRect(s_hdc, &rc, hbr);
2250
2251 SetBkMode(s_hdc, TRANSPARENT);
2252
2253 /*
2254 * When drawing block cursor, prevent inverted character spilling
2255 * over character cell (can happen with bold/italic)
2256 */
2257 if (flags & DRAW_CURSOR)
2258 {
2259 pcliprect = &rc;
2260 foptions = ETO_CLIPPED;
2261 }
2262 }
2263#else
2264 /*
2265 * The alternative would be to write the characters in opaque mode, but
2266 * when the text is not exactly the same proportions as normal text, too
2267 * big or too little a rectangle gets drawn for the background.
2268 */
2269 SetBkMode(s_hdc, OPAQUE);
2270 SetBkColor(s_hdc, gui.currBgColor);
2271#endif
2272 SetTextColor(s_hdc, gui.currFgColor);
2273 SelectFont(s_hdc, gui.currFont);
2274
2275 if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width)
2276 {
2277 vim_free(padding);
2278 pad_size = Columns;
2279
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00002280 /* Don't give an out-of-memory message here, it would call us
2281 * recursively. */
2282 padding = (int *)lalloc(pad_size * sizeof(int), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002283 if (padding != NULL)
2284 for (i = 0; i < pad_size; i++)
2285 padding[i] = gui.char_width;
2286 }
2287
2288 /* On NT, tell the font renderer not to "help" us with Hebrew and Arabic
2289 * text. This doesn't work in 9x, so we have to deal with it manually on
2290 * those systems. */
2291 if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT)
2292 foptions |= ETO_IGNORELANGUAGE;
2293
2294 /*
2295 * We have to provide the padding argument because italic and bold versions
2296 * of fixed-width fonts are often one pixel or so wider than their normal
2297 * versions.
2298 * No check for DRAW_BOLD, Windows will have done it already.
2299 */
2300
2301#ifdef FEAT_MBYTE
2302 /* Check if there are any UTF-8 characters. If not, use normal text
2303 * output to speed up output. */
2304 if (enc_utf8)
2305 for (n = 0; n < len; ++n)
2306 if (text[n] >= 0x80)
2307 break;
2308
2309 /* Check if the Unicode buffer exists and is big enough. Create it
Bram Moolenaar402d2fe2005-04-15 21:00:38 +00002310 * with the same length as the multi-byte string, the number of wide
Bram Moolenaar071d4272004-06-13 20:20:40 +00002311 * characters is always equal or smaller. */
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002312 if ((enc_utf8
2313 || (enc_codepage > 0 && (int)GetACP() != enc_codepage)
2314 || enc_latin9)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002315 && (unicodebuf == NULL || len > unibuflen))
2316 {
2317 vim_free(unicodebuf);
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00002318 unicodebuf = (WCHAR *)lalloc(len * sizeof(WCHAR), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002319
2320 vim_free(unicodepdy);
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00002321 unicodepdy = (int *)lalloc(len * sizeof(int), FALSE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002322
2323 unibuflen = len;
2324 }
2325
2326 if (enc_utf8 && n < len && unicodebuf != NULL)
2327 {
2328 /* Output UTF-8 characters. Caller has already separated
2329 * composing characters. */
Bram Moolenaarca003e12006-03-17 23:19:38 +00002330 int i;
2331 int wlen; /* string length in words */
2332 int clen; /* string length in characters */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002333 int cells; /* cell width of string up to composing char */
2334 int cw; /* width of current cell */
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002335 int c;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002336
Bram Moolenaar97b2ad32006-03-18 21:40:56 +00002337 wlen = 0;
Bram Moolenaarca003e12006-03-17 23:19:38 +00002338 clen = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002339 cells = 0;
Bram Moolenaarca003e12006-03-17 23:19:38 +00002340 for (i = 0; i < len; )
Bram Moolenaar071d4272004-06-13 20:20:40 +00002341 {
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002342 c = utf_ptr2char(text + i);
2343 if (c >= 0x10000)
2344 {
2345 /* Turn into UTF-16 encoding. */
Bram Moolenaarca003e12006-03-17 23:19:38 +00002346 unicodebuf[wlen++] = ((c - 0x10000) >> 10) + 0xD800;
2347 unicodebuf[wlen++] = ((c - 0x10000) & 0x3ff) + 0xDC00;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002348 }
2349 else
2350 {
Bram Moolenaarca003e12006-03-17 23:19:38 +00002351 unicodebuf[wlen++] = c;
Bram Moolenaar362e1a32006-03-06 23:29:24 +00002352 }
2353 cw = utf_char2cells(c);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002354 if (cw > 2) /* don't use 4 for unprintable char */
2355 cw = 1;
2356 if (unicodepdy != NULL)
2357 {
2358 /* Use unicodepdy to make characters fit as we expect, even
2359 * when the font uses different widths (e.g., bold character
2360 * is wider). */
2361 unicodepdy[clen] = cw * gui.char_width;
2362 }
2363 cells += cw;
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00002364 i += utfc_ptr2len_len(text + i, len - i);
Bram Moolenaarca003e12006-03-17 23:19:38 +00002365 ++clen;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002366 }
2367 ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
Bram Moolenaarca003e12006-03-17 23:19:38 +00002368 foptions, pcliprect, unicodebuf, wlen, unicodepdy);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002369 len = cells; /* used for underlining */
2370 }
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002371 else if ((enc_codepage > 0 && (int)GetACP() != enc_codepage) || enc_latin9)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002372 {
2373 /* If we want to display codepage data, and the current CP is not the
2374 * ANSI one, we need to go via Unicode. */
2375 if (unicodebuf != NULL)
2376 {
Bram Moolenaar3fdfa4a2004-10-07 21:02:47 +00002377 if (enc_latin9)
2378 latin9_to_ucs(text, len, unicodebuf);
2379 else
2380 len = MultiByteToWideChar(enc_codepage,
Bram Moolenaar071d4272004-06-13 20:20:40 +00002381 MB_PRECOMPOSED,
2382 (char *)text, len,
2383 (LPWSTR)unicodebuf, unibuflen);
2384 if (len != 0)
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002385 {
2386 /* Use unicodepdy to make characters fit as we expect, even
2387 * when the font uses different widths (e.g., bold character
2388 * is wider). */
2389 if (unicodepdy != NULL)
2390 {
2391 int i;
2392 int cw;
2393
2394 for (i = 0; i < len; ++i)
2395 {
2396 cw = utf_char2cells(unicodebuf[i]);
2397 if (cw > 2)
2398 cw = 1;
2399 unicodepdy[i] = cw * gui.char_width;
2400 }
2401 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002402 ExtTextOutW(s_hdc, TEXT_X(col), TEXT_Y(row),
Bram Moolenaar19a09a12005-03-04 23:39:37 +00002403 foptions, pcliprect, unicodebuf, len, unicodepdy);
2404 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002405 }
2406 }
2407 else
2408#endif
2409 {
2410#ifdef FEAT_RIGHTLEFT
2411 /* If we can't use ETO_IGNORELANGUAGE, we can't tell Windows not to
2412 * mess up RL text, so we have to draw it character-by-character.
2413 * Only do this if RL is on, since it's slow. */
2414 if (curwin->w_p_rl && !(foptions & ETO_IGNORELANGUAGE))
2415 RevOut(s_hdc, TEXT_X(col), TEXT_Y(row),
2416 foptions, pcliprect, (char *)text, len, padding);
2417 else
2418#endif
2419 ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row),
2420 foptions, pcliprect, (char *)text, len, padding);
2421 }
2422
Bram Moolenaare2cc9702005-03-15 22:43:58 +00002423 /* Underline */
Bram Moolenaar071d4272004-06-13 20:20:40 +00002424 if (flags & DRAW_UNDERL)
2425 {
2426 hpen = CreatePen(PS_SOLID, 1, gui.currFgColor);
2427 old_pen = SelectObject(s_hdc, hpen);
2428 /* When p_linespace is 0, overwrite the bottom row of pixels.
2429 * Otherwise put the line just below the character. */
2430 y = FILL_Y(row + 1) - 1;
2431#ifndef MSWIN16_FASTTEXT
2432 if (p_linespace > 1)
2433 y -= p_linespace - 1;
2434#endif
2435 MoveToEx(s_hdc, FILL_X(col), y, NULL);
2436 /* Note: LineTo() excludes the last pixel in the line. */
2437 LineTo(s_hdc, FILL_X(col + len), y);
2438 DeleteObject(SelectObject(s_hdc, old_pen));
2439 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00002440
2441 /* Undercurl */
2442 if (flags & DRAW_UNDERC)
2443 {
2444 int x;
2445 int offset;
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00002446 static const int val[8] = {1, 0, 0, 0, 1, 2, 2, 2 };
Bram Moolenaare2cc9702005-03-15 22:43:58 +00002447
2448 y = FILL_Y(row + 1) - 1;
2449 for (x = FILL_X(col); x < FILL_X(col + len); ++x)
2450 {
2451 offset = val[x % 8];
2452 SetPixel(s_hdc, x, y - offset, gui.currSpColor);
2453 }
2454 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00002455}
2456
2457
2458/*
2459 * Output routines.
2460 */
2461
2462/* Flush any output to the screen */
2463 void
2464gui_mch_flush(void)
2465{
2466# if defined(__BORLANDC__)
2467 /*
2468 * The GdiFlush declaration (in Borland C 5.01 <wingdi.h>) is not a
2469 * prototype declaration.
2470 * The compiler complains if __stdcall is not used in both declarations.
2471 */
2472 BOOL __stdcall GdiFlush(void);
2473# endif
2474
2475 GdiFlush();
2476}
2477
2478 static void
2479clear_rect(RECT *rcp)
2480{
2481 HBRUSH hbr;
2482
2483 hbr = CreateSolidBrush(gui.back_pixel);
2484 FillRect(s_hdc, rcp, hbr);
2485 DeleteBrush(hbr);
2486}
2487
2488
Bram Moolenaarc716c302006-01-21 22:12:51 +00002489 void
2490gui_mch_get_screen_dimensions(int *screen_w, int *screen_h)
2491{
2492 RECT workarea_rect;
2493
2494 get_work_area(&workarea_rect);
2495
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002496 *screen_w = workarea_rect.right - workarea_rect.left
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002497 - GetSystemMetrics(SM_CXFRAME) * 2;
Bram Moolenaarc716c302006-01-21 22:12:51 +00002498
2499 /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include
2500 * the menubar for MSwin, we subtract it from the screen height, so that
2501 * the window size can be made to fit on the screen. */
Bram Moolenaar910f66f2006-04-05 20:41:53 +00002502 *screen_h = workarea_rect.bottom - workarea_rect.top
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002503 - GetSystemMetrics(SM_CYFRAME) * 2
Bram Moolenaarc716c302006-01-21 22:12:51 +00002504 - GetSystemMetrics(SM_CYCAPTION)
2505#ifdef FEAT_MENU
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002506 - gui_mswin_get_menu_height(FALSE)
Bram Moolenaarc716c302006-01-21 22:12:51 +00002507#endif
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00002508 ;
Bram Moolenaarc716c302006-01-21 22:12:51 +00002509}
2510
2511
Bram Moolenaar071d4272004-06-13 20:20:40 +00002512#if defined(FEAT_MENU) || defined(PROTO)
2513/*
2514 * Add a sub menu to the menu bar.
2515 */
2516 void
2517gui_mch_add_menu(
2518 vimmenu_T *menu,
2519 int pos)
2520{
2521 vimmenu_T *parent = menu->parent;
2522
2523 menu->submenu_id = CreatePopupMenu();
2524 menu->id = s_menu_id++;
2525
2526 if (menu_is_menubar(menu->name))
2527 {
2528 if (is_winnt_3())
2529 {
2530 InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id,
2531 (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION,
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002532 (long_u)menu->submenu_id, (LPCTSTR) menu->name);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002533 }
2534 else
2535 {
2536#ifdef FEAT_MBYTE
2537 WCHAR *wn = NULL;
2538 int n;
2539
2540 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2541 {
2542 /* 'encoding' differs from active codepage: convert menu name
2543 * and use wide function */
2544 wn = enc_to_ucs2(menu->name, NULL);
2545 if (wn != NULL)
2546 {
2547 MENUITEMINFOW infow;
2548
2549 infow.cbSize = sizeof(infow);
2550 infow.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID
2551 | MIIM_SUBMENU;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002552 infow.dwItemData = (long_u)menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002553 infow.wID = menu->id;
2554 infow.fType = MFT_STRING;
2555 infow.dwTypeData = wn;
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00002556 infow.cch = (UINT)wcslen(wn);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002557 infow.hSubMenu = menu->submenu_id;
2558 n = InsertMenuItemW((parent == NULL)
2559 ? s_menuBar : parent->submenu_id,
2560 (UINT)pos, TRUE, &infow);
2561 vim_free(wn);
2562 if (n == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2563 /* Failed, try using non-wide function. */
2564 wn = NULL;
2565 }
2566 }
2567
2568 if (wn == NULL)
2569#endif
2570 {
2571 MENUITEMINFO info;
2572
2573 info.cbSize = sizeof(info);
2574 info.fMask = MIIM_DATA | MIIM_TYPE | MIIM_ID | MIIM_SUBMENU;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002575 info.dwItemData = (long_u)menu;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002576 info.wID = menu->id;
2577 info.fType = MFT_STRING;
2578 info.dwTypeData = (LPTSTR)menu->name;
2579 info.cch = (UINT)STRLEN(menu->name);
2580 info.hSubMenu = menu->submenu_id;
2581 InsertMenuItem((parent == NULL)
2582 ? s_menuBar : parent->submenu_id,
2583 (UINT)pos, TRUE, &info);
2584 }
2585 }
2586 }
2587
2588 /* Fix window size if menu may have wrapped */
2589 if (parent == NULL)
2590 gui_mswin_get_menu_height(!gui.starting);
2591#ifdef FEAT_TEAROFF
2592 else if (IsWindow(parent->tearoff_handle))
2593 rebuild_tearoff(parent);
2594#endif
2595}
2596
2597 void
2598gui_mch_show_popupmenu(vimmenu_T *menu)
2599{
2600 POINT mp;
2601
2602 (void)GetCursorPos((LPPOINT)&mp);
2603 gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y);
2604}
2605
2606 void
Bram Moolenaar045e82d2005-07-08 22:25:33 +00002607gui_make_popup(char_u *path_name, int mouse_pos)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002608{
2609 vimmenu_T *menu = gui_find_menu(path_name);
2610
2611 if (menu != NULL)
2612 {
2613 POINT p;
2614
2615 /* Find the position of the current cursor */
2616 GetDCOrgEx(s_hdc, &p);
Bram Moolenaar045e82d2005-07-08 22:25:33 +00002617 if (mouse_pos)
2618 {
2619 int mx, my;
2620
2621 gui_mch_getmouse(&mx, &my);
2622 p.x += mx;
2623 p.y += my;
2624 }
2625 else if (curwin != NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00002626 {
2627 p.x += TEXT_X(W_WINCOL(curwin) + curwin->w_wcol + 1);
2628 p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1);
2629 }
2630 msg_scroll = FALSE;
2631 gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y);
2632 }
2633}
2634
2635#if defined(FEAT_TEAROFF) || defined(PROTO)
2636/*
2637 * Given a menu descriptor, e.g. "File.New", find it in the menu hierarchy and
2638 * create it as a pseudo-"tearoff menu".
2639 */
2640 void
2641gui_make_tearoff(char_u *path_name)
2642{
2643 vimmenu_T *menu = gui_find_menu(path_name);
2644
2645 /* Found the menu, so tear it off. */
2646 if (menu != NULL)
2647 gui_mch_tearoff(menu->dname, menu, 0xffffL, 0xffffL);
2648}
2649#endif
2650
2651/*
2652 * Add a menu item to a menu
2653 */
2654 void
2655gui_mch_add_menu_item(
2656 vimmenu_T *menu,
2657 int idx)
2658{
2659 vimmenu_T *parent = menu->parent;
2660
2661 menu->id = s_menu_id++;
2662 menu->submenu_id = NULL;
2663
2664#ifdef FEAT_TEAROFF
2665 if (STRNCMP(menu->name, TEAR_STRING, TEAR_LEN) == 0)
2666 {
2667 InsertMenu(parent->submenu_id, (UINT)idx, MF_BITMAP|MF_BYPOSITION,
2668 (UINT)menu->id, (LPCTSTR) s_htearbitmap);
2669 }
2670 else
2671#endif
2672#ifdef FEAT_TOOLBAR
2673 if (menu_is_toolbar(parent->name))
2674 {
2675 TBBUTTON newtb;
2676
2677 vim_memset(&newtb, 0, sizeof(newtb));
2678 if (menu_is_separator(menu->name))
2679 {
2680 newtb.iBitmap = 0;
2681 newtb.fsStyle = TBSTYLE_SEP;
2682 }
2683 else
2684 {
2685 newtb.iBitmap = get_toolbar_bitmap(menu);
2686 newtb.fsStyle = TBSTYLE_BUTTON;
2687 }
2688 newtb.idCommand = menu->id;
2689 newtb.fsState = TBSTATE_ENABLED;
2690 newtb.iString = 0;
2691 SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx,
2692 (LPARAM)&newtb);
2693 menu->submenu_id = (HMENU)-1;
2694 }
2695 else
2696#endif
2697 {
2698#ifdef FEAT_MBYTE
2699 WCHAR *wn = NULL;
2700 int n;
2701
2702 if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
2703 {
2704 /* 'encoding' differs from active codepage: convert menu item name
2705 * and use wide function */
2706 wn = enc_to_ucs2(menu->name, NULL);
2707 if (wn != NULL)
2708 {
2709 n = InsertMenuW(parent->submenu_id, (UINT)idx,
2710 (menu_is_separator(menu->name)
2711 ? MF_SEPARATOR : MF_STRING) | MF_BYPOSITION,
2712 (UINT)menu->id, wn);
2713 vim_free(wn);
2714 if (n == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2715 /* Failed, try using non-wide function. */
2716 wn = NULL;
2717 }
2718 }
2719 if (wn == NULL)
2720#endif
2721 InsertMenu(parent->submenu_id, (UINT)idx,
2722 (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING)
2723 | MF_BYPOSITION,
2724 (UINT)menu->id, (LPCTSTR)menu->name);
2725#ifdef FEAT_TEAROFF
2726 if (IsWindow(parent->tearoff_handle))
2727 rebuild_tearoff(parent);
2728#endif
2729 }
2730}
2731
2732/*
2733 * Destroy the machine specific menu widget.
2734 */
2735 void
2736gui_mch_destroy_menu(vimmenu_T *menu)
2737{
2738#ifdef FEAT_TOOLBAR
2739 /*
2740 * is this a toolbar button?
2741 */
2742 if (menu->submenu_id == (HMENU)-1)
2743 {
2744 int iButton;
2745
2746 iButton = (int)SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX,
2747 (WPARAM)menu->id, 0);
2748 SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0);
2749 }
2750 else
2751#endif
2752 {
2753 if (menu->parent != NULL
2754 && menu_is_popup(menu->parent->dname)
2755 && menu->parent->submenu_id != NULL)
2756 RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND);
2757 else
2758 RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND);
2759 if (menu->submenu_id != NULL)
2760 DestroyMenu(menu->submenu_id);
2761#ifdef FEAT_TEAROFF
2762 if (IsWindow(menu->tearoff_handle))
2763 DestroyWindow(menu->tearoff_handle);
2764 if (menu->parent != NULL
2765 && menu->parent->children != NULL
2766 && IsWindow(menu->parent->tearoff_handle))
2767 {
2768 /* This menu must not show up when rebuilding the tearoff window. */
2769 menu->modes = 0;
2770 rebuild_tearoff(menu->parent);
2771 }
2772#endif
2773 }
2774}
2775
2776#ifdef FEAT_TEAROFF
2777 static void
2778rebuild_tearoff(vimmenu_T *menu)
2779{
2780 /*hackish*/
2781 char_u tbuf[128];
2782 RECT trect;
2783 RECT rct;
2784 RECT roct;
2785 int x, y;
2786
2787 HWND thwnd = menu->tearoff_handle;
2788
2789 GetWindowText(thwnd, tbuf, 127);
2790 if (GetWindowRect(thwnd, &trect)
2791 && GetWindowRect(s_hwnd, &rct)
2792 && GetClientRect(s_hwnd, &roct))
2793 {
2794 x = trect.left - rct.left;
2795 y = (trect.top - rct.bottom + roct.bottom);
2796 }
2797 else
2798 {
2799 x = y = 0xffffL;
2800 }
2801 DestroyWindow(thwnd);
2802 if (menu->children != NULL)
2803 {
2804 gui_mch_tearoff(tbuf, menu, x, y);
2805 if (IsWindow(menu->tearoff_handle))
2806 (void) SetWindowPos(menu->tearoff_handle,
2807 NULL,
2808 (int)trect.left,
2809 (int)trect.top,
2810 0, 0,
2811 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE);
2812 }
2813}
2814#endif /* FEAT_TEAROFF */
2815
2816/*
2817 * Make a menu either grey or not grey.
2818 */
2819 void
2820gui_mch_menu_grey(
2821 vimmenu_T *menu,
2822 int grey)
2823{
2824#ifdef FEAT_TOOLBAR
2825 /*
2826 * is this a toolbar button?
2827 */
2828 if (menu->submenu_id == (HMENU)-1)
2829 {
2830 SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON,
2831 (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) );
2832 }
2833 else
2834#endif
2835 if (grey)
2836 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED);
2837 else
2838 EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED);
2839
2840#ifdef FEAT_TEAROFF
2841 if ((menu->parent != NULL) && (IsWindow(menu->parent->tearoff_handle)))
2842 {
2843 WORD menuID;
2844 HWND menuHandle;
2845
2846 /*
2847 * A tearoff button has changed state.
2848 */
2849 if (menu->children == NULL)
2850 menuID = (WORD)(menu->id);
2851 else
Bram Moolenaareb3593b2006-04-22 22:33:57 +00002852 menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
Bram Moolenaar071d4272004-06-13 20:20:40 +00002853 menuHandle = GetDlgItem(menu->parent->tearoff_handle, menuID);
2854 if (menuHandle)
2855 EnableWindow(menuHandle, !grey);
2856
2857 }
2858#endif
2859}
2860
2861#endif /* FEAT_MENU */
2862
2863
2864/* define some macros used to make the dialogue creation more readable */
2865
2866#define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1)
2867#define add_word(x) *p++ = (x)
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00002868#define add_long(x) dwp = (DWORD *)p; *dwp++ = (x); p = (WORD *)dwp
Bram Moolenaar071d4272004-06-13 20:20:40 +00002869
2870#if defined(FEAT_GUI_DIALOG) || defined(PROTO)
2871/*
2872 * stuff for dialogs
2873 */
2874
2875/*
2876 * The callback routine used by all the dialogs. Very simple. First,
2877 * acknowledges the INITDIALOG message so that Windows knows to do standard
2878 * dialog stuff (Return = default, Esc = cancel....) Second, if a button is
2879 * pressed, return that button's ID - IDCANCEL (2), which is the button's
2880 * number.
2881 */
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00002882/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00002883 static LRESULT CALLBACK
2884dialog_callback(
2885 HWND hwnd,
2886 UINT message,
2887 WPARAM wParam,
2888 LPARAM lParam)
2889{
2890 if (message == WM_INITDIALOG)
2891 {
2892 CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER));
2893 /* Set focus to the dialog. Set the default button, if specified. */
2894 (void)SetFocus(hwnd);
2895 if (dialog_default_button > IDCANCEL)
2896 (void)SetFocus(GetDlgItem(hwnd, dialog_default_button));
Bram Moolenaar2b80e652007-08-14 14:57:55 +00002897 else
2898 /* We don't have a default, set focus on another element of the
2899 * dialog window, probably the icon */
2900 (void)SetFocus(GetDlgItem(hwnd, DLG_NONBUTTON_CONTROL));
Bram Moolenaar071d4272004-06-13 20:20:40 +00002901 return FALSE;
2902 }
2903
2904 if (message == WM_COMMAND)
2905 {
2906 int button = LOWORD(wParam);
2907
2908 /* Don't end the dialog if something was selected that was
2909 * not a button.
2910 */
2911 if (button >= DLG_NONBUTTON_CONTROL)
2912 return TRUE;
2913
2914 /* If the edit box exists, copy the string. */
2915 if (s_textfield != NULL)
2916 GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2,
2917 s_textfield, IOSIZE);
2918
2919 /*
2920 * Need to check for IDOK because if the user just hits Return to
2921 * accept the default value, some reason this is what we get.
2922 */
2923 if (button == IDOK)
2924 {
2925 if (dialog_default_button > IDCANCEL)
2926 EndDialog(hwnd, dialog_default_button);
2927 }
2928 else
2929 EndDialog(hwnd, button - IDCANCEL);
2930 return TRUE;
2931 }
2932
2933 if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
2934 {
2935 EndDialog(hwnd, 0);
2936 return TRUE;
2937 }
2938 return FALSE;
2939}
2940
2941/*
2942 * Create a dialog dynamically from the parameter strings.
2943 * type = type of dialog (question, alert, etc.)
2944 * title = dialog title. may be NULL for default title.
2945 * message = text to display. Dialog sizes to accommodate it.
2946 * buttons = '\n' separated list of button captions, default first.
2947 * dfltbutton = number of default button.
2948 *
2949 * This routine returns 1 if the first button is pressed,
2950 * 2 for the second, etc.
2951 *
2952 * 0 indicates Esc was pressed.
2953 * -1 for unexpected error
2954 *
2955 * If stubbing out this fn, return 1.
2956 */
2957
2958static const char_u *dlg_icons[] = /* must match names in resource file */
2959{
2960 "IDR_VIM",
2961 "IDR_VIM_ERROR",
2962 "IDR_VIM_ALERT",
2963 "IDR_VIM_INFO",
2964 "IDR_VIM_QUESTION"
2965};
2966
Bram Moolenaar071d4272004-06-13 20:20:40 +00002967 int
2968gui_mch_dialog(
2969 int type,
2970 char_u *title,
2971 char_u *message,
2972 char_u *buttons,
2973 int dfltbutton,
2974 char_u *textfield)
2975{
2976 WORD *p, *pdlgtemplate, *pnumitems;
Bram Moolenaarf4cd3e82005-12-22 22:47:02 +00002977 DWORD *dwp;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002978 int numButtons;
2979 int *buttonWidths, *buttonPositions;
2980 int buttonYpos;
2981 int nchar, i;
2982 DWORD lStyle;
2983 int dlgwidth = 0;
2984 int dlgheight;
2985 int editboxheight;
2986 int horizWidth = 0;
2987 int msgheight;
2988 char_u *pstart;
2989 char_u *pend;
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00002990 char_u *last_white;
Bram Moolenaar071d4272004-06-13 20:20:40 +00002991 char_u *tbuffer;
2992 RECT rect;
2993 HWND hwnd;
2994 HDC hdc;
2995 HFONT font, oldFont;
2996 TEXTMETRIC fontInfo;
2997 int fontHeight;
2998 int textWidth, minButtonWidth, messageWidth;
2999 int maxDialogWidth;
Bram Moolenaar748bf032005-02-02 23:04:36 +00003000 int maxDialogHeight;
3001 int scroll_flag = 0;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003002 int vertical;
3003 int dlgPaddingX;
3004 int dlgPaddingY;
3005#ifdef USE_SYSMENU_FONT
3006 LOGFONT lfSysmenu;
3007 int use_lfSysmenu = FALSE;
3008#endif
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003009 garray_T ga;
3010 int l;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003011
3012#ifndef NO_CONSOLE
3013 /* Don't output anything in silent mode ("ex -s") */
3014 if (silent_mode)
3015 return dfltbutton; /* return default option */
3016#endif
3017
Bram Moolenaar748bf032005-02-02 23:04:36 +00003018#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003019 /* If there is no window yet, open it. */
3020 if (s_hwnd == NULL && gui_mch_init() == FAIL)
3021 return dfltbutton;
Bram Moolenaar748bf032005-02-02 23:04:36 +00003022#else
3023 if (s_hwnd == NULL)
3024 get_dialog_font_metrics();
3025#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003026
3027 if ((type < 0) || (type > VIM_LAST_TYPE))
3028 type = 0;
3029
3030 /* allocate some memory for dialog template */
Bram Moolenaar1cd871b2004-12-19 22:46:22 +00003031 /* TODO should compute this really */
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003032 pdlgtemplate = p = (PWORD)LocalAlloc(LPTR,
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003033 DLG_ALLOC_SIZE + STRLEN(message) * 2);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003034
3035 if (p == NULL)
3036 return -1;
3037
3038 /*
3039 * make a copy of 'buttons' to fiddle with it. complier grizzles because
3040 * vim_strsave() doesn't take a const arg (why not?), so cast away the
3041 * const.
3042 */
3043 tbuffer = vim_strsave(buttons);
3044 if (tbuffer == NULL)
3045 return -1;
3046
3047 --dfltbutton; /* Change from one-based to zero-based */
3048
3049 /* Count buttons */
3050 numButtons = 1;
3051 for (i = 0; tbuffer[i] != '\0'; i++)
3052 {
3053 if (tbuffer[i] == DLG_BUTTON_SEP)
3054 numButtons++;
3055 }
3056 if (dfltbutton >= numButtons)
3057 dfltbutton = -1;
3058
3059 /* Allocate array to hold the width of each button */
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00003060 buttonWidths = (int *)lalloc(numButtons * sizeof(int), TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003061 if (buttonWidths == NULL)
3062 return -1;
3063
3064 /* Allocate array to hold the X position of each button */
Bram Moolenaarc54b8a72005-09-30 21:20:29 +00003065 buttonPositions = (int *)lalloc(numButtons * sizeof(int), TRUE);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003066 if (buttonPositions == NULL)
3067 return -1;
3068
3069 /*
3070 * Calculate how big the dialog must be.
3071 */
3072 hwnd = GetDesktopWindow();
3073 hdc = GetWindowDC(hwnd);
3074#ifdef USE_SYSMENU_FONT
3075 if (gui_w32_get_menu_font(&lfSysmenu) == OK)
3076 {
3077 font = CreateFontIndirect(&lfSysmenu);
3078 use_lfSysmenu = TRUE;
3079 }
3080 else
3081#endif
3082 font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3083 VARIABLE_PITCH , DLG_FONT_NAME);
3084 if (s_usenewlook)
3085 {
3086 oldFont = SelectFont(hdc, font);
3087 dlgPaddingX = DLG_PADDING_X;
3088 dlgPaddingY = DLG_PADDING_Y;
3089 }
3090 else
3091 {
3092 oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
3093 dlgPaddingX = DLG_OLD_STYLE_PADDING_X;
3094 dlgPaddingY = DLG_OLD_STYLE_PADDING_Y;
3095 }
3096 GetTextMetrics(hdc, &fontInfo);
3097 fontHeight = fontInfo.tmHeight;
3098
3099 /* Minimum width for horizontal button */
3100 minButtonWidth = GetTextWidth(hdc, "Cancel", 6);
3101
3102 /* Maximum width of a dialog, if possible */
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003103 if (s_hwnd == NULL)
3104 {
3105 RECT workarea_rect;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003106
Bram Moolenaarc716c302006-01-21 22:12:51 +00003107 /* We don't have a window, use the desktop area. */
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003108 get_work_area(&workarea_rect);
3109 maxDialogWidth = workarea_rect.right - workarea_rect.left - 100;
3110 if (maxDialogWidth > 600)
3111 maxDialogWidth = 600;
3112 maxDialogHeight = workarea_rect.bottom - workarea_rect.top - 100;
3113 }
3114 else
3115 {
3116 /* Use our own window for the size, unless it's very small. */
3117 GetWindowRect(s_hwnd, &rect);
3118 maxDialogWidth = rect.right - rect.left
3119 - GetSystemMetrics(SM_CXFRAME) * 2;
3120 if (maxDialogWidth < DLG_MIN_MAX_WIDTH)
3121 maxDialogWidth = DLG_MIN_MAX_WIDTH;
Bram Moolenaar748bf032005-02-02 23:04:36 +00003122
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003123 maxDialogHeight = rect.bottom - rect.top
3124 - GetSystemMetrics(SM_CXFRAME) * 2;
3125 if (maxDialogHeight < DLG_MIN_MAX_HEIGHT)
3126 maxDialogHeight = DLG_MIN_MAX_HEIGHT;
3127 }
3128
3129 /* Set dlgwidth to width of message.
3130 * Copy the message into "ga", changing NL to CR-NL and inserting line
3131 * breaks where needed. */
Bram Moolenaar071d4272004-06-13 20:20:40 +00003132 pstart = message;
3133 messageWidth = 0;
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003134 msgheight = 0;
3135 ga_init2(&ga, sizeof(char), 500);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003136 do
3137 {
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003138 msgheight += fontHeight; /* at least one line */
3139
3140 /* Need to figure out where to break the string. The system does it
3141 * at a word boundary, which would mean we can't compute the number of
3142 * wrapped lines. */
3143 textWidth = 0;
3144 last_white = NULL;
3145 for (pend = pstart; *pend != NUL && *pend != '\n'; )
Bram Moolenaar748bf032005-02-02 23:04:36 +00003146 {
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003147#ifdef FEAT_MBYTE
Bram Moolenaar0fa313a2005-08-10 21:07:57 +00003148 l = (*mb_ptr2len)(pend);
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003149#else
3150 l = 1;
3151#endif
3152 if (l == 1 && vim_iswhite(*pend)
3153 && textWidth > maxDialogWidth * 3 / 4)
3154 last_white = pend;
3155 textWidth += GetTextWidth(hdc, pend, l);
3156 if (textWidth >= maxDialogWidth)
Bram Moolenaar748bf032005-02-02 23:04:36 +00003157 {
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003158 /* Line will wrap. */
3159 messageWidth = maxDialogWidth;
Bram Moolenaar748bf032005-02-02 23:04:36 +00003160 msgheight += fontHeight;
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003161 textWidth = 0;
3162
3163 if (last_white != NULL)
3164 {
3165 /* break the line just after a space */
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003166 ga.ga_len -= (int)(pend - (last_white + 1));
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003167 pend = last_white + 1;
3168 last_white = NULL;
3169 }
3170 ga_append(&ga, '\r');
3171 ga_append(&ga, '\n');
3172 continue;
Bram Moolenaar748bf032005-02-02 23:04:36 +00003173 }
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003174
3175 while (--l >= 0)
3176 ga_append(&ga, *pend++);
Bram Moolenaar748bf032005-02-02 23:04:36 +00003177 }
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003178 if (textWidth > messageWidth)
Bram Moolenaar071d4272004-06-13 20:20:40 +00003179 messageWidth = textWidth;
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003180
3181 ga_append(&ga, '\r');
3182 ga_append(&ga, '\n');
Bram Moolenaar071d4272004-06-13 20:20:40 +00003183 pstart = pend + 1;
3184 } while (*pend != NUL);
Bram Moolenaar748bf032005-02-02 23:04:36 +00003185
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003186 if (ga.ga_data != NULL)
3187 message = ga.ga_data;
3188
Bram Moolenaar748bf032005-02-02 23:04:36 +00003189 messageWidth += 10; /* roundoff space */
3190
3191 /* Restrict the size to a maximum. Causes a scrollbar to show up. */
3192 if (msgheight > maxDialogHeight)
3193 {
3194 msgheight = maxDialogHeight;
3195 scroll_flag = WS_VSCROLL;
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003196 messageWidth += GetSystemMetrics(SM_CXVSCROLL);
Bram Moolenaar748bf032005-02-02 23:04:36 +00003197 }
Bram Moolenaar071d4272004-06-13 20:20:40 +00003198
3199 /* Add width of icon to dlgwidth, and some space */
Bram Moolenaar748bf032005-02-02 23:04:36 +00003200 dlgwidth = messageWidth + DLG_ICON_WIDTH + 3 * dlgPaddingX;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003201
3202 if (msgheight < DLG_ICON_HEIGHT)
3203 msgheight = DLG_ICON_HEIGHT;
3204
3205 /*
3206 * Check button names. A long one will make the dialog wider.
Bram Moolenaaraea02fa2007-05-04 20:29:09 +00003207 * When called early (-register error message) p_go isn't initialized.
Bram Moolenaar071d4272004-06-13 20:20:40 +00003208 */
Bram Moolenaaraea02fa2007-05-04 20:29:09 +00003209 vertical = (p_go != NULL && vim_strchr(p_go, GO_VERTICAL) != NULL);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003210 if (!vertical)
3211 {
3212 // Place buttons horizontally if they fit.
3213 horizWidth = dlgPaddingX;
3214 pstart = tbuffer;
3215 i = 0;
3216 do
3217 {
3218 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
3219 if (pend == NULL)
3220 pend = pstart + STRLEN(pstart); // Last button name.
3221 textWidth = GetTextWidth(hdc, pstart, (int)(pend - pstart));
3222 if (textWidth < minButtonWidth)
3223 textWidth = minButtonWidth;
3224 textWidth += dlgPaddingX; /* Padding within button */
3225 buttonWidths[i] = textWidth;
3226 buttonPositions[i++] = horizWidth;
3227 horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */
3228 pstart = pend + 1;
3229 } while (*pend != NUL);
3230
3231 if (horizWidth > maxDialogWidth)
3232 vertical = TRUE; // Too wide to fit on the screen.
3233 else if (horizWidth > dlgwidth)
3234 dlgwidth = horizWidth;
3235 }
3236
3237 if (vertical)
3238 {
3239 // Stack buttons vertically.
3240 pstart = tbuffer;
3241 do
3242 {
3243 pend = vim_strchr(pstart, DLG_BUTTON_SEP);
3244 if (pend == NULL)
3245 pend = pstart + STRLEN(pstart); // Last button name.
3246 textWidth = GetTextWidth(hdc, pstart, (int)(pend - pstart));
3247 textWidth += dlgPaddingX; /* Padding within button */
3248 textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */
3249 if (textWidth > dlgwidth)
3250 dlgwidth = textWidth;
3251 pstart = pend + 1;
3252 } while (*pend != NUL);
3253 }
3254
3255 if (dlgwidth < DLG_MIN_WIDTH)
3256 dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/
3257
3258 /* start to fill in the dlgtemplate information. addressing by WORDs */
3259 if (s_usenewlook)
3260 lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE |DS_SETFONT;
3261 else
3262 lStyle = DS_MODALFRAME | WS_CAPTION |DS_3DLOOK| WS_VISIBLE;
3263
3264 add_long(lStyle);
3265 add_long(0); // (lExtendedStyle)
3266 pnumitems = p; /*save where the number of items must be stored*/
3267 add_word(0); // NumberOfItems(will change later)
3268 add_word(10); // x
3269 add_word(10); // y
3270 add_word(PixelToDialogX(dlgwidth)); // cx
3271
3272 // Dialog height.
3273 if (vertical)
3274 dlgheight = msgheight + 2 * dlgPaddingY +
3275 DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons;
3276 else
3277 dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight;
3278
3279 // Dialog needs to be taller if contains an edit box.
3280 editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y;
3281 if (textfield != NULL)
3282 dlgheight += editboxheight;
3283
3284 add_word(PixelToDialogY(dlgheight));
3285
3286 add_word(0); // Menu
3287 add_word(0); // Class
3288
3289 /* copy the title of the dialog */
3290 nchar = nCopyAnsiToWideChar(p, (title ?
3291 (LPSTR)title :
3292 (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
3293 p += nchar;
3294
3295 if (s_usenewlook)
3296 {
3297 /* do the font, since DS_3DLOOK doesn't work properly */
3298#ifdef USE_SYSMENU_FONT
3299 if (use_lfSysmenu)
3300 {
3301 /* point size */
3302 *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
3303 GetDeviceCaps(hdc, LOGPIXELSY));
3304 nchar = nCopyAnsiToWideChar(p, TEXT(lfSysmenu.lfFaceName));
3305 }
3306 else
3307#endif
3308 {
3309 *p++ = DLG_FONT_POINT_SIZE; // point size
3310 nchar = nCopyAnsiToWideChar(p, TEXT(DLG_FONT_NAME));
3311 }
3312 p += nchar;
3313 }
3314
3315 buttonYpos = msgheight + 2 * dlgPaddingY;
3316
3317 if (textfield != NULL)
3318 buttonYpos += editboxheight;
3319
3320 pstart = tbuffer;
3321 if (!vertical)
3322 horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */
3323 for (i = 0; i < numButtons; i++)
3324 {
3325 /* get end of this button. */
3326 for ( pend = pstart;
3327 *pend && (*pend != DLG_BUTTON_SEP);
3328 pend++)
3329 ;
3330
3331 if (*pend)
3332 *pend = '\0';
3333
3334 /*
3335 * old NOTE:
3336 * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets
3337 * the focus to the first tab-able button and in so doing makes that
3338 * the default!! Grrr. Workaround: Make the default button the only
3339 * one with WS_TABSTOP style. Means user can't tab between buttons, but
3340 * he/she can use arrow keys.
3341 *
3342 * new NOTE: BS_DEFPUSHBUTTON is required to be able to select the
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00003343 * right button when hitting <Enter>. E.g., for the ":confirm quit"
Bram Moolenaar071d4272004-06-13 20:20:40 +00003344 * dialog. Also needed for when the textfield is the default control.
3345 * It appears to work now (perhaps not on Win95?).
3346 */
3347 if (vertical)
3348 {
3349 p = add_dialog_element(p,
3350 (i == dfltbutton
3351 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
3352 PixelToDialogX(DLG_VERT_PADDING_X),
3353 PixelToDialogY(buttonYpos /* TBK */
3354 + 2 * fontHeight * i),
3355 PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X),
3356 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
3357 (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
3358 }
3359 else
3360 {
3361 p = add_dialog_element(p,
3362 (i == dfltbutton
3363 ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP,
3364 PixelToDialogX(horizWidth + buttonPositions[i]),
3365 PixelToDialogY(buttonYpos), /* TBK */
3366 PixelToDialogX(buttonWidths[i]),
3367 (WORD)(PixelToDialogY(2 * fontHeight) - 1),
3368 (WORD)(IDCANCEL + 1 + i), (WORD)0x0080, pstart);
3369 }
3370 pstart = pend + 1; /*next button*/
3371 }
3372 *pnumitems += numButtons;
3373
3374 /* Vim icon */
3375 p = add_dialog_element(p, SS_ICON,
3376 PixelToDialogX(dlgPaddingX),
3377 PixelToDialogY(dlgPaddingY),
3378 PixelToDialogX(DLG_ICON_WIDTH),
3379 PixelToDialogY(DLG_ICON_HEIGHT),
3380 DLG_NONBUTTON_CONTROL + 0, (WORD)0x0082,
3381 dlg_icons[type]);
3382
Bram Moolenaar748bf032005-02-02 23:04:36 +00003383#if 0
Bram Moolenaar071d4272004-06-13 20:20:40 +00003384 /* Dialog message */
3385 p = add_dialog_element(p, SS_LEFT,
3386 PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
3387 PixelToDialogY(dlgPaddingY),
3388 (WORD)(PixelToDialogX(messageWidth) + 1),
3389 PixelToDialogY(msgheight),
3390 DLG_NONBUTTON_CONTROL + 1, (WORD)0x0082, message);
Bram Moolenaar748bf032005-02-02 23:04:36 +00003391#else
3392 /* Dialog message */
3393 p = add_dialog_element(p, ES_LEFT|scroll_flag|ES_MULTILINE|ES_READONLY,
3394 PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH),
3395 PixelToDialogY(dlgPaddingY),
3396 (WORD)(PixelToDialogX(messageWidth) + 1),
3397 PixelToDialogY(msgheight),
3398 DLG_NONBUTTON_CONTROL + 1, (WORD)0x0081, message);
3399#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00003400
3401 /* Edit box */
3402 if (textfield != NULL)
3403 {
3404 p = add_dialog_element(p, ES_LEFT|ES_AUTOHSCROLL|WS_TABSTOP|WS_BORDER,
3405 PixelToDialogX(2 * dlgPaddingX),
3406 PixelToDialogY(2 * dlgPaddingY + msgheight),
3407 PixelToDialogX(dlgwidth - 4 * dlgPaddingX),
3408 PixelToDialogY(fontHeight + dlgPaddingY),
3409 DLG_NONBUTTON_CONTROL + 2, (WORD)0x0081, textfield);
3410 *pnumitems += 1;
3411 }
3412
3413 *pnumitems += 2;
3414
3415 SelectFont(hdc, oldFont);
3416 DeleteObject(font);
3417 ReleaseDC(hwnd, hdc);
3418
3419 /* Let the dialog_callback() function know which button to make default
3420 * If we have an edit box, make that the default. We also need to tell
3421 * dialog_callback() if this dialog contains an edit box or not. We do
3422 * this by setting s_textfield if it does.
3423 */
3424 if (textfield != NULL)
3425 {
3426 dialog_default_button = DLG_NONBUTTON_CONTROL + 2;
3427 s_textfield = textfield;
3428 }
3429 else
3430 {
3431 dialog_default_button = IDCANCEL + 1 + dfltbutton;
3432 s_textfield = NULL;
3433 }
3434
3435 /* show the dialog box modally and get a return value */
3436 nchar = (int)DialogBoxIndirect(
3437 s_hinst,
3438 (LPDLGTEMPLATE)pdlgtemplate,
3439 s_hwnd,
3440 (DLGPROC)dialog_callback);
3441
3442 LocalFree(LocalHandle(pdlgtemplate));
3443 vim_free(tbuffer);
3444 vim_free(buttonWidths);
3445 vim_free(buttonPositions);
Bram Moolenaar3a7c85b2005-02-05 21:39:53 +00003446 vim_free(ga.ga_data);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003447
3448 /* Focus back to our window (for when MDI is used). */
3449 (void)SetFocus(s_hwnd);
3450
3451 return nchar;
3452}
3453
3454#endif /* FEAT_GUI_DIALOG */
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003455
Bram Moolenaar071d4272004-06-13 20:20:40 +00003456/*
3457 * Put a simple element (basic class) onto a dialog template in memory.
3458 * return a pointer to where the next item should be added.
3459 *
3460 * parameters:
3461 * lStyle = additional style flags
3462 * (be careful, NT3.51 & Win32s will ignore the new ones)
3463 * x,y = x & y positions IN DIALOG UNITS
3464 * w,h = width and height IN DIALOG UNITS
3465 * Id = ID used in messages
3466 * clss = class ID, e.g 0x0080 for a button, 0x0082 for a static
3467 * caption = usually text or resource name
3468 *
3469 * TODO: use the length information noted here to enable the dialog creation
3470 * routines to work out more exactly how much memory they need to alloc.
3471 */
3472 static PWORD
3473add_dialog_element(
3474 PWORD p,
3475 DWORD lStyle,
3476 WORD x,
3477 WORD y,
3478 WORD w,
3479 WORD h,
3480 WORD Id,
3481 WORD clss,
3482 const char *caption)
3483{
3484 int nchar;
3485
3486 p = lpwAlign(p); /* Align to dword boundary*/
3487 lStyle = lStyle | WS_VISIBLE | WS_CHILD;
3488 *p++ = LOWORD(lStyle);
3489 *p++ = HIWORD(lStyle);
3490 *p++ = 0; // LOWORD (lExtendedStyle)
3491 *p++ = 0; // HIWORD (lExtendedStyle)
3492 *p++ = x;
3493 *p++ = y;
3494 *p++ = w;
3495 *p++ = h;
3496 *p++ = Id; //9 or 10 words in all
3497
3498 *p++ = (WORD)0xffff;
3499 *p++ = clss; //2 more here
3500
3501 nchar = nCopyAnsiToWideChar(p, (LPSTR)caption); //strlen(caption)+1
3502 p += nchar;
3503
3504 *p++ = 0; // advance pointer over nExtraStuff WORD - 2 more
3505
3506 return p; //total = 15+ (strlen(caption)) words
3507 // = 30 + 2(strlen(caption) bytes reqd
3508}
3509
3510
3511/*
3512 * Helper routine. Take an input pointer, return closest pointer that is
3513 * aligned on a DWORD (4 byte) boundary. Taken from the Win32SDK samples.
3514 */
3515 static LPWORD
3516lpwAlign(
3517 LPWORD lpIn)
3518{
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003519 long_u ul;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003520
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003521 ul = (long_u)lpIn;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003522 ul += 3;
3523 ul >>= 2;
3524 ul <<= 2;
3525 return (LPWORD)ul;
3526}
3527
3528/*
3529 * Helper routine. Takes second parameter as Ansi string, copies it to first
3530 * parameter as wide character (16-bits / char) string, and returns integer
3531 * number of wide characters (words) in string (including the trailing wide
3532 * char NULL). Partly taken from the Win32SDK samples.
3533 */
3534 static int
3535nCopyAnsiToWideChar(
3536 LPWORD lpWCStr,
3537 LPSTR lpAnsiIn)
3538{
3539 int nChar = 0;
3540#ifdef FEAT_MBYTE
3541 int len = lstrlen(lpAnsiIn) + 1; /* include NUL character */
3542 int i;
3543 WCHAR *wn;
3544
3545 if (enc_codepage == 0 && (int)GetACP() != enc_codepage)
3546 {
3547 /* Not a codepage, use our own conversion function. */
3548 wn = enc_to_ucs2(lpAnsiIn, NULL);
3549 if (wn != NULL)
3550 {
3551 wcscpy(lpWCStr, wn);
Bram Moolenaara93fa7e2006-04-17 22:14:47 +00003552 nChar = (int)wcslen(wn) + 1;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003553 vim_free(wn);
3554 }
3555 }
3556 if (nChar == 0)
3557 /* Use Win32 conversion function. */
3558 nChar = MultiByteToWideChar(
3559 enc_codepage > 0 ? enc_codepage : CP_ACP,
3560 MB_PRECOMPOSED,
3561 lpAnsiIn, len,
3562 lpWCStr, len);
3563 for (i = 0; i < nChar; ++i)
3564 if (lpWCStr[i] == (WORD)'\t') /* replace tabs with spaces */
3565 lpWCStr[i] = (WORD)' ';
3566#else
3567 do
3568 {
3569 if (*lpAnsiIn == '\t')
3570 *lpWCStr++ = (WORD)' ';
3571 else
3572 *lpWCStr++ = (WORD)*lpAnsiIn;
3573 nChar++;
3574 } while (*lpAnsiIn++);
3575#endif
3576
3577 return nChar;
3578}
3579
3580
3581#ifdef FEAT_TEAROFF
3582/*
3583 * The callback function for all the modeless dialogs that make up the
3584 * "tearoff menus" Very simple - forward button presses (to fool Vim into
3585 * thinking its menus have been clicked), and go away when closed.
3586 */
3587 static LRESULT CALLBACK
3588tearoff_callback(
3589 HWND hwnd,
3590 UINT message,
3591 WPARAM wParam,
3592 LPARAM lParam)
3593{
3594 if (message == WM_INITDIALOG)
3595 return (TRUE);
3596
3597 /* May show the mouse pointer again. */
3598 HandleMouseHide(message, lParam);
3599
3600 if (message == WM_COMMAND)
3601 {
3602 if ((WORD)(LOWORD(wParam)) & 0x8000)
3603 {
3604 POINT mp;
3605 RECT rect;
3606
3607 if (GetCursorPos(&mp) && GetWindowRect(hwnd, &rect))
3608 {
3609 (void)TrackPopupMenu(
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003610 (HMENU)(long_u)(LOWORD(wParam) ^ 0x8000),
Bram Moolenaar071d4272004-06-13 20:20:40 +00003611 TPM_LEFTALIGN | TPM_LEFTBUTTON,
3612 (int)rect.right - 8,
3613 (int)mp.y,
3614 (int)0, /*reserved param*/
3615 s_hwnd,
3616 NULL);
3617 /*
3618 * NOTE: The pop-up menu can eat the mouse up event.
3619 * We deal with this in normal.c.
3620 */
3621 }
3622 }
3623 else
3624 /* Pass on messages to the main Vim window */
3625 PostMessage(s_hwnd, WM_COMMAND, LOWORD(wParam), 0);
3626 /*
3627 * Give main window the focus back: this is so after
3628 * choosing a tearoff button you can start typing again
3629 * straight away.
3630 */
3631 (void)SetFocus(s_hwnd);
3632 return TRUE;
3633 }
3634 if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE))
3635 {
3636 DestroyWindow(hwnd);
3637 return TRUE;
3638 }
3639
3640 /* When moved around, give main window the focus back. */
3641 if (message == WM_EXITSIZEMOVE)
3642 (void)SetActiveWindow(s_hwnd);
3643
3644 return FALSE;
3645}
3646#endif
3647
3648
3649/*
3650 * Decide whether to use the "new look" (small, non-bold font) or the "old
3651 * look" (big, clanky font) for dialogs, and work out a few values for use
3652 * later accordingly.
3653 */
3654 static void
3655get_dialog_font_metrics(void)
3656{
3657 HDC hdc;
3658 HFONT hfontTools = 0;
3659 DWORD dlgFontSize;
3660 SIZE size;
3661#ifdef USE_SYSMENU_FONT
3662 LOGFONT lfSysmenu;
3663#endif
3664
3665 s_usenewlook = FALSE;
3666
3667 /*
3668 * For NT3.51 and Win32s, we stick with the old look
3669 * because it matches everything else.
3670 */
3671 if (!is_winnt_3())
3672 {
3673#ifdef USE_SYSMENU_FONT
3674 if (gui_w32_get_menu_font(&lfSysmenu) == OK)
3675 hfontTools = CreateFontIndirect(&lfSysmenu);
3676 else
3677#endif
3678 hfontTools = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0,
3679 0, 0, 0, 0, VARIABLE_PITCH , DLG_FONT_NAME);
3680
3681 if (hfontTools)
3682 {
3683 hdc = GetDC(s_hwnd);
3684 SelectObject(hdc, hfontTools);
3685 /*
3686 * GetTextMetrics() doesn't return the right value in
3687 * tmAveCharWidth, so we have to figure out the dialog base units
3688 * ourselves.
3689 */
3690 GetTextExtentPoint(hdc,
3691 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
3692 52, &size);
3693 ReleaseDC(s_hwnd, hdc);
3694
3695 s_dlgfntwidth = (WORD)((size.cx / 26 + 1) / 2);
3696 s_dlgfntheight = (WORD)size.cy;
3697 s_usenewlook = TRUE;
3698 }
3699 }
3700
3701 if (!s_usenewlook)
3702 {
3703 dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/
3704 s_dlgfntwidth = LOWORD(dlgFontSize);
3705 s_dlgfntheight = HIWORD(dlgFontSize);
3706 }
3707}
3708
3709#if defined(FEAT_MENU) && defined(FEAT_TEAROFF)
3710/*
3711 * Create a pseudo-"tearoff menu" based on the child
3712 * items of a given menu pointer.
3713 */
3714 static void
3715gui_mch_tearoff(
3716 char_u *title,
3717 vimmenu_T *menu,
3718 int initX,
3719 int initY)
3720{
3721 WORD *p, *pdlgtemplate, *pnumitems, *ptrueheight;
3722 int template_len;
3723 int nchar, textWidth, submenuWidth;
3724 DWORD lStyle;
3725 DWORD lExtendedStyle;
3726 WORD dlgwidth;
3727 WORD menuID;
3728 vimmenu_T *pmenu;
3729 vimmenu_T *the_menu = menu;
3730 HWND hwnd;
3731 HDC hdc;
3732 HFONT font, oldFont;
3733 int col, spaceWidth, len;
3734 int columnWidths[2];
3735 char_u *label, *text;
3736 int acLen = 0;
3737 int nameLen;
3738 int padding0, padding1, padding2 = 0;
3739 int sepPadding=0;
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00003740 int x;
3741 int y;
Bram Moolenaar071d4272004-06-13 20:20:40 +00003742#ifdef USE_SYSMENU_FONT
3743 LOGFONT lfSysmenu;
3744 int use_lfSysmenu = FALSE;
3745#endif
3746
3747 /*
3748 * If this menu is already torn off, move it to the mouse position.
3749 */
3750 if (IsWindow(menu->tearoff_handle))
3751 {
3752 POINT mp;
3753 if (GetCursorPos((LPPOINT)&mp))
3754 {
3755 SetWindowPos(menu->tearoff_handle, NULL, mp.x, mp.y, 0, 0,
3756 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER);
3757 }
3758 return;
3759 }
3760
3761 /*
3762 * Create a new tearoff.
3763 */
3764 if (*title == MNU_HIDDEN_CHAR)
3765 title++;
3766
3767 /* Allocate memory to store the dialog template. It's made bigger when
3768 * needed. */
3769 template_len = DLG_ALLOC_SIZE;
3770 pdlgtemplate = p = (WORD *)LocalAlloc(LPTR, template_len);
3771 if (p == NULL)
3772 return;
3773
3774 hwnd = GetDesktopWindow();
3775 hdc = GetWindowDC(hwnd);
3776#ifdef USE_SYSMENU_FONT
3777 if (gui_w32_get_menu_font(&lfSysmenu) == OK)
3778 {
3779 font = CreateFontIndirect(&lfSysmenu);
3780 use_lfSysmenu = TRUE;
3781 }
3782 else
3783#endif
3784 font = CreateFont(-DLG_FONT_POINT_SIZE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3785 VARIABLE_PITCH , DLG_FONT_NAME);
3786 if (s_usenewlook)
3787 oldFont = SelectFont(hdc, font);
3788 else
3789 oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT));
3790
3791 /* Calculate width of a single space. Used for padding columns to the
3792 * right width. */
3793 spaceWidth = GetTextWidth(hdc, " ", 1);
3794
3795 /* Figure out max width of the text column, the accelerator column and the
3796 * optional submenu column. */
3797 submenuWidth = 0;
3798 for (col = 0; col < 2; col++)
3799 {
3800 columnWidths[col] = 0;
3801 for (pmenu = menu->children; pmenu != NULL; pmenu = pmenu->next)
3802 {
3803 /* Use "dname" here to compute the width of the visible text. */
3804 text = (col == 0) ? pmenu->dname : pmenu->actext;
3805 if (text != NULL && *text != NUL)
3806 {
3807 textWidth = GetTextWidthEnc(hdc, text, (int)STRLEN(text));
3808 if (textWidth > columnWidths[col])
3809 columnWidths[col] = textWidth;
3810 }
3811 if (pmenu->children != NULL)
3812 submenuWidth = TEAROFF_COLUMN_PADDING * spaceWidth;
3813 }
3814 }
3815 if (columnWidths[1] == 0)
3816 {
3817 /* no accelerators */
3818 if (submenuWidth != 0)
3819 columnWidths[0] += submenuWidth;
3820 else
3821 columnWidths[0] += spaceWidth;
3822 }
3823 else
3824 {
3825 /* there is an accelerator column */
3826 columnWidths[0] += TEAROFF_COLUMN_PADDING * spaceWidth;
3827 columnWidths[1] += submenuWidth;
3828 }
3829
3830 /*
3831 * Now find the total width of our 'menu'.
3832 */
3833 textWidth = columnWidths[0] + columnWidths[1];
3834 if (submenuWidth != 0)
3835 {
3836 submenuWidth = GetTextWidth(hdc, TEAROFF_SUBMENU_LABEL,
3837 (int)STRLEN(TEAROFF_SUBMENU_LABEL));
3838 textWidth += submenuWidth;
3839 }
3840 dlgwidth = GetTextWidthEnc(hdc, title, (int)STRLEN(title));
3841 if (textWidth > dlgwidth)
3842 dlgwidth = textWidth;
3843 dlgwidth += 2 * TEAROFF_PADDING_X + TEAROFF_BUTTON_PAD_X;
3844
3845 /* W95 can't do thin dialogs, they look v. weird! */
3846 if (mch_windows95() && dlgwidth < TEAROFF_MIN_WIDTH)
3847 dlgwidth = TEAROFF_MIN_WIDTH;
3848
3849 /* start to fill in the dlgtemplate information. addressing by WORDs */
3850 if (s_usenewlook)
3851 lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU |DS_SETFONT| WS_VISIBLE;
3852 else
3853 lStyle = DS_MODALFRAME | WS_CAPTION| WS_SYSMENU | WS_VISIBLE;
3854
3855 lExtendedStyle = WS_EX_TOOLWINDOW|WS_EX_STATICEDGE;
3856 *p++ = LOWORD(lStyle);
3857 *p++ = HIWORD(lStyle);
3858 *p++ = LOWORD(lExtendedStyle);
3859 *p++ = HIWORD(lExtendedStyle);
3860 pnumitems = p; /* save where the number of items must be stored */
3861 *p++ = 0; // NumberOfItems(will change later)
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00003862 gui_mch_getmouse(&x, &y);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003863 if (initX == 0xffffL)
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00003864 *p++ = PixelToDialogX(x); // x
Bram Moolenaar071d4272004-06-13 20:20:40 +00003865 else
3866 *p++ = PixelToDialogX(initX); // x
3867 if (initY == 0xffffL)
Bram Moolenaar9588a0f2005-01-08 21:45:39 +00003868 *p++ = PixelToDialogY(y); // y
Bram Moolenaar071d4272004-06-13 20:20:40 +00003869 else
3870 *p++ = PixelToDialogY(initY); // y
3871 *p++ = PixelToDialogX(dlgwidth); // cx
3872 ptrueheight = p;
3873 *p++ = 0; // dialog height: changed later anyway
3874 *p++ = 0; // Menu
3875 *p++ = 0; // Class
3876
3877 /* copy the title of the dialog */
3878 nchar = nCopyAnsiToWideChar(p, ((*title)
3879 ? (LPSTR)title
3880 : (LPSTR)("Vim "VIM_VERSION_MEDIUM)));
3881 p += nchar;
3882
3883 if (s_usenewlook)
3884 {
3885 /* do the font, since DS_3DLOOK doesn't work properly */
3886#ifdef USE_SYSMENU_FONT
3887 if (use_lfSysmenu)
3888 {
3889 /* point size */
3890 *p++ = -MulDiv(lfSysmenu.lfHeight, 72,
3891 GetDeviceCaps(hdc, LOGPIXELSY));
3892 nchar = nCopyAnsiToWideChar(p, TEXT(lfSysmenu.lfFaceName));
3893 }
3894 else
3895#endif
3896 {
3897 *p++ = DLG_FONT_POINT_SIZE; // point size
3898 nchar = nCopyAnsiToWideChar (p, TEXT(DLG_FONT_NAME));
3899 }
3900 p += nchar;
3901 }
3902
3903 /*
3904 * Loop over all the items in the menu.
3905 * But skip over the tearbar.
3906 */
3907 if (STRCMP(menu->children->name, TEAR_STRING) == 0)
3908 menu = menu->children->next;
3909 else
3910 menu = menu->children;
3911 for ( ; menu != NULL; menu = menu->next)
3912 {
3913 if (menu->modes == 0) /* this menu has just been deleted */
3914 continue;
3915 if (menu_is_separator(menu->dname))
3916 {
3917 sepPadding += 3;
3918 continue;
3919 }
3920
3921 /* Check if there still is plenty of room in the template. Make it
3922 * larger when needed. */
3923 if (((char *)p - (char *)pdlgtemplate) + 1000 > template_len)
3924 {
3925 WORD *newp;
3926
3927 newp = (WORD *)LocalAlloc(LPTR, template_len + 4096);
3928 if (newp != NULL)
3929 {
3930 template_len += 4096;
3931 mch_memmove(newp, pdlgtemplate,
3932 (char *)p - (char *)pdlgtemplate);
3933 p = newp + (p - pdlgtemplate);
3934 pnumitems = newp + (pnumitems - pdlgtemplate);
3935 ptrueheight = newp + (ptrueheight - pdlgtemplate);
3936 LocalFree(LocalHandle(pdlgtemplate));
3937 pdlgtemplate = newp;
3938 }
3939 }
3940
3941 /* Figure out minimal length of this menu label. Use "name" for the
3942 * actual text, "dname" for estimating the displayed size. "name"
3943 * has "&a" for mnemonic and includes the accelerator. */
3944 len = nameLen = (int)STRLEN(menu->name);
3945 padding0 = (columnWidths[0] - GetTextWidthEnc(hdc, menu->dname,
3946 (int)STRLEN(menu->dname))) / spaceWidth;
3947 len += padding0;
3948
3949 if (menu->actext != NULL)
3950 {
3951 acLen = (int)STRLEN(menu->actext);
3952 len += acLen;
3953 textWidth = GetTextWidthEnc(hdc, menu->actext, acLen);
3954 }
3955 else
3956 textWidth = 0;
3957 padding1 = (columnWidths[1] - textWidth) / spaceWidth;
3958 len += padding1;
3959
3960 if (menu->children == NULL)
3961 {
3962 padding2 = submenuWidth / spaceWidth;
3963 len += padding2;
3964 menuID = (WORD)(menu->id);
3965 }
3966 else
3967 {
3968 len += (int)STRLEN(TEAROFF_SUBMENU_LABEL);
Bram Moolenaareb3593b2006-04-22 22:33:57 +00003969 menuID = (WORD)((long_u)(menu->submenu_id) | (DWORD)0x8000);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003970 }
3971
3972 /* Allocate menu label and fill it in */
3973 text = label = alloc((unsigned)len + 1);
3974 if (label == NULL)
3975 break;
3976
Bram Moolenaarce0842a2005-07-18 21:58:11 +00003977 vim_strncpy(text, menu->name, nameLen);
Bram Moolenaar071d4272004-06-13 20:20:40 +00003978 text = vim_strchr(text, TAB); /* stop at TAB before actext */
3979 if (text == NULL)
3980 text = label + nameLen; /* no actext, use whole name */
3981 while (padding0-- > 0)
3982 *text++ = ' ';
3983 if (menu->actext != NULL)
3984 {
3985 STRNCPY(text, menu->actext, acLen);
3986 text += acLen;
3987 }
3988 while (padding1-- > 0)
3989 *text++ = ' ';
3990 if (menu->children != NULL)
3991 {
3992 STRCPY(text, TEAROFF_SUBMENU_LABEL);
3993 text += STRLEN(TEAROFF_SUBMENU_LABEL);
3994 }
3995 else
3996 {
3997 while (padding2-- > 0)
3998 *text++ = ' ';
3999 }
4000 *text = NUL;
4001
4002 /*
4003 * BS_LEFT will just be ignored on Win32s/NT3.5x - on
4004 * W95/NT4 it makes the tear-off look more like a menu.
4005 */
4006 p = add_dialog_element(p,
4007 BS_PUSHBUTTON|BS_LEFT,
4008 (WORD)PixelToDialogX(TEAROFF_PADDING_X),
4009 (WORD)(sepPadding + 1 + 13 * (*pnumitems)),
4010 (WORD)PixelToDialogX(dlgwidth - 2 * TEAROFF_PADDING_X),
4011 (WORD)12,
4012 menuID, (WORD)0x0080, label);
4013 vim_free(label);
4014 (*pnumitems)++;
4015 }
4016
4017 *ptrueheight = (WORD)(sepPadding + 1 + 13 * (*pnumitems));
4018
4019
4020 /* show modelessly */
4021 the_menu->tearoff_handle = CreateDialogIndirect(
4022 s_hinst,
4023 (LPDLGTEMPLATE)pdlgtemplate,
4024 s_hwnd,
4025 (DLGPROC)tearoff_callback);
4026
4027 LocalFree(LocalHandle(pdlgtemplate));
4028 SelectFont(hdc, oldFont);
4029 DeleteObject(font);
4030 ReleaseDC(hwnd, hdc);
4031
4032 /*
4033 * Reassert ourselves as the active window. This is so that after creating
4034 * a tearoff, the user doesn't have to click with the mouse just to start
4035 * typing again!
4036 */
4037 (void)SetActiveWindow(s_hwnd);
4038
4039 /* make sure the right buttons are enabled */
4040 force_menu_update = TRUE;
4041}
4042#endif
4043
4044#if defined(FEAT_TOOLBAR) || defined(PROTO)
4045#include "gui_w32_rc.h"
4046
4047/* This not defined in older SDKs */
4048# ifndef TBSTYLE_FLAT
4049# define TBSTYLE_FLAT 0x0800
4050# endif
4051
4052/*
4053 * Create the toolbar, initially unpopulated.
4054 * (just like the menu, there are no defaults, it's all
4055 * set up through menu.vim)
4056 */
4057 static void
4058initialise_toolbar(void)
4059{
4060 InitCommonControls();
4061 s_toolbarhwnd = CreateToolbarEx(
4062 s_hwnd,
4063 WS_CHILD | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT,
4064 4000, //any old big number
Bram Moolenaar2c7a7632007-05-10 18:19:11 +00004065 31, //number of images in initial bitmap
Bram Moolenaar071d4272004-06-13 20:20:40 +00004066 s_hinst,
4067 IDR_TOOLBAR1, // id of initial bitmap
4068 NULL,
4069 0, // initial number of buttons
4070 TOOLBAR_BUTTON_WIDTH, //api guide is wrong!
4071 TOOLBAR_BUTTON_HEIGHT,
4072 TOOLBAR_BUTTON_WIDTH,
4073 TOOLBAR_BUTTON_HEIGHT,
4074 sizeof(TBBUTTON)
4075 );
4076
4077 gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL);
4078}
4079
4080 static int
4081get_toolbar_bitmap(vimmenu_T *menu)
4082{
4083 int i = -1;
4084
4085 /*
4086 * Check user bitmaps first, unless builtin is specified.
4087 */
4088 if (!is_winnt_3() && !menu->icon_builtin)
4089 {
4090 char_u fname[MAXPATHL];
4091 HANDLE hbitmap = NULL;
4092
4093 if (menu->iconfile != NULL)
4094 {
4095 gui_find_iconfile(menu->iconfile, fname, "bmp");
4096 hbitmap = LoadImage(
4097 NULL,
4098 fname,
4099 IMAGE_BITMAP,
4100 TOOLBAR_BUTTON_WIDTH,
4101 TOOLBAR_BUTTON_HEIGHT,
4102 LR_LOADFROMFILE |
4103 LR_LOADMAP3DCOLORS
4104 );
4105 }
4106
4107 /*
4108 * If the LoadImage call failed, or the "icon=" file
4109 * didn't exist or wasn't specified, try the menu name
4110 */
4111 if (hbitmap == NULL
4112 && (gui_find_bitmap(menu->name, fname, "bmp") == OK))
4113 hbitmap = LoadImage(
4114 NULL,
4115 fname,
4116 IMAGE_BITMAP,
4117 TOOLBAR_BUTTON_WIDTH,
4118 TOOLBAR_BUTTON_HEIGHT,
4119 LR_LOADFROMFILE |
4120 LR_LOADMAP3DCOLORS
4121 );
4122
4123 if (hbitmap != NULL)
4124 {
4125 TBADDBITMAP tbAddBitmap;
4126
4127 tbAddBitmap.hInst = NULL;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004128 tbAddBitmap.nID = (long_u)hbitmap;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004129
4130 i = (int)SendMessage(s_toolbarhwnd, TB_ADDBITMAP,
4131 (WPARAM)1, (LPARAM)&tbAddBitmap);
4132 /* i will be set to -1 if it fails */
4133 }
4134 }
4135 if (i == -1 && menu->iconidx >= 0 && menu->iconidx < TOOLBAR_BITMAP_COUNT)
4136 i = menu->iconidx;
4137
4138 return i;
4139}
4140#endif
4141
Bram Moolenaar3991dab2006-03-27 17:01:56 +00004142#if defined(FEAT_GUI_TABLINE) || defined(PROTO)
4143 static void
4144initialise_tabline(void)
4145{
4146 InitCommonControls();
4147
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004148 s_tabhwnd = CreateWindow(WC_TABCONTROL, "Vim tabline",
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004149 WS_CHILD|TCS_FOCUSNEVER|TCS_TOOLTIPS,
Bram Moolenaar3991dab2006-03-27 17:01:56 +00004150 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
4151 CW_USEDEFAULT, s_hwnd, NULL, s_hinst, NULL);
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004152
Bram Moolenaar551dbcc2006-04-25 22:13:59 +00004153 gui.tabline_height = TABLINE_HEIGHT;
4154
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004155# ifdef USE_SYSMENU_FONT
Bram Moolenaar551dbcc2006-04-25 22:13:59 +00004156 set_tabline_font();
Bram Moolenaar910f66f2006-04-05 20:41:53 +00004157# endif
Bram Moolenaar3991dab2006-03-27 17:01:56 +00004158}
4159#endif
4160
Bram Moolenaar071d4272004-06-13 20:20:40 +00004161#if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO)
4162/*
4163 * Make the GUI window come to the foreground.
4164 */
4165 void
4166gui_mch_set_foreground(void)
4167{
4168 if (IsIconic(s_hwnd))
4169 SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0);
4170 SetForegroundWindow(s_hwnd);
4171}
4172#endif
4173
4174#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME)
4175 static void
4176dyn_imm_load(void)
4177{
4178 hLibImm = LoadLibrary("imm32.dll");
4179 if (hLibImm == NULL)
4180 return;
4181
4182 pImmGetCompositionStringA
4183 = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringA");
4184 pImmGetCompositionStringW
4185 = (void *)GetProcAddress(hLibImm, "ImmGetCompositionStringW");
4186 pImmGetContext
4187 = (void *)GetProcAddress(hLibImm, "ImmGetContext");
4188 pImmAssociateContext
4189 = (void *)GetProcAddress(hLibImm, "ImmAssociateContext");
4190 pImmReleaseContext
4191 = (void *)GetProcAddress(hLibImm, "ImmReleaseContext");
4192 pImmGetOpenStatus
4193 = (void *)GetProcAddress(hLibImm, "ImmGetOpenStatus");
4194 pImmSetOpenStatus
4195 = (void *)GetProcAddress(hLibImm, "ImmSetOpenStatus");
4196 pImmGetCompositionFont
4197 = (void *)GetProcAddress(hLibImm, "ImmGetCompositionFontA");
4198 pImmSetCompositionFont
4199 = (void *)GetProcAddress(hLibImm, "ImmSetCompositionFontA");
4200 pImmSetCompositionWindow
4201 = (void *)GetProcAddress(hLibImm, "ImmSetCompositionWindow");
4202 pImmGetConversionStatus
4203 = (void *)GetProcAddress(hLibImm, "ImmGetConversionStatus");
Bram Moolenaarca003e12006-03-17 23:19:38 +00004204 pImmSetConversionStatus
4205 = (void *)GetProcAddress(hLibImm, "ImmSetConversionStatus");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004206
4207 if ( pImmGetCompositionStringA == NULL
4208 || pImmGetCompositionStringW == NULL
4209 || pImmGetContext == NULL
4210 || pImmAssociateContext == NULL
4211 || pImmReleaseContext == NULL
4212 || pImmGetOpenStatus == NULL
4213 || pImmSetOpenStatus == NULL
4214 || pImmGetCompositionFont == NULL
4215 || pImmSetCompositionFont == NULL
4216 || pImmSetCompositionWindow == NULL
Bram Moolenaarca003e12006-03-17 23:19:38 +00004217 || pImmGetConversionStatus == NULL
4218 || pImmSetConversionStatus == NULL)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004219 {
4220 FreeLibrary(hLibImm);
4221 hLibImm = NULL;
4222 pImmGetContext = NULL;
4223 return;
4224 }
4225
4226 return;
4227}
4228
4229# if 0 /* not used */
4230 int
4231dyn_imm_unload(void)
4232{
4233 if (!hLibImm)
4234 return FALSE;
4235 FreeLibrary(hLibImm);
4236 hLibImm = NULL;
4237 return TRUE;
4238}
4239# endif
4240
4241#endif
4242
4243#if defined(FEAT_SIGN_ICONS) || defined(PROTO)
4244
4245# ifdef FEAT_XPM_W32
4246# define IMAGE_XPM 100
4247# endif
4248
4249typedef struct _signicon_t
4250{
4251 HANDLE hImage;
4252 UINT uType;
4253#ifdef FEAT_XPM_W32
4254 HANDLE hShape; /* Mask bitmap handle */
4255#endif
4256} signicon_t;
4257
4258 void
4259gui_mch_drawsign(row, col, typenr)
4260 int row;
4261 int col;
4262 int typenr;
4263{
4264 signicon_t *sign;
4265 int x, y, w, h;
4266
4267 if (!gui.in_use || (sign = (signicon_t *)sign_get_image(typenr)) == NULL)
4268 return;
4269
4270 x = TEXT_X(col);
4271 y = TEXT_Y(row);
4272 w = gui.char_width * 2;
4273 h = gui.char_height;
4274 switch (sign->uType)
4275 {
4276 case IMAGE_BITMAP:
4277 {
4278 HDC hdcMem;
4279 HBITMAP hbmpOld;
4280
4281 hdcMem = CreateCompatibleDC(s_hdc);
4282 hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hImage);
4283 BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCCOPY);
4284 SelectObject(hdcMem, hbmpOld);
4285 DeleteDC(hdcMem);
4286 }
4287 break;
4288 case IMAGE_ICON:
4289 case IMAGE_CURSOR:
4290 DrawIconEx(s_hdc, x, y, (HICON)sign->hImage, w, h, 0, NULL, DI_NORMAL);
4291 break;
4292#ifdef FEAT_XPM_W32
4293 case IMAGE_XPM:
4294 {
4295 HDC hdcMem;
4296 HBITMAP hbmpOld;
4297
4298 hdcMem = CreateCompatibleDC(s_hdc);
4299 hbmpOld = (HBITMAP)SelectObject(hdcMem, sign->hShape);
4300 /* Make hole */
4301 BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCAND);
4302
4303 SelectObject(hdcMem, sign->hImage);
4304 /* Paint sign */
4305 BitBlt(s_hdc, x, y, w, h, hdcMem, 0, 0, SRCPAINT);
4306 SelectObject(hdcMem, hbmpOld);
4307 DeleteDC(hdcMem);
4308 }
4309 break;
4310#endif
4311 }
4312}
4313
4314 static void
4315close_signicon_image(signicon_t *sign)
4316{
4317 if (sign)
4318 switch (sign->uType)
4319 {
4320 case IMAGE_BITMAP:
4321 DeleteObject((HGDIOBJ)sign->hImage);
4322 break;
4323 case IMAGE_CURSOR:
4324 DestroyCursor((HCURSOR)sign->hImage);
4325 break;
4326 case IMAGE_ICON:
4327 DestroyIcon((HICON)sign->hImage);
4328 break;
4329#ifdef FEAT_XPM_W32
4330 case IMAGE_XPM:
4331 DeleteObject((HBITMAP)sign->hImage);
4332 DeleteObject((HBITMAP)sign->hShape);
4333 break;
4334#endif
4335 }
4336}
4337
4338 void *
4339gui_mch_register_sign(signfile)
4340 char_u *signfile;
4341{
4342 signicon_t sign, *psign;
4343 char_u *ext;
4344
4345 if (is_winnt_3())
4346 {
4347 EMSG(_(e_signdata));
4348 return NULL;
4349 }
4350
4351 sign.hImage = NULL;
4352 ext = signfile + STRLEN(signfile) - 4; /* get extention */
4353 if (ext > signfile)
4354 {
4355 int do_load = 1;
4356
4357 if (!STRICMP(ext, ".bmp"))
4358 sign.uType = IMAGE_BITMAP;
4359 else if (!STRICMP(ext, ".ico"))
4360 sign.uType = IMAGE_ICON;
4361 else if (!STRICMP(ext, ".cur") || !STRICMP(ext, ".ani"))
4362 sign.uType = IMAGE_CURSOR;
4363 else
4364 do_load = 0;
4365
4366 if (do_load)
4367 sign.hImage = (HANDLE)LoadImage(NULL, signfile, sign.uType,
4368 gui.char_width * 2, gui.char_height,
4369 LR_LOADFROMFILE | LR_CREATEDIBSECTION);
4370#ifdef FEAT_XPM_W32
4371 if (!STRICMP(ext, ".xpm"))
4372 {
4373 sign.uType = IMAGE_XPM;
4374 LoadXpmImage(signfile, (HBITMAP *)&sign.hImage, (HBITMAP *)&sign.hShape);
4375 }
4376#endif
4377 }
4378
4379 psign = NULL;
4380 if (sign.hImage && (psign = (signicon_t *)alloc(sizeof(signicon_t)))
4381 != NULL)
4382 *psign = sign;
4383
4384 if (!psign)
4385 {
4386 if (sign.hImage)
4387 close_signicon_image(&sign);
4388 EMSG(_(e_signdata));
4389 }
4390 return (void *)psign;
4391
4392}
4393
4394 void
4395gui_mch_destroy_sign(sign)
4396 void *sign;
4397{
4398 if (sign)
4399 {
4400 close_signicon_image((signicon_t *)sign);
4401 vim_free(sign);
4402 }
4403}
Bram Moolenaar5c06f8b2005-05-31 22:14:58 +00004404#endif
Bram Moolenaar071d4272004-06-13 20:20:40 +00004405
4406#if defined(FEAT_BEVAL) || defined(PROTO)
4407
4408/* BALLOON-EVAL IMPLEMENTATION FOR WINDOWS.
Bram Moolenaar2ce06f62005-01-31 19:19:04 +00004409 * Added by Sergey Khorev <sergey.khorev@gmail.com>
Bram Moolenaar071d4272004-06-13 20:20:40 +00004410 *
Bram Moolenaare4efc3b2005-03-07 23:16:51 +00004411 * The only reused thing is gui_beval.h and get_beval_info()
Bram Moolenaar071d4272004-06-13 20:20:40 +00004412 * from gui_beval.c (note it uses x and y of the BalloonEval struct
4413 * to get current mouse position).
4414 *
4415 * Trying to use as more Windows services as possible, and as less
4416 * IE version as possible :)).
4417 *
4418 * 1) Don't create ToolTip in gui_mch_create_beval_area, only initialize
4419 * BalloonEval struct.
4420 * 2) Enable/Disable simply create/kill BalloonEval Timer
4421 * 3) When there was enough inactivity, timer procedure posts
4422 * async request to debugger
4423 * 4) gui_mch_post_balloon (invoked from netbeans.c) creates tooltip control
4424 * and performs some actions to show it ASAP
4425 * 5) WM_NOTOFY:TTN_POP destroys created tooltip
4426 */
4427
Bram Moolenaar45360022005-07-21 21:08:21 +00004428/*
4429 * determine whether installed Common Controls support multiline tooltips
4430 * (i.e. their version is >= 4.70
4431 */
4432 int
4433multiline_balloon_available(void)
4434{
4435 HINSTANCE hDll;
4436 static char comctl_dll[] = "comctl32.dll";
4437 static int multiline_tip = MAYBE;
4438
4439 if (multiline_tip != MAYBE)
4440 return multiline_tip;
4441
4442 hDll = GetModuleHandle(comctl_dll);
4443 if (hDll != NULL)
4444 {
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004445 DLLGETVERSIONPROC pGetVer;
4446 pGetVer = (DLLGETVERSIONPROC)GetProcAddress(hDll, "DllGetVersion");
Bram Moolenaar45360022005-07-21 21:08:21 +00004447
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004448 if (pGetVer != NULL)
4449 {
4450 DLLVERSIONINFO dvi;
4451 HRESULT hr;
Bram Moolenaar45360022005-07-21 21:08:21 +00004452
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004453 ZeroMemory(&dvi, sizeof(dvi));
4454 dvi.cbSize = sizeof(dvi);
Bram Moolenaar45360022005-07-21 21:08:21 +00004455
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004456 hr = (*pGetVer)(&dvi);
Bram Moolenaar45360022005-07-21 21:08:21 +00004457
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004458 if (SUCCEEDED(hr)
Bram Moolenaar45360022005-07-21 21:08:21 +00004459 && (dvi.dwMajorVersion > 4
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004460 || (dvi.dwMajorVersion == 4
4461 && dvi.dwMinorVersion >= 70)))
Bram Moolenaar45360022005-07-21 21:08:21 +00004462 {
4463 multiline_tip = TRUE;
4464 return multiline_tip;
4465 }
Bram Moolenaarc9b4b052006-04-30 18:54:39 +00004466 }
Bram Moolenaar45360022005-07-21 21:08:21 +00004467 else
4468 {
4469 /* there is chance we have ancient CommCtl 4.70
4470 which doesn't export DllGetVersion */
4471 DWORD dwHandle = 0;
4472 DWORD len = GetFileVersionInfoSize(comctl_dll, &dwHandle);
4473 if (len > 0)
4474 {
4475 VS_FIXEDFILEINFO *ver;
4476 UINT vlen = 0;
4477 void *data = alloc(len);
4478
4479 if (data != NULL
4480 && GetFileVersionInfo(comctl_dll, 0, len, data)
4481 && VerQueryValue(data, "\\", (void **)&ver, &vlen)
4482 && vlen
4483 && HIWORD(ver->dwFileVersionMS) > 4
4484 || (HIWORD(ver->dwFileVersionMS) == 4
4485 && LOWORD(ver->dwFileVersionMS) >= 70))
4486 {
4487 vim_free(data);
4488 multiline_tip = TRUE;
4489 return multiline_tip;
4490 }
4491 vim_free(data);
4492 }
4493 }
4494 }
4495 multiline_tip = FALSE;
4496 return multiline_tip;
4497}
4498
Bram Moolenaar071d4272004-06-13 20:20:40 +00004499 static void
4500make_tooltip(beval, text, pt)
4501 BalloonEval *beval;
4502 char *text;
4503 POINT pt;
4504{
Bram Moolenaar45360022005-07-21 21:08:21 +00004505 TOOLINFO *pti;
4506 int ToolInfoSize;
4507
4508 if (multiline_balloon_available() == TRUE)
4509 ToolInfoSize = sizeof(TOOLINFO_NEW);
4510 else
4511 ToolInfoSize = sizeof(TOOLINFO);
4512
4513 pti = (TOOLINFO *)alloc(ToolInfoSize);
4514 if (pti == NULL)
4515 return;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004516
4517 beval->balloon = CreateWindowEx(WS_EX_TOPMOST, TOOLTIPS_CLASS,
4518 NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP,
4519 CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
4520 beval->target, NULL, s_hinst, NULL);
4521
4522 SetWindowPos(beval->balloon, HWND_TOPMOST, 0, 0, 0, 0,
4523 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE);
4524
Bram Moolenaar45360022005-07-21 21:08:21 +00004525 pti->cbSize = ToolInfoSize;
4526 pti->uFlags = TTF_SUBCLASS;
4527 pti->hwnd = beval->target;
4528 pti->hinst = 0; /* Don't use string resources */
4529 pti->uId = ID_BEVAL_TOOLTIP;
4530
4531 if (multiline_balloon_available() == TRUE)
4532 {
4533 RECT rect;
4534 TOOLINFO_NEW *ptin = (TOOLINFO_NEW *)pti;
4535 pti->lpszText = LPSTR_TEXTCALLBACK;
4536 ptin->lParam = (LPARAM)text;
4537 if (GetClientRect(s_textArea, &rect)) /* switch multiline tooltips on */
4538 SendMessage(beval->balloon, TTM_SETMAXTIPWIDTH, 0,
4539 (LPARAM)rect.right);
4540 }
4541 else
4542 pti->lpszText = text; /* do this old way */
Bram Moolenaar071d4272004-06-13 20:20:40 +00004543
4544 /* Limit ballooneval bounding rect to CursorPos neighbourhood */
Bram Moolenaar45360022005-07-21 21:08:21 +00004545 pti->rect.left = pt.x - 3;
4546 pti->rect.top = pt.y - 3;
4547 pti->rect.right = pt.x + 3;
4548 pti->rect.bottom = pt.y + 3;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004549
Bram Moolenaar45360022005-07-21 21:08:21 +00004550 SendMessage(beval->balloon, TTM_ADDTOOL, 0, (LPARAM)pti);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004551 /* Make tooltip appear sooner */
4552 SendMessage(beval->balloon, TTM_SETDELAYTIME, TTDT_INITIAL, 10);
4553 /*
4554 * HACK: force tooltip to appear, because it'll not appear until
4555 * first mouse move. D*mn M$
4556 */
4557 mouse_event(MOUSEEVENTF_MOVE, 1, 1, 0, 0);
4558 mouse_event(MOUSEEVENTF_MOVE, (DWORD)-1, (DWORD)-1, 0, 0);
Bram Moolenaar45360022005-07-21 21:08:21 +00004559 vim_free(pti);
Bram Moolenaar071d4272004-06-13 20:20:40 +00004560}
4561
4562 static void
4563delete_tooltip(beval)
4564 BalloonEval *beval;
4565{
4566 DestroyWindow(beval->balloon);
4567}
4568
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00004569/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004570 static VOID CALLBACK
4571BevalTimerProc(hwnd, uMsg, idEvent, dwTime)
4572 HWND hwnd;
4573 UINT uMsg;
Bram Moolenaareb3593b2006-04-22 22:33:57 +00004574 UINT_PTR idEvent;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004575 DWORD dwTime;
4576{
4577 POINT pt;
4578 RECT rect;
4579
4580 if (cur_beval == NULL || cur_beval->showState == ShS_SHOWING || !p_beval)
4581 return;
4582
4583 GetCursorPos(&pt);
4584 if (WindowFromPoint(pt) != s_textArea)
4585 return;
4586
4587 ScreenToClient(s_textArea, &pt);
4588 GetClientRect(s_textArea, &rect);
4589 if (!PtInRect(&rect, pt))
4590 return;
4591
4592 if (LastActivity > 0
4593 && (dwTime - LastActivity) >= (DWORD)p_bdlay
4594 && (cur_beval->showState != ShS_PENDING
4595 || abs(cur_beval->x - pt.x) > 3
4596 || abs(cur_beval->y - pt.y) > 3))
4597 {
4598 /* Pointer resting in one place long enough, it's time to show
4599 * the tooltip. */
4600 cur_beval->showState = ShS_PENDING;
4601 cur_beval->x = pt.x;
4602 cur_beval->y = pt.y;
4603
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004604 // TRACE0("BevalTimerProc: sending request");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004605
4606 if (cur_beval->msgCB != NULL)
4607 (*cur_beval->msgCB)(cur_beval, 0);
4608 }
4609}
4610
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00004611/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004612 void
4613gui_mch_disable_beval_area(beval)
4614 BalloonEval *beval;
4615{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004616 // TRACE0("gui_mch_disable_beval_area {{{");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004617 KillTimer(s_textArea, BevalTimerId);
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004618 // TRACE0("gui_mch_disable_beval_area }}}");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004619}
4620
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00004621/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004622 void
4623gui_mch_enable_beval_area(beval)
4624 BalloonEval *beval;
4625{
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004626 // TRACE0("gui_mch_enable_beval_area |||");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004627 if (beval == NULL)
4628 return;
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004629 // TRACE0("gui_mch_enable_beval_area {{{");
Bram Moolenaar551dbcc2006-04-25 22:13:59 +00004630 BevalTimerId = SetTimer(s_textArea, 0, p_bdlay / 2, BevalTimerProc);
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004631 // TRACE0("gui_mch_enable_beval_area }}}");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004632}
4633
4634 void
4635gui_mch_post_balloon(beval, mesg)
4636 BalloonEval *beval;
4637 char_u *mesg;
4638{
4639 POINT pt;
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004640 // TRACE0("gui_mch_post_balloon {{{");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004641 if (beval->showState == ShS_SHOWING)
4642 return;
4643 GetCursorPos(&pt);
4644 ScreenToClient(s_textArea, &pt);
4645
4646 if (abs(beval->x - pt.x) < 3 && abs(beval->y - pt.y) < 3)
4647 /* cursor is still here */
4648 {
4649 gui_mch_disable_beval_area(cur_beval);
4650 beval->showState = ShS_SHOWING;
4651 make_tooltip(beval, mesg, pt);
4652 }
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004653 // TRACE0("gui_mch_post_balloon }}}");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004654}
4655
Bram Moolenaard857f0e2005-06-21 22:37:39 +00004656/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004657 BalloonEval *
4658gui_mch_create_beval_area(target, mesg, mesgCB, clientData)
4659 void *target; /* ignored, always use s_textArea */
4660 char_u *mesg;
4661 void (*mesgCB)__ARGS((BalloonEval *, int));
4662 void *clientData;
4663{
4664 /* partially stolen from gui_beval.c */
4665 BalloonEval *beval;
4666
4667 if (mesg != NULL && mesgCB != NULL)
4668 {
4669 EMSG(_("E232: Cannot create BalloonEval with both message and callback"));
4670 return NULL;
4671 }
4672
4673 beval = (BalloonEval *)alloc(sizeof(BalloonEval));
4674 if (beval != NULL)
4675 {
4676 beval->target = s_textArea;
4677 beval->balloon = NULL;
4678
4679 beval->showState = ShS_NEUTRAL;
4680 beval->x = 0;
4681 beval->y = 0;
4682 beval->msg = mesg;
4683 beval->msgCB = mesgCB;
4684 beval->clientData = clientData;
4685
4686 InitCommonControls();
Bram Moolenaar071d4272004-06-13 20:20:40 +00004687 cur_beval = beval;
4688
4689 if (p_beval)
4690 gui_mch_enable_beval_area(beval);
4691
4692 }
4693 return beval;
4694}
4695
Bram Moolenaar9ba0eb82005-06-13 22:28:56 +00004696/*ARGSUSED*/
Bram Moolenaar071d4272004-06-13 20:20:40 +00004697 static void
4698Handle_WM_Notify(hwnd, pnmh)
4699 HWND hwnd;
4700 LPNMHDR pnmh;
4701{
4702 if (pnmh->idFrom != ID_BEVAL_TOOLTIP) /* it is not our tooltip */
4703 return;
4704
4705 if (cur_beval != NULL)
4706 {
Bram Moolenaar45360022005-07-21 21:08:21 +00004707 switch (pnmh->code)
Bram Moolenaar071d4272004-06-13 20:20:40 +00004708 {
Bram Moolenaar45360022005-07-21 21:08:21 +00004709 case TTN_SHOW:
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004710 // TRACE0("TTN_SHOW {{{");
4711 // TRACE0("TTN_SHOW }}}");
Bram Moolenaar45360022005-07-21 21:08:21 +00004712 break;
4713 case TTN_POP: /* Before tooltip disappear */
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004714 // TRACE0("TTN_POP {{{");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004715 delete_tooltip(cur_beval);
4716 gui_mch_enable_beval_area(cur_beval);
Bram Moolenaare2cc9702005-03-15 22:43:58 +00004717 // TRACE0("TTN_POP }}}");
Bram Moolenaar071d4272004-06-13 20:20:40 +00004718
4719 cur_beval->showState = ShS_NEUTRAL;
Bram Moolenaar45360022005-07-21 21:08:21 +00004720 break;
4721 case TTN_GETDISPINFO:
4722 {
4723 /* if you get there then we have new common controls */
4724 NMTTDISPINFO_NEW *info = (NMTTDISPINFO_NEW *)pnmh;
4725 info->lpszText = (LPSTR)info->lParam;
4726 info->uFlags |= TTF_DI_SETITEM;
4727 }
4728 break;
Bram Moolenaar071d4272004-06-13 20:20:40 +00004729 }
4730 }
4731}
4732
4733 static void
4734TrackUserActivity(UINT uMsg)
4735{
4736 if ((uMsg >= WM_MOUSEFIRST && uMsg <= WM_MOUSELAST)
4737 || (uMsg >= WM_KEYFIRST && uMsg <= WM_KEYLAST))
4738 LastActivity = GetTickCount();
4739}
4740
4741 void
4742gui_mch_destroy_beval_area(beval)
4743 BalloonEval *beval;
4744{
4745 vim_free(beval);
4746}
4747#endif /* FEAT_BEVAL */
4748
4749#if defined(FEAT_NETBEANS_INTG) || defined(PROTO)
4750/*
4751 * We have multiple signs to draw at the same location. Draw the
4752 * multi-sign indicator (down-arrow) instead. This is the Win32 version.
4753 */
4754 void
4755netbeans_draw_multisign_indicator(int row)
4756{
4757 int i;
4758 int y;
4759 int x;
4760
4761 x = 0;
4762 y = TEXT_Y(row);
4763
4764 for (i = 0; i < gui.char_height - 3; i++)
4765 SetPixel(s_hdc, x+2, y++, gui.currFgColor);
4766
4767 SetPixel(s_hdc, x+0, y, gui.currFgColor);
4768 SetPixel(s_hdc, x+2, y, gui.currFgColor);
4769 SetPixel(s_hdc, x+4, y++, gui.currFgColor);
4770 SetPixel(s_hdc, x+1, y, gui.currFgColor);
4771 SetPixel(s_hdc, x+2, y, gui.currFgColor);
4772 SetPixel(s_hdc, x+3, y++, gui.currFgColor);
4773 SetPixel(s_hdc, x+2, y, gui.currFgColor);
4774}
4775#endif