patch 8.2.2345: no focus events in a terminal

Problem:    No focus events in a terminal.
Solution:   Add the t_fd and t_fe termcap entries and implement detecting
            focus events. (Hayaki Saito, Magnus Groß, closes #7673,
            closes #609, closes #5526)
diff --git a/src/term.c b/src/term.c
index 9e9a67b..bf33a1c 100644
--- a/src/term.c
+++ b/src/term.c
@@ -196,6 +196,11 @@
 
 static int  detected_8bit = FALSE;	// detected 8-bit terminal
 
+#if (defined(UNIX) || defined(VMS))
+static int focus_mode = FALSE; // xterm's "focus reporting" availability
+static int focus_state = FALSE; // TRUE if the terminal window gains focus
+#endif
+
 #ifdef FEAT_TERMRESPONSE
 // When the cursor shape was detected these values are used:
 // 1: block, 2: underline, 3: vertical bar
@@ -908,6 +913,10 @@
     {(int)KS_CRT,	IF_EB("\033[23;2t", ESC_STR "[23;2t")},
     {(int)KS_SSI,	IF_EB("\033[22;1t", ESC_STR "[22;1t")},
     {(int)KS_SRI,	IF_EB("\033[23;1t", ESC_STR "[23;1t")},
+#  if (defined(UNIX) || defined(VMS))
+    {(int)KS_FD,	IF_EB("\033[?1004l", ESC_STR "[?1004l")},
+    {(int)KS_FE,	IF_EB("\033[?1004h", ESC_STR "[?1004h")},
+#  endif
 
     {K_UP,		IF_EB("\033O*A", ESC_STR "O*A")},
     {K_DOWN,		IF_EB("\033O*B", ESC_STR "O*B")},
@@ -2044,6 +2053,27 @@
     set_mouse_termcode(KS_MOUSE, (char_u *)"\233M");
 #endif
 
+#if (defined(UNIX) || defined(VMS))
+    // focus reporting is supported by xterm compatible terminals and tmux.
+    if (use_xterm_like_mouse(term))
+    {
+	char_u name[3];
+	name[0] = (int)KS_EXTRA;
+	name[2] = NUL;
+
+	// handle focus in event
+	name[1] = (int)KE_FOCUSGAINED;
+	add_termcode(name, (char_u *)"\033[I", FALSE);
+
+	// handle focus out event
+	name[1] = (int)KE_FOCUSLOST;
+	add_termcode(name, (char_u *)"\033[O", FALSE);
+
+	focus_mode = TRUE;
+	focus_state = TRUE;
+    }
+#endif
+
 #ifdef USE_TERM_CONSOLE
     // DEFAULT_TERM indicates that it is the machine console.
     if (STRCMP(term, DEFAULT_TERM) != 0)
@@ -2519,7 +2549,10 @@
 	if (ch_log_output)
 	{
 	    out_buf[len] = NUL;
-	    ch_log(NULL, "raw terminal output: \"%s\"", out_buf);
+	    ch_log(NULL, "raw %s output: \"%s\"",
+			(gui.in_use && !gui.dying && !gui.starting)
+							  ? "GUI" : "terminal",
+			out_buf);
 	    ch_log_output = FALSE;
 	}
 #endif
@@ -3582,6 +3615,13 @@
 	out_str(T_CTI);			// start "raw" mode
 	out_str(T_KS);			// start "keypad transmit" mode
 	out_str(T_BE);			// enable bracketed paste mode
+
+#if (defined(UNIX) || defined(VMS))
+	// enable xterm's focus reporting mode
+	if (focus_mode && *T_FE != NUL)
+	    out_str(T_FE);
+#endif
+
 	out_flush();
 	termcap_active = TRUE;
 	screen_start();			// don't know where cursor is now
@@ -3633,6 +3673,13 @@
 #ifdef FEAT_JOB_CHANNEL
 	ch_log_output = TRUE;
 #endif
+
+#if (defined(UNIX) || defined(VMS))
+	// disable xterm's focus reporting mode
+	if (focus_mode && *T_FD != NUL)
+	    out_str(T_FD);
+#endif
+
 	out_str(T_BD);			// disable bracketed paste mode
 	out_str(T_KE);			// stop "keypad transmit" mode
 	out_flush();
@@ -5647,6 +5694,45 @@
 # endif // !USE_ON_FLY_SCROLL
 #endif // FEAT_GUI
 
+#if (defined(UNIX) || defined(VMS))
+	/*
+	 * Handle FocusIn/FocusOut event sequences reported by XTerm.
+	 * (CSI I/CSI O)
+	 */
+	if (focus_mode
+# ifdef FEAT_GUI
+		&& !gui.in_use
+# endif
+		&& key_name[0] == KS_EXTRA
+	    )
+	{
+	    int did_aucmd = FALSE;
+
+	    if (key_name[1] == KE_FOCUSGAINED && !focus_state)
+	    {
+		did_aucmd = apply_autocmds(EVENT_FOCUSGAINED,
+						    NULL, NULL, FALSE, curbuf);
+		did_cursorhold = TRUE;
+		focus_state = TRUE;
+		key_name[1] = (int)KE_IGNORE;
+	    }
+	    else if (key_name[1] == KE_FOCUSLOST && focus_state)
+	    {
+		did_aucmd = apply_autocmds(EVENT_FOCUSLOST,
+						    NULL, NULL, FALSE, curbuf);
+		did_cursorhold = TRUE;
+		focus_state = FALSE;
+		key_name[1] = (int)KE_IGNORE;
+	    }
+	    if (did_aucmd && (State & (NORMAL | INSERT | TERMINAL)))
+	    {
+		// in case a message was displayed: reposition the cursor
+		setcursor();
+		out_flush();
+	    }
+	}
+#endif
+
 	/*
 	 * Change <xHome> to <Home>, <xUp> to <Up>, etc.
 	 */