Skip to content

Commit e094e6c

Browse files
fredizzimodundargoc
authored andcommitted
feat(ui): support grid=0 in nvim_input_mouse neovim#32535
Problem: Multigrid UIs have to find out which window to send the input by using the Nvim focus rules, which are not fully documented. Furthermore,`getmousepos()` has several problems when multigrid is enabled, with the main one being that screenrow and screencol are window relative instead of screen relative, due to the fact that the UI don't send any absolute coordinates. Solution: Allow passing 0 as grid to `nvim_input_mouse`, with absolute coordinates, which lets nvim determine the actual window to send the mouse input to. This works as long as nvim is in charge of the window positioning. If the UI repositions or resizes the windows, it can still pass the grid it determines like before.
1 parent a3993f1 commit e094e6c

File tree

15 files changed

+2170
-1944
lines changed

15 files changed

+2170
-1944
lines changed

runtime/doc/api.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,8 +1147,9 @@ nvim_input_mouse({button}, {action}, {modifier}, {grid}, {row}, {col})
11471147
press, except that the "-" separator is optional, so
11481148
"C-A-", "c-a" and "CA" can all be used to specify
11491149
Ctrl+Alt+click.
1150-
{grid} (`integer`) Grid number if the client uses |ui-multigrid|,
1151-
else 0.
1150+
{grid} (`integer`) Grid number (used by |ui-multigrid| client),
1151+
or 0 to let Nvim decide positioning of windows. For more
1152+
information, see |dev-ui-multigrid|
11521153
{row} (`integer`) Mouse row-position (zero-based, like redraw
11531154
events)
11541155
{col} (`integer`) Mouse column-position (zero-based, like redraw

runtime/doc/develop.txt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,5 +685,23 @@ External UIs are expected to implement these common features:
685685
- Handle the "restart" UI event so that |:restart| works.
686686
- Detect capslock and show an indicator if capslock is active.
687687

688+
Multigrid UI ~
689+
*dev-ui-multigrid*
690+
- A multigrid UI should display floating windows using one of the following
691+
methods, using the `win_float_pos` |ui-multigrid| event. Different methods
692+
can be selected for each window as needed.
693+
694+
1. Let Nvim determine the position and z-order of the windows. This can be
695+
achieved by using the `compindex`, `screen_row`, and `screen_col` information from
696+
the `win_float_pos` UI event. To allow Nvim to automatically determine the grid,
697+
the UI should call `nvim_input_mouse` with 0 as the `grid` parameter.
698+
2. Use the `anchor`, `anchor_grid`, `anchor_row`, `anchor_col`, and `zindex` as
699+
references for positioning the windows. If windows are outside the screen,
700+
it is the UI's responsibility to reposition and/or resize them. Since Nvim
701+
lacks information about actual window placement in this case, the UI must
702+
call `nvim_input_mouse` with the actual grid id, factoring in `mouse_enabled`.
703+
Note: Some API functions may return unexpected results for these windows due
704+
to the missing information.
705+
- For external windows, the grid id should also be passed to `nvim_input_mouse`.
688706

689707
vim:tw=78:ts=8:sw=4:et:ft=help:norl:

runtime/doc/news.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,7 @@ UI
339339
• "Error executing Lua:" changed to "Lua:".
340340
'busy' status is shown in default statusline with symbol ◐
341341
• Improved LSP signature help rendering.
342+
• Multigrid UIs can call nvim_input_mouse with grid 0 to let Nvim decide the grid.
342343

343344
VIMSCRIPT
344345

runtime/lua/vim/_meta/api.lua

Lines changed: 2 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/nvim/api/vim.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,8 @@ Integer nvim_input(uint64_t channel_id, String keys)
382382
/// The same specifiers are used as for a key press, except
383383
/// that the "-" separator is optional, so "C-A-", "c-a"
384384
/// and "CA" can all be used to specify Ctrl+Alt+click.
385-
/// @param grid Grid number if the client uses |ui-multigrid|, else 0.
385+
/// @param grid Grid number (used by |ui-multigrid| client), or 0 to let Nvim decide positioning of
386+
/// windows. For more information, see [dev-ui-multigrid]
386387
/// @param row Mouse row-position (zero-based, like redraw events)
387388
/// @param col Mouse column-position (zero-based, like redraw events)
388389
/// @param[out] err Error details, if any

src/nvim/getchar.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2013,7 +2013,7 @@ static void getchar_common(typval_T *argvars, typval_T *rettv, bool allow_number
20132013
int winnr = 1;
20142014
// Find the window at the mouse coordinates and compute the
20152015
// text position.
2016-
win_T *const win = mouse_find_win(&grid, &row, &col);
2016+
win_T *const win = mouse_find_win_inner(&grid, &row, &col);
20172017
if (win == NULL) {
20182018
return;
20192019
}

src/nvim/mouse.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -235,7 +235,7 @@ static int get_fpos_of_mouse(pos_T *mpos)
235235
}
236236

237237
// find the window where the row is in
238-
win_T *wp = mouse_find_win(&grid, &row, &col);
238+
win_T *wp = mouse_find_win_inner(&grid, &row, &col);
239239
if (wp == NULL) {
240240
return IN_UNKNOWN;
241241
}
@@ -663,7 +663,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent)
663663
int click_grid = mouse_grid;
664664
int click_row = mouse_row;
665665
int click_col = mouse_col;
666-
win_T *wp = mouse_find_win(&click_grid, &click_row, &click_col);
666+
win_T *wp = mouse_find_win_inner(&click_grid, &click_row, &click_col);
667667
if (wp == NULL) {
668668
return false;
669669
}
@@ -1093,7 +1093,7 @@ void ins_mousescroll(int dir)
10931093
int grid = mouse_grid;
10941094
int row = mouse_row;
10951095
int col = mouse_col;
1096-
curwin = mouse_find_win(&grid, &row, &col);
1096+
curwin = mouse_find_win_inner(&grid, &row, &col);
10971097
if (curwin == NULL) {
10981098
curwin = old_curwin;
10991099
return;
@@ -1263,8 +1263,8 @@ int jump_to_mouse(int flags, bool *inclusive, int which_button)
12631263
}
12641264

