diff --git a/patches/st-csi_22_23-0.8.5.diff b/patches/st-csi_22_23-0.8.5.diff
new file mode 100644
index 0000000..c49aa30
--- /dev/null
+++ b/patches/st-csi_22_23-0.8.5.diff
@@ -0,0 +1,208 @@
+From c90af45228c1100377d64ad021fa3f0cff9a1df4 Mon Sep 17 00:00:00 2001
+From: wael <40663@protonmail.com>
+Date: Mon, 11 Apr 2022 21:28:43 +0300
+Subject: [PATCH] [st][patch][csi 22 23] update to 0.8.5
+
+---
+ st.c    | 36 ++++++++++++++++++++++++++++++++----
+ st.info |  4 ++--
+ win.h   |  4 +++-
+ x.c     | 41 ++++++++++++++++++++++++++++++++++++++---
+ 4 files changed, 75 insertions(+), 10 deletions(-)
+
+diff --git a/st.c b/st.c
+index f43cfd3..2802381 100644
+--- a/st.c
++++ b/st.c
+@@ -1801,6 +1801,33 @@ csihandle(void)
+ 			goto unknown;
+ 		}
+ 		break;
++	case 't': /* title stack operations */
++		switch (csiescseq.arg[0]) {
++		case 22: /* pust current title on stack */
++			switch (csiescseq.arg[1]) {
++			case 0:
++			case 1:
++			case 2:
++				xpushtitle();
++				break;
++			default:
++				goto unknown;
++			}
++			break;
++		case 23: /* pop last title from stack */
++			switch (csiescseq.arg[1]) {
++			case 0:
++			case 1:
++			case 2:
++				xsettitle(NULL, 1);
++				break;
++			default:
++				goto unknown;
++			}
++			break;
++		default:
++			goto unknown;
++		}
+ 	}
+ }
+ 
+@@ -1885,7 +1912,7 @@ strhandle(void)
+ 		switch (par) {
+ 		case 0:
+ 			if (narg > 1) {
+-				xsettitle(strescseq.args[1]);
++				xsettitle(strescseq.args[1], 0);
+ 				xseticontitle(strescseq.args[1]);
+ 			}
+ 			return;
+@@ -1895,7 +1922,7 @@ strhandle(void)
+ 			return;
+ 		case 2:
+ 			if (narg > 1)
+-				xsettitle(strescseq.args[1]);
++				xsettitle(strescseq.args[1], 0);
+ 			return;
+ 		case 52:
+ 			if (narg > 2 && allowwindowops) {
+@@ -1973,7 +2000,7 @@ strhandle(void)
+ 		}
+ 		break;
+ 	case 'k': /* old title set compatibility */
+-		xsettitle(strescseq.args[0]);
++		xsettitle(strescseq.args[0], 0);
+ 		return;
+ 	case 'P': /* DCS -- Device Control String */
+ 	case '_': /* APC -- Application Program Command */
+@@ -2345,6 +2372,7 @@ eschandle(uchar ascii)
+ 		break;
+ 	case 'c': /* RIS -- Reset to initial state */
+ 		treset();
++		xfreetitlestack();
+ 		resettitle();
+ 		xloadcols();
+ 		break;
+@@ -2631,7 +2659,7 @@ tresize(int col, int row)
+ void
+ resettitle(void)
+ {
+-	xsettitle(NULL);
++	xsettitle(NULL, 0);
+ }
+ 
+ void
+diff --git a/st.info b/st.info
+index 8201ad6..aeef606 100644
+--- a/st.info
++++ b/st.info
+@@ -161,7 +161,7 @@ st-mono| simpleterm monocolor,
+ 	rin=\E[%p1%dT,
+ 	ritm=\E[23m,
+ 	rmacs=\E(B,
+-	rmcup=\E[?1049l,
++	rmcup=\E[?1049l\E[23;0;0t,
+ 	rmir=\E[4l,
+ 	rmkx=\E[?1l\E>,
+ 	rmso=\E[27m,
+@@ -172,7 +172,7 @@ st-mono| simpleterm monocolor,
+ 	sitm=\E[3m,
+ 	sgr0=\E[0m,
+ 	smacs=\E(0,
+-	smcup=\E[?1049h,
++	smcup=\E[?1049h\E[22;0;0t,
+ 	smir=\E[4h,
+ 	smkx=\E[?1h\E=,
+ 	smso=\E[7m,
+diff --git a/win.h b/win.h
+index e6e4369..ef67fd6 100644
+--- a/win.h
++++ b/win.h
+@@ -31,7 +31,9 @@ void xfinishdraw(void);
+ void xloadcols(void);
+ int xsetcolorname(int, const char *);
+ void xseticontitle(char *);
+-void xsettitle(char *);
++void xfreetitlestack(void);
++void xsettitle(char *, int);
++void xpushtitle(void);
+ int xsetcursor(int);
+ void xsetmode(int, unsigned int);
+ void xsetpointermotion(int);
+diff --git a/x.c b/x.c
+index 2a3bd38..babb04c 100644
+--- a/x.c
++++ b/x.c
+@@ -63,6 +63,9 @@ static void ttysend(const Arg *);
+ /* config.h for applying patches and the configuration. */
+ #include "config.h"
+ 
++/* size of title stack */
++#define TITLESTACKSIZE 8
++
+ /* XEMBED messages */
+ #define XEMBED_FOCUS_IN  4
+ #define XEMBED_FOCUS_OUT 5
+@@ -220,6 +223,8 @@ static DC dc;
+ static XWindow xw;
+ static XSelection xsel;
+ static TermWindow win;
++static int tstki; /* title stack index */
++static char *titlestack[TITLESTACKSIZE]; /* title stack */
+ 
+ /* Font Ring Cache */
+ enum {
+@@ -1626,10 +1631,30 @@ xseticontitle(char *p)
+ }
+ 
+ void
+-xsettitle(char *p)
++xfreetitlestack(void)
+ {
+-	XTextProperty prop;
+-	DEFAULT(p, opt_title);
++	for (int i = 0; i < LEN(titlestack); i++) {
++		free(titlestack[i]);
++		titlestack[i] = NULL;
++	}
++}
++
++void
++xsettitle(char *p, int pop)
++{
++ 	XTextProperty prop;
++ 
++	free(titlestack[tstki]);
++	if (pop) {
++		titlestack[tstki] = NULL;
++		tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
++		p = titlestack[tstki] ? titlestack[tstki] : opt_title;
++	} else if (p) {
++		titlestack[tstki] = xstrdup(p);
++	} else {
++		titlestack[tstki] = NULL;
++		p = opt_title;
++	}
+ 
+ 	if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
+ 	                                &prop) != Success)
+@@ -1639,6 +1664,16 @@ xsettitle(char *p)
+ 	XFree(prop.value);
+ }
+ 
++void
++xpushtitle(void)
++{
++	int tstkin = (tstki + 1) % TITLESTACKSIZE;
++
++	free(titlestack[tstkin]);
++	titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
++	tstki = tstkin;
++}
++
+ int
+ xstartdraw(void)
+ {
+-- 
+2.35.1
+
diff --git a/st.c b/st.c
index 3d8571b..6ec4e15 100644
--- a/st.c
+++ b/st.c
@@ -1861,6 +1861,33 @@ csihandle(void)
 			goto unknown;
 		}
 		break;
+	case 't': /* title stack operations */
+		switch (csiescseq.arg[0]) {
+		case 22: /* pust current title on stack */
+			switch (csiescseq.arg[1]) {
+			case 0:
+			case 1:
+			case 2:
+				xpushtitle();
+				break;
+			default:
+				goto unknown;
+			}
+			break;
+		case 23: /* pop last title from stack */
+			switch (csiescseq.arg[1]) {
+			case 0:
+			case 1:
+			case 2:
+				xsettitle(NULL, 1);
+				break;
+			default:
+				goto unknown;
+			}
+			break;
+		default:
+			goto unknown;
+		}
 	}
 }
 
@@ -1939,7 +1966,7 @@ strhandle(void)
 		switch (par) {
 		case 0:
 			if (narg > 1) {
-				xsettitle(strescseq.args[1]);
+				xsettitle(strescseq.args[1], 0);
 				xseticontitle(strescseq.args[1]);
 			}
 			return;
@@ -1949,7 +1976,7 @@ strhandle(void)
 			return;
 		case 2:
 			if (narg > 1)
-				xsettitle(strescseq.args[1]);
+				xsettitle(strescseq.args[1], 0);
 			return;
 		case 52:
 			if (narg > 2 && allowwindowops) {
@@ -2008,7 +2035,7 @@ strhandle(void)
 		}
 		break;
 	case 'k': /* old title set compatibility */
-		xsettitle(strescseq.args[0]);
+		xsettitle(strescseq.args[0], 0);
 		return;
 	case 'P': /* DCS -- Device Control String */
 	case '_': /* APC -- Application Program Command */
@@ -2380,6 +2407,7 @@ eschandle(uchar ascii)
 		break;
 	case 'c': /* RIS -- Reset to initial state */
 		treset();
+		xfreetitlestack();
 		resettitle();
 		xloadcols();
 		break;
@@ -2669,7 +2697,7 @@ tresize(int col, int row)
 void
 resettitle(void)
 {
-	xsettitle(NULL);
+	xsettitle(NULL, 0);
 }
 
 void
diff --git a/st.info b/st.info
index 659878c..c3bfbb1 100644
--- a/st.info
+++ b/st.info
@@ -162,7 +162,7 @@ st-mono| simpleterm monocolor,
 	rin=\E[%p1%dT,
 	ritm=\E[23m,
 	rmacs=\E(B,
-	rmcup=\E[?1049l,
+	rmcup=\E[?1049l\E[23;0;0t,
 	rmir=\E[4l,
 	rmkx=\E[?1l\E>,
 	rmso=\E[27m,
@@ -173,7 +173,7 @@ st-mono| simpleterm monocolor,
 	sitm=\E[3m,
 	sgr0=\E[0m,
 	smacs=\E(0,
-	smcup=\E[?1049h,
+	smcup=\E[?1049h\E[22;0;0t,
 	smir=\E[4h,
 	smkx=\E[?1h\E=,
 	smso=\E[7m,
diff --git a/win.h b/win.h
index 94679e4..8712eea 100644
--- a/win.h
+++ b/win.h
@@ -32,7 +32,9 @@ void xloadcols(void);
 int xsetcolorname(int, const char *);
 int xgetcolor(int, unsigned char *, unsigned char *, unsigned char *);
 void xseticontitle(char *);
-void xsettitle(char *);
+void xfreetitlestack(void);
+void xsettitle(char *, int);
+void xpushtitle(void);
 int xsetcursor(int);
 void xsetmode(int, unsigned int);
 void xsetpointermotion(int);
diff --git a/x.c b/x.c
index 36cd910..4265784 100644
--- a/x.c
+++ b/x.c
@@ -72,6 +72,9 @@ static void ttysend(const Arg *);
 /* config.h for applying patches and the configuration. */
 #include "config.h"
 
+/* size of title stack */
+#define TITLESTACKSIZE 8
+
 /* XEMBED messages */
 #define XEMBED_FOCUS_IN  4
 #define XEMBED_FOCUS_OUT 5
@@ -231,6 +234,8 @@ static DC dc;
 static XWindow xw;
 static XSelection xsel;
 static TermWindow win;
+static int tstki; /* title stack index */
+static char *titlestack[TITLESTACKSIZE]; /* title stack */
 
 /* Font Ring Cache */
 enum {
@@ -2110,10 +2115,30 @@ xseticontitle(char *p)
 }
 
 void
-xsettitle(char *p)
+xfreetitlestack(void)
 {
-	XTextProperty prop;
-	DEFAULT(p, opt_title);
+	for (int i = 0; i < LEN(titlestack); i++) {
+		free(titlestack[i]);
+		titlestack[i] = NULL;
+	}
+}
+
+void
+xsettitle(char *p, int pop)
+{
+ 	XTextProperty prop;
+ 
+	free(titlestack[tstki]);
+	if (pop) {
+		titlestack[tstki] = NULL;
+		tstki = (tstki - 1 + TITLESTACKSIZE) % TITLESTACKSIZE;
+		p = titlestack[tstki] ? titlestack[tstki] : opt_title;
+	} else if (p) {
+		titlestack[tstki] = xstrdup(p);
+	} else {
+		titlestack[tstki] = NULL;
+		p = opt_title;
+	}
 
 	if (Xutf8TextListToTextProperty(xw.dpy, &p, 1, XUTF8StringStyle,
 	                                &prop) != Success)
@@ -2123,6 +2148,16 @@ xsettitle(char *p)
 	XFree(prop.value);
 }
 
+void
+xpushtitle(void)
+{
+	int tstkin = (tstki + 1) % TITLESTACKSIZE;
+
+	free(titlestack[tstkin]);
+	titlestack[tstkin] = titlestack[tstki] ? xstrdup(titlestack[tstki]) : NULL;
+	tstki = tstkin;
+}
+
 int
 xstartdraw(void)
 {