patch 8.1.1303: not possible to hide a balloon

Problem:    Not possible to hide a balloon.
Solution:   Hide the balloon when balloon_show() is called with an empty
            string or list.  Add balloon_gettext().
diff --git a/runtime/doc/eval.txt b/runtime/doc/eval.txt
index 84001b7..15732d6 100644
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -2226,6 +2226,7 @@
 asin({expr})			Float	arc sine of {expr}
 atan({expr})			Float	arc tangent of {expr}
 atan2({expr1}, {expr2})		Float	arc tangent of {expr1} / {expr2}
+balloon_gettext()		String	current text in the balloon
 balloon_show({expr})		none	show {expr} inside the balloon
 balloon_split({msg})		List	split {msg} as used for a balloon
 browse({save}, {title}, {initdir}, {default})
@@ -3007,15 +3008,20 @@
 <			2.356194
 		{only available when compiled with the |+float| feature}
 
+balloon_gettext()					*balloon_gettext()*
+		Return the current text in the balloon.  Only for the string,
+		not used for the List.
+
 balloon_show({expr})					*balloon_show()*
 		Show {expr} inside the balloon.  For the GUI {expr} is used as
 		a string.  For a terminal {expr} can be a list, which contains
 		the lines of the balloon.  If {expr} is not a list it will be
 		split with |balloon_split()|.
+		If {expr} is an empty string any existing balloon is removed.
 
 		Example: >
 			func GetBalloonContent()
-			   " initiate getting the content
+			   " ... initiate getting the content
 			   return ''
 			endfunc
 			set balloonexpr=GetBalloonContent()
@@ -4229,6 +4235,8 @@
 		and "\..." notation |expr-quote|. For example,
 		feedkeys("\<CR>") simulates pressing of the <Enter> key. But
 		feedkeys('\<CR>') pushes 5 characters.
+		A special code that might be useful is <Ignore>, it exits the
+		wait for a character without doing anything.  *<Ignore>*
 
 		{mode} is a String, which can contain these character flags:
 		'm'	Remap keys. This is default.  If {mode} is absent,
diff --git a/src/beval.h b/src/beval.h
index 090c5fb..60cf1ab 100644
--- a/src/beval.h
+++ b/src/beval.h
@@ -75,7 +75,7 @@
 #ifdef FEAT_VARTABS
     int			*vts;		// vartabstop setting for this buffer
 #endif
-    char_u		*msg;
+    char_u		*msg;		// allocated: current text
 #ifdef FEAT_GUI_MSWIN
     void		*tofree;
 #endif
diff --git a/src/evalfunc.c b/src/evalfunc.c
index ca412f7..eaefccf 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -63,6 +63,7 @@
 static void f_atan2(typval_T *argvars, typval_T *rettv);
 #endif
 #ifdef FEAT_BEVAL
+static void f_balloon_gettext(typval_T *argvars, typval_T *rettv);
 static void f_balloon_show(typval_T *argvars, typval_T *rettv);
 # if defined(FEAT_BEVAL_TERM)
 static void f_balloon_split(typval_T *argvars, typval_T *rettv);
@@ -552,6 +553,7 @@
     {"atan2",		2, 2, f_atan2},
 #endif
 #ifdef FEAT_BEVAL
+    {"balloon_gettext",	0, 0, f_balloon_gettext},
     {"balloon_show",	1, 1, f_balloon_show},
 # if defined(FEAT_BEVAL_TERM)
     {"balloon_split",	1, 1, f_balloon_split},
@@ -1764,6 +1766,19 @@
  */
 #ifdef FEAT_BEVAL
     static void
+f_balloon_gettext(typval_T *argvars UNUSED, typval_T *rettv)
+{
+    rettv->v_type = VAR_STRING;
+    if (balloonEval != NULL)
+    {
+	if (balloonEval->msg == NULL)
+	    rettv->vval.v_string = NULL;
+	else
+	    rettv->vval.v_string = vim_strsave(balloonEval->msg);
+    }
+}
+
+    static void
 f_balloon_show(typval_T *argvars, typval_T *rettv UNUSED)
 {
     if (balloonEval != NULL)
@@ -1773,9 +1788,21 @@
 		&& !gui.in_use
 # endif
 	   )
-	    post_balloon(balloonEval, NULL, argvars[0].vval.v_list);
+	{
+	    list_T *l = argvars[0].vval.v_list;
+
+	    // empty list removes the balloon
+	    post_balloon(balloonEval, NULL,
+				       l == NULL || l->lv_len == 0 ? NULL : l);
+	}
 	else
