Skip to content

Commit 4c063a0

Browse files
committed
patch 8.1.1517: when a popup changes all windows are redrawn
Problem: When a popup changes all windows are redrawn. Solution: Only update the lines that were affected. Add a file for profiling popup windows efficiency.
1 parent 640d4f0 commit 4c063a0

File tree

8 files changed

+178
-36
lines changed

8 files changed

+178
-36
lines changed

Filelist

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ SRC_ALL = \
152152
src/testdir/if_ver*.vim \
153153
src/testdir/color_ramp.vim \
154154
src/testdir/silent.wav \
155+
src/testdir/popupbounce.vim \
155156
src/proto.h \
156157
src/protodef.h \
157158
src/proto/arabic.pro \

src/globals.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ EXTERN short *TabPageIdxs INIT(= NULL);
7373
#ifdef FEAT_TEXT_PROP
7474
// Array with size Rows x Columns containing zindex of popups.
7575
EXTERN short *popup_mask INIT(= NULL);
76+
EXTERN short *popup_mask_next INIT(= NULL);
7677

7778
// Flag set to TRUE when popup_mask needs to be updated.
7879
EXTERN int popup_mask_refresh INIT(= TRUE);

src/popupwin.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -571,8 +571,7 @@ popup_adjust_position(win_T *wp)
571571
|| org_width != wp->w_width
572572
|| org_height != wp->w_height)
573573
{
574-
// TODO: redraw only windows that were below the popup.
575-
redraw_all_later(NOT_VALID);
574+
redraw_all_later(VALID);
576575
popup_mask_refresh = TRUE;
577576
}
578577
}

src/proto/screen.pro

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ int update_screen(int type_arg);
1616
int conceal_cursor_line(win_T *wp);
1717
void conceal_check_cursor_line(void);
1818
void update_debug_sign(buf_T *buf, linenr_T lnum);
19-
int may_update_popup_mask(int type_arg);
2019
void updateWindow(win_T *wp);
2120
int screen_get_current_line_off(void);
2221
void screen_line(int row, int coloff, int endcol, int clear_width, int flags);

src/screen.c

Lines changed: 86 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ static int redrawing_for_callback = 0;
122122
static schar_T *current_ScreenLine;
123123

124124
#ifdef FEAT_TEXT_PROP
125+
static void may_update_popup_mask(int type);
125126
static void update_popups(void);
126127
#endif
127128
static void win_update(win_T *wp);
@@ -612,8 +613,9 @@ update_screen(int type_arg)
612613
}
613614

614615
#ifdef FEAT_TEXT_PROP
615-
// Update popup_mask if needed.
616-
type = may_update_popup_mask(type);
616+
// Update popup_mask if needed. This may set w_redraw_top and w_redraw_bot
617+
// in some windows.
618+
may_update_popup_mask(type);
617619
#endif
618620

619621
updating_screen = TRUE;
@@ -1014,17 +1016,19 @@ get_wcr_attr(win_T *wp)
10141016
}
10151017

10161018
#ifdef FEAT_TEXT_PROP
1019+
10171020
/*
10181021
* Update "popup_mask" if needed.
10191022
* Also recomputes the popup size and positions.
10201023
* Also updates "popup_visible".
1021-
* If more redrawing is needed than "type_arg" a higher value is returned.
1024+
* Also marks window lines for redrawing.
10221025
*/
1023-
int
1024-
may_update_popup_mask(int type_arg)
1026+
static void
1027+
may_update_popup_mask(int type)
10251028
{
1026-
int type = type_arg;
10271029
win_T *wp;
1030+
short *mask;
1031+
int line, col;
10281032

10291033
if (popup_mask_tab != curtab)
10301034
popup_mask_refresh = TRUE;
@@ -1038,56 +1042,102 @@ may_update_popup_mask(int type_arg)
10381042
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
10391043
popup_mask_refresh = TRUE;
10401044
if (!popup_mask_refresh)
1041-
return type;
1045+
return;
10421046
}
10431047

