set _NET_WM_USER_TIME on the window
[dana/urxvt.git] / src / command.C
index 72ce796..78fa3b5 100644 (file)
@@ -164,12 +164,9 @@ void
 rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y)
 {
   rxvt_fontset *fs = FONTSET (r);
-  rxvt_font *f = (*fs)[fs->find_font (ch)];
-  wchar_t *chr, *alloc, ch2, *fname;
+  wchar_t *chr, *alloc, ch2, **fname;
   int len;
 
-  fname = rxvt_utf8towcs (f->name);
-
 # if ENABLE_COMBINING
   if (IS_COMPOSE (ch))
     {
@@ -199,7 +196,14 @@ rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y)
            r & RS_Uline   ? " uline"   : "",
            r & RS_Careful ? " careful" : "");
 
-  int width = wcswidth (fname, wcslen (fname));
+  int width = 0;
+  fname = rxvt_temp_buf<wchar_t *> (len);
+  for (int i = 0; i < len; i++)
+    {
+      rxvt_font *f = (*fs)[fs->find_font_idx (chr[i])];
+      fname[i] = rxvt_utf8towcs (f->name);
+      max_it (width, wcswidth (fname[i], wcslen (fname[i])));
+    }
 
   max_it (width, 8+5); // for char + hex
   max_it (width, strlen (attr));
@@ -210,7 +214,7 @@ rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y)
       x = 0;
     }
 
-  scr_overlay_new (x, y, width, len + 2);
+  scr_overlay_new (x, y, width, len * 2 + 1);
 
   r = SET_STYLE (OVERLAY_RSTYLE, GET_STYLE (r));
 
@@ -239,9 +243,11 @@ rxvt_term::iso14755_51 (unicode_t ch, rend_t r, int x, int y)
 //    scr_overlay_set (0, 0, buf);
 //  }
   scr_overlay_set (0, len    , attr);
-  scr_overlay_set (0, len + 1, fname);
-
-  free (fname);
+  for (int i = 0; i < len; i++)
+    {
+      scr_overlay_set (0, len + 1 + i, fname[i]);
+      free (fname[i]);
+    }
 
 # if ENABLE_COMBINING
   if (alloc)
@@ -281,10 +287,10 @@ rxvt_term::commit_iso14755 ()
   iso14755buf = 0;
 }
 
-int
-rxvt_term::hex_keyval (XKeyEvent &ev)
+static int
+hex_keyval (XKeyEvent &ev)
 {
-  // check wether this event corresponds to a hex digit
+  // check whether this event corresponds to a hex digit
   // if the modifiers had not been pressed.
   for (int index = 0; index < 8; index++)
     {
@@ -300,11 +306,112 @@ rxvt_term::hex_keyval (XKeyEvent &ev)
 }
 #endif
 
+static inline KeySym
+translate_keypad (KeySym keysym, bool kp)
+{
+#ifdef XK_KP_Home
+  static const KeySym keypadtrans[] = {
+    XK_KP_7, // XK_KP_Home
+    XK_KP_4, // XK_KP_Left
+    XK_KP_8, // XK_KP_Up
+    XK_KP_6, // XK_KP_Right
+    XK_KP_2, // XK_KP_Down
+# ifndef UNSHIFTED_SCROLLKEYS
+    XK_KP_9, // XK_KP_Prior
+    XK_KP_3, // XK_KP_Next
+# else
+    XK_Prior,
+    XK_Next,
+# endif
+    XK_KP_1, // XK_KP_End
+    XK_KP_5, // XK_KP_Begin
+  };
+
+  if (IN_RANGE_INC (keysym, XK_KP_Home, XK_KP_Begin))
+    {
+      unsigned int index = keysym - XK_KP_Home;
+      keysym = kp ? keypadtrans[index] : XK_Home + index;
+    }
+  else if (keysym == XK_KP_Insert)
+    keysym = kp ? XK_KP_0 : XK_Insert;
+# ifndef NO_DELETE_KEY
+  else if (keysym == XK_KP_Delete)
+    keysym = kp ? XK_KP_Decimal : XK_Delete;
+# endif
+#endif
+  return keysym;
+}
+
+static inline int
+map_function_key (KeySym keysym)
+{
+  int param = 0;
+
+  if (IN_RANGE_INC (keysym, XK_F1, XK_F35))
+    {
+      param = 11 + keysym - XK_F1;
+      if (keysym >= XK_F17)
+        param += 4;
+      else if (keysym >= XK_F15)
+        param += 3;
+      else if (keysym >= XK_F11)
+        param += 2;
+      else if (keysym >= XK_F6)
+        param += 1;
+    }
+  else
+    switch (keysym)
+      {
+        case XK_Find:
+          param = 1;
+          break;
+        case XK_Insert:
+          param = 2;
+          break;
+#ifdef DXK_Remove
+        case DXK_Remove:
+#endif
+        case XK_Execute:
+          param = 3;
+          break;
+        case XK_Select:
+          param = 4;
+          break;
+#ifndef UNSHIFTED_SCROLLKEYS
+        case XK_Prior:
+          param = 5;
+          break;
+        case XK_Next:
+          param = 6;
+          break;
+        case XK_Home:
+          param = 7;
+          break;
+        case XK_End:
+          param = 8;
+          break;
+#endif
+        case XK_Help:
+          param = 28;
+          break;
+        case XK_Menu:
+          param = 29;
+          break;
+      }
+  return param;
+}
+
+void
+rxvt_term::update_user_time (Time time)
+{
+  XChangeProperty (dpy, parent[0], xa[XA_NET_WM_USER_TIME], XA_CARDINAL,
+                   32, PropModeReplace, (unsigned char*)&time, 1);
+}
+
 void
 rxvt_term::key_press (XKeyEvent &ev)
 {
   int ctrl, meta, shft, len;
-  unsigned int newlen;
   KeySym keysym;
   int valid_keysym;
   char kbuf[KBUFSZ];
@@ -324,12 +431,6 @@ rxvt_term::key_press (XKeyEvent &ev)
   ctrl = ev.state & ControlMask;
   meta = ev.state & ModMetaMask;
 
-  if (numlock_state || (ev.state & ModNumLockMask))
-    {
-      numlock_state = (ev.state & ModNumLockMask);
-      PrivMode ((!numlock_state), PrivMode_aplKP);
-    }
-
   kbuf[0] = 0;
 
 #ifdef USE_XIM
@@ -413,6 +514,8 @@ rxvt_term::key_press (XKeyEvent &ev)
 #else
               lnsppg = nrow * 4 / 5;
 #endif
+              max_it (lnsppg, 1);
+
               if (keysym == XK_Prior)
                 {
                   scr_page (UP, lnsppg);
@@ -487,7 +590,7 @@ rxvt_term::key_press (XKeyEvent &ev)
 
 #if ENABLE_FRILLS || ISO_14755
       // ISO 14755 support
-      if (shft && ctrl)
+      if (iso14755buf & (ISO_14755_STARTED | ISO_14755_51))
         {
           int hv;
 
@@ -502,6 +605,24 @@ rxvt_term::key_press (XKeyEvent &ev)
 # endif
               return;
             }
+          else if (keysym == XK_C)
+            {
+              selection_make (ev.time, true);
+# if ISO_14755
+              scr_overlay_off ();
+# endif
+              iso14755buf = 0;
+              return;
+            }
+          else if (keysym == XK_V)
+            {
+              selection_request (ev.time, Sel_Clipboard);
+# if ISO_14755
+              scr_overlay_off ();
+# endif
+              iso14755buf = 0;
+              return;
+            }
           else if (keysym == XK_BackSpace)
             {
               iso14755buf = ((iso14755buf & ISO_14755_MASK) >> 4) | ISO_14755_51;
@@ -527,8 +648,9 @@ rxvt_term::key_press (XKeyEvent &ev)
               iso14755buf = 0;
             }
         }
-      else if ((ctrl && (keysym == XK_Shift_L || keysym == XK_Shift_R))
-               || (shft && (keysym == XK_Control_L || keysym == XK_Control_R)))
+      else if (option (Opt_iso14755) &&
+               ((ctrl && (keysym == XK_Shift_L || keysym == XK_Shift_R))
+                || (shft && (keysym == XK_Control_L || keysym == XK_Control_R))))
         if (!(iso14755buf & ISO_14755_STARTED))
           {
             iso14755buf |= ISO_14755_STARTED;
@@ -549,250 +671,143 @@ rxvt_term::key_press (XKeyEvent &ev)
 
       if (keysym >= 0xFF00 && keysym <= 0xFFFF)
         {
-            {
-              bool kp = priv_modes & PrivMode_aplKP ? !shft : shft;
-              newlen = 1;
-#ifdef XK_KP_Home
-              static const KeySym keypadtrans[] = {
-                XK_KP_7, // XK_KP_Home
-                XK_KP_4, // XK_KP_Left
-                XK_KP_8, // XK_KP_Up
-                XK_KP_6, // XK_KP_Right
-                XK_KP_2, // XK_KP_Down
-#ifndef UNSHIFTED_SCROLLKEYS
-                XK_KP_9, // XK_KP_Prior
-                XK_KP_3, // XK_KP_Next
-#else
-                XK_Prior,
-                XK_Next,
-#endif
-                XK_KP_1, // XK_KP_End
-                XK_KP_5, // XK_KP_Begin
-              };
+          bool kp = priv_modes & PrivMode_aplKP ? !shft : shft;
+          unsigned int newlen = 1;
 
-              if (IN_RANGE_INC (keysym, XK_KP_Home, XK_KP_Begin))
-                {
-                  unsigned int index = keysym - XK_KP_Home;
-                  keysym = kp ? keypadtrans[index] : XK_Home + index;
-                }
-              else if (keysym == XK_KP_Insert)
-                keysym = kp ? XK_KP_0 : XK_Insert;
-#ifndef NO_DELETE_KEY
-              else if (keysym == XK_KP_Delete)
-                keysym = kp ? XK_KP_Decimal : XK_Delete;
-#endif
-#endif
-              switch (keysym)
-                {
+          if (ev.state & ModNumLockMask)
+            kp = false;
+
+          keysym = translate_keypad (keysym, kp);
+
+          switch (keysym)
+            {
 #ifndef NO_BACKSPACE_KEY
-                  case XK_BackSpace:
-                    if (priv_modes & PrivMode_HaveBackSpace)
-                      {
-                        kbuf[0] = (!! (priv_modes & PrivMode_BackSpace)
-                                   ^ !!ctrl) ? '\b' : '\177';
-                        kbuf[1] = '\0';
-                      }
-                    else
-                      strcpy (kbuf, rs[Rs_backspace_key]);
-                    break;
+              case XK_BackSpace:
+                if (priv_modes & PrivMode_HaveBackSpace)
+                  {
+                    kbuf[0] = (!! (priv_modes & PrivMode_BackSpace)
+                               ^ !!ctrl) ? '\b' : '\177';
+                    kbuf[1] = '\0';
+                  }
+                else
+                  strcpy (kbuf, rs[Rs_backspace_key]);
+                break;
 #endif
 #ifndef NO_DELETE_KEY
-                  case XK_Delete:
-                    strcpy (kbuf, rs[Rs_delete_key]);
-                    break;
+              case XK_Delete:
+                strcpy (kbuf, rs[Rs_delete_key]);
+                break;
 #endif
-                  case XK_Tab:
-                    if (shft)
-                      strcpy (kbuf, "\033[Z");
-                    else
-                      {
+              case XK_Tab:
+                if (shft)
+                  strcpy (kbuf, "\033[Z");
+                else
+                  {
 #ifdef CTRL_TAB_MAKES_META
-                        if (ctrl)
-                          meta = 1;
+                    if (ctrl)
+                      meta = 1;
 #endif
 #ifdef MOD4_TAB_MAKES_META
-                        if (ev.state & Mod4Mask)
-                          meta = 1;
+                    if (ev.state & Mod4Mask)
+                      meta = 1;
 #endif
-                        newlen = 0;
-                      }
-                    break;
-
-                  case XK_Up:  /* "\033[A" */
-                  case XK_Down:        /* "\033[B" */
-                  case XK_Right:       /* "\033[C" */
-                  case XK_Left:        /* "\033[D" */
-                    strcpy (kbuf, "\033[Z");
-                    kbuf[2] = "DACB"[keysym - XK_Left];
-                    /* do Shift first */
-                    if (shft)
-                      kbuf[2] = "dacb"[keysym - XK_Left];
-                    else if (ctrl)
-                      {
-                        kbuf[1] = 'O';
-                        kbuf[2] = "dacb"[keysym - XK_Left];
-                      }
-                    else if (priv_modes & PrivMode_aplCUR)
-                      kbuf[1] = 'O';
-                    break;
-
-#ifndef UNSHIFTED_SCROLLKEYS
-                  case XK_Prior:
-                    strcpy (kbuf, "\033[5~");
-                    break;
-                  case XK_Next:
-                    strcpy (kbuf, "\033[6~");
-                    break;
-#endif
-                  case XK_KP_Enter:
-                    /* allow shift to override */
-                    if (kp)
-                      {
-                        strcpy (kbuf, "\033OM");
-                        break;
-                      }
-
-                    /* FALLTHROUGH */
+                    newlen = 0;
+                  }
+                break;
 
-                  case XK_Return:
-                    if (priv_modes & PrivMode_LFNL)
-                      {
-                        kbuf[0] = '\015';
-                        kbuf[1] = '\012';
-                        kbuf[2] = '\0';
-                      }
-                    else
-                      {
-                        kbuf[0] = '\015';
-                        kbuf[1] = '\0';
-                      }
-                    break;
+              case XK_Up:      /* "\033[A" */
+              case XK_Down:    /* "\033[B" */
+              case XK_Right:   /* "\033[C" */
+              case XK_Left:    /* "\033[D" */
+                strcpy (kbuf, "\033[Z");
+                kbuf[2] = "DACB"[keysym - XK_Left];
+                /* do Shift first */
+                if (shft)
+                  kbuf[2] = "dacb"[keysym - XK_Left];
+                else if (ctrl)
+                  {
+                    kbuf[1] = 'O';
+                    kbuf[2] = "dacb"[keysym - XK_Left];
+                  }
+                else if (priv_modes & PrivMode_aplCUR)
+                  kbuf[1] = 'O';
+                break;
 
-                  case XK_KP_F1:       /* "\033OP" */
-                  case XK_KP_F2:       /* "\033OQ" */
-                  case XK_KP_F3:       /* "\033OR" */
-                  case XK_KP_F4:       /* "\033OS" */
-                    strcpy (kbuf, "\033OP");
-                    kbuf[2] += (keysym - XK_KP_F1);
+              case XK_KP_Enter:
+                /* allow shift to override */
+                if (kp)
+                  {
+                    strcpy (kbuf, "\033OM");
                     break;
+                  }
 
-                  case XK_KP_Multiply: /* "\033Oj" : "*" */
-                  case XK_KP_Add:      /* "\033Ok" : "+" */
-                  case XK_KP_Separator:        /* "\033Ol" : "," */
-                  case XK_KP_Subtract: /* "\033Om" : "-" */
-                  case XK_KP_Decimal:  /* "\033On" : "." */
-                  case XK_KP_Divide:   /* "\033Oo" : "/" */
-                  case XK_KP_0:                /* "\033Op" : "0" */
-                  case XK_KP_1:                /* "\033Oq" : "1" */
-                  case XK_KP_2:                /* "\033Or" : "2" */
-                  case XK_KP_3:                /* "\033Os" : "3" */
-                  case XK_KP_4:                /* "\033Ot" : "4" */
-                  case XK_KP_5:                /* "\033Ou" : "5" */
-                  case XK_KP_6:                /* "\033Ov" : "6" */
-                  case XK_KP_7:                /* "\033Ow" : "7" */
-                  case XK_KP_8:                /* "\033Ox" : "8" */
-                  case XK_KP_9:                /* "\033Oy" : "9" */
-                    /* allow shift to override */
-                    if (kp)
-                      {
-                        strcpy (kbuf, "\033Oj");
-                        kbuf[2] += (keysym - XK_KP_Multiply);
-                      }
-                    else
-                      {
-                        kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
-                        kbuf[1] = '\0';
-                      }
-                    break;
+                /* FALLTHROUGH */
 
-                  case XK_Find:
-                    strcpy (kbuf, "\033[1~");
-                    break;
+              case XK_Return:
+                if (priv_modes & PrivMode_LFNL)
+                  {
+                    kbuf[0] = '\015';
+                    kbuf[1] = '\012';
+                    kbuf[2] = '\0';
+                  }
+                else
+                  {
+                    kbuf[0] = '\015';
+                    kbuf[1] = '\0';
+                  }
+                break;
 
-                  case XK_Insert:
-                    strcpy (kbuf, "\033[2~");
-                    break;
-#ifdef DXK_Remove              /* support for DEC remove like key */
-                  case DXK_Remove:
-                    /* FALLTHROUGH */
-#endif
-                  case XK_Execute:
-                    strcpy (kbuf, "\033[3~");
-                    break;
-                  case XK_Select:
-                    strcpy (kbuf, "\033[4~");
-                    break;
-                  case XK_End:
-                    strcpy (kbuf, KS_END);
-                    break;
-                  case XK_Home:
-                    strcpy (kbuf, KS_HOME);
-                    break;
+              case XK_KP_F1:   /* "\033OP" */
+              case XK_KP_F2:   /* "\033OQ" */
+              case XK_KP_F3:   /* "\033OR" */
+              case XK_KP_F4:   /* "\033OS" */
+                strcpy (kbuf, "\033OP");
+                kbuf[2] += (keysym - XK_KP_F1);
+                break;
 
-#define FKEY(n, fkey)                                                  \
-    sprintf ((char *)kbuf,"\033[%2d~", (int) ((n) + (keysym - fkey)))
+              case XK_KP_Multiply:     /* "\033Oj" : "*" */
+              case XK_KP_Add:          /* "\033Ok" : "+" */
+              case XK_KP_Separator:    /* "\033Ol" : "," */
+              case XK_KP_Subtract:     /* "\033Om" : "-" */
+              case XK_KP_Decimal:      /* "\033On" : "." */
+              case XK_KP_Divide:       /* "\033Oo" : "/" */
+              case XK_KP_0:            /* "\033Op" : "0" */
+              case XK_KP_1:            /* "\033Oq" : "1" */
+              case XK_KP_2:            /* "\033Or" : "2" */
+              case XK_KP_3:            /* "\033Os" : "3" */
+              case XK_KP_4:            /* "\033Ot" : "4" */
+              case XK_KP_5:            /* "\033Ou" : "5" */
+              case XK_KP_6:            /* "\033Ov" : "6" */
+              case XK_KP_7:            /* "\033Ow" : "7" */
+              case XK_KP_8:            /* "\033Ox" : "8" */
+              case XK_KP_9:            /* "\033Oy" : "9" */
+                /* allow shift to override */
+                if (kp)
+                  {
+                    strcpy (kbuf, "\033Oj");
+                    kbuf[2] += (keysym - XK_KP_Multiply);
+                  }
+                else
+                  {
+                    kbuf[0] = ('*' + (keysym - XK_KP_Multiply));
+                    kbuf[1] = '\0';
+                  }
+                break;
 
-                  case XK_F1:  /* "\033[11~" */
-                  case XK_F2:  /* "\033[12~" */
-                  case XK_F3:  /* "\033[13~" */
-                  case XK_F4:  /* "\033[14~" */
-                  case XK_F5:  /* "\033[15~" */
-                    FKEY (11, XK_F1);
-                    break;
-                  case XK_F6:  /* "\033[17~" */
-                  case XK_F7:  /* "\033[18~" */
-                  case XK_F8:  /* "\033[19~" */
-                  case XK_F9:  /* "\033[20~" */
-                  case XK_F10: /* "\033[21~" */
-                    FKEY (17, XK_F6);
-                    break;
-                  case XK_F11: /* "\033[23~" */
-                  case XK_F12: /* "\033[24~" */
-                  case XK_F13: /* "\033[25~" */
-                  case XK_F14: /* "\033[26~" */
-                    FKEY (23, XK_F11);
-                    break;
-                  case XK_F15: /* "\033[28~" */
-                  case XK_F16: /* "\033[29~" */
-                    FKEY (28, XK_F15);
-                    break;
-                  case XK_Help:        /* "\033[28~" */
-                    FKEY (28, XK_Help);
-                    break;
-                  case XK_Menu:        /* "\033[29~" */
-                    FKEY (29, XK_Menu);
-                    break;
-                  case XK_F17: /* "\033[31~" */
-                  case XK_F18: /* "\033[32~" */
-                  case XK_F19: /* "\033[33~" */
-                  case XK_F20: /* "\033[34~" */
-                  case XK_F21: /* "\033[35~" */
-                  case XK_F22: /* "\033[36~" */
-                  case XK_F23: /* "\033[37~" */
-                  case XK_F24: /* "\033[38~" */
-                  case XK_F25: /* "\033[39~" */
-                  case XK_F26: /* "\033[40~" */
-                  case XK_F27: /* "\033[41~" */
-                  case XK_F28: /* "\033[42~" */
-                  case XK_F29: /* "\033[43~" */
-                  case XK_F30: /* "\033[44~" */
-                  case XK_F31: /* "\033[45~" */
-                  case XK_F32: /* "\033[46~" */
-                  case XK_F33: /* "\033[47~" */
-                  case XK_F34: /* "\033[48~" */
-                  case XK_F35: /* "\033[49~" */
-                    FKEY (31, XK_F17);
-                    break;
-#undef FKEY
-                  default:
+              default:
+                {
+                  int param = map_function_key (keysym);
+                  if (param > 0)
+                    sprintf (kbuf,"\033[%d~", param);
+                  else
                     newlen = 0;
-                    break;
                 }
-
-              if (newlen)
-                len = strlen (kbuf);
+                break;
             }
 
+          if (newlen)
+            len = strlen (kbuf);
+
           /*
            * Pass meta for all function keys, if 'meta' option set
            */
@@ -1035,7 +1050,7 @@ rxvt_term::flush ()
         }
 
       scr_refresh ();
-      scrollbar_show (1);
+      scrollBar.show (1);
 #ifdef USE_XIM
       IMSendSpot ();
 #endif
@@ -1044,7 +1059,7 @@ rxvt_term::flush ()
   display->flush ();
 }
 
-/* checks wether a refresh is requested and starts the refresh timer */
+/* checks whether a refresh is requested and starts the refresh timer */
 void
 rxvt_term::refresh_check ()
 {
@@ -1092,8 +1107,8 @@ rxvt_term::text_blink_cb (ev::timer &w, int revents)
 void
 rxvt_term::cont_scroll_cb (ev::timer &w, int revents)
 {
-  if ((scrollbar_isUp () || scrollbar_isDn ())
-      && scr_page (scrollbar_isUp () ? UP : DN, 1))
+  if ((scrollBar.state == STATE_UP || scrollBar.state == STATE_DOWN)
+      && scr_page (scrollBar.state == STATE_UP ? UP : DN, 1))
     {
       want_refresh = 1;
       refresh_check ();
@@ -1147,8 +1162,11 @@ static struct event_handler
     // that giving a process calling sched_yield () less cpu time than
     // ones with high nice levels is a useful thing to do. It surely is is
     // allowed by the sus... as is returning ENOSYS.
+    // since the linux guys additionally thought that breaking the only
+    // known workaround against their unusable sched_yield hack is cool,
+    // we just nanosleep a bit and hope for the best.
 
-    struct timespec ts = { 0, 0 };
+    struct timespec ts = { 0, 1000 };
     nanosleep (&ts, 0);
 
     w.stop ();
@@ -1208,9 +1226,8 @@ rxvt_term::pty_cb (ev::io &w, int revents)
 
   if (revents & ev::READ)
     // loop, but don't allow a single term to monopolize us
-    while (pty_fill ())
-      if (cmd_parse ())
-        break;
+    for (int i = CBUFCNT; i-- && pty_fill (); )
+      cmd_parse ();
 
   if (revents & ev::WRITE)
     pty_write ();
@@ -1352,6 +1369,7 @@ rxvt_term::x_cb (XEvent &ev)
   switch (ev.type)
     {
       case KeyPress:
+        update_user_time (ev.xkey.time);
         key_press (ev.xkey);
         break;
 
@@ -1360,6 +1378,7 @@ rxvt_term::x_cb (XEvent &ev)
         break;
 
       case ButtonPress:
+        update_user_time (ev.xbutton.time);
         button_press (ev.xbutton);
         break;
 
@@ -1440,9 +1459,9 @@ rxvt_term::x_cb (XEvent &ev)
         break;
 
       case ConfigureNotify:
-      /* fprintf (stderr, "ConfigureNotify for %X, parent is %X, geom is %dx%d%+d%+d, old geom was %dx%d\n",
+        /*fprintf (stderr, "ConfigureNotify for %X, parent is %X, geom is %dx%d%+d%+d, old geom was %dx%d\n",
               ev.xconfigure.window, parent[0], ev.xconfigure.width, ev.xconfigure.height, ev.xconfigure.x, ev.xconfigure.y,
-              szHint.width, szHint.height); */
+              szHint.width, szHint.height);*/
         if (ev.xconfigure.window == parent[0])
           {
             while (XCheckTypedWindowEvent (dpy, ev.xconfigure.window, ConfigureNotify, &ev))
@@ -1457,7 +1476,12 @@ rxvt_term::x_cb (XEvent &ev)
               {
 #ifdef HAVE_BG_PIXMAP
                 if (bgPixmap.window_position_sensitive ())
-                  update_background ();
+                  {
+                    if (mapped)
+                      update_background ();
+                    else
+                      bgPixmap.invalidate ();
+                  }
 #endif
               }
 
@@ -1474,7 +1498,7 @@ rxvt_term::x_cb (XEvent &ev)
         break;
 
       case SelectionClear:
-        selection_clear ();
+        selection_clear (ev.xselectionclear.selection == xa[XA_CLIPBOARD]);
         break;
 
       case SelectionNotify:
@@ -1487,6 +1511,22 @@ rxvt_term::x_cb (XEvent &ev)
         break;
 
       case MapNotify:
+#ifdef HAVE_BG_PIXMAP
+        /* This is needed spcifically to fix the case of no window manager or a
+         * non-reparenting window manager. In those cases we never get first
+         * ConfigureNotify. Also that speeds startup under normal WM, by taking
+         * care of multiplicity of ConfigureNotify events arriwing while WM does
+         * reparenting.
+         * We should not render background immidiately, as there could be several
+         * ConfigureNotify's to follow. Lets take care of all of them in one scoop
+         * by scheduling background redraw as soon as we can, but giving a short
+         * bit of time for ConfigureNotifies to arrive.
+         * We should render background PRIOR to drawing any text, but AFTER all
+         * of ConfigureNotifys for the best results.
+         */
+        if (bgPixmap.flags & bgPixmap_t::isInvalid)
+          update_background_ev.start (0.025);
+#endif
         mapped = 1;
 #ifdef TEXT_BLINK
         text_blink_ev.start ();
@@ -1534,8 +1574,8 @@ rxvt_term::x_cb (XEvent &ev)
 
             if (scrollBar.state && ev.xany.window == scrollBar.win)
               {
-                scrollBar.setIdle ();
-                scrollbar_show (0);
+                scrollBar.state = STATE_IDLE;
+                scrollBar.show (0);
               }
           }
         break;
@@ -1632,7 +1672,7 @@ rxvt_term::x_cb (XEvent &ev)
 #endif
               }
           }
-        else if (scrollbar_isMotion () && ev.xany.window == scrollBar.win)
+        else if (scrollBar.state == STATE_MOTION && ev.xany.window == scrollBar.win)
           {
             while (XCheckTypedWindowEvent (dpy, scrollBar.win,
                                            MotionNotify, &ev))
@@ -1644,9 +1684,9 @@ rxvt_term::x_cb (XEvent &ev)
                           &ev.xbutton.x, &ev.xbutton.y,
                           &unused_mask);
             scr_move_to (scrollbar_position (ev.xbutton.y) - csrO,
-                         scrollbar_size ());
+                         scrollBar.size ());
             want_refresh = 1;
-            scrollbar_show (1);
+            scrollBar.show (1);
           }
         break;
     }
@@ -1681,6 +1721,22 @@ rxvt_term::x_cb (XEvent &ev)
   refresh_check ();
 }
 
+#if ENABLE_FRILLS
+void
+rxvt_term::set_urgency (bool enable)
+{
+  if (enable == urgency_hint)
+    return;
+
+  if (XWMHints *h = XGetWMHints (dpy, parent[0]))
+    {
+      h->flags = h->flags & ~XUrgencyHint | (enable ? XUrgencyHint : 0);
+      XSetWMHints (dpy, parent[0], h);
+      urgency_hint = enable;
+    }
+}
+#endif
+
 void
 rxvt_term::focus_in ()
 {
@@ -1689,8 +1745,6 @@ rxvt_term::focus_in ()
       focus = 1;
       want_refresh = 1;
 
-      HOOK_INVOKE ((this, HOOK_FOCUS_IN, DT_END));
-
 #if USE_XIM
       if (Input_Context != NULL)
         {
@@ -1711,14 +1765,10 @@ rxvt_term::focus_in ()
 #endif
 #if ENABLE_FRILLS
       if (option (Opt_urgentOnBell))
-        {
-          if (XWMHints *h = XGetWMHints(dpy, parent[0]))
-            {
-              h->flags &= ~XUrgencyHint;
-              XSetWMHints (dpy, parent[0], h);
-            }
-        }
+        set_urgency (0);
 #endif
+
+      HOOK_INVOKE ((this, HOOK_FOCUS_IN, DT_END));
     }
 }
 
@@ -1730,8 +1780,10 @@ rxvt_term::focus_out ()
       focus = 0;
       want_refresh = 1;
 
-      HOOK_INVOKE ((this, HOOK_FOCUS_OUT, DT_END));
-
+#if ENABLE_FRILLS
+      if (option (Opt_urgentOnBell))
+        set_urgency (0);
+#endif
 #if ENABLE_FRILLS || ISO_14755
       if (iso14755buf)
         {
@@ -1758,6 +1810,8 @@ rxvt_term::focus_out ()
           scr_recolour ();
         }
 #endif
+
+      HOOK_INVOKE ((this, HOOK_FOCUS_OUT, DT_END));
     }
 }
 
@@ -1812,6 +1866,8 @@ rxvt_term::button_press (XButtonEvent &ev)
 {
   int reportmode = 0, clickintime;
 
+  button_state[ev.button - Button1] = true;
+
   bypass_keystate = ev.state & (ModMetaMask | ShiftMask);
 
   if (!bypass_keystate)
@@ -1928,7 +1984,14 @@ rxvt_term::button_press (XButtonEvent &ev)
    */
   if (scrollBar.state && ev.window == scrollBar.win)
     {
-      scrollBar.setIdle ();
+      page_dirn direction = NO_DIR;
+
+      if (scrollBar.upButton (ev.y))
+        direction = UP; /* up */
+      else if (scrollBar.dnButton (ev.y))
+        direction = DN;  /* down */
+
+      scrollBar.state = STATE_IDLE;
       /*
        * Rxvt-style scrollbar:
        * move up if mouse is above slider
@@ -1947,15 +2010,9 @@ rxvt_term::button_press (XButtonEvent &ev)
            * arrow buttons - send up/down
            * click on scrollbar - send pageup/down
            */
-          if ((scrollBar.style == R_SB_NEXT
-               && scrollbarnext_upButton (ev.y))
-              || (scrollBar.style == R_SB_RXVT
-                  && scrollbarrxvt_upButton (ev.y)))
+          if (direction == UP)
             tt_printf ("\033[A");
-          else if ((scrollBar.style == R_SB_NEXT
-                    && scrollbarnext_dnButton (ev.y))
-                   || (scrollBar.style == R_SB_RXVT
-                       && scrollbarrxvt_dnButton (ev.y)))
+          else if (direction == DN)
             tt_printf ("\033[B");
           else
             switch (ev.button)
@@ -1973,37 +2030,19 @@ rxvt_term::button_press (XButtonEvent &ev)
         }
       else
 #endif /* NO_SCROLLBAR_REPORT */
-
         {
-          char upordown = 0;
-
-          if (scrollBar.style == R_SB_NEXT)
-            {
-              if (scrollbarnext_upButton (ev.y))
-                upordown = -1; /* up */
-              else if (scrollbarnext_dnButton (ev.y))
-                upordown = 1;  /* down */
-            }
-          else if (scrollBar.style == R_SB_RXVT)
-            {
-              if (scrollbarrxvt_upButton (ev.y))
-                upordown = -1; /* up */
-              else if (scrollbarrxvt_dnButton (ev.y))
-                upordown = 1;  /* down */
-            }
-
-          if (upordown)
+          if (direction != NO_DIR)
             {
 #ifndef NO_SCROLLBAR_BUTTON_CONTINUAL_SCROLLING
               if (!cont_scroll_ev.is_active ())
                 cont_scroll_ev.start (SCROLLBAR_INITIAL_DELAY, SCROLLBAR_CONTINUOUS_DELAY);
 #endif
-              if (scr_page (upordown < 0 ? UP : DN, 1))
+              if (scr_page (direction, 1))
                 {
-                  if (upordown < 0)
-                    scrollBar.setUp ();
+                  if (direction == UP)
+                    scrollBar.state = STATE_UP;
                   else
-                    scrollBar.setDn ();
+                    scrollBar.state = STATE_DOWN;
                 }
             }
           else
@@ -2026,9 +2065,9 @@ rxvt_term::button_press (XButtonEvent &ev)
                   if (scrollBar.style == R_SB_XTERM
                       || scrollbar_above_slider (ev.y)
                       || scrollbar_below_slider (ev.y))
-                    scr_move_to (scrollbar_position (ev.y) - csrO, scrollbar_size ());
+                    scr_move_to (scrollbar_position (ev.y) - csrO, scrollBar.size ());
 
-                  scrollBar.setMotion ();
+                  scrollBar.state = STATE_MOTION;
                   break;
 
                 case Button1:
@@ -2052,14 +2091,14 @@ rxvt_term::button_press (XButtonEvent &ev)
                         scr_page (DN, nrow / 4);
 # endif
                       else
-                        scrollBar.setMotion ();
+                        scrollBar.state = STATE_MOTION;
                     }
                   else
                     {
                       scr_page ((ev.button == Button1 ? DN : UP),
                                 (nrow
                                  * scrollbar_position (ev.y)
-                                 / scrollbar_size ()));
+                                 / scrollBar.size ()));
                     }
 
                   break;
@@ -2075,14 +2114,19 @@ rxvt_term::button_release (XButtonEvent &ev)
 {
   int reportmode = 0;
 
+  if (button_state[ev.button - Button1] == false)
+      return; /* it wasn't pressed so why is it released? */
+
+  button_state[ev.button - Button1] = false;
+
   csrO = 0;            /* reset csr Offset */
   if (!bypass_keystate)
     reportmode = !! (priv_modes & PrivMode_mouse_report);
 
-  if (scrollbar_isUpDn ())
+  if (scrollBar.state == STATE_UP || scrollBar.state == STATE_DOWN)
     {
-      scrollBar.setIdle ();
-      scrollbar_show (0);
+      scrollBar.state = STATE_IDLE;
+      scrollBar.show (0);
     }
 
 #ifdef SELECTION_SCROLLING
@@ -2142,7 +2186,7 @@ rxvt_term::button_release (XButtonEvent &ev)
 
           case Button2:
             if (IN_RANGE_EXC (ev.x, 0, width) && IN_RANGE_EXC (ev.y, 0, height)) // inside window?
-             selection_request (ev.time, ev.state & ModMetaMask ? Sel_Clipboard : Sel_Primary);
+              selection_request (ev.time, ev.state & ModMetaMask ? Sel_Clipboard : Sel_Primary);
             break;
 
 #ifdef MOUSE_WHEEL
@@ -2175,7 +2219,7 @@ rxvt_term::button_release (XButtonEvent &ev)
 # endif
                 {
                   scr_page (v, i);
-                  scrollbar_show (1);
+                  scrollBar.show (1);
                 }
             }
             break;
@@ -2186,16 +2230,15 @@ rxvt_term::button_release (XButtonEvent &ev)
 
 /*}}} */
 
-bool
+void
 rxvt_term::cmd_parse ()
 {
-  bool flag = false;
   wchar_t ch = NOCHAR;
   char *seq_begin; // remember start of esc-sequence here
 
   for (;;)
     {
-      if (ch == NOCHAR)
+      if (expect_false (ch == NOCHAR))
         {
           seq_begin = cmdbuf_ptr;
           ch = next_char ();
@@ -2204,9 +2247,9 @@ rxvt_term::cmd_parse ()
             break;
         }
 
-      if (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT)
+      if (expect_true (!IS_CONTROL (ch) || ch == C0_LF || ch == C0_CR || ch == C0_HT))
         {
-          if (!seen_input)
+          if (expect_false (!seen_input))
             {
               seen_input = 1;
               // many badly-written programs (e.g. jed) contain a race condition:
@@ -2229,12 +2272,12 @@ rxvt_term::cmd_parse ()
 
           for (;;)
             {
-              if (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT))
+              if (expect_false (ch == NOCHAR || (IS_CONTROL (ch) && ch != C0_LF && ch != C0_CR && ch != C0_HT)))
                 break;
 
               *str++ = ch;
 
-              if (ch == C0_LF || str >= eol)
+              if (expect_false (ch == C0_LF || str >= eol))
                 {
                   if (ch == C0_LF)
                     nlines++;
@@ -2293,11 +2336,9 @@ rxvt_term::cmd_parse ()
            */
           if (refreshnow)
             {
-              flag = true;
               scr_refresh ();
               want_refresh = 1;
             }
-
         }
       else
         {
@@ -2315,8 +2356,6 @@ rxvt_term::cmd_parse ()
           ch = NOCHAR;
         }
     }
-
-  return flag;
 }
 
 // read the next character
@@ -2326,7 +2365,7 @@ rxvt_term::next_char () NOTHROW
   while (cmdbuf_ptr < cmdbuf_endp)
     {
       // assume 7-bit to be ascii ALWAYS
-      if ((unsigned char)*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b)
+      if (expect_true ((unsigned char)*cmdbuf_ptr <= 0x7f && *cmdbuf_ptr != 0x1b))
         return *cmdbuf_ptr++;
 
       wchar_t wc;
@@ -2340,7 +2379,10 @@ rxvt_term::next_char () NOTHROW
         }
 
       if (len == (size_t)-1)
-        return (unsigned char)*cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
+        {
+          mbstate.reset (); // reset now undefined conversion state
+          return (unsigned char)*cmdbuf_ptr++; // the _occasional_ latin1 character is allowed to slip through
+        }
 
       // assume wchar == unicode
       cmdbuf_ptr += len;
@@ -2394,7 +2436,7 @@ rxvt_term::cmd_get8 () THROW ((class out_of_input))
 FILE *
 rxvt_term::popen_printer ()
 {
-  FILE *stream = popen (rs[Rs_print_pipe], "w");
+  FILE *stream = popen (rs[Rs_print_pipe] ? rs[Rs_print_pipe] : PRINTPIPE, "w");
 
   if (stream == NULL)
     rxvt_warn ("can't open printer pipe, not printing.\n");
@@ -2415,17 +2457,16 @@ rxvt_term::pclose_printer (FILE *stream)
 void
 rxvt_term::process_print_pipe ()
 {
-  int done;
-  FILE *fd;
+  FILE *fd = popen_printer ();
 
-  if ((fd = popen_printer ()) == NULL)
+  if (!fd)
     return;
 
   /*
    * Send all input to the printer until either ESC[4i or ESC[?4i
    * is received.
    */
-  for (done = 0; !done;)
+  for (int done = 0; !done; )
     {
       unsigned char buf[8];
       unicode_t ch;
@@ -2580,7 +2621,7 @@ rxvt_term::process_escape_vt52 (unicode_t ch)
         tt_printf ("\033/Z");  /* I am a VT100 emulating a VT52 */
         break;
       case '<':                /* turn off VT52 mode */
-        PrivMode (0, PrivMode_vt52);
+        set_privmode (PrivMode_vt52, 0);
         break;
       case 'F':        /* use special graphics character set */
       case 'G':           /* use regular character set */
@@ -2644,7 +2685,7 @@ rxvt_term::process_escape_seq ()
 #endif
       case '=':
       case '>':
-        PrivMode ((ch == '='), PrivMode_aplKP);
+        set_privmode (PrivMode_aplKP, ch == '=');
         break;
 
       case C1_40:
@@ -2693,21 +2734,21 @@ rxvt_term::process_escape_seq ()
         tt_write (ESCZ_ANSWER, sizeof (ESCZ_ANSWER) - 1);
         break;                 /* steal obsolete ESC [ c */
 
-        /* 8.3.16: CONTROL SEQUENCE INTRODUCER */
+        /* 8.3.16: CONTROL SEQUENCE INTRODUCER (CSI) */
       case C1_CSI:             /* ESC [ */
         process_csi_seq ();
         break;
 
-        /* 8.3.90: OPERATING SYSTEM COMMAND */
+        /* 8.3.90: OPERATING SYSTEM COMMAND (OSC) */
       case C1_OSC:             /* ESC ] */
         process_osc_seq ();
         break;
 
-        /* 8.3.106: RESET TO INITIAL STATE */
+        /* 8.3.106: RESET TO INITIAL STATE (RIS) */
       case 'c':
         mbstate.reset ();
         scr_poweron ();
-        scrollbar_show (1);
+        scrollBar.show (1);
         break;
 
         /* 8.3.79: LOCKING-SHIFT TWO (see ISO2022) */
@@ -2768,9 +2809,9 @@ rxvt_term::process_csi_seq ()
 
   priv = 0;
   ch = cmd_getc ();
-  if (ch >= '<' && ch <= '?')
+  if ((ch >= '<' && ch <= '?') || ch == '!')
     {
-      /* '<' '=' '>' '?' */
+      /* '<' '=' '>' '?' '!' */
       priv = ch;
       ch = cmd_getc ();
     }
@@ -2829,11 +2870,27 @@ rxvt_term::process_csi_seq ()
                 tt_printf ("\033[>%d;95;0c", 'U');
               }
             break;
+
           case '?':
             if (ch == 'h' || ch == 'l' || ch == 'r' || ch == 's' || ch == 't')
               process_terminal_mode (ch, priv, nargs, arg);
             break;
+
+          case '!':
+            if (ch == CSI_70)
+              {
+                /* DECSTR: soft terminal reset, used by our terminfo since 9.06 */
+                scr_soft_reset ();
+
+                static const int pm_h[] = { 7, 25 };
+                static const int pm_l[] = { 1, 3, 4, 5, 6, 9, 66, 1000, 1001, 1049 };
+
+                process_terminal_mode ('h', 0, sizeof (pm_h) / sizeof (pm_h[0]), pm_h);
+                process_terminal_mode ('l', 0, sizeof (pm_l) / sizeof (pm_l[0]), pm_l);
+              }
+          break;
         }
+
       return;
     }
 
@@ -3272,7 +3329,7 @@ rxvt_term::process_color_seq (int report, int color, const char *str, char resp)
  * XTerm escape sequences: ESC ] Ps;Pt (ST|BEL)
  */
 void
-rxvt_term::process_xterm_seq (int op, const char *str, char resp)
+rxvt_term::process_xterm_seq (int op, char *str, char resp)
 {
   int color;
   char *buf, *name;
@@ -3323,7 +3380,7 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
           }
         else
           {
-            char *eq = strchr (str, '='); // constness lost, but verified to be ok
+            char *eq = strchr (str, '=');
 
             if (eq)
               {
@@ -3354,9 +3411,11 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
             process_color_seq (op, color, name, resp);
           }
         break;
+      case Rxvt_restoreFG:
       case XTerm_Color00:
         process_color_seq (op, Color_fg, str, resp);
         break;
+      case Rxvt_restoreBG:
       case XTerm_Color01:
         process_color_seq (op, Color_bg, str, resp);
         break;
@@ -3371,15 +3430,18 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
       case XTerm_Color_pointer_bg:
         process_color_seq (op, Color_pointer_bg, str, resp);
         break;
-#ifndef NO_BOLD_UNDERLINE_REVERSE
-      case XTerm_Color_RV:
-        process_color_seq (op, Color_RV, str, resp);
+#ifdef OPTION_HC
+      case XTerm_Color_HC:
+        process_color_seq (op, Color_HC, str, resp);
         break;
-      case Rxvt_Color_BD:
+      case XTerm_Color_HTC:
+        process_color_seq (op, Color_HTC, str, resp);
+        break;
+#endif
+#ifndef NO_BOLD_UNDERLINE_REVERSE
       case URxvt_Color_BD:
         process_color_seq (op, Color_BD, str, resp);
         break;
-      case Rxvt_Color_UL:
       case URxvt_Color_UL:
         process_color_seq (op, Color_UL, str, resp);
         break;
@@ -3387,6 +3449,9 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
         process_color_seq (op, Color_IT, str, resp);
         break;
 #endif
+      case URxvt_Color_border:
+        process_color_seq (op, Color_border, str, resp);
+        break;
 #if ENABLE_TRANSPARENCY
       case URxvt_Color_tint:
         process_color_seq (op, Color_tint, str, resp);
@@ -3411,7 +3476,7 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
           {
             char str[256];
 
-            sprintf (str, "[%dx%d+%d+%d]",     /* can't presume snprintf () ! */
+            sprintf (str, "[%dx%d+%d+%d]",
                      min (bgPixmap.h_scale, 32767), min (bgPixmap.v_scale, 32767),
                      min (bgPixmap.h_align, 32767), min (bgPixmap.v_align, 32767));
             process_xterm_seq (XTerm_title, str, CHAR_ST);
@@ -3445,13 +3510,6 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
         break;
 #endif
 
-      case Rxvt_restoreFG:
-        set_window_color (Color_fg, str);
-        break;
-      case Rxvt_restoreBG:
-        set_window_color (Color_bg, str);
-        break;
-
       case XTerm_logfile:
         // TODO, when secure mode?
         break;
@@ -3527,8 +3585,7 @@ rxvt_term::process_xterm_seq (int op, const char *str, char resp)
 
 #if ENABLE_PERL
       case URxvt_perl:
-        if (HOOK_INVOKE ((this, HOOK_OSC_SEQ_PERL, DT_STR, str, DT_END)))
-          ; // no responses yet
+        HOOK_INVOKE ((this, HOOK_OSC_SEQ_PERL, DT_STR, str, DT_STR_LEN, &resp, 1, DT_END));
         break;
 #endif
     }
@@ -3561,7 +3618,7 @@ rxvt_term::privcases (int mode, unsigned long bit)
         state = (SavedModes & bit) ? 1 : 0;    /* no overlapping */
       else
         state = (mode == 't') ? ! (priv_modes & bit) : mode;
-      PrivMode (state, bit);
+      set_privmode (bit, state);
     }
 
   return state;
@@ -3579,29 +3636,31 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
     const int       argval;
     const unsigned long bit;
   } argtopriv[] = {
-                  { 1, PrivMode_aplCUR },
+                  { 1, PrivMode_aplCUR },       // DECCKM
                   { 2, PrivMode_vt52 },
-                  { 3, PrivMode_132 },
-                  { 4, PrivMode_smoothScroll },
-                  { 5, PrivMode_rVideo },
-                  { 6, PrivMode_relOrigin },
-                  { 7, PrivMode_Autowrap },
-                 // 8, bi-directional support mode
+                  { 3, PrivMode_132 },          // DECCOLM
+                  { 4, PrivMode_smoothScroll }, // DECSCLM
+                  { 5, PrivMode_rVideo },       // DECSCNM
+                  { 6, PrivMode_relOrigin },    // DECOM
+                  { 7, PrivMode_Autowrap },     // DECAWM
+                 // 8, auto-repeat keys         // DECARM
                   { 9, PrivMode_MouseX10 },
-                 // 18, 19 printing-related
-                  { 25, PrivMode_VisibleCursor },
+                 // 18 end FF to printer after print screen
+                 // 19 Print screen prints full screen/scorll region
+                  { 25, PrivMode_VisibleCursor }, // cnorm/cvvis/civis
 #ifdef scrollBar_esc
                   { scrollBar_esc, PrivMode_scrollBar },
 #endif
-                  { 35, PrivMode_ShiftKeys }, // rxvt extension
+                  { 35, PrivMode_ShiftKeys },   // rxvt extension
+                 // 38, tektronix mode          // DECTEK
                   { 40, PrivMode_132OK },
                  // 41 xterm more fixes NYI
                  // 45 margin bell NYI
                  // 46 start logging
                   { 47, PrivMode_Screen },
-                  { 66, PrivMode_aplKP },
+                  { 66, PrivMode_aplKP },       // DECPAM/DECPNM
 #ifndef NO_BACKSPACE_KEY
-                  { 67, PrivMode_BackSpace },
+                  { 67, PrivMode_BackSpace },   // DECBKM
 #endif
                   { 1000, PrivMode_MouseX11 },
                   { 1002, PrivMode_MouseBtnEvent },
@@ -3615,6 +3674,7 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
                  // 1048 save and restore cursor
                   { 1049, PrivMode_Screen }, /* xterm extension, clear screen on ti rather than te */
                  // 1051, 1052, 1060, 1061 keyboard emulation NYI
+                  { 2004, PrivMode_BracketPaste },
                 };
 
   if (nargs == 0)
@@ -3649,7 +3709,6 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
             break;
 #endif
           case 1048:           /* alternative cursor save */
-          case 1049:
             if (option (Opt_secondaryScreen))
               if (mode == 0)
                 scr_cursor (RESTORE);
@@ -3668,14 +3727,11 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
                * parameter.  Return from VT52 mode with an ESC < from
                * within VT52 mode
                */
-              PrivMode (1, PrivMode_vt52);
+              set_privmode (PrivMode_vt52, 1);
               break;
             case 3:                    /* 80/132 */
               if (priv_modes & PrivMode_132OK)
-                {
-                  scr_poweron ();
-                  set_widthheight (((state ? 132 : 80) * fwidth), 24 * fheight);
-                }
+                set_widthheight ((state ? 132 : 80) * fwidth, 24 * fheight);
               break;
             case 4:                    /* smooth scrolling */
               set_option (Opt_jumpScroll, !state);
@@ -3696,7 +3752,7 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
               break;
 #ifdef scrollBar_esc
             case scrollBar_esc:
-              if (scrollbar_mapping (state))
+              if (scrollBar.map (state))
                 {
                   resize_all_windows (0, 0, 0);
                   scr_touch (true);
@@ -3727,6 +3783,7 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
                 }
               else
                 vt_emask_mouse = NoEventMask;
+
               vt_select_input ();
               break;
             case 1010:         /* scroll to bottom on TTY output inhibit */
@@ -3737,15 +3794,23 @@ rxvt_term::process_terminal_mode (int mode, int priv UNUSED, unsigned int nargs,
               break;
             case 1047:         /* secondary screen w/ clearing last */
               if (option (Opt_secondaryScreen))
-                if (current_screen != PRIMARY)
+                if (!state)
                   scr_erase_screen (2);
+
               scr_change_screen (state);
               break;
             case 1049:         /* secondary screen w/ clearing first */
+              if (option (Opt_secondaryScreen))
+                if (state)
+                  scr_cursor (SAVE);
+
               scr_change_screen (state);
+
               if (option (Opt_secondaryScreen))
-                if (current_screen != PRIMARY)
+                if (state)
                   scr_erase_screen (2);
+                else
+                  scr_cursor (RESTORE);
               break;
             default:
               break;