]> granicus.if.org Git - vim/commitdiff
patch 8.1.2300: redraw breaks going through list of popup windows v8.1.2300
authorBram Moolenaar <Bram@vim.org>
Wed, 13 Nov 2019 21:35:19 +0000 (22:35 +0100)
committerBram Moolenaar <Bram@vim.org>
Wed, 13 Nov 2019 21:35:19 +0000 (22:35 +0100)
Problem:    Redraw breaks going through list of popup windows.
Solution:   Use different flags for popup_reset_handled(). (closes #5216)

src/mouse.c
src/popupwin.c
src/proto/popupwin.pro
src/structs.h
src/testdir/test_popupwin.vim
src/version.c
src/vim.h

index 366cbaf542f2bfc1ad726e45f83a60afd18a9936..3e1741f9838e812a787d8c6a6c12cf1c03297818 100644 (file)
@@ -2921,8 +2921,8 @@ mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED)
 
     if (popup != IGNORE_POPUP)
     {
-       popup_reset_handled();
-       while ((wp = find_next_popup(TRUE)) != NULL)
+       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
index 66ce30c46565c30cf74591868c47ca1b1c1003b8..ed04645ea10ba4a7ab17f087359362bc4810e76b 100644 (file)
@@ -2815,28 +2815,30 @@ error_if_popup_window()
 }
 
 /*
- * Reset all the POPF_HANDLED flags in global popup windows and popup windows
+ * 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()
+popup_reset_handled(int handled_flag)
 {
     win_T *wp;
 
     for (wp = first_popupwin; wp != NULL; wp = wp->w_next)
-       wp->w_popup_flags &= ~POPF_HANDLED;
+       wp->w_popup_handled &= ~handled_flag;
     for (wp = curtab->tp_first_popupwin; wp != NULL; wp = wp->w_next)
-       wp->w_popup_flags &= ~POPF_HANDLED;
+       wp->w_popup_handled &= ~handled_flag;
 }
 
 /*
- * Find the next visible popup where POPF_HANDLED is not set.
+ * 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)
+find_next_popup(int lowest, int handled_flag)
 {
     win_T   *wp;
     win_T   *found_wp;
@@ -2845,24 +2847,26 @@ find_next_popup(int lowest)
     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
+       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))
+                   : 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
+       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))
+                   : wp->w_zindex > found_zindex))
        {
            found_zindex = wp->w_zindex;
            found_wp = wp;
        }
 
     if (found_wp != NULL)
-       found_wp->w_popup_flags |= POPF_HANDLED;
+       found_wp->w_popup_handled |= handled_flag;
     return found_wp;
 }
 
@@ -2929,6 +2933,7 @@ invoke_popup_filter(win_T *wp, int c)
     {
        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,9 +2968,9 @@ popup_do_filter(int c)
            res = TRUE;
     }
 
-    popup_reset_handled();
+    popup_reset_handled(POPUP_HANDLED_2);
     state = get_real_state();
-    while (!res && (wp = find_next_popup(FALSE)) != NULL)
+    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,8 +3010,8 @@ popup_check_cursor_pos()
 {
     win_T *wp;
 
-    popup_reset_handled();
-    while ((wp = find_next_popup(TRUE)) != NULL)
+    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,8 +3247,8 @@ may_update_popup_mask(int type)
     // 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_reset_handled(POPUP_HANDLED_4);
+    while ((wp = find_next_popup(TRUE, POPUP_HANDLED_4)) != NULL)
     {
        int width;
        int height;
@@ -3383,8 +3388,8 @@ update_popups(void (*win_update)(win_T *wp))
     // 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)
+    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
index bc4315a8122c5ab023b72cb47478296a713ce159..6e9b162a406d2d8372ee17ea1573a86c904e35e2 100644 (file)
@@ -40,8 +40,8 @@ void f_popup_getpos(typval_T *argvars, typval_T *rettv);
 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);
+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);
index 7cd1a51692e500d6f9d807e66c878f52b0d5d453..1f2779882659ae3e0f7fc3c34e6630376249bac7 100644 (file)
@@ -3015,6 +3015,7 @@ struct window_S
     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
index 4992837a89bb79b87092d9c7b93a732b713b05e9..44e18197c600877a7f5cbace5fff761cb99f06b1 100644 (file)
@@ -2949,4 +2949,38 @@ func Test_popupwin_cancel()
   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
index 2221d64f51011e95ab011eba853c6d9f19d61299..13d861666476c8be561544d3f0ad73cd0b5cc8d5 100644 (file)
@@ -741,6 +741,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    2300,
 /**/
     2299,
 /**/
index fe1e982c5d610944f35f4c7be4030f7005cf1333..4d409d46fd657fac3e3b881ca7570e3c1603ca14 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -624,15 +624,21 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
 // 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
+#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)