12651265
// find the window where the row is in and adjust "row" and "col" to be
1266-
// relative to top-left of the window
1267-
win_T *wp = mouse_find_win(&grid, &row, &col);
1266+
// relative to top-left of the window inner area
1267+
win_T *wp = mouse_find_win_inner(&grid, &row, &col);
12681268
if (wp == NULL) {
12691269
return IN_UNKNOWN;
12701270
}
@@ -1581,7 +1581,7 @@ void nv_mousescroll(cmdarg_T *cap)
15811581
int grid = mouse_grid;
15821582
int row = mouse_row;
15831583
int col = mouse_col;
1584-
curwin = mouse_find_win(&grid, &row, &col);
1584+
curwin = mouse_find_win_inner(&grid, &row, &col);
15851585
if (curwin == NULL) {
15861586
curwin = old_curwin;
15871587
return;
@@ -1695,10 +1695,10 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump)
16951695
}
16961696

16971697
/// Find the window at "grid" position "*rowp" and "*colp". The positions are
1698-
/// updated to become relative to the top-left of the window.
1698+
/// updated to become relative to the top-left of the window inner area.
16991699
///
17001700
/// @return NULL when something is wrong.
1701-
win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
1701+
win_T *mouse_find_win_inner(int *gridp, int *rowp, int *colp)
17021702
{
17031703
win_T *wp_grid = mouse_find_grid_win(gridp, rowp, colp);
17041704
if (wp_grid) {
@@ -1740,6 +1740,20 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp)
17401740
return NULL;
17411741
}
17421742

1743+
/// Find the window at "grid" position "*rowp" and "*colp". The positions are
1744+
/// updated to become relative to the top-left of the window.
1745+
///
1746+
/// @return NULL when something is wrong.
1747+
win_T *mouse_find_win_outer(int *gridp, int *rowp, int *colp)
1748+
{
1749+
win_T *wp = mouse_find_win_inner(gridp, rowp, colp);
1750+
if (wp) {
1751+
*rowp += wp->w_winrow_off;
1752+
*colp += wp->w_wincol_off;
1753+
}
1754+
return wp;
1755+
}
1756+
17431757
static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
17441758
{
17451759
if (*gridp == msg_grid.handle) {
@@ -1755,18 +1769,26 @@ static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp)
17551769
}
17561770
} else if (*gridp == 0) {
17571771
ScreenGrid *grid = ui_comp_mouse_focus(*rowp, *colp);
1758-
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
1759-
if (&wp->w_grid_alloc != grid) {
1760-
continue;
1761-
}
1772+
if (grid == &pum_grid) {
17621773
*gridp = grid->handle;
1763-
*rowp -= grid->comp_row + wp->w_grid.row_offset;
1764-
*colp -= grid->comp_col + wp->w_grid.col_offset;
1765-
return wp;
1774+
*rowp -= grid->comp_row;
1775+
*colp -= grid->comp_col;
1776+
// The popup menu doesn't have a window, so return NULL
1777+
return NULL;
1778+
} else {
1779+
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
1780+
if (&wp->w_grid_alloc != grid) {
1781+
continue;
1782+
}
1783+
*gridp = grid->handle;
1784+
*rowp -= wp->w_winrow + wp->w_grid.row_offset;
1785+
*colp -= wp->w_wincol + wp->w_grid.col_offset;
1786+
return wp;
1787+
}
17661788
}
17671789

