diff options
Diffstat (limited to 'src/gui_w48.c')
-rw-r--r-- | src/gui_w48.c | 3402 |
1 files changed, 3402 insertions, 0 deletions
diff --git a/src/gui_w48.c b/src/gui_w48.c new file mode 100644 index 0000000000..761c1af167 --- /dev/null +++ b/src/gui_w48.c @@ -0,0 +1,3402 @@ +/* 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. + */ +/* + * gui_w48.c: This file is included in gui_w16.c and gui_w32.c. + * + * GUI support for Microsoft Windows (Win16 + Win32 = Win48 :-) + * + * The combined efforts of: + * George V. Reilly <george@reilly.org> + * Robert Webb + * Vince Negri + * ...and contributions from many others + * + */ + +#include "vim.h" +#include "version.h" /* used by dialog box routine for default title */ +#ifdef DEBUG +# include <tchar.h> +#endif +#ifndef __MINGW32__ +# include <shellapi.h> +#endif +#if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL) +# include <commctrl.h> +#endif +#ifdef WIN16 +# include <commdlg.h> +# include <shellapi.h> +# ifdef WIN16_3DLOOK +# include <ctl3d.h> +# endif +#endif +#include <windowsx.h> + +#ifdef GLOBAL_IME +# include "glbl_ime.h" +#endif + +#ifdef FEAT_MENU +# define MENUHINTS /* show menu hints in command line */ +#endif + +/* Some parameters for dialog boxes. All in pixels. */ +#define DLG_PADDING_X 10 +#define DLG_PADDING_Y 10 +#define DLG_OLD_STYLE_PADDING_X 5 +#define DLG_OLD_STYLE_PADDING_Y 5 +#define DLG_VERT_PADDING_X 4 /* For vertical buttons */ +#define DLG_VERT_PADDING_Y 4 +#define DLG_ICON_WIDTH 34 +#define DLG_ICON_HEIGHT 34 +#define DLG_MIN_WIDTH 150 +#define DLG_FONT_NAME "MS Sans Serif" +#define DLG_FONT_POINT_SIZE 8 +#define DLG_MIN_MAX_WIDTH 400 + +#define DLG_NONBUTTON_CONTROL 5000 /* First ID of non-button controls */ + +#ifndef WM_XBUTTONDOWN /* For Win2K / winME ONLY */ +# define WM_XBUTTONDOWN 0x020B +# define WM_XBUTTONUP 0x020C +# define WM_XBUTTONDBLCLK 0x020D +# define MK_XBUTTON1 0x0020 +# define MK_XBUTTON2 0x0040 +#endif + +#ifdef PROTO +/* + * Define a few things for generating prototypes. This is just to avoid + * syntax errors, the defines do not need to be correct. + */ +# define APIENTRY +# define CALLBACK +# define CONST +# define FAR +# define NEAR +# define _cdecl +typedef int BOOL; +typedef int BYTE; +typedef int DWORD; +typedef int WCHAR; +typedef int ENUMLOGFONT; +typedef int FINDREPLACE; +typedef int HANDLE; +typedef int HBITMAP; +typedef int HBRUSH; +typedef int HDROP; +typedef int INT; +typedef int LOGFONT[]; +typedef int LPARAM; +typedef int LPCREATESTRUCT; +typedef int LPCSTR; +typedef int LPCTSTR; +typedef int LPRECT; +typedef int LPSTR; +typedef int LPWINDOWPOS; +typedef int LPWORD; +typedef int LRESULT; +# undef MSG +typedef int MSG; +typedef int NEWTEXTMETRIC; +typedef int OSVERSIONINFO; +typedef int PWORD; +typedef int RECT; +typedef int UINT; +typedef int WORD; +typedef int WPARAM; +typedef int POINT; +typedef void *HINSTANCE; +typedef void *HMENU; +typedef void *HWND; +typedef void *HDC; +typedef void VOID; +typedef int LPNMHDR; +typedef int LONG; +#endif + +#ifndef GET_X_LPARAM +# define GET_X_LPARAM(lp) ((int)(short)LOWORD(lp)) +#endif + +static void _OnPaint( HWND hwnd); +static void clear_rect(RECT *rcp); +static int gui_mswin_get_menu_height(int fix_window); + +static WORD s_dlgfntheight; /* height of the dialog font */ +static WORD s_dlgfntwidth; /* width of the dialog font */ + +#ifdef FEAT_MENU +static HMENU s_menuBar = NULL; +#endif +#ifdef FEAT_TEAROFF +static void rebuild_tearoff(vimmenu_T *menu); +static HBITMAP s_htearbitmap; /* bitmap used to indicate tearoff */ +#endif + +/* Flag that is set while processing a message that must not be interupted by + * processing another message. */ +static int s_busy_processing = FALSE; + +static int destroying = FALSE; /* call DestroyWindow() ourselves */ + +#ifdef MSWIN_FIND_REPLACE +static UINT s_findrep_msg = 0; /* set in gui_w[16/32].c */ +static FINDREPLACE s_findrep_struct; +static HWND s_findrep_hwnd = NULL; +static int s_findrep_is_find; /* TRUE for find dialog, FALSE + for find/replace dialog */ +#endif + +static HINSTANCE s_hinst = NULL; +#if !defined(FEAT_SNIFF) && !defined(FEAT_GUI) +static +#endif +HWND s_hwnd = NULL; +static HDC s_hdc = NULL; +static HBRUSH s_brush = NULL; + +#ifdef FEAT_TOOLBAR +static HWND s_toolbarhwnd = NULL; +#endif + +static WPARAM s_wParam = 0; +static LPARAM s_lParam = 0; + +static HWND s_textArea = NULL; +static UINT s_uMsg = 0; + +static char_u *s_textfield; /* Used by dialogs to pass back strings */ + +static int s_need_activate = FALSE; + +/* This variable is set when waiting for an event, which is the only moment + * scrollbar dragging can be done directly. It's not allowed while commands + * are executed, because it may move the cursor and that may cause unexpected + * problems (e.g., while ":s" is working). + */ +static int allow_scrollbar = FALSE; + +#ifdef GLOBAL_IME +# define MyTranslateMessage(x) global_ime_TranslateMessage(x) +#else +# define MyTranslateMessage(x) TranslateMessage(x) +#endif + +#if (defined(WIN3264) && defined(FEAT_MBYTE)) || defined(GLOBAL_IME) + /* use of WindowProc depends on wide_WindowProc */ +# define MyWindowProc vim_WindowProc +#else + /* use ordinary WindowProc */ +# define MyWindowProc DefWindowProc +#endif + +extern int current_font_height; /* this is in os_mswin.c */ + +static struct +{ + UINT key_sym; + char_u vim_code0; + char_u vim_code1; +} special_keys[] = +{ + {VK_UP, 'k', 'u'}, + {VK_DOWN, 'k', 'd'}, + {VK_LEFT, 'k', 'l'}, + {VK_RIGHT, 'k', 'r'}, + + {VK_F1, 'k', '1'}, + {VK_F2, 'k', '2'}, + {VK_F3, 'k', '3'}, + {VK_F4, 'k', '4'}, + {VK_F5, 'k', '5'}, + {VK_F6, 'k', '6'}, + {VK_F7, 'k', '7'}, + {VK_F8, 'k', '8'}, + {VK_F9, 'k', '9'}, + {VK_F10, 'k', ';'}, + + {VK_F11, 'F', '1'}, + {VK_F12, 'F', '2'}, + {VK_F13, 'F', '3'}, + {VK_F14, 'F', '4'}, + {VK_F15, 'F', '5'}, + {VK_F16, 'F', '6'}, + {VK_F17, 'F', '7'}, + {VK_F18, 'F', '8'}, + {VK_F19, 'F', '9'}, + {VK_F20, 'F', 'A'}, + + {VK_F21, 'F', 'B'}, +#ifdef FEAT_NETBEANS_INTG + {VK_PAUSE, 'F', 'B'}, /* Pause == F21 (see gui_gtk_x11.c) */ +#endif + {VK_F22, 'F', 'C'}, + {VK_F23, 'F', 'D'}, + {VK_F24, 'F', 'E'}, /* winuser.h defines up to F24 */ + + {VK_HELP, '%', '1'}, + {VK_BACK, 'k', 'b'}, + {VK_INSERT, 'k', 'I'}, + {VK_DELETE, 'k', 'D'}, + {VK_HOME, 'k', 'h'}, + {VK_END, '@', '7'}, + {VK_PRIOR, 'k', 'P'}, + {VK_NEXT, 'k', 'N'}, + {VK_PRINT, '%', '9'}, + {VK_ADD, 'K', '6'}, + {VK_SUBTRACT, 'K', '7'}, + {VK_DIVIDE, 'K', '8'}, + {VK_MULTIPLY, 'K', '9'}, + {VK_SEPARATOR, 'K', 'A'}, /* Keypad Enter */ + {VK_DECIMAL, 'K', 'B'}, + + {VK_NUMPAD0, 'K', 'C'}, + {VK_NUMPAD1, 'K', 'D'}, + {VK_NUMPAD2, 'K', 'E'}, + {VK_NUMPAD3, 'K', 'F'}, + {VK_NUMPAD4, 'K', 'G'}, + {VK_NUMPAD5, 'K', 'H'}, + {VK_NUMPAD6, 'K', 'I'}, + {VK_NUMPAD7, 'K', 'J'}, + {VK_NUMPAD8, 'K', 'K'}, + {VK_NUMPAD9, 'K', 'L'}, + + /* Keys that we want to be able to use any modifier with: */ + {VK_SPACE, ' ', NUL}, + {VK_TAB, TAB, NUL}, + {VK_ESCAPE, ESC, NUL}, + {NL, NL, NUL}, + {CAR, CAR, NUL}, + + /* End of list marker: */ + {0, 0, 0} +}; + +/* Local variables */ +static int s_button_pending = -1; +static int s_x_pending; +static int s_y_pending; +static UINT s_kFlags_pending; +static UINT s_wait_timer = 0; /* Timer for get char from user */ +static int s_timed_out = FALSE; +static int dead_key = 0; /* 0 - no dead key, 1 - dead key pressed */ + +#ifdef WIN3264 +static OSVERSIONINFO os_version; /* like it says. Init in gui_mch_init() */ +#endif + +#ifdef FEAT_BEVAL +/* balloon-eval WM_NOTIFY_HANDLER */ +static void Handle_WM_Notify __ARGS((HWND hwnd, LPNMHDR pnmh)); +static void TrackUserActivity __ARGS((UINT uMsg)); +#endif + +/* + * For control IME. + */ +#ifdef FEAT_MBYTE +# ifdef USE_IM_CONTROL +static LOGFONT norm_logfont; +# endif +#endif + +#ifdef FEAT_MBYTE_IME +static LRESULT _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData); +#endif + +#ifdef DEBUG +/* + * Print out the last Windows error message + */ + static void +print_windows_error(void) +{ + LPVOID lpMsgBuf; + + FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, GetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPTSTR) &lpMsgBuf, 0, NULL); + TRACE1("Error: %s\n", lpMsgBuf); + LocalFree(lpMsgBuf); +} +#endif /* DEBUG */ + +/* + * Cursor blink functions. + * + * This is a simple state machine: + * BLINK_NONE not blinking at all + * BLINK_OFF blinking, cursor is not shown + * BLINK_ON blinking, cursor is shown + */ + +#define BLINK_NONE 0 +#define BLINK_OFF 1 +#define BLINK_ON 2 + +static int blink_state = BLINK_NONE; +static long_u blink_waittime = 700; +static long_u blink_ontime = 400; +static long_u blink_offtime = 250; +static UINT blink_timer = 0; + + void +gui_mch_set_blinking(long wait, long on, long off) +{ + blink_waittime = wait; + blink_ontime = on; + blink_offtime = off; +} + +/* ARGSUSED */ + static VOID CALLBACK +_OnBlinkTimer( + HWND hwnd, + UINT uMsg, + UINT idEvent, + DWORD dwTime) +{ + MSG msg; + + /* + TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer); + */ + + KillTimer(NULL, idEvent); + + /* Eat spurious WM_TIMER messages */ + while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE)) + ; + + if (blink_state == BLINK_ON) + { + gui_undraw_cursor(); + blink_state = BLINK_OFF; + blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_offtime, + (TIMERPROC)_OnBlinkTimer); + } + else + { + gui_update_cursor(TRUE, FALSE); + blink_state = BLINK_ON; + blink_timer = (UINT) SetTimer(NULL, 0, (UINT)blink_ontime, + (TIMERPROC)_OnBlinkTimer); + } +} + + static void +gui_mswin_rm_blink_timer(void) +{ + MSG msg; + + if (blink_timer != 0) + { + KillTimer(NULL, blink_timer); + /* Eat spurious WM_TIMER messages */ + while (PeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE)) + ; + blink_timer = 0; + } +} + +/* + * Stop the cursor blinking. Show the cursor if it wasn't shown. + */ + void +gui_mch_stop_blink(void) +{ + gui_mswin_rm_blink_timer(); + if (blink_state == BLINK_OFF) + gui_update_cursor(TRUE, FALSE); + blink_state = BLINK_NONE; +} + +/* + * Start the cursor blinking. If it was already blinking, this restarts the + * waiting time and shows the cursor. + */ + void +gui_mch_start_blink(void) +{ + gui_mswin_rm_blink_timer(); + + /* Only switch blinking on if none of the times is zero */ + if (blink_waittime && blink_ontime && blink_offtime && gui.in_focus) + { + blink_timer = (UINT)SetTimer(NULL, 0, (UINT)blink_waittime, + (TIMERPROC)_OnBlinkTimer); + blink_state = BLINK_ON; + gui_update_cursor(TRUE, FALSE); + } +} + +/* + * Call-back routines. + */ + + static VOID CALLBACK +_OnTimer( + HWND hwnd, + UINT uMsg, + UINT idEvent, + DWORD dwTime) +{ + MSG msg; + + /* + TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer); + */ + KillTimer(NULL, idEvent); + s_timed_out = TRUE; + + /* Eat spurious WM_TIMER messages */ + while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE)) + ; + if (idEvent == s_wait_timer) + s_wait_timer = 0; +} + + static void +_OnDeadChar( + HWND hwnd, + UINT ch, + int cRepeat) +{ + dead_key = 1; +} + +/* + * Convert Unicode character "ch" to bytes in "string[slen]". + * Return the length. + */ + static int +char_to_string(int ch, char_u *string, int slen) +{ + int len; + int i; +#ifdef FEAT_MBYTE + WCHAR wstring[2]; + char_u *ws = NULL;; + + /* "ch" is a UTF-16 character. Convert it to a string of bytes. When + * "enc_codepage" is non-zero use the standard Win32 function, otherwise + * use our own conversion function (e.g., for UTF-8). */ + wstring[0] = ch; + if (enc_codepage > 0) + len = WideCharToMultiByte(enc_codepage, 0, wstring, 1, string, slen, + 0, NULL); + else + { + len = 1; + ws = ucs2_to_enc(wstring, &len); + if (ws == NULL) + len = 0; + else + { + if (len > slen) /* just in case */ + len = slen; + mch_memmove(string, ws, len); + vim_free(ws); + } + } + if (len == 0) +#endif + { + string[0] = ch; + len = 1; + } + + for (i = 0; i < len; ++i) + if (string[i] == CSI && len <= slen - 2) + { + /* Insert CSI as K_CSI. */ + mch_memmove(string + i + 3, string + i + 1, len - i - 1); + string[++i] = KS_EXTRA; + string[++i] = (int)KE_CSI; + len += 2; + } + + return len; +} + +/* + * Key hit, add it to the input buffer. + */ + static void +_OnChar( + HWND hwnd, + UINT ch, + int cRepeat) +{ + char_u string[40]; + int len = 0; + + len = char_to_string(ch, string, 40); + if (len == 1 && string[0] == Ctrl_C && ctrl_c_interrupts) + { + trash_input_buf(); + got_int = TRUE; + } + + add_to_input_buf(string, len); +} + +/* + * Alt-Key hit, add it to the input buffer. + */ + static void +_OnSysChar( + HWND hwnd, + UINT cch, + int cRepeat) +{ + char_u string[40]; /* Enough for multibyte character */ + int len; + int modifiers; + int ch = cch; /* special keys are negative */ + + /* TRACE("OnSysChar(%d, %c)\n", ch, ch); */ + + /* OK, we have a character key (given by ch) which was entered with the + * ALT key pressed. Eg, if the user presses Alt-A, then ch == 'A'. Note + * that the system distinguishes Alt-a and Alt-A (Alt-Shift-a unless + * CAPSLOCK is pressed) at this point. + */ + modifiers = MOD_MASK_ALT; + if (GetKeyState(VK_SHIFT) & 0x8000) + modifiers |= MOD_MASK_SHIFT; + if (GetKeyState(VK_CONTROL) & 0x8000) + modifiers |= MOD_MASK_CTRL; + + ch = simplify_key(ch, &modifiers); + /* remove the SHIFT modifier for keys where it's already included, e.g., + * '(' and '*' */ + if (ch < 0x100 && !isalpha(ch) && isprint(ch)) + modifiers &= ~MOD_MASK_SHIFT; + + /* Interpret the ALT key as making the key META, include SHIFT, etc. */ + ch = extract_modifiers(ch, &modifiers); + if (ch == CSI) + ch = K_CSI; + + len = 0; + if (modifiers) + { + string[len++] = CSI; + string[len++] = KS_MODIFIER; + string[len++] = modifiers; + } + + if (IS_SPECIAL((int)ch)) + { + string[len++] = CSI; + string[len++] = K_SECOND((int)ch); + string[len++] = K_THIRD((int)ch); + } + else + { + /* Although the documentation isn't clear about it, we assume "ch" is + * a Unicode character. */ + len += char_to_string(ch, string + len, 40 - len); + } + + add_to_input_buf(string, len); +} + + static void +_OnMouseEvent( + int button, + int x, + int y, + int repeated_click, + UINT keyFlags) +{ + int vim_modifiers = 0x0; + + if (keyFlags & MK_SHIFT) + vim_modifiers |= MOUSE_SHIFT; + if (keyFlags & MK_CONTROL) + vim_modifiers |= MOUSE_CTRL; + if (GetKeyState(VK_MENU) & 0x8000) + vim_modifiers |= MOUSE_ALT; + + gui_send_mouse_event(button, x, y, repeated_click, vim_modifiers); +} + + static void +_OnMouseButtonDown( + HWND hwnd, + BOOL fDoubleClick, + int x, + int y, + UINT keyFlags) +{ + static LONG s_prevTime = 0; + + LONG currentTime = GetMessageTime(); + int button = -1; + int repeated_click; + + /* Give main window the focus: this is so the cursor isn't hollow. */ + (void)SetFocus(s_hwnd); + + if (s_uMsg == WM_LBUTTONDOWN || s_uMsg == WM_LBUTTONDBLCLK) + button = MOUSE_LEFT; + else if (s_uMsg == WM_MBUTTONDOWN || s_uMsg == WM_MBUTTONDBLCLK) + button = MOUSE_MIDDLE; + else if (s_uMsg == WM_RBUTTONDOWN || s_uMsg == WM_RBUTTONDBLCLK) + button = MOUSE_RIGHT; +#ifndef WIN16 /*<VN>*/ + else if (s_uMsg == WM_XBUTTONDOWN || s_uMsg == WM_XBUTTONDBLCLK) + { +#ifndef GET_XBUTTON_WPARAM +# define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) +#endif + button = ((GET_XBUTTON_WPARAM(s_wParam) == 1) ? MOUSE_X1 : MOUSE_X2); + } + else if (s_uMsg == WM_CAPTURECHANGED) + { + /* on W95/NT4, somehow you get in here with an odd Msg + * if you press one button while holding down the other..*/ + if (s_button_pending == MOUSE_LEFT) + button = MOUSE_RIGHT; + else + button = MOUSE_LEFT; + } +#endif + if (button >= 0) + { + repeated_click = ((int)(currentTime - s_prevTime) < p_mouset); + + /* + * Holding down the left and right buttons simulates pushing the middle + * button. + */ + if (repeated_click && + ((button == MOUSE_LEFT && s_button_pending == MOUSE_RIGHT) || + (button == MOUSE_RIGHT && s_button_pending == MOUSE_LEFT))) + { + /* + * Hmm, gui.c will ignore more than one button down at a time, so + * pretend we let go of it first. + */ + gui_send_mouse_event(MOUSE_RELEASE, x, y, FALSE, 0x0); + button = MOUSE_MIDDLE; + repeated_click = FALSE; + s_button_pending = -1; + _OnMouseEvent(button, x, y, repeated_click, keyFlags); + } + else if ((repeated_click) + || (mouse_model_popup() && (button == MOUSE_RIGHT))) + { + if (s_button_pending > -1) + { + _OnMouseEvent(s_button_pending, x, y, FALSE, keyFlags); + s_button_pending = -1; + } + /* TRACE("Button down at x %d, y %d\n", x, y); */ + _OnMouseEvent(button, x, y, repeated_click, keyFlags); + } + else + { + /* + * If this is the first press (i.e. not a multiple click) don't + * action immediately, but store and wait for: + * i) button-up + * ii) mouse move + * iii) another button press + * before using it. + * This enables us to make left+right simulate middle button, + * without left or right being actioned first. The side-effect is + * that if you click and hold the mouse without dragging, the + * cursor doesn't move until you release the button. In practice + * this is hardly a problem. + */ + s_button_pending = button; + s_x_pending = x; + s_y_pending = y; + s_kFlags_pending = keyFlags; + } + + s_prevTime = currentTime; + } +} + + static void +_OnMouseMoveOrRelease( + HWND hwnd, + int x, + int y, + UINT keyFlags) +{ + int button; + + if (s_button_pending > -1) + { + /* Delayed action for mouse down event */ + _OnMouseEvent(s_button_pending, s_x_pending, + s_y_pending, FALSE, s_kFlags_pending); + s_button_pending = -1; + } + if (s_uMsg == WM_MOUSEMOVE) + { + /* + * It's only a MOUSE_DRAG if one or more mouse buttons are being held + * down. + */ + if (!(keyFlags & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON + | MK_XBUTTON1 | MK_XBUTTON2))) + { + gui_mouse_moved(x, y); + return; + } + + /* + * While button is down, keep grabbing mouse move events when + * the mouse goes outside the window + */ + SetCapture(s_textArea); + button = MOUSE_DRAG; + /* TRACE(" move at x %d, y %d\n", x, y); */ + } + else + { + ReleaseCapture(); + button = MOUSE_RELEASE; + /* TRACE(" up at x %d, y %d\n", x, y); */ + } + + _OnMouseEvent(button, x, y, FALSE, keyFlags); +} + +#ifdef FEAT_MENU +/* + * Find the vimmenu_T with the given id + */ + static vimmenu_T * +gui_mswin_find_menu( + vimmenu_T *pMenu, + int id) +{ + vimmenu_T *pChildMenu; + + while (pMenu) + { + if (pMenu->id == (UINT)id) + break; + if (pMenu->children != NULL) + { + pChildMenu = gui_mswin_find_menu(pMenu->children, id); + if (pChildMenu) + { + pMenu = pChildMenu; + break; + } + } + pMenu = pMenu->next; + } + return pMenu; +} + + static void +_OnMenu( + HWND hwnd, + int id, + HWND hwndCtl, + UINT codeNotify) +{ + vimmenu_T *pMenu; + + pMenu = gui_mswin_find_menu(root_menu, id); + if (pMenu) + gui_menu_cb(pMenu); +} +#endif + +#ifdef MSWIN_FIND_REPLACE +/* + * Handle a Find/Replace window message. + */ + static void +_OnFindRepl(void) +{ + int flags = 0; + int down; + + if (s_findrep_struct.Flags & FR_DIALOGTERM) + /* Give main window the focus back. */ + (void)SetFocus(s_hwnd); + + if (s_findrep_struct.Flags & FR_FINDNEXT) + { + flags = FRD_FINDNEXT; + + /* Give main window the focus back: this is so the cursor isn't + * hollow. */ + (void)SetFocus(s_hwnd); + } + else if (s_findrep_struct.Flags & FR_REPLACE) + { + flags = FRD_REPLACE; + + /* Give main window the focus back: this is so the cursor isn't + * hollow. */ + (void)SetFocus(s_hwnd); + } + else if (s_findrep_struct.Flags & FR_REPLACEALL) + { + flags = FRD_REPLACEALL; + } + + if (flags != 0) + { + /* Call the generic GUI function to do the actual work. */ + if (s_findrep_struct.Flags & FR_WHOLEWORD) + flags |= FRD_WHOLE_WORD; + if (s_findrep_struct.Flags & FR_MATCHCASE) + flags |= FRD_MATCH_CASE; + down = (s_findrep_struct.Flags & FR_DOWN) != 0; + gui_do_findrepl(flags, s_findrep_struct.lpstrFindWhat, + s_findrep_struct.lpstrReplaceWith, down); + } +} +#endif + + static void +HandleMouseHide(UINT uMsg, LPARAM lParam) +{ + static LPARAM last_lParam = 0L; + + /* We sometimes get a mousemove when the mouse didn't move... */ + if (uMsg == WM_MOUSEMOVE) + { + if (lParam == last_lParam) + return; + last_lParam = lParam; + } + + /* Handle specially, to centralise coding. We need to be sure we catch all + * possible events which should cause us to restore the cursor (as it is a + * shared resource, we take full responsibility for it). + */ + switch (uMsg) + { + case WM_KEYUP: + case WM_CHAR: + /* + * blank out the pointer if necessary + */ + if (p_mh) + gui_mch_mousehide(TRUE); + break; + + case WM_SYSKEYUP: /* show the pointer when a system-key is pressed */ + case WM_SYSCHAR: + case WM_MOUSEMOVE: /* show the pointer on any mouse action */ + case WM_LBUTTONDOWN: + case WM_LBUTTONUP: + case WM_MBUTTONDOWN: + case WM_MBUTTONUP: + case WM_RBUTTONDOWN: + case WM_RBUTTONUP: + case WM_XBUTTONDOWN: + case WM_XBUTTONUP: + case WM_NCMOUSEMOVE: + case WM_NCLBUTTONDOWN: + case WM_NCLBUTTONUP: + case WM_NCMBUTTONDOWN: + case WM_NCMBUTTONUP: + case WM_NCRBUTTONDOWN: + case WM_NCRBUTTONUP: + case WM_KILLFOCUS: + /* + * if the pointer is currently hidden, then we should show it. + */ + gui_mch_mousehide(FALSE); + break; + } +} + + static LRESULT CALLBACK +_TextAreaWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + /* + TRACE("TextAreaWndProc: 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; + +#ifdef FEAT_BEVAL + TrackUserActivity(uMsg); +#endif + + switch (uMsg) + { + HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_LBUTTONDOWN,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_LBUTTONUP, _OnMouseMoveOrRelease); + HANDLE_MSG(hwnd, WM_MBUTTONDBLCLK,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_MBUTTONDOWN,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_MBUTTONUP, _OnMouseMoveOrRelease); + HANDLE_MSG(hwnd, WM_MOUSEMOVE, _OnMouseMoveOrRelease); + HANDLE_MSG(hwnd, WM_PAINT, _OnPaint); + HANDLE_MSG(hwnd, WM_RBUTTONDBLCLK,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_RBUTTONDOWN,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_RBUTTONUP, _OnMouseMoveOrRelease); +#ifndef WIN16 /*<VN>*/ + HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease); +#endif + +#ifdef FEAT_BEVAL + case WM_NOTIFY: Handle_WM_Notify(hwnd, (LPNMHDR)lParam); + return TRUE; +#endif + + default: + return MyWindowProc(hwnd, uMsg, wParam, lParam); + } +} + +#if (defined(WIN3264) && defined(FEAT_MBYTE)) \ + || defined(GLOBAL_IME) \ + || defined(PROTO) +# ifdef PROTO +typedef int WINAPI; +# endif + + LRESULT WINAPI +vim_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ +# ifdef GLOBAL_IME + return global_ime_DefWindowProc(hwnd, message, wParam, lParam); +# else + if (wide_WindowProc) + return DefWindowProcW(hwnd, message, wParam, lParam); + return DefWindowProc(hwnd, message, wParam, lParam); +#endif +} +#endif + +/* + * Called when the foreground or background color has been changed. + */ + void +gui_mch_new_colors(void) +{ + /* nothing to do? */ +} + +/* + * Set the colors to their default values. + */ + void +gui_mch_def_colors() +{ + gui.norm_pixel = GetSysColor(COLOR_WINDOWTEXT); + gui.back_pixel = GetSysColor(COLOR_WINDOW); + gui.def_norm_pixel = gui.norm_pixel; + gui.def_back_pixel = gui.back_pixel; +} + +/* + * Open the GUI window which was created by a call to gui_mch_init(). + */ + int +gui_mch_open(void) +{ +#ifndef SW_SHOWDEFAULT +# define SW_SHOWDEFAULT 10 /* Borland 5.0 doesn't have it */ +#endif + /* Actually open the window, if not already visible + * (may be done already in gui_mch_set_shellsize) */ + if (!IsWindowVisible(s_hwnd)) + ShowWindow(s_hwnd, SW_SHOWDEFAULT); + + return OK; +} + +/* + * Get the position of the top left corner of the window. + */ + int +gui_mch_get_winpos(int *x, int *y) +{ + RECT rect; + + GetWindowRect(s_hwnd, &rect); + *x = rect.left; + *y = rect.top; + return OK; +} + +/* + * Set the position of the top left corner of the window to the given + * coordinates. + */ + void +gui_mch_set_winpos(int x, int y) +{ + SetWindowPos(s_hwnd, NULL, x, y, 0, 0, + SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); +} + void +gui_mch_set_text_area_pos(int x, int y, int w, int h) +{ + static int oldx = 0; + static int oldy = 0; + + SetWindowPos(s_textArea, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE); + +#ifdef FEAT_TOOLBAR + if (vim_strchr(p_go, GO_TOOLBAR) != NULL) + SendMessage(s_toolbarhwnd, WM_SIZE, + (WPARAM)0, (LPARAM)(w + ((long)(TOOLBAR_BUTTON_HEIGHT+8)<<16))); +#endif + /* When side scroll bar is unshown, the size of window will change. + * then, the text area move left or right. thus client rect should be + * forcely redraw. (Yasuhiro Matsumoto) */ + if (oldx != x || oldy != y) + { + InvalidateRect(s_hwnd, NULL, FALSE); + oldx = x; + oldy = y; + } + +} + + +/* + * Scrollbar stuff: + */ + + void +gui_mch_enable_scrollbar( + scrollbar_T *sb, + int flag) +{ + ShowScrollBar(sb->id, SB_CTL, flag); + + /* TODO: When the window is maximized, the size of the window stays the + * same, thus the size of the text area changes. On Win98 it's OK, on Win + * NT 4.0 it's not... */ +} + + void +gui_mch_set_scrollbar_pos( + scrollbar_T *sb, + int x, + int y, + int w, + int h) +{ + SetWindowPos(sb->id, NULL, x, y, w, h, SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW); +} + + void +gui_mch_create_scrollbar( + scrollbar_T *sb, + int orient) /* SBAR_VERT or SBAR_HORIZ */ +{ + sb->id = CreateWindow( + "SCROLLBAR", "Scrollbar", + WS_CHILD | ((orient == SBAR_VERT) ? SBS_VERT : SBS_HORZ), 0, 0, + 10, /* Any value will do for now */ + 10, /* Any value will do for now */ + s_hwnd, NULL, + s_hinst, NULL); +} + +/* + * Find the scrollbar with the given hwnd. + */ + static scrollbar_T * +gui_mswin_find_scrollbar(HWND hwnd) +{ + win_T *wp; + + if (gui.bottom_sbar.id == hwnd) + return &gui.bottom_sbar; + FOR_ALL_WINDOWS(wp) + { + if (wp->w_scrollbars[SBAR_LEFT].id == hwnd) + return &wp->w_scrollbars[SBAR_LEFT]; + if (wp->w_scrollbars[SBAR_RIGHT].id == hwnd) + return &wp->w_scrollbars[SBAR_RIGHT]; + } + return NULL; +} + +/* + * Get the character size of a font. + */ + static void +GetFontSize(GuiFont font) +{ + HWND hwnd = GetDesktopWindow(); + HDC hdc = GetWindowDC(hwnd); + HFONT hfntOld = SelectFont(hdc, (HFONT)font); + TEXTMETRIC tm; + + GetTextMetrics(hdc, &tm); + gui.char_width = tm.tmAveCharWidth + tm.tmOverhang; + + gui.char_height = tm.tmHeight +#ifndef MSWIN16_FASTTEXT + + p_linespace +#endif + ; + + SelectFont(hdc, hfntOld); + + ReleaseDC(hwnd, hdc); +} + + int +gui_mch_adjust_charsize(void) +{ + GetFontSize(gui.norm_font); + return OK; +} + + static GuiFont +get_font_handle(LOGFONT *lf) +{ + HFONT font = NULL; + + /* Load the font */ + font = CreateFontIndirect(lf); + + if (font == NULL) + return NOFONT; + + return (GuiFont)font; +} + + static int +pixels_to_points(int pixels, int vertical) +{ + int points; + HWND hwnd; + HDC hdc; + + hwnd = GetDesktopWindow(); + hdc = GetWindowDC(hwnd); + + points = MulDiv(pixels, 72, + GetDeviceCaps(hdc, vertical ? LOGPIXELSY : LOGPIXELSX)); + + ReleaseDC(hwnd, hdc); + + return points; +} + + GuiFont +gui_mch_get_font( + char_u *name, + int giveErrorIfMissing) +{ + LOGFONT lf; + GuiFont font; + + get_logfont(&lf, name, NULL); + font = get_font_handle(&lf); + if (font == NOFONT && giveErrorIfMissing) + EMSG2(_(e_font), name); + return font; +} + void +gui_mch_free_font(GuiFont font) +{ + if (font) + DeleteObject((HFONT)font); +} + + static int +hex_digit(int c) +{ + if (VIM_ISDIGIT(c)) + return c - '0'; + c = TOLOWER_ASC(c); + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + return -1000; +} +/* + * Return the Pixel value (color) for the given color name. + * Return INVALCOLOR for error. + */ + guicolor_T +gui_mch_get_color(char_u *name) +{ + typedef struct guicolor_tTable + { + char *name; + COLORREF color; + } guicolor_tTable; + + static guicolor_tTable table[] = + { + {"Black", RGB(0x00, 0x00, 0x00)}, + {"DarkGray", RGB(0x80, 0x80, 0x80)}, + {"DarkGrey", RGB(0x80, 0x80, 0x80)}, + {"Gray", RGB(0xC0, 0xC0, 0xC0)}, + {"Grey", RGB(0xC0, 0xC0, 0xC0)}, + {"LightGray", RGB(0xE0, 0xE0, 0xE0)}, + {"LightGrey", RGB(0xE0, 0xE0, 0xE0)}, + {"White", RGB(0xFF, 0xFF, 0xFF)}, + {"DarkRed", RGB(0x80, 0x00, 0x00)}, + {"Red", RGB(0xFF, 0x00, 0x00)}, + {"LightRed", RGB(0xFF, 0xA0, 0xA0)}, + {"DarkBlue", RGB(0x00, 0x00, 0x80)}, + {"Blue", RGB(0x00, 0x00, 0xFF)}, + {"LightBlue", RGB(0xA0, 0xA0, 0xFF)}, + {"DarkGreen", RGB(0x00, 0x80, 0x00)}, + {"Green", RGB(0x00, 0xFF, 0x00)}, + {"LightGreen", RGB(0xA0, 0xFF, 0xA0)}, + {"DarkCyan", RGB(0x00, 0x80, 0x80)}, + {"Cyan", RGB(0x00, 0xFF, 0xFF)}, + {"LightCyan", RGB(0xA0, 0xFF, 0xFF)}, + {"DarkMagenta", RGB(0x80, 0x00, 0x80)}, + {"Magenta", RGB(0xFF, 0x00, 0xFF)}, + {"LightMagenta", RGB(0xFF, 0xA0, 0xFF)}, + {"Brown", RGB(0x80, 0x40, 0x40)}, + {"Yellow", RGB(0xFF, 0xFF, 0x00)}, + {"LightYellow", RGB(0xFF, 0xFF, 0xA0)}, + {"DarkYellow", RGB(0xBB, 0xBB, 0x00)}, + {"SeaGreen", RGB(0x2E, 0x8B, 0x57)}, + {"Orange", RGB(0xFF, 0xA5, 0x00)}, + {"Purple", RGB(0xA0, 0x20, 0xF0)}, + {"SlateBlue", RGB(0x6A, 0x5A, 0xCD)}, + {"Violet", RGB(0xEE, 0x82, 0xEE)}, + }; + + typedef struct SysColorTable + { + char *name; |