changeset 17055:f4de7ccdfd8c v8.1.1527

patch 8.1.1527: when moving popup window over the cmdline it is not redrawn commit https://github.com/vim/vim/commit/a540f8aa3b2570f1d903b63413301ec3d48b27d5 Author: Bram Moolenaar <Bram@vim.org> Date: Fri Jun 14 19:23:57 2019 +0200 patch 8.1.1527: when moving popup window over the cmdline it is not redrawn Problem: When moving a popup window over the command line it is not redrawn. Solution: Redraw the command line. Move popup redrawing code to the popupwin file.
author Bram Moolenaar <Bram@vim.org>
date Fri, 14 Jun 2019 19:30:05 +0200
parents aebfdd4e9ac5
children 6bb95f6facc8
files src/popupwin.c src/proto/popupwin.pro src/proto/screen.pro src/screen.c src/testdir/dumps/Test_popupwin_drag_01.dump src/testdir/dumps/Test_popupwin_drag_02.dump src/testdir/test_popupwin.vim src/version.c
diffstat 8 files changed, 364 insertions(+), 306 deletions(-) [+]
line wrap: on
line diff
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -1372,4 +1372,310 @@ popup_check_cursor_pos()
 	}
 }
 
+/*
+ * Update "popup_mask" if needed.
+ * Also recomputes the popup size and positions.
+ * Also updates "popup_visible".
+ * Also marks window lines for redrawing.
+ */
+    void
+may_update_popup_mask(int type)
+{
+    win_T	*wp;
+    short	*mask;
+    int		line, col;
+    int		redraw_all = FALSE;
+
+    // Need to recompute when switching tabs.
+    // Also recompute when the type is CLEAR or NOT_VALID, something basic
+    // (such as the screen size) must have changed.
+    if (popup_mask_tab != curtab || type >= NOT_VALID)
+    {
+	popup_mask_refresh = TRUE;
+	redraw_all = TRUE;
+    }
+    if (!popup_mask_refresh)
+    {
+	// Check if any buffer has changed.
+	for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
+	    if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
+		popup_mask_refresh = TRUE;
+	for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
+	    if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
+		popup_mask_refresh = TRUE;
+	if (!popup_mask_refresh)
+	    return;
+    }
+
+    // Need to update the mask, something has changed.
+    popup_mask_refresh = FALSE;
+    popup_mask_tab = curtab;
+    popup_visible = FALSE;
+
+    // If redrawing everything, just update "popup_mask".
+    // If redrawing only what is needed, update "popup_mask_next" and then
+    // compare with "popup_mask" to see what changed.
+    if (type >= SOME_VALID)
+	mask = popup_mask;
+    else
+	mask = popup_mask_next;
+    vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short));
+
+    // Find the window with the lowest zindex that hasn't been handled yet,
+    // so that the window with a higher zindex overwrites the value in
+    // popup_mask.
+    popup_reset_handled();
+    while ((wp = find_next_popup(TRUE)) != NULL)
+    {
+	popup_visible = TRUE;
+
+	// Recompute the position if the text changed.
+	if (redraw_all
+		|| wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
+	    popup_adjust_position(wp);
+
+	for (line = wp->w_winrow;
+		line < wp->w_winrow + popup_height(wp)
+						 && line < screen_Rows; ++line)
+	    for (col = wp->w_wincol;
+		 col < wp->w_wincol + popup_width(wp)
+						&& col < screen_Columns; ++col)
+		mask[line * screen_Columns + col] = wp->w_zindex;
+    }
+
+    // Only check which lines are to be updated if not already
+    // updating all lines.
+    if (mask == popup_mask_next)
+	for (line = 0; line < screen_Rows; ++line)
+	{
+	    int	    col_done = 0;
+
+	    for (col = 0; col < screen_Columns; ++col)
+	    {
+		int off = line * screen_Columns + col;
+
+		if (popup_mask[off] != popup_mask_next[off])
+		{
+		    popup_mask[off] = popup_mask_next[off];
+
+		    if (line >= cmdline_row)
+		    {
+			// the command line needs to be cleared if text below
+			// the popup is now visible.
+			if (!msg_scrolled && popup_mask_next[off] == 0)
+			    clear_cmdline = TRUE;
+		    }
+		    else if (col >= col_done)
+		    {
+			linenr_T	lnum;
+			int		line_cp = line;
+			int		col_cp = col;
+
+			// The screen position "line" / "col" needs to be
+			// redrawn.  Figure out what window that is and update
+			// w_redraw_top and w_redr_bot.  Only needs to be done
+			// once for each window line.
+			wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
+			if (wp != NULL)
+			{
+			    if (line_cp >= wp->w_height)
+				// In (or below) status line
+				wp->w_redr_status = TRUE;
+			    // compute the position in the buffer line from the
+			    // position on the screen
+			    else if (mouse_comp_pos(wp, &line_cp, &col_cp,
+									&lnum))
+				// past bottom
+				wp->w_redr_status = TRUE;
+			    else
+				redrawWinline(wp, lnum);
+
+			    // This line is going to be redrawn, no need to
+			    // check until the right side of the window.
+			    col_done = wp->w_wincol + wp->w_width - 1;
+			}
+		    }
+		}
+	    }
+	}
+}
+
+/*
+ * Return a string of "len" spaces in IObuff.
+ */
+    static char_u *
+get_spaces(int len)
+{
+    vim_memset(IObuff, ' ', (size_t)len);
+    IObuff[len] = NUL;
+    return IObuff;
+}
+
+/*
+ * Update popup windows.  They are drawn on top of normal windows.
+ * "win_update" is called for each popup window, lowest zindex first.
+ */
+    void
+update_popups(void (*win_update)(win_T *wp))
+{
+    win_T   *wp;
+    int	    top_off;
+    int	    left_off;
+    int	    total_width;
+    int	    total_height;
+    int	    popup_attr;
+    int	    border_attr[4];
+    int	    border_char[8];
+    char_u  buf[MB_MAXBYTES];
+    int	    row;
+    int	    i;
+
+    // Find the window with the lowest zindex that hasn't been updated yet,
+    // so that the window with a higher zindex is drawn later, thus goes on
+    // top.
+    popup_reset_handled();
+    while ((wp = find_next_popup(TRUE)) != NULL)
+    {
+	// This drawing uses the zindex of the popup window, so that it's on
+	// top of the text but doesn't draw when another popup with higher
+	// zindex is on top of the character.
+	screen_zindex = wp->w_zindex;
+
+	// adjust w_winrow and w_wincol for border and padding, since
+	// win_update() doesn't handle them.
+	top_off = wp->w_popup_padding[0] + wp->w_popup_border[0];
+	left_off = wp->w_popup_padding[3] + wp->w_popup_border[3];
+	wp->w_winrow += top_off;
+	wp->w_wincol += left_off;
+
+	// Draw the popup text.
+	win_update(wp);
+
+	wp->w_winrow -= top_off;
+	wp->w_wincol -= left_off;
+
+	total_width = wp->w_popup_border[3] + wp->w_popup_padding[3]
+		+ wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1];
+	total_height = wp->w_popup_border[0] + wp->w_popup_padding[0]
+		+ wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2];
+	popup_attr = get_wcr_attr(wp);
+
+	// We can only use these line drawing characters when 'encoding' is
+	// "utf-8" and 'ambiwidth' is "single".
+	if (enc_utf8 && *p_ambw == 's')
+	{
+	    border_char[0] = border_char[2] = 0x2550;
+	    border_char[1] = border_char[3] = 0x2551;
+	    border_char[4] = 0x2554;
+	    border_char[5] = 0x2557;
+	    border_char[6] = 0x255d;
+	    border_char[7] = 0x255a;
+	}
+	else
+	{
+	    border_char[0] = border_char[2] = '-';
+	    border_char[1] = border_char[3] = '|';
+	    for (i = 4; i < 8; ++i)
+		border_char[i] = '+';
+	}
+	for (i = 0; i < 8; ++i)
+	    if (wp->w_border_char[i] != 0)
+		border_char[i] = wp->w_border_char[i];
+
+	for (i = 0; i < 4; ++i)
+	{
+	    border_attr[i] = popup_attr;
+	    if (wp->w_border_highlight[i] != NULL)
+		border_attr[i] = syn_name2attr(wp->w_border_highlight[i]);
+	}
+
+	if (wp->w_popup_border[0] > 0)
+	{
+	    // top border
+	    screen_fill(wp->w_winrow, wp->w_winrow + 1,
+		    wp->w_wincol,
+		    wp->w_wincol + total_width,
+		    wp->w_popup_border[3] != 0
+					     ? border_char[4] : border_char[0],
+		    border_char[0], border_attr[0]);
+	    if (wp->w_popup_border[1] > 0)
+	    {
+		buf[mb_char2bytes(border_char[5], buf)] = NUL;
+		screen_puts(buf, wp->w_winrow,
+			       wp->w_wincol + total_width - 1, border_attr[1]);
+	    }
+	}
+
+	if (wp->w_popup_padding[0] > 0)
+	{
+	    // top padding
+	    row = wp->w_winrow + wp->w_popup_border[0];
+	    screen_fill(row, row + wp->w_popup_padding[0],
+		    wp->w_wincol + wp->w_popup_border[3],
+		    wp->w_wincol + total_width - wp->w_popup_border[1],
+							 ' ', ' ', popup_attr);
+	}
+
+	for (row = wp->w_winrow + wp->w_popup_border[0];
+		row < wp->w_winrow + total_height - wp->w_popup_border[2];
+		    ++row)
+	{
+	    // left border
+	    if (wp->w_popup_border[3] > 0)
+	    {
+		buf[mb_char2bytes(border_char[3], buf)] = NUL;
+		screen_puts(buf, row, wp->w_wincol, border_attr[3]);
+	    }
+	    // left padding
+	    if (wp->w_popup_padding[3] > 0)
+		screen_puts(get_spaces(wp->w_popup_padding[3]), row,
+			wp->w_wincol + wp->w_popup_border[3], popup_attr);
+	    // right border
+	    if (wp->w_popup_border[1] > 0)
+	    {
+		buf[mb_char2bytes(border_char[1], buf)] = NUL;
+		screen_puts(buf, row,
+			       wp->w_wincol + total_width - 1, border_attr[1]);
+	    }
+	    // right padding
+	    if (wp->w_popup_padding[1] > 0)
+		screen_puts(get_spaces(wp->w_popup_padding[1]), row,
+			wp->w_wincol + wp->w_popup_border[3]
+			   + wp->w_popup_padding[3] + wp->w_width, popup_attr);
+	}
+
+	if (wp->w_popup_padding[2] > 0)
+	{
+	    // bottom padding
+	    row = wp->w_winrow + wp->w_popup_border[0]
+				       + wp->w_popup_padding[0] + wp->w_height;
+	    screen_fill(row, row + wp->w_popup_padding[2],
+		    wp->w_wincol + wp->w_popup_border[3],
+		    wp->w_wincol + total_width - wp->w_popup_border[1],
+							 ' ', ' ', popup_attr);
+	}
+
+	if (wp->w_popup_border[2] > 0)
+	{
+	    // bottom border
+	    row = wp->w_winrow + total_height - 1;
+	    screen_fill(row , row + 1,
+		    wp->w_wincol,
+		    wp->w_wincol + total_width,
+		    wp->w_popup_border[3] != 0
+					     ? border_char[7] : border_char[2],
+		    border_char[2], border_attr[2]);
+	    if (wp->w_popup_border[1] > 0)
+	    {
+		buf[mb_char2bytes(border_char[6], buf)] = NUL;
+		screen_puts(buf, row,
+			       wp->w_wincol + total_width - 1, border_attr[2]);
+	    }
+	}
+
+	// Back to the normal zindex.
+	screen_zindex = 0;
+    }
+}
+
 #endif // FEAT_TEXT_PROP
