Merge: nsmenu.m: Replace all uses of XVECTOR with ASIZE and AREF.
[bpt/emacs.git] / src / fringe.c
index 991575d..bd17884 100644 (file)
@@ -1,14 +1,14 @@
 /* Fringe handling (split from xdisp.c).
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997,
                  1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
 /* Fringe handling (split from xdisp.c).
    Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997,
                  1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
-                 2006, 2007  Free Software Foundation, Inc.
+                 2006, 2007, 2008, 2009, 2010, 2011  Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
 
 This file is part of GNU Emacs.
 
-GNU Emacs is free software; you can redistribute it and/or modify
+GNU Emacs is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 3, or (at your option)
-any later version.
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 
 GNU Emacs is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -16,12 +16,11 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GNU Emacs; see the file COPYING.  If not, write to
-the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include <config.h>
 #include <stdio.h>
 
 #include <config.h>
 #include <stdio.h>
+#include <setjmp.h>
 
 #include "lisp.h"
 #include "frame.h"
 
 #include "lisp.h"
 #include "frame.h"
@@ -484,7 +483,7 @@ static struct fringe_bitmap **fringe_bitmaps;
 static Lisp_Object *fringe_faces;
 static int max_fringe_bitmaps;
 
 static Lisp_Object *fringe_faces;
 static int max_fringe_bitmaps;
 
-static int max_used_fringe_bitmap = MAX_STANDARD_FRINGE_BITMAPS;
+int max_used_fringe_bitmap = MAX_STANDARD_FRINGE_BITMAPS;
 
 
 /* Lookup bitmap number for symbol BITMAP.
 
 
 /* Lookup bitmap number for symbol BITMAP.
@@ -542,6 +541,20 @@ get_fringe_bitmap_name (bn)
   return num;
 }
 
   return num;
 }
 
+/* Get fringe bitmap data for bitmap number BN.  */
+
+static struct fringe_bitmap *
+get_fringe_bitmap_data (int bn)
+{
+  struct fringe_bitmap *fb;
+
+  fb = fringe_bitmaps[bn];
+  if (fb == NULL)
+    fb = &standard_bitmaps[bn < MAX_STANDARD_FRINGE_BITMAPS
+                          ? bn : UNDEF_FRINGE_BITMAP];
+
+  return fb;
+}
 
 /* Draw the bitmap WHICH in one of the left or right fringes of
    window W.  ROW is the glyph row for which to display the bitmap; it
 
 /* Draw the bitmap WHICH in one of the left or right fringes of
    window W.  ROW is the glyph row for which to display the bitmap; it
@@ -562,23 +575,26 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
   struct fringe_bitmap *fb;
   int period;
   int face_id = DEFAULT_FACE_ID;
   struct fringe_bitmap *fb;
   int period;
   int face_id = DEFAULT_FACE_ID;
+  int offset, header_line_height;
 
 
-  p.cursor_p = 0;
   p.overlay_p = (overlay & 1) == 1;
   p.cursor_p = (overlay & 2) == 2;
 
   if (which != NO_FRINGE_BITMAP)
     {
   p.overlay_p = (overlay & 1) == 1;
   p.cursor_p = (overlay & 2) == 2;
 
   if (which != NO_FRINGE_BITMAP)
     {
+      offset = 0;
     }
   else if (left_p)
     {
       which = row->left_fringe_bitmap;
       face_id = row->left_fringe_face_id;
     }
   else if (left_p)
     {
       which = row->left_fringe_bitmap;
       face_id = row->left_fringe_face_id;
+      offset = row->left_fringe_offset;
     }
   else
     {
       which = row->right_fringe_bitmap;
       face_id = row->right_fringe_face_id;
     }
   else
     {
       which = row->right_fringe_bitmap;
       face_id = row->right_fringe_face_id;
+      offset = row->right_fringe_offset;
     }
 
   if (face_id == DEFAULT_FACE_ID)
     }
 
   if (face_id == DEFAULT_FACE_ID)
@@ -586,20 +602,17 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
       Lisp_Object face;
 
       if ((face = fringe_faces[which], NILP (face))
       Lisp_Object face;
 
       if ((face = fringe_faces[which], NILP (face))
-         || (face_id = lookup_derived_face (f, face, 'A', FRINGE_FACE_ID, 0),
+         || (face_id = lookup_derived_face (f, face, FRINGE_FACE_ID, 0),
              face_id < 0))
        face_id = FRINGE_FACE_ID;
     }
 
              face_id < 0))
        face_id = FRINGE_FACE_ID;
     }
 
-  fb = fringe_bitmaps[which];
-  if (fb == NULL)
-    fb = &standard_bitmaps[which < MAX_STANDARD_FRINGE_BITMAPS
-                          ? which : UNDEF_FRINGE_BITMAP];
+  fb = get_fringe_bitmap_data (which);
 
   period = fb->period;
 
   /* Convert row to frame coordinates.  */
 
   period = fb->period;
 
   /* Convert row to frame coordinates.  */
