Handle DECRQM (Request Mode) escape sequences

The DECRQM [1] escape sequence is a request to the terminal to query the state
of a mode. The terminal replies to this request with a DECRPM [2] escape
sequence, containing the status of the mode flag.

[1] https://vt100.net/docs/vt510-rm/DECRQM.html
[2] https://vt100.net/docs/vt510-rm/DECRPM.html

diff -rup st-0.8.4.orig/st.c st-0.8.4/st.c
--- st-0.8.4.orig/st.c  2020-06-19 11:29:45.000000000 +0200
+++ st-0.8.4/st.c       2020-11-27 01:33:28.572861355 +0100
@@ -1476,17 +1476,17 @@ tsetmode(int priv, int set, int *args, i
                if (priv) {
                        switch (*args) {
                        case 1: /* DECCKM -- Cursor key */
-                               xsetmode(set, MODE_APPCURSOR);
+                               xdomode(priv, *args, set, MODE_APPCURSOR);
                                break;
                        case 5: /* DECSCNM -- Reverse video */
-                               xsetmode(set, MODE_REVERSE);
+                               xdomode(priv, *args, set, MODE_REVERSE);
                                break;
                        case 6: /* DECOM -- Origin */
-                               MODBIT(term.c.state, set, CURSOR_ORIGIN);
+                               DOBIT(priv, *args, term.c.state, set, 
CURSOR_ORIGIN);
                                tmoveato(0, 0);
                                break;
                        case 7: /* DECAWM -- Auto wrap */
-                               MODBIT(term.mode, set, MODE_WRAP);
+                               DOBIT(priv, *args, term.mode, set, MODE_WRAP);
                                break;
                        case 0:  /* Error (IGNORED) */
                        case 2:  /* DECANM -- ANSI/VT52 (IGNORED) */
@@ -1497,46 +1497,71 @@ tsetmode(int priv, int set, int *args, i
                        case 19: /* DECPEX -- Printer extent (IGNORED) */
                        case 42: /* DECNRCM -- National characters (IGNORED) */
                        case 12: /* att610 -- Start blinking cursor (IGNORED) */
+                               if (set & 2) decrpm(priv, *args, 0);
                                break;
                        case 25: /* DECTCEM -- Text Cursor Enable Mode */
-                               xsetmode(!set, MODE_HIDE);
+                               xdomode(priv, *args, set ^ 1, MODE_HIDE);
                                break;
                        case 9:    /* X10 mouse compatibility mode */
+                               if (set & 2) {
+                                       decrpm(priv, *args, 0);
+                                       break;
+                               }
                                xsetpointermotion(0);
                                xsetmode(0, MODE_MOUSE);
                                xsetmode(set, MODE_MOUSEX10);
                                break;
                        case 1000: /* 1000: report button press */
+                               if (set & 2) {
+                                       decrpm(priv, *args, 0);
+                                       break;
+                               }
                                xsetpointermotion(0);
                                xsetmode(0, MODE_MOUSE);
                                xsetmode(set, MODE_MOUSEBTN);
                                break;
                        case 1002: /* 1002: report motion on button press */
+                               if (set & 2) {
+                                       decrpm(priv, *args, 0);
+                                       break;
+                               }
                                xsetpointermotion(0);
                                xsetmode(0, MODE_MOUSE);
                                xsetmode(set, MODE_MOUSEMOTION);
                                break;
                        case 1003: /* 1003: enable all mouse motions */
+                               if (set & 2) {
+                                       decrpm(priv, *args, 0);
+                                       break;
+                               }
                                xsetpointermotion(set);
                                xsetmode(0, MODE_MOUSE);
                                xsetmode(set, MODE_MOUSEMANY);
                                break;
                        case 1004: /* 1004: send focus events to tty */
-                               xsetmode(set, MODE_FOCUS);
+                               xdomode(priv, *args, set, MODE_FOCUS);
                                break;
                        case 1006: /* 1006: extended reporting mode */
-                               xsetmode(set, MODE_MOUSESGR);
+                               xdomode(priv, *args, set, MODE_MOUSESGR);
                                break;
                        case 1034:
-                               xsetmode(set, MODE_8BIT);
+                               xdomode(priv, *args, set, MODE_8BIT);
                                break;
                        case 1049: /* swap screen & set/restore cursor as xterm 
*/
+                               if (set & 2) {
+                                       decrpm(priv, *args, 
!IS_SET(MODE_ALTSCREEN) + 1);
+                                       break;
+                               }
                                if (!allowaltscreen)
                                        break;
                                tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
                                /* FALLTHROUGH */
                        case 47: /* swap screen */
                        case 1047:
+                               if (set & 2) {
+                                       decrpm(priv, *args, 
!IS_SET(MODE_ALTSCREEN) + 1);
+                                       break;
+                               }
                                if (!allowaltscreen)
                                        break;
                                alt = IS_SET(MODE_ALTSCREEN);
@@ -1550,10 +1575,14 @@ tsetmode(int priv, int set, int *args, i
                                        break;
                                /* FALLTHROUGH */
                        case 1048:
+                               if (set & 2) {
+                                       decrpm(priv, *args, 0);
+                                       break;
+                               }
                                tcursor((set) ? CURSOR_SAVE : CURSOR_LOAD);
                                break;
                        case 2004: /* 2004: bracketed paste mode */
-                               xsetmode(set, MODE_BRCKTPASTE);
+                               xdomode(priv, *args, set, MODE_BRCKTPASTE);
                                break;
                        /* Not implemented mouse modes. See comments there. */
                        case 1001: /* mouse highlight mode; can hang the
@@ -1564,33 +1593,37 @@ tsetmode(int priv, int set, int *args, i
                        case 1015: /* urxvt mangled mouse mode; incompatible
                                      and can be mistaken for other control
                                      codes. */
+                               if (set & 2) decrpm(priv, *args, 0);
                                break;
                        default:
                                fprintf(stderr,
                                        "erresc: unknown private set/reset mode 
%d\n",
                                        *args);
+                               if (set & 2) decrpm(priv, *args, 0);
                                break;
                        }
                } else {
                        switch (*args) {
                        case 0:  /* Error (IGNORED) */
+                               if (set & 2) decrpm(priv, *args, 0);
                                break;
                        case 2:
-                               xsetmode(set, MODE_KBDLOCK);
+                               xdomode(priv, *args, set, MODE_KBDLOCK);
                                break;
                        case 4:  /* IRM -- Insertion-replacement */
-                               MODBIT(term.mode, set, MODE_INSERT);
+                               DOBIT(priv, *args, term.mode, set, MODE_INSERT);
                                break;
                        case 12: /* SRM -- Send/Receive */
-                               MODBIT(term.mode, !set, MODE_ECHO);
+                               DOBIT(priv, *args, term.mode, set ^ 1, 
MODE_ECHO);
                                break;
                        case 20: /* LNM -- Linefeed/new line */
-                               MODBIT(term.mode, set, MODE_CRLF);
+                               DOBIT(priv, *args, term.mode, set, MODE_CRLF);
                                break;
                        default:
                                fprintf(stderr,
                                        "erresc: unknown set/reset mode %d\n",
                                        *args);
+                               if (set & 2) decrpm(priv, *args, 0);
                                break;
                        }
                }
@@ -1806,6 +1839,15 @@ csihandle(void)
                        goto unknown;
                }
                break;
+       case '$':
+               switch (csiescseq.mode[1]) {
+               case 'p': /* DECRQM -- Request Mode - Host To Terminal */
+                       tsetmode(csiescseq.priv, 2, csiescseq.arg, 
csiescseq.narg);
+                       break;
+               default:
+                       goto unknown;
+               }
+               break;
        }
 }
 