--- a/src/proto/popupwin.pro
+++ b/src/proto/popupwin.pro
@@ -24,4 +24,6 @@ void popup_reset_handled(void);
 win_T *find_next_popup(int lowest);
 int popup_do_filter(int c);
 void popup_check_cursor_pos(void);
+void may_update_popup_mask(int type);
+void update_popups(void (*win_update)(win_T *wp));
 /* vim: set ft=c : */
--- a/src/proto/screen.pro
+++ b/src/proto/screen.pro
@@ -16,6 +16,7 @@ int update_screen(int type_arg);
 int conceal_cursor_line(win_T *wp);
 void conceal_check_cursor_line(void);
 void update_debug_sign(buf_T *buf, linenr_T lnum);
+int get_wcr_attr(win_T *wp);
 void updateWindow(win_T *wp);
 int screen_get_current_line_off(void);
 void screen_line(int row, int coloff, int endcol, int clear_width, int flags);
--- a/src/screen.c
+++ b/src/screen.c
@@ -121,10 +121,6 @@ static int redrawing_for_callback = 0;
  */
 static schar_T	*current_ScreenLine;
 
-#ifdef FEAT_TEXT_PROP
-static void may_update_popup_mask(int type);
-static void update_popups(void);
-#endif
 static void win_update(win_T *wp);
 static void win_redr_status(win_T *wp, int ignore_pum);
 static void win_draw_end(win_T *wp, int c1, int c2, int draw_margin, int row, int endrow, hlf_T hl);