-  p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y);
+  p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y) + offset;
 
   p.which = which;
   p.bits = fb->bits;
 
   p.which = which;
   p.bits = fb->bits;
@@ -608,9 +621,19 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
   p.h = fb->height;
   p.dh = (period > 0 ? (p.y % period) : 0);
   p.h -= p.dh;
   p.h = fb->height;
   p.dh = (period > 0 ? (p.y % period) : 0);
   p.h -= p.dh;
-  /* Clip bitmap if too high.  */
-  if (p.h > row->height)
-    p.h = row->height;
+
+  /* Adjust y to the offset in the row to start drawing the bitmap.  */
+  switch (fb->align)
+    {
+    case ALIGN_BITMAP_CENTER:
+      p.y += (row->height - p.h) / 2;
+      break;
+    case ALIGN_BITMAP_BOTTOM:
+      p.y += (row->visible_height - p.h);
+      break;
+    case ALIGN_BITMAP_TOP:
+      break;
+    }
 
   p.face = FACE_FROM_ID (f, face_id);
 
 
   p.face = FACE_FROM_ID (f, face_id);
 
@@ -626,6 +649,9 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
   /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
      the fringe.  */
   p.bx = -1;
   /* Clear left fringe if no bitmap to draw or if bitmap doesn't fill
      the fringe.  */
   p.bx = -1;
+  header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
+  p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
+  p.ny = row->visible_height;
   if (left_p)
     {
       int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
   if (left_p)
     {
       int wd = WINDOW_LEFT_FRINGE_WIDTH (w);
@@ -636,7 +662,7 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
        p.wd = wd;
       p.x = x - p.wd - (wd - p.wd) / 2;
 
        p.wd = wd;
       p.x = x - p.wd - (wd - p.wd) / 2;
 
-      if (p.wd < wd || row->height > p.h)
+      if (p.wd < wd || p.y > p.by || p.y + p.h < p.by + p.ny)
        {
          /* If W has a vertical border to its left, don't draw over it.  */
          wd -= ((!WINDOW_LEFTMOST_P (w)
        {
          /* If W has a vertical border to its left, don't draw over it.  */
          wd -= ((!WINDOW_LEFTMOST_P (w)
@@ -658,35 +684,13 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
       p.x = x + (wd - p.wd) / 2;
       /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
         the fringe.  */
       p.x = x + (wd - p.wd) / 2;
       /* Clear right fringe if no bitmap to draw of if bitmap doesn't fill
         the fringe.  */
-      if (p.wd < wd || row->height > p.h)
+      if (p.wd < wd || p.y > p.by || p.y + p.h < p.by + p.ny)
        {
          p.bx = x;
          p.nx = wd;
        }
     }
 
        {
          p.bx = x;
          p.nx = wd;
        }
     }
 
-  if (p.bx >= 0)
-    {
-      int header_line_height = WINDOW_HEADER_LINE_HEIGHT (w);
-
-      p.by = WINDOW_TO_FRAME_PIXEL_Y (w, max (header_line_height, row->y));
-      p.ny = row->visible_height;
-    }
-
-  /* Adjust y to the offset in the row to start drawing the bitmap.  */
-  switch (fb->align)
-    {
-    case ALIGN_BITMAP_CENTER:
-      p.y += (row->height - p.h) / 2;
-      break;
-    case ALIGN_BITMAP_BOTTOM:
-      p.h = fb->height;
-      p.y += (row->visible_height - p.h);
-      break;
-    case ALIGN_BITMAP_TOP:
-      break;
-    }
-
   FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p);
 }
 
   FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p);
 }
 
@@ -731,7 +735,7 @@ get_logical_fringe_bitmap (w, bitmap, right_p, partial_p)
      Elements are:
        BITMAP          -- use for all
        (L R)           -- use for left right (whether partial or not)
      Elements are:
        BITMAP          -- use for all
        (L R)           -- use for left right (whether partial or not)
-       (L R PL PR)     -- use for left rigth partial-left partial-right
+       (L R PL PR)     -- use for left right partial-left partial-right
        If any value in local binding is not present or t, use global value.
 
      If partial, lookup partial bitmap in default value if not found here.
        If any value in local binding is not present or t, use global value.
 
      If partial, lookup partial bitmap in default value if not found here.
@@ -912,7 +916,7 @@ draw_window_fringes (w, no_fringe)
   struct glyph_row *row;
   int yb = window_text_bottom_y (w);
   int nrows = w->current_matrix->nrows;
   struct glyph_row *row;
   int yb = window_text_bottom_y (w);
   int nrows = w->current_matrix->nrows;
-  int y = 0, rn;
+  int y, rn;
   int updated = 0;
 
   if (w->pseudo_window_p)
   int updated = 0;
 
   if (w->pseudo_window_p)
@@ -924,7 +928,7 @@ draw_window_fringes (w, no_fringe)
          || WINDOW_RIGHT_FRINGE_WIDTH (w) == 0))
     updated++;
 
          || WINDOW_RIGHT_FRINGE_WIDTH (w) == 0))
     updated++;
 
