diff src/gui_w16.c @ 7:3fc0f57ecb91 v7.0001

updated for version 7.0001
author vimboss
date Sun, 13 Jun 2004 20:20:40 +0000
parents
children 80000fb16feb
line wrap: on
line diff
new file mode 100644
--- /dev/null
+++ b/src/gui_w16.c
@@ -0,0 +1,1524 @@
+/* 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.
+ *
+ */
+
+/*
+ * 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);
+    }
+
+    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)
+	    {
+		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)
+{
+    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 posision 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 (win_xpos + win_width > workarea_rect.right)
+	win_xpos = workarea_rect.right - win_width;
+
+    if (win_xpos < workarea_rect.left)
+	win_xpos = workarea_rect.left;
+
+    if (win_ypos + win_height > workarea_rect.bottom)
+	win_ypos = workarea_rect.bottom - win_height;
+
+    if (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);
+}
+
+
+
+    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)
+	{
+	    int cell_len = 0;
+
+	    /* Compute the length in display cells. */
+	    for (n = 0; n < len; n += MB_BYTE2LEN(text[n]))
+		cell_len += (*mb_ptr2cells)(text + n);
+	    rc.right = FILL_X(col + cell_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);
+}
+
+
+
+
+#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)
+{
+    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 (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)
+{
+    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.  complier 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)
+#include "gui_w3~1.h"
+/*
+ * 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 inital 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