(function*, case, ecase, typecase, etypecase, progv, lexical-let, lexical-let*,
[bpt/emacs.git] / src / fringe.c
index 0d05e15..08c034b 100644 (file)
@@ -31,12 +31,22 @@ Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
 
 
 #ifdef HAVE_WINDOW_SYSTEM
 
+extern Lisp_Object Qfringe;
 extern Lisp_Object Qtop, Qbottom, Qcenter;
 extern Lisp_Object Qtop, Qbottom, Qcenter;
+extern Lisp_Object Qup, Qdown, Qleft, Qright;
 
 /* Non-nil means that newline may flow into the right fringe.  */
 
 Lisp_Object Voverflow_newline_into_fringe;
 
 
 /* Non-nil means that newline may flow into the right fringe.  */
 
 Lisp_Object Voverflow_newline_into_fringe;
 
+/* List of known fringe bitmap symbols.
+
+   The fringe bitmap number is stored in the `fringe' property on
+   those symbols.  Names for the built-in bitmaps are installed by
+   loading fringe.el.
+ */
+
+Lisp_Object Vfringe_bitmaps;
 
 enum fringe_bitmap_type
 {
 
 enum fringe_bitmap_type
 {
@@ -435,23 +445,69 @@ struct fringe_bitmap standard_bitmaps[MAX_STANDARD_FRINGE_BITMAPS] =
   { FRBITS (zv_bits),                 8, 3, ALIGN_BITMAP_TOP,    0 },
 };
 
   { FRBITS (zv_bits),                 8, 3, ALIGN_BITMAP_TOP,    0 },
 };
 
-static struct fringe_bitmap *fringe_bitmaps[MAX_FRINGE_BITMAPS];
-static unsigned fringe_faces[MAX_FRINGE_BITMAPS];
+static struct fringe_bitmap **fringe_bitmaps;
+static Lisp_Object *fringe_faces;
+static int max_fringe_bitmaps;
 
 static int max_used_fringe_bitmap = MAX_STANDARD_FRINGE_BITMAPS;
 
 
 static int max_used_fringe_bitmap = MAX_STANDARD_FRINGE_BITMAPS;
 
-/* Return 1 if FRINGE_ID is a valid fringe bitmap id.  */
+
+/* Lookup bitmap number for symbol BITMAP.
+   Return 0 if not a bitmap.  */
 
 int
 
 int
-valid_fringe_bitmap_id_p (fringe_id)
-     int fringe_id;
+lookup_fringe_bitmap (bitmap)
+     Lisp_Object bitmap;
+{
+  int bn;
+
+  bitmap = Fget (bitmap, Qfringe);
+  if (!INTEGERP (bitmap))
+    return 0;
+
+  bn = XINT (bitmap);
+  if (bn > NO_FRINGE_BITMAP
+      && bn < max_used_fringe_bitmap
+      && (bn < MAX_STANDARD_FRINGE_BITMAPS
+         || fringe_bitmaps[bn] != NULL))
+    return bn;
+
+  return 0;
+}
+
+/* Get fringe bitmap name for bitmap number BN.
+
+   Found by traversing Vfringe_bitmaps comparing BN to the
+   fringe property for each symbol.
+
+   Return BN if not found in Vfringe_bitmaps.  */
+
+static Lisp_Object
+get_fringe_bitmap_name (bn)
+     int bn;
 {
 {
-  return (fringe_id >= NO_FRINGE_BITMAP
-         && fringe_id < max_used_fringe_bitmap
-         && (fringe_id < MAX_STANDARD_FRINGE_BITMAPS
-             || fringe_bitmaps[fringe_id] != NULL));
+  Lisp_Object bitmaps;
+  Lisp_Object num;
+
+  /* Zero means no bitmap -- return nil.  */
+  if (bn <= 0)
+    return Qnil;
+
+  bitmaps = Vfringe_bitmaps;
+  num = make_number (bn);
+
+  while (CONSP (bitmaps))
+    {
+      Lisp_Object bitmap = XCAR (bitmaps);
+      if (EQ (num, Fget (bitmap, Qfringe)))
+       return bitmap;
+      bitmaps = XCDR (bitmaps);
+    }
+
+  return num;
 }
 
 }
 
+
 /* 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
    determines the vertical position at which the bitmap has to be
 /* 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
    determines the vertical position at which the bitmap has to be
@@ -491,7 +547,14 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
     }
 
   if (face_id == DEFAULT_FACE_ID)
     }
 
   if (face_id == DEFAULT_FACE_ID)
-    face_id = fringe_faces[which];
+    {
+      Lisp_Object face;
+
+      if ((face = fringe_faces[which], NILP (face))
+         || (face_id = lookup_derived_face (f, face, 'A', FRINGE_FACE_ID, 0),
+             face_id < 0))
+       face_id = FRINGE_FACE_ID;
+    }
 
   fb = fringe_bitmaps[which];
   if (fb == NULL)
 
   fb = fringe_bitmaps[which];
   if (fb == NULL)
@@ -518,7 +581,8 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which)
 
   if (p.face == NULL)
     {
 
   if (p.face == NULL)
     {
-      /* Why does this happen?  ++kfs */
+      /* This could happen after clearing face cache.
+        But it shouldn't happen anymore.  ++kfs */
       return;
     }
 
       return;
     }
 