-  for (y = 0, rn = 0, row = w->current_matrix->rows;
+  for (y = w->vscroll, rn = 0, row = w->current_matrix->rows;
        y < yb && rn < nrows;
        y += row->height, ++row, ++rn)
     {
        y < yb && rn < nrows;
        y += row->height, ++row, ++rn)
     {
@@ -960,6 +964,9 @@ update_window_fringes (w, keep_current_p)
   Lisp_Object ind = Qnil;
 #define MAX_BITMAP_CACHE (8*4)
   int bitmap_cache[MAX_BITMAP_CACHE];
   Lisp_Object ind = Qnil;
 #define MAX_BITMAP_CACHE (8*4)
   int bitmap_cache[MAX_BITMAP_CACHE];
+  int top_ind_rn, bot_ind_rn;
+  int top_ind_min_y, bot_ind_max_y;
+  int top_row_ends_at_zv_p, bot_row_ends_at_zv_p;
 
   if (w->pseudo_window_p)
     return 0;
 
   if (w->pseudo_window_p)
     return 0;
@@ -988,56 +995,41 @@ update_window_fringes (w, keep_current_p)
        boundary_top = boundary_bot = Qleft;
     }
 
        boundary_top = boundary_bot = Qleft;
     }
 
+  top_ind_rn = bot_ind_rn = -1;
   if (!NILP (ind))
     {
   if (!NILP (ind))
     {
-      int done_top = 0, done_bot = 0;
-
-      for (y = 0, rn = 0;
+      for (y = w->vscroll, rn = 0;
           y < yb && rn < nrows;
           y += row->height, ++rn)
        {
           y < yb && rn < nrows;
           y += row->height, ++rn)
        {
-         unsigned indicate_bob_p, indicate_top_line_p;
-         unsigned indicate_eob_p, indicate_bottom_line_p;
-
          row = w->desired_matrix->rows + rn;
          if (!row->enabled_p)
            row = w->current_matrix->rows + rn;
 
          row = w->desired_matrix->rows + rn;
          if (!row->enabled_p)
            row = w->current_matrix->rows + rn;
 
-         indicate_bob_p = row->indicate_bob_p;
-         indicate_top_line_p = row->indicate_top_line_p;
-         indicate_eob_p = row->indicate_eob_p;
-         indicate_bottom_line_p = row->indicate_bottom_line_p;
-
          row->indicate_bob_p = row->indicate_top_line_p = 0;
          row->indicate_eob_p = row->indicate_bottom_line_p = 0;
 
          if (!row->mode_line_p)
            {
          row->indicate_bob_p = row->indicate_top_line_p = 0;
          row->indicate_eob_p = row->indicate_bottom_line_p = 0;
 
          if (!row->mode_line_p)
            {
-             if (!done_top)
+             if (top_ind_rn < 0 && row->visible_height > 0)
                {
                  if (MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer))
                      && !MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
                    row->indicate_bob_p = !NILP (boundary_top);
                  else
                    row->indicate_top_line_p = !NILP (arrow_top);
                {
                  if (MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer))
                      && !MATRIX_ROW_PARTIALLY_VISIBLE_AT_TOP_P (w, row))
                    row->indicate_bob_p = !NILP (boundary_top);
                  else
                    row->indicate_top_line_p = !NILP (arrow_top);
-                 done_top = 1;
+                 top_ind_rn = rn;
                }
 
                }
 
-             if (!done_bot)
+             if (bot_ind_rn < 0)
                {
                  if (MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer))
                      && !MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row))
                {
                  if (MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer))
                      && !MATRIX_ROW_PARTIALLY_VISIBLE_AT_BOTTOM_P (w, row))
-                   row->indicate_eob_p = !NILP (boundary_bot), done_bot = 1;
+                   row->indicate_eob_p = !NILP (boundary_bot), bot_ind_rn = rn;
                  else if (y + row->height >= yb)
                  else if (y + row->height >= yb)
-                   row->indicate_bottom_line_p = !NILP (arrow_bot), done_bot = 1;
+                   row->indicate_bottom_line_p = !NILP (arrow_bot), bot_ind_rn = rn;
                }
            }
                }
            }
