⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gui_w32.c

📁 VIM文本编辑器
💻 C
📖 第 1 页 / 共 5 页
字号:
/* 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.
 *
 * Windows GUI.
 *
 * GUI support for Microsoft Windows.  Win32 initially; maybe Win16 later
 *
 * George V. Reilly <gvr@halcyon.com> wrote the original Win32 GUI.
 * Robert Webb reworked it to use the existing GUI stuff and added menu,
 * scrollbars, etc.
 *
 * Note: Clipboard stuff, for cutting and pasting text to other windows, is in
 * os_win32.c.	(It can also be done from the terminal version).
 */

#define WIN32_FIND_REPLACE	/* include code for find/replace dialog */
#define MENUHINTS		/* show menu hints in command line */

#include "vim.h"
#include "version.h"	/* used by dialog box routine for default title */
#include <windows.h>
#include <shellapi.h>
#ifdef USE_GUI_WIN32_TOOLBAR
#include <commctrl.h>
#endif
#include <windowsx.h>

/* 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

/* Some parameters for tearoff menus.  All in pixels. */
#define TEAROFF_PADDING_X	2
#define TEAROFF_BUTTON_PAD_X	8
#define TEAROFF_MIN_WIDTH	200
#define TEAROFF_SUBMENU_LABEL	">>"
#define TEAROFF_COLUMN_PADDING	3	// # spaces to pad column with.

#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 HINSTANCE  void *
# define HWND	    void *
# define HDC	    void *
# define HMENU	    void *
# define UINT	    int
# define WPARAM	    int
# define LPARAM	    int
typedef int LOGFONT[];
# define ENUMLOGFONT int
# define NEWTEXTMETRIC int
# define VOID	    void
# define CALLBACK
# define WORD	    int
# define DWORD	    int
# define HBITMAP    int
# define HDROP	    int
# define BOOL	    int
# define PWORD	    int
# define LPWORD	    int
# define LPRECT	    int
# define LRESULT    int
# define WINAPI
# define APIENTRY
# define LPSTR	    int
# define LPWINDOWPOS int
# define RECT	    int
# define LPCREATESTRUCT int
# define _cdecl
# define FINDREPLACE	int
# define LPCTSTR	int
# define OSVERSIONINFO int
#endif

/* For the Intellimouse: */
#ifndef WM_MOUSEWHEEL
#define WM_MOUSEWHEEL	0x20a
#endif

#ifdef MULTI_BYTE
static int sysfixed_width = 0;
static int sysfixed_height = 0;
#endif

/* Local variables: */
static int	    s_button_pending = -1;
static int	    s_x_pending;
static int	    s_y_pending;
static UINT	    s_kFlags_pending;

static HINSTANCE    s_hinst = NULL;
static HWND	    s_hwnd = NULL;
static HDC	    s_hdc = NULL;
#ifdef USE_GUI_WIN32_TOOLBAR
static HWND	    s_toolbarhwnd = NULL;
#endif
#ifdef WIN32_FIND_REPLACE
static HWND	    s_findrep_hwnd = NULL;
static UINT	    s_findrep_msg = 0;
static FINDREPLACE  s_findrep_struct;
static int	    s_findrep_is_find;
#endif
static HWND	    s_textArea = NULL;
static HMENU	    s_menuBar = NULL;
static UINT	    s_menu_id = 0;
static UINT	    s_wait_timer = 0;	/* Timer for get char from user */
static int	    destroying = FALSE;	/* calling DestroyWindow() ourselves */

static UINT	    s_uMsg = 0;
static WPARAM	    s_wParam = 0;
static LPARAM	    s_lParam = 0;

static int	    s_timed_out = FALSE;

static const LOGFONT s_lfDefault =
{
    -12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, DEFAULT_CHARSET,
    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
    PROOF_QUALITY, FIXED_PITCH | FF_DONTCARE,
    "Fixedsys"	/* see _ReadVimIni */
};

/* Initialise the "current height" to -12 (same as s_lfDefault) just
 * in case the user specifies a font in "guifont" with no size before a font
 * with an explicit size has been set. This defaults the size to this value
 * (-12 equates to roughly 9pt).
 */
static int current_font_height = -12;

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'},
    {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 */

    /* 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},
    {CR,	    CR, NUL},

    /* End of list marker: */
    {0,		    0, 0}
};


#define VIM_NAME	"vim"
#define VIM_CLASS	"Vim"

