diff --git a/src/buffer.c b/src/buffer.c
index 62b0bc8..5b9469b 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -5056,6 +5056,16 @@ init_buffer_once (void)
   bset_last_selected_window (&buffer_local_flags, make_number (0));
 
   idx = 1;
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  XSETFASTINT (BVAR (&buffer_local_flags, mc_list), idx); ++idx;
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   XSETFASTINT (BVAR (&buffer_local_flags, mode_line_format), idx); ++idx;
   XSETFASTINT (BVAR (&buffer_local_flags, abbrev_mode), idx); ++idx;
   XSETFASTINT (BVAR (&buffer_local_flags, overwrite_mode), idx); ++idx;
@@ -5133,6 +5143,16 @@ init_buffer_once (void)
   /* Must do these before making the first buffer! */
 
   /* real setup is done in bindings.el */
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  bset_mc_list (&buffer_defaults, Qnil);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   bset_mode_line_format (&buffer_defaults, build_pure_c_string ("%-"));
   bset_header_line_format (&buffer_defaults, Qnil);
   bset_abbrev_mode (&buffer_defaults, Qnil);
@@ -5379,6 +5399,15 @@ syms_of_buffer (void)
   staticpro (&QSFundamental);
   staticpro (&Vbuffer_alist);
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  DEFSYM (Qmc_list, "mc-list");
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   DEFSYM (Qchoice, "choice");
   DEFSYM (Qleft, "left");
   DEFSYM (Qright, "right");