1048+
// Need to update the mask, something has changed.
10441049
popup_mask_refresh = FALSE;
10451050
popup_mask_tab = curtab;
1046-
10471051
popup_visible = FALSE;
1048-
vim_memset(popup_mask, 0, screen_Rows * screen_Columns * sizeof(short));
1052+
1053+
// If redrawing everything, just update "popup_mask".
1054+
// If redrawing only what is needed, update "popup_mask_next" and then
1055+
// compare with "popup_mask" to see what changed.
1056+
if (type >= SOME_VALID)
1057+
mask = popup_mask;
1058+
else
1059+
mask = popup_mask_next;
1060+
vim_memset(mask, 0, screen_Rows * screen_Columns * sizeof(short));
10491061

10501062
// Find the window with the lowest zindex that hasn't been handled yet,
10511063
// so that the window with a higher zindex overwrites the value in
10521064
// popup_mask.
10531065
popup_reset_handled();
10541066
while ((wp = find_next_popup(TRUE)) != NULL)
10551067
{
1056-
int top_off, bot_off;
1057-
int left_off, right_off;
1058-
short *p;
1059-
int line, col;
1068+
int height_extra, width_extra;
10601069

10611070
popup_visible = TRUE;
10621071

10631072
// Recompute the position if the text changed.
10641073
if (wp->w_popup_last_changedtick != CHANGEDTICK(wp->w_buffer))
10651074
popup_adjust_position(wp);
10661075

1067-
// the position and size are for the inside, add the padding and
1076+
// the width and height are for the inside, add the padding and
10681077
// border
1069-
top_off = wp->w_popup_padding[0] + wp->w_popup_border[0];
1070-
bot_off = wp->w_popup_padding[2] + wp->w_popup_border[2];
1071-
left_off = wp->w_popup_padding[3] + wp->w_popup_border[3];
1072-
right_off = wp->w_popup_padding[1] + wp->w_popup_border[1];
1078+
height_extra = wp->w_popup_padding[0] + wp->w_popup_border[0]
1079+
+ wp->w_popup_padding[2] + wp->w_popup_border[2];
1080+
width_extra = wp->w_popup_padding[3] + wp->w_popup_border[3]
1081+
+ wp->w_popup_padding[1] + wp->w_popup_border[1];
10731082

1074-
for (line = wp->w_winrow + top_off;
1075-
line < wp->w_winrow + wp->w_height + bot_off
1083+
for (line = wp->w_winrow;
1084+
line < wp->w_winrow + wp->w_height + height_extra
10761085
&& line < screen_Rows; ++line)
1077-
for (col = wp->w_wincol + left_off;
1078-
col < wp->w_wincol + wp->w_width + right_off
1086+
for (col = wp->w_wincol;
1087+
col < wp->w_wincol + wp->w_width + width_extra
10791088
&& col < screen_Columns; ++col)
1089+
mask[line * screen_Columns + col] = wp->w_zindex;
1090+
}
1091+
1092+
// Only check which lines are to be updated if not already
1093+
// updating all lines.
1094+
if (mask == popup_mask_next)
1095+
for (line = 0; line < screen_Rows; ++line)
1096+
{
1097+
int col_done = 0;
1098+
1099+
for (col = 0; col < screen_Columns; ++col)
10801100
{
1081-
p = popup_mask + line * screen_Columns + col;
1082-
if (*p != wp->w_zindex)
1101+
int off = line * screen_Columns + col;
1102+
1103+
if (popup_mask[off] != popup_mask_next[off])
10831104
{
1084-
*p = wp->w_zindex;
1085-
type = NOT_VALID;
1105+
popup_mask[off] = popup_mask_next[off];
1106+
1107+
// The screen position "line" / "col" needs to be redrawn.
1108+
// Figure out what window that is and update w_redraw_top
1109+
// and w_redr_bot. Only needs to be done for each window
1110+
// line.
1111+
if (col >= col_done)
1112+
{
1113+
linenr_T lnum;
1114+
int line_cp = line;
1115+
int col_cp = col;
1116+
1117+
// find the window where the row is in
1118+
wp = mouse_find_win(&line_cp, &col_cp);
1119+
if (wp != NULL)
1120+
{
1121+
if (line_cp >= wp->w_height)
1122+
// In (or below) status line
1123+
wp->w_redr_status = TRUE;
1124+
// compute the position in the buffer line from the
1125+
// position on the screen
1126+
else if (mouse_comp_pos(wp, &line_cp, &col_cp,
1127+
&lnum))
1128+
// past bottom
1129+
wp->w_redr_status = TRUE;
1130+
else
1131+
redrawWinline(wp, lnum);
1132+
1133+
// This line is going to be redrawn, no need to
1134+
// check until the right side of the window.
1135+
col_done = wp->w_wincol + wp->w_width - 1;
1136+
}
1137+
}
10861138
}
10871139
}
1088-
}
1089-
1090-
return type;
1140+
}
10911141
}
10921142