1768-
// no float found, click on the default grid
1769-
// TODO(bfredl): grid can be &pum_grid, allow select pum items by mouse?
1790+
// No grid found, return the default grid. With multigrid this happens for split separators for
1791+
// example.
17701792
*gridp = DEFAULT_GRID_HANDLE;
17711793
}
17721794
return NULL;
@@ -1877,7 +1899,7 @@ static void mouse_check_grid(colnr_T *vcolp, int *flagsp)
18771899
int click_col = mouse_col;
18781900

18791901
// XXX: this doesn't change click_grid if it is 1, even with multigrid
1880-
if (mouse_find_win(&click_grid, &click_row, &click_col) != curwin
1902+
if (mouse_find_win_inner(&click_grid, &click_row, &click_col) != curwin
18811903
// Only use vcols[] after the window was redrawn. Mainly matters
18821904
// for tests, a user would not click before redrawing.
18831905
|| curwin->w_redr_type != 0) {
@@ -1931,7 +1953,7 @@ void f_getmousepos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr)
19311953
tv_dict_add_nr(d, S_LEN("screenrow"), (varnumber_T)mouse_row + 1);
19321954
tv_dict_add_nr(d, S_LEN("screencol"), (varnumber_T)mouse_col + 1);
19331955

1934-
win_T *wp = mouse_find_win(&grid, &row, &col);
1956+
win_T *wp = mouse_find_win_inner(&grid, &row, &col);
19351957
if (wp != NULL) {
19361958
int height = wp->w_height + wp->w_hsep_height + wp->w_status_height;
19371959
// The height is adjusted by 1 when there is a bottom border. This is not

src/nvim/popupmenu.c

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "nvim/memory_defs.h"
3838
#include "nvim/menu.h"
3939
#include "nvim/message.h"
40+
#include "nvim/mouse.h"
4041
#include "nvim/move.h"
4142
#include "nvim/option.h"
4243
#include "nvim/option_defs.h"
@@ -1325,6 +1326,10 @@ static void pum_position_at_mouse(int min_width)
13251326
int col = mouse_col;
13261327
pum_win_row_offset = 0;
13271328
pum_win_col_offset = 0;
1329+
1330+
if (ui_has(kUIMultigrid) && grid == 0) {
1331+
mouse_find_win_outer(&grid, &row, &col);
1332+
}
13281333
if (grid > 1) {
13291334
win_T *wp = get_win_by_grid_handle(grid);
13301335
if (wp != NULL) {
@@ -1395,17 +1400,27 @@ static void pum_position_at_mouse(int min_width)
13951400
/// Select the pum entry at the mouse position.
13961401
static void pum_select_mouse_pos(void)
13971402
{
1398-
if (mouse_grid == pum_grid.handle) {
1399-
pum_selected = mouse_row;
1403+
int grid = mouse_grid;
1404+
int row = mouse_row;
1405+
int col = mouse_col;
1406+
1407+
if (grid == 0) {
1408+
mouse_find_win_outer(&grid, &row, &col);
1409+
}
1410+
1411+
if (grid == pum_grid.handle) {
1412+
pum_selected = row;
14001413
return;
1401-
} else if (mouse_grid != pum_anchor_grid
1402-
|| mouse_col < pum_left_col - pum_win_col_offset
1403-
|| mouse_col >= pum_right_col - pum_win_col_offset) {
1414+
}
1415+
1416+
if (grid != pum_anchor_grid
1417+
|| col < pum_left_col - pum_win_col_offset
1418+
|| col >= pum_right_col - pum_win_col_offset) {
14041419
pum_selected = -1;
14051420
return;
14061421
}
14071422

1408-
int idx = mouse_row - (pum_row - pum_win_row_offset);
1423+
int idx = row - (pum_row - pum_win_row_offset);
14091424

14101425
if (idx < 0 || idx >= pum_height) {
14111426
pum_selected = -1;

src/nvim/terminal.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1907,7 +1907,7 @@ static bool send_mouse_event(Terminal *term, int c)
19071907
int row = mouse_row;
19081908
int col = mouse_col;
19091909
int grid = mouse_grid;
1910-
win_T *mouse_win = mouse_find_win(&grid, &row, &col);
1910+
win_T *mouse_win = mouse_find_win_inner(&grid, &row, &col);
19111911
if (mouse_win == NULL) {
19121912
goto end;
19131913
}

src/nvim/ui_compositor.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,15 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col)
318318
return grid;
319319
}
320320
}
321+
if (ui_has(kUIMultigrid)) {
322+
FOR_ALL_WINDOWS_IN_TAB(wp, curtab) {
323+
ScreenGrid *grid = &wp->w_grid_alloc;
324+
if (grid->mouse_enabled && row >= wp->w_winrow && row < wp->w_winrow + grid->rows
325+
&& col >= wp->w_wincol && col < wp->w_wincol + grid->cols) {
326+
return grid;
327+
}
328+
}
329+
}
321330
return NULL;
322331
}
323332

0 commit comments

Comments
 (0)