-
-         if (indicate_bob_p != row->indicate_bob_p
-             || indicate_top_line_p != row->indicate_top_line_p
-             || indicate_eob_p != row->indicate_eob_p
-             || indicate_bottom_line_p != row->indicate_bottom_line_p)
-           row->redraw_fringe_bitmaps_p = 1;
        }
     }
 
        }
     }
 
@@ -1061,12 +1053,132 @@ update_window_fringes (w, keep_current_p)
       get_logical_fringe_bitmap (w, which, 1, partial_p)))
 
 
       get_logical_fringe_bitmap (w, which, 1, partial_p)))
 
 
-  for (y = 0, rn = 0;
+  /* Extend top-aligned top indicator (or bottom-aligned bottom
+     indicator) to adjacent rows if it doesn't fit in one row.  */
+  top_ind_min_y = bot_ind_max_y = -1;
+  if (top_ind_rn >= 0)
+    {
+      int bn = NO_FRINGE_BITMAP;
+
+      row = w->desired_matrix->rows + top_ind_rn;
+      if (!row->enabled_p)
+       row = w->current_matrix->rows + top_ind_rn;
+
+      top_row_ends_at_zv_p = row->ends_at_zv_p;
+      if (row->indicate_bob_p)
+       {
+         if (EQ (boundary_top, Qleft))
+           bn = ((row->indicate_eob_p && EQ (boundary_bot, Qleft))
+                 ? LEFT_FRINGE (1, Qtop_bottom, row->ends_at_zv_p)
+                 : LEFT_FRINGE (2, Qtop, 0));
+         else
+           bn = ((row->indicate_eob_p && EQ (boundary_bot, Qright))
+                 ? RIGHT_FRINGE (1, Qtop_bottom, row->ends_at_zv_p)
+                 : RIGHT_FRINGE (2, Qtop, 0));
+       }
+      else if (row->indicate_top_line_p)
+       {
+         if (EQ (arrow_top, Qleft))
+           bn = LEFT_FRINGE (6, Qup, 0);
+         else
+           bn = RIGHT_FRINGE (6, Qup, 0);
+       }
+
+      if (bn != NO_FRINGE_BITMAP)
+       {
+         struct fringe_bitmap *fb = get_fringe_bitmap_data (bn);
+
+         if (fb->align == ALIGN_BITMAP_TOP && fb->period == 0)
+           {
+             struct glyph_row *row1;
+             int top_ind_max_y;
+
+             top_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+             top_ind_max_y = top_ind_min_y + fb->height;
+             if (top_ind_max_y > yb)
+               top_ind_max_y = yb;
+
+             for (y = row->y + row->height, rn = top_ind_rn + 1;
+                  y < top_ind_max_y && rn < nrows;
+                  y += row1->height, rn++)
+               {
+                 if (bot_ind_rn >= 0 && rn >= bot_ind_rn)
+                   break;
+
+                 row1 = w->desired_matrix->rows + rn;
+                 if (!row1->enabled_p)
+                   row1 = w->current_matrix->rows + rn;
+
+                 row1->indicate_bob_p = row->indicate_bob_p;
+                 row1->indicate_top_line_p = row->indicate_top_line_p;
+               }
+           }
+       }
+    }
+  if (bot_ind_rn >= 0)
+    {
+      int bn = NO_FRINGE_BITMAP;
+
+      row = w->desired_matrix->rows + bot_ind_rn;
+      if (!row->enabled_p)
+       row = w->current_matrix->rows + bot_ind_rn;
+
+      bot_row_ends_at_zv_p = row->ends_at_zv_p;
+      if (row->indicate_eob_p)
+       {
+         if (EQ (boundary_bot, Qleft))
+           bn = LEFT_FRINGE (3, Qbottom, row->ends_at_zv_p);
+         else
+           bn = RIGHT_FRINGE (3, Qbottom, row->ends_at_zv_p);
+       }
+      else if (row->indicate_bottom_line_p)
+       {
+         if (EQ (arrow_bot, Qleft))
+           bn = LEFT_FRINGE (7, Qdown, 0);
+         else
+           bn = RIGHT_FRINGE (7, Qdown, 0);
+       }
+
+      if (bn != NO_FRINGE_BITMAP)
+       {
+         struct fringe_bitmap *fb = get_fringe_bitmap_data (bn);
+
+         if (fb->align == ALIGN_BITMAP_BOTTOM && fb->period == 0)
+           {
+             struct glyph_row *row1;
+             int bot_ind_min_y;
+
+             bot_ind_max_y = row->y + row->visible_height;
+             bot_ind_min_y = bot_ind_max_y - fb->height;
+             if (bot_ind_min_y < WINDOW_HEADER_LINE_HEIGHT (w))
+               bot_ind_min_y = WINDOW_HEADER_LINE_HEIGHT (w);
+
+             for (y = row->y, rn = bot_ind_rn - 1;
+                  y >= bot_ind_min_y && rn >= 0;
+                  y -= row1->height, rn--)
+               {
+                 if (top_ind_rn >= 0 && rn <= top_ind_rn)
+                   break;
+
+                 row1 = w->desired_matrix->rows + rn;
+                 if (!row1->enabled_p)
+                   row1 = w->current_matrix->rows + rn;
+
+                 row1->indicate_eob_p = row->indicate_eob_p;
+                 row1->indicate_bottom_line_p = row->indicate_bottom_line_p;
+               }
+           }
+       }
+    }
+
+  for (y = w->vscroll, rn = 0;
        y < yb && rn < nrows;
        y += row->height, rn++)
     {
       int left, right;
       unsigned left_face_id, right_face_id;
        y < yb && rn < nrows;
        y += row->height, rn++)
     {
       int left, right;
       unsigned left_face_id, right_face_id;
+      int left_offset, right_offset;
+      int periodic_p;
 
       row = w->desired_matrix->rows + rn;
       cur = w->current_matrix->rows + rn;
 
       row = w->desired_matrix->rows + rn;
       cur = w->current_matrix->rows + rn;
@@ -1074,6 +1186,8 @@ update_window_fringes (w, keep_current_p)
        row = cur;
 
       left_face_id = right_face_id = DEFAULT_FACE_ID;
        row = cur;
 
       left_face_id = right_face_id = DEFAULT_FACE_ID;
+      left_offset = right_offset = 0;
+      periodic_p = 0;
 
       /* Decide which bitmap to draw in the left fringe.  */
       if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
 
       /* Decide which bitmap to draw in the left fringe.  */
       if (WINDOW_LEFT_FRINGE_WIDTH (w) == 0)
@@ -1086,19 +1200,35 @@ update_window_fringes (w, keep_current_p)
       else if (row->truncated_on_left_p)
        left = LEFT_FRINGE(0, Qtruncation, 0);
       else if (row->indicate_bob_p && EQ (boundary_top, Qleft))
       else if (row->truncated_on_left_p)
        left = LEFT_FRINGE(0, Qtruncation, 0);
       else if (row->indicate_bob_p && EQ (boundary_top, Qleft))
-       left = ((row->indicate_eob_p && EQ (boundary_bot, Qleft))
-               ? LEFT_FRINGE (1, Qtop_bottom, row->ends_at_zv_p)
-               : LEFT_FRINGE (2, Qtop, 0));
+       {
+         left = ((row->indicate_eob_p && EQ (boundary_bot, Qleft))
+                 ? LEFT_FRINGE (1, Qtop_bottom, top_row_ends_at_zv_p)
+                 : LEFT_FRINGE (2, Qtop, 0));
+         if (top_ind_min_y >= 0)
+           left_offset = top_ind_min_y - row->y;
+       }
       else if (row->indicate_eob_p && EQ (boundary_bot, Qleft))
       else if (row->indicate_eob_p && EQ (boundary_bot, Qleft))
-       left = LEFT_FRINGE (3, Qbottom, row->ends_at_zv_p);
+       {
+         left = LEFT_FRINGE (3, Qbottom, bot_row_ends_at_zv_p);
+         if (bot_ind_max_y >= 0)
+           left_offset = bot_ind_max_y - (row->y + row->visible_height);
+       }
       else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
        left = LEFT_FRINGE (4, Qcontinuation, 0);
       else if (row->indicate_empty_line_p && EQ (empty_pos, Qleft))
        left = LEFT_FRINGE (5, Qempty_line, 0);
       else if (row->indicate_top_line_p && EQ (arrow_top, Qleft))
       else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
        left = LEFT_FRINGE (4, Qcontinuation, 0);
       else if (row->indicate_empty_line_p && EQ (empty_pos, Qleft))
        left = LEFT_FRINGE (5, Qempty_line, 0);
       else if (row->indicate_top_line_p && EQ (arrow_top, Qleft))
-       left = LEFT_FRINGE (6, Qup, 0);
+       {
+         left = LEFT_FRINGE (6, Qup, 0);
+         if (top_ind_min_y >= 0)
+           left_offset = top_ind_min_y - row->y;
+       }
       else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qleft))
       else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qleft))