10931143
/*
@@ -9112,6 +9162,7 @@ screenalloc(int doclear)
91129162
short *new_TabPageIdxs;
91139163
#ifdef FEAT_TEXT_PROP
91149164
short *new_popup_mask;
9165+
short *new_popup_mask_next;
91159166
#endif
91169167
tabpage_T *tp;
91179168
static int entered = FALSE; /* avoid recursiveness */
@@ -9196,6 +9247,7 @@ screenalloc(int doclear)
91969247
new_TabPageIdxs = LALLOC_MULT(short, Columns);
91979248
#ifdef FEAT_TEXT_PROP
91989249
new_popup_mask = LALLOC_MULT(short, Rows * Columns);
9250+
new_popup_mask_next = LALLOC_MULT(short, Rows * Columns);
91999251
#endif
92009252

92019253
FOR_ALL_TAB_WINDOWS(tp, wp)
@@ -9241,6 +9293,7 @@ screenalloc(int doclear)
92419293
|| new_TabPageIdxs == NULL
92429294
#ifdef FEAT_TEXT_PROP
92439295
|| new_popup_mask == NULL
9296+
|| new_popup_mask_next == NULL
92449297
#endif
92459298
|| outofmem)
92469299
{
@@ -9264,6 +9317,7 @@ screenalloc(int doclear)
92649317
VIM_CLEAR(new_TabPageIdxs);
92659318
#ifdef FEAT_TEXT_PROP
92669319
VIM_CLEAR(new_popup_mask);
9320+
VIM_CLEAR(new_popup_mask_next);
92679321
#endif
92689322
}
92699323
else
@@ -9353,6 +9407,7 @@ screenalloc(int doclear)
93539407
TabPageIdxs = new_TabPageIdxs;
93549408
#ifdef FEAT_TEXT_PROP
93559409
popup_mask = new_popup_mask;
9410+
popup_mask_next = new_popup_mask_next;
93569411
vim_memset(popup_mask, 0, Rows * Columns * sizeof(short));
93579412
popup_mask_refresh = TRUE;
93589413
#endif
@@ -9421,6 +9476,7 @@ free_screenlines(void)
94219476
VIM_CLEAR(TabPageIdxs);
94229477
#ifdef FEAT_TEXT_PROP
94239478
VIM_CLEAR(popup_mask);
9479+
VIM_CLEAR(popup_mask_next);
94249480
#endif
94259481
}
94269482

@@ -10027,7 +10083,7 @@ win_do_lines(
1002710083
}
1002810084

1002910085
#ifdef FEAT_TEXT_PROP
10030-
// this doesn't work when tere are popups visible
10086+
// this doesn't work when there are popups visible
1003110087
if (popup_visible)
1003210088
return FAIL;
1003310089
#endif

