# HG changeset patch # User Bram Moolenaar # Date 1560364207 -7200 # Node ID 5ed4965ebc7bdefd5b91936b45d3dd95fc290698 # Parent 5ed044bdf675d53e2766e29fdf4b89e9da35627a patch 8.1.1520: popup windows are ignored when dealing with mouse position commit https://github.com/vim/vim/commit/451d4b5b7c7262631cd1f5057c75d6f5f5772fb1 Author: Bram Moolenaar Date: Wed Jun 12 20:22:27 2019 +0200 patch 8.1.1520: popup windows are ignored when dealing with mouse position Problem: Popup windows are ignored when dealing with mouse position Solution: Find the mouse position inside a popup window. Allow for modeless selection. diff --git a/src/beval.c b/src/beval.c --- a/src/beval.c +++ b/src/beval.c @@ -49,7 +49,7 @@ get_beval_info( col = X_2_COL(beval->x); } #endif - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp != NULL && row >= 0 && row < wp->w_height && col < wp->w_width) { /* Found a window and the cursor is in the text. Now find the line @@ -141,6 +141,7 @@ get_beval_info( /* * Show a balloon with "mesg" or "list". + * Hide the balloon when both are NULL. */ void post_balloon(BalloonEval *beval UNUSED, char_u *mesg, list_T *list UNUSED) @@ -153,7 +154,7 @@ post_balloon(BalloonEval *beval UNUSED, # endif # ifdef FEAT_BEVAL_GUI if (gui.in_use) - /* GUI can't handle a list */ + // GUI can't handle a list gui_mch_post_balloon(beval, mesg); # endif } diff --git a/src/edit.c b/src/edit.c --- a/src/edit.c +++ b/src/edit.c @@ -5267,7 +5267,7 @@ ins_mousescroll(int dir) col = mouse_col; /* find the window at the pointer coordinates */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return; curwin = wp; diff --git a/src/evalfunc.c b/src/evalfunc.c --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -5154,12 +5154,18 @@ f_getchar(typval_T *argvars, typval_T *r { /* Find the window at the mouse coordinates and compute the * text position. */ - win = mouse_find_win(&row, &col); + win = mouse_find_win(&row, &col, FIND_POPUP); if (win == NULL) return; (void)mouse_comp_pos(win, &row, &col, &lnum); - for (wp = firstwin; wp != win; wp = wp->w_next) - ++winnr; +# ifdef FEAT_TEXT_PROP + if (bt_popup(win->w_buffer)) + winnr = 0; + else +# endif + for (wp = firstwin; wp != win && wp != NULL; + wp = wp->w_next) + ++winnr; set_vim_var_nr(VV_MOUSE_WIN, winnr); set_vim_var_nr(VV_MOUSE_WINID, win->w_id); set_vim_var_nr(VV_MOUSE_LNUM, lnum); diff --git a/src/gui.c b/src/gui.c --- a/src/gui.c +++ b/src/gui.c @@ -4926,7 +4926,7 @@ xy2win(int x, int y) col = X_2_COL(x); if (row < 0 || col < 0) /* before first window */ return NULL; - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FALSE); if (wp == NULL) return NULL; #ifdef FEAT_MOUSESHAPE @@ -5382,7 +5382,7 @@ gui_wingoto_xy(int x, int y) if (row >= 0 && col >= 0) { - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp != NULL && wp != curwin) win_goto(wp); } diff --git a/src/normal.c b/src/normal.c --- a/src/normal.c +++ b/src/normal.c @@ -4521,7 +4521,7 @@ nv_mousescroll(cmdarg_T *cap) col = mouse_col; /* find the window at the pointer coordinates */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return; curwin = wp; diff --git a/src/popupwin.c b/src/popupwin.c --- a/src/popupwin.c +++ b/src/popupwin.c @@ -424,6 +424,28 @@ add_popup_dicts(buf_T *buf, list_T *l) } /* + * Return the height of popup window "wp", including border and padding. + */ + int +popup_height(win_T *wp) +{ + return wp->w_height + + wp->w_popup_padding[0] + wp->w_popup_border[0] + + wp->w_popup_padding[2] + wp->w_popup_border[2]; +} + +/* + * Return the width of popup window "wp", including border and padding. + */ + int +popup_width(win_T *wp) +{ + return wp->w_width + + wp->w_popup_padding[3] + wp->w_popup_border[3] + + wp->w_popup_padding[1] + wp->w_popup_border[1]; +} + +/* * Adjust the position and size of the popup to fit on the screen. */ void diff --git a/src/proto/popupwin.pro b/src/proto/popupwin.pro --- a/src/proto/popupwin.pro +++ b/src/proto/popupwin.pro @@ -1,4 +1,6 @@ /* popupwin.c */ +int popup_height(win_T *wp); +int popup_width(win_T *wp); void popup_adjust_position(win_T *wp); void f_popup_clear(typval_T *argvars, typval_T *rettv); void f_popup_create(typval_T *argvars, typval_T *rettv); diff --git a/src/proto/ui.pro b/src/proto/ui.pro --- a/src/proto/ui.pro +++ b/src/proto/ui.pro @@ -65,7 +65,7 @@ int clip_x11_owner_exists(VimClipboard * void yank_cut_buffer0(Display *dpy, VimClipboard *cbd); int jump_to_mouse(int flags, int *inclusive, int which_button); int mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump); -win_T *mouse_find_win(int *rowp, int *colp); +win_T *mouse_find_win(int *rowp, int *colp, mouse_find_T popup); int get_fpos_of_mouse(pos_T *mpos); int vcol2col(win_T *wp, linenr_T lnum, int vcol); void ui_focus_change(int in_focus); diff --git a/src/screen.c b/src/screen.c --- a/src/screen.c +++ b/src/screen.c @@ -1072,8 +1072,6 @@ may_update_popup_mask(int type) popup_reset_handled(); while ((wp = find_next_popup(TRUE)) != NULL) { - int height_extra, width_extra; - popup_visible = TRUE; // Recompute the position if the text changed. @@ -1081,18 +1079,11 @@ may_update_popup_mask(int type) || wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer)) popup_adjust_position(wp); - // the width and height are for the inside, add the padding and - // border - height_extra = wp->w_popup_padding[0] + wp->w_popup_border[0] - + wp->w_popup_padding[2] + wp->w_popup_border[2]; - width_extra = wp->w_popup_padding[3] + wp->w_popup_border[3] - + wp->w_popup_padding[1] + wp->w_popup_border[1]; - for (line = wp->w_winrow; - line < wp->w_winrow + wp->w_height + height_extra + line < wp->w_winrow + popup_height(wp) && line < screen_Rows; ++line) for (col = wp->w_wincol; - col < wp->w_wincol + wp->w_width + width_extra + col < wp->w_wincol + popup_width(wp) && col < screen_Columns; ++col) mask[line * screen_Columns + col] = wp->w_zindex; } @@ -1123,7 +1114,7 @@ may_update_popup_mask(int type) int col_cp = col; // find the window where the row is in - wp = mouse_find_win(&line_cp, &col_cp); + wp = mouse_find_win(&line_cp, &col_cp, IGNORE_POPUP); if (wp != NULL) { if (line_cp >= wp->w_height) diff --git a/src/structs.h b/src/structs.h --- a/src/structs.h +++ b/src/structs.h @@ -3626,3 +3626,10 @@ typedef enum { CDSCOPE_TABPAGE, // :tcd CDSCOPE_WINDOW // :lcd } cdscope_T; + +// argument for mouse_find_win() +typedef enum { + IGNORE_POPUP, // only check non-popup windows + FIND_POPUP, // also find popup windows + FAIL_POPUP // return NULL if mouse on popup window +} mouse_find_T; diff --git a/src/ui.c b/src/ui.c --- a/src/ui.c +++ b/src/ui.c @@ -1455,12 +1455,19 @@ clip_invert_rectangle( int width, int invert) { +#ifdef FEAT_TEXT_PROP + // this goes on top of all popup windows + screen_zindex = 32000; +#endif #ifdef FEAT_GUI if (gui.in_use) gui_mch_invert_rectangle(row, col, height, width); else #endif screen_draw_rectangle(row, col, height, width, invert); +#ifdef FEAT_TEXT_PROP + screen_zindex = 0; +#endif } /* @@ -2833,6 +2840,9 @@ jump_to_mouse( #ifdef FEAT_MENU static int in_winbar = FALSE; #endif +#ifdef FEAT_TEXT_PROP + static int in_popup_win = FALSE; +#endif static int prev_row = -1; static int prev_col = -1; static win_T *dragwin = NULL; /* window being dragged */ @@ -2879,7 +2889,7 @@ retnomove: * as a second click in the WinBar. */ if ((mod_mask & MOD_MASK_MULTI_CLICK) && !(flags & MOUSE_RELEASED)) { - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return IN_UNKNOWN; winbar_click(wp, col); @@ -2893,10 +2903,15 @@ retnomove: redraw_curbuf_later(INVERTED); /* delete the inversion */ } #if defined(FEAT_CMDWIN) && defined(FEAT_CLIPBOARD) - /* Continue a modeless selection in another window. */ + // Continue a modeless selection in another window. if (cmdwin_type != 0 && row < curwin->w_winrow) return IN_OTHER_WIN; #endif +#ifdef FEAT_TEXT_PROP + // Continue a modeless selection in a popup window. + if (in_popup_win) + return IN_OTHER_WIN; +#endif return IN_BUFFER; } @@ -2925,11 +2940,26 @@ retnomove: return IN_UNKNOWN; /* find the window where the row is in */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FIND_POPUP); if (wp == NULL) return IN_UNKNOWN; dragwin = NULL; +#ifdef FEAT_TEXT_PROP + // Click in a popup window may start modeless selection, but not much + // else. + if (bt_popup(wp->w_buffer)) + { + on_sep_line = 0; + in_popup_win = TRUE; +# ifdef FEAT_CLIPBOARD + return IN_OTHER_WIN; +# else + return IN_UNKNOWN; +# endif + } + in_popup_win = FALSE; +#endif #ifdef FEAT_MENU if (row == -1) { @@ -3096,6 +3126,11 @@ retnomove: if (cmdwin_type != 0 && row < curwin->w_winrow) return IN_OTHER_WIN; #endif +#ifdef FEAT_TEXT_PROP + // Continue a modeless selection in a popup window. + if (in_popup_win) + return IN_OTHER_WIN; +#endif row -= W_WINROW(curwin); col -= curwin->w_wincol; @@ -3348,14 +3383,41 @@ mouse_comp_pos( /* * Find the window at screen position "*rowp" and "*colp". The positions are * updated to become relative to the top-left of the window. + * When "popup" is FAIL_POPUP and the position is in a popup window then NULL + * is returned. When "popup" is IGNORE_POPUP then do not even check popup + * windows. * Returns NULL when something is wrong. */ win_T * -mouse_find_win(int *rowp, int *colp) +mouse_find_win(int *rowp, int *colp, mouse_find_T popup UNUSED) { frame_T *fp; win_T *wp; +#ifdef FEAT_TEXT_PROP + win_T *pwp = NULL; + + 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 + && *colp < wp->w_wincol + popup_width(wp)) + pwp = wp; + } + if (pwp != NULL) + { + if (popup == FAIL_POPUP) + return NULL; + *rowp -= pwp->w_winrow; + *colp -= pwp->w_wincol; + return pwp; + } + } +#endif + fp = topframe; *rowp -= firstwin->w_winrow; for (;;) @@ -3412,7 +3474,7 @@ get_fpos_of_mouse(pos_T *mpos) return IN_UNKNOWN; /* find the window where the row is in */ - wp = mouse_find_win(&row, &col); + wp = mouse_find_win(&row, &col, FAIL_POPUP); if (wp == NULL) return IN_UNKNOWN; /* diff --git a/src/version.c b/src/version.c --- 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 */ /**/ + 1520, +/**/ 1519, /**/ 1518,