changeset 13150:808625d4b71b v8.0.1449

patch 8.0.1449: slow redrawing with DirectX commit https://github.com/vim/vim/commit/a338adcf222b6a24e26ea5ae6a2ad27f914acb38 Author: Bram Moolenaar <Bram@vim.org> Date: Wed Jan 31 20:51:47 2018 +0100 patch 8.0.1449: slow redrawing with DirectX Problem: Slow redrawing with DirectX. Solution: Avoid calling gui_mch_flush() unnecessarily, especially when updating the cursor. (Ken Takata, closes #2560)
author Christian Brabandt <cb@256bit.org>
date Wed, 31 Jan 2018 21:00:08 +0100
parents 46794b7ab97a
children 3a3ecd0efd62
files runtime/doc/options.txt src/channel.c src/edit.c src/getchar.c src/gui.c src/gui_dwrite.cpp src/gui_dwrite.h src/gui_w32.c src/macros.h src/main.c src/message.c src/netbeans.c src/proto/gui.pro src/proto/term.pro src/screen.c src/search.c src/term.c src/ui.c src/version.c
diffstat 19 files changed, 226 insertions(+), 175 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -6122,7 +6122,7 @@ A jump table for the options with a shor
 		  geom	    pixelGeometry	int	0 - 2 (see below)
 		  renmode   renderingMode	int	0 - 6 (see below)
 		  taamode   textAntialiasMode	int	0 - 3 (see below)
-		  scrlines  Scroll Lines	int	>= 0  (see below)
+		  scrlines  Scroll Lines	int	(deprecated)
 
 		See this URL for detail (except for scrlines):
 		  https://msdn.microsoft.com/en-us/library/dd368190.aspx
@@ -6156,23 +6156,9 @@ A jump table for the options with a shor
 		See this URL for detail:
 		  https://msdn.microsoft.com/en-us/library/dd368170.aspx
 
-		For scrlines: threshold for lines to be scrolled.
-		    0 - Always use scrolling. (default)
-		    1 - Use full page redrawing.
-		  > 1 - If the lines to be scrolled is grater or equal to the
-			specified value, use redrawing.  Otherwise use
-			scrolling.
-
-		If you feel scrolling a page (CTRL-F) is too slow with DirectX
-		renderer, try this "scrlines" option.
-		When set it "1", Vim uses full page redrawing instead of
-		scrolling.  Redrawing a page is faster than scrolling a
-		page in some environments.
-		After that, when you feel scrolling lines (CTRL-Y) becomes
-		slow, please try "2" or greater value for this option.
-		It works threshold line number to switch scrolling to
-		redrawing.  Scrolling a few lines might be faster than
-		redrawing a page in some environments.
+		For scrlines:
+		This was used for optimizing scrolling behavior, however this
+		is now deprecated.  If specified, it is simply ignored.
 
 		Example: >
 		  set encoding=utf-8
--- a/src/channel.c
+++ b/src/channel.c
@@ -2207,14 +2207,7 @@ channel_exe_cmd(channel_T *channel, ch_p
 	ex_redraw(&ea);
 	showruler(FALSE);
 	setcursor();
-	out_flush();
-#ifdef FEAT_GUI
-	if (gui.in_use)
-	{
-	    gui_update_cursor(TRUE, FALSE);
-	    gui_mch_flush();
-	}
-#endif
+	out_flush_cursor(TRUE, FALSE);
     }
     else if (STRCMP(cmd, "expr") == 0 || STRCMP(cmd, "call") == 0)
     {
--- a/src/edit.c
+++ b/src/edit.c
@@ -3451,7 +3451,7 @@ ins_compl_clear(void)
     compl_orig_text = NULL;
     compl_enter_selects = FALSE;
     /* clear v:completed_item */
-    set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+    set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
 }
 
 /*
@@ -3553,8 +3553,7 @@ ins_compl_new_leader(void)
 	{
 	    /* Show the cursor after the match, not after the redrawn text. */
 	    setcursor();