src/testdir/popupbounce.vim

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
" Use this script to measure the redrawing performance when a popup is being
2+
" displayed. Usage with gcc:
3+
" cd src
4+
" # Edit Makefile to uncomment PROFILE_CFLAGS and PROFILE_LIBS
5+
" make reconfig
6+
" ./vim --clean -S testdir/popupbounce.vim main.c
7+
" gprof vim gmon.out | vim -
8+
9+
" using line contination
10+
set nocp
11+
12+
" don't switch screens when quitting, so we can read the frames/sec
13+
set t_te=
14+
15+
let winid = popup_create(['line1', 'line2', 'line3', 'line4'], {
16+
\ 'line' : 1,
17+
\ 'col' : 1,
18+
\ 'zindex' : 101,
19+
\ })
20+
redraw
21+
22+
let start = reltime()
23+
let framecount = 0
24+
25+
let line = 1.0
26+
let col = 1
27+
let downwards = 1
28+
let col_inc = 1
29+
let initial_speed = 0.2
30+
let speed = initial_speed
31+
let accel = 1.1
32+
let time = 0.1
33+
34+
let countdown = 0
35+
36+
while 1
37+
if downwards
38+
let speed += time * accel
39+
let line += speed
40+
else
41+
let speed -= time * accel
42+
let line -= speed
43+
endif
44+
45+
if line + 3 >= &lines
46+
let downwards = 0
47+
let speed = speed * 0.8
48+
let line = &lines - 3
49+
endif
50+
if !downwards && speed < 1.0
51+
let downwards = 1
52+
let speed = initial_speed
53+
if line + 4 > &lines && countdown == 0
54+
let countdown = 50
55+
endif
56+
endif
57+
58+
let col += col_inc
59+
if col + 4 >= &columns
60+
let col_inc = -1
61+
elseif col <= 1
62+
let col_inc = 1
63+
endif
64+
65+
call popup_move(winid, {'line': float2nr(line), 'col': col})
66+
redraw
67+
let framecount += 1
68+
if countdown > 0
69+
let countdown -= 1
70+
if countdown == 0
71+
break
72+
endif
73+
endif
74+
75+
endwhile
76+
77+
let elapsed = reltimefloat(reltime(start))
78+
echomsg framecount .. ' frames in ' .. string(elapsed) .. ' seconds, ' .. string(framecount / elapsed) .. ' frames/sec'
79+
80+
qa

src/ui.c

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3242,15 +3242,19 @@ jump_to_mouse(
32423242
|| curwin->w_cursor.col != old_cursor.col)
32433243
count |= CURSOR_MOVED; /* Cursor has moved */
32443244

3245-
#ifdef FEAT_FOLDING
3245+
# ifdef FEAT_FOLDING
32463246
if (mouse_char == '+')
32473247
count |= MOUSE_FOLD_OPEN;
32483248
else if (mouse_char != ' ')
32493249
count |= MOUSE_FOLD_CLOSE;
3250-
#endif
3250+
# endif
32513251

32523252
return count;
32533253
}
3254+
#endif
3255+
3256+
// Functions also used for popup windows.
3257+
#if defined(FEAT_MOUSE) || defined(FEAT_TEXT_PROP) || defined(PROTO)
32543258

32553259
/*
32563260
* Compute the position in the buffer line from the posn on the screen in
@@ -3347,7 +3351,7 @@ mouse_comp_pos(
33473351
* Returns NULL when something is wrong.
33483352
*/
33493353
win_T *
3350-
mouse_find_win(int *rowp, int *colp UNUSED)
3354+
mouse_find_win(int *rowp, int *colp)
33513355
{
33523356
frame_T *fp;
33533357
win_T *wp;

src/version.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -777,6 +777,8 @@ static char *(features[]) =
777777

778778
static int included_patches[] =
779779
{ /* Add new patch number below this line */
780+
/**/
781+
1517,
780782
/**/
781783
1516,
782784
/**/

0 commit comments

Comments
 (0)