-	    post_balloon(balloonEval, tv_get_string_chk(&argvars[0]), NULL);
+	{
+	    char_u *mesg = tv_get_string_chk(&argvars[0]);
+
+	    if (mesg != NULL)
+		// empty string removes the balloon
+		post_balloon(balloonEval, *mesg == NUL ? NULL : mesg, NULL);
+	}
     }
 }
 
diff --git a/src/gui_beval.c b/src/gui_beval.c
index e1e093f..f4309b8 100644
--- a/src/gui_beval.c
+++ b/src/gui_beval.c
@@ -117,7 +117,8 @@
 	beval->appContext = XtWidgetToApplicationContext((Widget)target);
 #endif
 	beval->showState = ShS_NEUTRAL;
-	beval->msg = mesg;
+	vim_free(beval->msg);
+	beval->msg = mesg == NULL ? NULL : vim_strsave(mesg);
 	beval->msgCB = mesgCB;
 	beval->clientData = clientData;
 
@@ -208,8 +209,9 @@
     void
 gui_mch_post_balloon(BalloonEval *beval, char_u *mesg)
 {
-    beval->msg = mesg;
-    if (mesg != NULL)
+    vim_free(beval->msg);
+    beval->msg = mesg == NULL ? NULL : vim_strsave(mesg);
+    if (beval->msg != NULL)
 	drawBalloon(beval);
     else
 	undrawBalloon(beval);
@@ -225,6 +227,7 @@
     void
 gui_mch_unpost_balloon(BalloonEval *beval)
 {
+    VIM_CLEAR(beval->msg);
     undrawBalloon(beval);
 }
 #endif
@@ -975,6 +978,7 @@
 	gtk_widget_show(beval->balloonShell);
 
 	beval->showState = ShS_SHOWING;
+	gui_mch_update();
     }
 }
 
diff --git a/src/gui_w32.c b/src/gui_w32.c
index 69212eb..8d28148 100644
--- a/src/gui_w32.c
+++ b/src/gui_w32.c
@@ -8506,6 +8506,15 @@
 {
     POINT   pt;
 
+    vim_free(beval->msg);
+    beval->msg = mesg == NULL ? NULL : vim_strsave(mesg);
+    if (beval->msg == NULL)
+    {
+	delete_tooltip(beval);
+	beval->showState = ShS_NEUTRAL;
+	return;
+    }
+
     // TRACE0("gui_mch_post_balloon {{{");
     if (beval->showState == ShS_SHOWING)
 	return;
diff --git a/src/popupmnu.c b/src/popupmnu.c
index 2639d97..0b002f5 100644
--- a/src/popupmnu.c
+++ b/src/popupmnu.c
@@ -1154,7 +1154,10 @@
     ui_remove_balloon();
 
     if (mesg == NULL && list == NULL)
+    {
+	pum_undisplay();
 	return;
+    }
     if (list != NULL)
     {
 	listitem_T  *li;
diff --git a/src/testdir/test_balloon.vim b/src/testdir/test_balloon.vim
index 966587c..57d8dcc 100644
--- a/src/testdir/test_balloon.vim
+++ b/src/testdir/test_balloon.vim
@@ -1,8 +1,7 @@
 " Tests for 'balloonevalterm'.
 
-if !has('balloon_eval_term') || has('gui_running')
-  finish
-endif
+" Tests that only work in the terminal.
+if has('balloon_eval_term') && !has('gui_running')
 
 source screendump.vim
 if !CanRunVimInTerminal()
@@ -53,3 +52,24 @@
   call StopVimInTerminal(buf)
   call delete('XTest_beval_visual')
 endfunc
+
+endif
+
+" Tests that only work in the GUI
+if has('gui_running')
+
+func Test_balloon_show_gui()
+  let msg = 'this this this this'
+  call balloon_show(msg)
+  call assert_equal(msg, balloon_gettext())
+  sleep 10m
+  call balloon_show('')
+
+  let msg = 'that that'
+  call balloon_show(msg)
+  call assert_equal(msg, balloon_gettext())
+  sleep 10m
+  call balloon_show('')
+endfunc
+
+endif
diff --git a/src/version.c b/src/version.c
index 96c72fa..8aef9dd 100644
--- a/src/version.c
+++ b/src/version.c
@@ -768,6 +768,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1303,
+/**/
     1302,
 /**/
     1301,