@@ -635,8 +699,11 @@ draw_fringe_bitmap (w, row, left_p)
 
   draw_fringe_bitmap_1 (w, row, left_p, overlay, NO_FRINGE_BITMAP);
 
 
   draw_fringe_bitmap_1 (w, row, left_p, overlay, NO_FRINGE_BITMAP);
 
-  if (left_p && row->overlay_arrow_p)
-    draw_fringe_bitmap_1 (w, row, 1, 1, OVERLAY_ARROW_BITMAP);
+  if (left_p && row->overlay_arrow_bitmap != NO_FRINGE_BITMAP)
+    draw_fringe_bitmap_1 (w, row, 1, 1,
+                         (row->overlay_arrow_bitmap < 0
+                          ? OVERLAY_ARROW_BITMAP
+                          : row->overlay_arrow_bitmap));
 }
 
 
 }
 
 
@@ -663,19 +730,35 @@ draw_row_fringe_bitmaps (w, row)
 }
 
 /* Draw the fringes of window W.  Only fringes for rows marked for
 }
 
 /* Draw the fringes of window W.  Only fringes for rows marked for
-   update in redraw_fringe_bitmaps_p are drawn.  */
+   update in redraw_fringe_bitmaps_p are drawn.
 
 
-void
-draw_window_fringes (w)
+   Return >0 if left or right fringe was redrawn in any way.
+
+   If NO_FRINGE is non-zero, also return >0 if either fringe has zero width.
+
+   A return value >0 indicates that the vertical line between windows
+   needs update (as it may be drawn in the fringe).
+*/
+
+int
+draw_window_fringes (w, no_fringe)
      struct window *w;
      struct window *w;
+     int no_fringe;
 {
   struct glyph_row *row;
   int yb = window_text_bottom_y (w);
   int nrows = w->current_matrix->nrows;
   int y = 0, rn;
 {
   struct glyph_row *row;
   int yb = window_text_bottom_y (w);
   int nrows = w->current_matrix->nrows;
   int y = 0, rn;
+  int updated = 0;
 
   if (w->pseudo_window_p)
 
   if (w->pseudo_window_p)
-    return;
+    return 0;
+
+  /* Must draw line if no fringe */
+  if (no_fringe
+      && (WINDOW_LEFT_FRINGE_WIDTH (w) == 0
+         || WINDOW_RIGHT_FRINGE_WIDTH (w) == 0))
+    updated++;
 
   for (y = 0, rn = 0, row = w->current_matrix->rows;
        y < yb && rn < nrows;
 
   for (y = 0, rn = 0, row = w->current_matrix->rows;
        y < yb && rn < nrows;
@@ -685,7 +768,10 @@ draw_window_fringes (w)
        continue;
       draw_row_fringe_bitmaps (w, row);
       row->redraw_fringe_bitmaps_p = 0;
        continue;
       draw_row_fringe_bitmaps (w, row);
       row->redraw_fringe_bitmaps_p = 0;
+      updated++;
     }
     }
+
+  return updated;
 }
 
 
 }
 
 
@@ -703,9 +789,10 @@ update_window_fringes (w, force_p)
   int rn, nrows = w->current_matrix->nrows;
   int y;
   int redraw_p = 0;
   int rn, nrows = w->current_matrix->nrows;
   int y;
   int redraw_p = 0;
-  Lisp_Object ind;
-  int boundary_pos = 0, arrow_pos = 0;
-  int empty_pos = 0;
+  Lisp_Object boundary_top = Qnil, boundary_bot = Qnil;
+  Lisp_Object arrow_top = Qnil, arrow_bot = Qnil;
+  Lisp_Object empty_pos;
+  Lisp_Object ind = Qnil;
 
   if (w->pseudo_window_p)
     return 0;
 
   if (w->pseudo_window_p)
     return 0;
