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 -- [email protected] -- 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    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201911132136.xADLa5Et017677%40masaka.moolenaar.net.

Raspunde prin e-mail lui