patch 9.2.1074: popup: image stays on the screen in another tab page
Problem: The image of a tab-local popup window stays on the screen
after switching to another tab page, while the border and the
background of the popup are gone. The image backends keep an
image until it is removed: a kitty placement and a GTK4
texture until they are deleted, GDI and cairo pixels until the
area is repainted, sixel pixels until the screen is cleared.
Solution: Remove the images of the popups local to a tab page when the
tab page is left, they are emitted again when it is entered.
(Hirohito Higashi).
related: #21234
closes: #21273
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
1 parent
737b761ee6
commit
3362c8c89f
5 files changed
+150
No files matched your search
@@ -4645,6 +4645,43 @@ popup_close(int id, int force)
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
#ifdef FEAT_IMAGE
|
||||
/*
|
||||
* Remove the images of the popups local to tabpage "tp", it is about to be
|
||||
* left. The popups are not drawn in another tabpage, their images stay until
|
||||
* they are removed. They are emitted again when the tabpage is entered.
|
||||
*/
|
||||
void
|
||||
popup_leave_tabpage(tabpage_T *tp)
|
||||
{
|
||||
win_T *wp;
|
||||
|
||||
FOR_ALL_POPUPWINS_IN_TAB(tp, wp)
|
||||
{
|
||||
if ((wp->w_popup_flags & POPF_HIDDEN) || wp->w_popup_image_data == NULL)
|
||||
continue;
|
||||
# ifdef FEAT_IMAGE_KITTY
|
||||
popup_image_clear_kitty(wp, false);
|
||||
# endif
|
||||
# ifdef FEAT_IMAGE_GDK
|
||||
if (gui.in_use)
|
||||
gui_gtk4_remove_image(wp);
|
||||
# endif
|
||||
# ifdef POPUP_IMAGE_CLEAR_GUI
|
||||
popup_image_clear_gui(wp);
|
||||
# endif
|
||||
# ifdef FEAT_IMAGE_SIXEL
|
||||
// Sixel pixels only go away with a clear of the screen.
|
||||
# ifdef FEAT_GUI
|
||||
if (!gui.in_use)
|
||||
# endif
|
||||
if (popup_image_backend() == IMAGE_BACKEND_SIXEL)
|
||||
redraw_later_clear();
|
||||
# endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Close a popup window with Window-id "id" in tabpage "tp".
|
||||
*/
|
||||
|
||||
@@ -39,6 +39,7 @@ void f_popup_settext(typval_T *argvars, typval_T *rettv);
|
||||
void f_popup_setbuf(typval_T *argvars, typval_T *rettv);
|
||||
int error_if_popup_window(int also_with_term);
|
||||
int popup_close(int id, int force);
|
||||
void popup_leave_tabpage(tabpage_T *tp);
|
||||
int popup_close_tabpage(tabpage_T *tp, int id, int force);
|
||||
void close_all_popups(int force);
|
||||
void f_popup_move(typval_T *argvars, typval_T *rettv);
|
||||
|
||||
@@ -6310,6 +6310,113 @@ func Test_popup_image_clipwindow_scroll()
|
||||
call prop_type_delete('imgclipprop')
|
||||
endfunc
|
||||
|
||||
" The kitty and sixel image backends cannot be tested in a terminal window:
|
||||
" it does not show the escape sequences Vim writes and does not answer the
|
||||
" probe for the kitty graphics protocol. Run Vim on a pty as a job instead
|
||||
" and look at what it writes there.
|
||||
|
||||
" The sequences of the kitty graphics protocol Vim writes, "a=" is the action.
|
||||
" See https://sw.kovidgoyal.net/kitty/graphics-protocol/
|
||||
" a=q: does the terminal support the protocol?
|
||||
let s:kitty_probe = "\<Esc>_Gi=31"
|
||||
" What a terminal that supports the protocol answers, followed by the reply to
|
||||
" the DA1 request that ends the probe.
|
||||
let s:kitty_probe_answer = "\<Esc>_Gi=31;OK\<Esc>\\\<Esc>[?62;4c"
|
||||
" a=t: transmit the pixels of an image.
|
||||
let s:kitty_transmit = "\<Esc>_Ga=t,"
|
||||
" a=p: place a transmitted image on the screen.
|
||||
let s:kitty_place = "\<Esc>_Ga=p,"
|
||||
" a=d,d=i: delete the placement of an image, the terminal keeps the pixels.
|
||||
let s:kitty_delete = "\<Esc>_Ga=d,d=i,"
|
||||
|
||||
" The start of a sixel image, a DCS with the "q" command.
|
||||
let s:sixel_start_pat = "\<Esc>P[0-9;]*q"
|
||||
" Clear the screen, the only way to remove sixel pixels on some terminals.
|
||||
let s:clear_screen = "\<Esc>[2J"
|
||||
|
||||
" The script for the Vim on the pty: create a popup with an image.
|
||||
let s:image_popup_script =<< trim END
|
||||
let img = repeat([0xff, 0, 0], 16 * 32)->list2blob()
|
||||
call popup_create('', #{image: #{data: img, width: 16, height: 32}})
|
||||
redraw
|
||||
END
|
||||
|
||||
" Collect what the Vim on the pty writes in s:pty_out. With "kitty" the probe
|
||||
" is answered like a terminal that supports the protocol, otherwise Vim gets
|
||||
" no answer and uses sixel.
|
||||
func s:PtyOutput(job, msg, kitty)
|
||||
let s:pty_out ..= a:msg
|
||||
if a:kitty && !s:pty_answered && stridx(s:pty_out, s:kitty_probe) >= 0
|
||||
call ch_sendraw(a:job, s:kitty_probe_answer)
|
||||
let s:pty_answered = 1
|
||||
endif
|
||||
endfunc
|
||||
|
||||
" Start Vim on a pty with the script written to XpopupImageTab.
|
||||
func s:StartVimWithImageOnPty(kitty)
|
||||
let s:pty_out = ''
|
||||
let s:pty_answered = 0
|
||||
return job_start(GetVimCommandCleanTerm() .. ' -S XpopupImageTab', #{
|
||||
\ pty: 1,
|
||||
\ out_mode: 'raw',
|
||||
\ env: #{TERM: 'xterm', LINES: '24', COLUMNS: '80'},
|
||||
\ out_cb: {job, msg -> s:PtyOutput(job, msg, a:kitty)},
|
||||
\ })
|
||||
endfunc
|
||||
|
||||
" Wait for the Vim on the pty to write "seq" after the first "start" bytes.
|
||||
func s:WaitForPtyOutput(seq, start)
|
||||
call WaitForAssert({-> assert_notequal(-1,
|
||||
\ stridx(s:pty_out, a:seq, a:start))})
|
||||
endfunc
|
||||
|
||||
func Test_popup_image_kitty_leave_tabpage()
|
||||
CheckUnix
|
||||
CheckFeature job
|
||||
CheckFeature image_kitty
|
||||
|
||||
call writefile(s:image_popup_script, 'XpopupImageTab', 'D')
|
||||
let job = s:StartVimWithImageOnPty(1)
|
||||
try
|
||||
call s:WaitForPtyOutput(s:kitty_transmit, 0)
|
||||
call s:WaitForPtyOutput(s:kitty_place, 0)
|
||||
|
||||
" Leaving the tab page deletes the placement.
|
||||
let start = len(s:pty_out)
|
||||
call ch_sendraw(job, ":tabedit\<CR>")
|
||||
call s:WaitForPtyOutput(s:kitty_delete, start)
|
||||
|
||||
" Entering the tab page places the image again without transmitting it.
|
||||
let start = len(s:pty_out)
|
||||
call ch_sendraw(job, ":tabnext\<CR>")
|
||||
call s:WaitForPtyOutput(s:kitty_place, start)
|
||||
call assert_equal(-1, stridx(s:pty_out, s:kitty_transmit, start))
|
||||
finally
|
||||
call job_stop(job, 'kill')
|
||||
call WaitForAssert({-> assert_equal('dead', job_status(job))})
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func Test_popup_image_sixel_leave_tabpage()
|
||||
CheckUnix
|
||||
CheckFeature job
|
||||
CheckFeature image_sixel
|
||||
|
||||
call writefile(s:image_popup_script, 'XpopupImageTab', 'D')
|
||||
let job = s:StartVimWithImageOnPty(0)
|
||||
try
|
||||
call WaitForAssert({-> assert_match(s:sixel_start_pat, s:pty_out)})
|
||||
|
||||
" Leaving the tab page clears the screen.
|
||||
let start = len(s:pty_out)
|
||||
call ch_sendraw(job, ":tabedit\<CR>")
|
||||
call s:WaitForPtyOutput(s:clear_screen, start)
|
||||
finally
|
||||
call job_stop(job, 'kill')
|
||||
call WaitForAssert({-> assert_equal('dead', job_status(job))})
|
||||
endtry
|
||||
endfunc
|
||||
|
||||
func Test_popupwin_textprop_redraw()
|
||||
CheckScreendump
|
||||
|
||||
|
||||
@@ -763,6 +763,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
1074,
|
||||
/**/
|
||||
1073,
|
||||
/**/
|
||||
|
||||
@@ -5116,6 +5116,9 @@ leave_tabpage(
|
||||
return FAIL;
|
||||
}
|
||||
|
||||
#ifdef FEAT_IMAGE
|
||||
popup_leave_tabpage(tp);
|
||||
#endif
|
||||
reset_dragwin();
|
||||
#if defined(FEAT_GUI)
|
||||
// Remove the scrollbars. They may be added back later.
|
||||
|
||||
Reference in new issue
Block a user