static int dead_key = 0;	/* 0 - no dead key, 1 - dead key pressed */
static OSVERSIONINFO os_version;    /* like it says.  Init in gui_mch_init() */

/* ron: No need to be stingy on Win32. Make it 16K - s/b big enough for
 * everyone!
 * I have had problems with the original 1000 byte, and with 2 or 5 K.  But
 * 16K should be good for all but the biggest.  Anyway, we free the memory
 * right away.
 */
#define DLG_ALLOC_SIZE 16 * 1024

/*
 * stuff for dialogs, menus, tearoffs etc.
 */
static LRESULT APIENTRY dialog_callback(HWND, UINT, WPARAM, LPARAM);
static LRESULT APIENTRY tearoff_callback(HWND, UINT, WPARAM, LPARAM);
static BOOL CenterWindow(HWND hwndChild, HWND hwndParent);
static PWORD
add_dialog_element(
	PWORD p,
	DWORD lStyle,
	WORD x,
	WORD y,
	WORD w,
	WORD h,
	WORD Id,
	WORD clss,
	const char *caption);
static LPWORD lpwAlign(LPWORD);
static int nCopyAnsiToWideChar(LPWORD, LPSTR);
static void gui_mch_tearoff(char_u *title, GuiMenu *menu, int initX, int initY);
static void rebuild_tearoff(GuiMenu *menu);
static void get_dialog_font_metrics(void);

/*
 * The scrollbar stuff can handle only up to 32767 lines.  When the file is
 * longer, scroll_shift is set to the number of shifts to reduce the count.
 */
static int scroll_shift = 0;

/* Intellimouse support */
static int mouse_scroll_lines = 0;
static UINT msh_msgmousewheel = 0;

static int	s_usenewlook;	    /* emulate W95/NT4 non-bold dialogs */
static WORD	s_dlgfntheight;	    /* height of the dialog font */
static WORD	s_dlgfntwidth;	    /* width of the dialog font	*/
static HBITMAP	s_htearbitmap;	    /* bitmap used to indicate tearoff */
#ifdef USE_GUI_WIN32_TOOLBAR
static void initialise_toolbar(void);
static int get_toolbar_bitmap(char_u *name);
#endif

#ifdef WIN32_FIND_REPLACE
static void initialise_findrep(char_u *initial_string);
static void find_rep_mode_adjust(char_u * buf);
#endif

#ifdef DEBUG
/*
 * Print out the last Windows error message
 */
    static void
print_windows_error(void)
{
    LPVOID  lpMsgBuf;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
		  NULL, GetLastError(),
		  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
		  (LPTSTR) &lpMsgBuf, 0, NULL);
    TRACE1("Error: %s\n", lpMsgBuf);
    LocalFree(lpMsgBuf);
}
#endif /* DEBUG */

/*
 * Return TRUE when running under Windows NT 3.x or Win32s, both of which have
 * less fancy GUI APIs.
 */
    static int
is_winnt_3(void)
{
    return ((os_version.dwPlatformId == VER_PLATFORM_WIN32_NT
		&& os_version.dwMajorVersion == 3)
	    || (os_version.dwPlatformId == VER_PLATFORM_WIN32s));
}

/*
 * Return TRUE when running under Win32s.
 */
    int
gui_is_win32s(void)
{
    return (os_version.dwPlatformId == VER_PLATFORM_WIN32s);
}

/*
 * Figure out how high the menu bar is at the moment.
 */
    static int
gui_w32_get_menu_height(
    int	    fix_window)	    /* If TRUE, resize window if menu height changed */
{
    static int	old_menu_height = -1;

    RECT    rc1, rc2;
    int	    num;
    int	    menu_height;

    if (gui.menu_is_active)
	num = GetMenuItemCount(s_menuBar);
    else
	num = 0;

    if (num == 0)
	menu_height = 0;
    else
    {
	if (is_winnt_3())	/* for NT 3.xx */
	{
	    RECT r1, r2;
	    int frameht = GetSystemMetrics(SM_CYFRAME);
	    int capht = GetSystemMetrics(SM_CYCAPTION);

	    /*	get window rect of s_hwnd
		get client rect of s_hwnd
		get cap height
		subtract from window rect, the sum of client height,
		(if not maximized)frame thickness, and caption height.
	     */
	    GetWindowRect(s_hwnd, &r1);
	    GetClientRect(s_hwnd, &r2);
	    menu_height = r1.bottom - r1.top - (r2.bottom-r2.top +
				   2 * frameht * (!IsZoomed(s_hwnd)) + capht);
	}
	else			/* win95 and variants (NT 4.0, I guess) */
	{
	    GetMenuItemRect(s_hwnd, s_menuBar, 0, &rc1);
	    GetMenuItemRect(s_hwnd, s_menuBar, num - 1, &rc2);
	    menu_height = rc2.bottom - rc1.top + 1;
	}
    }

    if (fix_window && menu_height != old_menu_height)
	gui_set_winsize(FALSE);

    old_menu_height = menu_height;
    return menu_height;
}

