To: vim_dev@googlegroups.com Subject: Patch 8.1.2300 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ 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 -- Bram@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 ///