-       left = LEFT_FRINGE (7, Qdown, 0);
+       {
+         left = LEFT_FRINGE (7, Qdown, 0);
+         if (bot_ind_max_y >= 0)
+           left_offset = bot_ind_max_y - (row->y + row->visible_height);
+       }
       else
        left = NO_FRINGE_BITMAP;
 
       else
        left = NO_FRINGE_BITMAP;
 
@@ -1113,22 +1243,41 @@ update_window_fringes (w, keep_current_p)
       else if (row->truncated_on_right_p)
        right = RIGHT_FRINGE (0, Qtruncation, 0);
       else if (row->indicate_bob_p && EQ (boundary_top, Qright))
       else if (row->truncated_on_right_p)
        right = RIGHT_FRINGE (0, Qtruncation, 0);
       else if (row->indicate_bob_p && EQ (boundary_top, Qright))
-       right = ((row->indicate_eob_p && EQ (boundary_bot, Qright))
-                ? RIGHT_FRINGE (1, Qtop_bottom, row->ends_at_zv_p)
-                : RIGHT_FRINGE (2, Qtop, 0));
+       {
+         right = ((row->indicate_eob_p && EQ (boundary_bot, Qright))
+                  ? RIGHT_FRINGE (1, Qtop_bottom, top_row_ends_at_zv_p)
+                  : RIGHT_FRINGE (2, Qtop, 0));
+         if (top_ind_min_y >= 0)
+           right_offset = top_ind_min_y - row->y;
+       }
       else if (row->indicate_eob_p && EQ (boundary_bot, Qright))
       else if (row->indicate_eob_p && EQ (boundary_bot, Qright))
