patch 8.1.2046: SafeState may be triggered at the wrong moment

Problem:    SafeState may be triggered at the wrong moment.
Solution:   Move it up higher to after where messages are processed.  Add a
            SafeStateAgain event to tigger there.
diff --git a/src/autocmd.c b/src/autocmd.c
index fb6c844..3f87e93 100644
--- a/src/autocmd.c
+++ b/src/autocmd.c
@@ -156,6 +156,7 @@
     {"QuitPre",		EVENT_QUITPRE},
     {"RemoteReply",	EVENT_REMOTEREPLY},
     {"SafeState",	EVENT_SAFESTATE},
+    {"SafeStateAgain",	EVENT_SAFESTATEAGAIN},
     {"SessionLoadPost",	EVENT_SESSIONLOADPOST},
     {"ShellCmdPost",	EVENT_SHELLCMDPOST},
     {"ShellFilterPost",	EVENT_SHELLFILTERPOST},
diff --git a/src/channel.c b/src/channel.c
index 3792b35..0dab3be 100644
--- a/src/channel.c
+++ b/src/channel.c
@@ -3593,10 +3593,6 @@
 
     ch_log(channel, "Blocking read JSON for id %d", id);
 
-    // Not considered a safe state here, since we are processing a JSON message
-    // and parsing other messages while waiting.
-    enter_unsafe_state();
-
     if (id >= 0)
 	channel_add_block_id(chanpart, id);
 
@@ -3666,9 +3662,6 @@
     if (id >= 0)
 	channel_remove_block_id(chanpart, id);
 
-    // This may trigger a SafeState autocommand.
-    leave_unsafe_state();
-
     return retval;
 }
 
diff --git a/src/getchar.c b/src/getchar.c
index 32e3550..3f3c6bc 100644
--- a/src/getchar.c
+++ b/src/getchar.c
@@ -933,6 +933,7 @@
     init_typebuf();
     if (++typebuf.tb_change_cnt == 0)
 	typebuf.tb_change_cnt = 1;
+    state_no_longer_safe();
 
     addlen = (int)STRLEN(str);
 
@@ -1779,10 +1780,11 @@
      */
     may_garbage_collect = FALSE;
 #endif
+
 #ifdef FEAT_BEVAL_TERM
     if (c != K_MOUSEMOVE && c != K_IGNORE && c != K_CURSORHOLD)
     {
-	/* Don't trigger 'balloonexpr' unless only the mouse was moved. */
+	// Don't trigger 'balloonexpr' unless only the mouse was moved.
 	bevalexpr_due_set = FALSE;
 	ui_remove_balloon();
     }
@@ -1792,6 +1794,11 @@
 	c = K_IGNORE;
 #endif
 
+    // Need to process the character before we know it's safe to do something
+    // else.
+    if (c != K_IGNORE)
+	state_no_longer_safe();
+
     return c;
 }
 
@@ -2039,12 +2046,15 @@
     int	    old_curbuf_fnum = curbuf->b_fnum;
     int	    i;
     int	    save_may_garbage_collect = may_garbage_collect;
+    static int entered = 0;
 
     // Do not handle messages while redrawing, because it may cause buffers to
     // change or be wiped while they are being redrawn.
     if (updating_screen)
 	return;
 
+    ++entered;
+
     // may_garbage_collect is set in main_loop() to do garbage collection when
     // blocking to wait on a character.  We don't want that while parsing
     // messages, a callback may invoke vgetc() while lists and dicts are in use
@@ -2090,12 +2100,19 @@
 	break;
     }
 
+    // When not nested we'll go back to waiting for a typed character.  If it
+    // was safe before then this triggers a SafeStateAgain autocommand event.
+    if (entered == 1)
+	leave_unsafe_state();
+
     may_garbage_collect = save_may_garbage_collect;
 
     // If the current window or buffer changed we need to bail out of the
     // waiting loop.  E.g. when a job exit callback closes the terminal window.
     if (curwin->w_id != old_curwin_id || curbuf->b_fnum != old_curbuf_fnum)
 	ins_char_typebuf(K_IGNORE);
+
+    --entered;
 }
 #endif
 
diff --git a/src/main.c b/src/main.c
index 94bb846..51e3915 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1029,8 +1029,8 @@
 }
 
 
+// When TRUE in a safe state when starting to wait for a character.
 static int	was_safe = FALSE;
-static int	not_safe_now = 0;
 
 /*
  * Trigger SafeState if currently in a safe state for main_loop().
@@ -1057,6 +1057,7 @@
     int is_safe = safe
 		    && stuff_empty()
 		    && typebuf.tb_len == 0
+		    && scriptin[curscript] == NULL
 		    && !global_busy;
 
     if (is_safe)
@@ -1065,24 +1066,25 @@
 }
 
 /*
- * Entering a not-safe state.
+ * Something changed which causes the state possibly to be unsafe, e.g. a
+ * character was typed.  It will remain unsafe until the next call to
+ * may_trigger_safestate().
  */
     void
-enter_unsafe_state(void)
+state_no_longer_safe(void)
 {
-    ++not_safe_now;
+    was_safe = FALSE;
 }
 
 /*
- * Leaving a not-safe state.  Trigger SafeState if we were in a safe state
- * before first calling enter_not_safe_state().
+ * Invoked when leaving code that invokes callbacks.  Then trigger
+ * SafeStateAgain, if it was safe when starting to wait for a character.
  */
     void
 leave_unsafe_state(void)
 {
-    --not_safe_now;
-    if (not_safe_now == 0 && was_safe)
-	apply_autocmds(EVENT_SAFESTATE, NULL, NULL, FALSE, curbuf);
+    if (was_safe)
+	apply_autocmds(EVENT_SAFESTATEAGAIN, NULL, NULL, FALSE, curbuf);
 }
 
 
diff --git a/src/proto/main.pro b/src/proto/main.pro
index a6b9784..2c07cea 100644
--- a/src/proto/main.pro
+++ b/src/proto/main.pro
@@ -3,7 +3,7 @@
 void common_init(mparm_T *paramp);
 int is_not_a_term(void);
 void may_trigger_safestate(int safe);
-void enter_unsafe_state(void);
+void state_no_longer_safe(void);
 void leave_unsafe_state(void);
 void main_loop(int cmdwin, int noexmode);
 void getout_preserve_modified(int exitval);
diff --git a/src/version.c b/src/version.c
index 34e3e6b..02e8cfb 100644
--- a/src/version.c
+++ b/src/version.c
@@ -758,6 +758,8 @@
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    2046,
+/**/
     2045,
 /**/
     2044,
diff --git a/src/vim.h b/src/vim.h
index 4b817c5..8bfbcaf 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -1316,6 +1316,7 @@
     EVENT_QUITPRE,		// before :quit
     EVENT_REMOTEREPLY,		// upon string reception from a remote vim
     EVENT_SAFESTATE,		// going to wait for a character
+    EVENT_SAFESTATEAGAIN,	// still waiting for a character
     EVENT_SESSIONLOADPOST,	// after loading a session file
     EVENT_SHELLCMDPOST,		// after ":!cmd"
     EVENT_SHELLFILTERPOST,	// after ":1,2!cmd", ":w !cmd", ":r !cmd".