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/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