-       right = RIGHT_FRINGE (3, Qbottom, row->ends_at_zv_p);
+       {
+         right = RIGHT_FRINGE (3, Qbottom, bot_row_ends_at_zv_p);
+         if (bot_ind_max_y >= 0)
+           right_offset = bot_ind_max_y - (row->y + row->visible_height);
+       }
       else if (row->continued_p)
        right = RIGHT_FRINGE (4, Qcontinuation, 0);
       else if (row->indicate_top_line_p && EQ (arrow_top, Qright))
       else if (row->continued_p)
        right = RIGHT_FRINGE (4, Qcontinuation, 0);
       else if (row->indicate_top_line_p && EQ (arrow_top, Qright))
-       right = RIGHT_FRINGE (6, Qup, 0);
+       {
+         right = RIGHT_FRINGE (6, Qup, 0);
+         if (top_ind_min_y >= 0)
+           right_offset = top_ind_min_y - row->y;
+       }
       else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qright))
       else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qright))
-       right = RIGHT_FRINGE (7, Qdown, 0);
+       {
+         right = RIGHT_FRINGE (7, Qdown, 0);
+         if (bot_ind_max_y >= 0)
+           right_offset = bot_ind_max_y - (row->y + row->visible_height);
+       }
       else if (row->indicate_empty_line_p && EQ (empty_pos, Qright))
        right = RIGHT_FRINGE (5, Qempty_line, 0);
       else
        right = NO_FRINGE_BITMAP;
 
       else if (row->indicate_empty_line_p && EQ (empty_pos, Qright))
        right = RIGHT_FRINGE (5, Qempty_line, 0);
       else
        right = NO_FRINGE_BITMAP;
 
+      periodic_p = (get_fringe_bitmap_data (left)->period != 0
+                   || get_fringe_bitmap_data (right)->period != 0);
+
       if (row->y != cur->y
          || row->visible_height != cur->visible_height
          || row->ends_at_zv_p != cur->ends_at_zv_p
       if (row->y != cur->y
          || row->visible_height != cur->visible_height
          || row->ends_at_zv_p != cur->ends_at_zv_p
@@ -1136,6 +1285,9 @@ update_window_fringes (w, keep_current_p)
          || right != cur->right_fringe_bitmap
          || left_face_id != cur->left_fringe_face_id
          || right_face_id != cur->right_fringe_face_id
          || right != cur->right_fringe_bitmap
          || left_face_id != cur->left_fringe_face_id
          || right_face_id != cur->right_fringe_face_id
+         || left_offset != cur->left_fringe_offset
+         || right_offset != cur->right_fringe_offset
+         || periodic_p != cur->fringe_bitmap_periodic_p
          || cur->redraw_fringe_bitmaps_p)
        {
          redraw_p = row->redraw_fringe_bitmaps_p = 1;
          || cur->redraw_fringe_bitmaps_p)
        {
          redraw_p = row->redraw_fringe_bitmaps_p = 1;
@@ -1146,6 +1298,9 @@ update_window_fringes (w, keep_current_p)
              cur->right_fringe_bitmap = right;
              cur->left_fringe_face_id = left_face_id;
              cur->right_fringe_face_id = right_face_id;
              cur->right_fringe_bitmap = right;
              cur->left_fringe_face_id = left_face_id;
              cur->right_fringe_face_id = right_face_id;
+             cur->left_fringe_offset = left_offset;
+             cur->right_fringe_offset = right_offset;
+             cur->fringe_bitmap_periodic_p = periodic_p;
            }
        }
 
            }
        }
 
