diff options
Diffstat (limited to 'src/gui_w32.c')
-rw-r--r-- | src/gui_w32.c | 4077 |
1 files changed, 4077 insertions, 0 deletions
diff --git a/src/gui_w32.c b/src/gui_w32.c new file mode 100644 index 0000000000..df079538ac --- /dev/null +++ b/src/gui_w32.c @@ -0,0 +1,4077 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * GUI support by Robert Webb + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ +/* + * Windows GUI. + * + * GUI support for Microsoft Windows. Win32 initially; maybe Win16 later + * + * George V. Reilly <george@reilly.org> wrote the original Win32 GUI. + * Robert Webb reworked it to use the existing GUI stuff and added menu, + * scrollbars, etc. + * + * Note: Clipboard stuff, for cutting and pasting text to other windows, is in + * os_win32.c. (It can also be done from the terminal version). + * + * TODO: Some of the function signatures ought to be updated for Win64; + * e.g., replace LONG with LONG_PTR, etc. + */ + +/* + * These are new in Windows ME/XP, only defined in recent compilers. + */ +#ifndef HANDLE_WM_XBUTTONUP +# define HANDLE_WM_XBUTTONUP(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +#endif +#ifndef HANDLE_WM_XBUTTONDOWN +# define HANDLE_WM_XBUTTONDOWN(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +#endif +#ifndef HANDLE_WM_XBUTTONDBLCLK +# define HANDLE_WM_XBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +#endif + +/* + * Include the common stuff for MS-Windows GUI. + */ +#include "gui_w48.c" + +#ifdef FEAT_XPM_W32 +# include "xpm_w32.h" +#endif + +#ifdef PROTO +# define WINAPI +#endif + +#ifdef __MINGW32__ +/* + * Add a lot of missing defines. + * They are not always missing, we need the #ifndef's. + */ +# ifndef _cdecl +# define _cdecl +# endif +# ifndef IsMinimized +# define IsMinimized(hwnd) IsIconic(hwnd) +# endif +# ifndef IsMaximized +# define IsMaximized(hwnd) IsZoomed(hwnd) +# endif +# ifndef SelectFont +# define SelectFont(hdc, hfont) ((HFONT)SelectObject((hdc), (HGDIOBJ)(HFONT)(hfont))) +# endif +# ifndef GetStockBrush +# define GetStockBrush(i) ((HBRUSH)GetStockObject(i)) +# endif +# ifndef DeleteBrush +# define DeleteBrush(hbr) DeleteObject((HGDIOBJ)(HBRUSH)(hbr)) +# endif + +# ifndef HANDLE_WM_RBUTTONDBLCLK +# define HANDLE_WM_RBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_MBUTTONUP +# define HANDLE_WM_MBUTTONUP(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_MBUTTONDBLCLK +# define HANDLE_WM_MBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_LBUTTONDBLCLK +# define HANDLE_WM_LBUTTONDBLCLK(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_RBUTTONDOWN +# define HANDLE_WM_RBUTTONDOWN(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_MOUSEMOVE +# define HANDLE_WM_MOUSEMOVE(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_RBUTTONUP +# define HANDLE_WM_RBUTTONUP(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_MBUTTONDOWN +# define HANDLE_WM_MBUTTONDOWN(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_LBUTTONUP +# define HANDLE_WM_LBUTTONUP(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_LBUTTONDOWN +# define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_SYSCHAR +# define HANDLE_WM_SYSCHAR(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) +# endif +# ifndef HANDLE_WM_ACTIVATEAPP +# define HANDLE_WM_ACTIVATEAPP(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (BOOL)(wParam), (DWORD)(lParam)), 0L) +# endif +# ifndef HANDLE_WM_WINDOWPOSCHANGING +# define HANDLE_WM_WINDOWPOSCHANGING(hwnd, wParam, lParam, fn) \ + (LRESULT)(DWORD)(BOOL)(fn)((hwnd), (LPWINDOWPOS)(lParam)) +# endif +# ifndef HANDLE_WM_VSCROLL +# define HANDLE_WM_VSCROLL(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L) +# endif +# ifndef HANDLE_WM_SETFOCUS +# define HANDLE_WM_SETFOCUS(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (HWND)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_KILLFOCUS +# define HANDLE_WM_KILLFOCUS(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (HWND)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_HSCROLL +# define HANDLE_WM_HSCROLL(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (HWND)(lParam), (UINT)(LOWORD(wParam)), (int)(short)HIWORD(wParam)), 0L) +# endif +# ifndef HANDLE_WM_DROPFILES +# define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (HDROP)(wParam)), 0L) +# endif +# ifndef HANDLE_WM_CHAR +# define HANDLE_WM_CHAR(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) +# endif +# ifndef HANDLE_WM_SYSDEADCHAR +# define HANDLE_WM_SYSDEADCHAR(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) +# endif +# ifndef HANDLE_WM_DEADCHAR +# define HANDLE_WM_DEADCHAR(hwnd, wParam, lParam, fn) \ + ((fn)((hwnd), (TCHAR)(wParam), (int)(short)LOWORD(lParam)), 0L) +# endif +#endif /* __MINGW32__ */ + + +/* Some parameters for tearoff menus. All in pixels. */ +#define TEAROFF_PADDING_X 2 +#define TEAROFF_BUTTON_PAD_X 8 +#define TEAROFF_MIN_WIDTH 200 +#define TEAROFF_SUBMENU_LABEL ">>" +#define TEAROFF_COLUMN_PADDING 3 // # spaces to pad column with. + + +/* For the Intellimouse: */ +#ifndef WM_MOUSEWHEEL +#define WM_MOUSEWHEEL 0x20a +#endif + + +#ifdef FEAT_BEVAL +# define ID_BEVAL_TOOLTIP 200 +# define BEVAL_TEXT_LEN MAXPATHL + +static void make_tooltip __ARGS((BalloonEval *beval, char *text, POINT pt)); +static void delete_tooltip __ARGS((BalloonEval *beval)); +static VOID CALLBACK BevalTimerProc __ARGS((HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime)); + +static BalloonEval *cur_beval = NULL; +static UINT BevalTimerId = 0; +static DWORD LastActivity = 0; +#endif + +/* Local variables: */ + +#ifdef FEAT_MENU +static UINT s_menu_id = 100; + +/* + * Use the system font for dialogs and tear-off menus. Remove this line to + * use DLG_FONT_NAME. + */ +# define USE_SYSMENU_FONT +#endif + +#define VIM_NAME "vim" +#define VIM_CLASS "Vim" +#define VIM_CLASSW L"Vim" + +/* Initial size for the dialog template. For gui_mch_dialog() it's fixed, + * thus there should be room for every dialog. For tearoffs it's made bigger + * when needed. */ +#define DLG_ALLOC_SIZE 16 * 1024 + +/* + * stuff for dialogs, menus, tearoffs etc. + */ +static LRESULT APIENTRY dialog_callback(HWND, UINT, WPARAM, LPARAM); +static LRESULT APIENTRY tearoff_callback(HWND, UINT, WPARAM, LPARAM); +static PWORD +add_dialog_element( + PWORD p, + DWORD lStyle, + WORD x, + WORD y, + WORD w, + WORD h, + WORD Id, + WORD clss, + const char *caption); +static LPWORD lpwAlign(LPWORD); +static int nCopyAnsiToWideChar(LPWORD, LPSTR); +static void gui_mch_tearoff(char_u *title, vimmenu_T *menu, int initX, int initY); +static void get_dialog_font_metrics(void); + +static int dialog_default_button = -1; + +/* Intellimouse support */ +static int mouse_scroll_lines = 0; +static UINT msh_msgmousewheel = 0; + +static int s_usenewlook; /* emulate W95/NT4 non-bold dialogs */ +#ifdef FEAT_TOOLBAR +static void initialise_toolbar(void); +static int get_toolbar_bitmap(vimmenu_T *menu); +#endif + +#ifdef FEAT_MBYTE_IME +static LRESULT _OnImeComposition(HWND hwnd, WPARAM dbcs, LPARAM param); +static char_u *GetResultStr(HWND hwnd, int GCS, int *lenp); +#endif +#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME) +# ifdef NOIME +typedef struct tagCOMPOSITIONFORM { + DWORD dwStyle; + POINT ptCurrentPos; + RECT rcArea; +} COMPOSITIONFORM, *PCOMPOSITIONFORM, NEAR *NPCOMPOSITIONFORM, FAR *LPCOMPOSITIONFORM; +typedef HANDLE HIMC; +# endif + +HINSTANCE hLibImm = NULL; +LONG (WINAPI *pImmGetCompositionStringA)(HIMC, DWORD, LPVOID, DWORD); +LONG (WINAPI *pImmGetCompositionStringW)(HIMC, DWORD, LPVOID, DWORD); +HIMC (WINAPI *pImmGetContext)(HWND); +HIMC (WINAPI *pImmAssociateContext)(HWND, HIMC); +BOOL (WINAPI *pImmReleaseContext)(HWND, HIMC); +BOOL (WINAPI *pImmGetOpenStatus)(HIMC); +BOOL (WINAPI *pImmSetOpenStatus)(HIMC, BOOL); +BOOL (WINAPI *pImmGetCompositionFont)(HIMC, LPLOGFONTA); +BOOL (WINAPI *pImmSetCompositionFont)(HIMC, LPLOGFONTA); +BOOL (WINAPI *pImmSetCompositionWindow)(HIMC, LPCOMPOSITIONFORM); +BOOL (WINAPI *pImmGetConversionStatus)(HIMC, LPDWORD, LPDWORD); +static void dyn_imm_load(void); +#else +# define pImmGetCompositionStringA ImmGetCompositionStringA +# define pImmGetCompositionStringW ImmGetCompositionStringW +# define pImmGetContext ImmGetContext +# define pImmAssociateContext ImmAssociateContext +# define pImmReleaseContext ImmReleaseContext +# define pImmGetOpenStatus ImmGetOpenStatus +# define pImmSetOpenStatus ImmSetOpenStatus +# define pImmGetCompositionFont ImmGetCompositionFontA +# define pImmSetCompositionFont ImmSetCompositionFontA +# define pImmSetCompositionWindow ImmSetCompositionWindow +# define pImmGetConversionStatus ImmGetConversionStatus +#endif + +#ifndef ETO_IGNORELANGUAGE +# define ETO_IGNORELANGUAGE 0x1000 +#endif + +/* multi monitor support */ +typedef struct _MONITORINFOstruct +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} _MONITORINFO; + +typedef HANDLE _HMONITOR; +typedef _HMONITOR (WINAPI *TMonitorFromWindow)(HWND, DWORD); +typedef BOOL (WINAPI *TGetMonitorInfo)(_HMONITOR, _MONITORINFO *); + +static TMonitorFromWindow pMonitorFromWindow = NULL; +static TGetMonitorInfo pGetMonitorInfo = NULL; +static HANDLE user32_lib = NULL; +#ifdef FEAT_NETBEANS_INTG +int WSInitialized = FALSE; /* WinSock is initialized */ +#endif +/* + * Return TRUE when running under Windows NT 3.x or Win32s, both of which have + * less fancy GUI APIs. + */ + static int +is_winnt_3(void) +{ + return ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT + && os_version.dwMajorVersion == 3) + || (os_version.dwPlatformId == VER_PLATFORM_WIN32s)); +} + +/* + * Return TRUE when running under Win32s. + */ + int +gui_is_win32s(void) +{ + return (os_version.dwPlatformId == VER_PLATFORM_WIN32s); +} + +#ifdef FEAT_MENU +/* + * Figure out how high the menu bar is at the moment. + */ + static int +gui_mswin_get_menu_height( + int fix_window) /* If TRUE, resize window if menu height changed */ +{ + static int old_menu_height = -1; + + RECT rc1, rc2; + int num; + int menu_height; + + if (gui.menu_is_active) + num = GetMenuItemCount(s_menuBar); + else + num = 0; + + if (num == 0) + menu_height = 0; + else + { + if (is_winnt_3()) /* for NT 3.xx */ + { + if (gui.starting) + menu_height = GetSystemMetrics(SM_CYMENU); + else + { + RECT r1, r2; + int frameht = GetSystemMetrics(SM_CYFRAME); + int capht = GetSystemMetrics(SM_CYCAPTION); + + /* get window rect of s_hwnd + * get client rect of s_hwnd + * get cap height + * subtract from window rect, the sum of client height, + * (if not maximized)frame thickness, and caption height. + */ + GetWindowRect(s_hwnd, &r1); + GetClientRect(s_hwnd, &r2); + menu_height = r1.bottom - r1.top - (r2.bottom - r2.top + + 2 * frameht * (!IsZoomed(s_hwnd)) + capht); + } + } + else /* win95 and variants (NT 4.0, I guess) */ + { + /* + * In case 'lines' is set in _vimrc/_gvimrc window width doesn't + * seem to have been set yet, so menu wraps in default window + * width which is very narrow. Instead just return height of a + * single menu item. Will still be wrong when the menu really + * should wrap over more than one line. + */ + GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1); + if (gui.starting) + menu_height = rc1.bottom - rc1.top + 1; + else + { + GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2); + menu_height = rc2.bottom - rc1.top + 1; + } + } + } + + if (fix_window && menu_height != old_menu_height) + { + old_menu_height = menu_height; + gui_set_shellsize(FALSE, FALSE); + } + + return menu_height; +} +#endif /*FEAT_MENU*/ + + +/* + * Setup for the Intellimouse + */ + static void +init_mouse_wheel(void) +{ + +#ifndef SPI_GETWHEELSCROLLLINES +# define SPI_GETWHEELSCROLLLINES 104 +#endif + +#define VMOUSEZ_CLASSNAME "MouseZ" /* hidden wheel window class */ +#define VMOUSEZ_TITLE "Magellan MSWHEEL" /* hidden wheel window title */ +#define VMSH_MOUSEWHEEL "MSWHEEL_ROLLMSG" +#define VMSH_SCROLL_LINES "MSH_SCROLL_LINES_MSG" + + HWND hdl_mswheel; + UINT msh_msgscrolllines; + + msh_msgmousewheel = 0; + mouse_scroll_lines = 3; /* reasonable default */ + + if ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT + && os_version.dwMajorVersion >= 4) + || (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + && ((os_version.dwMajorVersion == 4 + && os_version.dwMinorVersion >= 10) + || os_version.dwMajorVersion >= 5))) + { + /* if NT 4.0+ (or Win98) get scroll lines directly from system */ + SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, + &mouse_scroll_lines, 0); + } + else if (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + || (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT + && os_version.dwMajorVersion < 4)) + { /* + * If Win95 or NT 3.51, + * try to find the hidden point32 window. + */ + hdl_mswheel = FindWindow(VMOUSEZ_CLASSNAME, VMOUSEZ_TITLE); + if (hdl_mswheel) + { + msh_msgscrolllines = RegisterWindowMessage(VMSH_SCROLL_LINES); + if (msh_msgscrolllines) + { + mouse_scroll_lines = (int)SendMessage(hdl_mswheel, + msh_msgscrolllines, 0, 0); + msh_msgmousewheel = RegisterWindowMessage(VMSH_MOUSEWHEEL); + } + } + } +} + + +/* Intellimouse wheel handler */ + static void +_OnMouseWheel( + HWND hwnd, + short zDelta) +{ +/* Treat a mouse wheel event as if it were a scroll request */ + int i; + int size; + HWND hwndCtl; + + if (curwin->w_scrollbars[SBAR_RIGHT].id != 0) + { + hwndCtl = curwin->w_scrollbars[SBAR_RIGHT].id; + size = curwin->w_scrollbars[SBAR_RIGHT].size; + } + else if (curwin->w_scrollbars[SBAR_LEFT].id != 0) + { + hwndCtl = curwin->w_scrollbars[SBAR_LEFT].id; + size = curwin->w_scrollbars[SBAR_LEFT].size; + } + else + return; + + size = curwin->w_height; + if (mouse_scroll_lines == 0) + init_mouse_wheel(); + + if (mouse_scroll_lines > 0 + && mouse_scroll_lines < (size > 2 ? size - 2 : 1)) + { + for (i = mouse_scroll_lines; i > 0; --i) + _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_LINEUP : SB_LINEDOWN, 0); + } + else + _OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0); +} + +#if 0 /* disabled, a gap appears below and beside the window, and the window + can be moved (in a strange way) */ +/* + * Even though we have _DuringSizing() which makes the rubber band a valid + * size, we need this for when the user maximises the window. + * TODO: Doesn't seem to adjust the width though for some reason. + */ + static BOOL +_OnWindowPosChanging( + HWND hwnd, + LPWINDOWPOS lpwpos) +{ + RECT workarea_rect; + + if (!(lpwpos->flags & SWP_NOSIZE)) + { + if (IsMaximized(hwnd) + && (os_version.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS + || (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT + && os_version.dwMajorVersion >= 4))) + { + SystemParametersInfo(SPI_GETWORKAREA, 0, &workarea_rect, 0); + lpwpos->x = workarea_rect.left; + lpwpos->y = workarea_rect.top; + lpwpos->cx = workarea_rect.right - workarea_rect.left; + lpwpos->cy = workarea_rect.bottom - workarea_rect.top; + } + gui_mswin_get_valid_dimensions(lpwpos->cx, lpwpos->cy, + &lpwpos->cx, &lpwpos->cy); + } + return 0; +} +#endif + +#ifdef FEAT_NETBEANS_INTG + static void +_OnWindowPosChanged( + HWND hwnd, + const LPWINDOWPOS lpwpos) +{ + static int x = 0, y = 0, cx = 0, cy = 0; + + if (WSInitialized && (lpwpos->x != x || lpwpos->y != y + || lpwpos->cx != cx || lpwpos->cy != cy)) + { + x = lpwpos->x; + y = lpwpos->y; + cx = lpwpos->cx; + cy = lpwpos->cy; + netbeans_frame_moved(x, y); + } + /* Allow to send WM_SIZE and WM_MOVE */ + FORWARD_WM_WINDOWPOSCHANGED(hwnd, lpwpos, MyWindowProc); +} +#endif + + static int +_DuringSizing( + HWND hwnd, + UINT fwSide, + LPRECT lprc) +{ + int w, h; + int valid_w, valid_h; + int w_offset, h_offset; + + w = lprc->right - lprc->left; + h = lprc->bottom - lprc->top; + gui_mswin_get_valid_dimensions(w, h, &valid_w, &valid_h); + w_offset = w - valid_w; + h_offset = h - valid_h; + + if (fwSide == WMSZ_LEFT || fwSide == WMSZ_TOPLEFT + || fwSide == WMSZ_BOTTOMLEFT) + lprc->left += w_offset; + else if (fwSide == WMSZ_RIGHT || fwSide == WMSZ_TOPRIGHT + || fwSide == WMSZ_BOTTOMRIGHT) + lprc->right -= w_offset; + + if (fwSide == WMSZ_TOP || fwSide == WMSZ_TOPLEFT + || fwSide == WMSZ_TOPRIGHT) + lprc->top += h_offset; + else if (fwSide == WMSZ_BOTTOM || fwSide == WMSZ_BOTTOMLEFT + || fwSide == WMSZ_BOTTOMRIGHT) + lprc->bottom -= h_offset; + return TRUE; +} + + + + static LRESULT CALLBACK +_WndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + /* + TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", + hwnd, uMsg, wParam, lParam); + */ + + HandleMouseHide(uMsg, lParam); + + s_uMsg = uMsg; + s_wParam = wParam; + s_lParam = lParam; + + switch (uMsg) + { + HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar); + HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar); + /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */ + HANDLE_MSG(hwnd, WM_CLOSE, _OnClose); + /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */ + HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy); + HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles); + HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll); + HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus); +#ifdef FEAT_MENU + HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu); +#endif + /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */ + /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */ + HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus); + HANDLE_MSG(hwnd, WM_SIZE, _OnSize); + /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */ + /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */ + HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll); + // HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging); + HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp); +#ifdef FEAT_NETBEANS_INTG + HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGED, _OnWindowPosChanged); +#endif + + case WM_QUERYENDSESSION: /* System wants to go down. */ + gui_shell_closed(); /* Will exit when no changed buffers. */ + return FALSE; /* Do NOT allow system to go down. */ + + case WM_ENDSESSION: + if (wParam) /* system only really goes down when wParam is TRUE */ + _OnEndSession(); + break; + + case WM_CHAR: + /* Don't use HANDLE_MSG() for WM_CHAR, it truncates wParam to a single + * byte while we want the UTF-16 character value. */ + _OnChar(hwnd, wParam, (int)(short)LOWORD(lParam)); + return 0L; + + case WM_SYSCHAR: + /* + * if 'winaltkeys' is "no", or it's "menu" and it's not a menu + * shortcut key, handle like a typed ALT key, otherwise call Windows + * ALT key handling. + */ +#ifdef FEAT_MENU + if ( !gui.menu_is_active + || p_wak[0] == 'n' + || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam)) + ) +#endif + { + _OnSysChar(hwnd, wParam, (int)(short)LOWORD(lParam)); + return 0L; + } +#ifdef FEAT_MENU + else + return MyWindowProc(hwnd, uMsg, wParam, lParam); +#endif + + case WM_SYSKEYUP: +#ifdef FEAT_MENU + /* This used to be done only when menu is active: ALT key is used for + * that. But that caused problems when menu is disabled and using + * Alt-Tab-Esc: get into a strange state where no mouse-moved events + * are received, mouse pointer remains hidden. */ + return MyWindowProc(hwnd, uMsg, wParam, lParam); +#else + return 0; +#endif + + case WM_SIZING: /* HANDLE_MSG doesn't seem to handle this one */ + return _DuringSizing(hwnd, (UINT)wParam, (LPRECT)lParam); + + case WM_MOUSEWHEEL: + _OnMouseWheel(hwnd, HIWORD(wParam)); + break; + +#ifdef FEAT_TOOLBAR + case WM_NOTIFY: + switch (((LPNMHDR) lParam)->code) + { + case TTN_NEEDTEXT: + { + LPTOOLTIPTEXT lpttt; + UINT idButton; + int idx; + vimmenu_T *pMenu; + + lpttt = (LPTOOLTIPTEXT)lParam; + idButton = (UINT) lpttt->hdr.idFrom; + pMenu = gui_mswin_find_menu(root_menu, idButton); + if (pMenu) + { + idx = MENU_INDEX_TIP; + if (pMenu->strings[idx]) + { + lpttt->hinst = NULL; /* string, not resource */ + lpttt->lpszText = pMenu->strings[idx]; + } + } + } + break; + default: + break; + } + break; +#endif +#if defined(MENUHINTS) && defined(FEAT_MENU) + case WM_MENUSELECT: + if (((UINT) HIWORD(wParam) + & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP))) + == MF_HILITE + && (State & CMDLINE) == 0) + { + UINT idButton; + vimmenu_T *pMenu; + static int did_menu_tip = FALSE; + + if (did_menu_tip) + { + msg_clr_cmdline(); + setcursor(); + out_flush(); + did_menu_tip = FALSE; + } + + idButton = (UINT)LOWORD(wParam); + pMenu = gui_mswin_find_menu(root_menu, idButton); + if (pMenu != NULL && pMenu->strings[MENU_INDEX_TIP] != 0 + && GetMenuState(s_menuBar, pMenu->id, MF_BYCOMMAND) != -1) + { + msg(pMenu->strings[MENU_INDEX_TIP]); + setcursor(); + out_flush(); + did_menu_tip = TRUE; + } + } + break; +#endif + case WM_NCHITTEST: + { + LRESULT result; + int x, y; + int xPos = GET_X_LPARAM(lParam); + + result = MyWindowProc(hwnd, uMsg, wParam, lParam); + if (result == HTCLIENT) + { + gui_mch_get_winpos(&x, &y); + xPos -= x; + + if (xPos < 48) /* <VN> TODO should use system metric? */ + return HTBOTTOMLEFT; + else + return HTBOTTOMRIGHT; + } + else + return result; + } + /* break; notreached */ + +#ifdef FEAT_MBYTE_IME + case WM_IME_NOTIFY: + if (!_OnImeNotify(hwnd, (DWORD)wParam, (DWORD)lParam)) + return MyWindowProc(hwnd, uMsg, wParam, lParam); + break; + case WM_IME_COMPOSITION: + if (!_OnImeComposition(hwnd, wParam, lParam)) + return MyWindowProc(hwnd, uMsg, wParam, lParam); + break; +#endif + + default: + if (uMsg == msh_msgmousewheel && msh_msgmousewheel != 0) + { /* handle MSH_MOUSEWHEEL messages for Intellimouse */ + _OnMouseWheel(hwnd, HIWORD(wParam)); + break; + } +#ifdef MSWIN_FIND_REPLACE + else + if (uMsg == s_findrep_msg && s_findrep_msg != 0) + { + _OnFindRepl(); + } +#endif + return MyWindowProc(hwnd, uMsg, wParam, lParam); + } + + return 1; +} + +/* + * End of call-back routines + */ + +/* parent window, if specified with -P */ +HWND vim_parent_hwnd = NULL; + + static BOOL CALLBACK +FindWindowTitle(HWND hwnd, LPARAM lParam) +{ + char buf[2048]; + char *title = (char *)lParam; + + if (GetWindowText(hwnd, buf, sizeof(buf))) + { + if (strstr(buf, title) != NULL) + { + /* Found it. Store the window ref. and quit searching. */ + vim_parent_hwnd = FindWindowEx(hwnd, NULL, "MDIClient", NULL); + return FALSE; + } + } + return TRUE; /* continue searching */ +} + +/* + * Invoked for '-P "title"' argument: search for parent application to open + * our window in. + */ + void +gui_mch_set_parent(char *title) +{ + EnumWindows(FindWindowTitle, (LPARAM)title); + if (vim_parent_hwnd == NULL) + { + EMSG2(_("E671: Cannot find window title \"%s\""), title); + mch_exit(2); + } +} + + static void +ole_error(char *arg) +{ + EMSG2(_("E243: Argument not supported: \"-%s\"; Use the OLE version."), + arg); +} + +/* + * Parse the GUI related command-line arguments. Any arguments used are + * deleted from argv, and *argc is decremented accordingly. This is called + * when vim is started, whether or not the GUI has been started. + */ + void +gui_mch_prepare(int *argc, char **argv) +{ + int silent = FALSE; + int idx; + + /* Check for special OLE command line parameters */ + if ((*argc == 2 || *argc == 3) && (argv[1][0] == '-' || argv[1][0] == '/')) + { + /* Check for a "-silent" argument first. */ + if (*argc == 3 && STRICMP(argv[1] + 1, "silent") == 0 + && (argv[2][0] == '-' || argv[2][0] == '/')) + { + silent = TRUE; + idx = 2; + } + else + idx = 1; + + /* Register Vim as an OLE Automation server */ + if (STRICMP(argv[idx] + 1, "register") == 0) + { +#ifdef FEAT_OLE + RegisterMe(silent); + mch_exit(0); +#else + if (!silent) + ole_error("register"); + mch_exit(2); +#endif + } + + /* Unregister Vim as an OLE Automation server */ + if (STRICMP(argv[idx] + 1, "unregister") == 0) + { +#ifdef FEAT_OLE + UnregisterMe(!silent); + mch_exit(0); +#else + if (!silent) + ole_error("unregister"); + mch_exit(2); +#endif + } + + /* Ignore an -embedding argument. It is only relevant if the + * application wants to treat the case when it is started manually + * differently from the case where it is started via automation (and + * we don't). + */ + if (STRICMP(argv[idx] + 1, "embedding") == 0) + { +#ifdef FEAT_OLE + *argc = 1; +#else + ole_error("embedding"); + mch_exit(2); +#endif + } + } + +#ifdef FEAT_OLE + { + int bDoRestart = FALSE; + + InitOLE(&bDoRestart); + /* automatically exit after registering */ + if (bDoRestart) + mch_exit(0); + } +#endif + +#ifdef FEAT_NETBEANS_INTG + { + /* stolen from gui_x11.x */ + int arg; + + for (arg = 1; arg < *argc; arg++) + if (strncmp("-nb", argv[arg], 3) == 0) + { + usingNetbeans++; + netbeansArg = argv[arg]; + mch_memmove(&argv[arg], &argv[arg + 1], + (--*argc - arg) * sizeof(char *)); + argv[*argc] = NULL; + break; /* enough? */ + } + + if (usingNetbeans) + { + WSADATA wsaData; + int wsaerr; + + /* Init WinSock */ + wsaerr = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (wsaerr == 0) + WSInitialized = TRUE; + } + } +#endif + + /* get the OS version info */ + os_version.dwOSVersionInfoSize = sizeof(os_version); + GetVersionEx(&os_version); /* this call works on Win32s, Win95 and WinNT */ + + /* try and load the user32.dll library and get the entry points for + * multi-monitor-support. */ + if ((user32_lib = LoadLibrary("User32.dll")) != NULL) + { + pMonitorFromWindow = (TMonitorFromWindow)GetProcAddress(user32_lib, + "MonitorFromWindow"); + + /* there are ...A and ...W version of GetMonitorInfo - looking at + * winuser.h, they have exactly the same declaration. */ + pGetMonitorInfo = (TGetMonitorInfo)GetProcAddress(user32_lib, + "GetMonitorInfoA"); + } +} + +/* + * Initialise the GUI. Create all the windows, set up all the call-backs + * etc. + */ + int +gui_mch_init(void) +{ + const char szVimWndClass[] = VIM_CLASS; + const char szTextAreaClass[] = "VimTextArea"; + WNDCLASS wndclass; +#ifdef FEAT_MBYTE + const WCHAR szVimWndClassW[] = VIM_CLASSW; + WNDCLASSW wndclassw; +#endif +#ifdef GLOBAL_IME + ATOM atom; +#endif + + /* Display any pending error messages */ + display_errors(); + + /* Return here if the window was already opened (happens when + * gui_mch_dialog() is called early). */ + if (s_hwnd != NULL) + return OK; + + /* + * Load the tearoff bitmap + */ +#ifdef FEAT_TEAROFF + s_htearbitmap = LoadBitmap(s_hinst, "IDB_TEAROFF"); +#endif + + gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL); + gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL); +#ifdef FEAT_MENU + gui.menu_height = 0; /* Windows takes care of this */ +#endif + gui.border_width = 0; + + s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); + +#ifdef FEAT_MBYTE + /* First try using the wide version, so that we can use any title. + * Otherwise only characters in the active codepage will work. */ + if (GetClassInfoW(s_hinst, szVimWndClassW, &wndclassw) == 0) + { + wndclassw.style = 0; + wndclassw.lpfnWndProc = _WndProc; + wndclassw.cbClsExtra = 0; + wndclassw.cbWndExtra = 0; + wndclassw.hInstance = s_hinst; + wndclassw.hIcon = LoadIcon(wndclassw.hInstance, "IDR_VIM"); + wndclassw.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclassw.hbrBackground = s_brush; + wndclassw.lpszMenuName = NULL; + wndclassw.lpszClassName = szVimWndClassW; + + if (( +#ifdef GLOBAL_IME + atom = +#endif + RegisterClassW(&wndclassw)) == 0) + { + if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) + return FAIL; + + /* Must be Windows 98, fall back to non-wide function. */ + } + else + wide_WindowProc = TRUE; + } + + if (!wide_WindowProc) +#endif + + if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0) + { + wndclass.style = 0; + wndclass.lpfnWndProc = _WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = s_hinst; + wndclass.hIcon = LoadIcon(wndclass.hInstance, "IDR_VIM"); + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = s_brush; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = szVimWndClass; + + if (( +#ifdef GLOBAL_IME + atom = +#endif + RegisterClass(&wndclass)) == 0) + return FAIL; + } + + if (vim_parent_hwnd != NULL) + { +#ifdef HAVE_TRY_EXCEPT + __try + { +#endif + /* Open inside the specified parent window. + * TODO: last argument should point to a CLIENTCREATESTRUCT + * structure. */ + s_hwnd = CreateWindowEx( + WS_EX_MDICHILD, + szVimWndClass, "Vim MSWindows GUI", + WS_OVERLAPPEDWINDOW | WS_CHILD | WS_CLIPSIBLINGS | 0xC000, + gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x, + gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y, + 100, /* Any value will do */ + 100, /* Any value will do */ + vim_parent_hwnd, NULL, + s_hinst, NULL); +#ifdef HAVE_TRY_EXCEPT + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + /* NOP */ + } +#endif + if (s_hwnd == NULL) + { + EMSG(_("E672: Unable to open window inside MDI application")); + mch_exit(2); + } + } + else + /* Open toplevel window. */ + s_hwnd = CreateWindow( + szVimWndClass, "Vim MSWindows GUI", + WS_OVERLAPPEDWINDOW, + gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x, + gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y, + 100, /* Any value will do */ + 100, /* Any value will do */ + NULL, NULL, + s_hinst, NULL); + + if (s_hwnd == NULL) + return FAIL; + +#ifdef GLOBAL_IME + global_ime_init(atom, s_hwnd); +#endif +#if defined(FEAT_MBYTE_IME) && defined(DYNAMIC_IME) + dyn_imm_load(); +#endif + + /* Create the text area window */ + if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0) + { + wndclass.style = CS_OWNDC; + wndclass.lpfnWndProc = _TextAreaWndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = s_hinst; + wndclass.hIcon = NULL; + wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); + wndclass.hbrBackground = NULL; + wndclass.lpszMenuName = NULL; + wndclass.lpszClassName = szTextAreaClass; + + if (RegisterClass(&wndclass) == 0) + return FAIL; + } + s_textArea = CreateWindowEx( + WS_EX_CLIENTEDGE, + szTextAreaClass, "Vim text area", + WS_CHILD | WS_VISIBLE, 0, 0, + 100, /* Any value will do for now */ + 100, /* Any value will do for now */ + s_hwnd, NULL, + s_hinst, NULL); + + if (s_textArea == NULL) + return FAIL; + +#ifdef FEAT_MENU + s_menuBar = CreateMenu(); +#endif + s_hdc = GetDC(s_textArea); + +#ifdef MSWIN16_FASTTEXT + SetBkMode(s_hdc, OPAQUE); +#endif + +#ifdef FEAT_WINDOWS + DragAcceptFiles(s_hwnd, TRUE); +#endif + + /* Do we need to bother with this? */ + /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */ + + /* Get background/foreground colors from the system */ + gui_mch_def_colors(); + + /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc + * file) */ + set_normal_colors(); + + /* + * Check that none of the colors are the same as the background color. + * Then store the current values as the defaults. + */ + gui_check_colors(); + gui.def_norm_pixel = gui.norm_pixel; + gui.def_back_pixel = gui.back_pixel; + + /* Get the colors for the highlight groups (gui_check_colors() might have + * changed them) */ |