-	    out_flush();
-	    gui_update_cursor(FALSE, FALSE);
+	    out_flush_cursor(FALSE, FALSE);
 	}
 #endif
 	compl_restarting = TRUE;
@@ -4704,7 +4703,7 @@ ins_compl_delete(void)
      * flicker, thus we can't do that. */
     changed_cline_bef_curs();
     /* clear v:completed_item */
-    set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc());
+    set_vim_var_dict(VV_COMPLETED_ITEM, dict_alloc_lock(VAR_FIXED));
 }
 
 /*
@@ -4724,7 +4723,7 @@ ins_compl_insert(int in_compl_func)
 
     /* Set completed item. */
     /* { word, abbr, menu, kind, info } */
-    dict = dict_alloc();
+    dict = dict_alloc_lock(VAR_FIXED);
     if (dict != NULL)
     {
 	dict_add_nr_str(dict, "word", 0L,
@@ -4936,8 +4935,7 @@ ins_compl_next(
 	{
 	    /* Show the cursor after the match, not after the redrawn text. */
 	    setcursor();
-	    out_flush();
-	    gui_update_cursor(FALSE, FALSE);
+	    out_flush_cursor(FALSE, FALSE);
 	}
 #endif
 
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -2972,16 +2972,10 @@ inchar(
     if (wait_time == -1L || wait_time > 100L)  /* flush output before waiting */
     {
 	cursor_on();
-	out_flush();
-#ifdef FEAT_GUI
-	if (gui.in_use)
-	{
-	    gui_update_cursor(FALSE, FALSE);
-# ifdef FEAT_MOUSESHAPE
-	    if (postponed_mouseshape)
-		update_mouseshape(-1);
-# endif
-	}
+	out_flush_cursor(FALSE, FALSE);
+#if defined(FEAT_GUI) && defined(FEAT_MOUSESHAPE)
+	if (gui.in_use && postponed_mouseshape)
+	    update_mouseshape(-1);
 #endif
     }
 
--- a/src/gui.c
+++ b/src/gui.c
@@ -55,6 +55,7 @@ enum {
 static void gui_attempt_start(void);
 
 static int can_update_cursor = TRUE; /* can display the cursor */
+static int disable_flush = 0;	/* If > 0, gui_mch_flush() is disabled. */
 
 /*
  * The Athena scrollbars can move the thumb to after the end of the scrollbar,
@@ -1976,7 +1977,7 @@ gui_write(
     gui.dragged_sb = SBAR_NONE;
 #endif
 
-    gui_mch_flush();		    /* In case vim decides to take a nap */
+    gui_may_flush();		    /* In case vim decides to take a nap */
 }
 
 /*
@@ -2004,6 +2005,34 @@ gui_can_update_cursor(void)
      * after scrolling. */
 }
 
+/*
+ * Disable issuing gui_mch_flush().
+ */
+    void
+gui_disable_flush(void)
+{
+    ++disable_flush;
+}
+
+/*
+ * Enable issuing gui_mch_flush().
+ */
+    void
+gui_enable_flush(void)
+{
+    --disable_flush;
+}
+
+/*
+ * Issue gui_mch_flush() if it is not disabled.
+ */
+    void
+gui_may_flush(void)
+{
+    if (disable_flush == 0)
+	gui_mch_flush();
+}
+
     static void
 gui_outstr(char_u *s, int len)
 {
@@ -3682,7 +3711,6 @@ gui_update_tabline(void)
 	/* Updating the tabline uses direct GUI commands, flush
 	 * outstanding instructions first. (esp. clear screen) */
 	out_flush();
-	gui_mch_flush();
 
 	if (!showit != !shown)
 	    gui_mch_show_tabline(showit);
@@ -4122,8 +4150,7 @@ gui_drag_scrollbar(scrollbar_T *sb, long
 	setcursor();
     }
 # endif
-    out_flush();
-    gui_update_cursor(FALSE, TRUE);
+    out_flush_cursor(FALSE, TRUE);
 #else
     add_to_input_buf(bytes, byte_count);
     add_long_to_buf((long_u)value, bytes);
@@ -4486,7 +4513,9 @@ gui_do_scroll(void)
 	 * disappear when losing focus after a scrollbar drag. */
 	if (wp->w_redr_type < type)
 	    wp->w_redr_type = type;
+	mch_disable_flush();
 	updateWindow(wp);   /* update window, status line, and cmdline */
+	mch_enable_flush();
     }
 
 #ifdef FEAT_INS_EXPAND
@@ -4797,8 +4826,7 @@ gui_focus_change(int in_focus)
  */
 #if 1
     gui.in_focus = in_focus;
-    out_flush();		/* make sure output has been written */
-    gui_update_cursor(TRUE, FALSE);
+    out_flush_cursor(TRUE, FALSE);
 
 # ifdef FEAT_XIM
     xim_set_focus(in_focus);
@@ -5157,9 +5185,7 @@ gui_update_screen(void)
 	curwin->w_valid &= ~VALID_CROW;
     }
 # endif
-    out_flush();		/* make sure output has been written */
-    gui_update_cursor(TRUE, FALSE);
-    gui_mch_flush();
+    out_flush_cursor(TRUE, FALSE);
 }
 #endif
 
@@ -5516,9 +5542,7 @@ gui_handle_drop(
 	maketitle();
 #endif
 	setcursor();
-	out_flush();
-	gui_update_cursor(FALSE, FALSE);
-	gui_mch_flush();
+	out_flush_cursor(FALSE, FALSE);
     }
 
     entered = FALSE;
--- a/src/gui_dwrite.cpp
+++ b/src/gui_dwrite.cpp
@@ -286,6 +286,7 @@ struct DWriteContext {
     ID2D1DCRenderTarget *mRT;
     ID2D1GdiInteropRenderTarget *mGDIRT;
     ID2D1SolidColorBrush *mBrush;
+    ID2D1Bitmap *mBitmap;
 
     IDWriteFactory *mDWriteFactory;
 #ifdef FEAT_DIRECTX_COLOR_EMOJI
@@ -319,6 +320,8 @@ struct DWriteContext {
 
     void SetFont(HFONT hFont);
 
+    void Rebind();
+
     void BindDC(HDC hdc, const RECT *rect);
 
     HRESULT SetDrawingMode(DrawingMode mode);
@@ -335,6 +338,8 @@ struct DWriteContext {
 
     void SetPixel(int x, int y, COLORREF color);
 
+    void Scroll(int x, int y, const RECT *rc);
+
     void Flush();
 
     void SetRenderingParams(
@@ -596,6 +601,7 @@ DWriteContext::DWriteContext() :
     mRT(NULL),
     mGDIRT(NULL),
     mBrush(NULL),
+    mBitmap(NULL),
     mDWriteFactory(NULL),
 #ifdef FEAT_DIRECTX_COLOR_EMOJI
     mDWriteFactory2(NULL),
@@ -616,9 +622,6 @@ DWriteContext::DWriteContext() :
     _RPT2(_CRT_WARN, "D2D1CreateFactory: hr=%p p=%p\n", hr, mD2D1Factory);
 
     if (SUCCEEDED(hr))
-	hr = CreateDeviceResources();
-
-    if (SUCCEEDED(hr))
     {
 	hr = DWriteCreateFactory(
 		DWRITE_FACTORY_TYPE_SHARED,
@@ -662,6 +665,7 @@ DWriteContext::~DWriteContext()
 #ifdef FEAT_DIRECTX_COLOR_EMOJI
     SafeRelease(&mDWriteFactory2);
 #endif
+    SafeRelease(&mBitmap);
     SafeRelease(&mBrush);
     SafeRelease(&mGDIRT);
     SafeRelease(&mRT);
@@ -704,13 +708,7 @@ DWriteContext::CreateDeviceResources()
     }
 
     if (SUCCEEDED(hr))
-    {
-	if (mHDC != NULL)
-	{
-	    mRT->BindDC(mHDC, &mBindRect);
-	    mRT->SetTransform(D2D1::IdentityMatrix());
-	}
-    }
+	Rebind();
 
     return hr;
 }
@@ -718,6 +716,7 @@ DWriteContext::CreateDeviceResources()
     void
 DWriteContext::DiscardDeviceResources()
 {
+    SafeRelease(&mBitmap);
     SafeRelease(&mBrush);
     SafeRelease(&mGDIRT);
     SafeRelease(&mRT);
@@ -899,13 +898,36 @@ DWriteContext::SetFont(HFONT hFont)
 }
 
     void
+DWriteContext::Rebind()
+{
+    SafeRelease(&mBitmap);
+
+    mRT->BindDC(mHDC, &mBindRect);
+    mRT->SetTransform(D2D1::IdentityMatrix());
+
+    D2D1_BITMAP_PROPERTIES props = {
+	{DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE},
+	96.0f, 96.0f
+    };
+    mRT->CreateBitmap(
+	    D2D1::SizeU(mBindRect.right - mBindRect.left,
+		mBindRect.bottom - mBindRect.top),
+	    props, &mBitmap);
+}
+
+    void
 DWriteContext::BindDC(HDC hdc, const RECT *rect)
 {
-    Flush();
-    mRT->BindDC(hdc, rect);
-    mRT->SetTransform(D2D1::IdentityMatrix());
     mHDC = hdc;
     mBindRect = *rect;
+
+    if (mRT == NULL)
+	CreateDeviceResources();
+    else
+    {
+	Flush();
+	Rebind();
+    }
 }
 
     HRESULT
@@ -1081,6 +1103,49 @@ DWriteContext::SetPixel(int x, int y, CO
 }
 
     void
+DWriteContext::Scroll(int x, int y, const RECT *rc)
+{
+    SetDrawingMode(DM_DIRECTX);
+    mRT->Flush();
+
+    D2D1_RECT_U srcRect;
+    D2D1_POINT_2U destPoint;
+    if (x >= 0)
+    {
+	srcRect.left = rc->left;
+	srcRect.right = rc->right - x;
+	destPoint.x = rc->left + x;
+    }
+    else
+    {
+	srcRect.left = rc->left - x;
+	srcRect.right = rc->right;
+	destPoint.x = rc->left;
+    }
+    if (y >= 0)
+    {
+	srcRect.top = rc->top;
+	srcRect.bottom = rc->bottom - y;
+	destPoint.y = rc->top + y;
+    }
+    else
+    {
+	srcRect.top = rc->top - y;
+	srcRect.bottom = rc->bottom;
+	destPoint.y = rc->top;
+    }
+    mBitmap->CopyFromRenderTarget(&destPoint, mRT, &srcRect);
+
+    D2D1_RECT_F destRect = {
+	    FLOAT(destPoint.x), FLOAT(destPoint.y),
+	    FLOAT(destPoint.x + srcRect.right - srcRect.left),
+	    FLOAT(destPoint.y + srcRect.bottom - srcRect.top)
+    };
+    mRT->DrawBitmap(mBitmap, destRect, 1.0F,
+	    D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR, destRect);
+}
+
+    void
 DWriteContext::Flush()
 {
     SetDrawingMode(DM_GDI);
@@ -1240,6 +1305,13 @@ DWriteContext_SetPixel(DWriteContext *ct
 }
 
     void
+DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc)
+{
+    if (ctx != NULL)
+	ctx->Scroll(x, y, rc);
+}
+
+    void
 DWriteContext_Flush(DWriteContext *ctx)
 {
     if (ctx != NULL)
--- a/src/gui_dwrite.h
+++ b/src/gui_dwrite.h
@@ -74,6 +74,7 @@ void DWriteContext_FillRect(DWriteContex
 void DWriteContext_DrawLine(DWriteContext *ctx, int x1, int y1, int x2, int y2,
 	COLORREF color);
 void DWriteContext_SetPixel(DWriteContext *ctx, int x, int y, COLORREF color);
+void DWriteContext_Scroll(DWriteContext *ctx, int x, int y, const RECT *rc);
 void DWriteContext_Flush(DWriteContext *ctx);
 void DWriteContext_Close(DWriteContext *ctx);
 
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -36,7 +36,6 @@
 static DWriteContext *s_dwc = NULL;
 static int s_directx_enabled = 0;
 static int s_directx_load_attempted = 0;
-static int s_directx_scrlines = 0;
 # define IS_ENABLE_DIRECTX() (s_directx_enabled && s_dwc != NULL && enc_utf8)
 static int directx_enabled(void);
 static void directx_binddc(void);
@@ -61,7 +60,6 @@ gui_mch_set_rendering_options(char_u *s)
     int	    dx_geom = 0;
     int	    dx_renmode = 0;
     int	    dx_taamode = 0;
-    int	    dx_scrlines = 0;
 
     /* parse string as rendering options. */
     for (p = s; p != NULL && *p != NUL; )
@@ -124,7 +122,7 @@ gui_mch_set_rendering_options(char_u *s)
 	}
 	else if (STRCMP(name, "scrlines") == 0)
 	{
-	    dx_scrlines = atoi((char *)value);
+	    /* Deprecated.  Simply ignore it. */
 	}
 	else
 	    return FAIL;
@@ -159,7 +157,6 @@ gui_mch_set_rendering_options(char_u *s)
 	}
     }
     s_directx_enabled = dx_enable;
-    s_directx_scrlines = dx_scrlines;
 
     return OK;
 # else
@@ -3129,9 +3126,6 @@ gui_mch_delete_lines(
     int	    num_lines)
 {
     RECT	rc;
-#if defined(FEAT_DIRECTX)
-    int		use_redraw = 0;
-#endif
 
     rc.left = FILL_X(gui.scroll_region_left);
     rc.right = FILL_X(gui.scroll_region_right + 1);
@@ -3141,16 +3135,10 @@ gui_mch_delete_lines(
 #if defined(FEAT_DIRECTX)
     if (IS_ENABLE_DIRECTX())
     {
-	if (s_directx_scrlines > 0 && s_directx_scrlines <= num_lines)
-	{
-	    gui_redraw(rc.left, rc.top,
-		    rc.right - rc.left + 1, rc.bottom - rc.top + 1);
-	    use_redraw = 1;
-	}
-	else
-	    DWriteContext_Flush(s_dwc);
-    }
-    if (!use_redraw)
+	DWriteContext_Scroll(s_dwc, 0, -num_lines * gui.char_height, &rc);
+	DWriteContext_Flush(s_dwc);
+    }
+    else
 #endif
     {
 	intel_gpu_workaround();
@@ -3180,9 +3168,6 @@ gui_mch_insert_lines(
     int		num_lines)
 {
     RECT	rc;
-#if defined(FEAT_DIRECTX)
-    int		use_redraw = 0;
-#endif
 
     rc.left = FILL_X(gui.scroll_region_left);
     rc.right = FILL_X(gui.scroll_region_right + 1);
@@ -3192,16 +3177,10 @@ gui_mch_insert_lines(
 #if defined(FEAT_DIRECTX)
     if (IS_ENABLE_DIRECTX())
     {
-	if (s_directx_scrlines > 0 && s_directx_scrlines <= num_lines)
-	{
-	    gui_redraw(rc.left, rc.top,
-		    rc.right - rc.left + 1, rc.bottom - rc.top + 1);
-	    use_redraw = 1;
-	}
-	else
-	    DWriteContext_Flush(s_dwc);
-    }
-    if (!use_redraw)
+	DWriteContext_Scroll(s_dwc, 0, num_lines * gui.char_height, &rc);
+	DWriteContext_Flush(s_dwc);
+    }
+    else
 #endif
     {
 	intel_gpu_workaround();
@@ -4024,7 +4003,10 @@ gui_mch_browse(
      * position, but don't actually scroll by setting "dont_scroll". */
     dont_scroll = !allow_scrollbar;
 
+    mch_disable_flush();
     gui_drag_scrollbar(sb, val, dragging);
+    mch_enable_flush();
+    gui_may_flush();
 
     s_busy_processing = FALSE;
     dont_scroll = dont_scroll_save;
@@ -4651,6 +4633,7 @@ init_mouse_wheel(void)
     if (mouse_scroll_lines == 0)
 	init_mouse_wheel();
 
+    mch_disable_flush();
     if (mouse_scroll_lines > 0
 	    && mouse_scroll_lines < (size > 2 ? size - 2 : 1))
     {
@@ -4659,6 +4642,8 @@ init_mouse_wheel(void)
     }
     else
 	_OnScroll(hwnd, hwndCtl, zDelta >= 0 ? SB_PAGEUP : SB_PAGEDOWN, 0);
+    mch_enable_flush();
+    gui_may_flush();
 }
 
 #ifdef USE_SYSMENU_FONT
--- a/src/macros.h
+++ b/src/macros.h
@@ -365,6 +365,17 @@
  * HIKEY2DI() converts a hashitem key pointer to a dictitem pointer.
  * HI2DI() converts a hashitem pointer to a dictitem pointer.
  */
-# define DI2HIKEY(di) ((di)->di_key)
-# define HIKEY2DI(p)  ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
-# define HI2DI(hi)     HIKEY2DI((hi)->hi_key)
+#define DI2HIKEY(di) ((di)->di_key)
+#define HIKEY2DI(p)  ((dictitem_T *)(p - offsetof(dictitem_T, di_key)))
+#define HI2DI(hi)     HIKEY2DI((hi)->hi_key)
+
+/*
+ * Flush control functions.
+ */
+#ifdef FEAT_GUI
+# define mch_enable_flush()	gui_enable_flush()
+# define mch_disable_flush()	gui_disable_flush()
+#else
+# define mch_enable_flush()
+# define mch_disable_flush()
+#endif
--- a/src/main.c
+++ b/src/main.c
@@ -1242,7 +1242,11 @@ main_loop(
 	    if (VIsual_active)
 		update_curbuf(INVERTED);/* update inverted part */
 	    else if (must_redraw)
+	    {
+		mch_disable_flush();	/* Stop issuing gui_mch_flush(). */
 		update_screen(0);
+		mch_enable_flush();
+	    }
 	    else if (redraw_cmdline || clear_cmdline)
 		showmode();
 	    redraw_statuslines();
@@ -1283,11 +1287,13 @@ main_loop(
 			|| conceal_cursor_line(curwin)
 			|| need_cursor_line_redraw))
 	    {
+		mch_disable_flush();	/* Stop issuing gui_mch_flush(). */
 		if (conceal_old_cursor_line != conceal_new_cursor_line
 			&& conceal_old_cursor_line
 						<= curbuf->b_ml.ml_line_count)
 		    update_single_line(curwin, conceal_old_cursor_line);
 		update_single_line(curwin, conceal_new_cursor_line);
+		mch_enable_flush();
 		curwin->w_valid &= ~VALID_CROW;
 	    }
 # endif
@@ -4212,11 +4218,7 @@ eval_client_expr_to_string(char_u *expr)
     /* A client can tell us to redraw, but not to display the cursor, so do
      * that here. */
     setcursor();
-    out_flush();
-#ifdef FEAT_GUI
-    if (gui.in_use)
-	gui_update_cursor(FALSE, FALSE);
-#endif
+    out_flush_cursor(FALSE, FALSE);
 
     return res;
 }
--- a/src/message.c
+++ b/src/message.c
@@ -2316,7 +2316,9 @@ msg_scroll_up(void)
 	gui_undraw_cursor();
 #endif
     /* scrolling up always works */
+    mch_disable_flush();
     screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL);
+    mch_enable_flush();
 
     if (!can_clear((char_u *)" "))
     {
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -121,14 +121,7 @@ netbeans_close(void)
     update_screen(CLEAR);
     setcursor();
     cursor_on();
-    out_flush();
-#ifdef FEAT_GUI
-    if (gui.in_use)
-    {
-	gui_update_cursor(TRUE, FALSE);
-	gui_mch_flush();
-    }
-#endif
+    out_flush_cursor(TRUE, FALSE);
 }
 
 #define NB_DEF_HOST "localhost"
@@ -1848,14 +1841,8 @@ nb_do_cmd(
 	    update_screen(VALID);
 	    setcursor();
 	    cursor_on();
-	    out_flush();
-#ifdef FEAT_GUI
-	    if (gui.in_use)
-	    {
-		gui_update_cursor(TRUE, FALSE);
-		gui_mch_flush();
-	    }
-#endif
+	    out_flush_cursor(TRUE, FALSE);
+
 	    /* Quit a hit-return or more prompt. */
 	    if (State == HITRETURN || State == ASKMORE)
 	    {
@@ -2248,14 +2235,8 @@ nb_do_cmd(
 	update_screen(NOT_VALID);
 	setcursor();
 	cursor_on();
-	out_flush();
-#ifdef FEAT_GUI
-	if (gui.in_use)
-	{
-	    gui_update_cursor(TRUE, FALSE);
-	    gui_mch_flush();
-	}
-#endif
+	out_flush_cursor(TRUE, FALSE);
+
 	/* Quit a hit-return or more prompt. */
 	if (State == HITRETURN || State == ASKMORE)
 	{
@@ -2307,15 +2288,7 @@ coloncmd(char *cmd, ...)
 /*     ALT_INPUT_LOCK_OFF; */
 
     setcursor();		/* restore the cursor position */
-    out_flush();		/* make sure output has been written */
-
-#ifdef FEAT_GUI
-    if (gui.in_use)
-    {
-	gui_update_cursor(TRUE, FALSE);
-	gui_mch_flush();
-    }
-#endif
+    out_flush_cursor(TRUE, FALSE);
 }
 
 
@@ -2569,14 +2542,7 @@ netbeans_open(char *params, int doabort)
     update_screen(CLEAR);
     setcursor();
     cursor_on();
-    out_flush();
-#ifdef FEAT_GUI
-    if (gui.in_use)
-    {
-	gui_update_cursor(TRUE, FALSE);
-	gui_mch_flush();
-    }
-#endif
+    out_flush_cursor(TRUE, FALSE);
 }
 
 /*
--- a/src/proto/gui.pro
+++ b/src/proto/gui.pro
@@ -25,6 +25,9 @@ void gui_update_cursor_later(void);
 void gui_write(char_u *s, int len);
 void gui_dont_update_cursor(int undraw);
 void gui_can_update_cursor(void);
+void gui_disable_flush(void);
+void gui_enable_flush(void);
+void gui_may_flush(void);
 int gui_outstr_nowrap(char_u *s, int len, int flags, guicolor_T fg, guicolor_T bg, int back);
 void gui_undraw_cursor(void);
 void gui_redraw(int x, int y, int w, int h);
--- a/src/proto/term.pro
+++ b/src/proto/term.pro
@@ -12,6 +12,7 @@ int term_is_gui(char_u *name);
 char_u *tltoa(unsigned long i);
 void termcapinit(char_u *name);
 void out_flush(void);
+void out_flush_cursor(int force, int clear_selection);
 void out_flush_check(void);
 void out_trash(void);
 void out_char(unsigned c);
--- a/src/screen.c
+++ b/src/screen.c
@@ -468,16 +468,14 @@ redraw_after_callback(int call_update_sc
 	setcursor();
     }
     cursor_on();
-    out_flush();
 #ifdef FEAT_GUI
-    if (gui.in_use)
-    {
+    if (gui.in_use && !gui_mch_is_blink_off())
 	/* Don't update the cursor when it is blinking and off to avoid
 	 * flicker. */
-	if (!gui_mch_is_blink_off())
-	    gui_update_cursor(FALSE, FALSE);
-	gui_mch_flush();
-    }
+	out_flush_cursor(FALSE, FALSE);
+    else
+#else
+	out_flush();
 #endif
 
     --redrawing_for_callback;
@@ -800,9 +798,12 @@ update_screen(int type_arg)
      * done. */
     if (gui.in_use)
     {
-	out_flush();	/* required before updating the cursor */
 	if (did_undraw && !gui_mch_is_blink_off())
 	{
+	    mch_disable_flush();
+	    out_flush();	/* required before updating the cursor */
+	    mch_enable_flush();
+
 	    /* Put the GUI position where the cursor was, gui_update_cursor()
 	     * uses that. */
 	    gui.col = gui_cursor_col;
@@ -811,9 +812,12 @@ update_screen(int type_arg)
 	    gui.col = mb_fix_col(gui.col, gui.row);
 # endif
 	    gui_update_cursor(FALSE, FALSE);
+	    gui_may_flush();
 	    screen_cur_col = gui.col;
 	    screen_cur_row = gui.row;
 	}
+	else
+	    out_flush();
 	gui_update_scrollbars(FALSE);
     }
 #endif
@@ -863,8 +867,7 @@ update_finish(void)
      * done. */
     if (gui.in_use)
     {
-	out_flush();	/* required before updating the cursor */
-	gui_update_cursor(FALSE, FALSE);
+	out_flush_cursor(FALSE, FALSE);
 	gui_update_scrollbars(FALSE);
     }
 # endif
--- a/src/search.c
+++ b/src/search.c
@@ -2675,14 +2675,8 @@ showmatch(
 	    showruler(FALSE);
 	    setcursor();
 	    cursor_on();		/* make sure that the cursor is shown */
-	    out_flush();
-#ifdef FEAT_GUI
-	    if (gui.in_use)
-	    {
-		gui_update_cursor(TRUE, FALSE);
-		gui_mch_flush();
-	    }
-#endif
+	    out_flush_cursor(TRUE, FALSE);
+
 	    /* Restore dollar_vcol(), because setcursor() may call curs_rows()
 	     * which resets it if the matching position is in a previous line
 	     * and has a higher column number. */
--- a/src/term.c
+++ b/src/term.c
@@ -2501,6 +2501,27 @@ out_flush(void)
     }
 }
 
+/*
+ * out_flush_cursor(): flush the output buffer and redraw the cursor
+ */
+    void
+out_flush_cursor(
+    int	    force UNUSED,   /* when TRUE, update cursor even when not moved */
+    int	    clear_selection UNUSED) /* clear selection under cursor */
+{
+    mch_disable_flush();
+    out_flush();
+    mch_enable_flush();
+#ifdef FEAT_GUI
+    if (gui.in_use)
+    {
+	gui_update_cursor(force, clear_selection);
+	gui_may_flush();
+    }
+#endif
+}
+
+
 #if defined(FEAT_MBYTE) || defined(PROTO)
 /*
  * Sometimes a byte out of a multi-byte character is written with out_char().
--- a/src/ui.c
+++ b/src/ui.c
@@ -245,7 +245,7 @@ ui_wait_for_chars_or_timer(
 	if (interrupted != NULL && *interrupted)
 	    /* Nothing available, but need to return so that side effects get
 	     * handled, such as handling a message on a channel. */
-	    return FALSE;
+	    return FAIL;
 	if (wtime > 0)
 	    remaining -= due_time;
     }
@@ -578,11 +578,7 @@ clip_lose_selection(VimClipboard *cbd)
 	    update_curbuf(INVERTED_ALL);
 	    setcursor();
 	    cursor_on();
-	    out_flush();
-# ifdef FEAT_GUI
-	    if (gui.in_use)
-		gui_update_cursor(TRUE, FALSE);
-# endif
+	    out_flush_cursor(TRUE, FALSE);
 	}
     }
 #endif
@@ -3331,13 +3327,10 @@ ui_focus_change(
 	    setcursor();
 	}
 	cursor_on();	    /* redrawing may have switched it off */
-	out_flush();
+	out_flush_cursor(FALSE, TRUE);
 # ifdef FEAT_GUI
 	if (gui.in_use)
-	{
-	    gui_update_cursor(FALSE, TRUE);
 	    gui_update_scrollbars(FALSE);
-	}
 # endif
     }
 #ifdef FEAT_TITLE
--- a/src/version.c
+++ b/src/version.c
@@ -772,6 +772,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1449,
+/**/
     1448,
 /**/
     1447,