Patch 8.1.2300
Problem: Redraw breaks going through list of popup windows.
Solution: Use different flags for popup_reset_handled(). (closes #5216)
Files: src/popupwin.c, src/proto/
popupwin.pro, src/structs.h, src/vim.h,
src/mouse.c, src/testdir/test_popupwin.vim
*** ../vim-8.1.2299/src/popupwin.c 2019-11-11 21:45:01.925407125 +0100
--- src/popupwin.c 2019-11-13 22:34:02.378992414 +0100
***************
*** 2815,2842 ****
}
/*
! * Reset all the POPF_HANDLED flags in global popup windows and popup windows
* in the current tab page.
*/
void
! popup_reset_handled()
{
win_T *wp;
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
! wp->w_popup_flags &= ~POPF_HANDLED;
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
! wp->w_popup_flags &= ~POPF_HANDLED;
}
/*
! * Find the next visible popup where POPF_HANDLED is not set.
* Must have called popup_reset_handled() first.
* When "lowest" is TRUE find the popup with the lowest zindex, otherwise the
* popup with the highest zindex.
*/
win_T *
! find_next_popup(int lowest)
{
win_T *wp;
win_T *found_wp;
--- 2815,2844 ----
}
/*
! * Reset all the "handled_flag" flags in global popup windows and popup windows
* in the current tab page.
+ * Each calling function should use a different flag, see the list at
+ * POPUP_HANDLED_1. This won't work with recursive calls though.
*/
void
! popup_reset_handled(int handled_flag)
{
win_T *wp;
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
! wp->w_popup_handled &= ~handled_flag;
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
! wp->w_popup_handled &= ~handled_flag;
}
/*
! * Find the next visible popup where "handled_flag" is not set.
* Must have called popup_reset_handled() first.
* When "lowest" is TRUE find the popup with the lowest zindex, otherwise the
* popup with the highest zindex.
*/
win_T *
! find_next_popup(int lowest, int handled_flag)
{
win_T *wp;
win_T *found_wp;
***************
*** 2845,2868 ****
found_zindex = lowest ? INT_MAX : 0;
found_wp = NULL;
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
! if ((wp->w_popup_flags & (POPF_HANDLED|POPF_HIDDEN)) == 0
&& (lowest ? wp->w_zindex < found_zindex
! : wp->w_zindex > found_zindex))
{
found_zindex = wp->w_zindex;
found_wp = wp;
}
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
! if ((wp->w_popup_flags & (POPF_HANDLED|POPF_HIDDEN)) == 0
&& (lowest ? wp->w_zindex < found_zindex
! : wp->w_zindex > found_zindex))
{
found_zindex = wp->w_zindex;
found_wp = wp;
}
if (found_wp != NULL)
! found_wp->w_popup_flags |= POPF_HANDLED;
return found_wp;
}
--- 2847,2872 ----
found_zindex = lowest ? INT_MAX : 0;
found_wp = NULL;
for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
! if ((wp->w_popup_handled & handled_flag) == 0
! && (wp->w_popup_flags & POPF_HIDDEN) == 0
&& (lowest ? wp->w_zindex < found_zindex
! : wp->w_zindex > found_zindex))
{
found_zindex = wp->w_zindex;
found_wp = wp;
}
for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
! if ((wp->w_popup_handled & handled_flag) == 0
! && (wp->w_popup_flags & POPF_HIDDEN) == 0
&& (lowest ? wp->w_zindex < found_zindex
! : wp->w_zindex > found_zindex))
{
found_zindex = wp->w_zindex;
found_wp = wp;
}
if (found_wp != NULL)
! found_wp->w_popup_handled |= handled_flag;
return found_wp;
}
***************
*** 2929,2934 ****
--- 2933,2939 ----
{
set_vim_var_nr(VV_MOUSE_LNUM, 0);
set_vim_var_nr(VV_MOUSE_COL, 0);
+ set_vim_var_nr(VV_MOUSE_WINID, wp->w_id);
}
vim_free(argv[1].vval.v_string);
clear_tv(&rettv);
***************
*** 2963,2971 ****
res = TRUE;
}
! popup_reset_handled();
state = get_real_state();
! while (!res && (wp = find_next_popup(FALSE)) != NULL)
if (wp->w_filter_cb.cb_name != NULL
&& (wp->w_filter_mode & state) != 0)
res = invoke_popup_filter(wp, c);
--- 2968,2976 ----
res = TRUE;
}
! popup_reset_handled(POPUP_HANDLED_2);
state = get_real_state();
! while (!res && (wp = find_next_popup(FALSE, POPUP_HANDLED_2)) != NULL)
if (wp->w_filter_cb.cb_name != NULL
&& (wp->w_filter_mode & state) != 0)
res = invoke_popup_filter(wp, c);
***************
*** 3005,3012 ****
{
win_T *wp;
! popup_reset_handled();
! while ((wp = find_next_popup(TRUE)) != NULL)
if (wp->w_popup_curwin != NULL
&& (curwin != wp->w_popup_curwin
|| curwin->w_cursor.lnum != wp->w_popup_lnum
--- 3010,3017 ----
{
win_T *wp;
! popup_reset_handled(POPUP_HANDLED_3);
! while ((wp = find_next_popup(TRUE, POPUP_HANDLED_3)) != NULL)
if (wp->w_popup_curwin != NULL
&& (curwin != wp->w_popup_curwin
|| curwin->w_cursor.lnum != wp->w_popup_lnum
***************
*** 3242,3249 ****
// 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)
{
int width;
int height;
--- 3247,3254 ----
// 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(POPUP_HANDLED_4);
! while ((wp = find_next_popup(TRUE, POPUP_HANDLED_4)) != NULL)
{
int width;
int height;
***************
*** 3383,3390 ****
// 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
--- 3388,3395 ----
// 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(POPUP_HANDLED_5);
! while ((wp = find_next_popup(TRUE, POPUP_HANDLED_5)) != 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
*** ../vim-8.1.2299/src/proto/
popupwin.pro 2019-11-09 15:32:51.597873973 +0100
--- src/proto/
popupwin.pro 2019-11-13 22:25:01.603242949 +0100
***************
*** 40,47 ****
void f_popup_locate(typval_T *argvars, typval_T *rettv);
void f_popup_getoptions(typval_T *argvars, typval_T *rettv);
int error_if_popup_window(void);
! void popup_reset_handled(void);
! win_T *find_next_popup(int lowest);
int popup_do_filter(int c);
int popup_no_mapping(void);
void popup_check_cursor_pos(void);
--- 40,47 ----
void f_popup_locate(typval_T *argvars, typval_T *rettv);
void f_popup_getoptions(typval_T *argvars, typval_T *rettv);
int error_if_popup_window(void);
! void popup_reset_handled(int handled_flag);
! win_T *find_next_popup(int lowest, int handled_flag);
int popup_do_filter(int c);
int popup_no_mapping(void);
void popup_check_cursor_pos(void);
*** ../vim-8.1.2299/src/structs.h 2019-11-10 15:07:16.734954737 +0100
--- src/structs.h 2019-11-13 22:19:53.560702478 +0100
***************
*** 3015,3020 ****
--- 3015,3021 ----
pos_save_T w_save_cursor; // backup of cursor pos and topline
#ifdef FEAT_TEXT_PROP
int w_popup_flags; // POPF_ values
+ int w_popup_handled; // POPUP_HANDLE[0-9] flags
char_u *w_popup_title;
poppos_T w_popup_pos;
int w_popup_fixed; // do not shift popup to fit on screen
*** ../vim-8.1.2299/src/vim.h 2019-11-06 19:25:04.857696936 +0100
--- src/vim.h 2019-11-13 22:27:53.734395991 +0100
***************
*** 624,638 ****
// Values for w_popup_flags.
#define POPF_IS_POPUP 0x01 // this is a popup window
#define POPF_HIDDEN 0x02 // popup is not displayed
! #define POPF_HANDLED 0x04 // popup was just redrawn or filtered
! #define POPF_CURSORLINE 0x08 // popup is highlighting at the cursorline
! #define POPF_ON_CMDLINE 0x10 // popup overlaps command line
! #define POPF_DRAG 0x20 // popup can be moved by dragging
! #define POPF_RESIZE 0x40 // popup can be resized by dragging
! #define POPF_MAPPING 0x80 // mapping keys
! #define POPF_INFO 0x100 // used for info of popup menu
! #define POPF_INFO_MENU 0x200 // align info popup with popup menu
! #define POPF_POSINVERT 0x400 // vertical position can be inverted
#ifdef FEAT_TEXT_PROP
# define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0)
--- 624,644 ----
// Values for w_popup_flags.
#define POPF_IS_POPUP 0x01 // this is a popup window
#define POPF_HIDDEN 0x02 // popup is not displayed
! #define POPF_CURSORLINE 0x04 // popup is highlighting at the cursorline
! #define POPF_ON_CMDLINE 0x08 // popup overlaps command line
! #define POPF_DRAG 0x10 // popup can be moved by dragging
! #define POPF_RESIZE 0x20 // popup can be resized by dragging
! #define POPF_MAPPING 0x40 // mapping keys
! #define POPF_INFO 0x80 // used for info of popup menu
! #define POPF_INFO_MENU 0x100 // align info popup with popup menu
! #define POPF_POSINVERT 0x200 // vertical position can be inverted
!
! // flags used in w_popup_handled
! #define POPUP_HANDLED_1 0x01 // used by mouse_find_win()
! #define POPUP_HANDLED_2 0x02 // used by popup_do_filter()
! #define POPUP_HANDLED_3 0x04 // used by popup_check_cursor_pos()
! #define POPUP_HANDLED_4 0x08 // used by may_update_popup_mask()
! #define POPUP_HANDLED_5 0x10 // used by update_popups()
#ifdef FEAT_TEXT_PROP
# define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0)
*** ../vim-8.1.2299/src/mouse.c 2019-11-03 21:19:38.080721214 +0100
--- src/mouse.c 2019-11-13 22:25:37.091069780 +0100
***************
*** 2921,2928 ****
if (popup != IGNORE_POPUP)
{
! popup_reset_handled();
! while ((wp = find_next_popup(TRUE)) != NULL)
{
if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
&& *colp >= wp->w_wincol
--- 2921,2928 ----
if (popup != IGNORE_POPUP)
{
! popup_reset_handled(POPUP_HANDLED_1);
! while ((wp = find_next_popup(TRUE, POPUP_HANDLED_1)) != NULL)
{
if (*rowp >= wp->w_winrow && *rowp < wp->w_winrow + popup_height(wp)
&& *colp >= wp->w_wincol
*** ../vim-8.1.2299/src/testdir/test_popupwin.vim 2019-11-12 22:33:32.089004066 +0100
--- src/testdir/test_popupwin.vim 2019-11-13 22:16:45.657538615 +0100
***************
*** 2949,2952 ****
--- 2949,2986 ----
call assert_equal({}, popup_getpos(win3))
endfunc
+ func Test_popupwin_filter_redraw()
+ " Create two popups with a filter that closes the popup when typing "0".
+ " Both popups should close, even though the redraw also calls
+ " popup_reset_handled()
+
+ func CloseFilter(winid, key)
+ if a:key == '0'
+ call popup_close(a:winid)
+ redraw
+ endif
+ return 0 " pass the key
+ endfunc
+
+ let id1 = popup_create('first one', #{
+ \ line: 1,
+ \ col: 1,
+ \ filter: 'CloseFilter',
+ \ })
+ let id2 = popup_create('second one', #{
+ \ line: 9,
+ \ col: 1,
+ \ filter: 'CloseFilter',
+ \ })
+ call assert_equal(1, popup_getpos(id1).line)
+ call assert_equal(9, popup_getpos(id2).line)
+
+ call feedkeys('0', 'xt')
+ call assert_equal({}, popup_getpos(id1))
+ call assert_equal({}, popup_getpos(id2))
+
+ call popup_clear()
+ delfunc CloseFilter
+ endfunc
+
" vim: shiftwidth=2 sts=2
*** ../vim-8.1.2299/src/version.c 2019-11-13 21:49:21.288309771 +0100
--- src/version.c 2019-11-13 22:18:30.637077993 +0100
***************
*** 743,744 ****
--- 743,746 ----
{ /* Add new patch number below this line */
+ /**/
+ 2300,
/**/
--
hundred-and-one symptoms of being an internet addict:
88. Every single time you press the 'Get mail' button...it does get new mail.
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///