@@ -1154,17 +1309,21 @@ update_window_fringes (w, keep_current_p)
 
       if (row->overlay_arrow_bitmap != cur->overlay_arrow_bitmap)
        {
 
       if (row->overlay_arrow_bitmap != cur->overlay_arrow_bitmap)
        {
-         redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1;
-         cur->overlay_arrow_bitmap = row->overlay_arrow_bitmap;
+         redraw_p = row->redraw_fringe_bitmaps_p = 1;
+         if (!keep_current_p)
+           {
+             cur->redraw_fringe_bitmaps_p = 1;
+             cur->overlay_arrow_bitmap = row->overlay_arrow_bitmap;
+           }
        }
 
       row->left_fringe_bitmap = left;
       row->right_fringe_bitmap = right;
       row->left_fringe_face_id = left_face_id;
       row->right_fringe_face_id = right_face_id;
        }
 
       row->left_fringe_bitmap = left;
       row->right_fringe_bitmap = right;
       row->left_fringe_face_id = left_face_id;
       row->right_fringe_face_id = right_face_id;
-
-      if (rn > 0 && row->redraw_fringe_bitmaps_p)
-       row[-1].redraw_fringe_bitmaps_p = cur[-1].redraw_fringe_bitmaps_p = 1;
+      row->left_fringe_offset = left_offset;
+      row->right_fringe_offset = right_offset;
+      row->fringe_bitmap_periodic_p = periodic_p;
     }
 
   return redraw_p && !keep_current_p;
     }
 
   return redraw_p && !keep_current_p;
@@ -1330,6 +1489,14 @@ If BITMAP overrides a standard fringe bitmap, the original bitmap is restored.
    On W32 and MAC (little endian), there's no need to do this.
 */
 
    On W32 and MAC (little endian), there's no need to do this.
 */
 
+#if defined (HAVE_X_WINDOWS)
+static const unsigned char swap_nibble[16] = {
+  0x0, 0x8, 0x4, 0xc,           /* 0000 1000 0100 1100 */
+  0x2, 0xa, 0x6, 0xe,           /* 0010 1010 0110 1110 */
+  0x1, 0x9, 0x5, 0xd,           /* 0001 1001 0101 1101 */
+  0x3, 0xb, 0x7, 0xf};          /* 0011 1011 0111 1111 */
+#endif                          /* HAVE_X_WINDOWS */
+
 void
 init_fringe_bitmap (which, fb, once_p)
      int which;
 void
 init_fringe_bitmap (which, fb, once_p)
      int which;
@@ -1339,11 +1506,6 @@ init_fringe_bitmap (which, fb, once_p)
   if (once_p || fb->dynamic)
     {
 #if defined (HAVE_X_WINDOWS)
   if (once_p || fb->dynamic)
     {
 #if defined (HAVE_X_WINDOWS)
-      static unsigned char swap_nibble[16]
-       = { 0x0, 0x8, 0x4, 0xc,    /* 0000 1000 0100 1100 */
-           0x2, 0xa, 0x6, 0xe,    /* 0010 1010 0110 1110 */
-           0x1, 0x9, 0x5, 0xd,    /* 0001 1001 0101 1101 */
-           0x3, 0xb, 0x7, 0xf };  /* 0011 1011 0111 1111 */
       unsigned short *bits = fb->bits;
       int j;
 
       unsigned short *bits = fb->bits;
       int j;
 
@@ -1368,20 +1530,15 @@ init_fringe_bitmap (which, fb, once_p)
                                   | (swap_nibble[(b>>4) & 0xf] << 8)
                                   | (swap_nibble[(b>>8) & 0xf] << 4)
                                   | (swap_nibble[(b>>12) & 0xf]));
                                   | (swap_nibble[(b>>4) & 0xf] << 8)
                                   | (swap_nibble[(b>>8) & 0xf] << 4)
                                   | (swap_nibble[(b>>12) & 0xf]));
-             *bits++ = (b >> (16 - fb->width));
+             b >>= (16 - fb->width);
+#ifdef WORDS_BIG_ENDIAN
+             b = ((b >> 8) | (b << 8));
+#endif
+             *bits++ = b;
            }
        }
 #endif /* HAVE_X_WINDOWS */
 
            }
        }
 #endif /* HAVE_X_WINDOWS */
 
-#if defined (MAC_OS) && defined (WORDS_BIG_ENDIAN)
-      unsigned short *bits = fb->bits;
-      int j;
-      for (j = 0; j < fb->height; j++)
-       {
-         unsigned short b = *bits;
-         *bits++ = ((b >> 8) & 0xff) | ((b & 0xff) << 8);
-       }
-#endif /* MAC_OS && WORDS_BIG_ENDIAN */
     }
 
   if (!once_p)
     }
 
   if (!once_p)