@@ -5554,6 +5583,17 @@ This is the same as (default-value \\='scroll-up-aggressively).  */);
 This value applies in buffers that don't have their own local values.
 This is the same as (default-value \\='scroll-down-aggressively).  */);
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  DEFVAR_PER_BUFFER ("mc-list", &BVAR (current_buffer, mc_list), Qnil,
+    doc: /* A bufer-local variable to store the value of the multiple cursors to be displayed
+during the next redisplay.  */);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   DEFVAR_PER_BUFFER ("header-line-format",
 		     &BVAR (current_buffer, header_line_format),
 		     Qnil,
diff --git a/src/buffer.h b/src/buffer.h
index 87b7cee..2bfbb16 100644
--- a/src/buffer.h
+++ b/src/buffer.h
@@ -643,6 +643,16 @@ struct buffer
      cache are enabled.  See search.c, indent.c and bidi.c for details.  */
   Lisp_Object cache_long_scans_;
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  /* The name of list used by multiple cursors for next redisplay.  */
+  Lisp_Object mc_list_;
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   /* If the width run cache is enabled, this table contains the
      character widths width_run_cache (see above) assumes.  When we
      do a thorough redisplay, we compare this against the buffer's
@@ -884,6 +894,20 @@ struct buffer
 /* Most code should use these functions to set Lisp fields in struct
    buffer.  (Some setters that are private to a single .c file are
    defined as static in those files.)  */
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+INLINE void
+bset_mc_list (struct buffer *b, Lisp_Object val)
+{
+  b->mc_list_ = val;
+}
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 INLINE void
 bset_bidi_paragraph_direction (struct buffer *b, Lisp_Object val)
 {
diff --git a/src/dispextern.h b/src/dispextern.h
index 7035872..07ee120 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -2891,7 +2891,15 @@ struct redisplay_interface
 			      struct glyph_row *glyph_row,
 			      int x, int y,
 			      enum text_cursor_kinds cursor_type,
-			      int cursor_width, bool on_p, bool active_p);
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+         int cursor_width, bool on_p, bool active_p, double red, double green, double blue);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
 
   /* Draw vertical border for window W from (X,Y_0) to (X,Y_1).  */
   void (*draw_vertical_window_border) (struct window *w,
@@ -3269,6 +3277,15 @@ extern void get_font_ascent_descent (struct font *, int *, int *);
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+extern void mc_calc (struct window *, bool);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 #ifdef GLYPH_DEBUG
 extern void dump_glyph_string (struct glyph_string *) EXTERNALLY_VISIBLE;
 #endif
diff --git a/src/keyboard.c b/src/keyboard.c
index 1a5dbd0..ce187e4 100644
--- a/src/keyboard.c
+++ b/src/keyboard.c
@@ -1243,6 +1243,21 @@ static int read_key_sequence (Lisp_Object *, int, Lisp_Object,
                               bool, bool, bool, bool);
 static void adjust_point_for_property (ptrdiff_t, bool);
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+static void
+set_mc_draw_erase (void)
+{
+  Lisp_Object window = selected_window;
+  struct window *w = decode_live_window (window);
+  w->mc.draw_erase = true;
+}
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 Lisp_Object
 command_loop_1 (void)
 {
@@ -1439,6 +1454,15 @@ command_loop_1 (void)
       Vreal_this_command = cmd;
       safe_run_hooks (Qpre_command_hook);
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+      set_mc_draw_erase ();
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       already_adjusted = 0;
 
       if (NILP (Vthis_command))
diff --git a/src/nsterm.m b/src/nsterm.m
index 4048ac4..c58372d 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -1107,6 +1107,40 @@ static NSRect constrain_frame_rect(NSRect frameRect, bool isFullscreen)
     {
       block_input ();
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+      if (w->mc.draw_erase
+          && (!NILP (BVAR (XBUFFER (w->contents), mc_list))
+              || (w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          if ((w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+            mc_calc (w, 1);
+          /* Draw fake cursors  */
+          if (!NILP (BVAR (XBUFFER (w->contents), mc_list)))
+            mc_calc (w, 0);
+        }
+
+      /* First attempt at dealing with a `redisplay_preserve_echo_area' situation.  */
+      if (!w->mc.draw_erase
+          && !NILP (BVAR (XBUFFER (w->contents), mc_list))
+          && w->mc_cache
+          && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          mc_calc (w, 1);
+          /* Draw fake cursors  */
+          mc_calc (w, 0);
+        }
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       if (cursor_on_p)
 	display_and_set_cursor (w, 1,
 				w->output_cursor.hpos, w->output_cursor.vpos,
@@ -2811,7 +2845,16 @@ static void hide_bell ()
 static void
 ns_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
 		       int x, int y, enum text_cursor_kinds cursor_type,
-		       int cursor_width, bool on_p, bool active_p)
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+       int cursor_width, bool on_p, bool active_p, double red, double green, double blue)
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 /* --------------------------------------------------------------------------
      External call (RIF): draw cursor.
      Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
@@ -2896,7 +2939,20 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
       hollow_color = FRAME_CURSOR_COLOR (f);
     }
   else
-    [FRAME_CURSOR_COLOR (f) set];
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        [[NSColor colorWithCalibratedRed: red green: green blue: blue alpha: 1.0] set];
+        else
+          [FRAME_CURSOR_COLOR (f) set];
+    }
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
 
 #ifdef NS_IMPL_COCOA
   /* TODO: This makes drawing of cursor plus that of phys_cursor_glyph
@@ -3816,6 +3872,16 @@ overwriting cursor (usually when cursor on a tab) */
          (s->for_overlaps ? NS_DUMPGLYPH_FOREGROUND :
           NS_DUMPGLYPH_NORMAL));
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+      /* TODO:  Consider adding support for multiple cursor foreground
+      customization of a FILLED_BOX_CURSOR.  */
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       if (s->hl == DRAW_CURSOR && s->w->phys_cursor_type == FILLED_BOX_CURSOR)
         {
           unsigned long tmp = NS_FACE_BACKGROUND (s->face);
diff --git a/src/w32term.c b/src/w32term.c
index 8955ce2..8243f09 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -682,6 +682,40 @@ x_update_window_end (struct window *w, bool cursor_on_p,
     {
       block_input ();
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+      if (w->mc.draw_erase
+          && (!NILP (BVAR (XBUFFER (w->contents), mc_list))
+              || (w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          if ((w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+            mc_calc (w, 1);
+          /* Draw fake cursors  */
+          if (!NILP (BVAR (XBUFFER (w->contents), mc_list)))
+            mc_calc (w, 0);
+        }
+
+      /* First attempt at dealing with a `redisplay_preserve_echo_area' situation.  */
+      if (!w->mc.draw_erase
+          && !NILP (BVAR (XBUFFER (w->contents), mc_list))
+          && w->mc_cache
+          && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          mc_calc (w, 1);
+          /* Draw fake cursors  */
+          mc_calc (w, 0);
+        }
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       if (cursor_on_p)
 	display_and_set_cursor (w, true,
 				w->output_cursor.hpos, w->output_cursor.vpos,
@@ -935,10 +969,22 @@ static void w32_draw_box_rect (struct glyph_string *, int, int, int, int,
 static void
 x_set_cursor_gc (struct glyph_string *s)
 {
-  if (s->font == FRAME_FONT (s->f)
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  Lisp_Object window = (selected_window);
+  struct window *w = decode_live_window (window);
+  if ((s->font == FRAME_FONT (s->f)
       && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
       && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
       && !s->cmp)
+      || w->mc.set_cursor_gc)
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
     s->gc = s->f->output_data.w32->cursor_gc;
   else
     {
@@ -5640,7 +5686,16 @@ w32_clear_frame_area (struct frame *f, int x, int y, int width, int height)
 static void
 w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
 			int x, int y, enum text_cursor_kinds cursor_type,
-			int cursor_width, bool on_p, bool active_p)
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+   int cursor_width, bool on_p, bool active_p, double red, double green, double blue)
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 {
   if (on_p)
     {
@@ -5705,31 +5760,115 @@ w32_draw_window_cursor (struct window *w, struct glyph_row *glyph_row,
 	  return;
 	}
 
-      switch (cursor_type)
-	{
-	case HOLLOW_BOX_CURSOR:
-	  x_draw_hollow_cursor (w, glyph_row);
-	  break;
-
-	case FILLED_BOX_CURSOR:
-	  draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
-	  break;
 
-	case BAR_CURSOR:
-	  x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
-	  break;
-
-	case HBAR_CURSOR:
-	  x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
-	  break;
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+  switch (cursor_type)
+  {
+    case HOLLOW_BOX_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.w32->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          COLORREF orig_val = f->output_data.w32->cursor_pixel;
+          int int_red = red * 255;
+          int int_green = green * 255;
+          int int_blue = blue * 255;
+          f->output_data.w32->cursor_pixel = PALETTERGB (int_red, int_green, int_blue);
+          x_draw_hollow_cursor (w, glyph_row);
+          f->output_data.w32->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_hollow_cursor (w, glyph_row);
+      break;
+    }
+    case FILLED_BOX_CURSOR:
+    {
+      /* TODO:  kdb to consider adding support for multiple cursor foreground
+      customization of a FILLED_BOX_CURSOR.  */
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.w32->cursor_gc' by borrowing the
+        functionality of `x_make_gc' in w32fns.c.  */
+        {
+          block_input ();
+          Lisp_Object window = (selected_window);
+          struct window *w = decode_live_window (window);
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          int int_red = red * 255;
+          int int_green = green * 255;
+          int int_blue = blue * 255;
+          XGCValues gc_values;
+          unsigned long mask = GCFont | GCForeground | GCBackground;
+          COLORREF orig_val_a = FRAME_BACKGROUND_PIXEL (f);
+          COLORREF orig_val_b = f->output_data.w32->cursor_pixel;
+          gc_values.font = FRAME_FONT (f);
+          gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
+          gc_values.background = PALETTERGB (int_red, int_green, int_blue);
+          f->output_data.w32->cursor_gc
+            = XCreateGC (NULL, FRAME_W32_WINDOW (f), mask, &gc_values);
+          /* When `w->mc.set_cursor_gc = true', force `x_set_cursor_gc' to
+          use `s->f->output_data.w32->cursor_gc'.  */
+          w->mc.set_cursor_gc = true;
+          draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+          w->mc.set_cursor_gc = false;
+          gc_values.font = FRAME_FONT (f);
+          gc_values.foreground = orig_val_a;
+          gc_values.background = orig_val_b;
+          f->output_data.w32->cursor_gc
+            = XCreateGC (NULL, FRAME_W32_WINDOW (f), mask, &gc_values);
+          unblock_input ();
+        }
+        else
+          draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+      break;
+    }
+    case BAR_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.w32->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          COLORREF orig_val = f->output_data.w32->cursor_pixel;
+          int int_red = red * 255;
+          int int_green = green * 255;
+          int int_blue = blue * 255;
+          f->output_data.w32->cursor_pixel = PALETTERGB (int_red, int_green, int_blue);
+          x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+          f->output_data.w32->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+      break;
+    }
+    case HBAR_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.w32->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          COLORREF orig_val = f->output_data.w32->cursor_pixel;
+          int int_red = red * 255;
+          int int_green = green * 255;
+          int int_blue = blue * 255;
+          f->output_data.w32->cursor_pixel = PALETTERGB (int_red, int_green, int_blue);
+          x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+          f->output_data.w32->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+      break;
+    }
+    case NO_CURSOR:
+      w->phys_cursor_width = 0;
+      break;
+    default:
+      emacs_abort ();
+  }
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
 
-	case NO_CURSOR:
-	  w->phys_cursor_width = 0;
-	  break;
 
-	default:
-	  emacs_abort ();
-	}
     }
 }
 
diff --git a/src/window.h b/src/window.h
index 84180c9..2527444 100644
--- a/src/window.h
+++ b/src/window.h
@@ -76,6 +76,33 @@ one and the same, so its prev and next members are nil.
 
 A dead window has its contents field set to nil.  */
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+struct multiple_cursors
+{
+  /* Values for previous and current `window-start' and `window-end'.  */
+  EMACS_INT
+    y_diff, vpos_diff,
+    opoint, opoint_x, opoint_y, opoint_hpos, opoint_vpos,
+    start, start_x, start_y, start_hpos, start_vpos,
+    end, end_x, end_y, end_hpos, end_vpos,
+    prev_opoint, prev_opoint_x, prev_opoint_y, prev_opoint_hpos, prev_opoint_vpos,
+    prev_start, prev_start_x, prev_start_y, prev_start_hpos, prev_start_vpos,
+    prev_end, prev_end_x, prev_end_y, prev_end_hpos, prev_end_vpos;
+
+  /* True means to force `x_set_cursor_gc' to use `s->f->output_data.w32->cursor_gc'
+  in w32term.c or `s->f->output_data.x->cursor_gc' in xterm.c.  */
+  bool_bf set_cursor_gc : 1;
+
+  /* True means `mc_calc' has not run yet.  */
+  bool_bf draw_erase : 1;
+};
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 struct cursor_pos
 {
   /* Pixel position.  These are always window relative.  */
@@ -178,6 +205,17 @@ struct window
     /* An alist with parameters.  */
     Lisp_Object window_parameters;
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+    /* The cache for multiple cursors.  For an example of the structure of
+    the list, see the comments at the beginning of `mc_calc' in xdisp.c.  */
+    Lisp_Object mc_cache;
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
     /* No Lisp data may follow below this point without changing
        mark_object in alloc.c.  The member current_matrix must be the
        first non-Lisp member.  */
@@ -280,6 +318,16 @@ struct window
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+    /* The prefix for window pointers relating to multiple cursors.  */
+    struct multiple_cursors mc;
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
     /* Cursor type of last cursor drawn on the window.  */
     enum text_cursor_kinds phys_cursor_type;
 
@@ -399,6 +447,20 @@ struct window
 
 /* Most code should use these functions to set Lisp fields in struct
    window.  */
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+INLINE void
+wset_mc_cache (struct window *w, Lisp_Object val)
+{
+  w->mc_cache = val;
+}
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 INLINE void
 wset_frame (struct window *w, Lisp_Object val)
 {
diff --git a/src/xdisp.c b/src/xdisp.c
index bdc8af8..f873ecc 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -574,6 +574,640 @@ bool help_echo_showing_p;
 /* Functions to mark elements as needing redisplay.  */
 enum { REDISPLAY_SOME = 2};	/* Arbitrary choice.  */
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+static void debug_method_add (struct window *, char const *, ...) ATTRIBUTE_FORMAT_PRINTF (2, 3);
+
+static int draw_glyphs (struct window *, int, struct glyph_row *,
+  enum glyph_row_area, ptrdiff_t, ptrdiff_t, enum draw_glyphs_face, int);
+
+/* The let-bound variable `wrapped-peovl-underline' in `lawlist-+.el' looks like this:
+     (wrapped-peovl-underline
+       (propertize
+         (concat
+           " "
+           (progn
+             (dotimes (i (1- (- window-width col-eovl)))
+               (setq result (concat (char-to-string ?\u00A0) result))) result)) ;; nobreak-space
+         'cursor t))
+The overlay is placed with the following code:
+      (let ((ov (make-overlay peovl peovl+1)))
+        (overlay-put ov 'window win)
+        (overlay-put ov 'type 'col-eovl)
+        (overlay-put ov 'display hr-cursor-eol-string))
+The visual effect is that there is a horizontal line from the end of the word-wrapped line to
+the right edge of the window.  When point is at this location, the value returned by
+`current_column ();' is the beginning of the visual line below.  `lawlist-mwheel-scroll' has
+been modified also for this special situation to restore point when scrolling.  */
+Lisp_Object
+mc_x_y_hpos_vpos (struct window *w, EMACS_INT posint, EMACS_INT start, EMACS_INT end)
+{
+  struct it it;
+  void *itdata = bidi_shelve_cache ();
+  struct text_pos pt;
+  int x, y, hpos, vpos, pbovl_col, peovl_col, col_eovl, frame_char_width;
+  ptrdiff_t opoint= PT;
+  ptrdiff_t obytepos = PT_BYTE;
+  struct frame *f = XFRAME (w->frame);
+  frame_char_width = FRAME_COLUMN_WIDTH (f);
+  Lisp_Object overlays;
+  Lisp_Object ov = Qnil;
+  Lisp_Object ov_list = Qnil;
+  Lisp_Object ov_type = intern_c_string ("type");
+  Lisp_Object ov_col_eovl = intern_c_string ("col-eovl");
+  Lisp_Object ov_right_fringe = intern_c_string ("right-fringe");
+  Lisp_Object ov_query_type = Qnil;
+  Lisp_Object ov_query_after_string = Qnil;
+  Lisp_Object ov_query_display = Qnil;
+  bool ov_found_type_coleovl = false;
+  bool ov_found_afterstring = false;
+  bool ov_found_type_rightfringe = false;
+  if (posint >= start
+      && posint <= end)
+    {
+      overlays = Foverlays_in (make_number (posint), (make_number (posint + 1)));
+      if (!NILP (overlays))
+        {
+          for (ov_list = overlays;
+               CONSP (ov_list);
+               ov_list = XCDR (ov_list))
+            {
+              ov = XCAR (ov_list);
+              ov_query_type = Foverlay_get (ov, ov_type);
+              ov_query_display = Foverlay_get (ov, Qdisplay);
+              ov_query_after_string = Foverlay_get (ov, Qafter_string);
+              if (EQ (ov_query_type, ov_col_eovl))
+                ov_found_type_coleovl = true;
+              if (EQ (ov_query_type, ov_right_fringe))
+                ov_found_type_rightfringe = true;
+              if (!NILP (ov_query_after_string))
+                ov_found_afterstring = true;
+            }
+        }
+      SET_TEXT_POS_FROM_MARKER (pt, w->start);
+      start_display (&it, w, pt);
+      move_it_to (&it, posint, -1, -1, -1, MOVE_TO_POS);
+      y = it.current_y;
+      vpos = it.vpos;
+      if (ov_found_type_coleovl)
+        {
+          TEMP_SET_PT_BOTH (CHARPOS (it.current.pos), BYTEPOS (it.current.pos));
+          peovl_col = current_column () - 1;
+          move_it_by_lines (&it, -1);
+          TEMP_SET_PT_BOTH (CHARPOS (it.current.pos), BYTEPOS (it.current.pos));
+          pbovl_col = current_column ();
+          col_eovl = peovl_col - pbovl_col;
+          x = col_eovl * frame_char_width;
+          hpos = col_eovl;
+          TEMP_SET_PT_BOTH (opoint, obytepos);
+        }
+        /* Special handling for `after-string' and eob situations.  */
+        else if (ov_found_afterstring
+                 || FETCH_BYTE (IT_BYTEPOS (it)) == '\n'
+                 || posint == ZV)
+          {
+            TEMP_SET_PT_BOTH (CHARPOS (it.current.pos), BYTEPOS (it.current.pos));
+            peovl_col = current_column ();
+            /* DVPOS == 0 means move to the start of the screen line.  */
+            move_it_by_lines (&it, 0);
+            TEMP_SET_PT_BOTH (CHARPOS (it.current.pos), BYTEPOS (it.current.pos));
+            pbovl_col = current_column ();
+            col_eovl = peovl_col - pbovl_col;
+            x = col_eovl * frame_char_width;
+            hpos = col_eovl;
+            TEMP_SET_PT_BOTH (opoint, obytepos);
+          }
+          else
+            {
+              x = it.current_x;
+              hpos = it.hpos;
+            }
+      bidi_unshelve_cache (itdata, false);
+    }
+    else
+      {
+        x = -1;
+        y = -1;
+        hpos = -1;
+        vpos = -1;
+      }
+  return
+    listn (CONSTYPE_HEAP, 4,
+      listn (CONSTYPE_HEAP, 4, make_number (x), make_number (y), make_number (hpos), make_number (vpos)),
+      Fcons (build_string ("type"), ov_query_type),
+      Fcons (build_string ("display"), ov_query_display),
+      Fcons (build_string ("after-string"), ov_query_after_string));
+}
+
+/* Return the LSL color vector.  FRAME is derived from WINDOW.
+Note that the Nextstep version of xw_color_values ignores FRAME.  */
+Lisp_Object
+mc_color_vector_calculate (struct window *w, Lisp_Object color)
+{
+  Lisp_Object target_frame = w->frame;
+  Lisp_Object color_values;
+  double valmax = XINT (XCAR (Fxw_color_values (build_string ("#ffffff"), target_frame)));
+  Lisp_Object vlist;
+  ptrdiff_t x;
+  int i = 0;
+  Lisp_Object temp = Qnil;
+  Lisp_Object vector = (Fmake_vector (make_number (3), Qnil));
+  if (Fmemq ((Fframep (target_frame)), listn (CONSTYPE_HEAP, 3, Qx, Qw32, Qns)))
+    color_values = (Fxw_color_values (color, target_frame));
+    else
+      color_values = Qnil;
+  for (vlist = color_values;
+       CONSP (vlist);
+       vlist = XCDR (vlist))
+    {
+      x = XINT (XCAR (vlist));
+      temp = make_float (x / valmax);
+      ASET (vector, i, temp);
+      i = i + 1;
+    }
+  return vector;
+}
+
+DEFUN ("mc-color-vector-calculate", Fmc_color_vector_calculate, Smc_color_vector_calculate, 1, 2, 0,
+       doc: /* Return the LSL color vector.  FRAME is derived from WINDOW.
+Note that the Nextstep version of xw_color_values ignores FRAME.  */)
+     (Lisp_Object color, Lisp_Object window)
+{
+  if (NILP (window))
+    window = selected_window;
+  struct window *w = decode_live_window (window);
+  return mc_color_vector_calculate (w, color);
+}
+
+void
+mc_erase (struct window *w, EMACS_INT x, EMACS_INT y, EMACS_INT hpos, EMACS_INT vpos,
+          enum text_cursor_kinds cursor_type, int cursor_width)
+{
+  int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+  if (header_line_height > 0)
+    vpos = vpos + 1;
+  struct frame *f = XFRAME (w->frame);
+  struct glyph *cursor_glyph;
+  struct glyph_row *cursor_row = MATRIX_ROW (w->current_matrix, vpos);
+  /* Maybe clear the display under the cursor.  */
+  if (w->phys_cursor_type == HOLLOW_BOX_CURSOR)
+    {
+      int hollow_x, hollow_y, width;
+      if (!(vpos >= 0
+          && vpos < w->current_matrix->nrows))
+        cursor_glyph = NULL;
+      if (!cursor_row->enabled_p)
+        cursor_glyph = NULL;
+      if (w->hscroll)
+        {
+          /* When the window is hscrolled, cursor hpos can legitimately be
+           out of bounds, but we draw the cursor at the corresponding
+           window margin in that case.  */
+          if (!cursor_row->reversed_p && hpos < 0)
+            hpos = 0;
+          if (cursor_row->reversed_p && hpos >= cursor_row->used[TEXT_AREA])
+            hpos = cursor_row->used[TEXT_AREA] - 1;
+        }
+      if (0 <= hpos && hpos < cursor_row->used[TEXT_AREA])
+        cursor_glyph = cursor_row->glyphs[TEXT_AREA] + hpos;
+      else
+        cursor_glyph = NULL;
+      if (cursor_glyph == NULL)
+        goto done;
+      width = cursor_glyph->pixel_width;
+      hollow_x = x;
+      if (x < 0)
+        {
+          width += hollow_x;
+          hollow_x = 0;
+        }
+      width = min (width, window_box_width (w, TEXT_AREA) - hollow_x);
+      hollow_y = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, cursor_row->y));
+      hollow_x = WINDOW_TEXT_TO_FRAME_PIXEL_X (w, hollow_x);
+      if (width > 0)
+        FRAME_RIF (f)->clear_frame_area (f, hollow_x, hollow_y, width, cursor_row->visible_height);
+    }
+  if ((cursor_row->reversed_p
+       ? (hpos >= 0)
+       : (hpos < cursor_row->used[TEXT_AREA])))
+    {
+      int x1;
+      if (!cursor_row->reversed_p && hpos < 0)
+        hpos = 0;
+      if (cursor_row->reversed_p && hpos >= cursor_row->used[TEXT_AREA])
+        hpos = cursor_row->used[TEXT_AREA] - 1;
+      x1 = draw_glyphs (w, x, cursor_row, TEXT_AREA, hpos, hpos + 1, DRAW_NORMAL_TEXT, 0);
+      if (cursor_row->overlapped_p)
+        {
+          w->phys_cursor_width = x1 - x;
+          if (cursor_row > w->current_matrix->rows
+              && MATRIX_ROW_OVERLAPS_SUCC_P (cursor_row - 1))
+            x_fix_overlapping_area (w, cursor_row - 1, TEXT_AREA, OVERLAPS_ERASED_CURSOR);
+          if (MATRIX_ROW_BOTTOM_Y (cursor_row) < window_text_bottom_y (w)
+              && MATRIX_ROW_OVERLAPS_PRED_P (cursor_row + 1))
+            x_fix_overlapping_area (w, cursor_row + 1, TEXT_AREA, OVERLAPS_ERASED_CURSOR);
+        }
+    }
+  done:
+    Qnil;
+}
+
+void
+mc_draw (struct window *w, EMACS_INT x, EMACS_INT y, EMACS_INT hpos, EMACS_INT vpos,
+         enum text_cursor_kinds cursor_type, int cursor_width, double red, double green, double blue)
+{
+  int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+  if (header_line_height > 0)
+    vpos = vpos + 1;
+  struct glyph *glyph;
+  /* Record the current values for w->phys_cursor.x/y/hpos/vpos.  */
+  int prior_hpos = w->phys_cursor.hpos;
+  int prior_vpos = w->phys_cursor.vpos;
+  int prior_x = w->phys_cursor.x;
+  int prior_y = w->phys_cursor.y;
+  struct frame *f = XFRAME (w->frame);
+  struct glyph_row *glyph_row = MATRIX_ROW (w->current_matrix, vpos);
+  glyph = NULL;
+  if (!glyph_row->exact_window_width_line_p
+      || (0 <= hpos && hpos < glyph_row->used[TEXT_AREA]))
+    glyph = glyph_row->glyphs[TEXT_AREA] + hpos;
+  eassert (input_blocked_p ());
+  w->phys_cursor_ascent = glyph_row->ascent;
+  w->phys_cursor_height = glyph_row->height;
+  /* Hijack w->phys_cursor.x/y/hpos/vpos by setting new values.  */
+  w->phys_cursor.hpos = hpos;
+  w->phys_cursor.vpos = vpos;
+  w->phys_cursor.x = x;
+  w->phys_cursor.y = glyph_row->y;
+  FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y, cursor_type, cursor_width, 1, 0, red, green, blue);
+  /* Restore the previous values for w->phys_cursor.x/y/hpos/vpos.  */
+  w->phys_cursor.hpos = prior_hpos;
+  w->phys_cursor.vpos = prior_vpos;
+  w->phys_cursor.x = prior_x;
+  w->phys_cursor.y = prior_y;
+}
+
+int
+mc_lisp_to_cursor_type (Lisp_Object arg)
+{
+  char *str;
+  if (XTYPE (arg) == Lisp_String)
+    str = SSDATA (arg);
+  else if (XTYPE (arg) == Lisp_Symbol)
+    str = SSDATA (SYMBOL_NAME (arg));
+  else return -1;
+  if (!strcmp (str, "box"))
+    return FILLED_BOX_CURSOR;
+  if (!strcmp (str, "hollow"))
+    return HOLLOW_BOX_CURSOR;
+  if (!strcmp (str, "hbar"))
+    return HBAR_CURSOR;
+  if (!strcmp (str, "bar"))
+    return BAR_CURSOR;
+  if (!strcmp (str, "no"))
+    return NO_CURSOR;
+  return -1;
+}
+
+/* EXAMPLE #1:
+    (setq mc-list '(
+      (3 "hbar" [1.0 0.0 0.0])
+      (4 "bar" [0.0 1.0 0.0])
+      (5 "box" [0.0 0.0 1.0])
+      (6 "hollow" [0.8 0.4 0.2])
+      (7 ("hbar" 3) [1.0 0.0 1.0])
+      (8 ("bar" 3) [0.0 1.0 1.0])))
+   EXAMPLE #2:  (setq mc-list nil)
+The `mc_cache' is kept in the following example format:
+  ((
+    (3 hbar [1.0 0.0 0.0])
+    (4 bar [0.0 1.0 0.0])
+    (5 box [0.0 0.0 1.0])
+    (6 hollow [0.8 0.4 0.2])
+    (7 (hbar 3) [1.0 0.0 1.0])
+    (8 (bar 3) [0.0 1.0 1.0]))
+   (
+    ((3 hbar [1.0 0.0 0.0]) (22 20 2 0))
+    ((4 bar [0.0 1.0 0.0]) (33 20 3 0))
+    ((5 box [0.0 0.0 1.0]) (44 20 4 0))
+    ((6 hollow [0.8 0.4 0.2]) (55 20 5 0))
+    ((7 (hbar 3) [1.0 0.0 1.0]) (66 20 6 0))
+    ((8 (bar 3) [0.0 1.0 1.0]) (77 20 7 0))
+    )
+   (the buffer where `mc_cache' was set))
+TODO:  Set up a user option similar to `cursor-in-non-selected-windows'.
+To inspect a value that does not squarely fit into a GLYPH_DEBUG category,
+convert it to a lisp object and use `Fmessage'.  To avoid crashing Emacs,
+convert raw numbers using functions like `make_number', `make_float', etc.:
+  Lisp_Object my_object_one = make_float (0.1);
+  AUTO_STRING (my_string_one, "This is the value of `my_object_one':  %s");
+  CALLN (Fmessage, my_string_one, my_object_one);
+  Lisp_Object my_object_two = make_number (777);
+  AUTO_STRING (my_string_two, "This is the value of `my_object_two':  %s");
+  CALLN (Fmessage, my_string_two, my_object_two);  */
+void
+mc_calc (struct window *w, bool remove)
+{
+  int window_total_height = window_box_height (w);
+#ifdef GLYPH_DEBUG
+  debug_method_add (w, "window_total_height: %d", window_total_height);
+#endif
+  Lisp_Object frame;
+  EMACS_INT frame_char_width, frame_char_height, window_header_line_height;
+  struct frame *f = XFRAME (w->frame);
+  frame_char_width = FRAME_COLUMN_WIDTH (f);
+  frame_char_height = FRAME_LINE_HEIGHT (f);
+  window_header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+  struct window *sw = XWINDOW (f->selected_window);
+  enum text_cursor_kinds cursor_type = Qnil;
+  int cursor_width = 1;
+  double red, green, blue;
+  EMACS_INT posint, x, y, hpos, vpos;
+  EMACS_INT start = marker_position (w->start);
+  EMACS_INT end = BUF_Z (XBUFFER (w->contents)) - w->window_end_pos;
+  Lisp_Object cursor_spec_list, cursor_spec_type, cursor_color_vector, vlist, x_y_hpos_vpos, buf;
+  Lisp_Object temp = Qnil;
+  Lisp_Object result = Qnil;
+  struct buffer *b;
+  struct buffer *old_buffer = NULL;
+  buf = w->contents;
+  CHECK_BUFFER (buf);
+  b = XBUFFER (buf);
+  if (b != current_buffer)
+    {
+      old_buffer = current_buffer;
+      set_buffer_internal (b);
+    }
+  /* Normally window-start and window-end pointers are set within `redisplay_window', however,
+  that section of the code may not necessarily run when initializing the `mc_list'.  */
+  if (!w->mc.start && !w->mc.end && !w->mc.opoint)
+    {
+      w->mc.opoint = PT;
+      x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.opoint, start, end));
+      w->mc.opoint_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+      w->mc.opoint_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+      w->mc.opoint_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+      w->mc.opoint_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+      w->mc.start = start;
+      x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, start, start, end));
+      w->mc.start_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+      w->mc.start_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+      w->mc.start_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+      w->mc.start_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+      w->mc.end = end;
+      x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, end, start, end));
+      w->mc.end_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+      w->mc.end_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+      w->mc.end_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+      w->mc.end_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+      w->mc.y_diff = 0;
+      w->mc.vpos_diff = 0;
+    }
+  if ((remove && w->mc_cache && NILP (BVAR (b, mc_list)))
+      || (w->mc_cache && BVAR (b, mc_list) && (remove || w != sw)))
+    {
+#ifdef GLYPH_DEBUG
+  debug_method_add (w, "mc_calc:  remove cursors using cache");
+#endif
+      for (vlist = XCAR (XCDR (w->mc_cache));
+           CONSP (vlist);
+           vlist = XCDR (vlist))
+        {
+          cursor_spec_list = XCAR (XCAR (vlist));
+          posint = XINT (Fnth (make_number (0), cursor_spec_list));
+          cursor_spec_type = Fnth (make_number (1), cursor_spec_list);
+          if (CONSP (cursor_spec_type))
+            cursor_type = mc_lisp_to_cursor_type (XCAR (cursor_spec_type));
+            else
+              cursor_type = mc_lisp_to_cursor_type (cursor_spec_type);
+          if (CONSP (cursor_spec_type))
+            cursor_width = XINT (XCAR (XCDR (cursor_spec_type)));
+            else
+              cursor_width = 1;
+          if (posint
+              && w->mc.start
+              && w->mc.end
+              && posint >= w->mc.start
+              && posint <= w->mc.end)
+            {
+              x_y_hpos_vpos = XCAR (XCDR (XCAR (vlist)));
+              x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+              y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+              hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+              vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+              mc_erase (w, x, y, hpos, vpos, cursor_type, cursor_width);
+            }
+        }
+      if (NILP (BVAR (b, mc_list)))
+        wset_mc_cache (w, Qnil);
+    }
+  if (!remove
+      && w == sw
+      && w->mc.start
+      && w->mc.end
+      && w->mc.prev_start
+      && w->mc.prev_end
+      && w->mc.start == w->mc.prev_start
+      && w->mc.end == w->mc.prev_end
+      && !NILP (BVAR (b, mc_list))
+      && w->mc_cache
+      && !NILP (Fequal (Fnth (make_number (0), w->mc_cache), BVAR (b, mc_list))))
+    {
+#ifdef GLYPH_DEBUG
+  debug_method_add (w, "mc_calc:  draw cursors using cache");
+#endif
+      for (vlist = XCAR (XCDR (w->mc_cache));
+           CONSP (vlist);
+           vlist = XCDR (vlist))
+        {
+          cursor_spec_list = XCAR (XCAR (vlist));
+          posint = XINT (Fnth (make_number (0), cursor_spec_list));
+          cursor_spec_type = Fnth (make_number (1), cursor_spec_list);
+          if (CONSP (cursor_spec_type))
+            cursor_type = mc_lisp_to_cursor_type (XCAR (cursor_spec_type));
+            else
+              cursor_type = mc_lisp_to_cursor_type (cursor_spec_type);
+          if (CONSP (cursor_spec_type))
+            cursor_width = XINT (XCAR (XCDR (cursor_spec_type)));
+            else
+              cursor_width = 1;
+          cursor_color_vector = Fnth (make_number (2), cursor_spec_list);
+          if (STRINGP (cursor_color_vector))
+            cursor_color_vector = mc_color_vector_calculate (w, cursor_color_vector);
+          red = XFLOAT_DATA (AREF (cursor_color_vector, 0));
+          green = XFLOAT_DATA (AREF (cursor_color_vector, 1));
+          blue = XFLOAT_DATA (AREF (cursor_color_vector, 2));
+          if (posint
+              && w->mc.start
+              && w->mc.end
+              && posint >= w->mc.start
+              && posint <= w->mc.end)
+            {
+              x_y_hpos_vpos = XCAR (XCDR (XCAR (vlist)));
+              x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+              y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+              hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+              vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+              mc_draw (w, x, y, hpos, vpos, cursor_type, cursor_width, red, green, blue);
+            }
+        }
+    }
+  if (!remove
+      && w == sw
+      && w->mc.start
+      && w->mc.end
+      && !NILP (BVAR (b, mc_list)))
+    {
+#ifdef GLYPH_DEBUG
+  debug_method_add (w, "mc_calc:  draw cursors anew");
+#endif
+      for (vlist = BVAR (b, mc_list);
+           CONSP (vlist);
+           vlist = XCDR (vlist))
+        {
+          cursor_spec_list = XCAR (vlist);
+          posint = XINT (Fnth (make_number (0), cursor_spec_list));
+          cursor_spec_type = Fnth (make_number (1), cursor_spec_list);
+          if (CONSP (cursor_spec_type))
+            cursor_type = mc_lisp_to_cursor_type (XCAR (cursor_spec_type));
+            else
+              cursor_type = mc_lisp_to_cursor_type (cursor_spec_type);
+          if (CONSP (cursor_spec_type))
+            cursor_width = XINT (XCAR (XCDR (cursor_spec_type)));
+            else
+              cursor_width = 1;
+          cursor_color_vector = Fnth (make_number (2), cursor_spec_list);
+          if (STRINGP (cursor_color_vector))
+            cursor_color_vector = mc_color_vector_calculate (w, cursor_color_vector);
+          red = XFLOAT_DATA (AREF (cursor_color_vector, 0));
+          green = XFLOAT_DATA (AREF (cursor_color_vector, 1));
+          blue = XFLOAT_DATA (AREF (cursor_color_vector, 2));
+          x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, posint, w->mc.start, w->mc.end));
+          temp = Fcons (cursor_spec_list, Fcons (x_y_hpos_vpos, Qnil));
+          result = Fcons (temp, result);
+          x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+          y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+          hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+          vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+          if (w->mc.start
+              && w->mc.end
+              && posint >= w->mc.start
+              && posint <= w->mc.end)
+            mc_draw (w, x, y, hpos, vpos, cursor_type, cursor_width, red, green, blue);
+        }
+/* `w->mc_cache' is set for the window, not buffer+window -- i.e., all buffers appearing
+in the same window via `switch-to-buffer' will have `w->mc_cache'.  This behavior
+is consistent with functions such as `set-window-display-table'.  We deal with this in
+`nsterm.m' / `w32term.c' / `xterm.c' by comparing `w->contents' to the value of the `buf'
+stored in `w->mc_cache':  (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))  */
+      if (result)
+        wset_mc_cache (w, listn (CONSTYPE_HEAP, 3,
+                                   BVAR (b, mc_list),
+                                   Freverse (result),
+                                   Fcons (buf, Qnil)));
+    }
+  w->mc.draw_erase = false;
+  if (old_buffer)
+    set_buffer_internal (old_buffer);
+}
+
+void
+mc_remove_when_scrolled (struct window *w)
+{
+  struct frame *f = XFRAME (w->frame);
+  /* REMOVE FAKE CURSORS
+     update_begin (f) and update_end (f) are needed for quick removal of fake cursors;
+     otherwise, the user sees removal of each fake cursor in  s-l-o-w  m-o-t-i-o-n! */
+  update_begin (f);
+  if (!w->pseudo_window_p)
+    {
+      block_input ();
+      if (w->mc.draw_erase
+          && NILP (BVAR (XBUFFER (w->contents), mc_list))
+          && (w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache)))))
+          && !MINI_WINDOW_P (w))
+        mc_calc (w, 1);
+      unblock_input ();
+    }
+  update_end (f);
+}
+
+DEFUN ("mc-draw-fn", Fmc_draw_fn, Smc_draw_fn, 5, 5, 0,
+       doc: /* Draw multiple fake cursors.  */)
+  (Lisp_Object window, Lisp_Object x_y_hpos_vpos, Lisp_Object cursor_type, ptrdiff_t cursor_width, Lisp_Object color_vector)
+{
+  struct window *w = decode_live_window (window);
+  EMACS_INT x, y, hpos, vpos;
+  double red, green, blue;
+  x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+  y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+  hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+  vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+  cursor_type = mc_lisp_to_cursor_type (cursor_type);
+  red = XFLOAT_DATA (AREF (color_vector, 0));
+  green = XFLOAT_DATA (AREF (color_vector, 1));
+  blue = XFLOAT_DATA (AREF (color_vector, 2));
+  mc_draw (w, x, y, hpos, vpos, cursor_type, XINT (cursor_width), red, green, blue);
+  return Qnil;
+}
+
+DEFUN ("mc-erase-fn", Fmc_erase_fn, Smc_erase_fn, 4, 4, 0,
+       doc: /* Erase multiple fake cursors.  */)
+  (Lisp_Object window, Lisp_Object x_y_hpos_vpos, Lisp_Object cursor_type, ptrdiff_t cursor_width)
+{
+  struct window *w = decode_live_window (window);
+  EMACS_INT x, y, hpos, vpos;
+  x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+  y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+  hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+  vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+  cursor_type = mc_lisp_to_cursor_type (cursor_type);
+  mc_erase (w, x, y, hpos, vpos, cursor_type, XINT (cursor_width));
+  return Qnil;
+}
+
+DEFUN ("mc-x-y-hpos-vpos-fn", Fmc_x_y_hpos_vpos_fn, Smc_x_y_hpos_vpos_fn, 4, 4, 0,
+       doc: /* Calculate x/y/hpos/vpos.  START is `window-start'.  END is `window-end'.  */)
+  (Lisp_Object window, EMACS_INT posint, EMACS_INT start, EMACS_INT end)
+{
+  struct window *w = decode_live_window (window);
+  return mc_x_y_hpos_vpos (w, XINT (posint), XINT (start), XINT (end));
+}
+
+DEFUN ("mc-draw-erase", Fmc_draw_erase, Smc_draw_erase, 1, 1, 0,
+       doc: /* When using a timer, set `w->mc.draw_erase' -- `keyboard.c' is not used.  */)
+  (Lisp_Object window)
+{
+  struct window *w = decode_live_window (window);
+  w->mc.draw_erase = true;
+  return Qnil;
+}
+
+static struct window *
+mc_decode_valid_window (register Lisp_Object window)
+{
+  struct window *w;
+  if (NILP (window))
+    return XWINDOW (selected_window);
+  CHECK_VALID_WINDOW (window);
+  w = XWINDOW (window);
+  return w;
+}
+
+DEFUN ("mc-cache-fn", Fmc_cache_fn, Smc_cache_fn,
+       0, 1, 0,
+       doc: /* Return the mc_cache.  */)
+  (Lisp_Object window)
+{
+  return Fcopy_alist (mc_decode_valid_window (window)->mc_cache);
+}
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 void
 redisplay_other_windows (void)
 {
@@ -15418,6 +16052,15 @@ try_scrolling (Lisp_Object window, bool just_this_one_p,
 	}
     }
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  mc_remove_when_scrolled (w);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   /* Run window scroll functions.  */
   startp = run_window_scroll_functions (window, startp);
 
@@ -16342,7 +16985,19 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 	{
 	  update_mode_line = true;
 	  w->update_mode_line = true;
-	  startp = run_window_scroll_functions (window, startp);
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  mc_remove_when_scrolled (w);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
+  /* Run window scroll functions.  */
+  startp = run_window_scroll_functions (window, startp);
+
 	}
 
       if (CHARPOS (startp) < BEGV)
@@ -16496,6 +17151,16 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 #ifdef GLYPH_DEBUG
       debug_method_add (w, "forced window start");
 #endif
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  mc_remove_when_scrolled (w);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       goto done;
     }
 
@@ -16804,6 +17469,15 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
      get errors.  */
   set_marker_both (w->start, Qnil, IT_CHARPOS (it), IT_BYTEPOS (it));
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  mc_remove_when_scrolled (w);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   /* Run scroll hooks.  */
   startp = run_window_scroll_functions (window, it.current.pos);
 
@@ -16935,7 +17609,22 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
 	  clear_glyph_matrix (w->desired_matrix);
 	  if (1 == try_window (window, it.current.pos,
 			       TRY_WINDOW_CHECK_MARGINS))
-	    goto done;
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+    {
+
+      mc_remove_when_scrolled (w);
+
+      goto done;
+
+    }
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 	}
 
       /* If centering point failed to make the whole line visible,
@@ -17107,6 +17796,177 @@ redisplay_window (Lisp_Object window, bool just_this_one_p)
   else
     TEMP_SET_PT_BOTH (CHARPOS (opoint), BYTEPOS (opoint));
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+  if ((!NILP (BVAR (XBUFFER (w->contents), mc_list)) || w->mc_cache)
+      && !MINI_WINDOW_P (w))
+    {
+      Lisp_Object x_y_hpos_vpos;
+      EMACS_INT start = CHARPOS (startp);
+      EMACS_INT end = BUF_Z (buffer) - w->window_end_pos;
+      if (w->mc.draw_erase)
+        {
+          if (w->mc.start)
+            {
+              w->mc.prev_start = w->mc.start;
+              x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.prev_start, start, end));
+              w->mc.prev_start_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+              w->mc.prev_start_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+              w->mc.prev_start_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+              w->mc.prev_start_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+            }
+            else
+              {
+                w->mc.prev_start = -1;
+                w->mc.prev_start_x = -1;
+                w->mc.prev_start_y = -1;
+                w->mc.prev_start_hpos = -1;
+                w->mc.prev_start_vpos = -1;
+              }
+          if (w->mc.end)
+            {
+              w->mc.prev_end = w->mc.end;
+              /* eob IS visible.
+              Excludes a situation when last visible line at bottom of window contains eob.  */
+              if (w->mc.prev_end == end)
+                {
+                  x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.prev_end, start, end));
+                  w->mc.prev_end_x = w->mc.end_x;
+                  w->mc.prev_end_y = w->mc.end_y;
+                  w->mc.prev_end_hpos = w->mc.end_hpos;
+                  w->mc.prev_end_vpos = w->mc.end_vpos;
+                }
+                /* eob is NOT visible.
+                Excludes a situation when last visible line at bottom of window contains eob.  **/
+                else
+                  {
+                    x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.prev_end, start, end));
+                    w->mc.prev_end_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+                    w->mc.prev_end_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+                    w->mc.prev_end_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+                    w->mc.prev_end_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+                  }
+            }
+            else
+              {
+                w->mc.prev_end = -1;
+                w->mc.prev_end_x = -1;
+                w->mc.prev_end_y = -1;
+                w->mc.prev_end_hpos = -1;
+                w->mc.prev_end_vpos = -1;
+              }
+          if (w->mc.opoint)
+            {
+              w->mc.prev_opoint = w->mc.opoint;
+              w->mc.prev_opoint_x = w->mc.opoint_x;
+              w->mc.prev_opoint_y = w->mc.opoint_y;
+              w->mc.prev_opoint_hpos = w->mc.opoint_hpos;
+              w->mc.prev_opoint_vpos = w->mc.opoint_vpos;
+            }
+
+          w->mc.opoint = PT;
+          x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.opoint, start, end));
+          w->mc.opoint_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+          w->mc.opoint_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+          w->mc.opoint_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+          w->mc.opoint_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+
+          w->mc.start = start;
+          x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, start, start, end));
+          w->mc.start_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+          w->mc.start_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+          w->mc.start_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+          w->mc.start_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+
+          w->mc.end = end;
+          x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, end, start, end));
+          w->mc.end_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+          w->mc.end_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+          w->mc.end_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+          w->mc.end_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+
+          /* Start remains the same.  */
+          if (w->mc.prev_start_vpos == w->mc.start_vpos
+              || w->mc.prev_end < w->mc.start)
+            {
+              w->mc.y_diff = 0;
+              w->mc.vpos_diff = 0;
+            }
+            /* Screen moved ▼ -- e.g., `previous-line', `scroll-down'.  */
+            else if (w->mc.prev_start_vpos > 0)
+              {
+                w->mc.y_diff = (w->mc.prev_start_y - w->mc.start_y) * -1;
+                w->mc.vpos_diff = (w->mc.prev_start_vpos - w->mc.start_vpos) * -1;
+              }
+              /* Screen moved ▲ (eob NOT visible) -- e.g., `next-line', `scroll-up'.  */
+              else if (w->mc.end_vpos > w->mc.prev_end_vpos && w->mc.prev_end != -1)
+                {
+                  w->mc.y_diff = w->mc.end_y - w->mc.prev_end_y;
+                  w->mc.vpos_diff = w->mc.end_vpos - w->mc.prev_end_vpos;
+                }
+                /* Screen moved ▲ (eob IS visible) -- e.g., `next-line', `scroll-up'.  */
+                else if (w->mc.end_vpos < w->mc.prev_end_vpos && w->mc.prev_end != -1)
+                  {
+                    w->mc.y_diff = w->mc.prev_end_y - w->mc.end_y;
+                    w->mc.vpos_diff = w->mc.prev_end_vpos - w->mc.end_vpos;
+                  }
+                  /* Screen moved ▲ (eob just became visible) -- e.g., `next-line', `scroll-up'.
+                  Absent subtracting 1 from w->mc.prev_end, that point and the new w->mc.end are
+                  on the same line and it appears that nothing has changed -- w->mc.prev_end is
+                  on the far left of the line and w->mc.end is on the far right of the line.  */
+                  else if (w->mc.end_vpos == w->mc.prev_end_vpos)
+                    {
+                      x_y_hpos_vpos = Fnth (make_number (0), mc_x_y_hpos_vpos (w, w->mc.prev_end - 1, start, end));
+                      w->mc.prev_end_x = XINT (Fnth (make_number (0), x_y_hpos_vpos));
+                      w->mc.prev_end_y = XINT (Fnth (make_number (1), x_y_hpos_vpos));
+                      w->mc.prev_end_hpos = XINT (Fnth (make_number (2), x_y_hpos_vpos));
+                      w->mc.prev_end_vpos = XINT (Fnth (make_number (3), x_y_hpos_vpos));
+                      w->mc.y_diff = w->mc.end_y - w->mc.prev_end_y;
+                      w->mc.vpos_diff = w->mc.end_vpos - w->mc.prev_end_vpos;
+                    }
+                /* `mc-list` has just been initialized -- previous start/end are set to -1.  */
+                    else if (w->mc.prev_end == -1)
+                      {
+                        w->mc.y_diff = 0;
+                        w->mc.vpos_diff = 0;
+                      }
+
+          if (w->mc.y_diff < 0)
+            w->mc.y_diff = abs (w->mc.y_diff);
+            else if (w->mc.y_diff > 0)
+              w->mc.y_diff = w->mc.y_diff * -1;
+          if (w->mc.vpos_diff < 0)
+            w->mc.vpos_diff = abs (w->mc.vpos_diff);
+            else if (w->mc.vpos_diff > 0)
+            w->mc.vpos_diff = w->mc.vpos_diff * -1;
+
+/* #ifdef GLYPH_DEBUG
+  debug_method_add (w, "diff: (%d %d) | prev_start: %d (%d %d %d %d) | start: %d (%d %d %d %d) | prev_end: %d (%d %d %d %d) | end: %d (%d %d %d %d)",
+    w->mc.y_diff, w->mc.vpos_diff,
+    w->mc.prev_start, w->mc.prev_start_x, w->mc.prev_start_y, w->mc.prev_start_hpos, w->mc.prev_start_vpos,
+    w->mc.start, w->mc.start_x, w->mc.start_y, w->mc.start_hpos, w->mc.start_vpos,
+    w->mc.prev_end, w->mc.prev_end_x, w->mc.prev_end_y, w->mc.prev_end_hpos, w->mc.prev_end_vpos,
+    w->mc.end, w->mc.end_x, w->mc.end_y, w->mc.end_hpos, w->mc.end_vpos);
+#endif  */
+
+        }
+/* First attempt at dealing with a `redisplay_preserve_echo_area' situation.  */
+        else
+          {
+            w->mc.prev_opoint = w->mc.opoint;
+            w->mc.prev_opoint_x = w->mc.opoint_x;
+            w->mc.prev_opoint_y = w->mc.opoint_y;
+            w->mc.prev_opoint_hpos = w->mc.opoint_hpos;
+            w->mc.prev_opoint_vpos = w->mc.opoint_vpos;
+          }
+    }
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   set_buffer_internal_1 (old);
   /* Avoid an abort in TEMP_SET_PT_BOTH if the buffer has become
      shorter.  This can be caused by log truncation in *Messages*.  */
