Mercurial > vim
view src/gui_w48.c @ 2894:fe9c7da98b5e v7.3.220
updated for version 7.3.220
Problem: Python 3: vim.error is a 'str' instead of an 'Exception' object,
so 'except' or 'raise' it causes a 'SystemError' exception.
Buffer objects do not support slice assignment.
When exchanging text between Vim and Python, multibyte texts become
gabage or cause Unicode Expceptions, etc.
'py3file' tries to read in the file as Unicode, sometimes causes
UnicodeDecodeException
Solution: Fix the problems. (lilydjwg)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Sun, 19 Jun 2011 00:27:51 +0200 |
parents | 6c05b5e5c1be |
children | e5b17a5f6516 |
line wrap: on
line source
/* 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) || defined(FEAT_GUI_TABLINE) # 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_MIN_MAX_HEIGHT 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; typedef int HRESULT; # 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 interrupted 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; # if defined(FEAT_MBYTE) && defined(WIN3264) static FINDREPLACEW s_findrep_struct_w; # endif 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 #ifdef FEAT_GUI_TABLINE static HWND s_tabhwnd = NULL; static int showing_tabline = 0; #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; /* s_getting_focus is set when we got focus but didn't see mouse-up event yet, * so don't reset s_button_pending. */ static int s_getting_focus = FALSE; 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_ERROR /* * 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 /* * 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. */ /*ARGSUSED*/ 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; } /*ARGSUSED*/ static void _OnDeadChar( HWND hwnd, UINT ch, int cRepeat) { dead_key = 1; } /* * Convert Unicode character "ch" to bytes in "string[slen]". * When "had_alt" is TRUE the ALT key was included in "ch". * Return the length. */ static int char_to_string(int ch, char_u *string, int slen, int had_alt) { int len; int i; #ifdef FEAT_MBYTE WCHAR wstring[2]; char_u *ws = NULL;; if (os_version.dwPlatformId != VER_PLATFORM_WIN32_NT) { /* On Windows 95/98 we apparently get the character in the active * codepage, not in UCS-2. If conversion is needed convert it to * UCS-2 first. */ if ((int)GetACP() == enc_codepage) len = 0; /* no conversion required */ else { string[0] = ch; len = MultiByteToWideChar(GetACP(), 0, string, 1, wstring, 2); } } else { wstring[0] = ch; len = 1; } if (len > 0) { /* "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). */ if (enc_codepage > 0) { len = WideCharToMultiByte(enc_codepage, 0, wstring, len, string, slen, 0, NULL); /* If we had included the ALT key into the character but now the * upper bit is no longer set, that probably means the conversion * failed. Convert the original character and set the upper bit * afterwards. */ if (had_alt && len == 1 && ch >= 0x80 && string[0] < 0x80) { wstring[0] = ch & 0x7f; len = WideCharToMultiByte(enc_codepage, 0, wstring, len, string, slen, 0, NULL); if (len == 1) /* safety check */ string[0] |= 0x80; } } else { len = 1; ws = utf16_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. */ /*ARGSUSED*/ static void _OnChar( HWND hwnd, UINT ch, int cRepeat) { char_u string[40]; int len = 0; len = char_to_string(ch, string, 40, FALSE); 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. */ /*ARGSUSED*/ 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, TRUE); } add_to_input_buf(string, len); } static void _OnMouseEvent( int button, int x, int y, int repeated_click, UINT keyFlags) { int vim_modifiers = 0x0; s_getting_focus = FALSE; 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); } /*ARGSUSED*/ 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; } } /*ARGSUSED*/ static void _OnMouseMoveOrRelease( HWND hwnd, int x, int y, UINT keyFlags) { int button; s_getting_focus = FALSE; 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; } /*ARGSUSED*/ 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 # if defined(FEAT_MBYTE) && defined(WIN3264) /* * copy useful data from structure LPFINDREPLACE to structure LPFINDREPLACEW */ static void findrep_atow(LPFINDREPLACEW lpfrw, LPFINDREPLACE lpfr) { WCHAR *wp; lpfrw->hwndOwner = lpfr->hwndOwner; lpfrw->Flags = lpfr->Flags; wp = enc_to_utf16(lpfr->lpstrFindWhat, NULL); wcsncpy(lpfrw->lpstrFindWhat, wp, lpfrw->wFindWhatLen - 1); vim_free(wp); /* the field "lpstrReplaceWith" doesn't need to be copied */ } /* * copy useful data from structure LPFINDREPLACEW to structure LPFINDREPLACE */ static void findrep_wtoa(LPFINDREPLACE lpfr, LPFINDREPLACEW lpfrw) { char_u *p; lpfr->Flags = lpfrw->Flags; p = utf16_to_enc(lpfrw->lpstrFindWhat, NULL); vim_strncpy(lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1); vim_free(p); p = utf16_to_enc(lpfrw->lpstrReplaceWith, NULL); vim_strncpy(lpfr->lpstrReplaceWith, p, lpfr->wReplaceWithLen - 1); vim_free(p); } # endif /* * Handle a Find/Replace window message. */ static void _OnFindRepl(void) { int flags = 0; int down; # if defined(FEAT_MBYTE) && defined(WIN3264) /* If the OS is Windows NT, and 'encoding' differs from active codepage: * convert text from wide string. */ if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT && enc_codepage >= 0 && (int)GetACP() != enc_codepage) { findrep_wtoa(&s_findrep_struct, &s_findrep_struct_w); } # endif 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); #ifdef MSWIN_FIND_REPLACE /* Init replace string here, so that we keep it when re-opening the * dialog. */ s_findrep_struct.lpstrReplaceWith[0] = NUL; #endif 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 #if defined(FEAT_GUI_TABLINE) if (showing_tabline) { int top = 0; RECT rect; # ifdef FEAT_TOOLBAR if (vim_strchr(p_go, GO_TOOLBAR) != NULL) top = TOOLBAR_BUTTON_HEIGHT + TOOLBAR_BORDER_HEIGHT; # endif GetClientRect(s_hwnd, &rect); MoveWindow(s_tabhwnd, 0, top, rect.right, gui.tabline_height, TRUE); } #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); } /* * Adjust gui.char_height (after 'linespace' was changed). */ int gui_mch_adjust_charheight(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 = NOFONT; if (get_logfont(&lf, name, NULL, giveErrorIfMissing) == OK) font = get_font_handle(&lf); if (font == NOFONT && giveErrorIfMissing) EMSG2(_(e_font), name); return font; } #if defined(FEAT_EVAL) || defined(PROTO) /* * Return the name of font "font" in allocated memory. * Don't know how to get the actual name, thus use the provided name. */ /*ARGSUSED*/ char_u * gui_mch_get_fontname(font, name) GuiFont font; char_u *name; { if (name == NULL) return NULL; return vim_strsave(name); } #endif 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)}, {"Gray10", RGB(0x1A, 0x1A, 0x1A)}, {"Grey10", RGB(0x1A, 0x1A, 0x1A)}, {"Gray20", RGB(0x33, 0x33, 0x33)}, {"Grey20", RGB(0x33, 0x33, 0x33)}, {"Gray30", RGB(0x4D, 0x4D, 0x4D)}, {"Grey30", RGB(0x4D, 0x4D, 0x4D)}, {"Gray40", RGB(0x66, 0x66, 0x66)}, {"Grey40", RGB(0x66, 0x66, 0x66)}, {"Gray50", RGB(0x7F, 0x7F, 0x7F)}, {"Grey50", RGB(0x7F, 0x7F, 0x7F)}, {"Gray60", RGB(0x99, 0x99, 0x99)}, {"Grey60", RGB(0x99, 0x99, 0x99)}, {"Gray70", RGB(0xB3, 0xB3, 0xB3)}, {"Grey70", RGB(0xB3, 0xB3, 0xB3)}, {"Gray80", RGB(0xCC, 0xCC, 0xCC)}, {"Grey80", RGB(0xCC, 0xCC, 0xCC)}, {"Gray90", RGB(0xE5, 0xE5, 0xE5)}, {"Grey90", RGB(0xE5, 0xE5, 0xE5)}, {"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; int color; } SysColorTable; static SysColorTable sys_table[] = { #ifdef WIN3264 {"SYS_3DDKSHADOW", COLOR_3DDKSHADOW}, {"SYS_3DHILIGHT", COLOR_3DHILIGHT}, #ifndef __MINGW32__ {"SYS_3DHIGHLIGHT", COLOR_3DHIGHLIGHT}, #endif {"SYS_BTNHILIGHT", COLOR_BTNHILIGHT}, {"SYS_BTNHIGHLIGHT", COLOR_BTNHIGHLIGHT}, {"SYS_3DLIGHT", COLOR_3DLIGHT}, {"SYS_3DSHADOW", COLOR_3DSHADOW}, {"SYS_DESKTOP", COLOR_DESKTOP}, {"SYS_INFOBK", COLOR_INFOBK}, {"SYS_INFOTEXT", COLOR_INFOTEXT}, {"SYS_3DFACE", COLOR_3DFACE}, #endif {"SYS_BTNFACE", COLOR_BTNFACE}, {"SYS_BTNSHADOW", COLOR_BTNSHADOW}, {"SYS_ACTIVEBORDER", COLOR_ACTIVEBORDER}, {"SYS_ACTIVECAPTION", COLOR_ACTIVECAPTION}, {"SYS_APPWORKSPACE", COLOR_APPWORKSPACE}, {"SYS_BACKGROUND", COLOR_BACKGROUND}, {"SYS_BTNTEXT", COLOR_BTNTEXT}, {"SYS_CAPTIONTEXT", COLOR_CAPTIONTEXT}, {"SYS_GRAYTEXT", COLOR_GRAYTEXT}, {"SYS_HIGHLIGHT", COLOR_HIGHLIGHT}, {"SYS_HIGHLIGHTTEXT", COLOR_HIGHLIGHTTEXT}, {"SYS_INACTIVEBORDER", COLOR_INACTIVEBORDER}, {"SYS_INACTIVECAPTION", COLOR_INACTIVECAPTION}, {"SYS_INACTIVECAPTIONTEXT", COLOR_INACTIVECAPTIONTEXT}, {"SYS_MENU", COLOR_MENU}, {"SYS_MENUTEXT", COLOR_MENUTEXT}, {"SYS_SCROLLBAR", COLOR_SCROLLBAR}, {"SYS_WINDOW", COLOR_WINDOW}, {"SYS_WINDOWFRAME", COLOR_WINDOWFRAME}, {"SYS_WINDOWTEXT", COLOR_WINDOWTEXT} }; int r, g, b; int i; if (name[0] == '#' && strlen(name) == 7) { /* Name is in "#rrggbb" format */ r = hex_digit(name[1]) * 16 + hex_digit(name[2]); g = hex_digit(name[3]) * 16 + hex_digit(name[4]); b = hex_digit(name[5]) * 16 + hex_digit(name[6]); if (r < 0 || g < 0 || b < 0) return INVALCOLOR; return RGB(r, g, b); } else { /* Check if the name is one of the colors we know */ for (i = 0; i < sizeof(table) / sizeof(table[0]); i++) if (STRICMP(name, table[i].name) == 0) return table[i].color; } /* * Try to look up a system colour. */ for (i = 0; i < sizeof(sys_table) / sizeof(sys_table[0]); i++) if (STRICMP(name, sys_table[i].name) == 0) return GetSysColor(sys_table[i].color); /* * Last attempt. Look in the file "$VIMRUNTIME/rgb.txt". */ { #define LINE_LEN 100 FILE *fd; char line[LINE_LEN]; char_u *fname; fname = expand_env_save((char_u *)"$VIMRUNTIME/rgb.txt"); if (fname == NULL) return INVALCOLOR; fd = mch_fopen((char *)fname, "rt"); vim_free(fname); if (fd == NULL) return INVALCOLOR; while (!feof(fd)) { int len; int pos; char *color; fgets(line, LINE_LEN, fd); len = (int)STRLEN(line); if (len <= 1 || line[len-1] != '\n') continue; line[len-1] = '\0'; i = sscanf(line, "%d %d %d %n", &r, &g, &b, &pos); if (i != 3) continue; color = line + pos; if (STRICMP(color, name) == 0) { fclose(fd); return (guicolor_T) RGB(r, g, b); } } fclose(fd); } return INVALCOLOR; } /* * Return OK if the key with the termcap name "name" is supported. */ int gui_mch_haskey(char_u *name) { int i; for (i = 0; special_keys[i].vim_code1 != NUL; i++) if (name[0] == special_keys[i].vim_code0 && name[1] == special_keys[i].vim_code1) return OK; return FAIL; } void gui_mch_beep(void) { MessageBeep(MB_OK); } /* * Invert a rectangle from row r, column c, for nr rows and nc columns. */ void gui_mch_invert_rectangle( int r, int c, int nr, int nc) { RECT rc; /* * Note: InvertRect() excludes right and bottom of rectangle. */ rc.left = FILL_X(c); rc.top = FILL_Y(r); rc.right = rc.left + nc * gui.char_width; rc.bottom = rc.top + nr * gui.char_height; InvertRect(s_hdc, &rc); } /* * Iconify the GUI window. */ void gui_mch_iconify(void) { ShowWindow(s_hwnd, SW_MINIMIZE); } /* * Draw a cursor without focus. */ void gui_mch_draw_hollow_cursor(guicolor_T color) { HBRUSH hbr; RECT rc; /* * Note: FrameRect() excludes right and bottom of rectangle. */ rc.left = FILL_X(gui.col); rc.top = FILL_Y(gui.row); rc.right = rc.left + gui.char_width; #ifdef FEAT_MBYTE if (mb_lefthalve(gui.row, gui.col)) rc.right += gui.char_width; #endif rc.bottom = rc.top + gui.char_height; hbr = CreateSolidBrush(color); FrameRect(s_hdc, &rc, hbr); DeleteBrush(hbr); } /* * Draw part of a cursor, "w" pixels wide, and "h" pixels high, using * color "color". */ void gui_mch_draw_part_cursor( int w, int h, guicolor_T color) { HBRUSH hbr; RECT rc; /* * Note: FillRect() excludes right and bottom of rectangle. */ rc.left = #ifdef FEAT_RIGHTLEFT /* vertical line should be on the right of current point */ CURSOR_BAR_RIGHT ? FILL_X(gui.col + 1) - w : #endif FILL_X(gui.col); rc.top = FILL_Y(gui.row) + gui.char_height - h; rc.right = rc.left + w; rc.bottom = rc.top + h; hbr = CreateSolidBrush(color); FillRect(s_hdc, &rc, hbr); DeleteBrush(hbr); } /* * Process a single Windows message. * If one is not available we hang until one is. */ static void process_message(void) { MSG msg; UINT vk = 0; /* Virtual key */ char_u string[40]; int i; int modifiers = 0; int key; #ifdef FEAT_MENU static char_u k10[] = {K_SPECIAL, 'k', ';', 0}; #endif GetMessage(&msg, NULL, 0, 0); #ifdef FEAT_OLE /* Look after OLE Automation commands */ if (msg.message == WM_OLE) { char_u *str = (char_u *)msg.lParam; if (str == NULL || *str == NUL) { /* Message can't be ours, forward it. Fixes problem with Ultramon * 3.0.4 */ DispatchMessage(&msg); } else { add_to_input_buf(str, (int)STRLEN(str)); vim_free(str); /* was allocated in CVim::SendKeys() */ } return; } #endif #ifdef FEAT_NETBEANS_INTG if (msg.message == WM_NETBEANS) { netbeans_read(); return; } #endif #ifdef FEAT_SNIFF if (sniff_request_waiting && want_sniff_request) { static char_u bytes[3] = {CSI, (char_u)KS_EXTRA, (char_u)KE_SNIFF}; add_to_input_buf(bytes, 3); /* K_SNIFF */ sniff_request_waiting = 0; want_sniff_request = 0; /* request is handled in normal.c */ } if (msg.message == WM_USER) { MyTranslateMessage(&msg); DispatchMessage(&msg); return; } #endif #ifdef MSWIN_FIND_REPLACE /* Don't process messages used by the dialog */ if (s_findrep_hwnd != NULL && IsDialogMessage(s_findrep_hwnd, &msg)) { HandleMouseHide(msg.message, msg.lParam); return; } #endif /* * Check if it's a special key that we recognise. If not, call * TranslateMessage(). */ if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN) { vk = (int) msg.wParam; /* handle key after dead key, but ignore shift, alt and control */ if (dead_key && vk != VK_SHIFT && vk != VK_MENU && vk != VK_CONTROL) { dead_key = 0; /* handle non-alphabetic keys (ones that hopefully cannot generate * umlaut-characters), unless when control is down */ if (vk < 'A' || vk > 'Z' || (GetKeyState(VK_CONTROL) & 0x8000)) { MSG dm; dm.message = msg.message; dm.hwnd = msg.hwnd; dm.wParam = VK_SPACE; MyTranslateMessage(&dm); /* generate dead character */ if (vk != VK_SPACE) /* and send current character once more */ PostMessage(msg.hwnd, msg.message, msg.wParam, msg.lParam); return; } } /* Check for CTRL-BREAK */ if (vk == VK_CANCEL) { trash_input_buf(); got_int = TRUE; string[0] = Ctrl_C; add_to_input_buf(string, 1); } for (i = 0; special_keys[i].key_sym != 0; i++) { /* ignore VK_SPACE when ALT key pressed: system menu */ if (special_keys[i].key_sym == vk && (vk != VK_SPACE || !(GetKeyState(VK_MENU) & 0x8000))) { #ifdef FEAT_MENU /* Check for <F10>: Windows selects the menu. When <F10> is * mapped we want to use the mapping instead. */ if (vk == VK_F10 && gui.menu_is_active && check_map(k10, State, FALSE, TRUE, FALSE, NULL, NULL) == NULL) break; #endif if (GetKeyState(VK_SHIFT) & 0x8000) modifiers |= MOD_MASK_SHIFT; /* * Don't use caps-lock as shift, because these are special keys * being considered here, and we only want letters to get * shifted -- webb */ /* if (GetKeyState(VK_CAPITAL) & 0x0001) modifiers ^= MOD_MASK_SHIFT; */ if (GetKeyState(VK_CONTROL) & 0x8000) modifiers |= MOD_MASK_CTRL; if (GetKeyState(VK_MENU) & 0x8000) modifiers |= MOD_MASK_ALT; if (special_keys[i].vim_code1 == NUL) key = special_keys[i].vim_code0; else key = TO_SPECIAL(special_keys[i].vim_code0, special_keys[i].vim_code1); key = simplify_key(key, &modifiers); if (key == CSI) key = K_CSI; if (modifiers) { string[0] = CSI; string[1] = KS_MODIFIER; string[2] = modifiers; add_to_input_buf(string, 3); } if (IS_SPECIAL(key)) { string[0] = CSI; string[1] = K_SECOND(key); string[2] = K_THIRD(key); add_to_input_buf(string, 3); } else { int len; /* Handle "key" as a Unicode character. */ len = char_to_string(key, string, 40, FALSE); add_to_input_buf(string, len); } break; } } if (special_keys[i].key_sym == 0) { /* Some keys need C-S- where they should only need C-. * Ignore 0xff, Windows XP sends it when NUMLOCK has changed since * system startup (Helmut Stiegler, 2003 Oct 3). */ if (vk != 0xff && (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000)) { /* CTRL-6 is '^'; Japanese keyboard maps '^' to vk == 0xDE */ if (vk == '6' || MapVirtualKey(vk, 2) == (UINT)'^') { string[0] = Ctrl_HAT; add_to_input_buf(string, 1); } /* vk == 0xBD AZERTY for CTRL-'-', but CTRL-[ for * QWERTY! */ else if (vk == 0xBD) /* QWERTY for CTRL-'-' */ { string[0] = Ctrl__; add_to_input_buf(string, 1); } /* CTRL-2 is '@'; Japanese keyboard maps '@' to vk == 0xC0 */ else if (vk == '2' || MapVirtualKey(vk, 2) == (UINT)'@') { string[0] = Ctrl_AT; add_to_input_buf(string, 1); } else MyTranslateMessage(&msg); } else MyTranslateMessage(&msg); } } #ifdef FEAT_MBYTE_IME else if (msg.message == WM_IME_NOTIFY) _OnImeNotify(msg.hwnd, (DWORD)msg.wParam, (DWORD)msg.lParam); else if (msg.message == WM_KEYUP && im_get_status()) /* added for non-MS IME (Yasuhiro Matsumoto) */ MyTranslateMessage(&msg); #endif #if !defined(FEAT_MBYTE_IME) && defined(GLOBAL_IME) /* GIME_TEST */ else if (msg.message == WM_IME_STARTCOMPOSITION) { POINT point; global_ime_set_font(&norm_logfont); point.x = FILL_X(gui.col); point.y = FILL_Y(gui.row); MapWindowPoints(s_textArea, s_hwnd, &point, 1); global_ime_set_position(&point); } #endif #ifdef FEAT_MENU /* Check for <F10>: Default effect is to select the menu. When <F10> is * mapped we need to stop it here to avoid strange effects (e.g., for the * key-up event) */ if (vk != VK_F10 || check_map(k10, State, FALSE, TRUE, FALSE, NULL, NULL) == NULL) #endif DispatchMessage(&msg); } /* * Catch up with any queued events. This may put keyboard input into the * input buffer, call resize call-backs, trigger timers etc. If there is * nothing in the event queue (& no timers pending), then we return * immediately. */ void gui_mch_update(void) { MSG msg; if (!s_busy_processing) while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) && !vim_is_input_buf_full()) process_message(); } /* * GUI input routine called by gui_wait_for_chars(). Waits for a character * from the keyboard. * wtime == -1 Wait forever. * wtime == 0 This should never happen. * wtime > 0 Wait wtime milliseconds for a character. * Returns OK if a character was found to be available within the given time, * or FAIL otherwise. */ int gui_mch_wait_for_chars(int wtime) { MSG msg; int focus; s_timed_out = FALSE; if (wtime > 0) { /* Don't do anything while processing a (scroll) message. */ if (s_busy_processing) return FAIL; s_wait_timer = (UINT)SetTimer(NULL, 0, (UINT)wtime, (TIMERPROC)_OnTimer); } allow_scrollbar = TRUE; focus = gui.in_focus; while (!s_timed_out) { /* Stop or start blinking when focus changes */ if (gui.in_focus != focus) { if (gui.in_focus) gui_mch_start_blink(); else gui_mch_stop_blink(); focus = gui.in_focus; } if (s_need_activate) { #ifdef WIN32 (void)SetForegroundWindow(s_hwnd); #else (void)SetActiveWindow(s_hwnd); #endif s_need_activate = FALSE; } #ifdef FEAT_NETBEANS_INTG /* Process the queued netbeans messages. */ netbeans_parse_messages(); #endif /* * Don't use gui_mch_update() because then we will spin-lock until a * char arrives, instead we use GetMessage() to hang until an * event arrives. No need to check for input_buf_full because we are * returning as soon as it contains a single char -- webb */ process_message(); if (input_available()) { if (s_wait_timer != 0 && !s_timed_out) { KillTimer(NULL, s_wait_timer); /* Eat spurious WM_TIMER messages */ while (PeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE)) ; s_wait_timer = 0; } allow_scrollbar = FALSE; /* Clear pending mouse button, the release event may have been * taken by the dialog window. But don't do this when getting * focus, we need the mouse-up event then. */ if (!s_getting_focus) s_button_pending = -1; return OK; } } allow_scrollbar = FALSE; return FAIL; } /* * Clear a rectangular region of the screen from text pos (row1, col1) to * (row2, col2) inclusive. */ void gui_mch_clear_block( int row1, int col1, int row2, int col2) { RECT rc; /* * Clear one extra pixel at the far right, for when bold characters have * spilled over to the window border. * Note: FillRect() excludes right and bottom of rectangle. */ rc.left = FILL_X(col1); rc.top = FILL_Y(row1); rc.right = FILL_X(col2 + 1) + (col2 == Columns - 1); rc.bottom = FILL_Y(row2 + 1); clear_rect(&rc); } /* * Clear the whole text window. */ void gui_mch_clear_all(void) { RECT rc; rc.left = 0; rc.top = 0; rc.right = Columns * gui.char_width + 2 * gui.border_width; rc.bottom = Rows * gui.char_height + 2 * gui.border_width; clear_rect(&rc); } /* * Menu stuff. */ void gui_mch_enable_menu(int flag) { #ifdef FEAT_MENU SetMenu(s_hwnd, flag ? s_menuBar : NULL); #endif } /*ARGSUSED*/ void gui_mch_set_menu_pos( int x, int y, int w, int h) { /* It will be in the right place anyway */ } #if defined(FEAT_MENU) || defined(PROTO) /* * Make menu item hidden or not hidden */ void gui_mch_menu_hidden( vimmenu_T *menu, int hidden) { /* * This doesn't do what we want. Hmm, just grey the menu items for now. */ /* if (hidden) EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_DISABLED); else EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED); */ gui_mch_menu_grey(menu, hidden); } /* * This is called after setting all the menus to grey/hidden or not. */ void gui_mch_draw_menubar(void) { DrawMenuBar(s_hwnd); } #endif /*FEAT_MENU*/ #ifndef PROTO void #ifdef VIMDLL _export #endif _cdecl SaveInst(HINSTANCE hInst) { s_hinst = hInst; } #endif /* * Return the RGB value of a pixel as a long. */ long_u gui_mch_get_rgb(guicolor_T pixel) { return (GetRValue(pixel) << 16) + (GetGValue(pixel) << 8) + GetBValue(pixel); } #if defined(FEAT_GUI_DIALOG) || defined(PROTO) /* Convert pixels in X to dialog units */ static WORD PixelToDialogX(int numPixels) { return (WORD)((numPixels * 4) / s_dlgfntwidth); } /* Convert pixels in Y to dialog units */ static WORD PixelToDialogY(int numPixels) { return (WORD)((numPixels * 8) / s_dlgfntheight); } /* Return the width in pixels of the given text in the given DC. */ static int GetTextWidth(HDC hdc, char_u *str, int len) { SIZE size; GetTextExtentPoint(hdc, str, len, &size); return size.cx; } #ifdef FEAT_MBYTE /* * Return the width in pixels of the given text in the given DC, taking care * of 'encoding' to active codepage conversion. */ static int GetTextWidthEnc(HDC hdc, char_u *str, int len) { SIZE size; WCHAR *wstr; int n; int wlen = len; if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { /* 'encoding' differs from active codepage: convert text and use wide * function */ wstr = enc_to_utf16(str, &wlen); if (wstr != NULL) { n = GetTextExtentPointW(hdc, wstr, wlen, &size); vim_free(wstr); if (n) return size.cx; } } return GetTextWidth(hdc, str, len); } #else # define GetTextWidthEnc(h, s, l) GetTextWidth((h), (s), (l)) #endif /* * A quick little routine that will center one window over another, handy for * dialog boxes. Taken from the Win32SDK samples. */ static BOOL CenterWindow( HWND hwndChild, HWND hwndParent) { RECT rChild, rParent; int wChild, hChild, wParent, hParent; int wScreen, hScreen, xNew, yNew; HDC hdc; GetWindowRect(hwndChild, &rChild); wChild = rChild.right - rChild.left; hChild = rChild.bottom - rChild.top; /* If Vim is minimized put the window in the middle of the screen. */ if (hwndParent == NULL || IsMinimized(hwndParent)) { #ifdef WIN16 rParent.left = 0; rParent.top = 0; rParent.right = GetSystemMetrics(SM_CXSCREEN); rParent.bottom = GetSystemMetrics(SM_CYFULLSCREEN); #else SystemParametersInfo(SPI_GETWORKAREA, 0, &rParent, 0); #endif } else GetWindowRect(hwndParent, &rParent); wParent = rParent.right - rParent.left; hParent = rParent.bottom - rParent.top; hdc = GetDC(hwndChild); wScreen = GetDeviceCaps (hdc, HORZRES); hScreen = GetDeviceCaps (hdc, VERTRES); ReleaseDC(hwndChild, hdc); xNew = rParent.left + ((wParent - wChild) /2); if (xNew < 0) { xNew = 0; } else if ((xNew+wChild) > wScreen) { xNew = wScreen - wChild; } yNew = rParent.top + ((hParent - hChild) /2); if (yNew < 0) yNew = 0; else if ((yNew+hChild) > hScreen) yNew = hScreen - hChild; return SetWindowPos(hwndChild, NULL, xNew, yNew, 0, 0, SWP_NOSIZE | SWP_NOZORDER); } #endif /* FEAT_GUI_DIALOG */ void gui_mch_activate_window(void) { (void)SetActiveWindow(s_hwnd); } #if defined(FEAT_TOOLBAR) || defined(PROTO) void gui_mch_show_toolbar(int showit) { if (s_toolbarhwnd == NULL) return; if (showit) { # ifdef FEAT_MBYTE # ifndef TB_SETUNICODEFORMAT /* For older compilers. We assume this never changes. */ # define TB_SETUNICODEFORMAT 0x2005 # endif /* Enable/disable unicode support */ int uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage); SendMessage(s_toolbarhwnd, TB_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0); # endif ShowWindow(s_toolbarhwnd, SW_SHOW); } else ShowWindow(s_toolbarhwnd, SW_HIDE); } /* Then number of bitmaps is fixed. Exit is missing! */ #define TOOLBAR_BITMAP_COUNT 31 #endif #if defined(FEAT_GUI_TABLINE) || defined(PROTO) static void add_tabline_popup_menu_entry(HMENU pmenu, UINT item_id, char_u *item_text) { #ifdef FEAT_MBYTE WCHAR *wn = NULL; int n; if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) { /* 'encoding' differs from active codepage: convert menu name * and use wide function */ wn = enc_to_utf16(item_text, NULL); if (wn != NULL) { MENUITEMINFOW infow; infow.cbSize = sizeof(infow); infow.fMask = MIIM_TYPE | MIIM_ID; infow.wID = item_id; infow.fType = MFT_STRING; infow.dwTypeData = wn; infow.cch = (UINT)wcslen(wn); n = InsertMenuItemW(pmenu, item_id, FALSE, &infow); vim_free(wn); if (n == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED) /* Failed, try using non-wide function. */ wn = NULL; } } if (wn == NULL) #endif { MENUITEMINFO info; info.cbSize = sizeof(info); info.fMask = MIIM_TYPE | MIIM_ID; info.wID = item_id; info.fType = MFT_STRING; info.dwTypeData = item_text; info.cch = (UINT)STRLEN(item_text); InsertMenuItem(pmenu, item_id, FALSE, &info); } } static void show_tabline_popup_menu(void) { HMENU tab_pmenu; long rval; POINT pt; /* When ignoring events don't show the menu. */ if (hold_gui_events # ifdef FEAT_CMDWIN || cmdwin_type != 0 # endif ) return; tab_pmenu = CreatePopupMenu(); if (tab_pmenu == NULL) return; add_tabline_popup_menu_entry(tab_pmenu, TABLINE_MENU_CLOSE, _("Close tab")); add_tabline_popup_menu_entry(tab_pmenu, TABLINE_MENU_NEW, _("New tab")); add_tabline_popup_menu_entry(tab_pmenu, TABLINE_MENU_OPEN, _("Open tab...")); GetCursorPos(&pt); rval = TrackPopupMenuEx(tab_pmenu, TPM_RETURNCMD, pt.x, pt.y, s_tabhwnd, NULL); DestroyMenu(tab_pmenu); /* Add the string cmd into input buffer */ if (rval > 0) { TCHITTESTINFO htinfo; int idx; if (ScreenToClient(s_tabhwnd, &pt) == 0) return; htinfo.pt.x = pt.x; htinfo.pt.y = pt.y; idx = TabCtrl_HitTest(s_tabhwnd, &htinfo); if (idx == -1) idx = 0; else idx += 1; send_tabline_menu_event(idx, (int)rval); } } /* * Show or hide the tabline. */ void gui_mch_show_tabline(int showit) { if (s_tabhwnd == NULL) return; if (!showit != !showing_tabline) { if (showit) ShowWindow(s_tabhwnd, SW_SHOW); else ShowWindow(s_tabhwnd, SW_HIDE); showing_tabline = showit; } } /* * Return TRUE when tabline is displayed. */ int gui_mch_showing_tabline(void) { return s_tabhwnd != NULL && showing_tabline; } /* * Update the labels of the tabline. */ void gui_mch_update_tabline(void) { tabpage_T *tp; TCITEM tie; int nr = 0; int curtabidx = 0; RECT rc; #ifdef FEAT_MBYTE static int use_unicode = FALSE; int uu; WCHAR *wstr = NULL; #endif if (s_tabhwnd == NULL) return; #if defined(FEAT_MBYTE) # ifndef CCM_SETUNICODEFORMAT /* For older compilers. We assume this never changes. */ # define CCM_SETUNICODEFORMAT 0x2005 # endif uu = (enc_codepage >= 0 && (int)GetACP() != enc_codepage); if (uu != use_unicode) { /* Enable/disable unicode support */ SendMessage(s_tabhwnd, CCM_SETUNICODEFORMAT, (WPARAM)uu, (LPARAM)0); use_unicode = uu; } #endif tie.mask = TCIF_TEXT; tie.iImage = -1; /* Add a label for each tab page. They all contain the same text area. */ for (tp = first_tabpage; tp != NULL; tp = tp->tp_next, ++nr) { if (tp == curtab) curtabidx = nr; if (!TabCtrl_GetItemRect(s_tabhwnd, nr, &rc)) { /* Add the tab */ tie.pszText = "-Empty-"; TabCtrl_InsertItem(s_tabhwnd, nr, &tie); } get_tabline_label(tp, FALSE); tie.pszText = NameBuff; #ifdef FEAT_MBYTE wstr = NULL; if (use_unicode) { /* Need to go through Unicode. */ wstr = enc_to_utf16(NameBuff, NULL); if (wstr != NULL) { TCITEMW tiw; tiw.mask = TCIF_TEXT; tiw.iImage = -1; tiw.pszText = wstr; SendMessage(s_tabhwnd, TCM_SETITEMW, (WPARAM)nr, (LPARAM)&tiw); vim_free(wstr); } } if (wstr == NULL) #endif { TabCtrl_SetItem(s_tabhwnd, nr, &tie); } } /* Remove any old labels. */ while (TabCtrl_GetItemRect(s_tabhwnd, nr, &rc)) TabCtrl_DeleteItem(s_tabhwnd, nr); if (TabCtrl_GetCurSel(s_tabhwnd) != curtabidx) TabCtrl_SetCurSel(s_tabhwnd, curtabidx); } /* * Set the current tab to "nr". First tab is 1. */ void gui_mch_set_curtab(nr) int nr; { if (s_tabhwnd == NULL) return; if (TabCtrl_GetCurSel(s_tabhwnd) != nr -1) TabCtrl_SetCurSel(s_tabhwnd, nr -1); } #endif /* * ":simalt" command. */ void ex_simalt(exarg_T *eap) { char_u *keys = eap->arg; PostMessage(s_hwnd, WM_SYSCOMMAND, (WPARAM)SC_KEYMENU, (LPARAM)0); while (*keys) { if (*keys == '~') *keys = ' '; /* for showing system menu */ PostMessage(s_hwnd, WM_CHAR, (WPARAM)*keys, (LPARAM)0); keys++; } } /* * Create the find & replace dialogs. * You can't have both at once: ":find" when replace is showing, destroys * the replace dialog first, and the other way around. */ #ifdef MSWIN_FIND_REPLACE static void initialise_findrep(char_u *initial_string) { int wword = FALSE; int mcase = !p_ic; char_u *entry_text; /* Get the search string to use. */ entry_text = get_find_dialog_text(initial_string, &wword, &mcase); s_findrep_struct.hwndOwner = s_hwnd; s_findrep_struct.Flags = FR_DOWN; if (mcase) s_findrep_struct.Flags |= FR_MATCHCASE; if (wword) s_findrep_struct.Flags |= FR_WHOLEWORD; if (entry_text != NULL && *entry_text != NUL) vim_strncpy(s_findrep_struct.lpstrFindWhat, entry_text, s_findrep_struct.wFindWhatLen - 1); vim_free(entry_text); } #endif static void set_window_title(HWND hwnd, char *title) { #ifdef FEAT_MBYTE if (title != NULL && enc_codepage >= 0 && enc_codepage != (int)GetACP()) { WCHAR *wbuf; int n; /* Convert the title from 'encoding' to UTF-16. */ wbuf = (WCHAR *)enc_to_utf16((char_u *)title, NULL); if (wbuf != NULL) { n = SetWindowTextW(hwnd, wbuf); vim_free(wbuf); if (n != 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) return; /* Retry with non-wide function (for Windows 98). */ } } #endif (void)SetWindowText(hwnd, (LPCSTR)title); } void gui_mch_find_dialog(exarg_T *eap) { #ifdef MSWIN_FIND_REPLACE if (s_findrep_msg != 0) { if (IsWindow(s_findrep_hwnd) && !s_findrep_is_find) DestroyWindow(s_findrep_hwnd); if (!IsWindow(s_findrep_hwnd)) { initialise_findrep(eap->arg); # if defined(FEAT_MBYTE) && defined(WIN3264) /* If the OS is Windows NT, and 'encoding' differs from active * codepage: convert text and use wide function. */ if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT && enc_codepage >= 0 && (int)GetACP() != enc_codepage) { findrep_atow(&s_findrep_struct_w, &s_findrep_struct); s_findrep_hwnd = FindTextW( (LPFINDREPLACEW) &s_findrep_struct_w); } else # endif s_findrep_hwnd = FindText((LPFINDREPLACE) &s_findrep_struct); } set_window_title(s_findrep_hwnd, _("Find string (use '\\\\' to find a '\\')")); (void)SetFocus(s_findrep_hwnd); s_findrep_is_find = TRUE; } #endif } void gui_mch_replace_dialog(exarg_T *eap) { #ifdef MSWIN_FIND_REPLACE if (s_findrep_msg != 0) { if (IsWindow(s_findrep_hwnd) && s_findrep_is_find) DestroyWindow(s_findrep_hwnd); if (!IsWindow(s_findrep_hwnd)) { initialise_findrep(eap->arg); # if defined(FEAT_MBYTE) && defined(WIN3264) if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT && enc_codepage >= 0 && (int)GetACP() != enc_codepage) { findrep_atow(&s_findrep_struct_w, &s_findrep_struct); s_findrep_hwnd = ReplaceTextW( (LPFINDREPLACEW) &s_findrep_struct_w); } else # endif s_findrep_hwnd = ReplaceText( (LPFINDREPLACE) &s_findrep_struct); } set_window_title(s_findrep_hwnd, _("Find & Replace (use '\\\\' to find a '\\')")); (void)SetFocus(s_findrep_hwnd); s_findrep_is_find = FALSE; } #endif } /* * Set visibility of the pointer. */ void gui_mch_mousehide(int hide) { if (hide != gui.pointer_hidden) { ShowCursor(!hide); gui.pointer_hidden = hide; } } #ifdef FEAT_MENU static void gui_mch_show_popupmenu_at(vimmenu_T *menu, int x, int y) { /* Unhide the mouse, we don't get move events here. */ gui_mch_mousehide(FALSE); (void)TrackPopupMenu( (HMENU)menu->submenu_id, TPM_LEFTALIGN | TPM_LEFTBUTTON, x, y, (int)0, /*reserved param*/ s_hwnd, NULL); /* * NOTE: The pop-up menu can eat the mouse up event. * We deal with this in normal.c. */ } #endif /* * Got a message when the system will go down. */ static void _OnEndSession(void) { getout_preserve_modified(1); } /* * Get this message when the user clicks on the cross in the top right corner * of a Windows95 window. */ /*ARGSUSED*/ static void _OnClose( HWND hwnd) { gui_shell_closed(); } /* * Get a message when the window is being destroyed. */ static void _OnDestroy( HWND hwnd) { #ifdef WIN16_3DLOOK Ctl3dUnregister(s_hinst); #endif if (!destroying) _OnClose(hwnd); } static void _OnPaint( HWND hwnd) { if (!IsMinimized(hwnd)) { PAINTSTRUCT ps; out_flush(); /* make sure all output has been processed */ (void)BeginPaint(hwnd, &ps); #ifdef FEAT_MBYTE /* prevent multi-byte characters from misprinting on an invalid * rectangle */ if (has_mbyte) { RECT rect; GetClientRect(hwnd, &rect); ps.rcPaint.left = rect.left; ps.rcPaint.right = rect.right; } #endif if (!IsRectEmpty(&ps.rcPaint)) gui_redraw(ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left + 1, ps.rcPaint.bottom - ps.rcPaint.top + 1); EndPaint(hwnd, &ps); } } /*ARGSUSED*/ static void _OnSize( HWND hwnd, UINT state, int cx, int cy) { if (!IsMinimized(hwnd)) { gui_resize_shell(cx, cy); #ifdef FEAT_MENU /* Menu bar may wrap differently now */ gui_mswin_get_menu_height(TRUE); #endif } } static void _OnSetFocus( HWND hwnd, HWND hwndOldFocus) { gui_focus_change(TRUE); s_getting_focus = TRUE; (void)MyWindowProc(hwnd, WM_SETFOCUS, (WPARAM)hwndOldFocus, 0); } static void _OnKillFocus( HWND hwnd, HWND hwndNewFocus) { gui_focus_change(FALSE); s_getting_focus = FALSE; (void)MyWindowProc(hwnd, WM_KILLFOCUS, (WPARAM)hwndNewFocus, 0); } /* * Get a message when the user switches back to vim */ #ifdef WIN16 static BOOL #else static LRESULT #endif _OnActivateApp( HWND hwnd, BOOL fActivate, #ifdef WIN16 HTASK dwThreadId #else DWORD dwThreadId #endif ) { /* we call gui_focus_change() in _OnSetFocus() */ /* gui_focus_change((int)fActivate); */ return MyWindowProc(hwnd, WM_ACTIVATEAPP, fActivate, (DWORD)dwThreadId); } #if defined(FEAT_WINDOWS) || defined(PROTO) void gui_mch_destroy_scrollbar(scrollbar_T *sb) { DestroyWindow(sb->id); } #endif /* * Get current mouse coordinates in text window. */ void gui_mch_getmouse(int *x, int *y) { RECT rct; POINT mp; (void)GetWindowRect(s_textArea, &rct); (void)GetCursorPos((LPPOINT)&mp); *x = (int)(mp.x - rct.left); *y = (int)(mp.y - rct.top); } /* * Move mouse pointer to character at (x, y). */ void gui_mch_setmouse(int x, int y) { RECT rct; (void)GetWindowRect(s_textArea, &rct); (void)SetCursorPos(x + gui.border_offset + rct.left, y + gui.border_offset + rct.top); } static void gui_mswin_get_valid_dimensions( int w, int h, int *valid_w, int *valid_h) { int base_width, base_height; base_width = gui_get_base_width() + GetSystemMetrics(SM_CXFRAME) * 2; base_height = gui_get_base_height() + GetSystemMetrics(SM_CYFRAME) * 2 + GetSystemMetrics(SM_CYCAPTION) #ifdef FEAT_MENU + gui_mswin_get_menu_height(FALSE) #endif ; *valid_w = base_width + ((w - base_width) / gui.char_width) * gui.char_width; *valid_h = base_height + ((h - base_height) / gui.char_height) * gui.char_height; } void gui_mch_flash(int msec) { RECT rc; /* * Note: InvertRect() excludes right and bottom of rectangle. */ rc.left = 0; rc.top = 0; rc.right = gui.num_cols * gui.char_width; rc.bottom = gui.num_rows * gui.char_height; InvertRect(s_hdc, &rc); gui_mch_flush(); /* make sure it's displayed */ ui_delay((long)msec, TRUE); /* wait for a few msec */ InvertRect(s_hdc, &rc); } /* * Return flags used for scrolling. * The SW_INVALIDATE is required when part of the window is covered or * off-screen. Refer to MS KB Q75236. */ static int get_scroll_flags(void) { HWND hwnd; RECT rcVim, rcOther, rcDest; GetWindowRect(s_hwnd, &rcVim); /* Check if the window is partly above or below the screen. We don't care * about partly left or right of the screen, it is not relevant when * scrolling up or down. */ if (rcVim.top < 0 || rcVim.bottom > GetSystemMetrics(SM_CYFULLSCREEN)) return SW_INVALIDATE; /* Check if there is an window (partly) on top of us. */ for (hwnd = s_hwnd; (hwnd = GetWindow(hwnd, GW_HWNDPREV)) != (HWND)0; ) if (IsWindowVisible(hwnd)) { GetWindowRect(hwnd, &rcOther); if (IntersectRect(&rcDest, &rcVim, &rcOther)) return SW_INVALIDATE; } return 0; } /* * Delete the given number of lines from the given row, scrolling up any * text further down within the scroll region. */ void gui_mch_delete_lines( int row, int num_lines) { RECT rc; rc.left = FILL_X(gui.scroll_region_left); rc.right = FILL_X(gui.scroll_region_right + 1); rc.top = FILL_Y(row); rc.bottom = FILL_Y(gui.scroll_region_bot + 1); ScrollWindowEx(s_textArea, 0, -num_lines * gui.char_height, &rc, &rc, NULL, NULL, get_scroll_flags()); UpdateWindow(s_textArea); /* This seems to be required to avoid the cursor disappearing when * scrolling such that the cursor ends up in the top-left character on * the screen... But why? (Webb) */ /* It's probably fixed by disabling drawing the cursor while scrolling. */ /* gui.cursor_is_valid = FALSE; */ gui_clear_block(gui.scroll_region_bot - num_lines + 1, gui.scroll_region_left, gui.scroll_region_bot, gui.scroll_region_right); } /* * Insert the given number of lines before the given row, scrolling down any * following text within the scroll region. */ void gui_mch_insert_lines( int row, int num_lines) { RECT rc; rc.left = FILL_X(gui.scroll_region_left); rc.right = FILL_X(gui.scroll_region_right + 1); rc.top = FILL_Y(row); rc.bottom = FILL_Y(gui.scroll_region_bot + 1); /* The SW_INVALIDATE is required when part of the window is covered or * off-screen. How do we avoid it when it's not needed? */ ScrollWindowEx(s_textArea, 0, num_lines * gui.char_height, &rc, &rc, NULL, NULL, get_scroll_flags()); UpdateWindow(s_textArea); gui_clear_block(row, gui.scroll_region_left, row + num_lines - 1, gui.scroll_region_right); } /*ARGSUSED*/ void gui_mch_exit(int rc) { ReleaseDC(s_textArea, s_hdc); DeleteObject(s_brush); #ifdef FEAT_TEAROFF /* Unload the tearoff bitmap */ (void)DeleteObject((HGDIOBJ)s_htearbitmap); #endif /* Destroy our window (if we have one). */ if (s_hwnd != NULL) { destroying = TRUE; /* ignore WM_DESTROY message now */ DestroyWindow(s_hwnd); } #ifdef GLOBAL_IME global_ime_end(); #endif } static char_u * logfont2name(LOGFONT lf) { char *p; char *res; char *charset_name; charset_name = charset_id2name((int)lf.lfCharSet); res = alloc((unsigned)(strlen(lf.lfFaceName) + 20 + (charset_name == NULL ? 0 : strlen(charset_name) + 2))); if (res != NULL) { p = res; /* make a normal font string out of the lf thing:*/ sprintf((char *)p, "%s:h%d", lf.lfFaceName, pixels_to_points( lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, TRUE)); while (*p) { if (*p == ' ') *p = '_'; ++p; } #ifndef MSWIN16_FASTTEXT if (lf.lfItalic) STRCAT(p, ":i"); if (lf.lfWeight >= FW_BOLD) STRCAT(p, ":b"); #endif if (lf.lfUnderline) STRCAT(p, ":u"); if (lf.lfStrikeOut) STRCAT(p, ":s"); if (charset_name != NULL) { STRCAT(p, ":c"); STRCAT(p, charset_name); } } return res; } /* * Initialise vim to use the font with the given name. * Return FAIL if the font could not be loaded, OK otherwise. */ /*ARGSUSED*/ int gui_mch_init_font(char_u *font_name, int fontset) { LOGFONT lf; GuiFont font = NOFONT; char_u *p; /* Load the font */ if (get_logfont(&lf, font_name, NULL, TRUE) == OK) font = get_font_handle(&lf); if (font == NOFONT) return FAIL; if (font_name == NULL) font_name = lf.lfFaceName; #if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME) norm_logfont = lf; #endif #ifdef FEAT_MBYTE_IME im_set_font(&lf); #endif gui_mch_free_font(gui.norm_font); gui.norm_font = font; current_font_height = lf.lfHeight; GetFontSize(font); p = logfont2name(lf); if (p != NULL) { hl_set_font_name(p); /* When setting 'guifont' to "*" replace it with the actual font name. * */ if (STRCMP(font_name, "*") == 0 && STRCMP(p_guifont, "*") == 0) { vim_free(p_guifont); p_guifont = p; } else vim_free(p); } #ifndef MSWIN16_FASTTEXT gui_mch_free_font(gui.ital_font); gui.ital_font = NOFONT; gui_mch_free_font(gui.bold_font); gui.bold_font = NOFONT; gui_mch_free_font(gui.boldital_font); gui.boldital_font = NOFONT; if (!lf.lfItalic) { lf.lfItalic = TRUE; gui.ital_font = get_font_handle(&lf); lf.lfItalic = FALSE; } if (lf.lfWeight < FW_BOLD) { lf.lfWeight = FW_BOLD; gui.bold_font = get_font_handle(&lf); if (!lf.lfItalic) { lf.lfItalic = TRUE; gui.boldital_font = get_font_handle(&lf); } } #endif return OK; } #ifndef WPF_RESTORETOMAXIMIZED # define WPF_RESTORETOMAXIMIZED 2 /* just in case someone doesn't have it */ #endif /* * Return TRUE if the GUI window is maximized, filling the whole screen. */ int gui_mch_maximized() { WINDOWPLACEMENT wp; wp.length = sizeof(WINDOWPLACEMENT); if (GetWindowPlacement(s_hwnd, &wp)) return wp.showCmd == SW_SHOWMAXIMIZED || (wp.showCmd == SW_SHOWMINIMIZED && wp.flags == WPF_RESTORETOMAXIMIZED); return 0; } /* * Called when the font changed while the window is maximized. Compute the * new Rows and Columns. This is like resizing the window. */ void gui_mch_newfont() { RECT rect; GetWindowRect(s_hwnd, &rect); gui_resize_shell(rect.right - rect.left - GetSystemMetrics(SM_CXFRAME) * 2, rect.bottom - rect.top - GetSystemMetrics(SM_CYFRAME) * 2 - GetSystemMetrics(SM_CYCAPTION) #ifdef FEAT_MENU - gui_mswin_get_menu_height(FALSE) #endif ); } /* * Set the window title */ /*ARGSUSED*/ void gui_mch_settitle( char_u *title, char_u *icon) { set_window_title(s_hwnd, (title == NULL ? "VIM" : (char *)title)); } #ifdef FEAT_MOUSESHAPE /* Table for shape IDCs. Keep in sync with the mshape_names[] table in * misc2.c! */ static LPCSTR mshape_idcs[] = { MAKEINTRESOURCE(IDC_ARROW), /* arrow */ MAKEINTRESOURCE(0), /* blank */ MAKEINTRESOURCE(IDC_IBEAM), /* beam */ MAKEINTRESOURCE(IDC_SIZENS), /* updown */ MAKEINTRESOURCE(IDC_SIZENS), /* udsizing */ MAKEINTRESOURCE(IDC_SIZEWE), /* leftright */ MAKEINTRESOURCE(IDC_SIZEWE), /* lrsizing */ MAKEINTRESOURCE(IDC_WAIT), /* busy */ #ifdef WIN3264 MAKEINTRESOURCE(IDC_NO), /* no */ #else MAKEINTRESOURCE(IDC_ICON), /* no */ #endif MAKEINTRESOURCE(IDC_ARROW), /* crosshair */ MAKEINTRESOURCE(IDC_ARROW), /* hand1 */ MAKEINTRESOURCE(IDC_ARROW), /* hand2 */ MAKEINTRESOURCE(IDC_ARROW), /* pencil */ MAKEINTRESOURCE(IDC_ARROW), /* question */ MAKEINTRESOURCE(IDC_ARROW), /* right-arrow */ MAKEINTRESOURCE(IDC_UPARROW), /* up-arrow */ MAKEINTRESOURCE(IDC_ARROW) /* last one */ }; void mch_set_mouse_shape(int shape) { LPCSTR idc; if (shape == MSHAPE_HIDE) ShowCursor(FALSE); else { if (shape >= MSHAPE_NUMBERED) idc = MAKEINTRESOURCE(IDC_ARROW); else idc = mshape_idcs[shape]; #ifdef SetClassLongPtr SetClassLongPtr(s_textArea, GCLP_HCURSOR, (__int3264)(LONG_PTR)LoadCursor(NULL, idc)); #else # ifdef WIN32 SetClassLong(s_textArea, GCL_HCURSOR, (long_u)LoadCursor(NULL, idc)); # else /* Win16 */ SetClassWord(s_textArea, GCW_HCURSOR, (WORD)LoadCursor(NULL, idc)); # endif #endif if (!p_mh) { POINT mp; /* Set the position to make it redrawn with the new shape. */ (void)GetCursorPos((LPPOINT)&mp); (void)SetCursorPos(mp.x, mp.y); ShowCursor(TRUE); } } } #endif #ifdef FEAT_BROWSE /* * The file browser exists in two versions: with "W" uses wide characters, * without "W" the current codepage. When FEAT_MBYTE is defined and on * Windows NT/2000/XP the "W" functions are used. */ # if defined(FEAT_MBYTE) && defined(WIN3264) /* * Wide version of convert_filter(). Keep in sync! */ static WCHAR * convert_filterW(char_u *s) { WCHAR *res; unsigned s_len = (unsigned)STRLEN(s); unsigned i; res = (WCHAR *)alloc((s_len + 3) * sizeof(WCHAR)); if (res != NULL) { for (i = 0; i < s_len; ++i) if (s[i] == '\t' || s[i] == '\n') res[i] = '\0'; else res[i] = s[i]; res[s_len] = NUL; /* Add two extra NULs to make sure it's properly terminated. */ res[s_len + 1] = NUL; res[s_len + 2] = NUL; } return res; } /* * Wide version of gui_mch_browse(). Keep in sync! */ static char_u * gui_mch_browseW( int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter) { /* We always use the wide function. This means enc_to_utf16() must work, * otherwise it fails miserably! */ OPENFILENAMEW fileStruct; WCHAR fileBuf[MAXPATHL]; WCHAR *wp; int i; WCHAR *titlep = NULL; WCHAR *extp = NULL; WCHAR *initdirp = NULL; WCHAR *filterp; char_u *p; if (dflt == NULL) fileBuf[0] = NUL; else { wp = enc_to_utf16(dflt, NULL); if (wp == NULL) fileBuf[0] = NUL; else { for (i = 0; wp[i] != NUL && i < MAXPATHL - 1; ++i) fileBuf[i] = wp[i]; fileBuf[i] = NUL; vim_free(wp); } } /* Convert the filter to Windows format. */ filterp = convert_filterW(filter); vim_memset(&fileStruct, 0, sizeof(OPENFILENAMEW)); #ifdef OPENFILENAME_SIZE_VERSION_400 /* be compatible with Windows NT 4.0 */ /* TODO: what to use for OPENFILENAMEW??? */ fileStruct.lStructSize = OPENFILENAME_SIZE_VERSION_400; #else fileStruct.lStructSize = sizeof(fileStruct); #endif if (title != NULL) titlep = enc_to_utf16(title, NULL); fileStruct.lpstrTitle = titlep; if (ext != NULL) extp = enc_to_utf16(ext, NULL); fileStruct.lpstrDefExt = extp; fileStruct.lpstrFile = fileBuf; fileStruct.nMaxFile = MAXPATHL; fileStruct.lpstrFilter = filterp; fileStruct.hwndOwner = s_hwnd; /* main Vim window is owner*/ /* has an initial dir been specified? */ if (initdir != NULL && *initdir != NUL) { /* Must have backslashes here, no matter what 'shellslash' says */ initdirp = enc_to_utf16(initdir, NULL); if (initdirp != NULL) { for (wp = initdirp; *wp != NUL; ++wp) if (*wp == '/') *wp = '\\'; } fileStruct.lpstrInitialDir = initdirp; } /* * TODO: Allow selection of multiple files. Needs another arg to this * function to ask for it, and need to use OFN_ALLOWMULTISELECT below. * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on * files that don't exist yet, so I haven't put it in. What about * OFN_PATHMUSTEXIST? * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog. */ fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY); #ifdef FEAT_SHORTCUT if (curbuf->b_p_bin) fileStruct.Flags |= OFN_NODEREFERENCELINKS; #endif if (saving) { if (!GetSaveFileNameW(&fileStruct)) return NULL; } else { if (!GetOpenFileNameW(&fileStruct)) return NULL; } vim_free(filterp); vim_free(initdirp); vim_free(titlep); vim_free(extp); /* Convert from UCS2 to 'encoding'. */ p = utf16_to_enc(fileBuf, NULL); if (p != NULL) /* when out of memory we get garbage for non-ASCII chars */ STRCPY(fileBuf, p); vim_free(p); /* Give focus back to main window (when using MDI). */ SetFocus(s_hwnd); /* Shorten the file name if possible */ return vim_strsave(shorten_fname1((char_u *)fileBuf)); } # endif /* FEAT_MBYTE */ /* * Convert the string s to the proper format for a filter string by replacing * the \t and \n delimiters with \0. * Returns the converted string in allocated memory. * * Keep in sync with convert_filterW() above! */ static char_u * convert_filter(char_u *s) { char_u *res; unsigned s_len = (unsigned)STRLEN(s); unsigned i; res = alloc(s_len + 3); if (res != NULL) { for (i = 0; i < s_len; ++i) if (s[i] == '\t' || s[i] == '\n') res[i] = '\0'; else res[i] = s[i]; res[s_len] = NUL; /* Add two extra NULs to make sure it's properly terminated. */ res[s_len + 1] = NUL; res[s_len + 2] = NUL; } return res; } /* * Select a directory. */ char_u * gui_mch_browsedir(char_u *title, char_u *initdir) { /* We fake this: Use a filter that doesn't select anything and a default * file name that won't be used. */ return gui_mch_browse(0, title, (char_u *)_("Not Used"), NULL, initdir, (char_u *)_("Directory\t*.nothing\n")); } /* * Pop open a file browser and return the file selected, in allocated memory, * or NULL if Cancel is hit. * saving - TRUE if the file will be saved to, FALSE if it will be opened. * title - Title message for the file browser dialog. * dflt - Default name of file. * ext - Default extension to be added to files without extensions. * initdir - directory in which to open the browser (NULL = current dir) * filter - Filter for matched files to choose from. * * Keep in sync with gui_mch_browseW() above! */ char_u * gui_mch_browse( int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter) { OPENFILENAME fileStruct; char_u fileBuf[MAXPATHL]; char_u *initdirp = NULL; char_u *filterp; char_u *p; # if defined(FEAT_MBYTE) && defined(WIN3264) if (os_version.dwPlatformId == VER_PLATFORM_WIN32_NT) return gui_mch_browseW(saving, title, dflt, ext, initdir, filter); # endif if (dflt == NULL) fileBuf[0] = NUL; else vim_strncpy(fileBuf, dflt, MAXPATHL - 1); /* Convert the filter to Windows format. */ filterp = convert_filter(filter); vim_memset(&fileStruct, 0, sizeof(OPENFILENAME)); #ifdef OPENFILENAME_SIZE_VERSION_400 /* be compatible with Windows NT 4.0 */ fileStruct.lStructSize = OPENFILENAME_SIZE_VERSION_400; #else fileStruct.lStructSize = sizeof(fileStruct); #endif fileStruct.lpstrTitle = title; fileStruct.lpstrDefExt = ext; fileStruct.lpstrFile = fileBuf; fileStruct.nMaxFile = MAXPATHL; fileStruct.lpstrFilter = filterp; fileStruct.hwndOwner = s_hwnd; /* main Vim window is owner*/ /* has an initial dir been specified? */ if (initdir != NULL && *initdir != NUL) { /* Must have backslashes here, no matter what 'shellslash' says */ initdirp = vim_strsave(initdir); if (initdirp != NULL) for (p = initdirp; *p != NUL; ++p) if (*p == '/') *p = '\\'; fileStruct.lpstrInitialDir = initdirp; } /* * TODO: Allow selection of multiple files. Needs another arg to this * function to ask for it, and need to use OFN_ALLOWMULTISELECT below. * Also, should we use OFN_FILEMUSTEXIST when opening? Vim can edit on * files that don't exist yet, so I haven't put it in. What about * OFN_PATHMUSTEXIST? * Don't use OFN_OVERWRITEPROMPT, Vim has its own ":confirm" dialog. */ fileStruct.Flags = (OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY); #ifdef FEAT_SHORTCUT if (curbuf->b_p_bin) fileStruct.Flags |= OFN_NODEREFERENCELINKS; #endif if (saving) { if (!GetSaveFileName(&fileStruct)) return NULL; } else { if (!GetOpenFileName(&fileStruct)) return NULL; } vim_free(filterp); vim_free(initdirp); /* Give focus back to main window (when using MDI). */ SetFocus(s_hwnd); /* Shorten the file name if possible */ return vim_strsave(shorten_fname1((char_u *)fileBuf)); } #endif /* FEAT_BROWSE */ /*ARGSUSED*/ static void _OnDropFiles( HWND hwnd, HDROP hDrop) { #ifdef FEAT_WINDOWS #ifdef WIN3264 # define BUFPATHLEN _MAX_PATH # define DRAGQVAL 0xFFFFFFFF #else # define BUFPATHLEN MAXPATHL # define DRAGQVAL 0xFFFF #endif #ifdef FEAT_MBYTE WCHAR wszFile[BUFPATHLEN]; #endif char szFile[BUFPATHLEN]; UINT cFiles = DragQueryFile(hDrop, DRAGQVAL, NULL, 0); UINT i; char_u **fnames; POINT pt; int_u modifiers = 0; /* TRACE("_OnDropFiles: %d files dropped\n", cFiles); */ /* Obtain dropped position */ DragQueryPoint(hDrop, &pt); MapWindowPoints(s_hwnd, s_textArea, &pt, 1); # ifdef FEAT_VISUAL reset_VIsual(); # endif fnames = (char_u **)alloc(cFiles * sizeof(char_u *)); if (fnames != NULL) for (i = 0; i < cFiles; ++i) { #ifdef FEAT_MBYTE if (DragQueryFileW(hDrop, i, wszFile, BUFPATHLEN) > 0) fnames[i] = utf16_to_enc(wszFile, NULL); else #endif { DragQueryFile(hDrop, i, szFile, BUFPATHLEN); fnames[i] = vim_strsave(szFile); } } DragFinish(hDrop); if (fnames != NULL) { if ((GetKeyState(VK_SHIFT) & 0x8000) != 0) modifiers |= MOUSE_SHIFT; if ((GetKeyState(VK_CONTROL) & 0x8000) != 0) modifiers |= MOUSE_CTRL; if ((GetKeyState(VK_MENU) & 0x8000) != 0) modifiers |= MOUSE_ALT; gui_handle_drop(pt.x, pt.y, modifiers, fnames, cFiles); s_need_activate = TRUE; } #endif } /*ARGSUSED*/ static int _OnScroll( HWND hwnd, HWND hwndCtl, UINT code, int pos) { static UINT prev_code = 0; /* code of previous call */ scrollbar_T *sb, *sb_info; long val; int dragging = FALSE; int dont_scroll_save = dont_scroll; #ifndef WIN3264 int nPos; #else SCROLLINFO si; si.cbSize = sizeof(si); si.fMask = SIF_POS; #endif sb = gui_mswin_find_scrollbar(hwndCtl); if (sb == NULL) return 0; if (sb->wp != NULL) /* Left or right scrollbar */ { /* * Careful: need to get scrollbar info out of first (left) scrollbar * for window, but keep real scrollbar too because we must pass it to * gui_drag_scrollbar(). */ sb_info = &sb->wp->w_scrollbars[0]; } else /* Bottom scrollbar */ sb_info = sb; val = sb_info->value; switch (code) { case SB_THUMBTRACK: val = pos; dragging = TRUE; if (sb->scroll_shift > 0) val <<= sb->scroll_shift; break; case SB_LINEDOWN: val++; break; case SB_LINEUP: val--; break; case SB_PAGEDOWN: val += (sb_info->size > 2 ? sb_info->size - 2 : 1); break; case SB_PAGEUP: val -= (sb_info->size > 2 ? sb_info->size - 2 : 1); break; case SB_TOP: val = 0; break; case SB_BOTTOM: val = sb_info->max; break; case SB_ENDSCROLL: if (prev_code == SB_THUMBTRACK) { /* * "pos" only gives us 16-bit data. In case of large file, * use GetScrollPos() which returns 32-bit. Unfortunately it * is not valid while the scrollbar is being dragged. */ val = GetScrollPos(hwndCtl, SB_CTL); if (sb->scroll_shift > 0) val <<= sb->scroll_shift; } break; default: /* TRACE("Unknown scrollbar event %d\n", code); */ return 0; } prev_code = code; #ifdef WIN3264 si.nPos = (sb->scroll_shift > 0) ? val >> sb->scroll_shift : val; SetScrollInfo(hwndCtl, SB_CTL, &si, TRUE); #else nPos = (sb->scroll_shift > 0) ? val >> sb->scroll_shift : val; SetScrollPos(hwndCtl, SB_CTL, nPos, TRUE); #endif /* * When moving a vertical scrollbar, move the other vertical scrollbar too. */ if (sb->wp != NULL) { scrollbar_T *sba = sb->wp->w_scrollbars; HWND id = sba[ (sb == sba + SBAR_LEFT) ? SBAR_RIGHT : SBAR_LEFT].id; #ifdef WIN3264 SetScrollInfo(id, SB_CTL, &si, TRUE); #else SetScrollPos(id, SB_CTL, nPos, TRUE); #endif } /* Don't let us be interrupted here by another message. */ s_busy_processing = TRUE; /* When "allow_scrollbar" is FALSE still need to remember the new * position, but don't actually scroll by setting "dont_scroll". */ dont_scroll = !allow_scrollbar; gui_drag_scrollbar(sb, val, dragging); s_busy_processing = FALSE; dont_scroll = dont_scroll_save; return 0; } /* * Get command line arguments. * Use "prog" as the name of the program and "cmdline" as the arguments. * Copy the arguments to allocated memory. * Return the number of arguments (including program name). * Return pointers to the arguments in "argvp". Memory is allocated with * malloc(), use free() instead of vim_free(). * Return pointer to buffer in "tofree". * Returns zero when out of memory. */ /*ARGSUSED*/ int get_cmd_args(char *prog, char *cmdline, char ***argvp, char **tofree) { int i; char *p; char *progp; char *pnew = NULL; char *newcmdline; int inquote; int argc; char **argv = NULL; int round; *tofree = NULL; #ifdef FEAT_MBYTE /* Try using the Unicode version first, it takes care of conversion when * 'encoding' is changed. */ argc = get_cmd_argsW(&argv); if (argc != 0) goto done; #endif /* Handle the program name. Remove the ".exe" extension, and find the 1st * non-space. */ p = strrchr(prog, '.'); if (p != NULL) *p = NUL; for (progp = prog; *progp == ' '; ++progp) ; /* The command line is copied to allocated memory, so that we can change * it. Add the size of the string, the separating NUL and a terminating * NUL. */ newcmdline = malloc(STRLEN(cmdline) + STRLEN(progp) + 2); if (newcmdline == NULL) return 0; /* * First round: count the number of arguments ("pnew" == NULL). * Second round: produce the arguments. */ for (round = 1; round <= 2; ++round) { /* First argument is the program name. */ if (pnew != NULL) { argv[0] = pnew; strcpy(pnew, progp); pnew += strlen(pnew); *pnew++ = NUL; } /* * Isolate each argument and put it in argv[]. */ p = cmdline; argc = 1; while (*p != NUL) { inquote = FALSE; if (pnew != NULL) argv[argc] = pnew; ++argc; while (*p != NUL && (inquote || (*p != ' ' && *p != '\t'))) { /* Backslashes are only special when followed by a double * quote. */ i = (int)strspn(p, "\\"); if (p[i] == '"') { /* Halve the number of backslashes. */ if (i > 1 && pnew != NULL) { vim_memset(pnew, '\\', i / 2); pnew += i / 2; } /* Even nr of backslashes toggles quoting, uneven copies * the double quote. */ if ((i & 1) == 0) inquote = !inquote; else if (pnew != NULL) *pnew++ = '"'; p += i + 1; } else if (i > 0) { /* Copy span of backslashes unmodified. */ if (pnew != NULL) { vim_memset(pnew, '\\', i); pnew += i; } p += i; } else { if (pnew != NULL) *pnew++ = *p; #ifdef FEAT_MBYTE /* Can't use mb_* functions, because 'encoding' is not * initialized yet here. */ if (IsDBCSLeadByte(*p)) { ++p; if (pnew != NULL) *pnew++ = *p; } #endif ++p; } } if (pnew != NULL) *pnew++ = NUL; while (*p == ' ' || *p == '\t') ++p; /* advance until a non-space */ } if (round == 1) { argv = (char **)malloc((argc + 1) * sizeof(char *)); if (argv == NULL ) { free(newcmdline); return 0; /* malloc error */ } pnew = newcmdline; *tofree = newcmdline; } } #ifdef FEAT_MBYTE done: #endif argv[argc] = NULL; /* NULL-terminated list */ *argvp = argv; return argc; }