@@ -1410,7 +1567,7 @@ HEIGHT is height of bitmap.  If HEIGHT is nil, use length of BITS.
 WIDTH must be an integer between 1 and 16, or nil which defaults to 8.
 Optional fifth arg ALIGN may be one of `top', `center', or `bottom',
 indicating the positioning of the bitmap relative to the rows where it
 WIDTH must be an integer between 1 and 16, or nil which defaults to 8.
 Optional fifth arg ALIGN may be one of `top', `center', or `bottom',
 indicating the positioning of the bitmap relative to the rows where it
-is used; the default is to center the bitmap.  Fourth arg may also be a
+is used; the default is to center the bitmap.  Fifth arg may also be a
 list (ALIGN PERIODIC) where PERIODIC non-nil specifies that the bitmap
 should be repeated.
 If BITMAP already exists, the existing definition is replaced.  */)
 list (ALIGN PERIODIC) where PERIODIC non-nil specifies that the bitmap
 should be repeated.
 If BITMAP already exists, the existing definition is replaced.  */)
@@ -1427,7 +1584,7 @@ If BITMAP already exists, the existing definition is replaced.  */)
   if (STRINGP (bits))
     h = SCHARS (bits);
   else if (VECTORP (bits))
   if (STRINGP (bits))
     h = SCHARS (bits);
   else if (VECTORP (bits))
-    h = XVECTOR (bits)->size;
+    h = XVECTOR_SIZE (bits);
   else
     wrong_type_argument (Qsequencep, bits);
 
   else
     wrong_type_argument (Qsequencep, bits);
 
@@ -1560,7 +1717,7 @@ If FACE is nil, reset face to default fringe face.  */)
   if (!NILP (face))
     {
       face_id = lookup_derived_face (SELECTED_FRAME (), face,
   if (!NILP (face))
     {
       face_id = lookup_derived_face (SELECTED_FRAME (), face,
-                                    'A', FRINGE_FACE_ID, 1);
+                                    FRINGE_FACE_ID, 1);
       if (face_id < 0)
        error ("No such face");
     }
       if (face_id < 0)
        error ("No such face");
     }
@@ -1621,17 +1778,17 @@ Return nil if POS is not visible in WINDOW.  */)
 void
 syms_of_fringe ()
 {
 void
 syms_of_fringe ()
 {
-  Qtruncation = intern ("truncation");
+  Qtruncation = intern_c_string ("truncation");
   staticpro (&Qtruncation);
   staticpro (&Qtruncation);
-  Qcontinuation = intern ("continuation");
+  Qcontinuation = intern_c_string ("continuation");
   staticpro (&Qcontinuation);
   staticpro (&Qcontinuation);
-  Qoverlay_arrow = intern ("overlay-arrow");
+  Qoverlay_arrow = intern_c_string ("overlay-arrow");
   staticpro (&Qoverlay_arrow);
   staticpro (&Qoverlay_arrow);
-  Qempty_line = intern ("empty-line");
+  Qempty_line = intern_c_string ("empty-line");
   staticpro (&Qempty_line);
   staticpro (&Qempty_line);
-  Qtop_bottom = intern ("top-bottom");
+  Qtop_bottom = intern_c_string ("top-bottom");
   staticpro (&Qtop_bottom);
   staticpro (&Qtop_bottom);
-  Qhollow_small = intern ("hollow-small");
+  Qhollow_small = intern_c_string ("hollow-small");
   staticpro (&Qhollow_small);
 
   defsubr (&Sdestroy_fringe_bitmap);
   staticpro (&Qhollow_small);
 
   defsubr (&Sdestroy_fringe_bitmap);
@@ -1695,15 +1852,10 @@ init_fringe ()
     }
 }
 
     }
 }
 
-#if defined (HAVE_NTGUI) || defined (MAC_OS)
+#ifdef HAVE_NTGUI
 
 void
 
 void
-#ifdef HAVE_NTGUI
-w32_init_fringe (rif)
-#else  /* MAC_OS */
-mac_init_fringe (rif)
-#endif
-     struct redisplay_interface *rif;
+w32_init_fringe (struct redisplay_interface *rif)
 {
   int bt;
 
 {
   int bt;
 
@@ -1716,9 +1868,7 @@ mac_init_fringe (rif)
       rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width);
     }
 }
       rif->define_fringe_bitmap (bt, fb->bits, fb->height, fb->width);
     }
 }
-#endif
 
 
-#ifdef HAVE_NTGUI
 void
 w32_reset_fringes ()
 {
 void
 w32_reset_fringes ()
 {