@@ -28432,9 +29292,20 @@ display_and_set_cursor (struct window *w, bool on,
       w->phys_cursor.vpos = vpos;
     }
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  double red = -1.0;
+  double green = -1.0;
+  double blue = -1.0;
   FRAME_RIF (f)->draw_window_cursor (w, glyph_row, x, y,
                                      new_cursor_type, new_cursor_width,
-                                     on, active_cursor);
+                                     on, active_cursor, red, green, blue);
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 }
 
 
@@ -31108,6 +31979,32 @@ x_intersect_rectangles (XRectangle *r1, XRectangle *r2, XRectangle *result)
 void
 syms_of_xdisp (void)
 {
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+  defsubr (&Smc_color_vector_calculate);
+  defsubr (&Smc_draw_fn);
+  defsubr (&Smc_erase_fn);
+  defsubr (&Smc_x_y_hpos_vpos_fn);
+  defsubr (&Smc_draw_erase);
+  defsubr (&Smc_cache_fn);
+
+  DEFSYM (Qx, "x");
+  DEFSYM (Qw32, "w32");
+  DEFSYM (Qns, "ns");
+  DEFSYM (Qmc_color_vector_calculate, "mc-color-vector-calculate");
+  DEFSYM (Qmc_draw_fn, "mc-draw-fn");
+  DEFSYM (Qmc_erase_fn, "mc-erase-fn");
+  DEFSYM (Qmc_x_y_hpos_vpos_fn, "mc-x-y-hpos-vpos-fn");
+  DEFSYM (Qmc_draw_erase, "mc-draw-erase");
+  DEFSYM (Qmc_cache_fn, "mc-cache-fn");
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
   Vwith_echo_area_save_vector = Qnil;
   staticpro (&Vwith_echo_area_save_vector);
 
diff --git a/src/xterm.c b/src/xterm.c
index ba9bf50..a0b7dd9 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -1148,6 +1148,40 @@ x_update_window_end (struct window *w, bool cursor_on_p,
     {
       block_input ();
 
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+
+      if (w->mc.draw_erase
+          && (!NILP (BVAR (XBUFFER (w->contents), mc_list))
+              || (w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          if ((w->mc_cache && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))))
+            mc_calc (w, 1);
+          /* Draw fake cursors  */
+          if (!NILP (BVAR (XBUFFER (w->contents), mc_list)))
+            mc_calc (w, 0);
+        }
+
+      /* First attempt at dealing with a `redisplay_preserve_echo_area' situation.  */
+      if (!w->mc.draw_erase
+          && !NILP (BVAR (XBUFFER (w->contents), mc_list))
+          && w->mc_cache
+          && (EQ (w->contents, XCAR (Fnth (make_number (2), w->mc_cache))))
+          && !MINI_WINDOW_P (w))
+        {
+          /* Remove fake cursors.  */
+          mc_calc (w, 1);
+          /* Draw fake cursors  */
+          mc_calc (w, 0);
+        }
+
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
       if (cursor_on_p)
 	display_and_set_cursor (w, true,
 				w->output_cursor.hpos, w->output_cursor.vpos,
@@ -1449,10 +1483,22 @@ static void x_check_font (struct frame *, struct font *);
 static void
 x_set_cursor_gc (struct glyph_string *s)
 {
-  if (s->font == FRAME_FONT (s->f)
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+  Lisp_Object window = (selected_window);
+  struct window *w = decode_live_window (window);
+  if ((s->font == FRAME_FONT (s->f)
       && s->face->background == FRAME_BACKGROUND_PIXEL (s->f)
       && s->face->foreground == FRAME_FOREGROUND_PIXEL (s->f)
       && !s->cmp)
+      || w->mc.set_cursor_gc)
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
     s->gc = s->f->output_data.x->cursor_gc;
   else
     {
@@ -9044,7 +9090,16 @@ x_clear_frame_area (struct frame *f, int x, int y, int width, int height)
 static void
 x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
 		      int y, enum text_cursor_kinds cursor_type,
-		      int cursor_width, bool on_p, bool active_p)
+
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* multiple cursors */
+
+        int cursor_width, bool on_p, bool active_p, double red, double green, double blue)
+
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+
+
 {
   struct frame *f = XFRAME (WINDOW_FRAME (w));
 
@@ -9063,31 +9118,122 @@ x_draw_window_cursor (struct window *w, struct glyph_row *glyph_row, int x,
 	}
       else
 	{
-	  switch (cursor_type)
-	    {
-	    case HOLLOW_BOX_CURSOR:
-	      x_draw_hollow_cursor (w, glyph_row);
-	      break;
-
-	    case FILLED_BOX_CURSOR:
-	      draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
-	      break;
 
-	    case BAR_CURSOR:
-	      x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
-	      break;
 
-	    case HBAR_CURSOR:
-	      x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
-	      break;
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
+/* BEGIN multiple cursors */
+  switch (cursor_type)
+  {
+    case HOLLOW_BOX_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.x->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+          unsigned long orig_val = f->output_data.x->cursor_pixel;
+          int int_red = red * 65535;
+          int int_green = green * 65535;
+          int int_blue = blue * 65535;
+          f->output_data.x->cursor_pixel = x_make_truecolor_pixel (dpyinfo, int_red, int_green, int_blue);
+          x_draw_hollow_cursor (w, glyph_row);
+          f->output_data.x->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_hollow_cursor (w, glyph_row);
+      break;
+    }
+    case FILLED_BOX_CURSOR:
+    {
+       /* TODO:  kdb to consider adding support for multiple cursor foreground
+       customization of a FILLED_BOX_CURSOR.  */
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.x->cursor_gc' by borrowing the
+        functionality of `x_make_gc' in xfns.c.  */
+        {
+          block_input ();
+          Lisp_Object window = (selected_window);
+          struct window *w = decode_live_window (window);
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+          int int_red = red * 65535;
+          int int_green = green * 65535;
+          int int_blue = blue * 65535;
+          XGCValues gc_values;
+          unsigned long mask = GCForeground | GCBackground | GCFillStyle | GCLineWidth;
+          unsigned long orig_val_a = FRAME_BACKGROUND_PIXEL (f);
+          unsigned long orig_val_b = f->output_data.x->cursor_pixel;
+          gc_values.line_width = 0;  /* Means 1 using fast algorithm.  */
+          gc_values.foreground = FRAME_BACKGROUND_PIXEL (f);
+          gc_values.background = x_make_truecolor_pixel (dpyinfo, int_red, int_green, int_blue);
+          gc_values.fill_style = FillOpaqueStippled;
+          f->output_data.x->cursor_gc
+            = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), mask, &gc_values);
+          /* When `w->mc.set_cursor_gc = true', force `x_set_cursor_gc' to
+          use `s->f->output_data.x->cursor_gc'.  */
+          w->mc.set_cursor_gc = true;
+          draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+          w->mc.set_cursor_gc = false;
+          gc_values.line_width = 0;  /* Means 1 using fast algorithm.  */
+          gc_values.foreground = orig_val_a;
+          gc_values.background = orig_val_b;
+          gc_values.fill_style = FillOpaqueStippled;
+          f->output_data.x->cursor_gc
+            = XCreateGC (FRAME_X_DISPLAY (f), FRAME_X_WINDOW (f), mask, &gc_values);
+          unblock_input ();
+        }
+        else
+          draw_phys_cursor_glyph (w, glyph_row, DRAW_CURSOR);
+      break;
+    }
+    case BAR_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.x->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+          unsigned long orig_val = f->output_data.x->cursor_pixel;
+          int int_red = red * 65535;
+          int int_green = green * 65535;
+          int int_blue = blue * 65535;
+          f->output_data.x->cursor_pixel = x_make_truecolor_pixel (dpyinfo, int_red, int_green, int_blue);
+          x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+          f->output_data.x->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_bar_cursor (w, glyph_row, cursor_width, BAR_CURSOR);
+      break;
+    }
+    case HBAR_CURSOR:
+    {
+      if (red >= 0 && blue >= 0 && green >= 0)
+        /* Temporarily hijack `f->output_data.x->cursor_pixel'.  */
+        {
+          struct frame *f = XFRAME (WINDOW_FRAME (w));
+          struct x_display_info *dpyinfo = FRAME_DISPLAY_INFO (f);
+          unsigned long orig_val = f->output_data.x->cursor_pixel;
+          int int_red = red * 65535;
+          int int_green = green * 65535;
+          int int_blue = blue * 65535;
+          f->output_data.x->cursor_pixel = x_make_truecolor_pixel (dpyinfo, int_red, int_green, int_blue);
+          x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+          f->output_data.x->cursor_pixel = orig_val;
+        }
+        else
+          x_draw_bar_cursor (w, glyph_row, cursor_width, HBAR_CURSOR);
+      break;
+    }
+    case NO_CURSOR:
+      w->phys_cursor_width = 0;
+      break;
+    default:
+      emacs_abort ();
+  }
+/* END multiple cursors */
+/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; */
 
-	    case NO_CURSOR:
-	      w->phys_cursor_width = 0;
-	      break;
 
-	    default:
-	      emacs_abort ();
-	    }
 	}
 
 #ifdef HAVE_X_I18N