@@ -2595,3 +2637,17 @@ redraw(void)
        tfulldirt();
        draw();
 }
+
+void
+decrpm(int priv, int mode, unsigned value)
+{
+       char buf[40], *ptr = buf;
+       int len;
+
+       *ptr++ = 033;
+       *ptr++ = '[';
+       if (priv) *ptr++ = '?';
+       len = snprintf(ptr, sizeof(buf) - (ptr - buf), "%d;%u$y", mode, value);
+       if (len < 0) return;
+       ttywrite(buf, len + 2 + (priv != 0), 0);
+}
diff -rup st-0.8.4.orig/st.h st-0.8.4/st.h
--- st-0.8.4.orig/st.h  2020-06-19 11:29:45.000000000 +0200
+++ st-0.8.4/st.h       2020-11-27 00:58:15.278976407 +0100
@@ -16,6 +16,10 @@
 #define TIMEDIFF(t1, t2)       ((t1.tv_sec-t2.tv_sec)*1000 + \
                                (t1.tv_nsec-t2.tv_nsec)/1E6)
 #define MODBIT(x, set, bit)    ((set) ? ((x) |= (bit)) : ((x) &= ~(bit)))
+#define DOBIT(priv, mode, x, set, bit) (((set) & 2) ? \
+                               decrpm((priv), (mode), ((!((x) & (bit))) ^ 
((set) & 1)) + 1) : \
+                               ((void)MODBIT((x), (set), (bit))) \
+                               )
 
 #define TRUECOLOR(r,g,b)       (1 << 24 | (r) << 16 | (g) << 8 | (b))
 #define IS_TRUECOL(x)          (1 << 24 & (x))
@@ -111,6 +115,8 @@ void *xmalloc(size_t);
 void *xrealloc(void *, size_t);
 char *xstrdup(char *);
 
+void decrpm(int, int, unsigned int);
+
 /* config.h globals */
 extern char *utmp;
 extern char *scroll;
diff -rup st-0.8.4.orig/win.h st-0.8.4/win.h
--- st-0.8.4.orig/win.h 2020-06-19 11:29:45.000000000 +0200
+++ st-0.8.4/win.h      2020-11-27 00:02:20.482159051 +0100
@@ -33,6 +33,7 @@ int xsetcolorname(int, const char *);
 void xsettitle(char *);
 int xsetcursor(int);
 void xsetmode(int, unsigned int);
+void xdomode(int, int, int, unsigned int);
 void xsetpointermotion(int);
 void xsetsel(char *);
 int xstartdraw(void);
diff -rup st-0.8.4.orig/x.c st-0.8.4/x.c
--- st-0.8.4.orig/x.c   2020-06-19 11:29:45.000000000 +0200
+++ st-0.8.4/x.c        2020-11-27 00:34:55.913052592 +0100
@@ -1687,6 +1687,21 @@ xsetmode(int set, unsigned int flags)
                redraw();
 }
 
+void
+xdomode(int priv, int mode, int set, unsigned int flags)
+{
+       switch (set) {
+       case 0:
+       case 1:
+               xsetmode(set, flags);
+               break;
+       case 2:
+       case 3:
+               DOBIT(priv, mode, win.mode, set, flags);
+               break;
+       }
+}
+
 int
 xsetcursor(int cursor)
 {

Reply via email to