@@ -826,7 +822,7 @@ update_screen(int type_arg)
 
 #ifdef FEAT_TEXT_PROP
     // Display popup windows on top of the windows.
-    update_popups();
+    update_popups(win_update);
 #endif
 
 #ifdef FEAT_GUI
@@ -1001,7 +997,7 @@ update_debug_sign(buf_T *buf, linenr_T l
  * Get 'wincolor' attribute for window "wp".  If not set and "wp" is a popup
  * window then get the "Pmenu" highlight attribute.
  */
-    static int
+    int
 get_wcr_attr(win_T *wp)
 {
     int wcr_attr = 0;
@@ -1015,305 +1011,6 @@ get_wcr_attr(win_T *wp)
     return wcr_attr;
 }
 
-#ifdef FEAT_TEXT_PROP
-
-/*
- * Update "popup_mask" if needed.
- * Also recomputes the popup size and positions.
- * Also updates "popup_visible".
- * Also marks window lines for redrawing.
- */
-    static void
-may_update_popup_mask(int type)
-{
-    win_T	*wp;
-    short	*mask;
-    int		line, col;
-    int		redraw_all = FALSE;
-
-    // Need to recompute when switching tabs.
-    // Also recompute when the type is CLEAR or NOT_VALID, something basic
-    // (such as the screen size) must have changed.
-    if (popup_mask_tab != curtab || type >= NOT_VALID)
-    {
-	popup_mask_refresh = TRUE;
-	redraw_all = TRUE;
-    }
-    if (!popup_mask_refresh)
-    {
-	// Check if any buffer has changed.
-	for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
-	    if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
-		popup_mask_refresh = TRUE;
-	for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
-	    if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
-		popup_mask_refresh = TRUE;
-	if (!popup_mask_refresh)
-	    return;
-    }
-
-    // Need to update the mask, something has changed.
-    popup_mask_refresh = FALSE;
-    popup_mask_tab = curtab;
-    popup_visible = FALSE;
-
-    // If redrawing everything, just update "popup_mask".
-    // If redrawing only what is needed, update "popup_mask_next" and then
-    // compare with "popup_mask" to see what changed.
-    if (type >= SOME_VALID)
-	mask = popup_mask;
-    else
-	mask = popup_mask_next;
-    vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short));
-
-    // Find the window with the lowest zindex that hasn't been handled yet,
-    // so that the window with a higher zindex overwrites the value in
-    // popup_mask.
-    popup_reset_handled();
-    while ((wp = find_next_popup(TRUE)) != NULL)
-    {
-	popup_visible = TRUE;
-
-	// Recompute the position if the text changed.
-	if (redraw_all
-		|| wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
-	    popup_adjust_position(wp);
-
-	for (line = wp->w_winrow;
-		line < wp->w_winrow + popup_height(wp)
-						 && line < screen_Rows; ++line)
-	    for (col = wp->w_wincol;
-		 col < wp->w_wincol + popup_width(wp)
-						&& col < screen_Columns; ++col)
-		mask[line * screen_Columns + col] = wp->w_zindex;
-    }
-
-    // Only check which lines are to be updated if not already
-    // updating all lines.
-    if (mask == popup_mask_next)
-	for (line = 0; line < screen_Rows; ++line)
-	{
-	    int	    col_done = 0;
-
-	    for (col = 0; col < screen_Columns; ++col)
-	    {
-		int off = line * screen_Columns + col;
-
-		if (popup_mask[off] != popup_mask_next[off])
-		{
-		    popup_mask[off] = popup_mask_next[off];
-
-		    // The screen position "line" / "col" needs to be redrawn.
-		    // Figure out what window that is and update w_redraw_top
-		    // and w_redr_bot.  Only needs to be done for each window
-		    // line.
-		    if (col >= col_done)
-		    {
-			linenr_T	lnum;
-			int		line_cp = line;
-			int		col_cp = col;
-
-			// find the window where the row is in
-			wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP);
-			if (wp != NULL)
-			{
-			    if (line_cp >= wp->w_height)
-				// In (or below) status line
-				wp->w_redr_status = TRUE;
-			    // compute the position in the buffer line from the
-			    // position on the screen
-			    else if (mouse_comp_pos(wp, &line_cp, &col_cp,
-									&lnum))
-				// past bottom
-				wp->w_redr_status = TRUE;
-			    else
-				redrawWinline(wp, lnum);
-
-			    // This line is going to be redrawn, no need to
-			    // check until the right side of the window.
-			    col_done = wp->w_wincol + wp->w_width - 1;
-			}
-		    }
-		}
-	    }
-	}
-}
-
-/*
- * Return a string of "len" spaces in IObuff.
- */
-    static char_u *
-get_spaces(int len)
-{
-    vim_memset(IObuff, ' ', (size_t)len);
-    IObuff[len] = NUL;
-    return IObuff;
-}
-
-    static void
-update_popups(void)
-{
-    win_T   *wp;
-    int	    top_off;
-    int	    left_off;
-    int	    total_width;
-    int	    total_height;
-    int	    popup_attr;
-    int	    border_attr[4];
-    int	    border_char[8];
-    char_u  buf[MB_MAXBYTES];
-    int	    row;
-    int	    i;
-
-    // Find the window with the lowest zindex that hasn't been updated yet,
-    // so that the window with a higher zindex is drawn later, thus goes on
-    // top.
-    popup_reset_handled();
-    while ((wp = find_next_popup(TRUE)) != NULL)
-    {
-	// This drawing uses the zindex of the popup window, so that it's on
-	// top of the text but doesn't draw when another popup with higher
-	// zindex is on top of the character.
-	screen_zindex = wp->w_zindex;
-
-	// adjust w_winrow and w_wincol for border and padding, since
-	// win_update() doesn't handle them.
-	top_off = wp->w_popup_padding[0] + wp->w_popup_border[0];
-	left_off = wp->w_popup_padding[3] + wp->w_popup_border[3];
-	wp->w_winrow += top_off;
-	wp->w_wincol += left_off;
-
-	// Draw the popup text.
-	win_update(wp);
-
-	wp->w_winrow -= top_off;
-	wp->w_wincol -= left_off;
-
-	total_width = wp->w_popup_border[3] + wp->w_popup_padding[3]
-		+ wp->w_width + wp->w_popup_padding[1] + wp->w_popup_border[1];
-	total_height = wp->w_popup_border[0] + wp->w_popup_padding[0]
-		+ wp->w_height + wp->w_popup_padding[2] + wp->w_popup_border[2];
-	popup_attr = get_wcr_attr(wp);
-
-	// We can only use these line drawing characters when 'encoding' is
-	// "utf-8" and 'ambiwidth' is "single".
-	if (enc_utf8 && *p_ambw == 's')
-	{
-	    border_char[0] = border_char[2] = 0x2550;
-	    border_char[1] = border_char[3] = 0x2551;
-	    border_char[4] = 0x2554;
-	    border_char[5] = 0x2557;
-	    border_char[6] = 0x255d;
-	    border_char[7] = 0x255a;
-	}
-	else
-	{
-	    border_char[0] = border_char[2] = '-';
-	    border_char[1] = border_char[3] = '|';
-	    for (i = 4; i < 8; ++i)
-		border_char[i] = '+';
-	}
-	for (i = 0; i < 8; ++i)
-	    if (wp->w_border_char[i] != 0)
-		border_char[i] = wp->w_border_char[i];
-
-	for (i = 0; i < 4; ++i)
-	{
-	    border_attr[i] = popup_attr;
-	    if (wp->w_border_highlight[i] != NULL)
-		border_attr[i] = syn_name2attr(wp->w_border_highlight[i]);
-	}
-
-	if (wp->w_popup_border[0] > 0)
-	{
-	    // top border
-	    screen_fill(wp->w_winrow, wp->w_winrow + 1,
-		    wp->w_wincol,
-		    wp->w_wincol + total_width,
-		    wp->w_popup_border[3] != 0
-					     ? border_char[4] : border_char[0],
-		    border_char[0], border_attr[0]);
-	    if (wp->w_popup_border[1] > 0)
-	    {
-		buf[mb_char2bytes(border_char[5], buf)] = NUL;
-		screen_puts(buf, wp->w_winrow,
-			       wp->w_wincol + total_width - 1, border_attr[1]);
-	    }
-	}
-
-	if (wp->w_popup_padding[0] > 0)
-	{
-	    // top padding
-	    row = wp->w_winrow + wp->w_popup_border[0];
-	    screen_fill(row, row + wp->w_popup_padding[0],
-		    wp->w_wincol + wp->w_popup_border[3],
-		    wp->w_wincol + total_width - wp->w_popup_border[1],
-							 ' ', ' ', popup_attr);
-	}
-
-	for (row = wp->w_winrow + wp->w_popup_border[0];
-		row < wp->w_winrow + total_height - wp->w_popup_border[2];
-		    ++row)
-	{
-	    // left border
-	    if (wp->w_popup_border[3] > 0)
-	    {
-		buf[mb_char2bytes(border_char[3], buf)] = NUL;
-		screen_puts(buf, row, wp->w_wincol, border_attr[3]);
-	    }
-	    // left padding
-	    if (wp->w_popup_padding[3] > 0)
-		screen_puts(get_spaces(wp->w_popup_padding[3]), row,
-			wp->w_wincol + wp->w_popup_border[3], popup_attr);
-	    // right border
-	    if (wp->w_popup_border[1] > 0)
-	    {
-		buf[mb_char2bytes(border_char[1], buf)] = NUL;
-		screen_puts(buf, row,
-			       wp->w_wincol + total_width - 1, border_attr[1]);
-	    }
-	    // right padding
-	    if (wp->w_popup_padding[1] > 0)
-		screen_puts(get_spaces(wp->w_popup_padding[1]), row,
-			wp->w_wincol + wp->w_popup_border[3]
-			   + wp->w_popup_padding[3] + wp->w_width, popup_attr);
-	}
-
-	if (wp->w_popup_padding[2] > 0)
-	{
-	    // bottom padding
-	    row = wp->w_winrow + wp->w_popup_border[0]
-				       + wp->w_popup_padding[0] + wp->w_height;
-	    screen_fill(row, row + wp->w_popup_padding[2],
-		    wp->w_wincol + wp->w_popup_border[3],
-		    wp->w_wincol + total_width - wp->w_popup_border[1],
-							 ' ', ' ', popup_attr);
-	}
-
-	if (wp->w_popup_border[2] > 0)
-	{
-	    // bottom border
-	    row = wp->w_winrow + total_height - 1;
-	    screen_fill(row , row + 1,
-		    wp->w_wincol,
-		    wp->w_wincol + total_width,
-		    wp->w_popup_border[3] != 0
-					     ? border_char[7] : border_char[2],
-		    border_char[2], border_attr[2]);
-	    if (wp->w_popup_border[1] > 0)
-	    {
-		buf[mb_char2bytes(border_char[6], buf)] = NUL;
-		screen_puts(buf, row,
-			       wp->w_wincol + total_width - 1, border_attr[2]);
-	    }
-	}
-
-	// Back to the normal zindex.
-	screen_zindex = 0;
-    }
-}
-#endif
-
 #if defined(FEAT_GUI) || defined(PROTO)
 /*
  * Update a single window, its status line and maybe the command line msg.
@@ -1354,7 +1051,7 @@ updateWindow(win_T *wp)
 
 #ifdef FEAT_TEXT_PROP
     // Display popup windows on top of everything.
-    update_popups();
+    update_popups(win_update);
 #endif
 
     update_finish();
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_drag_01.dump
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @73
+|4| @73
+|5| @73
+|6| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32
+|7| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32
+|8| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32
+|9| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32
+@34|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@14|1|,|1| @10|T|o|p| 
new file mode 100644
--- /dev/null
+++ b/src/testdir/dumps/Test_popupwin_drag_02.dump
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @32|╔+0#0000001#ffd7ff255|═@5|╗| +0#0000000#ffffff0@32
+|3| @32|║+0#0000001#ffd7ff255|1@3| @1|║| +0#0000000#ffffff0@32
+|4| @32|║+0#0000001#ffd7ff255|2@5|║| +0#0000000#ffffff0@32
+|5| @32|║+0#0000001#ffd7ff255|3@4| |║| +0#0000000#ffffff0@32
+|6| @32|╚+0#0000001#ffd7ff255|═@5|╝| +0#0000000#ffffff0@32
+|7| @73
+|8| @73
+|9| @73
+@57|1|,|1| @10|T|o|p| 
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -289,6 +289,36 @@ func Test_popup_firstline()
   call delete('XtestPopupFirstline')
 endfunc
 
+func Test_popup_drag()
+  if !CanRunVimInTerminal()
+    throw 'Skipped: cannot make screendumps'
+  endif
+  " create a popup that covers the command line
+  let lines =<< trim END
+	call setline(1, range(1, 20))
+	let winid = popup_create(['1111', '222222', '33333'], {
+	      \ 'drag': 1,
+	      \ 'border': [],
+	      \ 'line': &lines - 4,
+	      \ })
+	func Dragit()
+	  call feedkeys("\<F3>\<LeftMouse>\<F4>\<LeftDrag>\<LeftRelease>", "xt")
+	endfunc
+	map <silent> <F3> :call test_setmouse(&lines - 4, &columns / 2)<CR>
+	map <silent> <F4> :call test_setmouse(&lines - 8, &columns / 2)<CR>
+  END
+  call writefile(lines, 'XtestPopupDrag')
+  let buf = RunVimInTerminal('-S XtestPopupDrag', {'rows': 10})
+  call VerifyScreenDump(buf, 'Test_popupwin_drag_01', {})
+
+  call term_sendkeys(buf, ":call Dragit()\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_drag_02', {})
+
+  " clean up
+  call StopVimInTerminal(buf)
+  call delete('XtestPopupDrag')
+endfunc
+
 func Test_popup_in_tab()
   " default popup is local to tab, not visible when in other tab
   let winid = popup_create("text", {})
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1527,
+/**/
     1526,
 /**/
     1525,