@@ -713,23 +800,30 @@ update_window_fringes (w, force_p)
   if (!MINI_WINDOW_P (w)
       && (ind = XBUFFER (w->buffer)->indicate_buffer_boundaries, !NILP (ind)))
     {
   if (!MINI_WINDOW_P (w)
       && (ind = XBUFFER (w->buffer)->indicate_buffer_boundaries, !NILP (ind)))
     {
-      int do_eob = 1, do_bob = 1;
-      Lisp_Object arrows;
-
-      if (CONSP (ind))
-       arrows = XCDR (ind), ind = XCAR (ind);
+      if (EQ (ind, Qleft) || EQ (ind, Qright))
+       boundary_top = boundary_bot = arrow_top = arrow_bot = ind;
+      else if (CONSP (ind) && CONSP (XCAR (ind)))
+       {
+         Lisp_Object pos;
+         if (pos = Fassq (Qt, ind), !NILP (pos))
+           boundary_top = boundary_bot = arrow_top = arrow_bot = XCDR (pos);
+         if (pos = Fassq (Qtop, ind), !NILP (pos))
+           boundary_top = XCDR (pos);
+         if (pos = Fassq (Qbottom, ind), !NILP (pos))
+           boundary_bot = XCDR (pos);
+         if (pos = Fassq (Qup, ind), !NILP (pos))
+           arrow_top = XCDR (pos);
+         if (pos = Fassq (Qdown, ind), !NILP (pos))
+           arrow_bot = XCDR (pos);
+       }
       else
       else
-       arrows = ind;
-
-      if (EQ (ind, Qleft))
-       boundary_pos = -1;
-      else if (EQ (ind, Qright))
-       boundary_pos = 1;
+       /* Anything else means boundary on left and no arrows.  */
+       boundary_top = boundary_bot = Qleft;
+    }
 
 
-      if (EQ (arrows, Qleft))
-       arrow_pos = -1;
-      else if (EQ (arrows, Qright))
-       arrow_pos = 1;
+  if (!NILP (ind))
+    {
+      int done_top = 0, done_bot = 0;
 
       for (y = 0, rn = 0;
           y < yb && rn < nrows;
 
       for (y = 0, rn = 0;
           y < yb && rn < nrows;
@@ -737,7 +831,7 @@ update_window_fringes (w, force_p)
        {
          unsigned indicate_bob_p, indicate_top_line_p;
          unsigned indicate_eob_p, indicate_bottom_line_p;
        {
          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;
@@ -746,23 +840,29 @@ update_window_fringes (w, force_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;
          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;
 
          row->indicate_bob_p = row->indicate_top_line_p = 0;
          row->indicate_eob_p = row->indicate_bottom_line_p = 0;
 
-         if (!NILP (ind)
-             && MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer)))
-           row->indicate_bob_p = do_bob, do_bob = 0;
-         else if (!NILP (arrows)
-                  && (WINDOW_WANTS_HEADER_LINE_P (w) ? 1 : 0) == rn)
-           row->indicate_top_line_p = 1;
-
-         if (!NILP (ind)
-             && MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer)))
-           row->indicate_eob_p = do_eob, do_eob = 0;
-         else if (!NILP (arrows)
-                  && y + row->height >= yb)
-           row->indicate_bottom_line_p = 1;
+         if (!row->mode_line_p)
+           {
+             if (!done_top)
+               {
+                 if (MATRIX_ROW_START_CHARPOS (row) <= BUF_BEGV (XBUFFER (w->buffer)))
+                   row->indicate_bob_p = !NILP (boundary_top);
+                 else
+                   row->indicate_top_line_p = !NILP (arrow_top);
+                 done_top = 1;
+               }
+
+             if (!done_bot)
+               {
+                 if (MATRIX_ROW_END_CHARPOS (row) >= BUF_ZV (XBUFFER (w->buffer)))
+                   row->indicate_eob_p = !NILP (boundary_bot), done_bot = 1;
+                 else if (y + row->height >= yb)
+                   row->indicate_bottom_line_p = !NILP (arrow_bot), done_bot = 1;
+               }
+           }
 
          if (indicate_bob_p != row->indicate_bob_p
              || indicate_top_line_p != row->indicate_top_line_p
 
          if (indicate_bob_p != row->indicate_bob_p
              || indicate_top_line_p != row->indicate_top_line_p
@@ -772,10 +872,9 @@ update_window_fringes (w, force_p)
        }
     }
 
        }
     }
 
-  if (EQ (XBUFFER (w->buffer)->indicate_empty_lines, Qright))
-    empty_pos = 1;
-  else if (EQ (XBUFFER (w->buffer)->indicate_empty_lines, Qleft))
-    empty_pos = -1;
+  empty_pos = XBUFFER (w->buffer)->indicate_empty_lines;
+  if (!NILP (empty_pos) && !EQ (empty_pos, Qright))
+    empty_pos = WINDOW_LEFT_FRINGE_WIDTH (w) == 0 ? Qright : Qleft;
 
   for (y = 0, rn = 0;
        y < yb && rn < nrows;
 
   for (y = 0, rn = 0;
        y < yb && rn < nrows;
@@ -799,24 +898,20 @@ update_window_fringes (w, force_p)
          left = row->left_user_fringe_bitmap;
          left_face_id = row->left_user_fringe_face_id;
        }
          left = row->left_user_fringe_bitmap;
          left_face_id = row->left_user_fringe_face_id;
        }
-#if 0  /* this is now done via an overlay */
-      else if (row->overlay_arrow_p)
-       left = OVERLAY_ARROW_BITMAP;
-#endif
-      else if (row->indicate_bob_p && boundary_pos <= 0)
-       left = ((row->indicate_eob_p && boundary_pos < 0)
-               ? LEFT_BRACKET_BITMAP : TOP_LEFT_ANGLE_BITMAP);
-      else if (row->indicate_eob_p && boundary_pos < 0)
-       left = BOTTOM_LEFT_ANGLE_BITMAP;
       else if (row->truncated_on_left_p)
        left = LEFT_TRUNCATION_BITMAP;
       else if (row->truncated_on_left_p)
        left = LEFT_TRUNCATION_BITMAP;
+      else if (row->indicate_bob_p && EQ (boundary_top, Qleft))
+       left = ((row->indicate_eob_p && EQ (boundary_bot, Qleft))
+               ? LEFT_BRACKET_BITMAP : TOP_LEFT_ANGLE_BITMAP);
+      else if (row->indicate_eob_p && EQ (boundary_bot, Qleft))
+       left = BOTTOM_LEFT_ANGLE_BITMAP;
       else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
        left = CONTINUATION_LINE_BITMAP;
       else if (MATRIX_ROW_CONTINUATION_LINE_P (row))
        left = CONTINUATION_LINE_BITMAP;
-      else if (row->indicate_empty_line_p && empty_pos <= 0)
+      else if (row->indicate_empty_line_p && EQ (empty_pos, Qleft))
        left = ZV_LINE_BITMAP;
        left = ZV_LINE_BITMAP;
-      else if (row->indicate_top_line_p && arrow_pos <= 0)
+      else if (row->indicate_top_line_p && EQ (arrow_top, Qleft))
        left = UP_ARROW_BITMAP;
        left = UP_ARROW_BITMAP;
-      else if (row->indicate_bottom_line_p && arrow_pos < 0)
+      else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qleft))
        left = DOWN_ARROW_BITMAP;
       else
        left = NO_FRINGE_BITMAP;
        left = DOWN_ARROW_BITMAP;
       else
        left = NO_FRINGE_BITMAP;
@@ -829,22 +924,20 @@ update_window_fringes (w, force_p)
          right = row->right_user_fringe_bitmap;
          right_face_id = row->right_user_fringe_face_id;
        }
          right = row->right_user_fringe_bitmap;
          right_face_id = row->right_user_fringe_face_id;
        }
-      else if (row->indicate_bob_p && boundary_pos > 0)
-       right = ((row->indicate_eob_p && boundary_pos >= 0)
-                ? RIGHT_BRACKET_BITMAP : TOP_RIGHT_ANGLE_BITMAP);
-      else if (row->indicate_eob_p && boundary_pos >= 0)
-       right = BOTTOM_RIGHT_ANGLE_BITMAP;
       else if (row->truncated_on_right_p)
        right = RIGHT_TRUNCATION_BITMAP;
       else if (row->truncated_on_right_p)
        right = RIGHT_TRUNCATION_BITMAP;
+      else if (row->indicate_bob_p && EQ (boundary_top, Qright))
+       right = ((row->indicate_eob_p && EQ (boundary_bot, Qright))
+                ? RIGHT_BRACKET_BITMAP : TOP_RIGHT_ANGLE_BITMAP);
+      else if (row->indicate_eob_p && EQ (boundary_bot, Qright))
+       right = BOTTOM_RIGHT_ANGLE_BITMAP;
       else if (row->continued_p)
        right = CONTINUED_LINE_BITMAP;
       else if (row->continued_p)
        right = CONTINUED_LINE_BITMAP;
-      else if (row->indicate_top_line_p && arrow_pos > 0)
+      else if (row->indicate_top_line_p && EQ (arrow_top, Qright))
        right = UP_ARROW_BITMAP;
        right = UP_ARROW_BITMAP;
-      else if (row->indicate_bottom_line_p && arrow_pos >= 0)
+      else if (row->indicate_bottom_line_p && EQ (arrow_bot, Qright))
        right = DOWN_ARROW_BITMAP;
        right = DOWN_ARROW_BITMAP;
-      else if (row->indicate_empty_line_p
-              && (empty_pos > 0
-                  || (WINDOW_LEFT_FRINGE_WIDTH (w) == 0 && empty_pos == 0)))
+      else if (row->indicate_empty_line_p && EQ (empty_pos, Qright))
        right = ZV_LINE_BITMAP;
       else
        right = NO_FRINGE_BITMAP;
        right = ZV_LINE_BITMAP;
       else
        right = NO_FRINGE_BITMAP;
@@ -852,6 +945,7 @@ update_window_fringes (w, force_p)
       if (force_p
          || row->y != cur->y
          || row->visible_height != cur->visible_height
       if (force_p
          || row->y != cur->y
          || row->visible_height != cur->visible_height
+         || row->ends_at_zv_p != cur->ends_at_zv_p
          || left != cur->left_fringe_bitmap
          || right != cur->right_fringe_bitmap
          || left_face_id != cur->left_fringe_face_id
          || left != cur->left_fringe_bitmap
          || right != cur->right_fringe_bitmap
          || left_face_id != cur->left_fringe_face_id
@@ -865,23 +959,26 @@ update_window_fringes (w, force_p)
          cur->right_fringe_face_id = right_face_id;
        }
 
          cur->right_fringe_face_id = right_face_id;
        }
 
-      if (row->overlay_arrow_p != cur->overlay_arrow_p)
+      if (row->overlay_arrow_bitmap != cur->overlay_arrow_bitmap)
        {
          redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1;
        {
          redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1;
-         cur->overlay_arrow_p = row->overlay_arrow_p;
+         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;
     }
 
   return redraw_p;
 }
 
 
     }
 
   return redraw_p;
 }
 
 
-/* Compute actual fringe widths for frame F.  
+/* Compute actual fringe widths for frame F.
 
    If REDRAW is 1, redraw F if the fringe settings was actually
    modified and F is visible.
 
    If REDRAW is 1, redraw F if the fringe settings was actually
    modified and F is visible.
@@ -891,11 +988,7 @@ update_window_fringes (w, force_p)
    Typically, we add an equal amount (+/- 1 pixel) to each fringe,
    but a negative width value is taken literally (after negating it).
 
    Typically, we add an equal amount (+/- 1 pixel) to each fringe,
    but a negative width value is taken literally (after negating it).
 
-   We never make the fringes narrower than specified.  It is planned
-   to make fringe bitmaps customizable and expandable, and at that
-   time, the user will typically specify the minimum number of pixels
-   needed for his bitmaps, so we shouldn't select anything less than
-   what is specified.
+   We never make the fringes narrower than specified.
 */
 
 void
 */
 
 void
@@ -979,26 +1072,21 @@ compute_fringe_widths (f, redraw)
       redraw_frame (f);
 }
 
       redraw_frame (f);
 }
 
-DEFUN ("destroy-fringe-bitmap", Fdestroy_fringe_bitmap, Sdestroy_fringe_bitmap,
-       1, 1, 0,
-       doc: /* Destroy fringe bitmap WHICH.
-If WHICH overrides a standard fringe bitmap, the original bitmap is restored.  */)
-  (which)
-     Lisp_Object which;
+
+/* Free resources used by a user-defined bitmap.  */
+
+void
+destroy_fringe_bitmap (n)
+     int n;
 {
 {
-  int n;
   struct fringe_bitmap **fbp;
 
   struct fringe_bitmap **fbp;
 
-  CHECK_NUMBER (which);
-  if (n = XINT (which), n >= max_used_fringe_bitmap)
-    return Qnil;
-
-  fringe_faces[n] = FRINGE_FACE_ID;
+  fringe_faces[n] = Qnil;
 
   fbp = &fringe_bitmaps[n];
   if (*fbp && (*fbp)->dynamic)
     {
 
   fbp = &fringe_bitmaps[n];
   if (*fbp && (*fbp)->dynamic)
     {
-      if (rif->destroy_fringe_bitmap)
+      if (rif && rif->destroy_fringe_bitmap)
        rif->destroy_fringe_bitmap (n);
       xfree (*fbp);
       *fbp = NULL;
        rif->destroy_fringe_bitmap (n);
       xfree (*fbp);
       *fbp = NULL;
@@ -1007,6 +1095,31 @@ If WHICH overrides a standard fringe bitmap, the original bitmap is restored.  *
   while (max_used_fringe_bitmap > MAX_STANDARD_FRINGE_BITMAPS
         && fringe_bitmaps[max_used_fringe_bitmap - 1] == NULL)
     max_used_fringe_bitmap--;
   while (max_used_fringe_bitmap > MAX_STANDARD_FRINGE_BITMAPS
         && fringe_bitmaps[max_used_fringe_bitmap - 1] == NULL)
     max_used_fringe_bitmap--;
+}
+
+
+DEFUN ("destroy-fringe-bitmap", Fdestroy_fringe_bitmap, Sdestroy_fringe_bitmap,
+       1, 1, 0,
+       doc: /* Destroy fringe bitmap BITMAP.
+If BITMAP overrides a standard fringe bitmap, the original bitmap is restored.  */)
+  (bitmap)
+     Lisp_Object bitmap;
+{
+  int n;
+
+  CHECK_SYMBOL (bitmap);
+  n = lookup_fringe_bitmap (bitmap);
+  if (!n)
+    return Qnil;
+
+  destroy_fringe_bitmap (n);
+
+  if (n >= MAX_STANDARD_FRINGE_BITMAPS)
+    {
+      Vfringe_bitmaps = Fdelq (bitmap, Vfringe_bitmaps);
+      /* It would be better to remove the fringe property.  */
+      Fput (bitmap, Qfringe, Qnil);
+    }
 
   return Qnil;
 }
 
   return Qnil;
 }
@@ -1017,7 +1130,9 @@ If WHICH overrides a standard fringe bitmap, the original bitmap is restored.  *
    On X, we bit-swap the built-in bitmaps and reduce bitmap
    from short to char array if width is <= 8 bits.
 
    On X, we bit-swap the built-in bitmaps and reduce bitmap
    from short to char array if width is <= 8 bits.
 
-   On W32 and MAC, there's no need to do this.
+   On MAC with big-endian CPU, we need to byte-swap each short.
+
+   On W32 and MAC (little endian), there's no need to do this.
 */
 
 void
 */
 
 void
@@ -1033,7 +1148,7 @@ init_fringe_bitmap (which, fb, once_p)
        = { 0x0, 0x8, 0x4, 0xc,    /* 0000 1000 0100 1100 */
            0x2, 0xa, 0x6, 0xe,    /* 0010 1010 0110 1110 */
            0x1, 0x9, 0x5, 0xd,    /* 0001 1001 0101 1101 */
        = { 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 */
+           0x3, 0xb, 0x7, 0xf };  /* 0011 1011 0111 1111 */
       unsigned short *bits = fb->bits;
       int j;
 
       unsigned short *bits = fb->bits;
       int j;
 
@@ -1061,14 +1176,24 @@ init_fringe_bitmap (which, fb, once_p)
              *bits++ = (b >> (16 - fb->width));
            }
        }
              *bits++ = (b >> (16 - fb->width));
            }
        }
-#endif
+#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)
     {
-      Fdestroy_fringe_bitmap (make_number (which));
+      destroy_fringe_bitmap (which);
 
 
-      if (rif->define_fringe_bitmap)
+      if (rif && rif->define_fringe_bitmap)
        rif->define_fringe_bitmap (which, fb->bits, fb->height, fb->width);
 
       fringe_bitmaps[which] = fb;
        rif->define_fringe_bitmap (which, fb->bits, fb->height, fb->width);
 
       fringe_bitmaps[which] = fb;
@@ -1079,46 +1204,48 @@ init_fringe_bitmap (which, fb, once_p)
 
 
 DEFUN ("define-fringe-bitmap", Fdefine_fringe_bitmap, Sdefine_fringe_bitmap,
 
 
 DEFUN ("define-fringe-bitmap", Fdefine_fringe_bitmap, Sdefine_fringe_bitmap,
-       1, 5, 0,
-       doc: /* Define a fringe bitmap from BITS of height HEIGHT and width WIDTH.
+       2, 5, 0,
+       doc: /* Define fringe bitmap BITMAP from BITS of size HEIGHT x WIDTH.
+BITMAP is a symbol or string naming the new fringe bitmap.
 BITS is either a string or a vector of integers.
 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.
 BITS is either a string or a vector of integers.
 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 forth arg ALIGN may be one of `top', `center', or `bottom',
+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
 list (ALIGN PERIODIC) where PERIODIC non-nil specifies that the bitmap
 should be repeated.
 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
 list (ALIGN PERIODIC) where PERIODIC non-nil specifies that the bitmap
 should be repeated.
-Optional fifth argument WHICH is bitmap number to redefine.
-Return new bitmap number, or nil of no more free bitmap slots.  */)
-  (bits, height, width, align, which)
-     Lisp_Object bits, height, width, align, which;
+If BITMAP already exists, the existing definition is replaced.  */)
+  (bitmap, bits, height, width, align)
+     Lisp_Object bitmap, bits, height, width, align;
 {
 {
-  Lisp_Object len;
   int n, h, i, j;
   unsigned short *b;
   struct fringe_bitmap fb, *xfb;
   int fill1 = 0, fill2 = 0;
 
   int n, h, i, j;
   unsigned short *b;
   struct fringe_bitmap fb, *xfb;
   int fill1 = 0, fill2 = 0;
 
-  if (!STRINGP (bits) && !VECTORP (bits))
-    bits = wrong_type_argument (Qstringp, bits);
+  CHECK_SYMBOL (bitmap);
 
 
-  len = Flength (bits);
+  if (STRINGP (bits))
+    h = SCHARS (bits);
+  else if (VECTORP (bits))
+    h = XVECTOR (bits)->size;
+  else
+    bits = wrong_type_argument (Qsequencep, bits);
 
   if (NILP (height))
 
   if (NILP (height))
-    h = fb.height = XINT (len);
+    fb.height = h;
   else
     {
       CHECK_NUMBER (height);
       fb.height = min (XINT (height), 255);
   else
     {
       CHECK_NUMBER (height);
       fb.height = min (XINT (height), 255);
-      if (fb.height > XINT (len))
+      if (fb.height > h)
        {
        {
-         h = XINT (len);
          fill1 = (fb.height - h) / 2;
          fill2 = fb.height - h - fill1;
        }
     }
          fill1 = (fb.height - h) / 2;
          fill2 = fb.height - h - fill1;
        }
     }
-  
+
   if (NILP (width))
     fb.width = 8;
   else
   if (NILP (width))
     fb.width = 8;
   else
@@ -1151,35 +1278,49 @@ Return new bitmap number, or nil of no more free bitmap slots.  */)
   else if (!NILP (align) && !EQ (align, Qcenter))
     error ("Bad align argument");
 
   else if (!NILP (align) && !EQ (align, Qcenter))
     error ("Bad align argument");
 
-  if (NILP (which))
+  n = lookup_fringe_bitmap (bitmap);
+  if (!n)
     {
     {
-      if (max_used_fringe_bitmap < MAX_FRINGE_BITMAPS)
-       n = make_number (max_used_fringe_bitmap++);
+      if (max_used_fringe_bitmap < max_fringe_bitmaps)
+       n = max_used_fringe_bitmap++;
       else
        {
          for (n = MAX_STANDARD_FRINGE_BITMAPS;
       else
        {
          for (n = MAX_STANDARD_FRINGE_BITMAPS;
-              n < MAX_FRINGE_BITMAPS;
+              n < max_fringe_bitmaps;
               n++)
            if (fringe_bitmaps[n] == NULL)
              break;
               n++)
            if (fringe_bitmaps[n] == NULL)
              break;
-         if (n == MAX_FRINGE_BITMAPS)
-           return Qnil;
+
+         if (n == max_fringe_bitmaps)
+           {
+             if ((max_fringe_bitmaps + 20) > MAX_FRINGE_BITMAPS)
+               error ("No free fringe bitmap slots");
+
+             i = max_fringe_bitmaps;
+             max_fringe_bitmaps += 20;
+             fringe_bitmaps
+               = ((struct fringe_bitmap **)
+                  xrealloc (fringe_bitmaps, max_fringe_bitmaps * sizeof (struct fringe_bitmap *)));
+             fringe_faces
+               = (Lisp_Object *) xrealloc (fringe_faces, max_fringe_bitmaps * sizeof (Lisp_Object));
+
+             for (; i < max_fringe_bitmaps; i++)
+               {
+                 fringe_bitmaps[i] = NULL;
+                 fringe_faces[i] = Qnil;
+               }
+           }
        }
        }
-      which = make_number (n);
-    }
-  else
-    {
-      CHECK_NUMBER (which);
-      n = XINT (which);
-      if (n <= NO_FRINGE_BITMAP || n >= MAX_FRINGE_BITMAPS)
-       error ("Invalid fringe bitmap number");
+
+      Vfringe_bitmaps = Fcons (bitmap, Vfringe_bitmaps);
+      Fput (bitmap, Qfringe, make_number (n));
     }
 
   fb.dynamic = 1;
 
     }
 
   fb.dynamic = 1;
 
-  xfb = (struct fringe_bitmap *)xmalloc (sizeof fb
-                                        + fb.height * BYTES_PER_BITMAP_ROW);
-  fb.bits = b = (unsigned short *)(xfb+1);
+  xfb = (struct fringe_bitmap *) xmalloc (sizeof fb
+                                         + fb.height * BYTES_PER_BITMAP_ROW);
+  fb.bits = b = (unsigned short *) (xfb + 1);
   bzero (b, fb.height);
 
   j = 0;
   bzero (b, fb.height);
 
   j = 0;
@@ -1187,7 +1328,7 @@ Return new bitmap number, or nil of no more free bitmap slots.  */)
     {
       for (i = 0; i < fill1 && j < fb.height; i++)
        b[j++] = 0;
     {
       for (i = 0; i < fill1 && j < fb.height; i++)
        b[j++] = 0;
-      for (i = 0; i < h & j < fb.height; i++)
+      for (i = 0; i < h && j < fb.height; i++)
        {
          Lisp_Object elt = Faref (bits, make_number (i));
          b[j++] = NUMBERP (elt) ? XINT (elt) : 0;
        {
          Lisp_Object elt = Faref (bits, make_number (i));
          b[j++] = NUMBERP (elt) ? XINT (elt) : 0;
@@ -1200,47 +1341,50 @@ Return new bitmap number, or nil of no more free bitmap slots.  */)
 
   init_fringe_bitmap (n, xfb, 0);
 
 
   init_fringe_bitmap (n, xfb, 0);
 
-  return which;
+  return bitmap;
 }
 
 DEFUN ("set-fringe-bitmap-face", Fset_fringe_bitmap_face, Sset_fringe_bitmap_face,
        1, 2, 0,
 }
 
 DEFUN ("set-fringe-bitmap-face", Fset_fringe_bitmap_face, Sset_fringe_bitmap_face,
        1, 2, 0,
-       doc:  /* Set face for fringe bitmap FRINGE-ID to FACE.
+       doc: /* Set face for fringe bitmap BITMAP to FACE.
 If FACE is nil, reset face to default fringe face.  */)
 If FACE is nil, reset face to default fringe face.  */)
-  (fringe_id, face)
-     Lisp_Object fringe_id, face;
+  (bitmap, face)
+     Lisp_Object bitmap, face;
 {
 {
+  int n;
   int face_id;
 
   int face_id;
 
-  CHECK_NUMBER (fringe_id);
-  if (!valid_fringe_bitmap_id_p (XINT (fringe_id)))
-    error ("Invalid fringe id");
+  CHECK_SYMBOL (bitmap);
+  n = lookup_fringe_bitmap (bitmap);
+  if (!n)
+    error ("Undefined fringe bitmap");
 
   if (!NILP (face))
     {
 
   if (!NILP (face))
     {
-      face_id = lookup_named_face (SELECTED_FRAME (), face, 'A');
+      face_id = lookup_derived_face (SELECTED_FRAME (), face,
+                                    'A', FRINGE_FACE_ID, 1);
       if (face_id < 0)
        error ("No such face");
     }
       if (face_id < 0)
        error ("No such face");
     }
-  else
-    face_id = FRINGE_FACE_ID;
 
 
-  fringe_faces [XINT (fringe_id)] = face_id;
+  fringe_faces[n] = face;
 
   return Qnil;
 }
 
 DEFUN ("fringe-bitmaps-at-pos", Ffringe_bitmaps_at_pos, Sfringe_bitmaps_at_pos,
        0, 2, 0,
 
   return Qnil;
 }
 
 DEFUN ("fringe-bitmaps-at-pos", Ffringe_bitmaps_at_pos, Sfringe_bitmaps_at_pos,
        0, 2, 0,
-       doc:  /* Return fringe bitmaps of row containing position POS in window WINDOW.
+       doc: /* Return fringe bitmaps of row containing position POS in window WINDOW.
 If WINDOW is nil, use selected window.  If POS is nil, use value of point
 If WINDOW is nil, use selected window.  If POS is nil, use value of point
-in that window.  Return value is a cons (LEFT . RIGHT) where LEFT and RIGHT
-are the fringe bitmap numbers for the bitmaps in the left and right fringe,
-resp.  Return nil if POS is not visible in WINDOW.  */)
+in that window.  Return value is a list (LEFT RIGHT OV), where LEFT
+is the symbol for the bitmap in the left fringe (or nil if no bitmap),
+RIGHT is similar for the right fringe, and OV is non-nil if there is an
+overlay arrow in the left fringe.
+Return nil if POS is not visible in WINDOW.  */)
   (pos, window)
   (pos, window)
+     Lisp_Object pos, window;
 {
   struct window *w;
 {
   struct window *w;
-  struct buffer *old_buffer = NULL;
   struct glyph_row *row;
   int textpos;
 
   struct glyph_row *row;
   int textpos;
 
@@ -1262,8 +1406,11 @@ resp.  Return nil if POS is not visible in WINDOW.  */)
   row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
   row = row_containing_pos (w, textpos, row, NULL, 0);
   if (row)
   row = MATRIX_FIRST_TEXT_ROW (w->current_matrix);
   row = row_containing_pos (w, textpos, row, NULL, 0);
   if (row)
-    return Fcons (make_number (row->left_fringe_bitmap),
-                 make_number (row->right_fringe_bitmap));
+    return list3 (get_fringe_bitmap_name (row->left_fringe_bitmap),
+                 get_fringe_bitmap_name (row->right_fringe_bitmap),
+                 (row->overlay_arrow_bitmap == 0 ? Qnil
+                  : row->overlay_arrow_bitmap < 0 ? Qt
+                  : get_fringe_bitmap_name (row->overlay_arrow_bitmap)));
   else
     return Qnil;
 }
   else
     return Qnil;
 }
@@ -1276,7 +1423,6 @@ resp.  Return nil if POS is not visible in WINDOW.  */)
 void
 syms_of_fringe ()
 {
 void
 syms_of_fringe ()
 {
-
   defsubr (&Sdestroy_fringe_bitmap);
   defsubr (&Sdefine_fringe_bitmap);
   defsubr (&Sfringe_bitmaps_at_pos);
   defsubr (&Sdestroy_fringe_bitmap);
   defsubr (&Sdefine_fringe_bitmap);
   defsubr (&Sfringe_bitmaps_at_pos);
@@ -1291,6 +1437,22 @@ is at the final newline, the cursor is shown in the right fringe.
 If nil, also continue lines which are exactly as wide as the window.  */);
   Voverflow_newline_into_fringe = Qt;
 
 If nil, also continue lines which are exactly as wide as the window.  */);
   Voverflow_newline_into_fringe = Qt;
 
+  DEFVAR_LISP ("fringe-bitmaps", &Vfringe_bitmaps,
+    doc: /* List of fringe bitmap symbols.
+You must (require 'fringe) to use fringe bitmap symbols in your programs." */);
+  Vfringe_bitmaps = Qnil;
+}
+
+/* Garbage collection hook */
+
+void
+mark_fringe_data ()
+{
+  int i;
+
+  for (i = 0; i < max_fringe_bitmaps; i++)
+    if (!NILP (fringe_faces[i]))
+      mark_object (fringe_faces[i]);
 }
 
 /* Initialize this module when Emacs starts.  */
 }
 
 /* Initialize this module when Emacs starts.  */
@@ -1309,9 +1471,18 @@ init_fringe ()
 {
   int i;
 
 {
   int i;
 
-  bzero (fringe_bitmaps, sizeof fringe_bitmaps);
-  for (i = 0; i < MAX_FRINGE_BITMAPS; i++)
-    fringe_faces[i] = FRINGE_FACE_ID;
+  max_fringe_bitmaps = MAX_STANDARD_FRINGE_BITMAPS + 20;
+
+  fringe_bitmaps
+    = (struct fringe_bitmap **) xmalloc (max_fringe_bitmaps * sizeof (struct fringe_bitmap *));
+  fringe_faces
+    = (Lisp_Object *) xmalloc (max_fringe_bitmaps * sizeof (Lisp_Object));
+
+  for (i = 0; i < max_fringe_bitmaps; i++)
+    {
+      fringe_bitmaps[i] = NULL;
+      fringe_faces[i] = Qnil;
+    }
 }
 
 #ifdef HAVE_NTGUI
 }
 
 #ifdef HAVE_NTGUI
@@ -1321,6 +1492,9 @@ w32_init_fringe ()
 {
   enum fringe_bitmap_type bt;
 
 {
   enum fringe_bitmap_type bt;
 
+  if (!rif)
+    return;
+
   for (bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++)
     {
       struct fringe_bitmap *fb = &standard_bitmaps[bt];
   for (bt = NO_FRINGE_BITMAP + 1; bt < MAX_STANDARD_FRINGE_BITMAPS; bt++)
     {
       struct fringe_bitmap *fb = &standard_bitmaps[bt];
@@ -1333,12 +1507,15 @@ w32_reset_fringes ()
 {
   /* Destroy row bitmaps.  */
   int bt;
 {
   /* Destroy row bitmaps.  */
   int bt;
-  
+
+  if (!rif)
+    return;
+
   for (bt = NO_FRINGE_BITMAP + 1; bt < max_used_fringe_bitmap; bt++)
     rif->destroy_fringe_bitmap (bt);
 }
 
   for (bt = NO_FRINGE_BITMAP + 1; bt < max_used_fringe_bitmap; bt++)
     rif->destroy_fringe_bitmap (bt);
 }
 
-#endif
+#endif /* HAVE_NTGUI */
 
 #endif /* HAVE_WINDOW_SYSTEM */
 
 
 #endif /* HAVE_WINDOW_SYSTEM */