Mercurial > vim
changeset 8140:563c923b1584 v7.4.1364
commit https://github.com/vim/vim/commit/cf7164a088664961e7d70dd100c5874dc5ceb293
Author: Bram Moolenaar <Bram@vim.org>
Date: Sat Feb 20 13:55:06 2016 +0100
patch 7.4.1364
Problem: The Win 16 code is not maintained and unused.
Solution: Remove the Win 16 support.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sat, 20 Feb 2016 14:00:06 +0100 |
parents | 2b0d471e04f7 |
children | 894b78ff8a1d |
files | Filelist src/Make_cyg_ming.mak src/Make_mvc.mak src/Make_w16.mak src/Makefile src/eval.c src/feature.h src/gui.c src/gui_w16.c src/gui_w32.c src/gui_w48.c src/guiw16rc.h src/misc2.c src/option.c src/os_msdos.c src/os_mswin.c src/os_win16.c src/os_win16.h src/proto.h src/proto/gui_w16.pro src/version.c src/vim.h src/vim16.def src/vim16.rc src/winclip.c |
diffstat | 25 files changed, 4124 insertions(+), 6869 deletions(-) [+] |
line wrap: on
line diff
--- a/Filelist +++ b/Filelist @@ -300,7 +300,6 @@ SRC_DOS = \ src/Make_dvc.mak \ src/Make_ming.mak \ src/Make_mvc.mak \ - src/Make_w16.mak \ src/bigvim.bat \ src/bigvim64.bat \ src/msvcsetup.bat \ @@ -314,10 +313,7 @@ SRC_DOS = \ src/glbl_ime.h \ src/gui_dwrite.cpp \ src/gui_dwrite.h \ - src/gui_w16.c \ src/gui_w32.c \ - src/gui_w48.c \ - src/guiw16rc.h \ src/gui_w32_rc.h \ src/if_ole.cpp \ src/if_ole.h \ @@ -329,16 +325,12 @@ SRC_DOS = \ src/os_msdos.h \ src/os_w32dll.c \ src/os_w32exe.c \ - src/os_win16.c \ src/os_win32.c \ src/os_mswin.c \ - src/os_win16.h \ src/os_win32.h \ - src/proto/gui_w16.pro \ src/proto/gui_w32.pro \ src/proto/if_ole.pro \ src/proto/os_msdos.pro \ - src/proto/os_win16.pro \ src/proto/os_win32.pro \ src/proto/os_mswin.pro \ src/testdir/Make_dos.mak \ @@ -349,8 +341,6 @@ SRC_DOS = \ src/vim.rc \ src/vimio.h \ src/gvim.exe.mnf \ - src/vim16.def \ - src/vim16.rc \ src/vimrun.c \ src/vimtbar.h \ src/xpm_w32.c \ @@ -390,7 +380,6 @@ SRC_DOS_BIN = \ src/VisVim/Res/*.bmp \ src/tearoff.bmp \ src/tools.bmp \ - src/tools16.bmp \ src/vim*.ico \ src/vim.tlb \ src/vimtbar.lib \
--- a/src/Make_cyg_ming.mak +++ b/src/Make_cyg_ming.mak @@ -860,7 +860,7 @@ INCL = vim.h feature.h os_win32.h os_dos $(OUTDIR)/ex_eval.o: ex_eval.c $(INCL) ex_cmds.h $(CC) -c $(CFLAGS) ex_eval.c -o $(OUTDIR)/ex_eval.o -$(OUTDIR)/gui_w32.o: gui_w32.c gui_w48.c $(INCL) +$(OUTDIR)/gui_w32.o: gui_w32.c $(INCL) $(CC) -c $(CFLAGS) gui_w32.c -o $(OUTDIR)/gui_w32.o $(OUTDIR)/gui_dwrite.o: gui_dwrite.cpp $(INCL) gui_dwrite.h
--- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -1175,7 +1175,7 @@ testclean: $(OUTDIR)/gui_beval.obj: $(OUTDIR) gui_beval.c $(INCL) $(GUI_INCL) -$(OUTDIR)/gui_w32.obj: $(OUTDIR) gui_w32.c gui_w48.c $(INCL) $(GUI_INCL) +$(OUTDIR)/gui_w32.obj: $(OUTDIR) gui_w32.c $(INCL) $(GUI_INCL) $(OUTDIR)/gui_dwrite.obj: $(OUTDIR) gui_dwrite.cpp $(INCL) $(GUI_INCL)
deleted file mode 100644 --- a/src/Make_w16.mak +++ /dev/null @@ -1,204 +0,0 @@ -# -# Borland C++ 5.0[12] makefile for vim, 16-bit windows gui version -# By Vince Negri -# -# NOTE: THIS IS OLD AND PROBABLY NO LONGER WORKS. -# -# ************************************************************* -# * WARNING! -# * This was originally produced by the IDE, but has since been -# * modified to make it work properly. Adjust with care! -# * In particular, leave LinkerLocalOptsAtW16_gvim16dexe alone -# * unless you are a guru. -# ************************************************************* -# -# Look for BOR below and either pass a different value or -# adjust the path as required. For example -# make -fMake_w16.mak -DBOR=C:\PF\Borland\BC5.01 -B BccW16.cfg -# make -fMake_w16.mak -# Note: $(BOR) is effectively ignored unless BccW16.cfg is rebuilt. -# -# Does not compile with Borland C++ 4.51 Walter Briscoe 2003-02-24 -# "out of memory" from compiler if gvim16 wildly wrong. WFB 2003-03-04 -# -# vim16.def must be a DOS-formatted file. (\r\n line endings.) -# It is a UNIX-formatted file (\n line endings) in vim-*-extra.tar.gz - -.AUTODEPEND - -# -# Borland C++ tools -# -IMPLIB = Implib -BCC = Bcc +BccW16.cfg -TLINK = TLink -TLIB = TLib -BRC = Brc -TASM = Tasm -# -# IDE macros -# - -# -# Options -# -!ifndef BOR -BOR = D:\BC5 -!endif - -# !ifndef INTDIR is lethal considering CLEAN below. WFB 2003-03-13 -INTDIR=w16 - -# /Twe Make the target a Windows .EXE with explicit functions exportable + -# /x Map file off -# /l Include source line numbers in object map files` -# /c case sensitive link -# /C Case-sensitive exports and imports (16-bit only) -# /k Produce "No Stack" warning. -# /Oa Minimise segment alignment -# /Oc Minimise Chain fixes -# /Oi Minimise Iterated data -# /Or Minimise resource alignment -# /P -P=x Code pack size -# /V Windows version for application -# /L Folder to search for library files -LinkerLocalOptsAtW16_gvim16dexe =/Twe/x/l/c/C/k/Or/Oc/Oa/Oi/P=65535/V3.10 - -CompInheritOptsAt_gvim16dexe = \ - -I$(BOR)\INCLUDE;PROTO;. \ - -DFEAT_GUI;FEAT_GUI_MSWIN;FEAT_GUI_W16;MSWIN;WIN16;MSWIN16_FASTTEXT \ - -DFEAT_TOOLBAR;WIN16_3DLOOK - -# -# Dependency List -# -Dep_Gvim16 = \ - gvim16.exe - -ObjFiles = \ - $(INTDIR)\buffer.obj\ - $(INTDIR)\charset.obj\ - $(INTDIR)\diff.obj\ - $(INTDIR)\digraph.obj\ - $(INTDIR)\edit.obj\ - $(INTDIR)\eval.obj\ - $(INTDIR)\ex_cmds.obj\ - $(INTDIR)\ex_cmds2.obj\ - $(INTDIR)\ex_docmd.obj\ - $(INTDIR)\ex_eval.obj\ - $(INTDIR)\ex_getln.obj\ - $(INTDIR)\fileio.obj\ - $(INTDIR)\fold.obj\ - $(INTDIR)\getchar.obj\ - $(INTDIR)\hardcopy.obj\ - $(INTDIR)\hashtab.obj\ - $(INTDIR)\gui.obj\ - $(INTDIR)\gui_w16.obj\ - $(INTDIR)\main.obj\ - $(INTDIR)\mark.obj\ - $(INTDIR)\mbyte.obj\ - $(INTDIR)\memfile.obj\ - $(INTDIR)\memline.obj\ - $(INTDIR)\menu.obj\ - $(INTDIR)\message.obj\ - $(INTDIR)\misc1.obj\ - $(INTDIR)\misc2.obj\ - $(INTDIR)\move.obj\ - $(INTDIR)\normal.obj\ - $(INTDIR)\ops.obj\ - $(INTDIR)\option.obj\ - $(INTDIR)\os_win16.obj\ - $(INTDIR)\os_msdos.obj\ - $(INTDIR)\os_mswin.obj\ - $(INTDIR)\winclip.obj\ - $(INTDIR)\popupmnu.obj\ - $(INTDIR)\quickfix.obj\ - $(INTDIR)\regexp.obj\ - $(INTDIR)\screen.obj\ - $(INTDIR)\search.obj\ - $(INTDIR)\spell.obj\ - $(INTDIR)\syntax.obj\ - $(INTDIR)\tag.obj\ - $(INTDIR)\term.obj\ - $(INTDIR)\ui.obj\ - $(INTDIR)\undo.obj\ - $(INTDIR)\version.obj\ - $(INTDIR)\window.obj - -Dep_gvim16dexe = \ - vimtbar.lib\ - vim16.def\ - $(INTDIR)\vim16.res\ - $(ObjFiles) - -# Without the following, the implicit rule in BUILTINS.MAK is picked up -# for a rule for .c.obj rather than the local implicit rule -.SUFFIXES -.SUFFIXES .c .obj -.path.c = . - -# -P- Force C++ compilation off -# -c Compilation only -# -n Place .OBJ files -{.}.c{$(INTDIR)}.obj: - $(BCC) -P- -c -n$(INTDIR)\ {$< } - -Gvim16 : BccW16.cfg $(Dep_Gvim16) - echo MakeNode - -gvim16.exe : $(Dep_gvim16dexe) - $(TLINK) $(LinkerLocalOptsAtW16_gvim16dexe) @&&| -c0wl.obj $(ObjFiles) -|,$*,,vimtbar ctl3dv2 import cwl, vim16.def,$(INTDIR)\vim16.res - -# Force objects to be built if $(BOR) changes -$(ObjFiles) : Make_w16.mak BccW16.cfg - -$(INTDIR)\vim16.res : vim16.rc - $(BRC) -R @&&| - $(CompInheritOptsAt_gvim16dexe) -fo$*.res $? -| - - -# Compiler configuration file -# There is no rule for $(INTDIR) as make always says it does not exist -BccW16.cfg : - -@if not exist $(INTDIR)\$(NULL) mkdir $(INTDIR) - Copy &&| --3 ; Generate 80386 protected-mode compatible instructions --a ; Byte alignment --dc ; Move string literals from data segment to code segment --ff ; Fast floating point --H ; Generate and use precompiled headers --H=$(INTDIR)\gvim16.csm ; gvim16.csm is the precompiled header filename --k- ; No standard stack frame --ml ; Large memory model --OW ; Suppress the inc bp/dec bp on windows far functions --O1 ; Generate smallest possible code --O2 ; Generate fastest possible code (overrides prior -O1 control) --pr ; Fastcall calling convention passing parameters in registers --R- ; Exclude browser information in generated .OBJ files --v- ; Turn off source debugging --vi ; Turn inline function expansion on --WE ; Only __far _export functions are exported --w ; Display warnings --w-par ; Suppress: Parameter 'parameter' is never used --w-pch ; Cannot create pre-compiled header: initialized data in header --w-sig ; identifier' declared but never used --w-ucp ; Mixing pointers to different 'char' types --wuse ; 'identifier' declared but never used - $(CompInheritOptsAt_gvim16dexe) -| $@ - -!IF "$(OS)" == "Windows_NT" -NULL= -DEL_TREE = rmdir /s /q -!ELSE -NULL=nul -DEL_TREE = deltree /y -!ENDIF - -CLEAN: - -@if exist $(INTDIR)\$(NULL) $(DEL_TREE) $(INTDIR) - -@if exist BccW16.cfg erase BccW16.cfg - -@if exist gvim16.exe erase gvim16.exe
--- a/src/Makefile +++ b/src/Makefile @@ -1336,7 +1336,7 @@ CARBONGUI_TESTARG = VIMPROG=../$(APPDIR) # All GUI files ALL_GUI_SRC = gui.c gui_gtk.c gui_gtk_f.c gui_motif.c gui_xmdlg.c gui_xmebw.c gui_athena.c gui_gtk_x11.c gui_x11.c gui_at_sb.c gui_at_fs.c pty.c -ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w16.pro gui_w32.pro gui_photon.pro +ALL_GUI_PRO = gui.pro gui_gtk.pro gui_motif.pro gui_xmdlg.pro gui_athena.pro gui_gtk_x11.pro gui_x11.pro gui_w32.pro gui_photon.pro # }}} @@ -1715,7 +1715,7 @@ PRO_AUTO = \ # Resources used for the Mac are in one directory. RSRC_DIR = os_mac_rsrc -PRO_MANUAL = os_amiga.pro os_msdos.pro os_win16.pro os_win32.pro \ +PRO_MANUAL = os_amiga.pro os_msdos.pro os_win32.pro \ os_mswin.pro winclip.pro os_beos.pro os_vms.pro $(PERL_PRO) # Default target is making the executable and tools @@ -1868,20 +1868,16 @@ os_msdos.pro: os_msdos.c $(CPROTO) -DMSDOS -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ -os_win16.pro: os_win16.c - $(CPROTO) -DWIN16 -UHAVE_CONFIG_H $< > proto/$@ - echo "/* vim: set ft=c : */" >> proto/$@ - os_win32.pro: os_win32.c $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ os_mswin.pro: os_mswin.c - $(CPROTO) -DWIN16 -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ winclip.pro: winclip.c - $(CPROTO) -DWIN16 -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + $(CPROTO) -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ os_beos.pro: os_beos.c @@ -2025,6 +2021,7 @@ test_arglist \ test_menu \ test_perl \ test_quickfix \ + test_reltime \ test_searchpos \ test_set \ test_sort \
--- a/src/eval.c +++ b/src/eval.c @@ -13235,9 +13235,6 @@ f_has(typval_T *argvars, typval_T *rettv #ifdef VMS "vms", #endif -#ifdef WIN16 - "win16", -#endif #ifdef WIN32 "win32", #endif
--- a/src/feature.h +++ b/src/feature.h @@ -320,7 +320,7 @@ * * Disabled for EBCDIC as it requires multibyte. */ -#if defined(FEAT_BIG) && !defined(WIN16) && VIM_SIZEOF_INT >= 4 && !defined(EBCDIC) +#if defined(FEAT_BIG) && VIM_SIZEOF_INT >= 4 && !defined(EBCDIC) # define FEAT_ARABIC #endif #ifdef FEAT_ARABIC @@ -624,8 +624,7 @@ * Multibyte support doesn't work on z/OS Unix currently. */ #if (defined(FEAT_NORMAL) || defined(FEAT_GUI_GTK) || defined(FEAT_ARABIC)) \ - && !defined(FEAT_MBYTE) && !defined(WIN16) \ - && VIM_SIZEOF_INT >= 4 && !defined(EBCDIC) + && !defined(FEAT_MBYTE) && VIM_SIZEOF_INT >= 4 && !defined(EBCDIC) # define FEAT_MBYTE #endif @@ -763,7 +762,7 @@ && (defined(FEAT_GUI_GTK) \ || (defined(FEAT_GUI_MOTIF) && defined(HAVE_XM_NOTEBOOK_H)) \ || defined(FEAT_GUI_MAC) \ - || (defined(FEAT_GUI_MSWIN) && !defined(WIN16) \ + || (defined(FEAT_GUI_MSWIN) \ && (!defined(_MSC_VER) || _MSC_VER > 1020))) # define FEAT_GUI_TABLINE #endif
--- a/src/gui.c +++ b/src/gui.c @@ -2184,7 +2184,7 @@ gui_outstr_nowrap( guicolor_T fg_color; guicolor_T bg_color; guicolor_T sp_color; -#if !defined(MSWIN16_FASTTEXT) && !defined(FEAT_GUI_GTK) +#if !defined(FEAT_GUI_GTK) GuiFont font = NOFONT; # ifdef FEAT_MBYTE GuiFont wide_font = NOFONT; @@ -2241,7 +2241,7 @@ gui_outstr_nowrap( highlight_mask = gui.highlight_mask; hl_mask_todo = highlight_mask; -#if !defined(MSWIN16_FASTTEXT) && !defined(FEAT_GUI_GTK) +#if !defined(FEAT_GUI_GTK) /* Set the font */ if (aep != NULL && aep->ae_u.gui.font != NOFONT) font = aep->ae_u.gui.font; @@ -2358,11 +2358,9 @@ gui_outstr_nowrap( clip_may_clear_selection(gui.row, gui.row); -#ifndef MSWIN16_FASTTEXT /* If there's no bold font, then fake it */ if (hl_mask_todo & (HL_BOLD | HL_STANDOUT)) draw_flags |= DRAW_BOLD; -#endif /* * When drawing bold or italic characters the spill-over from the left @@ -2383,11 +2381,7 @@ gui_outstr_nowrap( draw_flags |= DRAW_UNDERL; #else /* Do we underline the text? */ - if ((hl_mask_todo & HL_UNDERLINE) -# ifndef MSWIN16_FASTTEXT - || (hl_mask_todo & HL_ITALIC) -# endif - ) + if ((hl_mask_todo & HL_UNDERLINE) || (hl_mask_todo & HL_ITALIC)) draw_flags |= DRAW_UNDERL; #endif /* Do we undercurl the text? */ @@ -3338,7 +3332,7 @@ gui_init_which_components(char_u *oldval static int prev_footer = -1; int using_footer = FALSE; #endif -#if defined(FEAT_MENU) && !defined(WIN16) +#if defined(FEAT_MENU) static int prev_tearoff = -1; int using_tearoff = FALSE; #endif @@ -3415,7 +3409,7 @@ gui_init_which_components(char_u *oldval break; #endif case GO_TEAROFF: -#if defined(FEAT_MENU) && !defined(WIN16) +#if defined(FEAT_MENU) using_tearoff = TRUE; #endif break; @@ -3522,7 +3516,7 @@ gui_init_which_components(char_u *oldval fix_size = TRUE; } #endif -#if defined(FEAT_MENU) && !defined(WIN16) && !(defined(WIN3264) && !defined(FEAT_TEAROFF)) +#if defined(FEAT_MENU) && !(defined(WIN3264) && !defined(FEAT_TEAROFF)) if (using_tearoff != prev_tearoff) { gui_mch_toggle_tearoffs(using_tearoff);
deleted file mode 100644 --- a/src/gui_w16.c +++ /dev/null @@ -1,1564 +0,0 @@ -/* 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_w16.c - * - * GUI support for Microsoft Windows 3.1x - * - * George V. Reilly <george@reilly.org> wrote the original Win32 GUI. - * Robert Webb reworked it to use the existing GUI stuff and added menu, - * scrollbars, etc. - * - * Vince Negri then butchered the code to get it compiling for - * 16-bit windows. - * - */ - -/* Win16 doesn't use the "W" methods. */ -#define pDispatchMessage DispatchMessage -#define pGetMessage GetMessage -#define pIsDialogMessage IsDialogMessage -#define pPeekMessage PeekMessage - -/* - * Include the common stuff for MS-Windows GUI. - */ -#include "gui_w48.c" - -#include "guiw16rc.h" - -/* Undocumented Windows Message - not even defined in some SDK headers */ -#define WM_EXITSIZEMOVE 0x0232 - - -#ifdef FEAT_TOOLBAR -# define CMD_TB_BASE (99) -# include <vimtbar.h> -#endif - -#ifdef PROTO -# define WINAPI -#endif - -#define HANDLE_WM_DROPFILES(hwnd, wParam, lParam, fn) \ - ((fn)((hwnd), (HDROP)(wParam)), 0L) - - -/* Local variables: */ - -#ifdef FEAT_MENU -static UINT s_menu_id = 100; -#endif - - -#define VIM_NAME "vim" -#define VIM_CLASS "Vim" - -#define DLG_ALLOC_SIZE 16 * 1024 - -/* - * stuff for dialogs, menus, tearoffs etc. - */ -#if defined(FEAT_GUI_DIALOG) || defined(PROTO) -static BOOL CALLBACK dialog_callback(HWND, UINT, WPARAM, LPARAM); - -static LPWORD -add_dialog_element( - LPWORD p, - DWORD lStyle, - WORD x, - WORD y, - WORD w, - WORD h, - WORD Id, - BYTE clss, - const char *caption); - -static int dialog_default_button = -1; -#endif - -static void get_dialog_font_metrics(void); - -#ifdef FEAT_TOOLBAR -static void initialise_toolbar(void); -#endif - - -#ifdef FEAT_MENU -/* - * Figure out how high the menu bar is at the moment. - */ - static int -gui_mswin_get_menu_height( - int fix_window) /* If TRUE, resize window if menu height changed */ -{ - static int old_menu_height = -1; - - int num; - int menu_height; - - if (gui.menu_is_active) - num = GetMenuItemCount(s_menuBar); - else - num = 0; - - if (num == 0) - menu_height = 0; - else if (gui.starting) - menu_height = GetSystemMetrics(SM_CYMENU); - else - { - RECT r1, r2; - int frameht = GetSystemMetrics(SM_CYFRAME); - int capht = GetSystemMetrics(SM_CYCAPTION); - - /* get window rect of s_hwnd - * get client rect of s_hwnd - * get cap height - * subtract from window rect, the sum of client height, - * (if not maximized)frame thickness, and caption height. - */ - GetWindowRect(s_hwnd, &r1); - GetClientRect(s_hwnd, &r2); - menu_height = r1.bottom - r1.top - (r2.bottom-r2.top + - 2 * frameht * (!IsZoomed(s_hwnd)) + capht); - } - - if (fix_window && menu_height != old_menu_height) - { - old_menu_height = menu_height; - gui_set_shellsize(FALSE, FALSE, RESIZE_VERT); - } - - return menu_height; -} -#endif /*FEAT_MENU*/ - - -/* - * Even though we have _DuringSizing() which makes the rubber band a valid - * size, we need this for when the user maximises the window. - * TODO: Doesn't seem to adjust the width though for some reason. - */ - static BOOL -_OnWindowPosChanging( - HWND hwnd, - LPWINDOWPOS lpwpos) -{ - - if (!IsIconic(hwnd) && !(lpwpos->flags & SWP_NOSIZE)) - { - gui_mswin_get_valid_dimensions(lpwpos->cx, lpwpos->cy, - &lpwpos->cx, &lpwpos->cy); - } - return 0; -} - - - - - - static LRESULT CALLBACK -_WndProc( - HWND hwnd, - UINT uMsg, - WPARAM wParam, - LPARAM lParam) -{ - /* - TRACE("WndProc: hwnd = %08x, msg = %x, wParam = %x, lParam = %x\n", - hwnd, uMsg, wParam, lParam); - */ - - HandleMouseHide(uMsg, lParam); - - s_uMsg = uMsg; - s_wParam = wParam; - s_lParam = lParam; - - switch (uMsg) - { - HANDLE_MSG(hwnd, WM_DEADCHAR, _OnDeadChar); - HANDLE_MSG(hwnd, WM_SYSDEADCHAR, _OnDeadChar); - /* HANDLE_MSG(hwnd, WM_ACTIVATE, _OnActivate); */ - HANDLE_MSG(hwnd, WM_CHAR, _OnChar); - HANDLE_MSG(hwnd, WM_CLOSE, _OnClose); - /* HANDLE_MSG(hwnd, WM_COMMAND, _OnCommand); */ - HANDLE_MSG(hwnd, WM_DESTROY, _OnDestroy); - HANDLE_MSG(hwnd, WM_DROPFILES, _OnDropFiles); - HANDLE_MSG(hwnd, WM_HSCROLL, _OnScroll); - HANDLE_MSG(hwnd, WM_KILLFOCUS, _OnKillFocus); -#ifdef FEAT_MENU - HANDLE_MSG(hwnd, WM_COMMAND, _OnMenu); -#endif - /* HANDLE_MSG(hwnd, WM_MOVE, _OnMove); */ - /* HANDLE_MSG(hwnd, WM_NCACTIVATE, _OnNCActivate); */ - HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus); - HANDLE_MSG(hwnd, WM_SIZE, _OnSize); - /* HANDLE_MSG(hwnd, WM_SYSCOMMAND, _OnSysCommand); */ - /* HANDLE_MSG(hwnd, WM_SYSKEYDOWN, _OnAltKey); */ - HANDLE_MSG(hwnd, WM_VSCROLL, _OnScroll); - HANDLE_MSG(hwnd, WM_WINDOWPOSCHANGING, _OnWindowPosChanging); - HANDLE_MSG(hwnd, WM_ACTIVATEAPP, _OnActivateApp); - - case WM_QUERYENDSESSION: /* System wants to go down. */ - gui_shell_closed(); /* Will exit when no changed buffers. */ - return FALSE; /* Do NOT allow system to go down. */ - - case WM_ENDSESSION: - if (wParam) /* system only really goes down when wParam is TRUE */ - _OnEndSession(); - break; - - case WM_SYSCHAR: - /* - * if 'winaltkeys' is "no", or it's "menu" and it's not a menu - * shortcut key, handle like a typed ALT key, otherwise call Windows - * ALT key handling. - */ -#ifdef FEAT_MENU - if ( !gui.menu_is_active - || p_wak[0] == 'n' - || (p_wak[0] == 'm' && !gui_is_menu_shortcut((int)wParam)) - ) -#endif - return HANDLE_WM_SYSCHAR((hwnd), (wParam), (lParam), (_OnSysChar)); -#ifdef FEAT_MENU - else - return MyWindowProc(hwnd, uMsg, wParam, lParam); -#endif - - case WM_SYSKEYUP: -#ifdef FEAT_MENU - /* Only when menu is active, ALT key is used for that. */ - if (gui.menu_is_active) - { - return MyWindowProc(hwnd, uMsg, wParam, lParam); - } - else -#endif - return 0; - -#if defined(MENUHINTS) && defined(FEAT_MENU) - case WM_MENUSELECT: - if (((UINT) LOWORD(lParam) - & (0xffff ^ (MF_MOUSESELECT + MF_BITMAP + MF_POPUP))) - == MF_HILITE - && (State & CMDLINE) == 0) - { - UINT idButton; - int idx; - vimmenu_T *pMenu; - - idButton = (UINT)LOWORD(wParam); - pMenu = gui_mswin_find_menu(root_menu, idButton); - if (pMenu) - { - idx = MENU_INDEX_TIP; - msg_clr_cmdline(); - if (pMenu->strings[idx]) - msg(pMenu->strings[idx]); - else - msg(""); - setcursor(); - out_flush(); - } - } - break; -#endif - case WM_NCHITTEST: - { - LRESULT result; - int x, y; - int xPos = GET_X_LPARAM(lParam); - - result = MyWindowProc(hwnd, uMsg, wParam, lParam); - if (result == HTCLIENT) - { - (void)gui_mch_get_winpos(&x, &y); - xPos -= x; - - if (xPos < 48) /*<VN> TODO should use system metric?*/ - return HTBOTTOMLEFT; - else - return HTBOTTOMRIGHT; - } - else - return result; - } - /* break; */ - default: -#ifdef MSWIN_FIND_REPLACE - if (uMsg == s_findrep_msg && s_findrep_msg != 0) - { - _OnFindRepl(); - } -#endif - return MyWindowProc(hwnd, uMsg, wParam, lParam); - } - - return 1; -} - - - -/* - * End of call-back routines - */ - - -/* - * Parse the GUI related command-line arguments. Any arguments used are - * deleted from argv, and *argc is decremented accordingly. This is called - * when vim is started, whether or not the GUI has been started. - */ - void -gui_mch_prepare(int *argc, char **argv) -{ - /* No special args for win16 GUI at the moment. */ - -} - -/* - * Initialise the GUI. Create all the windows, set up all the call-backs - * etc. - */ - int -gui_mch_init(void) -{ - const char szVimWndClass[] = VIM_CLASS; - const char szTextAreaClass[] = "VimTextArea"; - WNDCLASS wndclass; - -#ifdef WIN16_3DLOOK - Ctl3dRegister(s_hinst); - Ctl3dAutoSubclass(s_hinst); -#endif - - /* Display any pending error messages */ - display_errors(); - - gui.scrollbar_width = GetSystemMetrics(SM_CXVSCROLL); - gui.scrollbar_height = GetSystemMetrics(SM_CYHSCROLL); -#ifdef FEAT_MENU - gui.menu_height = 0; /* Windows takes care of this */ -#endif - gui.border_width = 0; - - gui.currBgColor = INVALCOLOR; - - s_brush = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); - - if (GetClassInfo(s_hinst, szVimWndClass, &wndclass) == 0) { - wndclass.style = 0; - wndclass.lpfnWndProc = _WndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = s_hinst; - wndclass.hIcon = LoadIcon(wndclass.hInstance, MAKEINTRESOURCE(IDR_VIM)); - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = s_brush; - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szVimWndClass; - - if (( -#ifdef GLOBAL_IME - atom = -#endif - RegisterClass(&wndclass)) == 0) - return FAIL; - } - - s_hwnd = CreateWindow( - szVimWndClass, "Vim MSWindows GUI", - WS_OVERLAPPEDWINDOW, - gui_win_x == -1 ? CW_USEDEFAULT : gui_win_x, - gui_win_y == -1 ? CW_USEDEFAULT : gui_win_y, - 100, /* Any value will do */ - 100, /* Any value will do */ - NULL, NULL, - s_hinst, NULL); - - if (s_hwnd == NULL) - return FAIL; - -#ifdef GLOBAL_IME - global_ime_init(atom, s_hwnd); -#endif - - /* Create the text area window */ - if (GetClassInfo(s_hinst, szTextAreaClass, &wndclass) == 0) { - wndclass.style = CS_OWNDC; - wndclass.lpfnWndProc = _TextAreaWndProc; - wndclass.cbClsExtra = 0; - wndclass.cbWndExtra = 0; - wndclass.hInstance = s_hinst; - wndclass.hIcon = NULL; - wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); - wndclass.hbrBackground = NULL; - wndclass.lpszMenuName = NULL; - wndclass.lpszClassName = szTextAreaClass; - - if (RegisterClass(&wndclass) == 0) - return FAIL; - } - s_textArea = CreateWindow( - szTextAreaClass, "Vim text area", - WS_CHILD | WS_VISIBLE, 0, 0, - 100, /* Any value will do for now */ - 100, /* Any value will do for now */ - s_hwnd, NULL, - s_hinst, NULL); - - if (s_textArea == NULL) - return FAIL; - -#ifdef FEAT_MENU - s_menuBar = CreateMenu(); -#endif - s_hdc = GetDC(s_textArea); - -#ifdef MSWIN16_FASTTEXT - SetBkMode(s_hdc, OPAQUE); -#endif - - DragAcceptFiles(s_hwnd, TRUE); - - /* Do we need to bother with this? */ - /* m_fMouseAvail = GetSystemMetrics(SM_MOUSEPRESENT); */ - - /* Get background/foreground colors from the system */ - gui_mch_def_colors(); - - /* Get the colors from the "Normal" group (set in syntax.c or in a vimrc - * file) */ - set_normal_colors(); - - /* - * Check that none of the colors are the same as the background color. - * Then store the current values as the defaults. - */ - gui_check_colors(); - gui.def_norm_pixel = gui.norm_pixel; - gui.def_back_pixel = gui.back_pixel; - - /* Get the colors for the highlight groups (gui_check_colors() might have - * changed them) */ - highlight_gui_started(); - - /* - * Start out by adding the configured border width into the border offset - */ - gui.border_offset = gui.border_width; - - - /* - * compute a couple of metrics used for the dialogs - */ - get_dialog_font_metrics(); -#ifdef FEAT_TOOLBAR - /* - * Create the toolbar - */ - initialise_toolbar(); -#endif -#ifdef MSWIN_FIND_REPLACE - /* - * Initialise the dialog box stuff - */ - s_findrep_msg = RegisterWindowMessage(FINDMSGSTRING); - - /* Initialise the struct */ - s_findrep_struct.lStructSize = sizeof(s_findrep_struct); - s_findrep_struct.lpstrFindWhat = alloc(MSWIN_FR_BUFSIZE); - s_findrep_struct.lpstrFindWhat[0] = NUL; - s_findrep_struct.lpstrReplaceWith = alloc(MSWIN_FR_BUFSIZE); - s_findrep_struct.lpstrReplaceWith[0] = NUL; - s_findrep_struct.wFindWhatLen = MSWIN_FR_BUFSIZE; - s_findrep_struct.wReplaceWithLen = MSWIN_FR_BUFSIZE; -#endif - - return OK; -} - - -/* - * Set the size of the window to the given width and height in pixels. - */ - void -gui_mch_set_shellsize(int width, int height, - int min_width, int min_height, int base_width, int base_height, - int direction) -{ - RECT workarea_rect; - int win_width, win_height; - int win_xpos, win_ypos; - WINDOWPLACEMENT wndpl; - - /* try to keep window completely on screen */ - /* get size of the screen work area - use SM_CYFULLSCREEN - * instead of SM_CYSCREEN so that we don't overlap the - * taskbar if someone fires us up on Win95/NT */ - workarea_rect.left = 0; - workarea_rect.top = 0; - workarea_rect.right = GetSystemMetrics(SM_CXSCREEN); - workarea_rect.bottom = GetSystemMetrics(SM_CYFULLSCREEN); - - /* get current position of our window */ - wndpl.length = sizeof(WINDOWPLACEMENT); - GetWindowPlacement(s_hwnd, &wndpl); - if (wndpl.showCmd == SW_SHOWNORMAL) - { - win_xpos = wndpl.rcNormalPosition.left; - win_ypos = wndpl.rcNormalPosition.top; - } - else - { - win_xpos = workarea_rect.left; - win_ypos = workarea_rect.top; - } - - /* compute the size of the outside of the window */ - win_width = width + GetSystemMetrics(SM_CXFRAME) * 2; - win_height = height + GetSystemMetrics(SM_CYFRAME) * 2 - + GetSystemMetrics(SM_CYCAPTION) -#ifdef FEAT_MENU - + gui_mswin_get_menu_height(FALSE) -#endif - ; - - /* if the window is going off the screen, move it on to the screen */ - if ((direction & RESIZE_HOR) && win_xpos + win_width > workarea_rect.right) - win_xpos = workarea_rect.right - win_width; - - if ((direction & RESIZE_HOR) && win_xpos < workarea_rect.left) - win_xpos = workarea_rect.left; - - if ((direction & RESIZE_VERT) - && win_ypos + win_height > workarea_rect.bottom) - win_ypos = workarea_rect.bottom - win_height; - - if ((direction & RESIZE_VERT) && win_ypos < workarea_rect.top) - win_ypos = workarea_rect.top; - - /* set window position */ - SetWindowPos(s_hwnd, NULL, win_xpos, win_ypos, win_width, win_height, - SWP_NOZORDER | SWP_NOACTIVATE); - -#ifdef FEAT_MENU - /* Menu may wrap differently now */ - gui_mswin_get_menu_height(!gui.starting); -#endif -} - - void -gui_mch_set_scrollbar_thumb( - scrollbar_T *sb, - long val, - long size, - long max) -{ - sb->scroll_shift = 0; - while (max > 32767) - { - max = (max + 1) >> 1; - val >>= 1; - size >>= 1; - ++sb->scroll_shift; - } - - if (sb->scroll_shift > 0) - ++size; - - SetScrollRange(sb->id, SB_CTL, 0, (int) max, FALSE); - SetScrollPos(sb->id, SB_CTL, (int) val, TRUE); -} - - -/* - * Set the current text font. - */ - void -gui_mch_set_font(GuiFont font) -{ - gui.currFont = font; - SelectFont(s_hdc, gui.currFont); -} - -/* - * Set the current text foreground color. - */ - void -gui_mch_set_fg_color(guicolor_T color) -{ - gui.currFgColor = color; - SetTextColor(s_hdc, gui.currFgColor); -} - -/* - * Set the current text background color. - */ - void -gui_mch_set_bg_color(guicolor_T color) -{ - if (gui.currBgColor == color) - return; - - gui.currBgColor = color; - SetBkColor(s_hdc, gui.currBgColor); -} - -/* - * Set the current text special color. - */ - void -gui_mch_set_sp_color(guicolor_T color) -{ - /* TODO */ -} - - - - void -gui_mch_draw_string( - int row, - int col, - char_u *text, - int len, - int flags) -{ -#ifndef MSWIN16_FASTTEXT - static int *padding = NULL; - static int pad_size = 0; - int i; -#endif - HPEN hpen, old_pen; - int y; - -#ifndef MSWIN16_FASTTEXT - /* - * Italic and bold text seems to have an extra row of pixels at the bottom - * (below where the bottom of the character should be). If we draw the - * characters with a solid background, the top row of pixels in the - * character below will be overwritten. We can fix this by filling in the - * background ourselves, to the correct character proportions, and then - * writing the character in transparent mode. Still have a problem when - * the character is "_", which gets written on to the character below. - * New fix: set gui.char_ascent to -1. This shifts all characters up one - * pixel in their slots, which fixes the problem with the bottom row of - * pixels. We still need this code because otherwise the top row of pixels - * becomes a problem. - webb. - */ - HBRUSH hbr; - RECT rc; - - if (!(flags & DRAW_TRANSP)) - { - /* - * Clear background first. - * Note: FillRect() excludes right and bottom of rectangle. - */ - rc.left = FILL_X(col); - rc.top = FILL_Y(row); -#ifdef FEAT_MBYTE - if (has_mbyte) - { - /* Compute the length in display cells. */ - rc.right = FILL_X(col + mb_string2cells(text, len)); - } - else -#endif - rc.right = FILL_X(col + len); - rc.bottom = FILL_Y(row + 1); - hbr = CreateSolidBrush(gui.currBgColor); - FillRect(s_hdc, &rc, hbr); - DeleteBrush(hbr); - - SetBkMode(s_hdc, TRANSPARENT); - - /* - * When drawing block cursor, prevent inverted character spilling - * over character cell (can happen with bold/italic) - */ - if (flags & DRAW_CURSOR) - { - pcliprect = &rc; - foptions = ETO_CLIPPED; - } - } -#else - /* - * Alternative: write the characters in opaque mode, since we have blocked - * bold or italic fonts. - */ - /* The OPAQUE mode and backcolour have already been set */ -#endif - /* The forecolor and font have already been set */ - -#ifndef MSWIN16_FASTTEXT - - if (pad_size != Columns || padding == NULL || padding[0] != gui.char_width) - { - vim_free(padding); - pad_size = Columns; - - padding = (int *)alloc(pad_size * sizeof(int)); - if (padding != NULL) - for (i = 0; i < pad_size; i++) - padding[i] = gui.char_width; - } -#endif - - /* - * We have to provide the padding argument because italic and bold versions - * of fixed-width fonts are often one pixel or so wider than their normal - * versions. - * No check for DRAW_BOLD, Windows will have done it already. - */ -#ifndef MSWIN16_FASTTEXT - ExtTextOut(s_hdc, TEXT_X(col), TEXT_Y(row), 0, NULL, - (char *)text, len, padding); -#else - TextOut(s_hdc, TEXT_X(col), TEXT_Y(row), (char *)text, len); -#endif - - if (flags & DRAW_UNDERL) - { - hpen = CreatePen(PS_SOLID, 1, gui.currFgColor); - old_pen = SelectObject(s_hdc, hpen); - /* When p_linespace is 0, overwrite the bottom row of pixels. - * Otherwise put the line just below the character. */ - y = FILL_Y(row + 1) - 1; -#ifndef MSWIN16_FASTTEXT - if (p_linespace > 1) - y -= p_linespace - 1; -#endif - MoveToEx(s_hdc, FILL_X(col), y, NULL); - /* Note: LineTo() excludes the last pixel in the line. */ - LineTo(s_hdc, FILL_X(col + len), y); - DeleteObject(SelectObject(s_hdc, old_pen)); - } -} - - -/* - * Output routines. - */ - -/* Flush any output to the screen */ - void -gui_mch_flush(void) -{ - /* Is anything needed here? */ -} - - static void -clear_rect(RECT *rcp) -{ - /* Use trick for fast rect clear */ - gui_mch_set_bg_color(gui.back_pixel); - ExtTextOut(s_hdc, 0, 0, ETO_CLIPPED | ETO_OPAQUE, rcp, NULL, 0, NULL); -} - - - void -gui_mch_get_screen_dimensions(int *screen_w, int *screen_h) -{ - - *screen_w = GetSystemMetrics(SM_CXFULLSCREEN) - - GetSystemMetrics(SM_CXFRAME) * 2; - /* FIXME: dirty trick: Because the gui_get_base_height() doesn't include - * the menubar for MSwin, we subtract it from the screen height, so that - * the window size can be made to fit on the screen. */ - *screen_h = GetSystemMetrics(SM_CYFULLSCREEN) - - GetSystemMetrics(SM_CYFRAME) * 2 -#ifdef FEAT_MENU - - gui_mswin_get_menu_height(FALSE) -#endif - ; -} - - -#if defined(FEAT_MENU) || defined(PROTO) -/* - * Add a sub menu to the menu bar. - */ - void -gui_mch_add_menu( - vimmenu_T *menu, - int pos) -{ - vimmenu_T *parent = menu->parent; - - menu->submenu_id = CreatePopupMenu(); - menu->id = s_menu_id++; - - if (menu_is_menubar(menu->name)) - { - InsertMenu((parent == NULL) ? s_menuBar : parent->submenu_id, - (UINT)pos, MF_POPUP | MF_STRING | MF_BYPOSITION, - (UINT)menu->submenu_id, menu->name); - } - - /* Fix window size if menu may have wrapped */ - if (parent == NULL) - gui_mswin_get_menu_height(!gui.starting); -} - - void -gui_mch_show_popupmenu(vimmenu_T *menu) -{ - POINT mp; - - (void)GetCursorPos((LPPOINT)&mp); - gui_mch_show_popupmenu_at(menu, (int)mp.x, (int)mp.y); -} - - void -gui_make_popup(char_u *path_name, int mouse_pos) -{ - vimmenu_T *menu = gui_find_menu(path_name); - - if (menu != NULL) - { - /* Find the position of the current cursor */ - DWORD temp_p; - POINT p; - temp_p = GetDCOrg(s_hdc); - p.x = LOWORD(temp_p); - p.y = HIWORD(temp_p); - if (mouse_pos) - { - int mx, my; - - gui_mch_getmouse(&mx, &my); - p.x += mx; - p.y += my; - } - else if (curwin != NULL) - { - p.x += TEXT_X(W_WINCOL(curwin) + curwin->w_wcol + 1); - p.y += TEXT_Y(W_WINROW(curwin) + curwin->w_wrow + 1); - } - msg_scroll = FALSE; - gui_mch_show_popupmenu_at(menu, (int)p.x, (int)p.y); - } -} - -/* - * Add a menu item to a menu - */ - void -gui_mch_add_menu_item( - vimmenu_T *menu, - int idx) -{ - vimmenu_T *parent = menu->parent; - - menu->id = s_menu_id++; - menu->submenu_id = NULL; - -#ifdef FEAT_TOOLBAR - if (menu_is_toolbar(parent->name)) - { - TBBUTTON newtb; - - vim_memset(&newtb, 0, sizeof(newtb)); - if (menu_is_separator(menu->name)) - { - newtb.iBitmap = 0; - newtb.fsStyle = TBSTYLE_SEP; - } - else - { - if (menu->iconidx >= TOOLBAR_BITMAP_COUNT) - newtb.iBitmap = -1; - else - newtb.iBitmap = menu->iconidx; - newtb.fsStyle = TBSTYLE_BUTTON; - } - newtb.idCommand = menu->id; - newtb.fsState = TBSTATE_ENABLED; - SendMessage(s_toolbarhwnd, TB_INSERTBUTTON, (WPARAM)idx, - (LPARAM)&newtb); - menu->submenu_id = (HMENU)-1; - } - else -#endif - { - InsertMenu(parent->submenu_id, (UINT)idx, - (menu_is_separator(menu->name) ? MF_SEPARATOR : MF_STRING) - | MF_BYPOSITION, - (UINT)menu->id, menu->name); - } -} - -/* - * Destroy the machine specific menu widget. - */ - void -gui_mch_destroy_menu(vimmenu_T *menu) -{ - UINT i, j; - char pants[80]; /*<VN> hack*/ -#ifdef FEAT_TOOLBAR - /* - * is this a toolbar button? - */ - if (menu->submenu_id == (HMENU)-1) - { - int iButton; - - iButton = SendMessage(s_toolbarhwnd, TB_COMMANDTOINDEX, (WPARAM)menu->id, 0); - SendMessage(s_toolbarhwnd, TB_DELETEBUTTON, (WPARAM)iButton, 0); - } - else -#endif - { - /* - * negri: horrible API bug when running 16-bit programs under Win9x or - * NT means that we can't use MF_BYCOMMAND for menu items which have - * submenus, including the top-level headings. We have to find the menu - * item and use MF_BYPOSITION instead. :-p - */ - if (menu->parent != NULL - && menu_is_popup(menu->parent->dname) - && menu->parent->submenu_id != NULL) - RemoveMenu(menu->parent->submenu_id, menu->id, MF_BYCOMMAND); - else if (menu->submenu_id == NULL) - RemoveMenu(s_menuBar, menu->id, MF_BYCOMMAND); - else if (menu->parent != NULL) - { - i = GetMenuItemCount(menu->parent->submenu_id); - for (j = 0; j < i; ++j) - { - GetMenuString(menu->parent->submenu_id, j, - pants, 80, MF_BYPOSITION); - if (strcmp(pants, menu->name) == 0) - { - RemoveMenu(menu->parent->submenu_id, j, MF_BYPOSITION); - break; - } - } - } - else - { - i = GetMenuItemCount(s_menuBar); - for (j = 0; j < i; ++j) - { - GetMenuString(s_menuBar, j, pants, 80, MF_BYPOSITION); - if (strcmp(pants, menu->name) == 0) - { - RemoveMenu(s_menuBar, j, MF_BYPOSITION); - break; - } - } - } - - if (menu->submenu_id != NULL) - DestroyMenu(menu->submenu_id); - } - DrawMenuBar(s_hwnd); -} - - -/* - * Make a menu either grey or not grey. - */ - void -gui_mch_menu_grey( - vimmenu_T *menu, - int grey) -{ -#ifdef FEAT_TOOLBAR - /* - * is this a toolbar button? - */ - if (menu->submenu_id == (HMENU)-1) - { - SendMessage(s_toolbarhwnd, TB_ENABLEBUTTON, - (WPARAM)menu->id, (LPARAM) MAKELONG((grey ? FALSE : TRUE), 0) ); - } - else -#endif - if (grey) - EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_GRAYED); - else - EnableMenuItem(s_menuBar, menu->id, MF_BYCOMMAND | MF_ENABLED); - -} - - -#endif /*FEAT_MENU*/ - - -/* define some macros used to make the dialogue creation more readable */ - -#define add_string(s) strcpy((LPSTR)p, s); (LPSTR)p += (strlen((LPSTR)p) + 1) -#define add_word(x) *p++ = (x) -#define add_byte(x) *((LPSTR)p)++ = (x) -#define add_long(x) *((LPDWORD)p)++ = (x) - -#if defined(FEAT_GUI_DIALOG) || defined(PROTO) -/* - * stuff for dialogs - */ - -/* - * The callback routine used by all the dialogs. Very simple. First, - * acknowledges the INITDIALOG message so that Windows knows to do standard - * dialog stuff (Return = default, Esc = cancel....) Second, if a button is - * pressed, return that button's ID - IDCANCEL (2), which is the button's - * number. - */ - static BOOL CALLBACK -dialog_callback( - HWND hwnd, - UINT message, - WPARAM wParam, - LPARAM lParam) -{ - if (message == WM_INITDIALOG) - { - CenterWindow(hwnd, GetWindow(hwnd, GW_OWNER)); - /* Set focus to the dialog. Set the default button, if specified. */ - (void)SetFocus(hwnd); - if (dialog_default_button > IDCANCEL) - (void)SetFocus(GetDlgItem(hwnd, dialog_default_button)); -// if (dialog_default_button > 0) -// (void)SetFocus(GetDlgItem(hwnd, dialog_default_button + IDCANCEL)); - return FALSE; - } - - if (message == WM_COMMAND) - { - int button = LOWORD(wParam); - - /* Don't end the dialog if something was selected that was - * not a button. - */ - if (button >= DLG_NONBUTTON_CONTROL) - return TRUE; - - /* If the edit box exists, copy the string. */ - if (s_textfield != NULL) - GetDlgItemText(hwnd, DLG_NONBUTTON_CONTROL + 2, - s_textfield, IOSIZE); - - /* - * Need to check for IDOK because if the user just hits Return to - * accept the default value, some reason this is what we get. - */ - if (button == IDOK) - EndDialog(hwnd, dialog_default_button); - else - EndDialog(hwnd, button - IDCANCEL); - return TRUE; - } - - if ((message == WM_SYSCOMMAND) && (wParam == SC_CLOSE)) - { - EndDialog(hwnd, 0); - return TRUE; - } - return FALSE; -} - -/* - * Create a dialog dynamically from the parameter strings. - * type = type of dialog (question, alert, etc.) - * title = dialog title. may be NULL for default title. - * message = text to display. Dialog sizes to accommodate it. - * buttons = '\n' separated list of button captions, default first. - * dfltbutton = number of default button. - * - * This routine returns 1 if the first button is pressed, - * 2 for the second, etc. - * - * 0 indicates Esc was pressed. - * -1 for unexpected error - * - * If stubbing out this fn, return 1. - */ - -static const char_u dlg_icons[] = /* must match names in resource file */ -{ - IDR_VIM, - IDR_VIM_ERROR, - IDR_VIM_ALERT, - IDR_VIM_INFO, - IDR_VIM_QUESTION -}; - - int -gui_mch_dialog( - int type, - char_u *title, - char_u *message, - char_u *buttons, - int dfltbutton, - char_u *textfield, - int ex_cmd) -{ - FARPROC dp; - LPWORD p, pnumitems; - int numButtons; - int *buttonWidths, *buttonPositions; - int buttonYpos; - int nchar, i; - DWORD lStyle; - int dlgwidth = 0; - int dlgheight; - int editboxheight; - int horizWidth; - int msgheight; - char_u *pstart; - char_u *pend; - char_u *tbuffer; - RECT rect; - HWND hwnd; - HDC hdc; - HFONT oldFont; - TEXTMETRIC fontInfo; - int fontHeight; - int textWidth, minButtonWidth, messageWidth; - int maxDialogWidth; - int vertical; - int dlgPaddingX; - int dlgPaddingY; - HGLOBAL hglbDlgTemp; - -#ifndef NO_CONSOLE - /* Don't output anything in silent mode ("ex -s") */ - if (silent_mode) - return dfltbutton; /* return default option */ -#endif - - /* If there is no window yet, open it. */ - if (s_hwnd == NULL && gui_mch_init() == FAIL) - return dfltbutton; - - if ((type < 0) || (type > VIM_LAST_TYPE)) - type = 0; - - /* allocate some memory for dialog template */ - /* TODO should compute this really*/ - - hglbDlgTemp = GlobalAlloc(GHND, DLG_ALLOC_SIZE); - if (hglbDlgTemp == NULL) - return -1; - - p = (LPWORD) GlobalLock(hglbDlgTemp); - - if (p == NULL) - return -1; - - /* - * make a copy of 'buttons' to fiddle with it. compiler grizzles because - * vim_strsave() doesn't take a const arg (why not?), so cast away the - * const. - */ - tbuffer = vim_strsave(buttons); - if (tbuffer == NULL) - return -1; - - --dfltbutton; /* Change from one-based to zero-based */ - - /* Count buttons */ - numButtons = 1; - for (i = 0; tbuffer[i] != '\0'; i++) - { - if (tbuffer[i] == DLG_BUTTON_SEP) - numButtons++; - } - if (dfltbutton >= numButtons) - dfltbutton = 0; - - /* Allocate array to hold the width of each button */ - buttonWidths = (int *) lalloc(numButtons * sizeof(int), TRUE); - if (buttonWidths == NULL) - return -1; - - /* Allocate array to hold the X position of each button */ - buttonPositions = (int *) lalloc(numButtons * sizeof(int), TRUE); - if (buttonPositions == NULL) - return -1; - - /* - * Calculate how big the dialog must be. - */ - hwnd = GetDesktopWindow(); - hdc = GetWindowDC(hwnd); - oldFont = SelectFont(hdc, GetStockObject(SYSTEM_FONT)); - dlgPaddingX = DLG_OLD_STYLE_PADDING_X; - dlgPaddingY = DLG_OLD_STYLE_PADDING_Y; - - GetTextMetrics(hdc, &fontInfo); - fontHeight = fontInfo.tmHeight; - - /* Minimum width for horizontal button */ - minButtonWidth = GetTextWidth(hdc, "Cancel", 6); - - /* Maximum width of a dialog, if possible */ - GetWindowRect(s_hwnd, &rect); - maxDialogWidth = rect.right - rect.left - - GetSystemMetrics(SM_CXFRAME) * 2; - if (maxDialogWidth < DLG_MIN_MAX_WIDTH) - maxDialogWidth = DLG_MIN_MAX_WIDTH; - - /* Set dlgwidth to width of message */ - pstart = message; - messageWidth = 0; - msgheight = 0; - do - { - pend = vim_strchr(pstart, DLG_BUTTON_SEP); - if (pend == NULL) - pend = pstart + STRLEN(pstart); /* Last line of message. */ - msgheight += fontHeight; - textWidth = GetTextWidth(hdc, pstart, pend - pstart); - if (textWidth > messageWidth) - messageWidth = textWidth; - pstart = pend + 1; - } while (*pend != NUL); - dlgwidth = messageWidth; - - /* Add width of icon to dlgwidth, and some space */ - dlgwidth += DLG_ICON_WIDTH + 3 * dlgPaddingX; - - if (msgheight < DLG_ICON_HEIGHT) - msgheight = DLG_ICON_HEIGHT; - - /* - * Check button names. A long one will make the dialog wider. - */ - vertical = (vim_strchr(p_go, GO_VERTICAL) != NULL); - if (!vertical) - { - // Place buttons horizontally if they fit. - horizWidth = dlgPaddingX; - pstart = tbuffer; - i = 0; - do - { - pend = vim_strchr(pstart, DLG_BUTTON_SEP); - if (pend == NULL) - pend = pstart + STRLEN(pstart); // Last button name. - textWidth = GetTextWidth(hdc, pstart, pend - pstart); - if (textWidth < minButtonWidth) - textWidth = minButtonWidth; - textWidth += dlgPaddingX; /* Padding within button */ - buttonWidths[i] = textWidth; - buttonPositions[i++] = horizWidth; - horizWidth += textWidth + dlgPaddingX; /* Pad between buttons */ - pstart = pend + 1; - } while (*pend != NUL); - - if (horizWidth > maxDialogWidth) - vertical = TRUE; // Too wide to fit on the screen. - else if (horizWidth > dlgwidth) - dlgwidth = horizWidth; - } - - if (vertical) - { - // Stack buttons vertically. - pstart = tbuffer; - do - { - pend = vim_strchr(pstart, DLG_BUTTON_SEP); - if (pend == NULL) - pend = pstart + STRLEN(pstart); // Last button name. - textWidth = GetTextWidth(hdc, pstart, pend - pstart); - textWidth += dlgPaddingX; /* Padding within button */ - textWidth += DLG_VERT_PADDING_X * 2; /* Padding around button */ - if (textWidth > dlgwidth) - dlgwidth = textWidth; - pstart = pend + 1; - } while (*pend != NUL); - } - - if (dlgwidth < DLG_MIN_WIDTH) - dlgwidth = DLG_MIN_WIDTH; /* Don't allow a really thin dialog!*/ - - /* start to fill in the dlgtemplate information. addressing by WORDs */ - lStyle = DS_MODALFRAME | WS_CAPTION | WS_VISIBLE ; - - add_long(lStyle); - pnumitems = p; /*save where the number of items must be stored*/ - add_byte(0); // NumberOfItems(will change later) - add_word(10); // x - add_word(10); // y - add_word(PixelToDialogX(dlgwidth)); - - // Dialog height. - if (vertical) - dlgheight = msgheight + 2 * dlgPaddingY + - DLG_VERT_PADDING_Y + 2 * fontHeight * numButtons; - else - dlgheight = msgheight + 3 * dlgPaddingY + 2 * fontHeight; - - // Dialog needs to be taller if contains an edit box. - editboxheight = fontHeight + dlgPaddingY + 4 * DLG_VERT_PADDING_Y; - if (textfield != NULL) - dlgheight += editboxheight; - - add_word(PixelToDialogY(dlgheight)); - - add_byte(0); //menu - add_byte(0); //class - - /* copy the title of the dialog */ - add_string(title ? title : ("Vim"VIM_VERSION_MEDIUM)); - - buttonYpos = msgheight + 2 * dlgPaddingY; - - if (textfield != NULL) - buttonYpos += editboxheight; - - pstart = tbuffer; //dflt_text - horizWidth = (dlgwidth - horizWidth) / 2; /* Now it's X offset */ - for (i = 0; i < numButtons; i++) - { - /* get end of this button. */ - for ( pend = pstart; - *pend && (*pend != DLG_BUTTON_SEP); - pend++) - ; - - if (*pend) - *pend = '\0'; - - /* - * NOTE: - * setting the BS_DEFPUSHBUTTON style doesn't work because Windows sets - * the focus to the first tab-able button and in so doing makes that - * the default!! Grrr. Workaround: Make the default button the only - * one with WS_TABSTOP style. Means user can't tab between buttons, but - * he/she can use arrow keys. - * - * NOTE (Thore): Setting BS_DEFPUSHBUTTON works fine when it's the - * first one, so I changed the correct button to be this style. This - * is necessary because when an edit box is added, we need a button to - * be default. The edit box will be the default control, and when the - * user presses enter from the edit box we want the default button to - * be pressed. - */ - if (vertical) - { - p = add_dialog_element(p, - ((i == dfltbutton || dfltbutton < 0) && textfield != NULL - ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP, - PixelToDialogX(DLG_VERT_PADDING_X), - PixelToDialogY(buttonYpos /* TBK */ - + 2 * fontHeight * i), - PixelToDialogX(dlgwidth - 2 * DLG_VERT_PADDING_X), - (WORD)(PixelToDialogY(2 * fontHeight) - 1), - (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart); - } - else - { - p = add_dialog_element(p, - ((i == dfltbutton || dfltbutton < 0) && textfield != NULL - ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON) | WS_TABSTOP, - PixelToDialogX(horizWidth + buttonPositions[i]), - PixelToDialogY(buttonYpos), /* TBK */ - PixelToDialogX(buttonWidths[i]), - (WORD)(PixelToDialogY(2 * fontHeight) - 1), - (WORD)(IDCANCEL + 1 + i), (BYTE)0x80, pstart); - } - - pstart = pend + 1; /*next button*/ - - } - *pnumitems += numButtons; - - /* Vim icon */ - p = add_dialog_element(p, SS_ICON, - PixelToDialogX(dlgPaddingX), - PixelToDialogY(dlgPaddingY), - PixelToDialogX(DLG_ICON_WIDTH), - PixelToDialogY(DLG_ICON_HEIGHT), - DLG_NONBUTTON_CONTROL + 0, (BYTE)0x82, - &dlg_icons[type]); - - - /* Dialog message */ - p = add_dialog_element(p, SS_LEFT, - PixelToDialogX(2 * dlgPaddingX + DLG_ICON_WIDTH), - PixelToDialogY(dlgPaddingY), - (WORD)(PixelToDialogX(messageWidth) + 1), - PixelToDialogY(msgheight), - DLG_NONBUTTON_CONTROL + 1, (BYTE)0x82, message); - - /* Edit box */ - if (textfield != NULL) - { - p = add_dialog_element(p, ES_LEFT | ES_AUTOHSCROLL | WS_TABSTOP | WS_BORDER, - PixelToDialogX(2 * dlgPaddingX), - PixelToDialogY(2 * dlgPaddingY + msgheight), - PixelToDialogX(dlgwidth - 4 * dlgPaddingX), - PixelToDialogY(fontHeight + dlgPaddingY), - DLG_NONBUTTON_CONTROL + 2, (BYTE)0x81, textfield); - *pnumitems += 1; - } - - *pnumitems += 2; - - SelectFont(hdc, oldFont); - ReleaseDC(hwnd, hdc); - dp = MakeProcInstance((FARPROC)dialog_callback, s_hinst); - - - /* Let the dialog_callback() function know which button to make default - * If we have an edit box, make that the default. We also need to tell - * dialog_callback() if this dialog contains an edit box or not. We do - * this by setting s_textfield if it does. - */ - if (textfield != NULL) - { - dialog_default_button = DLG_NONBUTTON_CONTROL + 2; - s_textfield = textfield; - } - else - { - dialog_default_button = IDCANCEL + 1 + dfltbutton; - s_textfield = NULL; - } - - /*show the dialog box modally and get a return value*/ - nchar = DialogBoxIndirect( - s_hinst, - (HGLOBAL) hglbDlgTemp, - s_hwnd, - (DLGPROC)dp); - - FreeProcInstance( dp ); - GlobalUnlock(hglbDlgTemp); - GlobalFree(hglbDlgTemp); - vim_free(tbuffer); - vim_free(buttonWidths); - vim_free(buttonPositions); - - - return nchar; -} - -/* - * Put a simple element (basic class) onto a dialog template in memory. - * return a pointer to where the next item should be added. - * - * parameters: - * lStyle = additional style flags - * x,y = x & y positions IN DIALOG UNITS - * w,h = width and height IN DIALOG UNITS - * Id = ID used in messages - * clss = class ID, e.g 0x80 for a button, 0x82 for a static - * caption = usually text or resource name - * - * TODO: use the length information noted here to enable the dialog creation - * routines to work out more exactly how much memory they need to alloc. - */ - static LPWORD -add_dialog_element( - LPWORD p, - DWORD lStyle, - WORD x, - WORD y, - WORD w, - WORD h, - WORD Id, - BYTE clss, - const char *caption) -{ - - lStyle = lStyle | WS_VISIBLE | WS_CHILD; - - add_word(x); - add_word(y); - add_word(w); - add_word(h); - add_word(Id); - add_long(lStyle); - add_byte(clss); - if (((lStyle & SS_ICON) != 0) && (clss == 0x82)) - { - /* Use resource ID */ - add_byte(0xff); - add_byte(*caption); - } - else - add_string(caption); - - add_byte(0); //# of extra bytes following - - - return p; -} - -#undef add_byte -#undef add_string -#undef add_long -#undef add_word - -#endif /* FEAT_GUI_DIALOG */ - - static void -get_dialog_font_metrics(void) -{ - DWORD dlgFontSize; - dlgFontSize = GetDialogBaseUnits(); /* fall back to big old system*/ - s_dlgfntwidth = LOWORD(dlgFontSize); - s_dlgfntheight = HIWORD(dlgFontSize); -} - - -#if defined(FEAT_TOOLBAR) || defined(PROTO) - -/* cproto fails on missing include files */ -#ifndef PROTO -# include "gui_w3~1.h" -#endif - -/* - * Create the toolbar, initially unpopulated. - * (just like the menu, there are no defaults, it's all - * set up through menu.vim) - */ - static void -initialise_toolbar(void) -{ - s_toolbarhwnd = CreateToolbar( - s_hwnd, - WS_CHILD | WS_VISIBLE, - CMD_TB_BASE, /*<vn>*/ - 31, //number of images in initial bitmap - s_hinst, - IDR_TOOLBAR1, // id of initial bitmap - NULL, - 0 // initial number of buttons - ); - - gui_mch_show_toolbar(vim_strchr(p_go, GO_TOOLBAR) != NULL); -} -#endif - -#if defined(FEAT_OLE) || defined(FEAT_EVAL) || defined(PROTO) -/* - * Make the GUI window come to the foreground. - */ - void -gui_mch_set_foreground(void) -{ - if (IsIconic(s_hwnd)) - SendMessage(s_hwnd, WM_SYSCOMMAND, SC_RESTORE, 0); - SetActiveWindow(s_hwnd); -} -#endif
--- a/src/gui_w32.c +++ b/src/gui_w32.c @@ -10,7 +10,7 @@ /* * Windows GUI. * - * GUI support for Microsoft Windows. Win32 initially; maybe Win16 later + * GUI support for Microsoft Windows, aka Win32. Also for Win64. * * George V. Reilly <george@reilly.org> wrote the original Win32 GUI. * Robert Webb reworked it to use the existing GUI stuff and added menu, @@ -185,10 +185,4095 @@ gui_mch_set_rendering_options(char_u *s) ((fn)((hwnd), TRUE, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L) #endif -/* - * Include the common stuff for MS-Windows GUI. - */ -#include "gui_w48.c" + +#include "version.h" /* used by dialog box routine for default title */ +#ifdef DEBUG +# include <tchar.h> +#endif + +/* cproto fails on missing include files */ +#ifndef PROTO + +#ifndef __MINGW32__ +# include <shellapi.h> +#endif +#if defined(FEAT_TOOLBAR) || defined(FEAT_BEVAL) || defined(FEAT_GUI_TABLINE) +# include <commctrl.h> +#endif +#include <windowsx.h> + +#ifdef GLOBAL_IME +# include "glbl_ime.h" +#endif + +#endif /* PROTO */ + +#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; +typedef int WNDPROC; +#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 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; +static WNDPROC s_toolbar_wndproc = NULL; +#endif + +#ifdef FEAT_GUI_TABLINE +static HWND s_tabhwnd = NULL; +static WNDPROC s_tabline_wndproc = 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(HWND hwnd, LPNMHDR pnmh); +static void TrackUserActivity(UINT uMsg); +#endif + +/* + * For control IME. + * + * These LOGFONT used for IME. + */ +#ifdef FEAT_MBYTE +# ifdef USE_IM_CONTROL +/* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */ +static LOGFONT norm_logfont; +/* holds LOGFONT for 'guifont' always. */ +static LOGFONT sub_logfont; +# endif +#endif + +#ifdef FEAT_MBYTE_IME +static LRESULT _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData); +#endif + +#if defined(FEAT_BROWSE) +static char_u *convert_filter(char_u *s); +#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 (pPeekMessage(&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 (pPeekMessage(&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 (pPeekMessage(&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, (LPCSTR)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, + (LPSTR)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, + (LPSTR)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; + + dead_key = 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 */ + + dead_key = 0; + + /* 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; + 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; + } + 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((char_u *)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((short_u*)lpfrw->lpstrFindWhat, NULL); + vim_strncpy((char_u *)lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1); + vim_free(p); + + p = utf16_to_enc((short_u*)lpfrw->lpstrReplaceWith, NULL); + vim_strncpy((char_u *)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, (char_u *)s_findrep_struct.lpstrFindWhat, + (char_u *)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 || uMsg == WM_NCMOUSEMOVE) + { + 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); + HANDLE_MSG(hwnd, WM_XBUTTONDBLCLK,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_XBUTTONDOWN,_OnMouseButtonDown); + HANDLE_MSG(hwnd, WM_XBUTTONUP, _OnMouseMoveOrRelease); + +#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(void) +{ + 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 + * forcedly redrawn. (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 + p_linespace; + + 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(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(0xA9, 0xA9, 0xA9)}, + {"DarkGrey", RGB(0xA9, 0xA9, 0xA9)}, + {"Gray", RGB(0xC0, 0xC0, 0xC0)}, + {"Grey", RGB(0xC0, 0xC0, 0xC0)}, + {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, + {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, + {"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(0xAD, 0xD8, 0xE6)}, + {"DarkGreen", RGB(0x00, 0x80, 0x00)}, + {"Green", RGB(0x00, 0xFF, 0x00)}, + {"LightGreen", RGB(0x90, 0xEE, 0x90)}, + {"DarkCyan", RGB(0x00, 0x80, 0x80)}, + {"Cyan", RGB(0x00, 0xFF, 0xFF)}, + {"LightCyan", RGB(0xE0, 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, 0xE0)}, + {"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); +} + + +/* + * Generates a VK_SPACE when the internal dead_key flag is set to output the + * dead key's nominal character and re-post the original message. + */ + static void +outputDeadKey_rePost(MSG originalMsg) +{ + static MSG deadCharExpel; + + if (!dead_key) + return; + + dead_key = 0; + + /* Make Windows generate the dead key's character */ + deadCharExpel.message = originalMsg.message; + deadCharExpel.hwnd = originalMsg.hwnd; + deadCharExpel.wParam = VK_SPACE; + + MyTranslateMessage(&deadCharExpel); + + /* re-generate the current character free of the dead char influence */ + PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam, + originalMsg.lParam); +} + + +/* + * 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 + + pGetMessage(&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 */ + pDispatchMessage(&msg); + } + else + { + add_to_input_buf(str, (int)STRLEN(str)); + vim_free(str); /* was allocated in CVim::SendKeys() */ + } + return; + } +#endif + +#ifdef FEAT_CHANNEL + if (msg.message == WM_NETBEANS) + { + int what; + channel_T *channel = channel_fd2channel((sock_T)msg.wParam, &what); + + if (channel != NULL) + { + /* Disable error messages, they can mess up the display and throw + * an exception. */ + ++emsg_off; + channel_read(channel, what, "process_message"); + --emsg_off; + } + 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); + pDispatchMessage(&msg); + return; + } +#endif + +#ifdef MSWIN_FIND_REPLACE + /* Don't process messages used by the dialog */ + if (s_findrep_hwnd != NULL && pIsDialogMessage(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 dead keys in special conditions in other cases we let Windows + * handle them and do not interfere. + * + * The dead_key flag must be reset on several occasions: + * - in _OnChar() (or _OnSysChar()) as any dead key was necessarily + * consumed at that point (This is when we let Windows combine the + * dead character on its own) + * + * - Before doing something special such as regenerating keypresses to + * expel the dead character as this could trigger an infinite loop if + * for some reason MyTranslateMessage() do not trigger a call + * immediately to _OnChar() (or _OnSysChar()). + */ + if (dead_key) + { + /* + * If a dead key was pressed and the user presses VK_SPACE, + * VK_BACK, or VK_ESCAPE it means that he actually wants to deal + * with the dead char now, so do nothing special and let Windows + * handle it. + * + * Note that VK_SPACE combines with the dead_key's character and + * only one WM_CHAR will be generated by TranslateMessage(), in + * the two other cases two WM_CHAR will be generated: the dead + * char and VK_BACK or VK_ESCAPE. That is most likely what the + * user expects. + */ + if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) + { + dead_key = 0; + MyTranslateMessage(&msg); + return; + } + /* In modes where we are not typing, dead keys should behave + * normally */ + else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE))) + { + outputDeadKey_rePost(msg); + 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))) + { + /* + * Behave as exected if we have a dead key and the special key + * is a key that would normally trigger the dead key nominal + * character output (such as a NUMPAD printable character or + * the TAB key, etc...). + */ + if (dead_key && (special_keys[i].vim_code0 == 'K' + || vk == VK_TAB || vk == CAR)) + { + outputDeadKey_rePost(msg); + return; + } + +#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 + pDispatchMessage(&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 (pPeekMessage(&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 MESSAGE_QUEUE + parse_queued_messages(); +#endif + +#ifdef FEAT_CHANNEL + channel_handle_events(); +#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 (pPeekMessage(&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, (LPCSTR)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)) + SystemParametersInfo(SPI_GETWORKAREA, 0, &rParent, 0); + 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 = (LPTSTR)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; + + if (first_tabpage->tp_next != NULL) + add_tabline_popup_menu_entry(tab_pmenu, + TABLINE_MENU_CLOSE, (char_u *)_("Close tab")); + add_tabline_popup_menu_entry(tab_pmenu, + TABLINE_MENU_NEW, (char_u *)_("New tab")); + add_tabline_popup_menu_entry(tab_pmenu, + TABLINE_MENU_OPEN, (char_u *)_("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; + int tabadded = 0; +#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; + + /* Disable redraw for tab updates to eliminate O(N^2) draws. */ + SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)FALSE, 0); + + /* 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 (nr >= TabCtrl_GetItemCount(s_tabhwnd)) + { + /* Add the tab */ + tie.pszText = "-Empty-"; + TabCtrl_InsertItem(s_tabhwnd, nr, &tie); + tabadded = 1; + } + + get_tabline_label(tp, FALSE); + tie.pszText = (LPSTR)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 (nr < TabCtrl_GetItemCount(s_tabhwnd)) + TabCtrl_DeleteItem(s_tabhwnd, nr); + + if (!tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx) + TabCtrl_SetCurSel(s_tabhwnd, curtabidx); + + /* Re-enable redraw and redraw. */ + SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)TRUE, 0); + RedrawWindow(s_tabhwnd, NULL, NULL, + RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); + + if (tabadded && 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(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((char_u *)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) +{ + 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); +#if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_BeginDraw(s_dwc); +#endif + +#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)) + { +#if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_BindDC(s_dwc, s_hdc, &ps.rcPaint); +#endif + gui_redraw(ps.rcPaint.left, ps.rcPaint.top, + ps.rcPaint.right - ps.rcPaint.left + 1, + ps.rcPaint.bottom - ps.rcPaint.top + 1); + } + +#if defined(FEAT_DIRECTX) + if (IS_ENABLE_DIRECTX()) + DWriteContext_EndDraw(s_dwc); +#endif + 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 + */ + static LRESULT +_OnActivateApp( + HWND hwnd, + BOOL fActivate, + DWORD dwThreadId) +{ + /* 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) + + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2; + base_height = gui_get_base_height() + + (GetSystemMetrics(SM_CYFRAME) + + GetSystemMetrics(SM_CXPADDEDBORDER)) * 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; +} + +/* + * On some Intel GPUs, the regions drawn just prior to ScrollWindowEx() + * may not be scrolled out properly. + * For gVim, when _OnScroll() is repeated, the character at the + * previous cursor position may be left drawn after scroll. + * The problem can be avoided by calling GetPixel() to get a pixel in + * the region before ScrollWindowEx(). + */ + static void +intel_gpu_workaround(void) +{ + GetPixel(s_hdc, FILL_X(gui.col), FILL_Y(gui.row)); +} + +/* + * 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; + + intel_gpu_workaround(); + + 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; + + intel_gpu_workaround(); + + 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) +{ +#if defined(FEAT_DIRECTX) + DWriteContext_Close(s_dwc); + DWrite_Final(); + s_dwc = NULL; +#endif + + 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; + char *font_name = lf.lfFaceName; + + charset_name = charset_id2name((int)lf.lfCharSet); +#ifdef FEAT_MBYTE + /* Convert a font name from the current codepage to 'encoding'. + * TODO: Use Wide APIs (including LOGFONTW) instead of ANSI APIs. */ + if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) + { + int len; + acp_to_enc((char_u *)lf.lfFaceName, (int)strlen(lf.lfFaceName), + (char_u **)&font_name, &len); + } +#endif + res = (char *)alloc((unsigned)(strlen(font_name) + 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", font_name, pixels_to_points( + lf.lfHeight < 0 ? -lf.lfHeight : lf.lfHeight, TRUE)); + while (*p) + { + if (*p == ' ') + *p = '_'; + ++p; + } + if (lf.lfItalic) + STRCAT(p, ":i"); + if (lf.lfWeight >= FW_BOLD) + STRCAT(p, ":b"); + if (lf.lfUnderline) + STRCAT(p, ":u"); + if (lf.lfStrikeOut) + STRCAT(p, ":s"); + if (charset_name != NULL) + { + STRCAT(p, ":c"); + STRCAT(p, charset_name); + } + } + +#ifdef FEAT_MBYTE + if (font_name != lf.lfFaceName) + vim_free(font_name); +#endif + return (char_u *)res; +} + + +#ifdef FEAT_MBYTE_IME +/* + * Set correct LOGFONT to IME. Use 'guifontwide' if available, otherwise use + * 'guifont' + */ + static void +update_im_font(void) +{ + LOGFONT lf_wide; + + if (p_guifontwide != NULL && *p_guifontwide != NUL + && gui.wide_font != NOFONT + && GetObject((HFONT)gui.wide_font, sizeof(lf_wide), &lf_wide)) + norm_logfont = lf_wide; + else + norm_logfont = sub_logfont; + im_set_font(&norm_logfont); +} +#endif + +#ifdef FEAT_MBYTE +/* + * Handler of gui.wide_font (p_guifontwide) changed notification. + */ + void +gui_mch_wide_font_changed(void) +{ + LOGFONT lf; + +# ifdef FEAT_MBYTE_IME + update_im_font(); +# endif + + gui_mch_free_font(gui.wide_ital_font); + gui.wide_ital_font = NOFONT; + gui_mch_free_font(gui.wide_bold_font); + gui.wide_bold_font = NOFONT; + gui_mch_free_font(gui.wide_boldital_font); + gui.wide_boldital_font = NOFONT; + + if (gui.wide_font + && GetObject((HFONT)gui.wide_font, sizeof(lf), &lf)) + { + if (!lf.lfItalic) + { + lf.lfItalic = TRUE; + gui.wide_ital_font = get_font_handle(&lf); + lf.lfItalic = FALSE; + } + if (lf.lfWeight < FW_BOLD) + { + lf.lfWeight = FW_BOLD; + gui.wide_bold_font = get_font_handle(&lf); + if (!lf.lfItalic) + { + lf.lfItalic = TRUE; + gui.wide_boldital_font = get_font_handle(&lf); + } + } + } +} +#endif + +/* + * 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 = (char_u *)lf.lfFaceName; +#if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME) + norm_logfont = lf; + sub_logfont = lf; +#endif +#ifdef FEAT_MBYTE_IME + update_im_font(); +#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); + } + + 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); + } + } + + 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(void) +{ + 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(void) +{ + RECT rect; + + GetWindowRect(s_hwnd, &rect); + if (win_socket_id == 0) + { + gui_resize_shell(rect.right - rect.left + - (GetSystemMetrics(SM_CXFRAME) + + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2, + rect.bottom - rect.top + - (GetSystemMetrics(SM_CYFRAME) + + GetSystemMetrics(SM_CXPADDEDBORDER)) * 2 + - GetSystemMetrics(SM_CYCAPTION) +#ifdef FEAT_MENU + - gui_mswin_get_menu_height(FALSE) +#endif + ); + } + else + { + /* Inside another window, don't use the frame and border. */ + gui_resize_shell(rect.right - rect.left, + rect.bottom - rect.top +#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[] = +{ + IDC_ARROW, /* arrow */ + MAKEINTRESOURCE(0), /* blank */ + IDC_IBEAM, /* beam */ + IDC_SIZENS, /* updown */ + IDC_SIZENS, /* udsizing */ + IDC_SIZEWE, /* leftright */ + IDC_SIZEWE, /* lrsizing */ + IDC_WAIT, /* busy */ +#ifdef WIN3264 + IDC_NO, /* no */ +#else + IDC_ICON, /* no */ +#endif + IDC_ARROW, /* crosshair */ + IDC_ARROW, /* hand1 */ + IDC_ARROW, /* hand2 */ + IDC_ARROW, /* pencil */ + IDC_ARROW, /* question */ + IDC_ARROW, /* right-arrow */ + IDC_UPARROW, /* up-arrow */ + 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 = 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(). + */ + static WCHAR * +convert_filterW(char_u *s) +{ + char_u *tmp; + int len; + WCHAR *res; + + tmp = convert_filter(s); + if (tmp == NULL) + return NULL; + len = (int)STRLEN(s) + 3; + res = enc_to_utf16(tmp, &len); + vim_free(tmp); + 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 = (LPSTR)title; + fileStruct.lpstrDefExt = (LPSTR)ext; + + fileStruct.lpstrFile = (LPSTR)fileBuf; + fileStruct.nMaxFile = MAXPATHL; + fileStruct.lpstrFilter = (LPSTR)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 = (LPSTR)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); + + reset_VIsual(); + + 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((char_u *)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; +} #ifdef FEAT_XPM_W32 # include "xpm_w32.h" @@ -1692,10 +5777,6 @@ gui_mch_init(void) #endif s_hdc = GetDC(s_textArea); -#ifdef MSWIN16_FASTTEXT - SetBkMode(s_hdc, OPAQUE); -#endif - #ifdef FEAT_WINDOWS DragAcceptFiles(s_hwnd, TRUE); #endif @@ -2410,7 +6491,6 @@ gui_mch_draw_string( int font_is_ttf_or_vector = 0; #endif -#ifndef MSWIN16_FASTTEXT /* * Italic and bold text seems to have an extra row of pixels at the bottom * (below where the bottom of the character should be). If we draw the @@ -2484,15 +6564,6 @@ gui_mch_draw_string( foptions = ETO_CLIPPED; } } -#else - /* - * The alternative would be to write the characters in opaque mode, but - * when the text is not exactly the same proportions as normal text, too - * big or too little a rectangle gets drawn for the background. - */ - SetBkMode(s_hdc, OPAQUE); - SetBkColor(s_hdc, gui.currBgColor); -#endif SetTextColor(s_hdc, gui.currFgColor); SelectFont(s_hdc, gui.currFont); @@ -2677,10 +6748,8 @@ gui_mch_draw_string( /* When p_linespace is 0, overwrite the bottom row of pixels. * Otherwise put the line just below the character. */ y = FILL_Y(row + 1) - 1; -#ifndef MSWIN16_FASTTEXT if (p_linespace > 1) y -= p_linespace - 1; -#endif MoveToEx(s_hdc, FILL_X(col), y, NULL); /* Note: LineTo() excludes the last pixel in the line. */ LineTo(s_hdc, FILL_X(col + len), y);
deleted file mode 100644 --- a/src/gui_w48.c +++ /dev/null @@ -1,4155 +0,0 @@ -/* 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 - -/* cproto fails on missing include files */ -#ifndef PROTO - -#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 - -#endif /* PROTO */ - -#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; -typedef int WNDPROC; -#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 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; -static WNDPROC s_toolbar_wndproc = NULL; -#endif - -#ifdef FEAT_GUI_TABLINE -static HWND s_tabhwnd = NULL; -static WNDPROC s_tabline_wndproc = 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(HWND hwnd, LPNMHDR pnmh); -static void TrackUserActivity(UINT uMsg); -#endif - -/* - * For control IME. - * - * These LOGFONT used for IME. - */ -#ifdef FEAT_MBYTE -# ifdef USE_IM_CONTROL -/* holds LOGFONT for 'guifontwide' if available, otherwise 'guifont' */ -static LOGFONT norm_logfont; -/* holds LOGFONT for 'guifont' always. */ -static LOGFONT sub_logfont; -# endif -#endif - -#ifdef FEAT_MBYTE_IME -static LRESULT _OnImeNotify(HWND hWnd, DWORD dwCommand, DWORD dwData); -#endif - -#if defined(FEAT_BROWSE) -static char_u *convert_filter(char_u *s); -#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 (pPeekMessage(&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 (pPeekMessage(&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 (pPeekMessage(&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, (LPCSTR)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, - (LPSTR)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, - (LPSTR)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; - - dead_key = 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 */ - - dead_key = 0; - - /* 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((char_u *)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((short_u*)lpfrw->lpstrFindWhat, NULL); - vim_strncpy((char_u *)lpfr->lpstrFindWhat, p, lpfr->wFindWhatLen - 1); - vim_free(p); - - p = utf16_to_enc((short_u*)lpfrw->lpstrReplaceWith, NULL); - vim_strncpy((char_u *)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, (char_u *)s_findrep_struct.lpstrFindWhat, - (char_u *)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 || uMsg == WM_NCMOUSEMOVE) - { - 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(void) -{ - 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 - * forcedly redrawn. (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(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(0xA9, 0xA9, 0xA9)}, - {"DarkGrey", RGB(0xA9, 0xA9, 0xA9)}, - {"Gray", RGB(0xC0, 0xC0, 0xC0)}, - {"Grey", RGB(0xC0, 0xC0, 0xC0)}, - {"LightGray", RGB(0xD3, 0xD3, 0xD3)}, - {"LightGrey", RGB(0xD3, 0xD3, 0xD3)}, - {"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(0xAD, 0xD8, 0xE6)}, - {"DarkGreen", RGB(0x00, 0x80, 0x00)}, - {"Green", RGB(0x00, 0xFF, 0x00)}, - {"LightGreen", RGB(0x90, 0xEE, 0x90)}, - {"DarkCyan", RGB(0x00, 0x80, 0x80)}, - {"Cyan", RGB(0x00, 0xFF, 0xFF)}, - {"LightCyan", RGB(0xE0, 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, 0xE0)}, - {"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); -} - - -/* - * Generates a VK_SPACE when the internal dead_key flag is set to output the - * dead key's nominal character and re-post the original message. - */ - static void -outputDeadKey_rePost(MSG originalMsg) -{ - static MSG deadCharExpel; - - if (!dead_key) - return; - - dead_key = 0; - - /* Make Windows generate the dead key's character */ - deadCharExpel.message = originalMsg.message; - deadCharExpel.hwnd = originalMsg.hwnd; - deadCharExpel.wParam = VK_SPACE; - - MyTranslateMessage(&deadCharExpel); - - /* re-generate the current character free of the dead char influence */ - PostMessage(originalMsg.hwnd, originalMsg.message, originalMsg.wParam, - originalMsg.lParam); -} - - -/* - * 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 - - pGetMessage(&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 */ - pDispatchMessage(&msg); - } - else - { - add_to_input_buf(str, (int)STRLEN(str)); - vim_free(str); /* was allocated in CVim::SendKeys() */ - } - return; - } -#endif - -#ifdef FEAT_CHANNEL - if (msg.message == WM_NETBEANS) - { - int what; - channel_T *channel = channel_fd2channel((sock_T)msg.wParam, &what); - - if (channel != NULL) - { - /* Disable error messages, they can mess up the display and throw - * an exception. */ - ++emsg_off; - channel_read(channel, what, "process_message"); - --emsg_off; - } - 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); - pDispatchMessage(&msg); - return; - } -#endif - -#ifdef MSWIN_FIND_REPLACE - /* Don't process messages used by the dialog */ - if (s_findrep_hwnd != NULL && pIsDialogMessage(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 dead keys in special conditions in other cases we let Windows - * handle them and do not interfere. - * - * The dead_key flag must be reset on several occasions: - * - in _OnChar() (or _OnSysChar()) as any dead key was necessarily - * consumed at that point (This is when we let Windows combine the - * dead character on its own) - * - * - Before doing something special such as regenerating keypresses to - * expel the dead character as this could trigger an infinite loop if - * for some reason MyTranslateMessage() do not trigger a call - * immediately to _OnChar() (or _OnSysChar()). - */ - if (dead_key) - { - /* - * If a dead key was pressed and the user presses VK_SPACE, - * VK_BACK, or VK_ESCAPE it means that he actually wants to deal - * with the dead char now, so do nothing special and let Windows - * handle it. - * - * Note that VK_SPACE combines with the dead_key's character and - * only one WM_CHAR will be generated by TranslateMessage(), in - * the two other cases two WM_CHAR will be generated: the dead - * char and VK_BACK or VK_ESCAPE. That is most likely what the - * user expects. - */ - if ((vk == VK_SPACE || vk == VK_BACK || vk == VK_ESCAPE)) - { - dead_key = 0; - MyTranslateMessage(&msg); - return; - } - /* In modes where we are not typing, dead keys should behave - * normally */ - else if (!(get_real_state() & (INSERT | CMDLINE | SELECTMODE))) - { - outputDeadKey_rePost(msg); - 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))) - { - /* - * Behave as exected if we have a dead key and the special key - * is a key that would normally trigger the dead key nominal - * character output (such as a NUMPAD printable character or - * the TAB key, etc...). - */ - if (dead_key && (special_keys[i].vim_code0 == 'K' - || vk == VK_TAB || vk == CAR)) - { - outputDeadKey_rePost(msg); - return; - } - -#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 - pDispatchMessage(&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 (pPeekMessage(&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 MESSAGE_QUEUE - parse_queued_messages(); -#endif - -#ifdef FEAT_CHANNEL - channel_handle_events(); -#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 (pPeekMessage(&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, (LPCSTR)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 = (LPTSTR)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; - - if (first_tabpage->tp_next != NULL) - add_tabline_popup_menu_entry(tab_pmenu, - TABLINE_MENU_CLOSE, (char_u *)_("Close tab")); - add_tabline_popup_menu_entry(tab_pmenu, - TABLINE_MENU_NEW, (char_u *)_("New tab")); - add_tabline_popup_menu_entry(tab_pmenu, - TABLINE_MENU_OPEN, (char_u *)_("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; - int tabadded = 0; -#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; - - /* Disable redraw for tab updates to eliminate O(N^2) draws. */ - SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)FALSE, 0); - - /* 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 (nr >= TabCtrl_GetItemCount(s_tabhwnd)) - { - /* Add the tab */ - tie.pszText = "-Empty-"; - TabCtrl_InsertItem(s_tabhwnd, nr, &tie); - tabadded = 1; - } - - get_tabline_label(tp, FALSE); - tie.pszText = (LPSTR)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 (nr < TabCtrl_GetItemCount(s_tabhwnd)) - TabCtrl_DeleteItem(s_tabhwnd, nr); - - if (!tabadded && TabCtrl_GetCurSel(s_tabhwnd) != curtabidx) - TabCtrl_SetCurSel(s_tabhwnd, curtabidx); - - /* Re-enable redraw and redraw. */ - SendMessage(s_tabhwnd, WM_SETREDRAW, (WPARAM)TRUE, 0); - RedrawWindow(s_tabhwnd, NULL, NULL, - RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); - - if (tabadded && 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(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((char_u *)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); -#if defined(FEAT_DIRECTX) - if (IS_ENABLE_DIRECTX()) - DWriteContext_BeginDraw(s_dwc); -#endif - -#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)) - { -#if defined(FEAT_DIRECTX) - if (IS_ENABLE_DIRECTX()) - DWriteContext_BindDC(s_dwc, s_hdc, &ps.rcPaint); -#endif - gui_redraw(ps.rcPaint.left, ps.rcPaint.top, - ps.rcPaint.right - ps.rcPaint.left + 1, - ps.rcPaint.bottom - ps.rcPaint.top + 1); - } - -#if defined(FEAT_DIRECTX) - if (IS_ENABLE_DIRECTX()) - DWriteContext_EndDraw(s_dwc); -#endif - 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) + - GetSystemMetrics(SM_CXPADDEDBORDER)) * 2; - base_height = gui_get_base_height() - + (GetSystemMetrics(SM_CYFRAME) + - GetSystemMetrics(SM_CXPADDEDBORDER)) * 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; -} - -/* - * On some Intel GPUs, the regions drawn just prior to ScrollWindowEx() - * may not be scrolled out properly. - * For gVim, when _OnScroll() is repeated, the character at the - * previous cursor position may be left drawn after scroll. - * The problem can be avoided by calling GetPixel() to get a pixel in - * the region before ScrollWindowEx(). - */ - static void -intel_gpu_workaround(void) -{ - GetPixel(s_hdc, FILL_X(gui.col), FILL_Y(gui.row)); -} - -/* - * 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; - - intel_gpu_workaround(); - - 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; - - intel_gpu_workaround(); - - 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) -{ -#if defined(FEAT_DIRECTX) - DWriteContext_Close(s_dwc); - DWrite_Final(); - s_dwc = NULL; -#endif - - 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; - char *font_name = lf.lfFaceName; - - charset_name = charset_id2name((int)lf.lfCharSet); -#ifdef FEAT_MBYTE - /* Convert a font name from the current codepage to 'encoding'. - * TODO: Use Wide APIs (including LOGFONTW) instead of ANSI APIs. */ - if (enc_codepage >= 0 && (int)GetACP() != enc_codepage) - { - int len; - acp_to_enc((char_u *)lf.lfFaceName, (int)strlen(lf.lfFaceName), - (char_u **)&font_name, &len); - } -#endif - res = (char *)alloc((unsigned)(strlen(font_name) + 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", font_name, 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); - } - } - -#ifdef FEAT_MBYTE - if (font_name != lf.lfFaceName) - vim_free(font_name); -#endif - return (char_u *)res; -} - - -#ifdef FEAT_MBYTE_IME -/* - * Set correct LOGFONT to IME. Use 'guifontwide' if available, otherwise use - * 'guifont' - */ - static void -update_im_font(void) -{ - LOGFONT lf_wide; - - if (p_guifontwide != NULL && *p_guifontwide != NUL - && gui.wide_font != NOFONT - && GetObject((HFONT)gui.wide_font, sizeof(lf_wide), &lf_wide)) - norm_logfont = lf_wide; - else - norm_logfont = sub_logfont; - im_set_font(&norm_logfont); -} -#endif - -#ifdef FEAT_MBYTE -/* - * Handler of gui.wide_font (p_guifontwide) changed notification. - */ - void -gui_mch_wide_font_changed(void) -{ -# ifndef MSWIN16_FASTTEXT - LOGFONT lf; -# endif - -# ifdef FEAT_MBYTE_IME - update_im_font(); -# endif - -# ifndef MSWIN16_FASTTEXT - gui_mch_free_font(gui.wide_ital_font); - gui.wide_ital_font = NOFONT; - gui_mch_free_font(gui.wide_bold_font); - gui.wide_bold_font = NOFONT; - gui_mch_free_font(gui.wide_boldital_font); - gui.wide_boldital_font = NOFONT; - - if (gui.wide_font - && GetObject((HFONT)gui.wide_font, sizeof(lf), &lf)) - { - if (!lf.lfItalic) - { - lf.lfItalic = TRUE; - gui.wide_ital_font = get_font_handle(&lf); - lf.lfItalic = FALSE; - } - if (lf.lfWeight < FW_BOLD) - { - lf.lfWeight = FW_BOLD; - gui.wide_bold_font = get_font_handle(&lf); - if (!lf.lfItalic) - { - lf.lfItalic = TRUE; - gui.wide_boldital_font = get_font_handle(&lf); - } - } - } -# endif -} -#endif - -/* - * 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 = (char_u *)lf.lfFaceName; -#if defined(FEAT_MBYTE_IME) || defined(GLOBAL_IME) - norm_logfont = lf; - sub_logfont = lf; -#endif -#ifdef FEAT_MBYTE_IME - update_im_font(); -#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(void) -{ - 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(void) -{ - RECT rect; - - GetWindowRect(s_hwnd, &rect); - if (win_socket_id == 0) - { - gui_resize_shell(rect.right - rect.left - - (GetSystemMetrics(SM_CXFRAME) + - GetSystemMetrics(SM_CXPADDEDBORDER)) * 2, - rect.bottom - rect.top - - (GetSystemMetrics(SM_CYFRAME) + - GetSystemMetrics(SM_CXPADDEDBORDER)) * 2 - - GetSystemMetrics(SM_CYCAPTION) -#ifdef FEAT_MENU - - gui_mswin_get_menu_height(FALSE) -#endif - ); - } - else - { - /* Inside another window, don't use the frame and border. */ - gui_resize_shell(rect.right - rect.left, - rect.bottom - rect.top -#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[] = -{ - IDC_ARROW, /* arrow */ - MAKEINTRESOURCE(0), /* blank */ - IDC_IBEAM, /* beam */ - IDC_SIZENS, /* updown */ - IDC_SIZENS, /* udsizing */ - IDC_SIZEWE, /* leftright */ - IDC_SIZEWE, /* lrsizing */ - IDC_WAIT, /* busy */ -#ifdef WIN3264 - IDC_NO, /* no */ -#else - IDC_ICON, /* no */ -#endif - IDC_ARROW, /* crosshair */ - IDC_ARROW, /* hand1 */ - IDC_ARROW, /* hand2 */ - IDC_ARROW, /* pencil */ - IDC_ARROW, /* question */ - IDC_ARROW, /* right-arrow */ - IDC_UPARROW, /* up-arrow */ - 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 = 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(). - */ - static WCHAR * -convert_filterW(char_u *s) -{ - char_u *tmp; - int len; - WCHAR *res; - - tmp = convert_filter(s); - if (tmp == NULL) - return NULL; - len = (int)STRLEN(s) + 3; - res = enc_to_utf16(tmp, &len); - vim_free(tmp); - 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 = (LPSTR)title; - fileStruct.lpstrDefExt = (LPSTR)ext; - - fileStruct.lpstrFile = (LPSTR)fileBuf; - fileStruct.nMaxFile = MAXPATHL; - fileStruct.lpstrFilter = (LPSTR)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 = (LPSTR)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); - - reset_VIsual(); - - 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((char_u *)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; -}
deleted file mode 100644 --- a/src/guiw16rc.h +++ /dev/null @@ -1,17 +0,0 @@ - -#define IDR_VIM 150 - -#define IDR_VIM_ERROR 151 -#define IDR_VIM_ALERT 152 -#define IDR_VIM_INFO 153 -#define IDR_VIM_QUESTION 154 - -#define IDR_ICOBUDDYBASE 200 - -#define IDR_ICOBUDDY_DEF1 (IDR_ICOBUDDYBASE + 3) -#define IDR_ICOBUDDY_DEF2 (IDR_ICOBUDDYBASE + 0) -#define IDR_ICOBUDDY_DEF3 (IDR_ICOBUDDYBASE + 1) -#define IDR_ICOBUDDY_DEF4 (IDR_ICOBUDDYBASE + 2) - -#define IDR_ICOBUDDY_GRIN (IDR_ICOBUDDYBASE + 4) -#define IDR_ICOBUDDY_ALARM (IDR_ICOBUDDYBASE + 5)
--- a/src/misc2.c +++ b/src/misc2.c @@ -1400,7 +1400,7 @@ vim_strsave_shellescape(char_u *string, length = (unsigned)STRLEN(string) + 3; /* two quotes and a trailing NUL */ for (p = string; *p != NUL; mb_ptr_adv(p)) { -# if defined(WIN32) || defined(WIN16) || defined(DOS) +# if defined(WIN32) || defined(DOS) if (!p_ssl) { if (*p == '"') @@ -1431,7 +1431,7 @@ vim_strsave_shellescape(char_u *string, d = escaped_string; /* add opening quote */ -# if defined(WIN32) || defined(WIN16) || defined(DOS) +# if defined(WIN32) || defined(DOS) if (!p_ssl) *d++ = '"'; else @@ -1440,7 +1440,7 @@ vim_strsave_shellescape(char_u *string, for (p = string; *p != NUL; ) { -# if defined(WIN32) || defined(WIN16) || defined(DOS) +# if defined(WIN32) || defined(DOS) if (!p_ssl) { if (*p == '"') @@ -1483,7 +1483,7 @@ vim_strsave_shellescape(char_u *string, } /* add terminating quote and finish with a NUL */ -# if defined(WIN32) || defined(WIN16) || defined(DOS) +# if defined(WIN32) || defined(DOS) if (!p_ssl) *d++ = '"'; else
--- a/src/option.c +++ b/src/option.c @@ -2296,14 +2296,10 @@ static struct vimoption # if defined(MSDOS) (char_u *)"command", # else -# if defined(WIN16) - (char_u *)"command.com", +# if defined(WIN3264) + (char_u *)"", /* set in set_init_1() */ # else -# if defined(WIN3264) - (char_u *)"", /* set in set_init_1() */ -# else (char_u *)"sh", -# endif # endif # endif #endif /* VMS */ @@ -2367,7 +2363,7 @@ static struct vimoption {"shellxescape", "sxe", P_STRING|P_VI_DEF|P_SECURE, (char_u *)&p_sxe, PV_NONE, { -#if defined(MSDOS) || defined(WIN16) || defined(WIN3264) +#if defined(MSDOS) || defined(WIN3264) (char_u *)"\"&|<>()@^", #else (char_u *)"",
--- a/src/os_msdos.c +++ b/src/os_msdos.c @@ -28,12 +28,6 @@ # include <conio.h> #endif -/* - * MS-DOS only code, not used for Win16. - */ -#ifndef WIN16 - - #ifndef PROTO # include <bios.h> # ifdef DJGPP @@ -2850,11 +2844,6 @@ Win16SetClipboardData( #endif /* FEAT_CLIPBOARD */ #endif /* DJGPP */ -/* - * End of MS-DOS only code - */ -#endif /* WIN16 */ - /* common MS-DOS and Win16 code follows */ static int
--- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -10,28 +10,11 @@ /* * os_mswin.c * - * Routines common to both Win16 and Win32. + * Routines for Win32. */ -#ifdef WIN16 -# ifdef __BORLANDC__ -# pragma warn -par -# pragma warn -ucp -# pragma warn -use -# pragma warn -aus -# endif -#endif - #include "vim.h" -#ifdef WIN16 -# define SHORT_FNAME /* always 8.3 file name */ -/* cproto fails on missing include files */ -# ifndef PROTO -# include <dos.h> -# endif -# include <string.h> -#endif #include <sys/types.h> #include <signal.h> #include <limits.h> @@ -904,7 +887,6 @@ typedef int (*MYSTRPROCINT)(LPSTR); typedef int (*MYINTPROCINT)(int); # endif -# ifndef WIN16 /* * Check if a pointer points to a valid NUL terminated string. * Return the length of the string, including terminating NUL. @@ -944,7 +926,6 @@ check_str_len(char_u *str) return 0; } -# endif /* * Passed to do_in_runtimepath() to load a vim.ico file. @@ -991,11 +972,7 @@ mch_libcall( BOOL fRunTimeLinkSuccess = FALSE; // Get a handle to the DLL module. -# ifdef WIN16 - hinstLib = LoadLibrary(libname); -# else hinstLib = vimLoadLib((char *)libname); -# endif // If the handle is valid, try to get the function address. if (hinstLib != NULL) @@ -1034,15 +1011,7 @@ mch_libcall( if (string_result == NULL) *number_result = retval_int; else if (retval_str != NULL -# ifdef WIN16 - && retval_str != (char_u *)1 - && retval_str != (char_u *)-1 - && !IsBadStringPtr(retval_str, INT_MAX) - && (len = strlen(retval_str) + 1) > 0 -# else - && (len = check_str_len(retval_str)) > 0 -# endif - ) + && (len = check_str_len(retval_str)) > 0) { *string_result = lalloc((long_u)len, TRUE); if (*string_result != NULL) @@ -1184,9 +1153,6 @@ mch_set_winpos(int x, int y) #if (defined(FEAT_PRINTER) && !defined(FEAT_POSTSCRIPT)) || defined(PROTO) -# ifdef WIN16 -# define TEXT(a) a -# endif /*================================================================= * Win32 printer stuff */ @@ -1211,7 +1177,7 @@ static char_u *prt_name = NULL; #define IDC_PRINTTEXT2 402 #define IDC_PROGRESS 403 -#if !defined(FEAT_MBYTE) || defined(WIN16) +#if !defined(FEAT_MBYTE) # define vimSetDlgItemText(h, i, s) SetDlgItemText(h, i, s) #else static BOOL @@ -1456,23 +1422,13 @@ prt_get_cpl(void) int dvoff; int rev_offset; int dpi; -#ifdef WIN16 - POINT pagesize; -#endif GetTextMetrics(prt_dlg.hDC, &prt_tm); prt_line_height = prt_tm.tmHeight + prt_tm.tmExternalLeading; hr = GetDeviceCaps(prt_dlg.hDC, HORZRES); -#ifdef WIN16 - Escape(prt_dlg.hDC, GETPHYSPAGESIZE, NULL, NULL, &pagesize); - phyw = pagesize.x; - Escape(prt_dlg.hDC, GETPRINTINGOFFSET, NULL, NULL, &pagesize); - dvoff = pagesize.x; -#else phyw = GetDeviceCaps(prt_dlg.hDC, PHYSICALWIDTH); dvoff = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETX); -#endif dpi = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSX); rev_offset = phyw - (dvoff + hr); @@ -1501,20 +1457,10 @@ prt_get_lpp(void) int rev_offset; int bottom_margin; int dpi; -#ifdef WIN16 - POINT pagesize; -#endif vr = GetDeviceCaps(prt_dlg.hDC, VERTRES); -#ifdef WIN16 - Escape(prt_dlg.hDC, GETPHYSPAGESIZE, NULL, NULL, &pagesize); - phyw = pagesize.y; - Escape(prt_dlg.hDC, GETPRINTINGOFFSET, NULL, NULL, &pagesize); - dvoff = pagesize.y; -#else phyw = GetDeviceCaps(prt_dlg.hDC, PHYSICALHEIGHT); dvoff = GetDeviceCaps(prt_dlg.hDC, PHYSICALOFFSETY); -#endif dpi = GetDeviceCaps(prt_dlg.hDC, LOGPIXELSY); rev_offset = phyw - (dvoff + vr); @@ -1741,12 +1687,6 @@ init_fail_dlg: if (err) { -#ifdef WIN16 - char buf[20]; - - sprintf(buf, "%ld", err); - EMSG2(_("E238: Print error: %s"), buf); -#else char_u *buf; /* I suspect FormatMessage() doesn't work for values returned by @@ -1758,7 +1698,6 @@ init_fail_dlg: EMSG2(_("E238: Print error: %s"), buf == NULL ? (char_u *)_("Unknown") : buf); LocalFree((LPVOID)(buf)); -#endif } else msg_clr_eos(); /* Maybe canceled */ @@ -1778,11 +1717,7 @@ mch_print_begin(prt_settings_T *psetting hDlgPrint = CreateDialog(GetModuleHandle(NULL), TEXT("PrintDlgBox"), prt_dlg.hwndOwner, PrintDlgProc); -#ifdef WIN16 - Escape(prt_dlg.hDC, SETABORTPROC, 0, (LPSTR)AbortProc, NULL); -#else SetAbortProc(prt_dlg.hDC, AbortProc); -#endif wsprintf(szBuffer, _("Printing '%s'"), gettail(psettings->jobname)); vimSetDlgItemText(hDlgPrint, IDC_PRINTTEXT1, (char_u *)szBuffer); @@ -1845,10 +1780,10 @@ mch_print_start_line(int margin, int pag int mch_print_text_out(char_u *p, int len) { -#if defined(FEAT_PROPORTIONAL_FONTS) || (defined(FEAT_MBYTE) && !defined(WIN16)) +#if defined(FEAT_PROPORTIONAL_FONTS) || defined(FEAT_MBYTE) SIZE sz; #endif -#if defined(FEAT_MBYTE) && !defined(WIN16) +#if defined(FEAT_MBYTE) WCHAR *wp = NULL; int wlen = len; @@ -1888,20 +1823,12 @@ mch_print_text_out(char_u *p, int len) return (prt_pos_x + prt_left_margin + prt_tm.tmAveCharWidth + prt_tm.tmOverhang > prt_right_margin); #else -# ifdef WIN16 - GetTextExtentPoint(prt_dlg.hDC, (LPCSTR)p, len, &sz); -# else GetTextExtentPoint32(prt_dlg.hDC, (LPCSTR)p, len, &sz); -# endif prt_pos_x += (sz.cx - prt_tm.tmOverhang); /* This is wrong when printing spaces for a TAB. */ if (p[len] == NUL) return FALSE; -# ifdef WIN16 - GetTextExtentPoint(prt_dlg.hDC, p + len, 1, &sz); -# else GetTextExtentPoint32(prt_dlg.hDC, p + len, 1, &sz); -# endif return (prt_pos_x + prt_left_margin + sz.cx > prt_right_margin); #endif } @@ -3027,14 +2954,10 @@ get_logfont( lf->lfWidth = points_to_pixels(p, &p, FALSE, (long_i)printer_dc); break; case 'b': -#ifndef MSWIN16_FASTTEXT lf->lfWeight = FW_BOLD; -#endif break; case 'i': -#ifndef MSWIN16_FASTTEXT lf->lfItalic = TRUE; -#endif break; case 'u': lf->lfUnderline = TRUE;
deleted file mode 100644 --- a/src/os_win16.c +++ /dev/null @@ -1,427 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * 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. - */ -/* - * os_win16.c - * - * Win16 (Windows 3.1x) system-dependent routines. - * Carved brutally from os_win32.c by Vince Negri <vn@aslnet.co.uk> - */ -#ifdef __BORLANDC__ -# pragma warn -par -# pragma warn -ucp -# pragma warn -use -# pragma warn -aus -# pragma warn -obs -#endif - -#include "vim.h" - -/* cproto fails on missing include files */ -#ifndef PROTO -# include <dos.h> -#endif - -#include <string.h> -#include <sys/types.h> -#include <signal.h> -#include <limits.h> - -#ifndef PROTO -# include <process.h> - -# undef chdir -# include <direct.h> -# include <shellapi.h> /* required for FindExecutable() */ -#endif - - -/* Record all output and all keyboard & mouse input */ -/* #define MCH_WRITE_DUMP */ - -#ifdef MCH_WRITE_DUMP -FILE* fdDump = NULL; -#endif - - -/* - * When generating prototypes for Win32 on Unix, these lines make the syntax - * errors disappear. They do not need to be correct. - */ -#ifdef PROTO -typedef int HANDLE; -typedef int SMALL_RECT; -typedef int COORD; -typedef int SHORT; -typedef int WORD; -typedef int DWORD; -typedef int BOOL; -typedef int LPSTR; -typedef int LPTSTR; -typedef int KEY_EVENT_RECORD; -typedef int MOUSE_EVENT_RECORD; -# define WINAPI -typedef int CONSOLE_CURSOR_INFO; -typedef char * LPCSTR; -# define WINBASEAPI -typedef int INPUT_RECORD; -# define _cdecl -#endif - -#ifdef __BORLANDC__ -/* being a more ANSI compliant compiler, BorlandC doesn't define _stricoll: - * but it does in BC 5.02! */ -# if __BORLANDC__ < 0x502 -int _stricoll(char *a, char *b); -# endif -#endif - -/* cproto doesn't create a prototype for main() */ -int _cdecl -VimMain - (int argc, char **argv); -static int (_cdecl *pmain)(int, char **); - -#ifndef PROTO -void _cdecl SaveInst(HINSTANCE hInst); -static void (_cdecl *pSaveInst)(HINSTANCE); - -int WINAPI -WinMain( - HINSTANCE hInstance, - HINSTANCE hPrevInst, - LPSTR lpszCmdLine, - int nCmdShow) -{ - int argc; - char **argv; - char *tofree; - char prog[256]; - - /* - * Ron: added full path name so that the $VIM variable will get set to our - * startup path (so the .vimrc file can be found w/o a VIM env. var.) - * Remove the ".exe" extension, and find the 1st non-space. - */ - GetModuleFileName(hInstance, prog, 255); - if (*prog != NUL) - exe_name = FullName_save((char_u *)prog, FALSE); - - /* Separate the command line into arguments. */ - argc = get_cmd_args(prog, (char *)lpszCmdLine, &argv, &tofree); - if (argc == 0) - { - /* Error message? */ - return 0; - } - - pSaveInst = SaveInst; - pmain = VimMain; - pSaveInst(hInstance); - pmain(argc, argv); - - free(argv); - if (tofree != NULL) - free(tofree); - - return 0; -} -#endif - - - - - - -#ifdef FEAT_MOUSE - -/* - * For the GUI the mouse handling is in gui_w32.c. - */ - void -mch_setmouse( - int on) -{ -} -#endif /* FEAT_MOUSE */ - - - -/* - * GUI version of mch_init(). - */ - void -mch_init(void) -{ - extern int _fmode; - - - /* Let critical errors result in a failure, not in a dialog box. Required - * for the timestamp test to work on removed floppies. */ - SetErrorMode(SEM_FAILCRITICALERRORS); - - _fmode = O_BINARY; /* we do our own CR-LF translation */ - - /* Specify window size. Is there a place to get the default from? */ - Rows = 25; - Columns = 80; - - - set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0); - -#ifdef FEAT_CLIPBOARD - clip_init(TRUE); - - /* - * Vim's own clipboard format recognises whether the text is char, line, - * or rectangular block. Only useful for copying between two Vims. - * "VimClipboard" was used for previous versions, using the first - * character to specify MCHAR, MLINE or MBLOCK. - */ - clip_star.format = RegisterClipboardFormat("VimClipboard2"); - clip_star.format_raw = RegisterClipboardFormat("VimRawBytes"); -#endif -} - - - -/* - * Do we have an interactive window? - */ - int -mch_check_win( - int argc, - char **argv) -{ - return OK; /* GUI always has a tty */ -} - - -/* - * return process ID - */ - long -mch_get_pid(void) -{ - return (long)GetCurrentTask(); -} - - -/* - * Specialised version of system(). - * This version proceeds as follows: - * 1. Start the program with WinExec - * 2. Wait for the module use count of the program to go to 0 - * (This is the best way of detecting the program has finished) - */ - - static int -mch_system(char *cmd, int options) -{ - DWORD ret = 0; - UINT wShowWindow; - UINT h_module; - MSG msg; - BOOL again = TRUE; - - /* - * It's nicer to run a filter command in a minimized window, but in - */ - if (options & SHELL_DOOUT) - wShowWindow = SW_SHOWMINIMIZED; - else - wShowWindow = SW_SHOWNORMAL; - - /* Now, run the command */ - h_module = WinExec((LPCSTR)cmd, wShowWindow); - - if (h_module < 32) - { - /*error*/ - ret = -h_module; - } - else - { - /* Wait for the command to terminate before continuing */ - while (GetModuleUsage((HINSTANCE)h_module) > 0 && again ) - { - while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) && again) - { - if (msg.message == WM_QUIT) - - { - PostQuitMessage(msg.wParam); - again = FALSE; - } - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - - return ret; -} - -/* - * Either execute a command by calling the shell or start a new shell - */ - int -mch_call_shell( - char_u *cmd, - int options) /* SHELL_, see vim.h */ -{ - int x; - int tmode = cur_tmode; - - out_flush(); - - -#ifdef MCH_WRITE_DUMP - if (fdDump) - { - fprintf(fdDump, "mch_call_shell(\"%s\", %d)\n", cmd, options); - fflush(fdDump); - } -#endif - - /* - * Catch all deadly signals while running the external command, because a - * CTRL-C, Ctrl-Break or illegal instruction might otherwise kill us. - */ - signal(SIGINT, SIG_IGN); - signal(SIGILL, SIG_IGN); - signal(SIGFPE, SIG_IGN); - signal(SIGSEGV, SIG_IGN); - signal(SIGTERM, SIG_IGN); - signal(SIGABRT, SIG_IGN); - - if (options & SHELL_COOKED) - settmode(TMODE_COOK); /* set to normal mode */ - - if (cmd == NULL) - { - x = mch_system(p_sh, options); - } - else - { - /* we use "command" or "cmd" to start the shell; slow but easy */ - char_u *newcmd; - - newcmd = lalloc( - STRLEN(p_sh) + STRLEN(p_shcf) + STRLEN(cmd) + 10, TRUE); - if (newcmd != NULL) - { - if (STRNICMP(cmd, "start ", 6) == 0) - { - sprintf((char *)newcmd, "%s\0", cmd+6); - if (WinExec((LPCSTR)newcmd, SW_SHOWNORMAL) > 31) - x = 0; - else - x = -1; - } - else - { - sprintf((char *)newcmd, "%s%s %s %s", - "", - p_sh, - p_shcf, - cmd); - x = mch_system((char *)newcmd, options); - } - vim_free(newcmd); - } - } - - if (tmode == TMODE_RAW) - settmode(TMODE_RAW); /* set to raw mode */ - - if (x && !(options & SHELL_SILENT) && !emsg_silent) - { - smsg(_("shell returned %d"), x); - msg_putchar('\n'); - } -#ifdef FEAT_TITLE - resettitle(); -#endif - - signal(SIGINT, SIG_DFL); - signal(SIGILL, SIG_DFL); - signal(SIGFPE, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGTERM, SIG_DFL); - signal(SIGABRT, SIG_DFL); - - - return x; -} - - -/* - * Delay for half a second. - */ - void -mch_delay( - long msec, - int ignoreinput) -{ -#ifdef MUST_FIX - Sleep((int)msec); /* never wait for input */ -#endif -} - - -/* - * check for an "interrupt signal": CTRL-break or CTRL-C - */ - void -mch_breakcheck(void) -{ - /* never used */ -} - - -/* - * How much memory is available in Kbyte? - */ - long_u -mch_avail_mem( - int special) -{ - return GetFreeSpace(0) >> 10; -} - - -/* - * Like rename(), returns 0 upon success, non-zero upon failure. - * Should probably set errno appropriately when errors occur. - */ - int -mch_rename( - const char *pszOldFile, - const char *pszNewFile) -{ - - /* - * No need to play tricks, this isn't rubbish like Windows 95 <g> - */ - return rename(pszOldFile, pszNewFile); - -} - -/* - * Get the default shell for the current hardware platform - */ - char* -default_shell(void) -{ - char* psz = NULL; - - psz = "command.com"; - - return psz; -}
deleted file mode 100644 --- a/src/os_win16.h +++ /dev/null @@ -1,143 +0,0 @@ -/* vi:set ts=8 sts=4 sw=4: - * - * VIM - Vi IMproved by Bram Moolenaar - * - * Do ":help uganda" in Vim to read copying and usage conditions. - * Do ":help credits" in Vim to see a list of people who contributed. - */ - -/* - * Win16 (Windows 3.1x) machine-dependent things. - */ - -#include "os_dos.h" /* common MS-DOS and Windows stuff */ - -#define BINARY_FILE_IO -#define USE_EXE_NAME /* use argv[0] for $VIM */ -#define SYNC_DUP_CLOSE /* sync() a file with dup() and close() */ -#define USE_TERM_CONSOLE -#define HAVE_STRING_H -#define HAVE_STRCSPN -#define HAVE_STRICMP -#define HAVE_STRNICMP -#define HAVE_STRFTIME /* guessed */ -#define HAVE_MEMSET -#define USE_TMPNAM /* use tmpnam() instead of mktemp() */ -#define HAVE_LOCALE_H -#define HAVE_FCNTL_H -#define HAVE_QSORT -#define HAVE_ST_MODE /* have stat.st_mode */ -#define HAVE_MATH_H -//#define USE_FNAME_CASE /* adjust case of file names */ -#ifndef FEAT_CLIPBOARD -# define FEAT_CLIPBOARD /* include clipboard support */ -#endif -#if defined(__DATE__) && defined(__TIME__) -# define HAVE_DATE_TIME -#endif -#define HAVE_AVAIL_MEM - -#define SHORT_FNAME /* always 8.3 file name */ - -#define SMALL_MALLOC /* 16 bit storage allocation */ - -#ifdef __BORLANDC__ -# define HAVE_PUTENV /* at least Bcc 5.2 has it */ -#endif - -#ifdef FEAT_GUI_W16 -# define NO_CONSOLE /* don't included console-only code */ -#endif - -/* toupper() is not really broken, but it's very slow. Probably because of - * using unicode characters on Windows NT */ -#define BROKEN_TOUPPER - -#define FNAME_ILLEGAL "\"*?><|" /* illegal characters in a file name */ - -#ifndef VIM_SIZEOF_INT -# define VIM_SIZEOF_INT 2 -#endif - -typedef long off_t; - -#include <stdlib.h> -#include <time.h> - -/* cproto fails on missing include files */ -#ifndef PROTO -# include <dos.h> -# include <dir.h> - -# ifndef STRICT -# define STRICT -# endif -# ifndef COBJMACROS -# define COBJMACROS /* For OLE: Enable "friendlier" access to objects */ -# endif -# include <windows.h> - -#endif /* PROTO */ - -/* - * plenty of memory, use large buffers - */ -#define CMDBUFFSIZE 1024 /* size of the command processing buffer */ - - -#define BASENAMELEN (MAXPATHL-5) /* length of base of file name */ - -#ifndef DFLT_MAXMEM -# define DFLT_MAXMEM (256) /* use up to 256K for a buffer*/ -#endif - -#ifndef DFLT_MAXMEMTOT -# define DFLT_MAXMEMTOT (5*1024) /* use up to 5 Mbyte for Vim */ -#endif - -/* - * Some simple debugging macros that look and behave a lot like their - * namesakes in MFC. - */ - -#ifdef _DEBUG - -# if defined(_MSC_VER) && (_MSC_VER >= 1000) - /* Use the new debugging tools in Visual C++ 4.x */ -# include <crtdbg.h> -# define ASSERT(f) _ASSERT(f) -# else -# include <assert.h> -# define ASSERT(f) assert(f) -# endif - -# define TRACE Trace -# define TRACE0(sz) Trace(_T("%s"), _T(sz)) -# define TRACE1(sz, p1) Trace(_T(sz), p1) -# define TRACE2(sz, p1, p2) Trace(_T(sz), p1, p2) -# define TRACE3(sz, p1, p2, p3) Trace(_T(sz), p1, p2, p3) - -/* In debug version, writes trace messages to debug stream */ -void __cdecl -Trace(char *pszFormat, ...); - -#else /* !_DEBUG */ - - /* These macros should all compile away to nothing */ -# define ASSERT(f) ((void)0) -# define TRACE 1 ? (void)0 : printf -# define TRACE0(sz) -# define TRACE1(sz, p1) -# define TRACE2(sz, p1, p2) -# define TRACE3(sz, p1, p2, p3) - -#endif /* !_DEBUG */ - - -#define ASSERT_POINTER(p, type) \ - ASSERT(((p) != NULL) && IsValidAddress((p), sizeof(type), FALSE)) - -#define ASSERT_NULL_OR_POINTER(p, type) \ - ASSERT(((p) == NULL) || IsValidAddress((p), sizeof(type), FALSE)) - -#define mch_setenv(name, val, x) setenv(name, val, x)
--- a/src/proto.h +++ b/src/proto.h @@ -38,17 +38,9 @@ # if defined(UNIX) || defined(__EMX__) || defined(VMS) # include "os_unix.pro" # endif -# if defined(MSDOS) || defined(WIN16) +# if defined(MSDOS) # include "os_msdos.pro" # endif -# ifdef WIN16 - typedef LPSTR LPWSTR; - typedef LPCSTR LPCWSTR; - typedef int LPBOOL; -# include "os_win16.pro" -# include "os_mswin.pro" -# include "winclip.pro" -# endif # ifdef WIN3264 # include "os_win32.pro" # include "os_mswin.pro"
deleted file mode 100644 --- a/src/proto/gui_w16.pro +++ /dev/null @@ -1,80 +0,0 @@ -/* gui_w16.c */ -void gui_mch_set_blinking(long wait, long on, long off); -void gui_mch_stop_blink(void); -void gui_mch_start_blink(void); -LRESULT WINAPI vim_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); -void gui_mch_new_colors(void); -void gui_mch_def_colors(void); -int gui_mch_open(void); -int gui_mch_get_winpos(int *x, int *y); -void gui_mch_set_winpos(int x, int y); -void gui_mch_set_text_area_pos(int x, int y, int w, int h); -void gui_mch_enable_scrollbar(scrollbar_T *sb, int flag); -void gui_mch_set_scrollbar_pos(scrollbar_T *sb, int x, int y, int w, int h); -void gui_mch_create_scrollbar(scrollbar_T *sb, int orient); -int gui_mch_adjust_charheight(void); -GuiFont gui_mch_get_font(char_u *name, int giveErrorIfMissing); -char_u *gui_mch_get_fontname(GuiFont font, char_u *name); -void gui_mch_free_font(GuiFont font); -guicolor_T gui_mch_get_color(char_u *name); -int gui_mch_haskey(char_u *name); -void gui_mch_beep(void); -void gui_mch_invert_rectangle(int r, int c, int nr, int nc); -void gui_mch_iconify(void); -void gui_mch_draw_hollow_cursor(guicolor_T color); -void gui_mch_draw_part_cursor(int w, int h, guicolor_T color); -void gui_mch_update(void); -int gui_mch_wait_for_chars(int wtime); -void gui_mch_clear_block(int row1, int col1, int row2, int col2); -void gui_mch_clear_all(void); -void gui_mch_enable_menu(int flag); -void gui_mch_set_menu_pos(int x, int y, int w, int h); -void gui_mch_menu_hidden(vimmenu_T *menu, int hidden); -void gui_mch_draw_menubar(void); -long_u gui_mch_get_rgb(guicolor_T pixel); -void gui_mch_activate_window(void); -void gui_mch_show_toolbar(int showit); -void gui_mch_show_tabline(int showit); -int gui_mch_showing_tabline(void); -void gui_mch_update_tabline(void); -void gui_mch_set_curtab(int nr); -void ex_simalt(exarg_T *eap); -void gui_mch_find_dialog(exarg_T *eap); -void gui_mch_replace_dialog(exarg_T *eap); -void gui_mch_mousehide(int hide); -void gui_mch_destroy_scrollbar(scrollbar_T *sb); -void gui_mch_getmouse(int *x, int *y); -void gui_mch_setmouse(int x, int y); -void gui_mch_flash(int msec); -void gui_mch_delete_lines(int row, int num_lines); -void gui_mch_insert_lines(int row, int num_lines); -void gui_mch_exit(int rc); -void gui_mch_wide_font_changed(void); -int gui_mch_init_font(char_u *font_name, int fontset); -int gui_mch_maximized(void); -void gui_mch_newfont(void); -void gui_mch_settitle(char_u *title, char_u *icon); -void mch_set_mouse_shape(int shape); -char_u *gui_mch_browsedir(char_u *title, char_u *initdir); -char_u *gui_mch_browse(int saving, char_u *title, char_u *dflt, char_u *ext, char_u *initdir, char_u *filter); -int get_cmd_args(char *prog, char *cmdline, char ***argvp, char **tofree); -void gui_mch_prepare(int *argc, char **argv); -int gui_mch_init(void); -void gui_mch_set_shellsize(int width, int height, int min_width, int min_height, int base_width, int base_height, int direction); -void gui_mch_set_scrollbar_thumb(scrollbar_T *sb, long val, long size, long max); -void gui_mch_set_font(GuiFont font); -void gui_mch_set_fg_color(guicolor_T color); -void gui_mch_set_bg_color(guicolor_T color); -void gui_mch_set_sp_color(guicolor_T color); -void gui_mch_draw_string(int row, int col, char_u *text, int len, int flags); -void gui_mch_flush(void); -void gui_mch_get_screen_dimensions(int *screen_w, int *screen_h); -void gui_mch_add_menu(vimmenu_T *menu, int pos); -void gui_mch_show_popupmenu(vimmenu_T *menu); -void gui_make_popup(char_u *path_name, int mouse_pos); -void gui_mch_add_menu_item(vimmenu_T *menu, int idx); -void gui_mch_destroy_menu(vimmenu_T *menu); -void gui_mch_menu_grey(vimmenu_T *menu, int grey); -int gui_mch_dialog(int type, char_u *title, char_u *message, char_u *buttons, int dfltbutton, char_u *textfield, int ex_cmd); -void gui_mch_set_foreground(void); -/* vim: set ft=c : */
--- a/src/version.c +++ b/src/version.c @@ -748,6 +748,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 1364, +/**/ 1363, /**/ 1362, @@ -3638,9 +3640,6 @@ list_version(void) # endif # endif #endif -#ifdef WIN16 - MSG_PUTS(_("\nMS-Windows 16-bit version")); -#endif #ifdef MSDOS # ifdef DJGPP MSG_PUTS(_("\n32-bit MS-DOS version"));
--- a/src/vim.h +++ b/src/vim.h @@ -27,7 +27,7 @@ # endif #endif -#if defined(MSDOS) || defined(WIN16) || defined(WIN32) || defined(_WIN64) \ +#if defined(MSDOS) || defined(WIN32) || defined(_WIN64) \ || defined(__EMX__) # include "vimio.h" #endif @@ -150,7 +150,7 @@ #if defined(FEAT_GUI_W32) || defined(FEAT_GUI_W16) # define FEAT_GUI_MSWIN #endif -#if defined(WIN16) || defined(WIN32) || defined(_WIN64) +#if defined(WIN32) || defined(_WIN64) # define MSWIN #endif /* Practically everything is common to both Win32 and Win64 */ @@ -308,10 +308,6 @@ # include "os_msdos.h" #endif -#ifdef WIN16 -# include "os_win16.h" -#endif - #ifdef WIN3264 # include "os_win32.h" #endif @@ -471,7 +467,7 @@ typedef unsigned long u8char_T; /* l # include <sys/stat.h> #endif -#if defined(HAVE_ERRNO_H) || defined(DJGPP) || defined(WIN16) \ +#if defined(HAVE_ERRNO_H) || defined(DJGPP) \ || defined(WIN32) || defined(_WIN64) || defined(__EMX__) # include <errno.h> #endif
deleted file mode 100644 --- a/src/vim16.def +++ /dev/null @@ -1,5 +0,0 @@ -CODE PRELOAD EXECUTEONLY -DATA MULTIPLE SHARED -DESCRIPTION 'Vim 7.4' -STACKSIZE 16000 -HEAPSIZE 10000
deleted file mode 100644 --- a/src/vim16.rc +++ /dev/null @@ -1,81 +0,0 @@ -// vim:ts=8:sw=4:sts=4: -// -// VIM - Vi IMproved by Bram Moolenaar -// -// Do ":help uganda" in Vim to read copying and usage conditions. -// Do ":help credits" in Vim to see a list of people who contributed. - -// vim.rc -// Icon and version information for the Win32 version of Vim -// Must be in DOS format <CR><NL>! - -#include "version.h" -#include "gui_w3~1.h" -#include "guiw16rc.h" - -// -// Icons -// -IDR_VIM ICON "VIM.ICO" - -#ifndef FEAT_TINY -IDR_VIM_ERROR ICON "VIM_ER~1.ICO" -IDR_VIM_ALERT ICON "VIM_AL~1.ICO" -IDR_VIM_INFO ICON "VIM_INFO.ICO" -IDR_VIM_QUESTION ICON "VIM_QU~1.ICO" -#endif - -// -// Bitmaps -// -#ifdef FEAT_TOOLBAR -IDR_TOOLBAR1 BITMAP DISCARDABLE "tools16.bmp" -#endif -// -// Version -// - -VS_VERSION_INFO VERSIONINFO - FILEVERSION VIM_VERSION_MAJOR,VIM_VERSION_MINOR,VIM_VERSION_BUILD,VIM_VERSION_PATCHLEVEL - PRODUCTVERSION VIM_VERSION_MAJOR,VIM_VERSION_MINOR,VIM_VERSION_BUILD,VIM_VERSION_PATCHLEVEL - FILEFLAGSMASK VS_FFI_FILEFLAGSMASK - -#if VIM_VERSION_PATCHLEVEL > 0 - #ifdef _DEBUG - FILEFLAGS VS_FF_PRERELEASE | VS_FF_DEBUG | VS_FF_PATCHED - #else - FILEFLAGS VS_FF_PRERELEASE | VS_FF_PATCHED - #endif -#else - #ifdef _DEBUG - FILEFLAGS VS_FF_PRERELEASE | VS_FF_DEBUG - #else - FILEFLAGS VS_FF_PRERELEASE - #endif -#endif - - FILEOS VOS__WINDOWS32 - FILETYPE VFT_APP - FILESUBTYPE 0x0L -BEGIN - BLOCK "StringFileInfo" - BEGIN - // 0x0409 == U.S. English; 0x04E4 => Windows Multilingual - BLOCK "040904E4" - BEGIN - VALUE "CompanyName", "Vim Developers\0" - VALUE "FileDescription", "Vi Improved - A Text Editor\0" - VALUE "FileVersion", VIM_VERSION_MAJOR_STR ", " VIM_VERSION_MINOR_STR ", " VIM_VERSION_BUILD_STR ", " VIM_VERSION_PATCHLEVEL_STR "\0" - VALUE "InternalName", "VIM\0" - VALUE "LegalCopyright", "Copyright \251 1996\0" - VALUE "LegalTrademarks", "Vim\0" - VALUE "OriginalFilename", "VIM.EXE\0" - VALUE "ProductName", "Vim\0" - VALUE "ProductVersion", VIM_VERSION_MAJOR_STR ", " VIM_VERSION_MINOR_STR ", " VIM_VERSION_BUILD_STR ", " VIM_VERSION_PATCHLEVEL_STR "\0" - END - END - BLOCK "VarFileInfo" - BEGIN - VALUE "Translation", 0x409, 0x4E4 - END -END