/*
 * Cursor blink functions.
 *
 * This is a simple state machine:
 * BLINK_NONE	not blinking at all
 * BLINK_OFF	blinking, cursor is not shown
 * BLINK_ON	blinking, cursor is shown
 */

#define BLINK_NONE  0
#define BLINK_OFF   1
#define BLINK_ON    2

static int		blink_state = BLINK_NONE;
static long_u		blink_waittime = 700;
static long_u		blink_ontime = 400;
static long_u		blink_offtime = 250;
static UINT		blink_timer = 0;

    void
gui_mch_set_blinking(long wait, long on, long off)
{
    blink_waittime = wait;
    blink_ontime = on;
    blink_offtime = off;
}

/* ARGSUSED */
    static VOID CALLBACK
_OnBlinkTimer(
    HWND hwnd,
    UINT uMsg,
    UINT idEvent,
    DWORD dwTime)
{
    MSG msg;

    /*
    TRACE2("Got timer event, id %d, blink_timer %d\n", idEvent, blink_timer);
    */

    KillTimer(NULL, idEvent);

    /* Eat spurious WM_TIMER messages */
    while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
	;

    if (blink_state == BLINK_ON)
    {
	gui_undraw_cursor();
	blink_state = BLINK_OFF;
	blink_timer = SetTimer(NULL, 0, (UINT)blink_offtime,
						    (TIMERPROC)_OnBlinkTimer);
    }
    else
    {
	gui_update_cursor(TRUE, FALSE);
	blink_state = BLINK_ON;
	blink_timer = SetTimer(NULL, 0, (UINT)blink_ontime,
						    (TIMERPROC)_OnBlinkTimer);
    }
}

    static void
gui_w32_rm_blink_timer(void)
{
    MSG msg;

    if (blink_timer != 0)
    {
	KillTimer(NULL, blink_timer);
	/* Eat spurious WM_TIMER messages */
	while (PeekMessage(&msg, s_hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
	    ;
	blink_timer = 0;
    }
}

/*
 * Stop the cursor blinking.  Show the cursor if it wasn't shown.
 */
    void
gui_mch_stop_blink(void)
{
    gui_w32_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_w32_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 = SetTimer(NULL, 0, (UINT)blink_waittime,
						    (TIMERPROC)_OnBlinkTimer);
	blink_state = BLINK_ON;
	gui_update_cursor(TRUE, FALSE);
    }
}

/*
 * Call-back routines.
 */

    static VOID CALLBACK
_OnTimer(
    HWND hwnd,
    UINT uMsg,
    UINT idEvent,
    DWORD dwTime)
{
    MSG msg;

    /*
    TRACE2("Got timer event, id %d, s_wait_timer %d\n", idEvent, s_wait_timer);
    */
    KillTimer(NULL, idEvent);
    s_timed_out = TRUE;

    /* Eat spurious WM_TIMER messages */
    while (PeekMessage(&msg, hwnd, WM_TIMER, WM_TIMER, PM_REMOVE))
	;
    if (idEvent == s_wait_timer)
	s_wait_timer = 0;
}

/*
 * Get this message when the user clicks on the cross in the top right corner
 * of a Windows95 window.
 */
    static void
_OnClose(
    HWND hwnd)
{
#ifdef USE_BROWSE
    int save_browse = browse;
#endif
#if defined(GUI_DIALOG) || defined(CON_DIALOG)
    int save_confirm = confirm;
#endif

    /* Only exit when there are no changed files */
    exiting = TRUE;
#ifdef USE_BROWSE
    browse = TRUE;
#endif
#if defined(GUI_DIALOG) || defined(CON_DIALOG)
    confirm = TRUE;
#endif
    if (!check_changed_any(FALSE))    /* will give warning for changed buffer */
	getout(0);

    exiting = FALSE;
#ifdef USE_BROWSE
    browse = save_browse;
#endif
#if defined(GUI_DIALOG) || defined(CON_DIALOG)
    confirm = save_confirm;
#endif
    setcursor();		    /* position cursor */
    out_flush();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -