*** empty log message ***
[dana/urxvt.git] / src / screen.C
index 81c3d62..5836898 100644 (file)
@@ -1,8 +1,9 @@
 /*--------------------------------*-C-*--------------------------------------*
- * File:        screen.c
+ * File:        screen.C
  *---------------------------------------------------------------------------*
  *
  * Copyright (c) 1997-2001 Geoff Wing <gcw@pobox.com>
+ * Copyright (c) 2003-2004 Marc Lehmann <pcg@goof.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *--------------------------------------------------------------------------*/
+
 /*
- * We handle _all_ screen updates and selections
+ * This file handles _all_ screen updates and selections
  */
 
 #include "../config.h"          /* NECESSARY */
-#define INTERN_SCREEN
 #include "rxvt.h"               /* NECESSARY */
-#include "screen.intpro"        /* PROTOS for internal routines */
 
 #include <X11/Xmd.h>            /* get the typedef for CARD32 */
 
-#include <stdint.h>
+#include <inttypes.h>
 #include <wchar.h>
 
-#include "salloc.C" // HACK!!
+#include "salloc.C" // HACK, should be a seperate compile!
 
 inline void fill_text (text_t *start, text_t value, int len)
 {
@@ -41,49 +41,50 @@ inline void fill_text (text_t *start, text_t value, int len)
 }
 
 /* ------------------------------------------------------------------------- */
-#define PROP_SIZE               16384
+#define PROP_SIZE               256*1024
+#define PASTE_SIZE             32768
 #define TABSIZE                 8       /* default tab size */
 
 /* ------------------------------------------------------------------------- *
  *             GENERAL SCREEN AND SELECTION UPDATE ROUTINES                  *
  * ------------------------------------------------------------------------- */
-#define ZERO_SCROLLBACK(R)                                              \
-    if (((R)->Options & Opt_scrollTtyOutput) == Opt_scrollTtyOutput)    \
-        (R)->TermWin.view_start = 0
-#define CLEAR_SELECTION(R)                                              \
-    (R)->selection.beg.row = (R)->selection.beg.col                     \
-        = (R)->selection.end.row = (R)->selection.end.col = 0
-#define CLEAR_ALL_SELECTION(R)                                          \
-    (R)->selection.beg.row = (R)->selection.beg.col                     \
-        = (R)->selection.mark.row = (R)->selection.mark.col             \
-        = (R)->selection.end.row = (R)->selection.end.col = 0
-
-#define ROW_AND_COL_IS_AFTER(A, B, C, D)                                \
+#define ZERO_SCROLLBACK()                                              \
+    if (options & Opt_scrollTtyOutput)                                 \
+        TermWin.view_start = 0
+#define CLEAR_SELECTION()                                              \
+    selection.beg.row = selection.beg.col                              \
+        = selection.end.row = selection.end.col = 0
+#define CLEAR_ALL_SELECTION()                                          \
+    selection.beg.row = selection.beg.col                              \
+        = selection.mark.row = selection.mark.col                      \
+        = selection.end.row = selection.end.col = 0
+
+#define ROW_AND_COL_IS_AFTER(A, B, C, D)                               \
     (((A) > (C)) || (((A) == (C)) && ((B) > (D))))
-#define ROW_AND_COL_IS_BEFORE(A, B, C, D)                               \
+#define ROW_AND_COL_IS_BEFORE(A, B, C, D)                              \
     (((A) < (C)) || (((A) == (C)) && ((B) < (D))))
-#define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D)                            \
+#define ROW_AND_COL_IN_ROW_AFTER(A, B, C, D)                           \
     (((A) == (C)) && ((B) > (D)))
-#define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D)                      \
+#define ROW_AND_COL_IN_ROW_AT_OR_AFTER(A, B, C, D)                     \
     (((A) == (C)) && ((B) >= (D)))
-#define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D)                           \
+#define ROW_AND_COL_IN_ROW_BEFORE(A, B, C, D)                          \
     (((A) == (C)) && ((B) < (D)))
-#define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D)                     \
+#define ROW_AND_COL_IN_ROW_AT_OR_BEFORE(A, B, C, D)                    \
     (((A) == (C)) && ((B) <= (D)))
 
 /* these must be row_col_t */
-#define ROWCOL_IS_AFTER(X, Y)                                           \
-    ROW_AND_COL_IS_AFTER((X).row, (X).col, (Y).row, (Y).col)
-#define ROWCOL_IS_BEFORE(X, Y)                                          \
-    ROW_AND_COL_IS_BEFORE((X).row, (X).col, (Y).row, (Y).col)
-#define ROWCOL_IN_ROW_AFTER(X, Y)                                       \
-    ROW_AND_COL_IN_ROW_AFTER((X).row, (X).col, (Y).row, (Y).col)
-#define ROWCOL_IN_ROW_BEFORE(X, Y)                                      \
-    ROW_AND_COL_IN_ROW_BEFORE((X).row, (X).col, (Y).row, (Y).col)
-#define ROWCOL_IN_ROW_AT_OR_AFTER(X, Y)                                 \
-    ROW_AND_COL_IN_ROW_AT_OR_AFTER((X).row, (X).col, (Y).row, (Y).col)
-#define ROWCOL_IN_ROW_AT_OR_BEFORE(X, Y)                                \
-    ROW_AND_COL_IN_ROW_AT_OR_BEFORE((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IS_AFTER(X, Y)                                          \
+    ROW_AND_COL_IS_AFTER ((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IS_BEFORE(X, Y)                                         \
+    ROW_AND_COL_IS_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IN_ROW_AFTER(X, Y)                                      \
+    ROW_AND_COL_IN_ROW_AFTER ((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IN_ROW_BEFORE(X, Y)                                     \
+    ROW_AND_COL_IN_ROW_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IN_ROW_AT_OR_AFTER(X, Y)                                \
+    ROW_AND_COL_IN_ROW_AT_OR_AFTER ((X).row, (X).col, (Y).row, (Y).col)
+#define ROWCOL_IN_ROW_AT_OR_BEFORE(X, Y)                               \
+    ROW_AND_COL_IN_ROW_AT_OR_BEFORE ((X).row, (X).col, (Y).row, (Y).col)
 
 /*
  * CLEAR_ROWS : clear <num> rows starting from row <row>
@@ -92,33 +93,34 @@ inline void fill_text (text_t *start, text_t value, int len)
  */
 #define drawBuffer      TermWin.vt
 
-#define CLEAR_ROWS(row, num)                                            \
-    if (TermWin.mapped)                                              \
-        XClearArea (Xdisplay, drawBuffer, TermWin.int_bwidth,      \
-                    Row2Pixel(row), (unsigned int)TermWin.width,      \
-                    (unsigned int)Height2Pixel(num), False)
+#define CLEAR_ROWS(row, num)                                           \
+    if (TermWin.mapped)                                                \
+        XClearArea (display->display, drawBuffer, 0,                   \
+                    Row2Pixel (row), (unsigned int)TermWin.width,      \
+                    (unsigned int)Height2Pixel (num), False)
 
-#define CLEAR_CHARS(x, y, num)                                          \
-    if (TermWin.mapped)                                              \
-        XClearArea (Xdisplay, drawBuffer, x, y,                       \
-                    (unsigned int)Width2Pixel(num),                      \
-                    (unsigned int)Height2Pixel(1), False)
+#define CLEAR_CHARS(x, y, num)                                         \
+    if (TermWin.mapped)                                                \
+        XClearArea (display->display, drawBuffer, x, y,                \
+                    (unsigned int)Width2Pixel (num),                   \
+                    (unsigned int)Height2Pixel (1), False)
 
-#define ERASE_ROWS(row, num)                                            \
-    XFillRectangle (Xdisplay, drawBuffer, TermWin.gc,              \
-                    TermWin.int_bwidth, Row2Pixel(row),               \
-                    (unsigned int)TermWin.width,                      \
-                    (unsigned int)Height2Pixel(num))
+#define ERASE_ROWS(row, num)                                           \
+    XFillRectangle (display->display, drawBuffer, TermWin.gc,          \
+                    0, Row2Pixel (row),                                \
+                    (unsigned int)TermWin.width,                       \
+                    (unsigned int)Height2Pixel (num))
 
 /* ------------------------------------------------------------------------- *
  *                        SCREEN `COMMON' ROUTINES                           *
  * ------------------------------------------------------------------------- */
+
 /* Fill part/all of a line with blanks. */
 void
 rxvt_term::scr_blank_line (text_t *et, rend_t *er, unsigned int width, rend_t efs)
 {
   efs &= ~RS_baseattrMask;
-  efs = SET_FONT (efs, TermWin.fontset->find_font (' '));
+  efs = SET_FONT (efs, FONTSET (efs)->find_font (' '));
 
   while (width--)
     {
@@ -133,7 +135,7 @@ void
 rxvt_term::scr_blank_screen_mem (text_t **tp, rend_t **rp, unsigned int row, rend_t efs)
 {
 #ifdef DEBUG_STRICT
-  assert((tp[row] && rp[row]) || (tp[row] == NULL && rp[row] == NULL));
+  assert ((tp[row] && rp[row]) || (tp[row] == NULL && rp[row] == NULL));
 #endif
   if (tp[row] == NULL)
     {
@@ -155,7 +157,9 @@ rxvt_term::scr_reset ()
   int k;
   rend_t setrstyle;
 
-  D_SCREEN((stderr, "rxvt_scr_reset()"));
+#if ENABLE_OVERLAY
+  scr_overlay_off ();
+#endif
 
   TermWin.view_start = 0;
   num_scr = 0;
@@ -172,10 +176,18 @@ rxvt_term::scr_reset ()
   if (ncol == prev_ncol && nrow == prev_nrow)
     return;
 
+  // we need at least two lines for wrapping to work correctly
+  if (nrow + TermWin.saveLines < 2)
+    {
+      TermWin.saveLines++;
+      prev_nrow--;
+      TermWin.nscrolled++;
+    }
+
   want_refresh = 1;
 
-  total_rows = nrow + TermWin.saveLines;
   prev_total_rows = prev_nrow + TermWin.saveLines;
+  total_rows = nrow + TermWin.saveLines;
 
   screen.tscroll = 0;
   screen.bscroll = nrow - 1;
@@ -185,25 +197,25 @@ rxvt_term::scr_reset ()
       talloc = new rxvt_salloc (ncol * sizeof (text_t));
       ralloc = new rxvt_salloc (ncol * sizeof (rend_t));
     }
-     
-  if (prev_nrow == 0)
+
+  if (!screen.text)
     {
       /*
-       * first time called so just malloc everything : don't rely on realloc
+       * first time called so just malloc everything: don't rely on realloc
        * Note: this is still needed so that all the scrollback lines are NULL
        */
-      screen.text = (text_t **)rxvt_calloc(total_rows, sizeof(text_t *));
-      buf_text = (text_t **)rxvt_calloc(total_rows, sizeof(text_t *));
-      drawn_text = (text_t **)rxvt_calloc(nrow, sizeof(text_t *));
-      swap.text = (text_t **)rxvt_calloc(nrow, sizeof(text_t *));
+      screen.text = (text_t **)rxvt_calloc (total_rows, sizeof (text_t *));
+      buf_text = (text_t **)rxvt_calloc (total_rows, sizeof (text_t *));
+      drawn_text = (text_t **)rxvt_calloc (nrow, sizeof (text_t *));
+      swap.text = (text_t **)rxvt_calloc (nrow, sizeof (text_t *));
 
-      screen.tlen = (int16_t *)rxvt_calloc(total_rows, sizeof(int16_t));
-      swap.tlen = (int16_t *)rxvt_calloc(nrow, sizeof(int16_t));
+      screen.tlen = (int16_t *)rxvt_calloc (total_rows, sizeof (int16_t));
+      swap.tlen = (int16_t *)rxvt_calloc (nrow, sizeof (int16_t));
 
-      screen.rend = (rend_t **)rxvt_calloc(total_rows, sizeof(rend_t *));
-      buf_rend = (rend_t **)rxvt_calloc(total_rows, sizeof(rend_t *));
-      drawn_rend = (rend_t **)rxvt_calloc(nrow, sizeof(rend_t *));
-      swap.rend = (rend_t **)rxvt_calloc(nrow, sizeof(rend_t *));
+      screen.rend = (rend_t **)rxvt_calloc (total_rows, sizeof (rend_t *));
+      buf_rend = (rend_t **)rxvt_calloc (total_rows, sizeof (rend_t *));
+      drawn_rend = (rend_t **)rxvt_calloc (nrow, sizeof (rend_t *));
+      swap.rend = (rend_t **)rxvt_calloc (nrow, sizeof (rend_t *));
 
       for (p = 0; p < nrow; p++)
         {
@@ -214,21 +226,21 @@ rxvt_term::scr_reset ()
           scr_blank_screen_mem (drawn_text, drawn_rend, p, DEFAULT_RSTYLE);
         }
 
-      MEMSET(charsets, 'B', sizeof(charsets));
+      memset (charsets, 'B', sizeof (charsets));
       TermWin.nscrolled = 0;       /* no saved lines */
       rstyle = DEFAULT_RSTYLE;
       screen.flags = Screen_DefaultFlags;
       screen.cur.row = screen.cur.col = 0;
       screen.charset = 0;
       current_screen = PRIMARY;
-      rxvt_scr_cursor (this, SAVE);
+      scr_cursor (SAVE);
 
 #if NSCREENS
       swap.flags = Screen_DefaultFlags;
       swap.cur.row = swap.cur.col = 0;
       swap.charset = 0;
       current_screen = SECONDARY;
-      rxvt_scr_cursor (this, SAVE);
+      scr_cursor (SAVE);
       current_screen = PRIMARY;
 #endif
 
@@ -237,7 +249,7 @@ rxvt_term::scr_reset ()
       selection.op = SELECTION_CLEAR;
       selection.screen = PRIMARY;
       selection.clicks = 0;
-      CLEAR_ALL_SELECTION (this);
+      CLEAR_ALL_SELECTION ();
       rvideo = 0;
     }
   else
@@ -256,6 +268,7 @@ rxvt_term::scr_reset ()
           for (p = nrow; p < prev_nrow; p++)
             {
               q = p + TermWin.saveLines;
+
               if (screen.text[q])
                 {
 #ifdef DEBUG_STRICT
@@ -264,6 +277,7 @@ rxvt_term::scr_reset ()
                   talloc->free (screen.text[q]);
                   ralloc->free (screen.rend[q]);
                 }
+
               if (swap.text[p])
                 {
 #ifdef DEBUG_STRICT
@@ -272,6 +286,7 @@ rxvt_term::scr_reset ()
                   talloc->free (swap.text[p]);
                   ralloc->free (swap.rend[p]);
                 }
+
 #ifdef DEBUG_STRICT
               assert (drawn_text[p] && drawn_rend[p]);
 #endif
@@ -311,7 +326,7 @@ rxvt_term::scr_reset ()
               swap.rend[p] = NULL;
               drawn_text[p] = NULL;
               drawn_rend[p] = NULL;
-              scr_blank_screen_mem (swap.text, swap.rend, p, setrstyle);
+              scr_blank_screen_mem (swap.text,  swap.rend,  p, setrstyle);
               scr_blank_screen_mem (drawn_text, drawn_rend, p, setrstyle);
             }
 
@@ -323,12 +338,12 @@ rxvt_term::scr_reset ()
               TermWin.nscrolled -= k;
             }
 #ifdef DEBUG_STRICT
-          assert(screen.cur.row < TermWin.nrow);
-          assert(swap.cur.row < TermWin.nrow);
+          assert (screen.cur.row < TermWin.nrow);
+          assert (swap.cur.row < TermWin.nrow);
 #else                           /* drive with your eyes closed */
 
-          MIN_IT(screen.cur.row, nrow - 1);
-          MIN_IT(swap.cur.row, nrow - 1);
+          MIN_IT (screen.cur.row, nrow - 1);
+          MIN_IT (swap.cur.row, nrow - 1);
 #endif
           TermWin.ncol =  ncol; // save b/c scr_blank_screen_mem uses this
         }
@@ -336,47 +351,45 @@ rxvt_term::scr_reset ()
       /* resize columns */
       if (ncol != prev_ncol)
         {
-          int common = min (prev_ncol, ncol);
           rxvt_salloc *ta = new rxvt_salloc (ncol * sizeof (text_t));
           rxvt_salloc *ra = new rxvt_salloc (ncol * sizeof (rend_t));
-     
+
           for (p = 0; p < total_rows; p++)
             {
               if (screen.text[p])
                 {
-                  text_t *t = (text_t *)ta->alloc (); memcpy (t, screen.text[p], common * sizeof (text_t)); screen.text[p] = t;
-                  rend_t *r = (rend_t *)ra->alloc (); memcpy (r, screen.rend[p], common * sizeof (rend_t)); screen.rend[p] = r;
+                  screen.text[p] = (text_t *)ta->alloc (screen.text[p], prev_ncol * sizeof (text_t));
+                  screen.rend[p] = (rend_t *)ra->alloc (screen.rend[p], prev_ncol * sizeof (rend_t));
 
-                  MIN_IT(screen.tlen[p], (int16_t)ncol);
+                  MIN_IT (screen.tlen[p], (int16_t)ncol);
 
                   if (ncol > prev_ncol)
-                    scr_blank_line (&(screen.text[p][prev_ncol]),
-                                    &(screen.rend[p][prev_ncol]),
-                                    ncol - prev_ncol,
-                                    setrstyle);
+                    scr_blank_line (&screen.text[p][prev_ncol],
+                                    &screen.rend[p][prev_ncol],
+                                    ncol - prev_ncol, setrstyle);
                 }
             }
 
           for (p = 0; p < nrow; p++)
             {
-              text_t *t = (text_t *)ta->alloc (); memcpy (t, drawn_text[p], common * sizeof (text_t)); drawn_text[p] = t;
-              rend_t *r = (rend_t *)ra->alloc (); memcpy (r, drawn_rend[p], common * sizeof (rend_t)); drawn_rend[p] = r;
+              drawn_text[p] = (text_t *)ta->alloc (drawn_text[p], prev_ncol * sizeof (text_t));
+              drawn_rend[p] = (rend_t *)ra->alloc (drawn_rend[p], prev_ncol * sizeof (rend_t));
 
               if (ncol > prev_ncol)
-                scr_blank_line (&(drawn_text[p][prev_ncol]),
-                                &(drawn_rend[p][prev_ncol]),
+                scr_blank_line (&drawn_text[p][prev_ncol],
+                                &drawn_rend[p][prev_ncol],
                                 ncol - prev_ncol, setrstyle);
 
               if (swap.text[p])
                 {
-                  text_t *t = (text_t *)ta->alloc (); memcpy (t, swap.text[p], common * sizeof (text_t)); swap.text[p] = t;
-                  rend_t *r = (rend_t *)ra->alloc (); memcpy (r, swap.rend[p], common * sizeof (rend_t)); swap.rend[p] = r;
+                  swap.text[p] = (text_t *)ta->alloc (swap.text[p], prev_ncol * sizeof (text_t));
+                  swap.rend[p] = (rend_t *)ra->alloc (swap.rend[p], prev_ncol * sizeof (rend_t));
 
-                  MIN_IT(swap.tlen[p], (int16_t)ncol);
+                  MIN_IT (swap.tlen[p], (int16_t)ncol);
 
                   if (ncol > prev_ncol)
-                    scr_blank_line (&(swap.text[p][prev_ncol]),
-                                    &(swap.rend[p][prev_ncol]),
+                    scr_blank_line (&swap.text[p][prev_ncol],
+                                    &swap.rend[p][prev_ncol],
                                     ncol - prev_ncol, setrstyle);
                 }
 
@@ -390,13 +403,13 @@ rxvt_term::scr_reset ()
         }
 
       if (tabs)
-        free(tabs);
+        free (tabs);
     }
 
   prev_nrow = nrow;
   prev_ncol = ncol;
 
-  tabs = (char *)rxvt_malloc (ncol * sizeof(char));
+  tabs = (char *)rxvt_malloc (ncol * sizeof (char));
 
   for (p = 0; p < ncol; p++)
     tabs[p] = (p % TABSIZE == 0) ? 1 : 0;
@@ -405,25 +418,25 @@ rxvt_term::scr_reset ()
 }
 
 void
-rxvt_term::scr_reset_realloc()
+rxvt_term::scr_reset_realloc ()
 {
-  uint16_t total_rows, nrow;
+  unsigned int total_rows, nrow;
 
   nrow = TermWin.nrow;
   total_rows = nrow + TermWin.saveLines;
   /* *INDENT-OFF* */
-  screen.text = (text_t **)rxvt_realloc(screen.text, total_rows * sizeof(text_t *));
-  buf_text    = (text_t **)rxvt_realloc(buf_text   , total_rows * sizeof(text_t *));
-  drawn_text  = (text_t **)rxvt_realloc(drawn_text , nrow       * sizeof(text_t *));
-  swap.text   = (text_t **)rxvt_realloc(swap.text  , nrow       * sizeof(text_t *));
-
-  screen.tlen = (int16_t *)rxvt_realloc(screen.tlen, total_rows * sizeof(int16_t));
-  swap.tlen   = (int16_t *)rxvt_realloc(swap.tlen  , total_rows * sizeof(int16_t));
-
-  screen.rend = (rend_t **)rxvt_realloc(screen.rend, total_rows * sizeof(rend_t *));
-  buf_rend    = (rend_t **)rxvt_realloc(buf_rend   , total_rows * sizeof(rend_t *));
-  drawn_rend  = (rend_t **)rxvt_realloc(drawn_rend , nrow       * sizeof(rend_t *));
-  swap.rend   = (rend_t **)rxvt_realloc(swap.rend  , nrow       * sizeof(rend_t *));
+  screen.text = (text_t **)rxvt_realloc (screen.text, total_rows * sizeof (text_t *));
+  buf_text    = (text_t **)rxvt_realloc (buf_text   , total_rows * sizeof (text_t *));
+  drawn_text  = (text_t **)rxvt_realloc (drawn_text , nrow       * sizeof (text_t *));
+  swap.text   = (text_t **)rxvt_realloc (swap.text  , nrow       * sizeof (text_t *));
+
+  screen.tlen = (int16_t *)rxvt_realloc (screen.tlen, total_rows * sizeof (int16_t));
+  swap.tlen   = (int16_t *)rxvt_realloc (swap.tlen  , total_rows * sizeof (int16_t));
+
+  screen.rend = (rend_t **)rxvt_realloc (screen.rend, total_rows * sizeof (rend_t *));
+  buf_rend    = (rend_t **)rxvt_realloc (buf_rend   , total_rows * sizeof (rend_t *));
+  drawn_rend  = (rend_t **)rxvt_realloc (drawn_rend , nrow       * sizeof (rend_t *));
+  swap.rend   = (rend_t **)rxvt_realloc (swap.rend  , nrow       * sizeof (rend_t *));
   /* *INDENT-ON* */
 }
 
@@ -432,22 +445,13 @@ rxvt_term::scr_reset_realloc()
  * Free everything.  That way malloc debugging can find leakage.
  */
 void
-rxvt_term::scr_release()
+rxvt_term::scr_release ()
 {
-  uint16_t total_rows;
+  unsigned int total_rows;
   int i;
 
   total_rows = TermWin.nrow + TermWin.saveLines;
 
-#ifdef DEBUG_STRICT
-  for (i = 0; i < total_rows; i++)
-    {
-      if (screen.text[i])
-        /* then so is screen.rend[i] */
-        assert(screen.rend[i]);
-    }
-#endif
-
   delete talloc; talloc = 0;
   delete ralloc; ralloc = 0;
 
@@ -476,21 +480,15 @@ rxvt_term::scr_release()
 /*
  * Hard reset
  */
-/* EXTPROTO */
 void
-rxvt_scr_poweron(pR)
+rxvt_term::scr_poweron ()
 {
-  D_SCREEN((stderr, "rxvt_scr_poweron()"));
-
-  R->scr_release ();
-  R->prev_nrow = R->prev_ncol = 0;
-  R->scr_reset ();
+  scr_release ();
+  prev_nrow = prev_ncol = 0;
+  scr_reset ();
 
-  R->scr_clear ();
-  R->scr_refresh (SLOW_REFRESH);
-#ifdef RXVT_GRAPHICS
-  rxvt_Gr_reset (aR);
-#endif
+  scr_clear (true);
+  scr_refresh (SLOW_REFRESH);
 }
 
 /* ------------------------------------------------------------------------- *
@@ -501,48 +499,49 @@ rxvt_scr_poweron(pR)
  * XTERM_SEQ: Save cursor   : ESC 7
  * XTERM_SEQ: Restore cursor: ESC 8
  */
-/* EXTPROTO */
 void
-rxvt_scr_cursor(pR_ int mode)
+rxvt_term::scr_cursor (int mode)
 {
-    screen_t       *s;
-
-    D_SCREEN((stderr, "rxvt_scr_cursor(%c)", mode));
+  screen_t *s;
 
 #if NSCREENS && !defined(NO_SECONDARY_SCREEN_CURSOR)
-    if (R->current_screen == SECONDARY)
-        s = &(R->swap);
-    else
+  if (current_screen == SECONDARY)
+    s = &swap;
+  else
 #endif
-        s = &(R->screen);
-    switch (mode) {
-    case SAVE:
-        s->s_cur.row = s->cur.row;
-        s->s_cur.col = s->cur.col;
-        s->s_rstyle = R->rstyle;
-        s->s_charset = s->charset;
-        s->s_charset_char = R->charsets[s->charset];
+    s = &screen;
+
+  switch (mode)
+    {
+      case SAVE:
+        s->s_cur.row = screen.cur.row;
+        s->s_cur.col = screen.cur.col;
+        s->s_rstyle = rstyle;
+        s->s_charset = screen.charset;
+        s->s_charset_char = charsets[screen.charset];
         break;
-    case RESTORE:
-        R->want_refresh = 1;
-        s->cur.row = s->s_cur.row;
-        s->cur.col = s->s_cur.col;
-        s->flags &= ~Screen_WrapNext;
-        R->rstyle = s->s_rstyle;
-        s->charset = s->s_charset;
-        R->charsets[s->charset] = s->s_charset_char;
-        rxvt_set_font_style(aR);
+
+      case RESTORE:
+        want_refresh = 1;
+        screen.cur.row = s->s_cur.row;
+        screen.cur.col = s->s_cur.col;
+        screen.flags &= ~Screen_WrapNext;
+        rstyle = s->s_rstyle;
+        screen.charset = s->s_charset;
+        charsets[screen.charset] = s->s_charset_char;
+        set_font_style ();
         break;
     }
-/* boundary check in case screen size changed between SAVE and RESTORE */
-    MIN_IT(s->cur.row, R->TermWin.nrow - 1);
-    MIN_IT(s->cur.col, R->TermWin.ncol - 1);
+
+  /* boundary check in case screen size changed between SAVE and RESTORE */
+  MIN_IT (s->cur.row, TermWin.nrow - 1);
+  MIN_IT (s->cur.col, TermWin.ncol - 1);
 #ifdef DEBUG_STRICT
-    assert(s->cur.row >= 0);
-    assert(s->cur.col >= 0);
+  assert (s->cur.row >= 0);
+  assert (s->cur.col >= 0);
 #else                           /* drive with your eyes closed */
-    MAX_IT(s->cur.row, 0);
-    MAX_IT(s->cur.col, 0);
+  MAX_IT (s->cur.row, 0);
+  MAX_IT (s->cur.col, 0);
 #endif
 }
 
@@ -552,105 +551,110 @@ rxvt_scr_cursor(pR_ int mode)
  * XTERM_SEQ: Primary screen  : ESC [ ? 4 7 h
  * XTERM_SEQ: Secondary screen: ESC [ ? 4 7 l
  */
-/* EXTPROTO */
 int
-rxvt_scr_change_screen(pR_ int scrn)
+rxvt_term::scr_change_screen (int scrn)
 {
-    int             i;
+  int i;
 #if NSCREENS
-    int             offset;
+  int offset;
 #endif
 
-    R->want_refresh = 1;
+  want_refresh = 1;
 
-    D_SCREEN((stderr, "rxvt_scr_change_screen(%d)", scrn));
+  TermWin.view_start = 0;
 
-    R->TermWin.view_start = 0;
+  if (current_screen == scrn)
+    return scrn;
 
-    if (R->current_screen == scrn)
-        return R->current_screen;
+  selection_check (2);        /* check for boundary cross */
 
-    rxvt_selection_check(aR_ 2);        /* check for boundary cross */
+  SWAP_IT (current_screen, scrn, int);
 
-    SWAP_IT(R->current_screen, scrn, int);
-#if NSCREENS
-    R->num_scr = 0;
-    offset = R->TermWin.saveLines;
-    for (i = R->prev_nrow; i--;) {
-        SWAP_IT(R->screen.text[i + offset], R->swap.text[i], text_t *);
-        SWAP_IT(R->screen.tlen[i + offset], R->swap.tlen[i], int16_t);
-        SWAP_IT(R->screen.rend[i + offset], R->swap.rend[i], rend_t *);
-    }
-    SWAP_IT(R->screen.cur.row, R->swap.cur.row, int16_t);
-    SWAP_IT(R->screen.cur.col, R->swap.cur.col, int16_t);
+  SWAP_IT (screen.cur.row, swap.cur.row, int16_t);
+  SWAP_IT (screen.cur.col, swap.cur.col, int16_t);
 # ifdef DEBUG_STRICT
-    assert((R->screen.cur.row >= 0) && (R->screen.cur.row < R->prev_nrow));
-    assert((R->screen.cur.col >= 0) && (R->screen.cur.col < R->prev_ncol));
+  assert (screen.cur.row >= 0 && screen.cur.row < prev_nrow);
+  assert (screen.cur.col >= 0 && screen.cur.col < prev_ncol);
 # else                          /* drive with your eyes closed */
-    MAX_IT(R->screen.cur.row, 0);
-    MIN_IT(R->screen.cur.row, (int32_t)R->prev_nrow - 1);
-    MAX_IT(R->screen.cur.col, 0);
-    MIN_IT(R->screen.cur.col, (int32_t)R->prev_ncol - 1);
+  MAX_IT (screen.cur.row, 0);
+  MIN_IT (screen.cur.row, (int32_t)prev_nrow - 1);
+  MAX_IT (screen.cur.col, 0);
+  MIN_IT (screen.cur.col, (int32_t)prev_ncol - 1);
 # endif
-    SWAP_IT(R->screen.charset, R->swap.charset, int16_t);
-    SWAP_IT(R->screen.flags, R->swap.flags, int);
-    R->screen.flags |= Screen_VisibleCursor;
-    R->swap.flags |= Screen_VisibleCursor;
 
-# ifdef RXVT_GRAPHICS
+#if NSCREENS
+  if (options & Opt_secondaryScreen)
+    {
+      num_scr = 0;
+      offset = TermWin.saveLines;
+
+      for (i = prev_nrow; i--;)
+        {
+          SWAP_IT (screen.text[i + offset], swap.text[i], text_t *);
+          SWAP_IT (screen.tlen[i + offset], swap.tlen[i], int16_t);
+          SWAP_IT (screen.rend[i + offset], swap.rend[i], rend_t *);
+        }
 
-    if (rxvt_Gr_Displayed(aR)) {
-        rxvt_Gr_scroll(aR_ 0);
-        rxvt_Gr_ChangeScreen(aR);
+      SWAP_IT (screen.charset, swap.charset, int16_t);
+      SWAP_IT (screen.flags, swap.flags, int);
+      screen.flags |= Screen_VisibleCursor;
+      swap.flags |= Screen_VisibleCursor;
     }
-# endif
-#else
-# ifdef SCROLL_ON_NO_SECONDARY
-#  ifdef RXVT_GRAPHICS
-    if (rxvt_Gr_Displayed(aR))
-        rxvt_Gr_ClearScreen(aR);
-#  endif
-    if (R->current_screen == PRIMARY
-#  ifdef RXVT_GRAPHICS
-        && !rxvt_Gr_Displayed(aR)
-#  endif
-        )
-        R->scr_scroll_text(0, (R->prev_nrow - 1), R->prev_nrow, 0);
-# endif
+  else
 #endif
-    return scrn;
+    if (options & Opt_secondaryScroll)
+      scr_scroll_text (0, prev_nrow - 1, prev_nrow, 0);
+
+  return scrn;
+}
+
+// clear WrapNext indicator, solidifying position on next line
+void
+rxvt_term::scr_do_wrap ()
+{
+  if (!(screen.flags & Screen_WrapNext))
+    return;
+
+  screen.flags &= ~Screen_WrapNext;
+
+  screen.cur.col = 0;
+
+  if (screen.cur.row == screen.bscroll)
+    scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
+  else if (screen.cur.row < TermWin.nrow - 1)
+    screen.cur.row++;
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Change the colour for following text
  */
-/* EXTPROTO */
 void
-rxvt_scr_color(pR_ unsigned int color, int fgbg)
+rxvt_term::scr_color (unsigned int color, int fgbg)
 {
-    color &= RS_fgMask;
-    if (fgbg == Color_fg)
-        R->rstyle = SET_FGCOLOR(R->rstyle, color);
-    else 
-        R->rstyle = SET_BGCOLOR(R->rstyle, color);
+  if (color > maxTermCOLOR)
+    color = fgbg;
+
+  if (fgbg == Color_fg)
+    rstyle = SET_FGCOLOR (rstyle, color);
+  else
+    rstyle = SET_BGCOLOR (rstyle, color);
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Change the rendition style for following text
  */
-/* EXTPROTO */
 void
-rxvt_scr_rendition(pR_ int set, int style)
-{
+rxvt_term::scr_rendition (int set, int style)
+  {
     if (set)
-        R->rstyle |= style;
+      rstyle |= style;
     else if (style == ~RS_None)
-        R->rstyle = DEFAULT_RSTYLE;
+      rstyle = DEFAULT_RSTYLE;
     else
-        R->rstyle &= ~style;
-}
+      rstyle &= ~style;
+  }
 
 /* ------------------------------------------------------------------------- */
 /*
@@ -669,21 +673,21 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
     return 0;
 
   want_refresh = 1;
-  D_SCREEN((stderr, "rxvt_scroll_text(%d,%d,%d,%d): %s", row1, row2, count, spec, (current_screen == PRIMARY) ? "Primary" : "Secondary"));
 
-  if ((count > 0) && (row1 == 0) && (current_screen == PRIMARY))
+  if (row1 == 0 && count > 0
+      && (current_screen == PRIMARY || options & Opt_secondaryScroll))
     {
       nscrolled = (long)TermWin.nscrolled + (long)count;
 
       if (nscrolled > (long)TermWin.saveLines)
         TermWin.nscrolled = TermWin.saveLines;
       else
-        TermWin.nscrolled = (uint16_t)nscrolled;
+        TermWin.nscrolled = (unsigned int)nscrolled;
 
-      if ((Options & Opt_scrollWithBuffer)
+      if ((options & Opt_scrollWithBuffer)
           && TermWin.view_start != 0
           && TermWin.view_start != TermWin.saveLines)
-        rxvt_scr_page (this, UP, count);
+        scr_page (UP, count);
     }
   else if (!spec)
     row1 += TermWin.saveLines;
@@ -701,7 +705,7 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
           || (j - count < row1 && j >= row1)
           || (j - count > row2 && j <= row2))
         {
-          CLEAR_ALL_SELECTION (this);
+          CLEAR_ALL_SELECTION ();
           selection.op = SELECTION_CLEAR;  /* XXX: too aggressive? */
         }
       else if (j >= row1 && j <= row2)
@@ -713,7 +717,7 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
         }
     }
 
-  rxvt_selection_check (this, 0);        /* _after_ TermWin.nscrolled update */
+  selection_check (0);        /* _after_ TermWin.nscrolled update */
 
   num_scr += count;
   j = count;
@@ -722,25 +726,22 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
     count = -count;
 
   i = row2 - row1 + 1;
-  MIN_IT(count, i);
+  MIN_IT (count, i);
 
   if (j > 0)
     {
       /* A: scroll up */
 
       /* A1: Copy lines that will get clobbered by the rotation */
-      for (i = 0, j = row1; i < count; i++, j++)
-        {
-          buf_text[i] = screen.text[j];
-          buf_rend[i] = screen.rend[j];
-        }
+      memcpy (buf_text, screen.text + row1, count * sizeof (text_t *));
+      memcpy (buf_rend, screen.rend + row1, count * sizeof (rend_t *));
+
       /* A2: Rotate lines */
-      for (j = row1, i = j + count; i <= row2; i++, j++)
-        {
-          screen.tlen[j] = screen.tlen[i];
-          screen.text[j] = screen.text[i];
-          screen.rend[j] = screen.rend[i];
-        }
+      i = row2 - row1 - count + 1;
+      memmove (screen.tlen + row1, screen.tlen + row1 + count, i * sizeof (int16_t));
+      memmove (screen.text + row1, screen.text + row1 + count, i * sizeof (text_t *));
+      memmove (screen.rend + row1, screen.rend + row1 + count, i * sizeof (rend_t *));
+
       j = row2 - count + 1, i = count;
     }
   else /* if (j < 0) */
@@ -753,6 +754,7 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
           buf_text[i] = screen.text[j];
           buf_rend[i] = screen.rend[j];
         }
+
       /* B2: Rotate lines */
       for (j = row2, i = j - count; i >= row1; i--, j--)
         {
@@ -760,26 +762,18 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
           screen.text[j] = screen.text[i];
           screen.rend[j] = screen.rend[i];
         }
+
       j = row1, i = count;
       count = -count;
     }
 
   /* C: Resurrect lines */
-  for (; i--; j++)
-    {
-      screen.tlen[j] = 0;
-      screen.text[j] = buf_text[i];
-      screen.rend[j] = buf_rend[i];
-
-      if (!spec)              /* line length may not equal TermWin.ncol */
-        scr_blank_screen_mem (screen.text, screen.rend,
-                              (unsigned int)j, rstyle);
-    }
-
-#ifdef RXVT_GRAPHICS
-  if (rxvt_Gr_Displayed (this))
-    rxvt_Gr_scroll(this, count);
-#endif
+  memset (screen.tlen + j, 0, i * sizeof (int16_t));
+  memcpy (screen.text + j, buf_text, i * sizeof (text_t *));
+  memcpy (screen.rend + j, buf_rend, i * sizeof (text_t *));
+  if (!spec) /* line length may not equal TermWin.ncol */
+    for (; i--; j++)
+      scr_blank_screen_mem (screen.text, screen.rend, (unsigned int)j, rstyle);
 
   return count;
 }
@@ -788,160 +782,257 @@ rxvt_term::scr_scroll_text (int row1, int row2, int count, int spec)
 /*
  * Add text given in <str> of length <len> to screen struct
  */
-/* EXTPROTO */
 void
-rxvt_scr_add_lines(pR_ const uint32_t *str, int nlines, int len)
+rxvt_term::scr_add_lines (const unicode_t *str, int nlines, int len)
 {
-    unsigned char   checksel, clearsel;
-    uint32_t        c;
-    int             i, row, last_col;
-    text_t         *stp;
-    rend_t         *srp;
+  unsigned char checksel;
+  unicode_t c;
+  int i, row, last_col;
+  text_t *stp;
+  rend_t *srp;
 
-    if (len <= 0)               /* sanity */
-        return;
+  if (len <= 0)               /* sanity */
+    return;
 
-    R->want_refresh = 1;
-    last_col = R->TermWin.ncol;
-
-    D_SCREEN((stderr, "rxvt_scr_add_lines(%d,%d)", nlines, len));
-    ZERO_SCROLLBACK(R);
-    if (nlines > 0) {
-        nlines += (R->screen.cur.row - R->screen.bscroll);
-        if ((nlines > 0)
-            && (R->screen.tscroll == 0)
-            && (R->screen.bscroll == (R->TermWin.nrow - 1))) {
-            /* _at least_ this many lines need to be scrolled */
-            R->scr_scroll_text(R->screen.tscroll, R->screen.bscroll, nlines, 0);
-            R->screen.cur.row -= nlines;
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
+  last_col = TermWin.ncol;
+
+  if (nlines > 0)
+    {
+      nlines += screen.cur.row - screen.bscroll;
+      if ((nlines > 0)
+          && (screen.tscroll == 0)
+          && (screen.bscroll == (TermWin.nrow - 1)))
+        {
+          /* _at least_ this many lines need to be scrolled */
+          scr_scroll_text (screen.tscroll, screen.bscroll, nlines, 0);
+          screen.cur.row -= nlines;
         }
     }
+
 #ifdef DEBUG_STRICT
-    assert(R->screen.cur.col < last_col);
-    assert((R->screen.cur.row < R->TermWin.nrow)
-           && (R->screen.cur.row >= -(int32_t)R->TermWin.nscrolled));
+  assert (screen.cur.col < last_col);
+  assert ((screen.cur.row < TermWin.nrow)
+          && (screen.cur.row >= - (int32_t)TermWin.nscrolled));
 #else                           /* drive with your eyes closed */
-    MIN_IT(R->screen.cur.col, last_col - 1);
-    MIN_IT(R->screen.cur.row, (int32_t)R->TermWin.nrow - 1);
-    MAX_IT(R->screen.cur.row, -(int32_t)R->TermWin.nscrolled);
+  MIN_IT (screen.cur.col, last_col - 1);
+  MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
+  MAX_IT (screen.cur.row, - (int32_t)TermWin.nscrolled);
 #endif
-    row = R->screen.cur.row + R->TermWin.saveLines;
+  row = screen.cur.row + TermWin.saveLines;
 
-    checksel = (R->selection.op
-                && R->current_screen == R->selection.screen) ? 1 : 0;
-    clearsel = 0;
+  checksel = selection.op && current_screen == selection.screen ? 1 : 0;
 
-    stp = R->screen.text[row];
-    srp = R->screen.rend[row];
+  stp = screen.text[row];
+  srp = screen.rend[row];
 
-    for (i = 0; i < len;) {
-        c = str[i++];
-        switch (c) {
-        case '\t':
-            rxvt_scr_tab (aR_ 1);
-            continue;
-        case '\n':
-            if (R->screen.tlen[row] != -1)      /* XXX: think about this */
-                MAX_IT(R->screen.tlen[row], R->screen.cur.col);
-            R->screen.flags &= ~Screen_WrapNext;
-            if (R->screen.cur.row == R->screen.bscroll)
-                R->scr_scroll_text (R->screen.tscroll, R->screen.bscroll, 1, 0);
-            else if (R->screen.cur.row < (R->TermWin.nrow - 1))
-                row = (++R->screen.cur.row) + R->TermWin.saveLines;
-            stp = R->screen.text[row];  /* _must_ refresh */
-            srp = R->screen.rend[row];  /* _must_ refresh */
-            continue;
-        case '\r':
-            if (R->screen.tlen[row] != -1)      /* XXX: think about this */
-                MAX_IT(R->screen.tlen[row], R->screen.cur.col);
-            R->screen.flags &= ~Screen_WrapNext;
-            R->screen.cur.col = 0;
-            continue;
-        default:
-            if (c == 127)
-                continue;       /* yummmm..... */
-            break;
+  while (len--)
+    {
+      c = *str++;
+
+      if (c < 0x20)
+        switch (c)
+          {
+            case C0_HT:
+              scr_tab (1, true);
+              continue;
+
+            case C0_LF:
+              if (screen.tlen[row] != -1)      /* XXX: think about this */
+                MAX_IT (screen.tlen[row], screen.cur.col);
+
+              screen.flags &= ~Screen_WrapNext;
+
+              if (screen.cur.row == screen.bscroll)
+                scr_scroll_text (screen.tscroll, screen.bscroll, 1, 0);
+              else if (screen.cur.row < (TermWin.nrow - 1))
+                row = (++screen.cur.row) + TermWin.saveLines;
+
+              stp = screen.text[row];  /* _must_ refresh */
+              srp = screen.rend[row];  /* _must_ refresh */
+              continue;
+
+            case C0_CR:
+              if (screen.tlen[row] != -1)      /* XXX: think about this */
+                MAX_IT (screen.tlen[row], screen.cur.col);
+
+              screen.flags &= ~Screen_WrapNext;
+              screen.cur.col = 0;
+              continue;
+          }
+
+      if (checksel            /* see if we're writing within selection */
+          && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
+          && ROWCOL_IS_BEFORE (screen.cur, selection.end))
+        {
+          checksel = 0;
+          /*
+           * If we wrote anywhere in the selected area, kill the selection
+           * XXX: should we kill the mark too?  Possibly, but maybe that
+           *      should be a similar check.
+           */
+          CLEAR_SELECTION ();
         }
 
-        if (checksel            /* see if we're writing within selection */
-            && !ROWCOL_IS_BEFORE(R->screen.cur, R->selection.beg)
-            && ROWCOL_IS_BEFORE(R->screen.cur, R->selection.end)) {
-            checksel = 0;
-            clearsel = 1;
+      if (screen.flags & Screen_WrapNext)
+        {
+          screen.tlen[row] = -1;
+
+          scr_do_wrap (); row = screen.cur.row + TermWin.saveLines;
+
+          stp = screen.text[row];  /* _must_ refresh */
+          srp = screen.rend[row];  /* _must_ refresh */
         }
-        if (R->screen.flags & Screen_WrapNext) {
-            R->screen.tlen[row] = -1;
-            if (R->screen.cur.row == R->screen.bscroll)
-                R->scr_scroll_text(R->screen.tscroll, R->screen.bscroll, 1, 0);
-            else if (R->screen.cur.row < (R->TermWin.nrow - 1))
-                row = (++R->screen.cur.row) + R->TermWin.saveLines;
-            stp = R->screen.text[row];  /* _must_ refresh */
-            srp = R->screen.rend[row];  /* _must_ refresh */
-            R->screen.cur.col = 0;
-            R->screen.flags &= ~Screen_WrapNext;
+
+      // rely on wcwidth to tell us the character width, at least for non-latin1
+      // do wcwidth before further replacements, as wcwidth says that line-drawing
+      // characters have width -1 (DOH!) on GNU/Linux sometimes.
+      int width = c < 0x100 ? 1 : wcwidth (c);
+
+      if (charsets[screen.charset] == '0') // DEC SPECIAL
+        {
+          // vt100 special graphics and line drawing
+          // 5f-7e standard vt100
+          // 40-5e rxvt extension for extra curses acs chars
+          static uint16_t vt100_0[63] = { // 40 .. 7e
+            0x0000, 0x2191, 0x2193, 0x2192, 0x2190, 0x2588, 0x259a, 0x2603, // 40-47 hi mr. snowman!
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 48-4f
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, // 50-57
+            0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0020, // 58-5f
+            0x25c6, 0x2592, 0x2409, 0x240c, 0x240d, 0x240a, 0x00b0, 0x00b1, // 60-67
+            0x2424, 0x240b, 0x2518, 0x2510, 0x250c, 0x2514, 0x253c, 0x23ba, // 68-6f
+            0x23bb, 0x2500, 0x23bc, 0x23bd, 0x251c, 0x2524, 0x2534, 0x252c, // 70-77
+            0x2502, 0x2264, 0x2265, 0x03c0, 0x2260, 0x00a3, 0x00b7,         // 78-7e
+          };
+
+          if (c >= 0x40 && c <= 0x7e && vt100_0[c - 0x40])
+            {
+              c = vt100_0[c - 0x40];
+              width = 1;
+            }
         }
-        if (R->screen.flags & Screen_Insert)
-            rxvt_scr_insdel_chars(aR_ 1, INSERT);
 
-        if (R->charsets[R->screen.charset] == '0') // DEC SPECIAL
-          switch (c)
+      if (screen.flags & Screen_Insert)
+        scr_insdel_chars (width, INSERT);
+
+      if (width != 0)
+        {
+          // some utf-8 decoders decode surrogate characters.
+          if (0xd800 <= c && c <= 0xdfff)
+            c = 0xfffd;
+
+#if !UNICODE_3
+          // trim characters we can't store directly :(
+          if (c >= 0x10000)
+# if ENABLE_COMBINING
+            c = rxvt_composite.compose (c); // map to lower 16 bits
+# else
+            c = 0xfffd;
+# endif
+#endif
+
+          // nuke the character at this position, if required
+          if (stp[screen.cur.col] == NOCHAR
+              || (screen.cur.col < TermWin.ncol - 1
+                  && stp[screen.cur.col + 1] == NOCHAR))
             {
-              case '+': c = 0x2192; break; case ',': c = 0x2190; break; case '-': c = 0x2191; break;
-              case '.': c = 0x2193; break; case '0': c = 0x25ae; break; case '`': c = 0x25c6; break;
-              case 'a': c = 0x2592; break; case 'f': c = 0x00b0; break; case 'g': c = 0x00b1; break;
-              case 'h': c = 0x2592; break; case 'i': c = 0x2603; break; case 'j': c = 0x2518; break;
-              case 'k': c = 0x2510; break; case 'l': c = 0x250c; break; case 'm': c = 0x2514; break;
-              case 'n': c = 0x253c; break; case 'o': c = 0x23ba; break; case 'p': c = 0x23bb; break;
-              case 'q': c = 0x2500; break; case 'r': c = 0x23bc; break; case 's': c = 0x23bd; break;
-              case 't': c = 0x251c; break; case 'u': c = 0x2524; break; case 'v': c = 0x2534; break;
-              case 'w': c = 0x252c; break; case 'x': c = 0x2502; break; case 'y': c = 0x2264; break;
-              case 'z': c = 0x2265; break; case '{': c = 0x03c0; break; case '|': c = 0x2260; break;
-              case '}': c = 0x00a3; break; case '~': c = 0x00b7; break;
+              int col = screen.cur.col;
+
+              // find begin
+              while (col > 0 && stp[col] == NOCHAR)
+                col--;
+
+              rend_t rend = SET_FONT (srp[col], FONTSET (srp[col])->find_font (' '));
+
+              // found begin, nuke
+              do {
+                stp[col] = ' ';
+                srp[col] = rend;
+                col++;
+              } while (col < TermWin.ncol && stp[col] == NOCHAR);
             }
 
-        rend_t rend = SET_FONT (R->rstyle, R->TermWin.fontset->find_font (c));
-        // rely on wcwidth to tell us the character width, at least for non-ascii
-        int width = c <= 128 ? 1 : wcwidth (c);
+          rend_t rend = SET_FONT (rstyle, FONTSET (rstyle)->find_font (c));
 
-        // width -1 characters (e.g. combining chars) are ignored currently.
-        if (width > 0)
           do
             {
-              stp[R->screen.cur.col] = c;
-              srp[R->screen.cur.col] = rend;
+              stp[screen.cur.col] = c;
+              srp[screen.cur.col] = rend;
 
-              if (R->screen.cur.col < last_col - 1)
-                R->screen.cur.col++;
+              if (screen.cur.col < last_col - 1)
+                screen.cur.col++;
               else
                 {
-                  R->screen.tlen[row] = last_col;
-                  if (R->screen.flags & Screen_Autowrap)
-                    R->screen.flags |= Screen_WrapNext;
+                  screen.tlen[row] = last_col;
+                  if (screen.flags & Screen_Autowrap)
+                    screen.flags |= Screen_WrapNext;
                   break;
                 }
 
               c = NOCHAR;
             }
           while (--width > 0);
-        else
-          1; /* handle combining character etc. here. */
-    }
 
-    if (R->screen.tlen[row] != -1)      /* XXX: think about this */
-      MAX_IT(R->screen.tlen[row], R->screen.cur.col);
+          // pad with spaces when overwriting wide character with smaller one
+          if (!width)
+            for (int c = screen.cur.col; c < last_col && stp[c] == NOCHAR; c++)
+              {
+                stp[c] = ' ';
+                srp[c] = rend;
+              }
+        }
+      else if (width == 0)
+        {
+#if ENABLE_COMBINING
+          // handle combining characters
+          // we just tag the accent on the previous on-screen character.
+          // this is arguably not correct, but also arguably not wrong.
+          // we don't handle double-width characters nicely yet.
 
-/*
- * If we wrote anywhere in the selected area, kill the selection
- * XXX: should we kill the mark too?  Possibly, but maybe that
- *      should be a similar check.
- */
-    if (clearsel)
-        CLEAR_SELECTION(R);
+          text_t *tp;
+          rend_t *rp;
+
+          if (screen.cur.col > 0)
+            {
+              tp = stp + screen.cur.col - 1;
+              rp = srp + screen.cur.col - 1;
+
+              while (*tp == NOCHAR && tp > stp)
+                tp--, rp--;
+            }
+          else if (screen.cur.row > 0
+                   && screen.tlen [screen.cur.row - 1 + TermWin.saveLines] == -1)
+            {
+              int line = screen.cur.row - 1 + TermWin.saveLines;
+
+              tp = screen.text[line] + last_col - 1;
+              rp = screen.rend[line] + last_col - 1;
+
+              while (*tp == NOCHAR && tp > screen.text[line])
+                tp--, rp--;
+            }
+          else
+            continue;
+
+          // first try to find a precomposed character
+          unicode_t n = rxvt_compose (*tp, c);
+          if (n == NOCHAR)
+            n = rxvt_composite.compose (*tp, c);
+
+          *tp = n;
+          *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
+#endif
+        }
+    }
+
+  if (screen.tlen[row] != -1)      /* XXX: think about this */
+    MAX_IT (screen.tlen[row], screen.cur.col);
 
 #ifdef DEBUG_STRICT
-    assert(R->screen.cur.row >= 0);
+  assert (screen.cur.row >= 0);
 #else                           /* drive with your eyes closed */
-    MAX_IT(R->screen.cur.row, 0);
+  MAX_IT (screen.cur.row, 0);
 #endif
 }
 
@@ -950,22 +1041,26 @@ rxvt_scr_add_lines(pR_ const uint32_t *str, int nlines, int len)
  * Process Backspace.  Move back the cursor back a position, wrap if have to
  * XTERM_SEQ: CTRL-H
  */
-/* EXTPROTO */
 void
-rxvt_scr_backspace(pR)
+rxvt_term::scr_backspace ()
 {
-    R->want_refresh = 1;
-    if (R->screen.cur.col == 0) {
-        if (R->screen.cur.row > 0) {
+  want_refresh = 1;
+
+  if (screen.cur.col == 0)
+    {
+      if (screen.cur.row > 0)
+        {
 #ifdef TERMCAP_HAS_BW
-            R->screen.cur.col = R->TermWin.ncol - 1;
-            R->screen.cur.row--;
-            return;
+          screen.cur.col = TermWin.ncol - 1;
+          screen.cur.row--;
+          return;
 #endif
         }
-    } else if ((R->screen.flags & Screen_WrapNext) == 0)
-        rxvt_scr_gotorc(aR_ 0, -1, RELATIVE);
-    R->screen.flags &= ~Screen_WrapNext;
+    }
+  else if (!(screen.flags & Screen_WrapNext))
+    scr_gotorc (0, -1, RELATIVE);
+
+  screen.flags &= ~Screen_WrapNext;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -974,38 +1069,75 @@ rxvt_scr_backspace(pR)
  * count: +ve = forward; -ve = backwards
  * XTERM_SEQ: CTRL-I
  */
-/* EXTPROTO */
 void
-rxvt_scr_tab(pR_ int count)
+rxvt_term::scr_tab (int count, bool ht)
 {
-    int             i, x;
+  int i, x;
 
-    D_SCREEN((stderr, "rxvt_scr_tab(%d)", count));
-    R->want_refresh = 1;
-    i = x = R->screen.cur.col;
-    if (count == 0)
-        return;
-    else if (count > 0) {
-        for (; ++i < R->TermWin.ncol; )
-            if (R->tabs[i]) {
-                x = i;
-                if (!--count)
-                    break;
-            }
-        if (count)
-            x = R->TermWin.ncol - 1;
-    } else /* if (count < 0) */ {
-        for (; --i >= 0; )
-            if (R->tabs[i]) {
-                x = i;
-                if (!++count)
-                    break;
+  want_refresh = 1;
+  i = x = screen.cur.col;
+
+  if (count == 0)
+    return;
+  else if (count > 0)
+    {
+      int row = TermWin.saveLines + screen.cur.row;
+      text_t *tp = screen.text[row];
+      rend_t *rp = screen.rend[row];
+      rend_t base_rend = rp[i];
+      ht &= tp[i] == ' ';
+
+      for (; ++i < TermWin.ncol; )
+        if (tabs[i])
+          {
+            x = i;
+            if (!--count)
+              break;
+          }
+        else 
+          ht &= tp[i] == ' '
+                && RS_SAME (rp[i], base_rend);
+
+      if (count)
+        x = TermWin.ncol - 1;
+
+      // store horizontal tab commands as characters inside the text
+      // buffer so they can be selected and pasted.
+      if (ht && options & Opt_pastableTabs)
+        {
+          base_rend = SET_FONT (base_rend, 0);
+
+          if (screen.tlen[row] != -1)      /* XXX: think about this */
+            MAX_IT (screen.tlen[row], x);
+
+          i = screen.cur.col;
+
+          tp[i] = '\t';
+          rp[i] = base_rend;
+
+          while (++i < x)
+            {
+              tp[i] = NOCHAR;
+              rp[i] = base_rend;
             }
-        if (count)
-            x = 0;
+        }
+    }
+  else /* if (count < 0) */
+    {
+      for (; --i >= 0; )
+        if (tabs[i])
+          {
+            x = i;
+            if (!++count)
+              break;
+          }
+
+      if (count)
+        x = 0;
     }
-    if (x != R->screen.cur.col)
-        rxvt_scr_gotorc(aR_ 0, x, R_RELATIVE);
+
+  if (x != screen.cur.col)
+    scr_gotorc (0, x, R_RELATIVE);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1015,17 +1147,18 @@ rxvt_scr_tab(pR_ int count)
  * Move cursor left in row.  If we're at the left boundary, shift everything
  * in that row right.  Clear left column.
  */
-#ifndef NO_FRILLS
-/* EXTPROTO */
+#if ENABLE_FRILLS
 void
-rxvt_scr_backindex(pR)
+rxvt_term::scr_backindex ()
 {
-    if (R->screen.cur.col > 0)
-        rxvt_scr_gotorc(aR_ 0, -1, R_RELATIVE | C_RELATIVE);
-    else {
-        if (R->screen.tlen[R->screen.cur.row + R->TermWin.saveLines] == 0)
-            return;             /* um, yeah? */
-        rxvt_scr_insdel_chars(aR_ 1, INSERT);
+  if (screen.cur.col > 0)
+    scr_gotorc (0, -1, R_RELATIVE | C_RELATIVE);
+  else
+    {
+      if (screen.tlen[screen.cur.row + TermWin.saveLines] == 0)
+        return;             /* um, yeah? */
+
+      scr_insdel_chars (1, INSERT);
     }
 }
 #endif
@@ -1036,24 +1169,26 @@ rxvt_scr_backindex(pR)
  * Move cursor right in row.  If we're at the right boundary, shift everything
  * in that row left.  Clear right column.
  */
-#ifndef NO_FRILLS
-/* EXTPROTO */
+#if ENABLE_FRILLS
 void
-rxvt_scr_forwardindex(pR)
+rxvt_term::scr_forwardindex ()
 {
-    int             row;
+  int             row;
+
+  if (screen.cur.col < TermWin.ncol - 1)
+    scr_gotorc (0, 1, R_RELATIVE | C_RELATIVE);
+  else
+    {
+      row = screen.cur.row + TermWin.saveLines;
 
-    if (R->screen.cur.col < R->TermWin.ncol - 1)
-        rxvt_scr_gotorc(aR_ 0, 1, R_RELATIVE | C_RELATIVE);
-    else {
-        row = R->screen.cur.row + R->TermWin.saveLines;
-        if (R->screen.tlen[row] == 0)
-            return;             /* um, yeah? */
-        else if (R->screen.tlen[row] == -1)
-            R->screen.tlen[row] = R->TermWin.ncol;
-        rxvt_scr_gotorc(aR_ 0, 0, R_RELATIVE);
-        rxvt_scr_insdel_chars(aR_ 1, DELETE);
-        rxvt_scr_gotorc(aR_ 0, R->TermWin.ncol - 1, R_RELATIVE);
+      if (screen.tlen[row] == 0)
+        return;             /* um, yeah? */
+      else if (screen.tlen[row] == -1)
+        screen.tlen[row] = TermWin.ncol;
+
+      scr_gotorc (0, 0, R_RELATIVE);
+      scr_insdel_chars (1, DELETE);
+      scr_gotorc (0, TermWin.ncol - 1, R_RELATIVE);
     }
 }
 #endif
@@ -1062,80 +1197,77 @@ rxvt_scr_forwardindex(pR)
 /*
  * Goto Row/Column
  */
-/* EXTPROTO */
 void
-rxvt_scr_gotorc(pR_ int row, int col, int relative)
+rxvt_term::scr_gotorc (int row, int col, int relative)
 {
-    R->want_refresh = 1;
-    ZERO_SCROLLBACK(R);
-#ifdef RXVT_GRAPHICS
-    if (rxvt_Gr_Displayed(aR))
-        rxvt_Gr_scroll(aR_ 0);
-#endif
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-    D_SCREEN((stderr, "rxvt_scr_gotorc(r:%s%d,c:%s%d): from (r:%d,c:%d)", (relative & R_RELATIVE ? "+" : ""), row, (relative & C_RELATIVE ? "+" : ""), col, R->screen.cur.row, R->screen.cur.col));
+  screen.cur.col = relative & C_RELATIVE ? screen.cur.col + col : col;
+  MAX_IT (screen.cur.col, 0);
+  MIN_IT (screen.cur.col, (int32_t)TermWin.ncol - 1);
 
-    R->screen.cur.col = ((relative & C_RELATIVE) ? (R->screen.cur.col + col)
-                                                 : col);
-    MAX_IT(R->screen.cur.col, 0);
-    MIN_IT(R->screen.cur.col, (int32_t)R->TermWin.ncol - 1);
+  screen.flags &= ~Screen_WrapNext;
 
-    R->screen.flags &= ~Screen_WrapNext;
-    if (relative & R_RELATIVE) {
-        if (row > 0) {
-            if (R->screen.cur.row <= R->screen.bscroll
-                && (R->screen.cur.row + row) > R->screen.bscroll)
-                R->screen.cur.row = R->screen.bscroll;
-            else
-                R->screen.cur.row += row;
-        } else if (row < 0) {
-            if (R->screen.cur.row >= R->screen.tscroll
-                && (R->screen.cur.row + row) < R->screen.tscroll)
-                R->screen.cur.row = R->screen.tscroll;
-            else
-                R->screen.cur.row += row;
+  if (relative & R_RELATIVE)
+    {
+      if (row > 0)
+        {
+          if (screen.cur.row <= screen.bscroll
+              && (screen.cur.row + row) > screen.bscroll)
+            screen.cur.row = screen.bscroll;
+          else
+            screen.cur.row += row;
         }
-    } else {
-        if (R->screen.flags & Screen_Relative) {        /* relative origin mode */
-            R->screen.cur.row = row + R->screen.tscroll;
-            MIN_IT(R->screen.cur.row, R->screen.bscroll);
-        } else
-            R->screen.cur.row = row;
+      else if (row < 0)
+        {
+          if (screen.cur.row >= screen.tscroll
+              && (screen.cur.row + row) < screen.tscroll)
+            screen.cur.row = screen.tscroll;
+          else
+            screen.cur.row += row;
+        }
+    }
+  else
+    {
+      if (screen.flags & Screen_Relative)
+        {        /* relative origin mode */
+          screen.cur.row = row + screen.tscroll;
+          MIN_IT (screen.cur.row, screen.bscroll);
+        }
+      else
+        screen.cur.row = row;
     }
-    MAX_IT(R->screen.cur.row, 0);
-    MIN_IT(R->screen.cur.row, (int32_t)R->TermWin.nrow - 1);
+
+  MAX_IT (screen.cur.row, 0);
+  MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
 }
 
 /* ------------------------------------------------------------------------- */
 /*
- * direction  should be UP or DN
+ * direction should be UP or DN
  */
-/* EXTPROTO */
 void
-rxvt_scr_index(pR_ enum page_dirn direction)
+rxvt_term::scr_index (enum page_dirn direction)
 {
-    int             dirn;
+  int dirn;
 
-    R->want_refresh = 1;
-    dirn = ((direction == UP) ? 1 : -1);
-    D_SCREEN((stderr, "rxvt_scr_index(%d)", dirn));
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-    ZERO_SCROLLBACK(R);
+  dirn = ((direction == UP) ? 1 : -1);
 
-#ifdef RXVT_GRAPHICS
-    if (rxvt_Gr_Displayed(aR))
-        rxvt_Gr_scroll(aR_ 0);
-#endif
+  screen.flags &= ~Screen_WrapNext;
 
-    R->screen.flags &= ~Screen_WrapNext;
-    if ((R->screen.cur.row == R->screen.bscroll && direction == UP)
-        || (R->screen.cur.row == R->screen.tscroll && direction == DN))
-        R->scr_scroll_text(R->screen.tscroll, R->screen.bscroll, dirn, 0);
-    else
-        R->screen.cur.row += dirn;
-    MAX_IT(R->screen.cur.row, 0);
-    MIN_IT(R->screen.cur.row, (int32_t)R->TermWin.nrow - 1);
-    rxvt_selection_check(aR_ 0);
+  if ((screen.cur.row == screen.bscroll && direction == UP)
+      || (screen.cur.row == screen.tscroll && direction == DN))
+    scr_scroll_text (screen.tscroll, screen.bscroll, dirn, 0);
+  else
+    screen.cur.row += dirn;
+
+  MAX_IT (screen.cur.row, 0);
+  MIN_IT (screen.cur.row, (int32_t)TermWin.nrow - 1);
+  selection_check (0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1145,60 +1277,50 @@ rxvt_scr_index(pR_ enum page_dirn direction)
  * XTERM_SEQ: Clear line to left : ESC [ 1 K
  * XTERM_SEQ: Clear whole line   : ESC [ 2 K
  */
-/* EXTPROTO */
 void
-rxvt_scr_erase_line(pR_ int mode)
+rxvt_term::scr_erase_line (int mode)
 {
   unsigned int row, col, num;
 
-  R->want_refresh = 1;
-  D_SCREEN((stderr, "rxvt_scr_erase_line(%d) at screen row: %d", mode, R->screen.cur.row));
-  ZERO_SCROLLBACK (R);
-
-#ifdef RXVT_GRAPHICS
-  if (rxvt_Gr_Displayed (aR))
-    rxvt_Gr_scroll (aR_ 0);
-#endif
-
-  rxvt_selection_check (aR_ 1);
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-  R->screen.flags &= ~Screen_WrapNext;
+  selection_check (1);
 
-  row = R->TermWin.saveLines + R->screen.cur.row;
+  row = TermWin.saveLines + screen.cur.row;
   switch (mode)
     {
       case 0:                     /* erase to end of line */
-        col = R->screen.cur.col;
-        num = R->TermWin.ncol - col;
-        MIN_IT(R->screen.tlen[row], (int16_t)col);
-        if (ROWCOL_IN_ROW_AT_OR_AFTER(R->selection.beg, R->screen.cur)
-            || ROWCOL_IN_ROW_AT_OR_AFTER(R->selection.end, R->screen.cur))
-          CLEAR_SELECTION(R);
+        col = screen.cur.col;
+        num = TermWin.ncol - col;
+        MIN_IT (screen.tlen[row], (int16_t)col);
+        if (ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur)
+            || ROWCOL_IN_ROW_AT_OR_AFTER (selection.end, screen.cur))
+          CLEAR_SELECTION ();
         break;
       case 1:                     /* erase to beginning of line */
         col = 0;
-        num = R->screen.cur.col + 1;
-        if (ROWCOL_IN_ROW_AT_OR_BEFORE(R->selection.beg, R->screen.cur)
-            || ROWCOL_IN_ROW_AT_OR_BEFORE(R->selection.end, R->screen.cur))
-          CLEAR_SELECTION(R);
+        num = screen.cur.col + 1;
+        if (ROWCOL_IN_ROW_AT_OR_BEFORE (selection.beg, screen.cur)
+            || ROWCOL_IN_ROW_AT_OR_BEFORE (selection.end, screen.cur))
+          CLEAR_SELECTION ();
         break;
       case 2:                     /* erase whole line */
         col = 0;
-        num = R->TermWin.ncol;
-        R->screen.tlen[row] = 0;
-        if (R->selection.beg.row <= R->screen.cur.row
-            && R->selection.end.row >= R->screen.cur.row)
-          CLEAR_SELECTION(R);
+        num = TermWin.ncol;
+        screen.tlen[row] = 0;
+        if (selection.beg.row <= screen.cur.row
+            && selection.end.row >= screen.cur.row)
+          CLEAR_SELECTION ();
         break;
       default:
         return;
     }
 
-  if (R->screen.text[row])
-    R->scr_blank_line (&(R->screen.text[row][col]),
-                       &(R->screen.rend[row][col]), num, R->rstyle);
+  if (screen.text[row])
+    scr_blank_line (&screen.text[row][col], &screen.rend[row][col], num, rstyle);
   else
-    R->scr_blank_screen_mem (R->screen.text, R->screen.rend, row, R->rstyle);
+    scr_blank_screen_mem (screen.text, screen.rend, row, rstyle);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1211,68 +1333,72 @@ rxvt_scr_erase_line(pR_ int mode)
 void
 rxvt_term::scr_erase_screen (int mode)
 {
-    int             num;
-    int32_t         row, row_offset;
-    rend_t          ren;
-    XGCValues       gcvalue;
+  int num;
+  int32_t row, row_offset;
+  rend_t ren;
+  XGCValues gcvalue;
+
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-    want_refresh = 1;
-    D_SCREEN((stderr, "rxvt_scr_erase_screen(%d) at screen row: %d", mode, screen.cur.row));
-    ZERO_SCROLLBACK(this);
-    row_offset = (int32_t)TermWin.saveLines;
+  row_offset = (int32_t)TermWin.saveLines;
 
-    switch (mode) {
-    case 0:                     /* erase to end of screen */
-        rxvt_selection_check(this,1);
-        rxvt_scr_erase_line(this,0);
+  switch (mode)
+    {
+      case 0:                     /* erase to end of screen */
+        selection_check (1);
+        scr_erase_line (0);
         row = screen.cur.row + 1;    /* possible OOB */
         num = TermWin.nrow - row;
         break;
-    case 1:                     /* erase to beginning of screen */
-        rxvt_selection_check(this,3);
-        rxvt_scr_erase_line(this,1);
+      case 1:                     /* erase to beginning of screen */
+        selection_check (3);
+        scr_erase_line (1);
         row = 0;
         num = screen.cur.row;
         break;
-    case 2:                     /* erase whole screen */
-        rxvt_selection_check (this, 3);
-#ifdef RXVT_GRAPHICS
-        rxvt_Gr_ClearScreen (this);
-#endif
+      case 2:                     /* erase whole screen */
+        selection_check (3);
         row = 0;
         num = TermWin.nrow;
         break;
-    default:
+      default:
         return;
     }
-    refresh_type |= REFRESH_BOUNDS;
-    if (selection.op && current_screen == selection.screen
-        && ((selection.beg.row >= row && selection.beg.row <= row + num)
-            || (selection.end.row >= row
-                && selection.end.row <= row + num)))
-        CLEAR_SELECTION (this);
-    if (row >= TermWin.nrow) /* Out Of Bounds */
-        return;
-    MIN_IT(num, (TermWin.nrow - row));
-    if (rstyle & (RS_RVid | RS_Uline))
-        ren = (rend_t) ~RS_None;
-    else if (GET_BASEBG(rstyle) == Color_bg) {
-        ren = DEFAULT_RSTYLE;
-        CLEAR_ROWS(row, num);
-    } else {
-        ren = (rstyle & (RS_fgMask | RS_bgMask));
-        gcvalue.foreground = PixColors[GET_BGCOLOR(rstyle)];
-        XChangeGC(Xdisplay, TermWin.gc, GCForeground, &gcvalue);
-        ERASE_ROWS(row, num);
-        gcvalue.foreground = PixColors[Color_fg];
-        XChangeGC(Xdisplay, TermWin.gc, GCForeground, &gcvalue);
-    }
-    for (; num--; row++) {
-        scr_blank_screen_mem (screen.text, screen.rend,
-                                 (unsigned int)(row + row_offset), rstyle);
-        screen.tlen[row + row_offset] = 0;
-        scr_blank_line (drawn_text[row], drawn_rend[row],
-                           (unsigned int)TermWin.ncol, ren);
+
+  if (selection.op && current_screen == selection.screen
+      && ((selection.beg.row >= row && selection.beg.row <= row + num)
+          || (selection.end.row >= row
+              && selection.end.row <= row + num)))
+    CLEAR_SELECTION ();
+
+  if (row >= TermWin.nrow) /* Out Of Bounds */
+    return;
+
+  MIN_IT (num, (TermWin.nrow - row));
+
+  if (rstyle & (RS_RVid | RS_Uline))
+    ren = (rend_t) ~RS_None;
+  else if (GET_BASEBG (rstyle) == Color_bg)
+    {
+      ren = DEFAULT_RSTYLE;
+      CLEAR_ROWS (row, num);
+    }
+  else
+    {
+      ren = rstyle & (RS_fgMask | RS_bgMask);
+      gcvalue.foreground = pix_colors[GET_BGCOLOR (rstyle)];
+      XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue);
+      ERASE_ROWS (row, num);
+      gcvalue.foreground = pix_colors[Color_fg];
+      XChangeGC (display->display, TermWin.gc, GCForeground, &gcvalue);
+    }
+
+  for (; num--; row++)
+    {
+      scr_blank_screen_mem (screen.text, screen.rend, (unsigned int) (row + row_offset), rstyle);
+      screen.tlen[row + row_offset] = 0;
+      scr_blank_line (drawn_text[row], drawn_rend[row], (unsigned int)TermWin.ncol, ren);
     }
 }
 
@@ -1281,24 +1407,25 @@ rxvt_term::scr_erase_screen (int mode)
  * Fill the screen with `E's
  * XTERM_SEQ: Screen Alignment Test: ESC # 8
  */
-/* EXTPROTO */
 void
-rxvt_scr_E(pR)
+rxvt_term::scr_E ()
 {
-    int             i, j, k;
-    rend_t         *r1, fs;
+  int             i, j, k;
+  rend_t         *r1, fs;
+
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-    R->want_refresh = 1;
-    R->num_scr_allow = 0;
-    ZERO_SCROLLBACK(R);
-    rxvt_selection_check(aR_ 3);
+  num_scr_allow = 0;
+  selection_check (3);
 
-    fs = SET_FONT (R->rstyle, R->TermWin.fontset->find_font ('E'));
-    for (k = R->TermWin.saveLines, i = R->TermWin.nrow; i--; k++) {
-        R->screen.tlen[k] = R->TermWin.ncol;    /* make the `E's selectable */
-        fill_text (R->screen.text[k], 'E', R->TermWin.ncol);
-        for (r1 = R->screen.rend[k], j = R->TermWin.ncol; j--; )
-            *r1++ = fs;
+  fs = SET_FONT (rstyle, FONTSET (rstyle)->find_font ('E'));
+  for (k = TermWin.saveLines, i = TermWin.nrow; i--; k++)
+    {
+      screen.tlen[k] = TermWin.ncol;    /* make the `E's selectable */
+      fill_text (screen.text[k], 'E', TermWin.ncol);
+      for (r1 = screen.rend[k], j = TermWin.ncol; j--; )
+        *r1++ = fs;
     }
 }
 
@@ -1306,129 +1433,137 @@ rxvt_scr_E(pR)
 /*
  * Insert/Delete <count> lines
  */
-/* EXTPROTO */
 void
-rxvt_scr_insdel_lines(pR_ int count, int insdel)
+rxvt_term::scr_insdel_lines (int count, int insdel)
 {
-    int             end;
+  int end;
 
-    ZERO_SCROLLBACK(R);
+  ZERO_SCROLLBACK ();
 
-#ifdef RXVT_GRAPHICS
-    if (rxvt_Gr_Displayed(aR))
-        rxvt_Gr_scroll(aR_ 0);
-#endif
+  selection_check (1);
 
-    rxvt_selection_check(aR_ 1);
+  if (screen.cur.row > screen.bscroll)
+    return;
 
-    if (R->screen.cur.row > R->screen.bscroll)
+  end = screen.bscroll - screen.cur.row + 1;
+  if (count > end)
+    {
+      if (insdel == DELETE)
         return;
-
-    end = R->screen.bscroll - R->screen.cur.row + 1;
-    if (count > end) {
-        if (insdel == DELETE)
-            return;
-        else if (insdel == INSERT)
-            count = end;
+      else if (insdel == INSERT)
+        count = end;
     }
-    R->screen.flags &= ~Screen_WrapNext;
 
-    R->scr_scroll_text(R->screen.cur.row, R->screen.bscroll, insdel * count, 0);
+  scr_do_wrap ();
+
+  scr_scroll_text (screen.cur.row, screen.bscroll, insdel * count, 0);
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Insert/Delete <count> characters from the current position
  */
-/* EXTPROTO */
 void
-rxvt_scr_insdel_chars(pR_ int count, int insdel)
+rxvt_term::scr_insdel_chars (int count, int insdel)
 {
-    int             col, row;
-    rend_t          tr;
-    text_t         *stp;
-    rend_t         *srp;
-    int16_t        *slp;
+  int col, row;
+  rend_t tr;
+  text_t *stp;
+  rend_t *srp;
+  int16_t *slp;
 
-    R->want_refresh = 1;
-    ZERO_SCROLLBACK(R);
+  want_refresh = 1;
+  ZERO_SCROLLBACK ();
 
-#ifdef RXVT_GRAPHICS
-    if (rxvt_Gr_Displayed(aR))
-        rxvt_Gr_scroll(aR_ 0);
-#endif
+  if (count <= 0)
+    return;
 
-    if (count <= 0)
-        return;
+  scr_do_wrap ();
+
+  selection_check (1);
+  MIN_IT (count, (TermWin.ncol - screen.cur.col));
 
-    rxvt_selection_check(aR_ 1);
-    MIN_IT(count, (R->TermWin.ncol - R->screen.cur.col));
+  row = screen.cur.row + TermWin.saveLines;
 
-    row = R->screen.cur.row + R->TermWin.saveLines;
-    R->screen.flags &= ~Screen_WrapNext;
+  stp = screen.text[row];
+  srp = screen.rend[row];
+  slp = &screen.tlen[row];
 
-    stp = R->screen.text[row];
-    srp = R->screen.rend[row];
-    slp = &(R->screen.tlen[row]);
-    switch (insdel) {
-    case INSERT:
-        for (col = R->TermWin.ncol - 1; (col - count) >= R->screen.cur.col;
-             col--) {
+  switch (insdel)
+    {
+      case INSERT:
+        for (col = TermWin.ncol - 1; (col - count) >= screen.cur.col; col--)
+          {
             stp[col] = stp[col - count];
             srp[col] = srp[col - count];
-        }
-        if (*slp != -1) {
+          }
+
+        if (*slp != -1)
+          {
             *slp += count;
-            MIN_IT(*slp, R->TermWin.ncol);
-        }
-        if (R->selection.op && R->current_screen == R->selection.screen
-            && ROWCOL_IN_ROW_AT_OR_AFTER(R->selection.beg, R->screen.cur)) {
-            if (R->selection.end.row != R->screen.cur.row
-                || (R->selection.end.col + count >= R->TermWin.ncol))
-                CLEAR_SELECTION(R);
-            else {              /* shift selection */
-                R->selection.beg.col += count;
-                R->selection.mark.col += count; /* XXX: yes? */
-                R->selection.end.col += count;
-            }
-        }
-        R->scr_blank_line (&(stp[R->screen.cur.col]), &(srp[R->screen.cur.col]),
-                           (unsigned int)count, R->rstyle);
-        break;
-    case ERASE:
-        R->screen.cur.col += count;     /* don't worry if > R->TermWin.ncol */
-        rxvt_selection_check(aR_ 1);
-        R->screen.cur.col -= count;
-        R->scr_blank_line (&(stp[R->screen.cur.col]), &(srp[R->screen.cur.col]),
-                           (unsigned int)count, R->rstyle);
+            MIN_IT (*slp, TermWin.ncol);
+          }
+
+        if (selection.op && current_screen == selection.screen
+            && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
+          {
+            if (selection.end.row != screen.cur.row
+                || (selection.end.col + count >= TermWin.ncol))
+              CLEAR_SELECTION ();
+            else
+              {              /* shift selection */
+                selection.beg.col  += count;
+                selection.mark.col += count; /* XXX: yes? */
+                selection.end.col  += count;
+              }
+          }
+
+        scr_blank_line (&stp[screen.cur.col], &srp[screen.cur.col],
+                        (unsigned int)count, rstyle);
+        break;
+
+      case ERASE:
+        screen.cur.col += count;     /* don't worry if > TermWin.ncol */
+        selection_check (1);
+        screen.cur.col -= count;
+        scr_blank_line (&stp[screen.cur.col], &srp[screen.cur.col],
+                        (unsigned int)count, rstyle);
         break;
-    case DELETE:
-        tr = srp[R->TermWin.ncol - 1]
-             & (RS_fgMask | RS_bgMask | RS_baseattrMask);
-        for (col = R->screen.cur.col; (col + count) < R->TermWin.ncol; col++) {
+
+      case DELETE:
+        tr = srp[TermWin.ncol - 1] & (RS_fgMask | RS_bgMask | RS_baseattrMask);
+
+        for (col = screen.cur.col; (col + count) < TermWin.ncol; col++)
+          {
             stp[col] = stp[col + count];
             srp[col] = srp[col + count];
-        }
-        R->scr_blank_line (&(stp[R->TermWin.ncol - count]),
-                           &(srp[R->TermWin.ncol - count]),
-                           (unsigned int)count, tr);
+          }
+
+        scr_blank_line (&stp[TermWin.ncol - count], &srp[TermWin.ncol - count],
+                        (unsigned int)count, tr);
+
         if (*slp == -1) /* break line continuation */
-            *slp = R->TermWin.ncol;
+          *slp = TermWin.ncol;
+        
         *slp -= count;
-        MAX_IT(*slp, 0);
-        if (R->selection.op && R->current_screen == R->selection.screen
-            && ROWCOL_IN_ROW_AT_OR_AFTER(R->selection.beg, R->screen.cur)) {
-            if (R->selection.end.row != R->screen.cur.row
-                || (R->screen.cur.col >= R->selection.beg.col - count)
-                || R->selection.end.col >= R->TermWin.ncol)
-                CLEAR_SELECTION(R);
-            else {
+        MAX_IT (*slp, 0);
+
+        if (selection.op && current_screen == selection.screen
+            && ROWCOL_IN_ROW_AT_OR_AFTER (selection.beg, screen.cur))
+          {
+            if (selection.end.row != screen.cur.row
+                || (screen.cur.col >= selection.beg.col - count)
+                || selection.end.col >= TermWin.ncol)
+              CLEAR_SELECTION ();
+            else
+              {
                 /* shift selection */
-                R->selection.beg.col -= count;
-                R->selection.mark.col -= count; /* XXX: yes? */
-                R->selection.end.col -= count;
-            }
-        }
+                selection.beg.col  -= count;
+                selection.mark.col -= count; /* XXX: yes? */
+                selection.end.col  -= count;
+              }
+          }
+
         break;
     }
 }
@@ -1438,17 +1573,18 @@ rxvt_scr_insdel_chars(pR_ int count, int insdel)
  * Set the scrolling region
  * XTERM_SEQ: Set region <top> - <bot> inclusive: ESC [ <top> ; <bot> r
  */
-/* EXTPROTO */
 void
-rxvt_scr_scroll_region(pR_ int top, int bot)
+rxvt_term::scr_scroll_region (int top, int bot)
 {
-    MAX_IT(top, 0);
-    MIN_IT(bot, (int)R->TermWin.nrow - 1);
-    if (top > bot)
-        return;
-    R->screen.tscroll = top;
-    R->screen.bscroll = bot;
-    rxvt_scr_gotorc(aR_ 0, 0, 0);
+  MAX_IT (top, 0);
+  MIN_IT (bot, (int)TermWin.nrow - 1);
+
+  if (top > bot)
+    return;
+
+  screen.tscroll = top;
+  screen.bscroll = bot;
+  scr_gotorc (0, 0, 0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1457,15 +1593,15 @@ rxvt_scr_scroll_region(pR_ int top, int bot)
  * XTERM_SEQ: Make cursor visible  : ESC [ ? 25 h
  * XTERM_SEQ: Make cursor invisible: ESC [ ? 25 l
  */
-/* EXTPROTO */
 void
-rxvt_scr_cursor_visible(pR_ int mode)
+rxvt_term::scr_cursor_visible (int mode)
 {
-    R->want_refresh = 1;
-    if (mode)
-        R->screen.flags |= Screen_VisibleCursor;
-    else
-        R->screen.flags &= ~Screen_VisibleCursor;
+  want_refresh = 1;
+
+  if (mode)
+    screen.flags |= Screen_VisibleCursor;
+  else
+    screen.flags &= ~Screen_VisibleCursor;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1474,14 +1610,13 @@ rxvt_scr_cursor_visible(pR_ int mode)
  * XTERM_SEQ: Set Wraparound  : ESC [ ? 7 h
  * XTERM_SEQ: Unset Wraparound: ESC [ ? 7 l
  */
-/* EXTPROTO */
 void
-rxvt_scr_autowrap(pR_ int mode)
+rxvt_term::scr_autowrap (int mode)
 {
-    if (mode)
-        R->screen.flags |= Screen_Autowrap;
-    else
-        R->screen.flags &= ~(Screen_Autowrap | Screen_WrapNext);
+  if (mode)
+    screen.flags |= Screen_Autowrap;
+  else
+    screen.flags &= ~(Screen_Autowrap | Screen_WrapNext);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1494,15 +1629,15 @@ rxvt_scr_autowrap(pR_ int mode)
  * XTERM_SEQ: Set Absolute: ESC [ ? 6 h
  * XTERM_SEQ: Set Relative: ESC [ ? 6 l
  */
-/* EXTPROTO */
 void
-rxvt_scr_relative_origin(pR_ int mode)
+rxvt_term::scr_relative_origin (int mode)
 {
-    if (mode)
-        R->screen.flags |= Screen_Relative;
-    else
-        R->screen.flags &= ~Screen_Relative;
-    rxvt_scr_gotorc(aR_ 0, 0, 0);
+  if (mode)
+    screen.flags |= Screen_Relative;
+  else
+    screen.flags &= ~Screen_Relative;
+
+  scr_gotorc (0, 0, 0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1511,14 +1646,13 @@ rxvt_scr_relative_origin(pR_ int mode)
  * XTERM_SEQ: Set Insert mode : ESC [ ? 4 h
  * XTERM_SEQ: Set Replace mode: ESC [ ? 4 l
  */
-/* EXTPROTO */
 void
-rxvt_scr_insert_mode(pR_ int mode)
+rxvt_term::scr_insert_mode (int mode)
 {
-    if (mode)
-        R->screen.flags |= Screen_Insert;
-    else
-        R->screen.flags &= ~Screen_Insert;
+  if (mode)
+    screen.flags |= Screen_Insert;
+  else
+    screen.flags &= ~Screen_Insert;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1528,14 +1662,13 @@ rxvt_scr_insert_mode(pR_ int mode)
  * XTERM_SEQ: Clear tab at current column: ESC [ 0 g
  * XTERM_SEQ: Clear all tabs             : ESC [ 3 g
  */
-/* EXTPROTO */
 void
-rxvt_scr_set_tab(pR_ int mode)
+rxvt_term::scr_set_tab (int mode)
 {
-    if (mode < 0)
-        MEMSET(R->tabs, 0, R->TermWin.ncol * sizeof(char));
-    else if (R->screen.cur.col < R->TermWin.ncol)
-        R->tabs[R->screen.cur.col] = (mode ? 1 : 0);
+  if (mode < 0)
+    memset (tabs, 0, TermWin.ncol * sizeof (char));
+  else if (screen.cur.col < TermWin.ncol)
+    tabs[screen.cur.col] = (mode ? 1 : 0);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1544,30 +1677,30 @@ rxvt_scr_set_tab(pR_ int mode)
  * XTERM_SEQ: Reverse video: ESC [ ? 5 h
  * XTERM_SEQ: Normal video : ESC [ ? 5 l
  */
-/* EXTPROTO */
 void
-rxvt_scr_rvideo_mode(pR_ int mode)
+rxvt_term::scr_rvideo_mode (int mode)
 {
-    XGCValues       gcvalue;
+  XGCValues gcvalue;
 
-    if (R->rvideo != mode) {
-        R->rvideo = mode;
-        SWAP_IT(R->PixColors[Color_fg], R->PixColors[Color_bg], rxvt_color);
-#if defined(XPM_BACKGROUND)
-        if (R->bgPixmap.pixmap == None)
+  if (rvideo != mode)
+    {
+      rvideo = mode;
+      SWAP_IT (pix_colors[Color_fg], pix_colors[Color_bg], rxvt_color);
+#if XPM_BACKGROUND
+      if (bgPixmap.pixmap == None)
 #endif
-#if defined(TRANSPARENT)
-            if (!(R->Options & Opt_transparent) || R->am_transparent == 0)
+#if TRANSPARENT
+        if (! (options & Opt_transparent) || am_transparent == 0)
 #endif
-            XSetWindowBackground(R->Xdisplay, R->TermWin.vt,
-                                 R->PixColors[Color_bg]);
+          XSetWindowBackground (display->display, TermWin.vt,
+                               pix_colors[Color_bg]);
 
-        gcvalue.foreground = R->PixColors[Color_fg];
-        gcvalue.background = R->PixColors[Color_bg];
-        XChangeGC(R->Xdisplay, R->TermWin.gc, GCBackground | GCForeground,
-                  &gcvalue);
-        R->scr_clear ();
-        R->scr_touch (true);
+      gcvalue.foreground = pix_colors[Color_fg];
+      gcvalue.background = pix_colors[Color_bg];
+      XChangeGC (display->display, TermWin.gc, GCBackground | GCForeground,
+                &gcvalue);
+      scr_clear ();
+      scr_touch (true);
     }
 }
 
@@ -1576,11 +1709,10 @@ rxvt_scr_rvideo_mode(pR_ int mode)
  * Report current cursor position
  * XTERM_SEQ: Report position: ESC [ 6 n
  */
-/* EXTPROTO */
 void
-rxvt_scr_report_position(pR)
+rxvt_term::scr_report_position ()
 {
-    R->tt_printf("\033[%d;%dR", R->screen.cur.row + 1, R->screen.cur.col + 1);
+  tt_printf ("\033[%d;%dR", screen.cur.row + 1, screen.cur.col + 1);
 }
 \f
 /* ------------------------------------------------------------------------- *
@@ -1590,24 +1722,24 @@ rxvt_scr_report_position(pR)
 /*
  * Set font style
  */
-/* INTPROTO */
 void
-rxvt_set_font_style(pR)
+rxvt_term::set_font_style ()
 {
-    switch (R->charsets[R->screen.charset]) {
-    case '0':                   /* DEC Special Character & Line Drawing Set */
+  switch (charsets[screen.charset])
+    {
+      case '0':                   /* DEC Special Character & Line Drawing Set */
         break;
-    case 'A':                   /* United Kingdom (UK) */
+      case 'A':                   /* United Kingdom (UK) */
         break;
-    case 'B':                   /* United States (USASCII) */
+      case 'B':                   /* United States (USASCII) */
         break;
-    case '<':                   /* Multinational character set */
+      case '<':                   /* Multinational character set */
         break;
-    case '5':                   /* Finnish character set */
+      case '5':                   /* Finnish character set */
         break;
-    case 'C':                   /* Finnish character set */
+      case 'C':                   /* Finnish character set */
         break;
-    case 'K':                   /* German character set */
+      case 'K':                   /* German character set */
         break;
     }
 }
@@ -1620,12 +1752,11 @@ rxvt_set_font_style(pR)
  * XTERM_SEQ: Invoke G2 character set: ESC N
  * XTERM_SEQ: Invoke G3 character set: ESC O
  */
-/* EXTPROTO */
 void
-rxvt_scr_charset_choose(pR_ int set)
+rxvt_term::scr_charset_choose (int set)
 {
-    R->screen.charset = set;
-    rxvt_set_font_style(aR);
+  screen.charset = set;
+  set_font_style ();
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1637,12 +1768,11 @@ rxvt_scr_charset_choose(pR_ int set)
  * XTERM_SEQ: Set G3 character set: ESC + <C>
  * See set_font_style for possible values for <C>
  */
-/* EXTPROTO */
 void
-rxvt_scr_charset_set(pR_ int set, unsigned int ch)
+rxvt_term::scr_charset_set (int set, unsigned int ch)
 {
-    R->charsets[set] = (unsigned char)ch;
-    rxvt_set_font_style(aR);
+  charsets[set] = (unsigned char)ch;
+  set_font_style ();
 }
 
 \f
@@ -1651,12 +1781,36 @@ rxvt_scr_charset_set(pR_ int set, unsigned int ch)
  * ------------------------------------------------------------------------- */
 
 /*
+ * refresh matching text.
+ */
+bool
+rxvt_term::scr_refresh_rend (rend_t mask, rend_t value)
+{
+  bool found = false;
+
+  for (int i = 0; i < TermWin.nrow; i++)
+    {
+      int col = 0;
+      rend_t *drp = drawn_rend [i];
+
+      for (; col < TermWin.ncol; col++, drp++)
+        if ((*drp & mask) == value)
+          {
+            found = true;
+            *drp = ~value;
+          }
+    }
+
+  return found;
+}
+
+/*
  * Refresh an area
  */
 enum {
-    PART_BEG = 0,
-    PART_END,
-    RC_COUNT
+  PART_BEG = 0,
+  PART_END,
+  RC_COUNT
 };
 
 void
@@ -1668,35 +1822,40 @@ rxvt_term::scr_expose (int x, int y, int width, int height, bool refresh)
   if (drawn_text == NULL)  /* sanity check */
     return;
 
+#ifndef NO_SLOW_LINK_SUPPORT
+  if (refresh_type == FAST_REFRESH && !display->is_local)
+    {
+      y = 0;
+      height = TermWin.height;
+    }
+#endif
+
 #ifdef DEBUG_STRICT
-  x = max(x, (int)TermWin.int_bwidth);
-  x = min(x, (int)TermWin.width);
-  y = max(y, (int)TermWin.int_bwidth);
-  y = min(y, (int)TermWin.height);
+  x = max (x, 0);
+  x = min (x, (int)TermWin.width);
+  y = max (y, 0);
+  y = min (y, (int)TermWin.height);
 #endif
 
-/* round down */
-  rc[PART_BEG].col = Pixel2Col(x);
-  rc[PART_BEG].row = Pixel2Row(y);
-/* round up */
-  rc[PART_END].col = Pixel2Width(x + width + TermWin.fwidth - 1);
-  rc[PART_END].row = Pixel2Row(y + height + TermWin.fheight - 1);
+  /* round down */
+  rc[PART_BEG].col = Pixel2Col (x);
+  rc[PART_BEG].row = Pixel2Row (y);
+  /* round up */
+  rc[PART_END].col = Pixel2Width (x + width + TermWin.fwidth - 1);
+  rc[PART_END].row = Pixel2Row (y + height + TermWin.fheight - 1);
 
-/* sanity checks */
+  /* sanity checks */
   for (i = PART_BEG; i < RC_COUNT; i++)
     {
-      MIN_IT(rc[i].col, TermWin.ncol - 1);
-      MIN_IT(rc[i].row, TermWin.nrow - 1);
+      MIN_IT (rc[i].col, TermWin.ncol - 1);
+      MIN_IT (rc[i].row, TermWin.nrow - 1);
     }
 
-  D_SCREEN((stderr, "rxvt_scr_expose(x:%d, y:%d, w:%d, h:%d) area (c:%d,r:%d)-(c:%d,r:%d)", x, y, width, height, rc[PART_BEG].col, rc[PART_BEG].row, rc[PART_END].col, rc[PART_END].row));
-
   for (i = rc[PART_BEG].row; i <= rc[PART_END].row; i++)
-    fill_text (&(drawn_text[i][rc[PART_BEG].col]), 0,
-               (rc[PART_END].col - rc[PART_BEG].col + 1));
+    fill_text (&drawn_text[i][rc[PART_BEG].col], 0, rc[PART_END].col - rc[PART_BEG].col + 1);
 
   if (refresh)
-    scr_refresh (SLOW_REFRESH | REFRESH_BOUNDS);
+    scr_refresh (SLOW_REFRESH);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1714,23 +1873,24 @@ rxvt_term::scr_touch (bool refresh)
  * Move the display so that the line represented by scrollbar value Y is at
  * the top of the screen
  */
-/* EXTPROTO */
 int
-rxvt_scr_move_to(pR_ int y, int len)
+rxvt_term::scr_move_to (int y, int len)
 {
-    long            p = 0;
-    uint16_t       oldviewstart;
+  long p = 0;
+  unsigned int oldviewstart;
 
-    oldviewstart = R->TermWin.view_start;
-    if (y < len) {
-        p = (R->TermWin.nrow + R->TermWin.nscrolled) * (len - y) / len;
-        p -= (long)(R->TermWin.nrow - 1);
-        p = max(p, 0);
+  oldviewstart = TermWin.view_start;
+
+  if (y < len)
+    {
+      p = (TermWin.nrow + TermWin.nscrolled) * (len - y) / len;
+      p -= (long) (TermWin.nrow - 1);
+      p = max (p, 0);
     }
-    R->TermWin.view_start = (uint16_t)min(p, R->TermWin.nscrolled);
-    D_SCREEN((stderr, "rxvt_scr_move_to(%d, %d) view_start:%d", y, len, R->TermWin.view_start));
 
-    return rxvt_scr_changeview(aR_ oldviewstart);
+  TermWin.view_start = (unsigned int)min (p, TermWin.nscrolled);
+
+  return scr_changeview (oldviewstart);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -1738,590 +1898,689 @@ rxvt_scr_move_to(pR_ int y, int len)
  * Page the screen up/down nlines
  * direction should be UP or DN
  */
-/* EXTPROTO */
 int
-rxvt_scr_page(pR_ enum page_dirn direction, int nlines)
+rxvt_term::scr_page (enum page_dirn direction, int nlines)
 {
-    int             n;
-    uint16_t       oldviewstart;
+  int n;
+  unsigned int oldviewstart;
 
-    D_SCREEN((stderr, "rxvt_scr_page(%s, %d) view_start:%d", ((direction == UP) ? "UP" : "DN"), nlines, R->TermWin.view_start));
 #ifdef DEBUG_STRICT
-    assert((nlines >= 0) && (nlines <= R->TermWin.nrow));
+  assert ((nlines >= 0) && (nlines <= TermWin.nrow));
 #endif
-    oldviewstart = R->TermWin.view_start;
-    if (direction == UP) {
-        n = R->TermWin.view_start + nlines;
-        R->TermWin.view_start = min(n, R->TermWin.nscrolled);
-    } else {
-        n = R->TermWin.view_start - nlines;
-        R->TermWin.view_start = max(n, 0);
+  oldviewstart = TermWin.view_start;
+  if (direction == UP)
+    {
+      n = TermWin.view_start + nlines;
+      TermWin.view_start = min (n, TermWin.nscrolled);
     }
-    return rxvt_scr_changeview(aR_ oldviewstart);
+  else
+    {
+      n = TermWin.view_start - nlines;
+      TermWin.view_start = max (n, 0);
+    }
+  return scr_changeview (oldviewstart);
 }
 
-/* INTPROTO */
 int
-rxvt_scr_changeview(pR_ uint16_t oldviewstart)
+rxvt_term::scr_changeview (unsigned int oldviewstart)
 {
-    if (R->TermWin.view_start != oldviewstart) {
-        R->want_refresh = 1;
-#ifdef RXVT_GRAPHICS
-        if (rxvt_Gr_Displayed(aR))
-            rxvt_Gr_scroll(aR_ 0);
-#endif
-        R->num_scr -= (R->TermWin.view_start - oldviewstart);
+  if (TermWin.view_start != oldviewstart)
+    {
+      want_refresh = 1;
+      num_scr -= (TermWin.view_start - oldviewstart);
     }
-    return (int)(R->TermWin.view_start - oldviewstart);
+
+  return (int) (TermWin.view_start - oldviewstart);
 }
 
 /* ------------------------------------------------------------------------- */
-/* EXTPROTO */
 void
-rxvt_scr_bell(pR)
+rxvt_term::scr_bell ()
 {
 #ifndef NO_BELL
 # ifndef NO_MAPALERT
 #  ifdef MAPALERT_OPTION
-    if (R->Options & Opt_mapAlert)
+  if (options & Opt_mapAlert)
 #  endif
-        XMapWindow(R->Xdisplay, R->TermWin.parent[0]);
+    XMapWindow (display->display, TermWin.parent[0]);
 # endif
-    if (R->Options & Opt_visualBell) {
-        rxvt_scr_rvideo_mode(aR_ !R->rvideo); /* refresh also done */
-        rxvt_scr_rvideo_mode(aR_ !R->rvideo); /* refresh also done */
-    } else
-        XBell(R->Xdisplay, 0);
+  if (options & Opt_visualBell)
+    {
+      scr_rvideo_mode (!rvideo); /* refresh also done */
+      scr_rvideo_mode (!rvideo); /* refresh also done */
+    }
+  else
+    XBell (display->display, 0);
 #endif
 }
 
 /* ------------------------------------------------------------------------- */
 /* ARGSUSED */
-/* EXTPROTO */
 void
-rxvt_scr_printscreen(pR_ int fullhist)
+rxvt_term::scr_printscreen (int fullhist)
 {
 #ifdef PRINTPIPE
-    int             i, r1, nrows, row_offset;
-    text_t         *t;
-    FILE           *fd;
+  int i, r1, nrows, row_offset;
+  FILE *fd;
 
-    if ((fd = rxvt_popen_printer(aR)) == NULL)
-        return;
-    nrows = R->TermWin.nrow;
-    row_offset = R->TermWin.saveLines;
-    if (!fullhist)
-        row_offset -= R->TermWin.view_start;
-    else {
-        nrows += R->TermWin.nscrolled;
-        row_offset -= R->TermWin.nscrolled;
-    }
-
-    for (r1 = 0; r1 < nrows; r1++) {
-        t = R->screen.text[r1 + row_offset];
-        for (i = R->TermWin.ncol - 1; i >= 0; i--)
-            if (!isspace(t[i]))
-                break;
-        fprintf(fd, "%.*s\n", (i + 1), t);
+  if ((fd = popen_printer ()) == NULL)
+    return;
+
+  nrows = TermWin.nrow;
+  row_offset = TermWin.saveLines;
+
+  if (!fullhist)
+    row_offset -= TermWin.view_start;
+  else
+    {
+      nrows += TermWin.nscrolled;
+      row_offset -= TermWin.nscrolled;
     }
-    rxvt_pclose_printer(fd);
+
+  wctomb (0, 0);
+
+  for (r1 = 0; r1 < nrows; r1++)
+    {
+      text_t *tp = screen.text[r1 + row_offset];
+      int len = screen.tlen[r1 + row_offset];
+
+      for (i = len >= 0 ? len : TermWin.ncol - 1; i--; )
+        {
+          char mb[MB_LEN_MAX];
+          text_t t = *tp++;
+          if (t == NOCHAR)
+            continue;
+
+          len = wctomb (mb, t);
+
+          if (len <= 0)
+            {
+              mb[0] = ' ';
+              len = 1;
+            }
+
+          fwrite (mb, 1, len, fd);
+        }
+
+      fputc ('\n', fd);
+    }
+
+  pclose_printer (fd);
 #endif
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Refresh the screen
- * R->drawn_text/R->drawn_rend contain the screen information before the update.
- * R->screen.text/R->screen.rend contain what the screen will change to.
+ * drawn_text/drawn_rend contain the screen information before the update.
+ * screen.text/screen.rend contain what the screen will change to.
  */
 
 #define FONT_WIDTH(X, Y)                                                \
-    (X)->per_char[(Y) - (X)->min_char_or_byte2].width
+    (X)->per_char[ (Y) - (X)->min_char_or_byte2].width
 #define FONT_RBEAR(X, Y)                                                \
-    (X)->per_char[(Y) - (X)->min_char_or_byte2].rbearing
+    (X)->per_char[ (Y) - (X)->min_char_or_byte2].rbearing
 #define FONT_LBEAR(X, Y)                                                \
-    (X)->per_char[(Y) - (X)->min_char_or_byte2].lbearing
+    (X)->per_char[ (Y) - (X)->min_char_or_byte2].lbearing
 #define IS_FONT_CHAR(X, Y)                                              \
     ((Y) >= (X)->min_char_or_byte2 && (Y) <= (X)->max_char_or_byte2)
 
 void
 rxvt_term::scr_refresh (unsigned char refresh_type)
 {
-    unsigned char   clearfirst, /* first character writes before cell        */
-                    clearlast,  /* last character writes beyond cell         */
-                    must_clear, /* use draw_string not draw_image_string     */
-                    rvid,       /* reverse video this position               */
-                    showcursor; /* show the cursor                           */
-    int16_t         col, row,   /* column/row we're processing               */
-                    ocrow;      /* old cursor row                            */
-    int             cursorwidth;
-    int             i,          /* tmp                                       */
-                    row_offset; /* basic offset in screen structure          */
+  unsigned char must_clear, /* use draw_string not draw_image_string     */
+                showcursor; /* show the cursor                           */
+  int16_t col, row,   /* column/row we're processing               */
+          ocrow;      /* old cursor row                            */
+  int i,              /* tmp                                       */
+  row_offset;         /* basic offset in screen structure          */
 #ifndef NO_CURSORCOLOR
-    rend_t          cc1;        /* store colours at cursor position(s)       */
-    rend_t          cc2;        /* store colours at cursor position(s)       */
+  rend_t cc1;         /* store colours at cursor position (s)      */
 #endif
-    rend_t         *drp, *srp;  /* drawn-rend-pointer, screen-rend-pointer   */
-    text_t         *dtp, *stp;  /* drawn-text-pointer, screen-text-pointer   */
-
-    if (refresh_type == NO_REFRESH || !TermWin.mapped)
-      return;
-
-    /*
-     * A: set up vars
-     */
-    clearfirst = clearlast = must_clear = 0;
+  rend_t *crp;        // cursor rendition pointer
 
-    if (currmaxcol < TermWin.ncol)
-      {
-        currmaxcol = TermWin.ncol;
-        buffer = (char *)rxvt_realloc (buffer,
-                                          sizeof(char) * (currmaxcol + 1) * MB_CUR_MAX);
-      }
+  want_refresh = 0;        /* screen is current */
 
-    refresh_count = 0;
+  if (refresh_type == NO_REFRESH || !TermWin.mapped)
+    return;
 
-    row_offset = TermWin.saveLines - TermWin.view_start;
+  /*
+   * A: set up vars
+   */
+  must_clear = 0;
+  refresh_count = 0;
 
-    if ((refresh_type & REFRESH_BOUNDS))
-      {
-        clearfirst = clearlast = 1;
-        refresh_type &= ~REFRESH_BOUNDS;
-      }
+  row_offset = TermWin.saveLines - TermWin.view_start;
 
-#if defined(XPM_BACKGROUND)
-    must_clear |= (bgPixmap.pixmap != None);
+#if XPM_BACKGROUND
+  must_clear |= (bgPixmap.pixmap != None);
 #endif
-#if defined(TRANSPARENT)
-    must_clear |= ((Options & Opt_transparent) && am_transparent);
+#if TRANSPARENT
+  must_clear |= ((options & Opt_transparent) && am_transparent);
 #endif
-    ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
+  ocrow = oldcursor.row; /* is there an old outline cursor on screen? */
 
-    /*
-     * B: reverse any characters which are selected
-     */
-    rxvt_scr_reverse_selection (this);
-
-    /*
-     * C: set the cursor character(s)
-     */
-    {
-      unsigned char   setoldcursor;
-      rend_t          ccol1,  /* Cursor colour       */
-                      ccol2;  /* Cursor colour2      */
+  /*
+   * B: reverse any characters which are selected
+   */
+  scr_reverse_selection ();
 
-      showcursor = (screen.flags & Screen_VisibleCursor);
-      cursorwidth = 0;
+  /*
+   * C: set the cursor character (s)
+   */
+  {
+    unsigned char setoldcursor;
+    rend_t ccol1,  /* Cursor colour       */
+           ccol2;  /* Cursor colour2      */
+
+    showcursor = (screen.flags & Screen_VisibleCursor);
 #ifdef CURSOR_BLINK
-      if (hidden_cursor)
-          showcursor = 0;
+    if (hidden_cursor)
+      showcursor = 0;
 #endif
 
-      cursorwidth = 0;
+    if (showcursor)
+      {
+        int col = screen.cur.col;
 
-      if (showcursor)
-        {
-          cursorwidth++;
+        while (col && screen.text[screen.cur.row + TermWin.saveLines][col] == NOCHAR)
+          col--;
 
-          srp = &(screen.rend[screen.cur.row + TermWin.saveLines]
-                                [screen.cur.col]);
+        crp = &screen.rend[screen.cur.row + TermWin.saveLines][col];
 
-          if (showcursor && TermWin.focus)
-            {
-              *srp ^= RS_RVid;
+        if (showcursor && TermWin.focus)
+          {
+            *crp ^= RS_RVid;
 #ifndef NO_CURSORCOLOR
-              cc1 = *srp & (RS_fgMask | RS_bgMask);
-              if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_cursor))
-                  ccol1 = Color_cursor;
-              else
+            cc1 = *crp & (RS_fgMask | RS_bgMask);
+            if (ISSET_PIXCOLOR (Color_cursor))
+              ccol1 = Color_cursor;
+            else
 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
-                  ccol1 = GET_FGCOLOR(rstyle);
+              ccol1 = GET_FGCOLOR (rstyle);
 #else
-                  ccol1 = Color_fg;
+              ccol1 = Color_fg;
 #endif
-              if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_cursor2))
-                  ccol2 = Color_cursor2;
-              else
+            if (ISSET_PIXCOLOR (Color_cursor2))
+              ccol2 = Color_cursor2;
+            else
 #ifdef CURSOR_COLOR_IS_RENDITION_COLOR
-                  ccol2 = GET_BGCOLOR(rstyle);
+              ccol2 = GET_BGCOLOR (rstyle);
 #else
-                  ccol2 = Color_bg;
+              ccol2 = Color_bg;
 #endif
-              *srp = SET_FGCOLOR(*srp, ccol1);
-              *srp = SET_BGCOLOR(*srp, ccol2);
+            *crp = SET_FGCOLOR (*crp, ccol1);
+            *crp = SET_BGCOLOR (*crp, ccol2);
 #endif
-            }
-        }
-
-      /* make sure no outline cursor is left around */
-      setoldcursor = 0;
-      if (ocrow != -1) {
-          if (screen.cur.row + TermWin.view_start != ocrow
-              || screen.cur.col != oldcursor.col) {
-              if (ocrow < TermWin.nrow
-                  && oldcursor.col < TermWin.ncol) {
-                  drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline);
-              }
-              if (TermWin.focus || !showcursor)
-                  oldcursor.row = -1;
-              else
-                  setoldcursor = 1;
           }
-      } else if (!TermWin.focus)
-          setoldcursor = 1;
-      if (setoldcursor) {
-          if (screen.cur.row + TermWin.view_start >= TermWin.nrow)
+      }
+
+    /* make sure no outline cursor is left around */
+    setoldcursor = 0;
+    if (ocrow != -1)
+      {
+        if (screen.cur.row + TermWin.view_start != ocrow
+            || screen.cur.col != oldcursor.col)
+          {
+            if (ocrow < TermWin.nrow
+                && oldcursor.col < TermWin.ncol)
+              drawn_rend[ocrow][oldcursor.col] ^= (RS_RVid | RS_Uline);
+
+            if (TermWin.focus || !showcursor)
               oldcursor.row = -1;
-          else {
-              oldcursor.row = screen.cur.row + TermWin.view_start;
-              oldcursor.col = screen.cur.col;
+            else
+              setoldcursor = 1;
           }
       }
-    }
+    else if (!TermWin.focus)
+      setoldcursor = 1;
 
-#ifndef NO_SLOW_LINK_SUPPORT
-    /*
-     * D: CopyArea pass - very useful for slower links
-     *    This has been deliberately kept simple.
-     */
-    i = num_scr;
-    if (refresh_type == FAST_REFRESH && num_scr_allow && i
-        && abs(i) < TermWin.nrow && !must_clear)
+    if (setoldcursor)
       {
-        int16_t         nits;
-        int             j;
-        rend_t         *drp2;
-        text_t         *dtp2;
-        int             len, wlen;
-
-        j = TermWin.nrow;
-        wlen = len = -1;
-        row = i > 0 ? 0 : j - 1;
-        for (; j-- >= 0; row += (i > 0 ? 1 : -1))
+        if (screen.cur.row + TermWin.view_start >= TermWin.nrow)
+          oldcursor.row = -1;
+        else
           {
-            if (row + i >= 0 && row + i < TermWin.nrow && row + i != ocrow)
-              {
-                stp = screen.text[row + row_offset];
-                srp = screen.rend[row + row_offset];
-                dtp = drawn_text[row];
-                dtp2 = drawn_text[row + i];
-                drp = drawn_rend[row];
-                drp2 = drawn_rend[row + i];
-
-                for (nits = 0, col = TermWin.ncol; col--; )
-                  if (stp[col] != dtp2[col] || srp[col] != drp2[col])
-                    nits--;
-                  else if (stp[col] != dtp[col] || srp[col] != drp[col])
-                    nits++;
-
-                if (nits > 8) /* XXX: arbitrary choice */
-                  {
-                    for (col = TermWin.ncol; col--; )
-                      {
-                        *dtp++ = *dtp2++;
-                        *drp++ = *drp2++;
-                      }
+            oldcursor.row = screen.cur.row + TermWin.view_start;
+            oldcursor.col = screen.cur.col;
+          }
+      }
+  }
 
-                    if (len == -1)
-                      len = row;
+#if ENABLE_OVERLAY
+  scr_swap_overlay ();
+#endif
 
-                    wlen = row;
-                    continue;
-                  }
-              }
+  rend_t *drp, *srp;  /* drawn-rend-pointer, screen-rend-pointer   */
+  text_t *dtp, *stp;  /* drawn-text-pointer, screen-text-pointer   */
 
-            if (len != -1)
-              {
-                /* also comes here at end if needed because of >= above */
-                if (wlen < len)
-                  SWAP_IT(wlen, len, int);
-
-                D_SCREEN((stderr, "rxvt_scr_refresh(): XCopyArea: %d -> %d (height: %d)", len + i, len, wlen - len + 1));
-                XCopyArea (Xdisplay, TermWin.vt, TermWin.vt,
-                           TermWin.gc, 0, Row2Pixel (len + i),
-                           (unsigned int)TermWin_TotalWidth (),
-                           (unsigned int)Height2Pixel (wlen - len + 1),
-                           0, Row2Pixel (len));
-                len = -1;
-              }
-          }
+#ifndef NO_SLOW_LINK_SUPPORT
+  /*
+   * D: CopyArea pass - very useful for slower links
+   *    This has been deliberately kept simple.
+   */
+  i = num_scr;
+  if (!display->is_local
+      && refresh_type == FAST_REFRESH && num_scr_allow && i
+      && abs (i) < TermWin.nrow && !must_clear)
+    {
+      int16_t nits;
+      int j;
+      int len, wlen;
+
+      j = TermWin.nrow;
+      wlen = len = -1;
+      row = i > 0 ? 0 : j - 1;
+      for (; j-- >= 0; row += (i > 0 ? 1 : -1))
+        {
+          if (row + i >= 0 && row + i < TermWin.nrow && row + i != ocrow)
+            {
+              text_t *stp  = screen.text[row + row_offset];
+              rend_t *srp  = screen.rend[row + row_offset];
+              text_t *dtp  = drawn_text[row];
+              text_t *dtp2 = drawn_text[row + i];
+              rend_t *drp  = drawn_rend[row];
+              rend_t *drp2 = drawn_rend[row + i];
+
+              for (nits = 0, col = TermWin.ncol; col--; )
+                if (stp[col] != dtp2[col] || srp[col] != drp2[col])
+                  nits--;
+                else if (stp[col] != dtp[col] || srp[col] != drp[col])
+                  nits++;
+
+              if (nits > 8) /* XXX: arbitrary choice */
+                {
+                  for (col = TermWin.ncol; col--; )
+                    {
+                      *dtp++ = *dtp2++;
+                      *drp++ = *drp2++;
+                    }
+
+                  if (len == -1)
+                    len = row;
+
+                  wlen = row;
+                  continue;
+                }
+            }
+
+          if (len != -1)
+            {
+              /* also comes here at end if needed because of >= above */
+              if (wlen < len)
+                SWAP_IT (wlen, len, int);
+
+              XCopyArea (display->display, TermWin.vt, TermWin.vt,
+                         TermWin.gc, 0, Row2Pixel (len + i),
+                         (unsigned int)TermWin_TotalWidth (),
+                         (unsigned int)Height2Pixel (wlen - len + 1),
+                         0, Row2Pixel (len));
+              len = -1;
+            }
+        }
     }
 #endif
 
-    /*
-     * E: main pass across every character
-     */
-    for (row = 0; row < TermWin.nrow; row++)
-      {
-        stp = screen.text[row + row_offset];
-        srp = screen.rend[row + row_offset];
-        dtp = drawn_text[row];
-        drp = drawn_rend[row];
+  /*
+   * E: main pass across every character
+   */
+  for (row = 0; row < TermWin.nrow; row++)
+    {
+      text_t *stp = screen.text[row + row_offset];
+      rend_t *srp = screen.rend[row + row_offset];
+      text_t *dtp = drawn_text[row];
+      rend_t *drp = drawn_rend[row];
 
-        /*
-         * E2: OK, now the real pass
-         */
-        int ypixel = (int)Row2Pixel(row);
+      /*
+       * E2: OK, now the real pass
+       */
+      int ypixel = (int)Row2Pixel (row);
 
-        for (col = 0; col < TermWin.ncol; col++)
-          {
-            /* compare new text with old - if exactly the same then continue */
-            rend_t rend = srp[col];     /* screen rendition (target rendtion) */
+      for (col = 0; col < TermWin.ncol; col++)
+        {
+          /* compare new text with old - if exactly the same then continue */
+          if (stp[col] == dtp[col]    /* Must match characters to skip. */
+              && (RS_SAME (srp[col], drp[col])    /* Either rendition the same or   */
+                  || (stp[col] == ' ' /* space w/ no background change  */
+                      && GET_BGATTR (srp[col]) == GET_BGATTR (drp[col]))))
+            continue;
 
-            if (stp[col] == dtp[col]    /* Must match characters to skip. */
-                && (rend == drp[col]    /* Either rendition the same or   */
-                    || (stp[col] == ' ' /* space w/ no background change  */
-                        && GET_BGATTR(rend) == GET_BGATTR(drp[col]))))
-              continue;
+          // redraw one or more characters
 
-            text_t *text = stp + col;
-            int count = 1;
+          // seek to the beginning of wide characters
+          while (stp[col] == NOCHAR && col > 0)
+            --col;
 
-            /* redraw one or more characters */
+          rend_t rend = srp[col];     /* screen rendition (target rendtion) */
+          text_t *text = stp + col;
+          int count = 1;
 
-            dtp[col] = stp[col];
-            drp[col] = rend;
+          dtp[col] = stp[col];
+          drp[col] = rend;
 
-            if (*text == NOCHAR) // never start redrawing at invisible characters. */
-              continue;
+          int xpixel = Col2Pixel (col);
 
-            int xpixel = Col2Pixel(col);
+          for (i = 0; ++col < TermWin.ncol; )
+            {
+              if (stp[col] == NOCHAR)
+                {
+                  dtp[col] = stp[col];
+                  drp[col] = rend;
+                  count++;
+                  i++;
 
-            // this loop looks very messy, it can probably be optimized
-            // and cleaned a bit by you?
-            for (i = 0; ++col < TermWin.ncol; )
-              {
-                if (stp[col] == NOCHAR)
-                  {
-                    dtp[col] = stp[col];
-                    drp[col] = rend;
-                    count++;
+                  continue;
+                }
 
-                    if (i) // only possible skip if char unchanged
-                      i++;
+              if (!RS_SAME (rend, srp[col]))
+                break;
 
-                    continue;
-                  }
+              count++;
 
-                if (rend != srp[col])
-                  break;
+              if (stp[col] != dtp[col]
+                  || !RS_SAME (srp[col], drp[col]))
+                {
+                  if (must_clear && (i++ > count / 2))
+                    break;
 
-                count++;
+                  dtp[col] = stp[col];
+                  drp[col] = rend;
+                  i = 0;
+                }
+              else if (must_clear || (stp[col] != ' ' && ++i >= 16))
+                break;
+            }
 
-                if (stp[col] != dtp[col]
-                    || srp[col] != drp[col])
-                  {
-                    if (must_clear && (i++ > (count / 2)))
-                      break;
+          col--;      /* went one too far.  move back */
+          count -= i; /* dump any matching trailing chars */
 
-                    dtp[col] = stp[col];
-                    drp[col] = rend;
-                    i = 0;
-                  }
-                else if (must_clear || (stp[col] != ' ' && ++i >= 32))
-                  break;
-              }
+          // sometimes we optimize away the trailing NOCHAR's, add them back
+          while (i && text[count] == NOCHAR)
+            count++, i--;
 
-            col--;      /* went one too far.  move back */
-            count -= i; /* dump any matching trailing chars */
+#if ENABLE_STYLES
+          // force redraw after "careful" characters to avoid pixel droppings
+          if (srp[col] & RS_Careful && col < TermWin.ncol - 1 && 0)
+            drp[col + 1] = ~srp[col + 1];
 
-            /*
-             * Determine the attributes for the string
-             */
-            int fid = GET_FONT (rend);
-            int fore = GET_FGCOLOR (rend); // desired foreground
-            int back = GET_BGCOLOR (rend); // desired background
+          // include previous careful character(s) if possible, looks nicer (best effort...)
+          while (text > stp
+              && srp[text - stp - 1] & RS_Careful
+              && RS_SAME (rend, srp[text - stp - 1]))
+            text--, count++, xpixel -= TermWin.fwidth;
+#endif
 
-            rend = GET_ATTR (rend);
+          /*
+           * Determine the attributes for the string
+           */
+          int fore = GET_FGCOLOR (rend); // desired foreground
+          int back = GET_BGCOLOR (rend); // desired background
 
-            rvid = !!(rend & RS_RVid);
-#ifdef OPTION_HC
-            if (!rvid && (rend & RS_Blink))
-              {
-                if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_HC))
-                  back = Color_HC;
-                else
-                  rvid = !rvid; /* fall back */
-              }
-#endif
-            if (rvid)
-              {
-                SWAP_IT(fore, back, int);
+          // only do special processing if ana attributes are set, which is rare
+          if (rend & (RS_Bold | RS_Italic | RS_Uline | RS_RVid | RS_Blink))
+            {
+              bool invert = rend & RS_RVid;
 
 #ifndef NO_BOLD_UNDERLINE_REVERSE
-                if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_RV)
-# ifndef NO_CURSORCOLOR
-                    && !ISSET_PIXCOLOR (this, Color_cursor)
+              if (rend & RS_Bold
+                  && fore == Color_fg)
+                {
+                  if (ISSET_PIXCOLOR (Color_BD))
+                    fore = Color_BD;
+# if !ENABLE_STYLES
+                  else
+                    invert = !invert;
 # endif
-                    )
-                  back = Color_RV;
+                }
+
+              if (rend & RS_Italic
+                  && fore == Color_fg)
+                {
+                  if (ISSET_PIXCOLOR (Color_IT))
+                    fore = Color_IT;
+# if !ENABLE_STYLES
+                  else
+                    invert = !invert;
+# endif
+                }
+
+              if (rend & RS_Uline && ISSET_PIXCOLOR (Color_UL))
+                fore = Color_UL;
 #endif
-              }
+
+              if (invert)
+                {
+                  SWAP_IT (fore, back, int);
+
 #ifndef NO_BOLD_UNDERLINE_REVERSE
-            else if (rend & RS_Bold)
-              {
-                if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_BD))
-                  fore = Color_BD;
-              }
-            else if (rend & RS_Uline)
-              {
-                if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_UL))
-                  fore = Color_UL;
-              }
+                  if (ISSET_PIXCOLOR (Color_RV))
+                    back = Color_RV;
+#endif
+                }
+
+#ifdef TEXT_BLINK
+              if (rend & RS_Blink && (back == Color_bg || fore == Color_bg))
+                {
+                  if (!text_blink_ev.active)
+                    {
+                      text_blink_ev.start (NOW + TEXT_BLINK_INTERVAL);
+                      hidden_text = 0;
+                    }
+                  else if (hidden_text)
+                    fore = back;
+                }
 #endif
+            }
 
-            /*
-             * Actually do the drawing of the string here
-             */
-            rxvt_font *font = (*TermWin.fontset)[fid];
+          /*
+           * Actually do the drawing of the string here
+           */
+          rxvt_font *font = (*TermWin.fontset[GET_STYLE (rend)])[GET_FONT (rend)];
 
-            if (back == Color_bg)
-              {
-                if (must_clear)
-                  {
-                    for (i = 0; i < count; i++) /* don't draw empty strings */
-                      if (text[i] != ' ')
-                        {
-                          font->draw (xpixel, ypixel, text, count, fore, -1);
-                          goto nodraw;
-                        }
-
-                    CLEAR_CHARS (xpixel, ypixel, count);
-nodraw: ;
-                  }
-                else
-                  font->draw (xpixel, ypixel, text, count, fore, Color_bg);
-              }
-            else
-              font->draw (xpixel, ypixel, text, count, fore, back);
-
-            if ((rend & RS_Uline) && (font->descent > 1))
-                XDrawLine(Xdisplay, drawBuffer, TermWin.gc,
-                          xpixel, ypixel + font->ascent + 1,
-                          xpixel + Width2Pixel(count) - 1, ypixel + font->ascent + 1);
-          }                     /* for (col....) */
-      }                         /* for (row....) */
-
-    /*
-     * G: cleanup cursor and display outline cursor if necessary
-     */
-    if (showcursor) {
-        if (TermWin.focus) {
-            srp = &(screen.rend[screen.cur.row + TermWin.saveLines]
-                                  [screen.cur.col]);
-            *srp ^= RS_RVid;
+          if (back == fore)
+            font->clear_rect (*TermWin.drawable, xpixel, ypixel,
+                              TermWin.fwidth * count, TermWin.fheight,
+                              back);
+          else if (back == Color_bg)
+            {
+              if (must_clear)
+                {
+                  CLEAR_CHARS (xpixel, ypixel, count);
+
+                  for (i = 0; i < count; i++) /* don't draw empty strings */
+                    if (text[i] != ' ')
+                      {
+                        font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, -1);
+                        break;
+                      }
+                }
+              else
+                font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, Color_bg);
+            }
+          else
+            font->draw (*TermWin.drawable, xpixel, ypixel, text, count, fore, back);
+
+          if (rend & RS_Uline && font->descent > 1 && fore != back)
+            {
+              XSetForeground (display->display, TermWin.gc, pix_colors[fore]);
+              XDrawLine (display->display, drawBuffer, TermWin.gc,
+                         xpixel, ypixel + font->ascent + 1,
+                         xpixel + Width2Pixel (count) - 1, ypixel + font->ascent + 1);
+            }
+        }                     /* for (col....) */
+    }                         /* for (row....) */
+
+#if ENABLE_OVERLAY
+  scr_swap_overlay ();
+#endif
+
+  /*
+   * G: cleanup cursor and display outline cursor if necessary
+   */
+  if (showcursor)
+    {
+      if (TermWin.focus)
+        {
+          *crp ^= RS_RVid;
 #ifndef NO_CURSORCOLOR
-            *srp = (*srp & ~(RS_fgMask | RS_bgMask)) | cc1;
+          *crp = (*crp & ~ (RS_fgMask | RS_bgMask)) | cc1;
 #endif
-        } else if (oldcursor.row >= 0) {
+        }
+      else if (oldcursor.row >= 0)
+        {
 #ifndef NO_CURSORCOLOR
-            unsigned long   gcmask;     /* Graphics Context mask */
+          if (ISSET_PIXCOLOR (Color_cursor))
+            XSetForeground (display->display, TermWin.gc, pix_colors[Color_cursor]);
+#endif
+          int cursorwidth = 1;
+          while (oldcursor.col + cursorwidth < TermWin.ncol
+                 && drawn_text[oldcursor.row][oldcursor.col + cursorwidth] == NOCHAR)
+            cursorwidth++;
+
+          XDrawRectangle (display->display, drawBuffer, TermWin.gc,
+                          Col2Pixel (oldcursor.col),
+                          Row2Pixel (oldcursor.row),
+                          (unsigned int) (Width2Pixel (cursorwidth) - 1),
+                          (unsigned int) (Height2Pixel (1) - TermWin.lineSpace - 1));
+        }
+    }
+
+  /*
+   * H: cleanup selection
+   */
+  scr_reverse_selection ();
+
+  if (refresh_type & SMOOTH_REFRESH)
+    XFlush (display->display);
+
+  num_scr = 0;
+  num_scr_allow = 1;
+}
+
+void
+rxvt_term::scr_remap_chars (text_t *tp, rend_t *rp)
+{
+  if (!rp || !tp)
+    return;
+
+  for (int i = TermWin.ncol; i; i--, rp++, tp++)
+    *rp = SET_FONT (*rp, FONTSET (*rp)->find_font (*tp));
+}
+
+void
+rxvt_term::scr_remap_chars ()
+{
+  for (int i = TermWin.nrow + TermWin.saveLines; i--; )
+    scr_remap_chars (screen.text[i], screen.rend[i]);
+
+  for (int i = TermWin.nrow; i--; )
+    {
+      scr_remap_chars (drawn_text[i], drawn_rend[i]);
+      scr_remap_chars (swap.text[i], swap.rend[i]);
+    }
+}
 
-            if (Xdepth > 2 && ISSET_PIXCOLOR (this, Color_cursor))
-              XSetForeground (Xdisplay, TermWin.gc, PixColors[Color_cursor]);
+void
+rxvt_term::scr_recolour ()
+{
+  if (1
+#if TRANSPARENT
+      && !am_transparent
 #endif
-            XDrawRectangle(Xdisplay, drawBuffer, TermWin.gc,
-                           Col2Pixel(oldcursor.col),
-                           Row2Pixel(oldcursor.row),
-                           (unsigned int)(Width2Pixel(cursorwidth) - 1),
-                           (unsigned int)(Height2Pixel(1) - TermWin.lineSpace - 1));
+#if XPM_BACKGROUND
+      && !bgPixmap.pixmap
+#endif
+      )
+    {
+      XSetWindowBackground (display->display, TermWin.parent[0], pix_colors[Color_border]);
+      XClearWindow (display->display, TermWin.parent[0]);
+      XSetWindowBackground (display->display, TermWin.vt, pix_colors[Color_bg]);
+#if HAVE_SCROLLBARS
+      if (scrollBar.win)
+        {
+          XSetWindowBackground (display->display, scrollBar.win, pix_colors[Color_border]);
+          scrollBar.setIdle ();
+          scrollbar_show (0);
         }
+#endif
     }
 
-    /*
-     * H: cleanup selection
-     */
-    rxvt_scr_reverse_selection (this);
-
-    /*
-     * I: other general cleanup
-     */
-    if (clearfirst && TermWin.int_bwidth)
-        /* 
-         * clear the whole screen height, note that width == 0 is treated
-         * specially by XClearArea
-         */
-        XClearArea(Xdisplay, TermWin.vt, 0, 0,
-                   (unsigned int)TermWin.int_bwidth,
-                   (unsigned int)TermWin_TotalHeight(), False);
-    if (clearlast && TermWin.int_bwidth)
-        /* 
-         * clear the whole screen height, note that width == 0 is treated
-         * specially by XClearArea
-         */
-        XClearArea(Xdisplay, TermWin.vt,
-                   TermWin.width + TermWin.int_bwidth, 0,
-                   (unsigned int)TermWin.int_bwidth,
-                   (unsigned int)TermWin_TotalHeight(), False);
-    if (refresh_type & SMOOTH_REFRESH)
-        XSync(Xdisplay, False);
-
-    num_scr = 0;
-    num_scr_allow = 1;
-    want_refresh = 0;        /* screen is current */
+  scr_clear ();
+  scr_touch (true);
+  want_refresh = 1;
 }
 
 /* ------------------------------------------------------------------------- */
 void
-rxvt_term::scr_clear()
+rxvt_term::scr_clear (bool really)
 {
   if (!TermWin.mapped)
     return;
 
   num_scr_allow = 0;
   want_refresh = 1;
-#ifdef TRANSPARENT
-  if ((Options & Opt_transparent) && (am_pixmap_trans == 0))
+
+#if TRANSPARENT
+  if ((options & Opt_transparent) && (am_pixmap_trans == 0))
     {
       int i;
 
-      if (!(Options & Opt_transparent_all))
+      if (!(options & Opt_transparent_all))
         i = 0;
       else
-        i = (int)(sizeof(TermWin.parent) / sizeof(Window));
+        i = (int) (sizeof (TermWin.parent) / sizeof (Window));
 
       while (i--)
         if (TermWin.parent[i] != None)
-          XClearWindow(Xdisplay, TermWin.parent[i]);
+          XClearWindow (display->display, TermWin.parent[i]);
     }
 #endif
 
-  XClearWindow (Xdisplay, TermWin.vt);
+  if (really)
+    XClearWindow (display->display, TermWin.vt);
 }
 
 /* ------------------------------------------------------------------------- */
-/* INTPROTO */
-void
-rxvt_scr_reverse_selection(pR)
-{
-    int             i, col, row, end_row;
-    rend_t         *srp;
-
-    if (R->selection.op && R->current_screen == R->selection.screen) {
-        end_row = R->TermWin.saveLines - R->TermWin.view_start;
-        i = R->selection.beg.row + R->TermWin.saveLines;
-        row = R->selection.end.row + R->TermWin.saveLines;
-        if (i >= end_row)
-            col = R->selection.beg.col;
-        else {
-            col = 0;
-            i = end_row;
+void
+rxvt_term::scr_reverse_selection ()
+{
+  if (selection.op && current_screen == selection.screen)
+    {
+      int end_row = TermWin.saveLines - TermWin.view_start;
+      int i = selection.beg.row + TermWin.saveLines;
+      int col, row = selection.end.row + TermWin.saveLines;
+      rend_t *srp;
+
+#if ENABLE_FRILLS
+      if (selection.rect)
+        {
+          end_row += TermWin.nrow;
+
+          for (; i <= row && i <= end_row; i++)
+            for (srp = screen.rend[i], col = selection.beg.col; col < selection.end.col; col++)
+              srp[col] ^= RS_RVid;
         }
-        end_row += R->TermWin.nrow;
-        for (; i < row && i < end_row; i++, col = 0)
-            for (srp = R->screen.rend[i]; col < R->TermWin.ncol; col++)
-#ifndef OPTION_HC
-                srp[col] ^= RS_RVid;
-#else
-                srp[col] ^= RS_Blink;
-#endif
-        if (i == row && i < end_row)
-            for (srp = R->screen.rend[i]; col < R->selection.end.col; col++)
-#ifndef OPTION_HC
-                srp[col] ^= RS_RVid;
-#else
-                srp[col] ^= RS_Blink;
+      else
 #endif
+        {
+          if (i >= end_row)
+            col = selection.beg.col;
+          else
+            {
+              col = 0;
+              i = end_row;
+            }
+
+          end_row += TermWin.nrow;
+
+          for (; i < row && i < end_row; i++, col = 0)
+            for (srp = screen.rend[i]; col < TermWin.ncol; col++)
+              srp[col] ^= RS_RVid;
+
+          if (i == row && i < end_row)
+            for (srp = screen.rend[i]; col < selection.end.col; col++)
+              srp[col] ^= RS_RVid;
+        }
     }
 }
 
@@ -2331,27 +2590,28 @@ rxvt_scr_reverse_selection(pR)
  * invoking routine must close the fd.
  */
 #if 0
-/* EXTPROTO */
-void
-rxvt_scr_dump(pR_ int fd)
-{
-    int             row, wrote;
-    unsigned int    width, towrite;
-    char            r1[] = "\n";
-
-    for (row = R->TermWin.saveLines - R->TermWin.nscrolled;
-         row < R->TermWin.saveLines + R->TermWin.nrow - 1; row++) {
-        width = R->screen.tlen[row] >= 0 ? R->screen.tlen[row]
-                                         : R->TermWin.ncol;
-        for (towrite = width; towrite; towrite -= wrote) {
-            wrote = write(fd, &(R->screen.text[row][width - towrite]),
-                          towrite);
-            if (wrote < 0)
-                return;         /* XXX: death, no report */
+void
+rxvt_term::scr_dump (int fd)
+{
+  int             row, wrote;
+  unsigned int    width, towrite;
+  char            r1[] = "\n";
+
+  for (row = TermWin.saveLines - TermWin.nscrolled;
+       row < TermWin.saveLines + TermWin.nrow - 1; row++)
+    {
+      width = screen.tlen[row] >= 0 ? screen.tlen[row]
+              : TermWin.ncol;
+      for (towrite = width; towrite; towrite -= wrote)
+        {
+          wrote = write (fd, & (screen.text[row][width - towrite]),
+                        towrite);
+          if (wrote < 0)
+            return;         /* XXX: death, no report */
         }
-        if (R->screen.tlen[row] >= 0)
-            if (write(fd, r1, 1) <= 0)
-                return; /* XXX: death, no report */
+      if (screen.tlen[row] >= 0)
+        if (write (fd, r1, 1) <= 0)
+          return; /* XXX: death, no report */
     }
 }
 #endif
@@ -2361,37 +2621,36 @@ rxvt_scr_dump(pR_ int fd)
  * ------------------------------------------------------------------------- */
 
 /*
- * -R->TermWin.nscrolled <= (selection row) <= R->TermWin.nrow - 1
+ * -TermWin.nscrolled <= (selection row) <= TermWin.nrow - 1
  */
-/* EXTPROTO */
 void
-rxvt_selection_check(pR_ int check_more)
+rxvt_term::selection_check (int check_more)
 {
-    row_col_t       pos;
+  row_col_t pos;
 
-    if (!R->selection.op)
-        return;
+  if (!selection.op)
+    return;
 
-    pos.row = pos.col = 0;
-    if ((R->selection.beg.row < -(int32_t)R->TermWin.nscrolled)
-        || (R->selection.beg.row >= R->TermWin.nrow)
-        || (R->selection.mark.row < -(int32_t)R->TermWin.nscrolled)
-        || (R->selection.mark.row >= R->TermWin.nrow)
-        || (R->selection.end.row < -(int32_t)R->TermWin.nscrolled)
-        || (R->selection.end.row >= R->TermWin.nrow)
-        || (check_more == 1
-            && R->current_screen == R->selection.screen
-            && !ROWCOL_IS_BEFORE(R->screen.cur, R->selection.beg)
-            && ROWCOL_IS_BEFORE(R->screen.cur, R->selection.end))
-        || (check_more == 2
-            && ROWCOL_IS_BEFORE(R->selection.beg, pos)
-            && ROWCOL_IS_AFTER(R->selection.end, pos))
-        || (check_more == 3
-            && ROWCOL_IS_AFTER(R->selection.end, pos))
-        || (check_more == 4     /* screen width change */
-            && (R->selection.beg.row != R->selection.end.row
-                || R->selection.end.col > R->TermWin.ncol)))
-        CLEAR_SELECTION(R);
+  pos.row = pos.col = 0;
+  if ((selection.beg.row < - (int32_t)TermWin.nscrolled)
+      || (selection.beg.row >= TermWin.nrow)
+      || (selection.mark.row < - (int32_t)TermWin.nscrolled)
+      || (selection.mark.row >= TermWin.nrow)
+      || (selection.end.row < - (int32_t)TermWin.nscrolled)
+      || (selection.end.row >= TermWin.nrow)
+      || (check_more == 1
+          && current_screen == selection.screen
+          && !ROWCOL_IS_BEFORE (screen.cur, selection.beg)
+          && ROWCOL_IS_BEFORE (screen.cur, selection.end))
+      || (check_more == 2
+          && ROWCOL_IS_BEFORE (selection.beg, pos)
+          && ROWCOL_IS_AFTER (selection.end, pos))
+      || (check_more == 3
+          && ROWCOL_IS_AFTER (selection.end, pos))
+      || (check_more == 4     /* screen width change */
+          && (selection.beg.row != selection.end.row
+              || selection.end.col > TermWin.ncol)))
+    CLEAR_SELECTION ();
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2402,27 +2661,22 @@ void
 rxvt_term::paste (const unsigned char *data, unsigned int len)
 {
   unsigned int i, j, n;
-  unsigned char *ds = (unsigned char *)rxvt_malloc (PROP_SIZE);
-  
-#if 0
-  /* a paste should act like the user is typing, so check scrollTtyKeypress */
-  ZERO_SCROLLBACK (r);
-#endif
+  unsigned char *ds = (unsigned char *)rxvt_malloc (PASTE_SIZE);
 
   /* convert normal newline chars into common keyboard Return key sequence */
-  for (i = 0; i < len; i += PROP_SIZE)
+  for (i = 0; i < len; i += PASTE_SIZE)
     {
-      n = min (len - i, PROP_SIZE);
-      MEMCPY (ds, data + i, n);
+      n = min (len - i, PASTE_SIZE);
+      memcpy (ds, data + i, n);
 
       for (j = 0; j < n; j++)
-        if (ds[j] == '\n')
-          ds[j] = '\r';
+        if (ds[j] == C0_LF)
+          ds[j] = C0_CR;
 
       tt_write (ds, (int)n);
     }
 
-  free(ds);
+  free (ds);
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2430,108 +2684,166 @@ rxvt_term::paste (const unsigned char *data, unsigned int len)
  * Respond to a notification that a primary selection has been sent
  * EXT: SelectionNotify
  */
-/* EXTPROTO */
-int
-rxvt_selection_paste(pR_ Window win, Atom prop, Bool delete_prop)
+void
+rxvt_term::selection_paste (Window win, Atom prop, bool delete_prop)
 {
-  long nread = 0;
-  unsigned long bytes_after;
-  XTextProperty ct;
-
-  D_SELECT((stderr, "rxvt_selection_paste(%08lx, %lu, %d), wait=%2x", win, (unsigned long)prop, (int)delete_prop, R->selection_wait));
-
   if (prop == None)         /* check for failed XConvertSelection */
     {
-      if ((R->selection_type & Sel_CompoundText))
+      if ((selection_type & Sel_CompoundText))
         {
-          int selnum = R->selection_type & Sel_whereMask;
+          int selnum = selection_type & Sel_whereMask;
 
-          R->selection_type = 0;
+          selection_type = 0;
           if (selnum != Sel_direct)
-            rxvt_selection_request_other(aR_ XA_STRING, selnum);
+            selection_request_other (XA_STRING, selnum);
         }
-      
-      if ((R->selection_type & Sel_UTF8String))
+
+      if ((selection_type & Sel_UTF8String))
         {
-          int selnum = R->selection_type & Sel_whereMask;
+          int selnum = selection_type & Sel_whereMask;
 
-          R->selection_type = Sel_CompoundText;
+          selection_type = Sel_CompoundText;
           if (selnum != Sel_direct)
-            rxvt_selection_request_other(aR_ R->xa[XA_COMPOUND_TEXT], selnum);
+            selection_request_other (xa[XA_COMPOUND_TEXT], selnum);
           else
-            R->selection_type = 0;
+            selection_type = 0;
         }
-      
-      return 0;
+
+      return;
     }
 
-  for (;;)
+  unsigned long bytes_after;
+  XTextProperty ct;
+
+  if (XGetWindowProperty (display->display, win, prop,
+                          0, PROP_SIZE / 4,
+                          delete_prop, AnyPropertyType,
+                          &ct.encoding, &ct.format,
+                          &ct.nitems, &bytes_after,
+                          &ct.value) != Success)
     {
-      if (XGetWindowProperty(R->Xdisplay, win, prop, (long)(nread / 4),
-                             (long)(PROP_SIZE / 4), delete_prop,
-                             AnyPropertyType, &ct.encoding, &ct.format,
-                             &ct.nitems, &bytes_after,
-                             &ct.value) != Success)
-        break;
+      ct.value = 0;
+      goto bailout;
+    }
 
-      if (ct.encoding == 0)
-        {
-          D_SELECT((stderr, "rxvt_selection_paste: property didn't exist!"));
-          break;
-        }
+  if (ct.encoding == None)
+    goto bailout;
 
-      if (ct.value == NULL)
+  if (bytes_after)
+    {
+      // fetch and append remaining data
+      XTextProperty ct2;
+
+      if (XGetWindowProperty (display->display, win, prop,
+                              ct.nitems / 4, (bytes_after + 3) / 4,
+                              delete_prop, AnyPropertyType,
+                              &ct2.encoding, &ct2.format,
+                              &ct2.nitems, &bytes_after,
+                              &ct2.value) != Success)
+        goto bailout;
+
+      // realloc should be compatible to XFree, here, and elsewhere, too
+      ct.value = (unsigned char *)realloc (ct.value, ct.nitems + ct2.nitems + 1);
+      memcpy (ct.value + ct.nitems, ct2.value, ct2.nitems + 1);
+      ct.nitems += ct2.nitems;
+
+      XFree (ct2.value);
+    }
+
+  if (ct.value == 0)
+    goto bailout;
+
+  if (ct.encoding == xa[XA_INCR])
+    {
+      // INCR selection, start handshake
+      if (!delete_prop)
+        XDeleteProperty (display->display, win, prop);
+
+      selection_wait = Sel_incr;
+      incr_buf_fill = 0;
+      incr_ev.start (NOW + 10);
+
+      goto bailout;
+    }
+
+  if (ct.nitems == 0)
+    {
+      if (selection_wait == Sel_incr)
         {
-          D_SELECT((stderr, "rxvt_selection_paste: property shooting blanks!"));
-          continue;
-        }
+          XFree (ct.value);
 
-      if (ct.nitems == 0)
+          // finally complete, now paste the whole thing
+          selection_wait = Sel_normal;
+          ct.value = (unsigned char *)incr_buf;
+          ct.nitems = incr_buf_fill;
+          incr_buf = 0;
+          incr_buf_size = 0;
+          incr_ev.stop ();
+        }
+      else 
         {
-          D_SELECT((stderr, "rxvt_selection_paste: property empty - also INCR end"));
-          if (R->selection_wait == Sel_normal && nread == 0)
+          if (selection_wait == Sel_normal
+              && (win != display->root || prop != XA_CUT_BUFFER0)) // avoid recursion
             {
               /*
                * pass through again trying CUT_BUFFER0 if we've come from
-               * XConvertSelection() but nothing was presented
+               * XConvertSelection () but nothing was presented
                */
-              D_SELECT((stderr, "rxvt_selection_request: pasting CUT_BUFFER0"));
-              rxvt_selection_paste (aR_ Xroot, XA_CUT_BUFFER0, False);
+              selection_paste (display->root, XA_CUT_BUFFER0, False);
             }
 
-          nread = -1;         /* discount any previous stuff */
-          break;
+          goto bailout;
         }
+    }
+  else if (selection_wait == Sel_incr)
+    {
+      incr_ev.start (NOW + 10);
 
-      nread += ct.nitems;
-
-      char **cl;
-      int cr;
-      if (XmbTextPropertyToTextList (R->Xdisplay, &ct, &cl,
-                                     &cr) >= 0 && cl)
+      while (incr_buf_fill + ct.nitems > incr_buf_size)
         {
-          for (int i = 0; i < cr; i++)
-            R->paste ((unsigned char *)cl[i], STRLEN (cl[i]));
-
-          XFreeStringList (cl);
+          incr_buf_size = incr_buf_size ? incr_buf_size * 2 : 128*1024;
+          incr_buf = (char *)realloc (incr_buf, incr_buf_size);
         }
-      else
-        R->paste (ct.value, ct.nitems);
 
-      if (bytes_after == 0)
-        break;
+      memcpy (incr_buf + incr_buf_fill, ct.value, ct.nitems);
+      incr_buf_fill += ct.nitems;
 
-      XFree (ct.value);
+      goto bailout;
+    }
+
+  char **cl;
+  int cr;
+
+#if ENABLE_FRILLS
+  // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
+  // so recode it manually
+  if (ct.encoding == xa[XA_UTF8_STRING])
+    {
+      wchar_t *w = rxvt_utf8towcs ((const char *)ct.value, ct.nitems);
+      char *s = rxvt_wcstombs (w);
+      free (w);
+      // TODO: strlen == only the first element will be converted. well...
+      paste ((unsigned char *)s, strlen (s));
+      free (s);
     }
+  else
+#endif
+  if (XmbTextPropertyToTextList (display->display, &ct, &cl, &cr) >= 0
+      && cl)
+    {
+      for (int i = 0; i < cr; i++)
+        paste ((unsigned char *)cl[i], strlen (cl[i]));
 
-  if (ct.value)
-    XFree (ct.value);
+      XFreeStringList (cl);
+    }
+  else
+    paste (ct.value, ct.nitems); // paste raw
 
-  if (R->selection_wait == Sel_normal)
-    R->selection_wait = Sel_none;
+bailout:
+  XFree (ct.value);
 
-  D_SELECT((stderr, "rxvt_selection_paste: bytes written: %ld", nread));
-  return (int)nread;
+  if (selection_wait == Sel_normal)
+    selection_wait = Sel_none;
 }
 
 void
@@ -2539,121 +2851,94 @@ rxvt_term::incr_cb (time_watcher &w)
 {
   selection_wait = Sel_none;
 
-  rxvt_print_error ("data loss: timeout on INCR selection paste");
+  incr_buf_size = 0;
+  free (incr_buf);
+
+  rxvt_warn ("data loss: timeout on INCR selection paste, ignoring.\n");
 }
 
-/*
- * INCR support originally provided by Paul Sheer <psheer@obsidian.co.za>
- */
-/* EXTPROTO */
 void
-rxvt_selection_property(pR_ Window win, Atom prop)
+rxvt_term::selection_property (Window win, Atom prop)
 {
-    int             reget_time = 0;
+  if (prop == None || selection_wait != Sel_incr)
+    return;
 
-    if (prop == None)
-        return;
-    D_SELECT((stderr, "rxvt_selection_property(%08lx, %lu)", win, (unsigned long)prop));
-    if (R->selection_wait == Sel_normal) {
-        int             a, afmt;
-        Atom            atype;
-        unsigned long   bytes_after, nitems;
-        unsigned char  *s = NULL;
-
-        a = XGetWindowProperty(R->Xdisplay, win, prop, 0L, 1L, False,
-                               R->xa[XA_INCR], &atype, &afmt, &nitems,
-                               &bytes_after, &s);
-        if (s)
-            XFree(s);
-        if (a != Success)
-            return;
-#ifndef __CYGWIN32__
-        if (atype == R->xa[XA_INCR]) {  /* start an INCR transfer */
-            D_SELECT((stderr, "rxvt_selection_property: INCR: starting transfer"));
-            XDeleteProperty(R->Xdisplay, win, prop);
-            XFlush(R->Xdisplay);
-            reget_time = 1;
-            R->selection_wait = Sel_incr;
-        }
-#endif
-    } else if (R->selection_wait == Sel_incr) {
-        reget_time = 1;
-        if (rxvt_selection_paste(aR_ win, prop, True) == -1) {
-            D_SELECT((stderr, "rxvt_selection_property: INCR: clean end"));
-            R->selection_wait = Sel_none;
-            R->incr_ev.stop ();
-        }
-    }
-    if (reget_time) /* received more data so reget time */
-      R->incr_ev.start (NOW + 10);
+  selection_paste (win, prop, true);
 }
+
 /* ------------------------------------------------------------------------- */
 /*
  * Request the current selection: 
  * Order: > internal selection if available
  *        > PRIMARY, SECONDARY, CLIPBOARD if ownership is claimed (+)
  *        > CUT_BUFFER0
- * (+) if ownership is claimed but property is empty, rxvt_selection_paste()
+ * (+) if ownership is claimed but property is empty, rxvt_selection_paste ()
  *     will auto fallback to CUT_BUFFER0
  * EXT: button 2 release
  */
-/* EXTPROTO */
 void
-rxvt_selection_request(pR_ Time tm, int x, int y)
+rxvt_term::selection_request (Time tm, int x, int y)
 {
-    D_SELECT((stderr, "rxvt_selection_request(%lu, %d, %d)", tm, x, y));
-    if (x < 0 || x >= R->TermWin.width || y < 0 || y >= R->TermWin.height)
-        return;                 /* outside window */
+  if (x < 0 || x >= TermWin.width || y < 0 || y >= TermWin.height)
+    return;                 /* outside window */
 
-    if (R->selection.text != NULL) {    /* internal selection */
-        D_SELECT((stderr, "rxvt_selection_request: pasting internal"));
-        R->paste (R->selection.text, R->selection.len);
-        return;
-    } else {
-        int             i;
+  if (selection.text)
+    { /* internal selection */
+      char *str = rxvt_wcstombs (selection.text, selection.len);
+      paste ((unsigned char *)str, strlen (str));
+      free (str);
+      return;
+    }
+  else
+    {
+      int i;
+
+      selection_request_time = tm;
+      selection_wait = Sel_normal;
 
-        R->selection_request_time = tm;
-        R->selection_wait = Sel_normal;
-        for (i = Sel_Primary; i <= Sel_Clipboard; i++) {
+      for (i = Sel_Primary; i <= Sel_Clipboard; i++)
+        {
 #if X_HAVE_UTF8_STRING
-            R->selection_type = Sel_UTF8String;
-            if (rxvt_selection_request_other(aR_ R->xa[XA_UTF8_STRING], i))
-                return;
+          selection_type = Sel_UTF8String;
+          if (selection_request_other (xa[XA_UTF8_STRING], i))
+            return;
 #else
-            R->selection_type = Sel_CompoundText;
-            if (rxvt_selection_request_other(aR_ R->xa[XA_COMPOUND_TEXT], i))
-                return;
+          selection_type = Sel_CompoundText;
+          if (selection_request_other (xa[XA_COMPOUND_TEXT], i))
+            return;
 #endif
         }
     }
-    R->selection_wait = Sel_none;       /* don't loop in rxvt_selection_paste() */
-    D_SELECT((stderr, "rxvt_selection_request: pasting CUT_BUFFER0"));
-    rxvt_selection_paste(aR_ Xroot, XA_CUT_BUFFER0, False);
+
+  selection_wait = Sel_none;       /* don't loop in selection_paste () */
+  selection_paste (display->root, XA_CUT_BUFFER0, false);
 }
 
-/* INTPROTO */
 int
-rxvt_selection_request_other(pR_ Atom target, int selnum)
+rxvt_term::selection_request_other (Atom target, int selnum)
 {
-    Atom            sel;
+  Atom sel;
 #ifdef DEBUG_SELECT
-    char           *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
+  char *debug_xa_names[] = { "PRIMARY", "SECONDARY", "CLIPBOARD" };
 #endif
 
-    R->selection_type |= selnum;
-    if (selnum == Sel_Primary)
-        sel = XA_PRIMARY;
-    else if (selnum == Sel_Secondary)
-        sel = XA_SECONDARY;
-    else
-        sel = R->xa[XA_CLIPBOARD];
-    if (XGetSelectionOwner(R->Xdisplay, sel) != None) {
-        D_SELECT((stderr, "rxvt_selection_request_other: pasting %s", debug_xa_names[selnum]));
-        XConvertSelection(R->Xdisplay, sel, target, R->xa[XA_VT_SELECTION],
-                          R->TermWin.vt, R->selection_request_time);
-        return 1;
+  selection_type |= selnum;
+
+  if (selnum == Sel_Primary)
+    sel = XA_PRIMARY;
+  else if (selnum == Sel_Secondary)
+    sel = XA_SECONDARY;
+  else
+    sel = xa[XA_CLIPBOARD];
+
+  if (XGetSelectionOwner (display->display, sel) != None)
+    {
+      XConvertSelection (display->display, sel, target, xa[XA_VT_SELECTION],
+                         TermWin.vt, selection_request_time);
+      return 1;
     }
-    return 0;
+
+  return 0;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2661,18 +2946,17 @@ rxvt_selection_request_other(pR_ Atom target, int selnum)
  * Clear all selected text
  * EXT: SelectionClear
  */
-/* EXTPROTO */
 void
-rxvt_selection_clear(pR)
+rxvt_term::selection_clear ()
 {
-    D_SELECT((stderr, "rxvt_selection_clear()"));
+  want_refresh = 1;
+  free (selection.text);
+  selection.text = NULL;
+  selection.len = 0;
+  CLEAR_SELECTION ();
 
-    R->want_refresh = 1;
-    if (R->selection.text)
-        free(R->selection.text);
-    R->selection.text = NULL;
-    R->selection.len = 0;
-    CLEAR_SELECTION(R);
+  if (display->selection_owner == this)
+    display->selection_owner = 0;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2680,124 +2964,125 @@ rxvt_selection_clear(pR)
  * Copy a selection into the cut buffer
  * EXT: button 1 or 3 release
  */
-/* EXTPROTO */
 void
-rxvt_selection_make(pR_ Time tm)
+rxvt_term::selection_make (Time tm)
 {
-    int             i, col, end_col, row, end_row;
-    unsigned char  *new_selection_text;
-    char           *str;
-    text_t         *t;
-#ifdef ACS_ASCII
-    rend_t         *re;
-#endif
+  int i, col, end_col, row, end_row;
+  wchar_t *new_selection_text;
+  text_t *t;
 
-    D_SELECT((stderr, "rxvt_selection_make(): R->selection.op=%d, R->selection.clicks=%d", R->selection.op, R->selection.clicks));
-    switch (R->selection.op) {
-    case SELECTION_CONT:
+  switch (selection.op)
+    {
+      case SELECTION_CONT:
         break;
-    case SELECTION_INIT:
-        CLEAR_SELECTION(R);
-    /* FALLTHROUGH */
-    case SELECTION_BEGIN:
-        R->selection.op = SELECTION_DONE;
-    /* FALLTHROUGH */
-    default:
+      case SELECTION_INIT:
+        CLEAR_SELECTION ();
+        /* FALLTHROUGH */
+      case SELECTION_BEGIN:
+        selection.op = SELECTION_DONE;
+        /* FALLTHROUGH */
+      default:
         return;
     }
-    R->selection.op = SELECTION_DONE;
 
-    if (R->selection.clicks == 4)
-        return;                 /* nothing selected, go away */
+  selection.op = SELECTION_DONE;
 
-    i = (R->selection.end.row - R->selection.beg.row + 1) * (R->TermWin.ncol + 1) + 1;
-    str = (char *)rxvt_malloc(i * MB_CUR_MAX + 1);
+  if (selection.clicks == 4)
+    return;                 /* nothing selected, go away */
 
-    new_selection_text = (unsigned char *)str;
+  i = (selection.end.row - selection.beg.row + 1) * (TermWin.ncol + 1);
+  new_selection_text = (wchar_t *)rxvt_malloc ((i + 4) * sizeof (wchar_t));
 
-    col = R->selection.beg.col;
-    MAX_IT(col, 0);
-    row = R->selection.beg.row + R->TermWin.saveLines;
-    end_row = R->selection.end.row + R->TermWin.saveLines;
+  col = selection.beg.col;
+  row = selection.beg.row + TermWin.saveLines;
+  end_row = selection.end.row + TermWin.saveLines;
+  int ofs = 0;
+  int extra = 0;
 
-    for (; row <= end_row; row++, col = 0)
-      {
-        t = &(R->screen.text[row][col]);
+  for (; row <= end_row; row++, col = 0)
+    {
+      end_col = screen.tlen[row];
 
-        end_col = R->screen.tlen[row];
+#if ENABLE_FRILLS
+      if (selection.rect)
+        {
+          col = selection.beg.col;
+          end_col = TermWin.ncol + 1;
+        }
+#endif
 
-        if (end_col == -1)
-          end_col = R->TermWin.ncol;
+      MAX_IT (col, 0);
 
-        if (row == end_row)
-          MIN_IT (end_col, R->selection.end.col);
+      if (end_col == -1)
+        end_col = TermWin.ncol;
 
-        for (; col < end_col; col++)
+      if (row == end_row || selection.rect)
+        MIN_IT (end_col, selection.end.col);
+
+      t = &screen.text[row][col];
+      for (; col < end_col; col++)
+        {
           if (*t == NOCHAR)
             t++;
-          else
+#if ENABLE_COMBINING
+          else if (IS_COMPOSE (*t))
             {
-              int len = wctomb (str, *t++);
-              if (len > 0)
-                str += len;
-            }
+              int len = rxvt_composite.expand (*t, 0);
 
-        if (R->screen.tlen[row] != -1 && row != end_row)
-            *str++ = '\n';
-      }
+              extra -= (len - 1);
 
-#ifndef NO_OLD_SELECTION
-    if (R->selection_style == OLD_SELECT)
-        if (end_col == R->TermWin.ncol)
-            *str++ = '\n';
-#endif
-#ifndef NO_NEW_SELECTION
-    if (R->selection_style != OLD_SELECT)
-        if (end_col != R->selection.end.col)
-            *str++ = '\n';
+              if (extra < 0)
+                {
+                  extra += i;
+                  i += i;
+                  new_selection_text = (wchar_t *)rxvt_realloc (new_selection_text, (i + 4) * sizeof (wchar_t));
+                }
+
+              ofs += rxvt_composite.expand (*t++, new_selection_text + ofs);
+            }
 #endif
-    *str = '\0';
+          else
+            new_selection_text[ofs++] = *t++;
+        }
 
-    i = str - (char *)new_selection_text;
-    if (i == 0)
-      {
-        free (new_selection_text);
-        return;
-      }
+      if (screen.tlen[row] != -1 && row != end_row)
+        new_selection_text[ofs++] = C0_LF;
+    }
+
+  if (end_col != selection.end.col)
+    new_selection_text[ofs++] = C0_LF;
 
-    // due to MB_MAX_CUR, selection wastage is usually high, so realloc
-    if (str - (char *)new_selection_text > 1024)
-      new_selection_text = (unsigned char *)rxvt_realloc (new_selection_text, i + 1);
+  new_selection_text[ofs] = 0;
 
-    R->selection.len = i;
+  if (ofs == 0)
+    {
+      free (new_selection_text);
+      return;
+    }
 
-    if (R->selection.text)
-        free (R->selection.text);
+  free (selection.text);
 
-    R->selection.text = new_selection_text;
+  // we usually allocate much more than necessary, so realloc it smaller again
+  selection.len = ofs;
+  selection.text = (wchar_t *)rxvt_realloc (new_selection_text, (ofs + 1) * sizeof (wchar_t));
 
-    XSetSelectionOwner(R->Xdisplay, XA_PRIMARY, R->TermWin.vt, tm);
-    if (XGetSelectionOwner(R->Xdisplay, XA_PRIMARY) != R->TermWin.vt)
-        rxvt_print_error("can't get primary selection");
+  XSetSelectionOwner (display->display, XA_PRIMARY, TermWin.vt, tm);
+  if (XGetSelectionOwner (display->display, XA_PRIMARY) == TermWin.vt)
+    display->set_selection_owner (this);
+  else
+    rxvt_warn ("can't get primary selection, ignoring.\n");
 
+#if 0
+  XTextProperty ct;
 
+  if (XwcTextListToTextProperty (display->display, &selection.text, 1, XStringStyle, &ct) >= 0)
     {
-      XTextProperty ct;
-      char *cl = (char *)R->selection.text;
-
-      if (XmbTextListToTextProperty(R->Xdisplay, &cl, 1, XStringStyle, &ct) >= 0)
-        {
-          XChangeProperty(R->Xdisplay, Xroot, XA_CUT_BUFFER0, XA_STRING, 8,
-                          PropModeReplace, ct.value, ct.nitems);
-          XFree (ct.value);
-        }
-      else
-        XChangeProperty(R->Xdisplay, Xroot, XA_CUT_BUFFER0, XA_STRING, 8,
-                        PropModeReplace, R->selection.text, (int)R->selection.len);
+      set_string_property (XA_CUT_BUFFER0, ct.value, ct.nitems);
+      XFree (ct.value);
     }
+#endif
 
-    R->selection_time = tm;
-    D_SELECT((stderr, "rxvt_selection_make(): R->selection.len=%d", R->selection.len));
+  selection_time = tm;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2808,43 +3093,47 @@ rxvt_selection_make(pR_ Time tm)
 void
 rxvt_term::selection_click (int clicks, int x, int y)
 {
-  D_SELECT((stderr, "rxvt_selection_click(%d, %d, %d)", clicks, x, y));
-
   clicks = ((clicks - 1) % 3) + 1;
   selection.clicks = clicks;       /* save clicks so extend will work */
 
-  rxvt_selection_start_colrow (this, Pixel2Col(x), Pixel2Row(y));
+  selection_start_colrow (Pixel2Col (x), Pixel2Row (y));
 
   if (clicks == 2 || clicks == 3)
-    rxvt_selection_extend_colrow (this, selection.mark.col,
-                                  selection.mark.row + TermWin.view_start,
-                                  0, /* button 3     */
-                                  1, /* button press */
-                                  0);        /* click change */
+    selection_extend_colrow (selection.mark.col,
+                             selection.mark.row + TermWin.view_start,
+                             0, /* button 3     */
+                             1, /* button press */
+                             0);        /* click change */
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Mark a selection at the specified col/row
  */
-/* INTPROTO */
 void
-rxvt_selection_start_colrow(pR_ int col, int row)
+rxvt_term::selection_start_colrow (int col, int row)
 {
-    R->want_refresh = 1;
-    R->selection.mark.col = col;
-    R->selection.mark.row = row - R->TermWin.view_start;
-    MAX_IT(R->selection.mark.row, -(int32_t)R->TermWin.nscrolled);
-    MIN_IT(R->selection.mark.row, (int32_t)R->TermWin.nrow - 1);
-    MAX_IT(R->selection.mark.col, 0);
-    MIN_IT(R->selection.mark.col, (int32_t)R->TermWin.ncol - 1);
+  want_refresh = 1;
+  selection.mark.col = col;
+  selection.mark.row = row - TermWin.view_start;
+
+  MAX_IT (selection.mark.row, - (int32_t)TermWin.nscrolled);
+  MIN_IT (selection.mark.row, (int32_t)TermWin.nrow - 1);
+  MAX_IT (selection.mark.col, 0);
+  MIN_IT (selection.mark.col, (int32_t)TermWin.ncol - 1);
 
-    if (R->selection.op) {      /* clear the old selection */
-        R->selection.beg.row = R->selection.end.row = R->selection.mark.row;
-        R->selection.beg.col = R->selection.end.col = R->selection.mark.col;
+  while (selection.mark.col > 0
+         && screen.text[selection.mark.row + TermWin.saveLines][selection.mark.col] == NOCHAR)
+    --selection.mark.col;
+  
+  if (selection.op)
+    {      /* clear the old selection */
+      selection.beg.row = selection.end.row = selection.mark.row;
+      selection.beg.col = selection.end.col = selection.mark.col;
     }
-    R->selection.op = SELECTION_INIT;
-    R->selection.screen = R->current_screen;
+
+  selection.op = SELECTION_INIT;
+  selection.screen = current_screen;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2854,82 +3143,88 @@ rxvt_selection_start_colrow(pR_ int col, int row)
  */
 
 /* what do we want: spaces/tabs are delimiters or cutchars or non-cutchars */
-#define DELIMIT_TEXT(x) \
-    (((x) == ' ' || (x) == '\t') ? 2 : (STRCHR(R->rs[Rs_cutchars], (x)) != NULL))
+#define DELIMIT_TEXT(x)                \
+    (unicode::is_space (x) ? 2 : (x) <= 0xff && !!strchr (rs[Rs_cutchars], (x)))
 #define DELIMIT_REND(x)        1
 
-/* INTPROTO */
-void
-rxvt_selection_delimit_word(pR_ enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
-{
-    int             col, row, dirnadd, tcol, trow, w1, w2;
-    row_col_t       bound;
-    text_t         *stp;
-    rend_t         *srp;
-
-    if (dirn == UP) {
-        bound.row = R->TermWin.saveLines - R->TermWin.nscrolled - 1;
-        bound.col = 0;
-        dirnadd = -1;
-    } else {
-        bound.row = R->TermWin.saveLines + R->TermWin.nrow;
-        bound.col = R->TermWin.ncol - 1;
-        dirnadd = 1;
-    }
-    row = mark->row + R->TermWin.saveLines;
-    col = mark->col;
-    MAX_IT(col, 0);
-/* find the edge of a word */
-    stp = &(R->screen.text[row][col]);
-    w1 = DELIMIT_TEXT(*stp);
-
-    if (R->selection_style != NEW_SELECT) {
-        if (w1 == 1) {
-            stp += dirnadd;
-            if (DELIMIT_TEXT(*stp) == 1)
-                goto Old_Word_Selection_You_Die;
-            col += dirnadd;
-        }
-        w1 = 0;
+void
+rxvt_term::selection_delimit_word (enum page_dirn dirn, const row_col_t *mark, row_col_t *ret)
+{
+  int col, row, dirnadd, tcol, trow, w1, w2;
+  row_col_t bound;
+  text_t *stp;
+  rend_t *srp;
+
+  if (dirn == UP)
+    {
+      bound.row = TermWin.saveLines - TermWin.nscrolled - 1;
+      bound.col = 0;
+      dirnadd = -1;
+    }
+  else
+    {
+      bound.row = TermWin.saveLines + TermWin.nrow;
+      bound.col = TermWin.ncol - 1;
+      dirnadd = 1;
     }
-    srp = (&R->screen.rend[row][col]);
-    w2 = DELIMIT_REND(*srp);
 
-    for (;;) {
-        for (; col != bound.col; col += dirnadd) {
-            stp += dirnadd;
-            if (DELIMIT_TEXT(*stp) != w1)
+  row = mark->row + TermWin.saveLines;
+  col = mark->col;
+  MAX_IT (col, 0);
+  /* find the edge of a word */
+  stp = &screen.text[row][col];
+  w1 = DELIMIT_TEXT (*stp);
+
+  srp = &screen.rend[row][col];
+  w2 = DELIMIT_REND (*srp);
+
+  for (;;)
+    {
+      for (; col != bound.col; col += dirnadd)
+        {
+          stp += dirnadd;
+          srp += dirnadd;
+
+          if (*stp == NOCHAR)
+            continue;
+
+          if (DELIMIT_TEXT (*stp) != w1)
+            break;
+          if (DELIMIT_REND (*srp) != w2)
+            break;
+        }
+
+      if ((col == bound.col) && (row != bound.row))
+        {
+          if (screen.tlen[ (row - (dirn == UP ? 1 : 0))] == -1)
+            {
+              trow = row + dirnadd;
+              tcol = dirn == UP ? TermWin.ncol - 1 : 0;
+
+              if (screen.text[trow] == NULL)
                 break;
-            srp += dirnadd;
-            if (DELIMIT_REND(*srp) != w2)
+
+              stp = & (screen.text[trow][tcol]);
+              srp = & (screen.rend[trow][tcol]);
+
+              if (DELIMIT_TEXT (*stp) != w1 || DELIMIT_REND (*srp) != w2)
                 break;
-        }
-        if ((col == bound.col) && (row != bound.row)) {
-            if (R->screen.tlen[(row - (dirn == UP ? 1 : 0))] == -1) {
-                trow = row + dirnadd;
-                tcol = dirn == UP ? R->TermWin.ncol - 1 : 0;
-                if (R->screen.text[trow] == NULL)
-                    break;
-                stp = &(R->screen.text[trow][tcol]);
-                srp = &(R->screen.rend[trow][tcol]);
-                if (DELIMIT_TEXT(*stp) != w1 || DELIMIT_REND(*srp) != w2)
-                    break;
-                row = trow;
-                col = tcol;
-                continue;
+
+              row = trow;
+              col = tcol;
+              continue;
             }
         }
-        break;
+      break;
     }
-  Old_Word_Selection_You_Die:
-    D_SELECT((stderr, "rxvt_selection_delimit_word(%s,...) @ (r:%3d, c:%3d) has boundary (r:%3d, c:%3d)", (dirn == UP ? "up     " : "down"), mark->row, mark->col, row - R->TermWin.saveLines, col));
 
-    if (dirn == DN)
-        col++;                  /* put us on one past the end */
+Old_Word_Selection_You_Die:
+  if (dirn == DN)
+    col++;                  /* put us on one past the end */
 
-/* Poke the values back in */
-    ret->row = row - R->TermWin.saveLines;
-    ret->col = col;
+  /* Poke the values back in */
+  ret->row = row - TermWin.saveLines;
+  ret->col = col;
 }
 
 /* ------------------------------------------------------------------------- */
@@ -2945,297 +3240,284 @@ rxvt_term::selection_extend (int x, int y, int flag)
 {
   int col, row;
 
-  col = Pixel2Col(x);
-  row = Pixel2Row(y);
-  MAX_IT(row, 0);
-  MIN_IT(row, (int)TermWin.nrow - 1);
-  MAX_IT(col, 0);
-  MIN_IT(col, (int)TermWin.ncol);
+  col = Pixel2Col (x);
+  row = Pixel2Row (y);
+  MAX_IT (row, 0);
+  MIN_IT (row, (int)TermWin.nrow - 1);
+  MAX_IT (col, 0);
+  MIN_IT (col, (int)TermWin.ncol);
 
-#ifndef NO_NEW_SELECTION
   /*
   * If we're selecting characters (single click) then we must check first
   * if we are at the same place as the original mark.  If we are then
   * select nothing.  Otherwise, if we're to the right of the mark, you have to
   * be _past_ a character for it to be selected.
   */
-  if (selection_style != OLD_SELECT)
+  if (((selection.clicks % 3) == 1) && !flag
+      && (col == selection.mark.col
+          && (row == selection.mark.row + TermWin.view_start)))
     {
-      if (((selection.clicks % 3) == 1) && !flag
-          && (col == selection.mark.col
-              && (row == selection.mark.row + TermWin.view_start)))
-        {
-          /* select nothing */
-          selection.beg.row = selection.end.row = 0;
-          selection.beg.col = selection.end.col = 0;
-          selection.clicks = 4;
-          want_refresh = 1;
-          D_SELECT((stderr, "rxvt_selection_extend() selection.clicks = 4"));
-          return;
-        }
+      /* select nothing */
+      selection.beg.row = selection.end.row = 0;
+      selection.beg.col = selection.end.col = 0;
+      selection.clicks = 4;
+      want_refresh = 1;
+      return;
     }
-#endif
+
   if (selection.clicks == 4)
     selection.clicks = 1;
 
-  rxvt_selection_extend_colrow (this, col, row, !!flag,  /* ? button 3      */
-                                flag == 1 ? 1 : 0,     /* ? button press  */
-                                0);    /* no click change */
+  selection_extend_colrow (col, row, !!flag,  /* ? button 3      */
+                           flag == 1 ? 1 : 0,     /* ? button press  */
+                           0);    /* no click change */
 }
 
 /* ------------------------------------------------------------------------- */
 /*
  * Extend the selection to the specified col/row
  */
-/* INTPROTO */
-void
-rxvt_selection_extend_colrow(pR_ int32_t col, int32_t row, int button3, int buttonpress, int clickchange)
-{
-    int16_t         ncol = R->TermWin.ncol;
-    int             end_col;
-    row_col_t       pos;
-    enum {
-        LEFT, RIGHT
-    } closeto = RIGHT;
-
-    D_SELECT((stderr, "rxvt_selection_extend_colrow(c:%d, r:%d, %d, %d) clicks:%d, op:%d", col, row, button3, buttonpress, R->selection.clicks, R->selection.op));
-    D_SELECT((stderr, "rxvt_selection_extend_colrow() ENT  b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)", R->selection.beg.row, R->selection.beg.col, R->selection.mark.row, R->selection.mark.col, R->selection.end.row, R->selection.end.col));
-
-    R->want_refresh = 1;
-    switch (R->selection.op) {
-    case SELECTION_INIT:
-        CLEAR_SELECTION(R);
-        R->selection.op = SELECTION_BEGIN;
-    /* FALLTHROUGH */
-    case SELECTION_BEGIN:
-        if (row != R->selection.mark.row || col != R->selection.mark.col
+void
+rxvt_term::selection_extend_colrow (int32_t col, int32_t row, int button3, int buttonpress, int clickchange)
+{
+  int16_t ncol = TermWin.ncol;
+  int end_col;
+  row_col_t pos;
+  enum {
+    LEFT, RIGHT
+  } closeto = RIGHT;
+
+  want_refresh = 1;
+
+  switch (selection.op)
+    {
+      case SELECTION_INIT:
+        CLEAR_SELECTION ();
+        selection.op = SELECTION_BEGIN;
+        /* FALLTHROUGH */
+      case SELECTION_BEGIN:
+        if (row != selection.mark.row || col != selection.mark.col
             || (!button3 && buttonpress))
-            R->selection.op = SELECTION_CONT;
+          selection.op = SELECTION_CONT;
         break;
-    case SELECTION_DONE:
-        R->selection.op = SELECTION_CONT;
-    /* FALLTHROUGH */
-    case SELECTION_CONT:
+      case SELECTION_DONE:
+        selection.op = SELECTION_CONT;
+        /* FALLTHROUGH */
+      case SELECTION_CONT:
         break;
-    case SELECTION_CLEAR:
-        rxvt_selection_start_colrow(aR_ col, row);
-    /* FALLTHROUGH */
-    default:
+      case SELECTION_CLEAR:
+        selection_start_colrow (col, row);
+        /* FALLTHROUGH */
+      default:
         return;
     }
-    if (R->selection.beg.col == R->selection.end.col
-        && R->selection.beg.col != R->selection.mark.col
-        && R->selection.beg.row == R->selection.end.row
-        && R->selection.beg.row != R->selection.mark.row) {
-        R->selection.beg.col = R->selection.end.col = R->selection.mark.col;
-        R->selection.beg.row = R->selection.end.row = R->selection.mark.row;
-        D_SELECT((stderr, "rxvt_selection_extend_colrow() ENT2 b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)", R->selection.beg.row, R->selection.beg.col, R->selection.mark.row, R->selection.mark.col, R->selection.end.row, R->selection.end.col));
+
+  if (selection.beg.col == selection.end.col
+      && selection.beg.col != selection.mark.col
+      && selection.beg.row == selection.end.row
+      && selection.beg.row != selection.mark.row)
+    {
+      selection.beg.col = selection.end.col = selection.mark.col;
+      selection.beg.row = selection.end.row = selection.mark.row;
     }
 
-    pos.col = col;
-    pos.row = row;
+  pos.col = col;
+  pos.row = row;
 
-    pos.row -= R->TermWin.view_start;   /* adjust for scroll */
+  pos.row -= TermWin.view_start;   /* adjust for scroll */
 
-#ifndef NO_OLD_SELECTION
-/*
- * This mimics some of the selection behaviour of version 2.20 and before.
- * There are no ``selection modes'', button3 is always character extension.
- * Note: button3 drag is always available, c.f. v2.20
- * Selection always terminates (left or right as appropriate) at the mark.
- */
-    if (R->selection_style == OLD_SELECT) {
-        if (R->selection.clicks == 1 || button3) {
-            if (R->hate_those_clicks) {
-                R->hate_those_clicks = 0;
-                if (R->selection.clicks == 1) {
-                    R->selection.beg.row = R->selection.mark.row;
-                    R->selection.beg.col = R->selection.mark.col;
-                } else {
-                    R->selection.mark.row = R->selection.beg.row;
-                    R->selection.mark.col = R->selection.beg.col;
-                }
-            }
-            if (ROWCOL_IS_BEFORE(pos, R->selection.mark)) {
-                R->selection.end.row = R->selection.mark.row;
-                R->selection.end.col = R->selection.mark.col + 1;
-                R->selection.beg.row = pos.row;
-                R->selection.beg.col = pos.col;
-            } else {
-                R->selection.beg.row = R->selection.mark.row;
-                R->selection.beg.col = R->selection.mark.col;
-                R->selection.end.row = pos.row;
-                R->selection.end.col = pos.col + 1;
-            }
-        } else if (R->selection.clicks == 2) {
-            rxvt_selection_delimit_word(aR_ UP, &(R->selection.mark),
-                                        &(R->selection.beg));
-            rxvt_selection_delimit_word(aR_ DN, &(R->selection.mark),
-                                        &(R->selection.end));
-            R->hate_those_clicks = 1;
-        } else if (R->selection.clicks == 3) {
-            R->selection.beg.row = R->selection.end.row = R->selection.mark.row;
-            R->selection.beg.col = 0;
-            R->selection.end.col = ncol;
-            R->hate_those_clicks = 1;
+  /*
+   * This is mainly xterm style selection with a couple of differences, mainly
+   * in the way button3 drag extension works.
+   * We're either doing: button1 drag; button3 press; or button3 drag
+   *  a) button1 drag : select around a midpoint/word/line - that point/word/line
+   *     is always at the left/right edge of the selection.
+   *  b) button3 press: extend/contract character/word/line at whichever edge of
+   *     the selection we are closest to.
+   *  c) button3 drag : extend/contract character/word/line - we select around
+   *     a point/word/line which is either the start or end of the selection
+   *     and it was decided by whichever point/word/line was `fixed' at the
+   *     time of the most recent button3 press
+   */
+  if (button3 && buttonpress)
+    { /* button3 press */
+      /*
+       * first determine which edge of the selection we are closest to
+       */
+      if (ROWCOL_IS_BEFORE (pos, selection.beg)
+          || (!ROWCOL_IS_AFTER (pos, selection.end)
+              && (((pos.col - selection.beg.col)
+                   + ((pos.row - selection.beg.row) * ncol))
+                  < ((selection.end.col - pos.col)
+                     + ((selection.end.row - pos.row) * ncol)))))
+        closeto = LEFT;
+
+      if (closeto == LEFT)
+        {
+          selection.beg.row = pos.row;
+          selection.beg.col = pos.col;
+          selection.mark.row = selection.end.row;
+          selection.mark.col = selection.end.col - (selection.clicks == 2);
+        }
+      else
+        {
+          selection.end.row = pos.row;
+          selection.end.col = pos.col;
+          selection.mark.row = selection.beg.row;
+          selection.mark.col = selection.beg.col;
         }
-        D_SELECT((stderr, "rxvt_selection_extend_colrow() EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)", R->selection.beg.row, R->selection.beg.col, R->selection.mark.row, R->selection.mark.col, R->selection.end.row, R->selection.end.col));
-        return;
     }
-#endif                          /* ! NO_OLD_SELECTION */
-#ifndef NO_NEW_SELECTION
-/* selection_style must not be OLD_SELECT to get here */
-/*
- * This is mainly xterm style selection with a couple of differences, mainly
- * in the way button3 drag extension works.
- * We're either doing: button1 drag; button3 press; or button3 drag
- *  a) button1 drag : select around a midpoint/word/line - that point/word/line
- *     is always at the left/right edge of the R->selection.
- *  b) button3 press: extend/contract character/word/line at whichever edge of
- *     the selection we are closest to.
- *  c) button3 drag : extend/contract character/word/line - we select around
- *     a point/word/line which is either the start or end of the selection
- *     and it was decided by whichever point/word/line was `fixed' at the
- *     time of the most recent button3 press
- */
-    if (button3 && buttonpress) {       /* button3 press */
-        /*
-         * first determine which edge of the selection we are closest to
-         */
-        if (ROWCOL_IS_BEFORE(pos, R->selection.beg)
-            || (!ROWCOL_IS_AFTER(pos, R->selection.end)
-                && (((pos.col - R->selection.beg.col)
-                     + ((pos.row - R->selection.beg.row) * ncol))
-                    < ((R->selection.end.col - pos.col)
-                       + ((R->selection.end.row - pos.row) * ncol)))))
-             closeto = LEFT;
-        if (closeto == LEFT) {
-            R->selection.beg.row = pos.row;
-            R->selection.beg.col = pos.col;
-            R->selection.mark.row = R->selection.end.row;
-            R->selection.mark.col = R->selection.end.col
-                                    - (R->selection.clicks == 2);
-        } else {
-            R->selection.end.row = pos.row;
-            R->selection.end.col = pos.col;
-            R->selection.mark.row = R->selection.beg.row;
-            R->selection.mark.col = R->selection.beg.col;
+  else
+    { /* button1 drag or button3 drag */
+      if (ROWCOL_IS_AFTER (selection.mark, pos))
+        {
+          if (selection.mark.row == selection.end.row
+              && selection.mark.col == selection.end.col
+              && clickchange
+              && selection.clicks == 2)
+            selection.mark.col--;
+
+          selection.beg.row = pos.row;
+          selection.beg.col = pos.col;
+          selection.end.row = selection.mark.row;
+          selection.end.col = selection.mark.col + (selection.clicks == 2);
         }
-    } else {                    /* button1 drag or button3 drag */
-        if (ROWCOL_IS_AFTER(R->selection.mark, pos)) {
-            if ((R->selection.mark.row == R->selection.end.row)
-                && (R->selection.mark.col == R->selection.end.col)
-                && clickchange && R->selection.clicks == 2)
-                R->selection.mark.col--;
-            R->selection.beg.row = pos.row;
-            R->selection.beg.col = pos.col;
-            R->selection.end.row = R->selection.mark.row;
-            R->selection.end.col = R->selection.mark.col
-                                   + (R->selection.clicks == 2);
-        } else {
-            R->selection.beg.row = R->selection.mark.row;
-            R->selection.beg.col = R->selection.mark.col;
-            R->selection.end.row = pos.row;
-            R->selection.end.col = pos.col;
+      else
+        {
+          selection.beg.row = selection.mark.row;
+          selection.beg.col = selection.mark.col;
+          selection.end.row = pos.row;
+          selection.end.col = pos.col;
         }
     }
 
-    if (R->selection.clicks == 1) {
-        end_col = R->screen.tlen[R->selection.beg.row + R->TermWin.saveLines];
-        if (end_col != -1 && R->selection.beg.col > end_col) {
-#if 1
-            R->selection.beg.col = ncol;
-#else
-            if (R->selection.beg.row != R->selection.end.row)
-                R->selection.beg.col = ncol;
-            else
-                R->selection.beg.col = R->selection.mark.col;
+  if (selection.clicks == 1)
+    {
+      end_col = screen.tlen[selection.beg.row + TermWin.saveLines];
+
+      if (selection.beg.col > end_col
+          && end_col != -1
+#if ENABLE_FRILLS
+          && !selection.rect
 #endif
-        }
-        end_col = R->screen.tlen[R->selection.end.row + R->TermWin.saveLines];
-        if (end_col != -1 && R->selection.end.col > end_col)
-            R->selection.end.col = ncol;
-
-    } else if (R->selection.clicks == 2) {
-        if (ROWCOL_IS_AFTER(R->selection.end, R->selection.beg))
-            R->selection.end.col--;
-        rxvt_selection_delimit_word(aR_ UP, &(R->selection.beg),
-                                    &(R->selection.beg));
-        rxvt_selection_delimit_word(aR_ DN, &(R->selection.end),
-                                    &(R->selection.end));
-    } else if (R->selection.clicks == 3) {
-#ifndef NO_FRILLS
-        if ((R->Options & Opt_tripleclickwords)) {
-            int             end_row;
-
-            rxvt_selection_delimit_word(aR_ UP, &(R->selection.beg),
-                                        &(R->selection.beg));
-            end_row = R->screen.tlen[R->selection.mark.row
-                                     + R->TermWin.saveLines];
-            for (end_row = R->selection.mark.row; end_row < R->TermWin.nrow;
-                 end_row++) {
-                end_col = R->screen.tlen[end_row + R->TermWin.saveLines];
-                if (end_col != -1) {
-                    R->selection.end.row = end_row;
-                    R->selection.end.col = end_col;
-                    rxvt_selection_remove_trailing_spaces(aR);
-                    break;
+         )
+        selection.beg.col = ncol;
+
+      end_col = screen.tlen[selection.end.row + TermWin.saveLines];
+
+      if (
+          selection.end.col > end_col
+          && end_col != -1
+#if ENABLE_FRILLS
+          && !selection.rect
+#endif
+         )
+        selection.end.col = ncol;
+    }
+  else if (selection.clicks == 2)
+    {
+      if (ROWCOL_IS_AFTER (selection.end, selection.beg))
+        selection.end.col--;
+
+      selection_delimit_word (UP, &selection.beg, &selection.beg);
+      selection_delimit_word (DN, &selection.end, &selection.end);
+    }
+  else if (selection.clicks == 3)
+    {
+#if ENABLE_FRILLS
+      if ((options & Opt_tripleclickwords))
+        {
+          int end_row;
+
+          selection_delimit_word (UP, &selection.beg, &selection.beg);
+          end_row = screen.tlen[selection.mark.row + TermWin.saveLines];
+
+          for (end_row = selection.mark.row; end_row < TermWin.nrow; end_row++)
+            {
+              end_col = screen.tlen[end_row + TermWin.saveLines];
+
+              if (end_col != -1)
+                {
+                  selection.end.row = end_row;
+                  selection.end.col = end_col;
+                  selection_remove_trailing_spaces ();
+                  break;
                 }
             }
-        } else
+        }
+      else
 #endif
         {
-            if (ROWCOL_IS_AFTER(R->selection.mark, R->selection.beg))
-                R->selection.mark.col++;
-            R->selection.beg.col = 0;
-            R->selection.end.col = ncol;
+          if (ROWCOL_IS_AFTER (selection.mark, selection.beg))
+            selection.mark.col++;
+
+          selection.beg.col = 0;
+          selection.end.col = ncol;
         }
     }
-    if (button3 && buttonpress) {       /* mark may need to be changed */
-        if (closeto == LEFT) {
-            R->selection.mark.row = R->selection.end.row;
-            R->selection.mark.col = R->selection.end.col
-                                    - (R->selection.clicks == 2);
-        } else {
-            R->selection.mark.row = R->selection.beg.row;
-            R->selection.mark.col = R->selection.beg.col;
+
+  if (button3 && buttonpress)
+    { /* mark may need to be changed */
+      if (closeto == LEFT)
+        {
+          selection.mark.row = selection.end.row;
+          selection.mark.col = selection.end.col - (selection.clicks == 2);
+        }
+      else
+        {
+          selection.mark.row = selection.beg.row;
+          selection.mark.col = selection.beg.col;
         }
     }
-    D_SELECT((stderr, "rxvt_selection_extend_colrow() EXIT b:(r:%d,c:%d) m:(r:%d,c:%d), e:(r:%d,c:%d)", R->selection.beg.row, R->selection.beg.col, R->selection.mark.row, R->selection.mark.col, R->selection.end.row, R->selection.end.col));
-#endif                          /* ! NO_NEW_SELECTION */
+
+#if ENABLE_FRILLS
+  if (selection.rect && selection.beg.col > selection.end.col)
+    SWAP_IT (selection.beg.col, selection.end.col, int);
+#endif
 }
 
-#ifndef NO_FRILLS
-/* INTPROTO */
+#if ENABLE_FRILLS
 void
-rxvt_selection_remove_trailing_spaces(pR)
+rxvt_term::selection_remove_trailing_spaces ()
 {
-    int32_t         end_col, end_row;
-    text_t         *stp; 
+  int32_t end_col, end_row;
+  text_t *stp;
 
-    end_col = R->selection.end.col;
-    end_row = R->selection.end.row;
-    for ( ; end_row >= R->selection.beg.row; ) {
-        stp = R->screen.text[end_row + R->TermWin.saveLines];
-        while (--end_col >= 0) {
-            if (stp[end_col] != ' ' && stp[end_col] != '\t')
-                break;
-        }
-        if (end_col >= 0
-            || R->screen.tlen[end_row - 1 + R->TermWin.saveLines] != -1) {
-            R->selection.end.col = end_col + 1;
-            R->selection.end.row = end_row;
+  end_col = selection.end.col;
+  end_row = selection.end.row;
+
+  for ( ; end_row >= selection.beg.row; )
+    {
+      stp = screen.text[end_row + TermWin.saveLines];
+
+      while (--end_col >= 0)
+        {
+          if (stp[end_col] != ' '
+              && stp[end_col] != '\t'
+              && stp[end_col] != NOCHAR)
             break;
         }
-        end_row--;
-        end_col = R->TermWin.ncol;
+
+      if (end_col >= 0
+          || screen.tlen[end_row - 1 + TermWin.saveLines] != -1)
+        {
+          selection.end.col = end_col + 1;
+          selection.end.row = end_row;
+          break;
+        }
+
+      end_row--;
+      end_col = TermWin.ncol;
+    }
+
+  if (selection.mark.row > selection.end.row)
+    {
+      selection.mark.row = selection.end.row;
+      selection.mark.col = selection.end.col;
     }
-    if (R->selection.mark.row > R->selection.end.row) {
-        R->selection.mark.row = R->selection.end.row;
-        R->selection.mark.col = R->selection.end.col;
-    } else if (R->selection.mark.row == R->selection.end.row
-               && R->selection.mark.col > R->selection.end.col)
-        R->selection.mark.col = R->selection.end.col;
+  else if (selection.mark.row == selection.end.row
+           && selection.mark.col > selection.end.col)
+    selection.mark.col = selection.end.col;
 }
 #endif
 
@@ -3248,117 +3530,142 @@ void
 rxvt_term::selection_rotate (int x, int y)
 {
   selection.clicks = selection.clicks % 3 + 1;
-  rxvt_selection_extend_colrow (this, Pixel2Col(x), Pixel2Row(y), 1, 0, 1);
+  selection_extend_colrow (Pixel2Col (x), Pixel2Row (y), 1, 0, 1);
 }
 
 /* ------------------------------------------------------------------------- */
 /*
- * On some systems, the Atom typedef is 64 bits wide.  We need to have a type
- * that is exactly 32 bits wide, because a format of 64 is not allowed by
- * the X11 protocol.
- */
-typedef CARD32 Atom32;
-
-/* ------------------------------------------------------------------------- */
-/*
  * Respond to a request for our current selection
  * EXT: SelectionRequest
  */
-/* EXTPROTO */
-void
-rxvt_selection_send(pR_ const XSelectionRequestEvent *rq)
-{
-    XSelectionEvent ev;
-    XTextProperty ct;
-    XICCEncodingStyle style;
-    Atom target;
-
-    ev.type = SelectionNotify;
-    ev.property = None;
-    ev.display = rq->display;
-    ev.requestor = rq->requestor;
-    ev.selection = rq->selection;
-    ev.target = rq->target;
-    ev.time = rq->time;
-
-    if (rq->target == R->xa[XA_TARGETS]) {
-        Atom32 target_list[5];
-        Atom32 *target = target_list;
-
-        *target++ = (Atom32) R->xa[XA_TARGETS];
-        *target++ = (Atom32) XA_STRING;
-        *target++ = (Atom32) R->xa[XA_TEXT];
-        *target++ = (Atom32) R->xa[XA_COMPOUND_TEXT];
-#if X_HAVE_UTF8_STRING
-        *target++ = (Atom32) R->xa[XA_UTF8_STRING];
-#endif
-        XChangeProperty(R->Xdisplay, rq->requestor, rq->property, XA_ATOM,
-                        (8 * sizeof(target_list[0])), PropModeReplace,
-                        (unsigned char *)target_list,
-                        target - target_list);
-        ev.property = rq->property;
-    } else if (rq->target == R->xa[XA_MULTIPLE]) {
-        /* TODO: Handle MULTIPLE */
-    } else if (rq->target == R->xa[XA_TIMESTAMP] && R->selection.text) {
-        XChangeProperty(R->Xdisplay, rq->requestor, rq->property, XA_INTEGER,
-                        (8 * sizeof(Time)), PropModeReplace,
-                        (unsigned char *)&R->selection_time, 1);
-        ev.property = rq->property;
-    } else if (rq->target == XA_STRING
-               || rq->target == R->xa[XA_TEXT]
-               || rq->target == R->xa[XA_COMPOUND_TEXT]
-               || rq->target == R->xa[XA_UTF8_STRING]
-              ) {
-        short freect = 0;
-        int selectlen;
-        char *cl;
-
-        target = rq->target;
-
-        if (target == XA_STRING)
-          // we actually don't do XA_STRING, but who cares, as i18n clients
-          // will ask for another format anyways.
-          style = XStringStyle;
-        else if (target == R->xa[XA_TEXT])
-          style = XTextStyle;
-        else if (target == R->xa[XA_COMPOUND_TEXT])
-          style = XCompoundTextStyle;
+void
+rxvt_term::selection_send (const XSelectionRequestEvent &rq)
+{
+  XSelectionEvent ev;
+
+  ev.type = SelectionNotify;
+  ev.property = None;
+  ev.display = rq.display;
+  ev.requestor = rq.requestor;
+  ev.selection = rq.selection;
+  ev.target = rq.target;
+  ev.time = rq.time;
+
+  if (rq.target == xa[XA_TARGETS])
+    {
+      Atom target_list[6];
+      Atom *target = target_list;
+
+      *target++ = xa[XA_TARGETS];
+      *target++ = xa[XA_TIMESTAMP];
+      *target++ = XA_STRING;
+      *target++ = xa[XA_TEXT];
+      *target++ = xa[XA_COMPOUND_TEXT];
 #if X_HAVE_UTF8_STRING
-        else if (target == R->xa[XA_UTF8_STRING])
-          style = XUTF8StringStyle;
+      *target++ = xa[XA_UTF8_STRING];
 #endif
-        else
-          {
-            target = R->xa[XA_COMPOUND_TEXT];
-            style = XCompoundTextStyle;
-          }
 
-        if (R->selection.text) {
-            cl = (char *)R->selection.text;
-            selectlen = R->selection.len;
-        } else {
-            cl = "";
-            selectlen = 0;
+      XChangeProperty (display->display, rq.requestor, rq.property, XA_ATOM,
+                       32, PropModeReplace,
+                       (unsigned char *)target_list, target - target_list);
+      ev.property = rq.property;
+    }
+#if TODO // TODO
+  else if (rq.target == xa[XA_MULTIPLE])
+    {
+      /* TODO: Handle MULTIPLE */
+    }
+#endif
+  else if (rq.target == xa[XA_TIMESTAMP] && selection.text)
+    {
+      XChangeProperty (display->display, rq.requestor, rq.property, rq.target,
+                       32, PropModeReplace, (unsigned char *)&selection_time, 1);
+      ev.property = rq.property;
+    }
+  else if (rq.target == XA_STRING
+           || rq.target == xa[XA_TEXT]
+           || rq.target == xa[XA_COMPOUND_TEXT]
+           || rq.target == xa[XA_UTF8_STRING]
+          )
+    {
+      XTextProperty ct;
+      Atom target = rq.target;
+      short freect = 0;
+      int selectlen;
+      wchar_t *cl;
+      enum {
+        enc_string        = XStringStyle,
+        enc_text          = XStdICCTextStyle,
+        enc_compound_text = XCompoundTextStyle,
+#ifdef X_HAVE_UTF8_STRING
+        enc_utf8          = XUTF8StringStyle,
+#else
+        enc_utf8          = -1,
+#endif
+      } style;
+
+      if (target == XA_STRING)
+        // we actually don't do XA_STRING, but who cares, as i18n clients
+        // will ask for another format anyways.
+        style = enc_string;
+      else if (target == xa[XA_TEXT])
+        style = enc_text;
+      else if (target == xa[XA_COMPOUND_TEXT])
+        style = enc_compound_text;
+#if ENABLE_FRILLS
+      else if (target == xa[XA_UTF8_STRING])
+        style = enc_utf8;
+#endif
+      else
+        {
+          target = xa[XA_COMPOUND_TEXT];
+          style = enc_compound_text;
         }
 
-        if (XmbTextListToTextProperty(R->Xdisplay, &cl, 1, style, &ct) >= 0)
-            freect = 1;
-        else
-          {
-            /* if we failed to convert then send it raw */
-            ct.value = (unsigned char *)cl;
-            ct.nitems = selectlen;
-          }
+      if (selection.text)
+        {
+          cl = selection.text;
+          selectlen = selection.len;
+        }
+      else
+        {
+          cl = L"";
+          selectlen = 0;
+        }
+
+#if ENABLE_FRILLS
+      // xlib is horribly broken with respect to UTF8_STRING, and nobody cares to fix it
+      // so recode it manually
+      if (style == enc_utf8)
+        {
+          freect = 1;
+          ct.encoding = target;
+          ct.format = 8;
+          ct.value = (unsigned char *)rxvt_wcstoutf8 (cl, selectlen);
+          ct.nitems = strlen ((char *)ct.value);
+        }
+      else
+#endif
+      if (XwcTextListToTextProperty (display->display, &cl, 1, (XICCEncodingStyle) style, &ct) >= 0)
+        freect = 1;
+      else
+        {
+          /* if we failed to convert then send it raw */
+          ct.value = (unsigned char *)cl;
+          ct.nitems = selectlen;
+          ct.encoding = target;
+        }
 
-        XChangeProperty(R->Xdisplay, rq->requestor, rq->property,
-                        target, 8, PropModeReplace,
-                        ct.value, (int)ct.nitems);
-        ev.property = rq->property;
+      XChangeProperty (display->display, rq.requestor, rq.property,
+                       ct.encoding, 8, PropModeReplace,
+                       ct.value, (int)ct.nitems);
+      ev.property = rq.property;
 
-        if (freect)
-            XFree (ct.value);
+      if (freect)
+        XFree (ct.value);
     }
-    XSendEvent(R->Xdisplay, rq->requestor, False, 0L, (XEvent *)&ev);
+
+  XSendEvent (display->display, rq.requestor, False, 0L, (XEvent *)&ev);
 }
 \f
 /* ------------------------------------------------------------------------- *
@@ -3371,68 +3678,146 @@ rxvt_selection_send(pR_ const XSelectionRequestEvent *rq)
 void
 rxvt_term::pixel_position (int *x, int *y)
 {
-  *x = Pixel2Col(*x);
-  /* MAX_IT(*x, 0); MIN_IT(*x, (int)R->TermWin.ncol - 1); */
-  *y = Pixel2Row(*y);
-  /* MAX_IT(*y, 0); MIN_IT(*y, (int)R->TermWin.nrow - 1); */
+  *x = Pixel2Col (*x);
+  /* MAX_IT (*x, 0); MIN_IT (*x, (int)TermWin.ncol - 1); */
+  *y = Pixel2Row (*y);
+  /* MAX_IT (*y, 0); MIN_IT (*y, (int)TermWin.nrow - 1); */
 }
 
 /* ------------------------------------------------------------------------- */
 #ifdef USE_XIM
 void
-rxvt_term::set_position (XPoint *pos)
+rxvt_term::im_set_position (XPoint &pos)
 {
   XWindowAttributes xwa;
 
-  XGetWindowAttributes (Xdisplay, TermWin.vt, &xwa);
-  pos->x = Col2Pixel (screen.cur.col) + xwa.x;
-  pos->y = Height2Pixel ((screen.cur.row + 1)) + xwa.y - TermWin.lineSpace;
-}
+  XGetWindowAttributes (display->display, TermWin.vt, &xwa);
 
+  pos.x = xwa.x + Col2Pixel    (screen.cur.col);
+  pos.y = xwa.y + Height2Pixel (screen.cur.row) + TermWin.fbase;
+}
 #endif
-/* ------------------------------------------------------------------------- */
-\f
-/* ------------------------------------------------------------------------- *
- *                              DEBUG ROUTINES                               *
- * ------------------------------------------------------------------------- */
-#if 0
-/* INTPROTO */
+
+#if ENABLE_OVERLAY
+void
+rxvt_term::scr_overlay_new (int x, int y, int w, int h)
+{
+  if (TermWin.nrow < 3 || TermWin.ncol < 3)
+    return;
+
+  want_refresh = 1;
+
+  scr_overlay_off ();
+
+  if (x < 0) x = TermWin.ncol - w;
+  if (y < 0) y = TermWin.nrow - h;
+
+  // make space for border
+  w += 2; MIN_IT (w, TermWin.ncol);
+  h += 2; MIN_IT (h, TermWin.nrow);
+
+  x -= 1; MAX_IT (x, 0);
+  y -= 1; MAX_IT (y, 0);
+
+  MIN_IT (x, TermWin.ncol - w);
+  MIN_IT (y, TermWin.nrow - h);
+
+  ov_x = x; ov_y = y;
+  ov_w = w; ov_h = h;
+
+  ov_text = new text_t *[h];
+  ov_rend = new rend_t *[h];
+
+  for (y = 0; y < h; y++)
+    {
+      text_t *tp = ov_text[y] = new text_t[w];
+      rend_t *rp = ov_rend[y] = new rend_t[w];
+
+      text_t t0, t1, t2;
+      rend_t r = OVERLAY_RSTYLE;
+
+      if (y == 0)
+        t0 = 0x2554, t1 = 0x2550, t2 = 0x2557;
+      else if (y < h - 1)
+        t0 = 0x2551, t1 = 0x0020, t2 = 0x2551;
+      else
+        t0 = 0x255a, t1 = 0x2550, t2 = 0x255d;
+
+      *tp++ = t0;
+      *rp++ = r;
+
+      for (x = w - 2; x > 0; --x)
+        {
+          *tp++ = t1;
+          *rp++ = r;
+        }
+
+      *tp = t2;
+      *rp = r;
+    }
+}
+
 void
-rxvt_debug_colors(void)
+rxvt_term::scr_overlay_off ()
 {
-    int             color;
-    const char     *name[] = {
-        "fg", "bg",
-        "black", "red", "green", "yellow", "blue", "magenta", "cyan", "white"
-    };
+  if (!ov_text)
+    return;
 
-    fprintf(stderr, "Color ( ");
-    if (R->rstyle & RS_RVid)
-        fprintf(stderr, "rvid ");
-    if (R->rstyle & RS_Bold)
-        fprintf(stderr, "bold ");
-    if (R->rstyle & RS_Blink)
-        fprintf(stderr, "blink ");
-    if (R->rstyle & RS_Uline)
-        fprintf(stderr, "uline ");
-    fprintf(stderr, "): ");
+  want_refresh = 1;
 
-    color = GET_FGCOLOR(R->rstyle);
-#ifndef NO_BRIGHTCOLOR
-    if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
-        color -= (minBrightCOLOR - minCOLOR);
-        fprintf(stderr, "bright ");
+  for (int y = 0; y < ov_h; y++)
+    {
+      delete [] ov_text[y];
+      delete [] ov_rend[y];
     }
-#endif
-    fprintf(stderr, "%s on ", name[color]);
 
-    color = GET_BGCOLOR(R->rstyle);
-#ifndef NO_BRIGHTCOLOR
-    if (color >= minBrightCOLOR && color <= maxBrightCOLOR) {
-        color -= (minBrightCOLOR - minCOLOR);
-        fprintf(stderr, "bright ");
+  delete [] ov_text; ov_text = 0;
+  delete [] ov_rend; ov_rend = 0;
+}
+
+void
+rxvt_term::scr_overlay_set (int x, int y, text_t text, rend_t rend)
+{
+  if (!ov_text || x >= ov_w - 2 || y >= ov_h - 2)
+    return;
+
+  x++, y++;
+
+  ov_text[y][x] = text;
+  ov_rend[y][x] = rend;
+}
+
+void
+rxvt_term::scr_overlay_set (int x, int y, const char *s)
+{
+  while (*s)
+    scr_overlay_set (x++, y, *s++);
+}
+
+void
+rxvt_term::scr_swap_overlay ()
+{
+  if (!ov_text)
+    return;
+
+  int row_offset = ov_y + TermWin.saveLines - TermWin.view_start;
+
+  // swap screen mem with overlay
+  for (int y = ov_h; y--; )
+    {
+      text_t *t1 = ov_text[y];
+      rend_t *r1 = ov_rend[y];
+
+      text_t *t2 = screen.text[y + row_offset] + ov_x;
+      rend_t *r2 = screen.rend[y + row_offset] + ov_x;
+
+      for (int x = ov_w; x--; )
+        {
+          text_t t = *t1; *t1++ = *t2; *t2++ = t;
+          rend_t r = *r1; *r1++ = *r2; *r2++ = SET_FONT (r, FONTSET (r)->find_font (t));
+        }
     }
-#endif
-    fprintf(stderr, "%s\n", name[color]);
 }
+
 #endif
+/* ------------------------------------------------------------------------- */