X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/d30b6b3390969ebe92b242b811482a08c77b0e24..c615a00cdaae92bb335275e74c0a7f57cf077322:/src/fringe.c diff --git a/src/fringe.c b/src/fringe.c index 82c7c19102..754ee68ca5 100644 --- a/src/fringe.c +++ b/src/fringe.c @@ -1,6 +1,7 @@ /* Fringe handling (split from xdisp.c). - Copyright (C) 1985,86,87,88,93,94,95,97,98,99,2000,01,02,03,04 - Free Software Foundation, Inc. + Copyright (C) 1985, 1986, 1987, 1988, 1993, 1994, 1995, 1997, + 1998, 1999, 2000, 2000, 2001, 2002, 2003, 2004, + 2005 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -16,8 +17,8 @@ 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., 59 Temple Place - Suite 330, -Boston, MA 02111-1307, USA. */ +the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +Boston, MA 02110-1301, USA. */ #include #include @@ -31,12 +32,22 @@ Boston, MA 02111-1307, USA. */ #ifdef HAVE_WINDOW_SYSTEM +extern Lisp_Object Qfringe; 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; +/* 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 { @@ -435,23 +446,69 @@ struct fringe_bitmap standard_bitmaps[MAX_STANDARD_FRINGE_BITMAPS] = { 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; -/* Return 1 if FRINGE_ID is a valid fringe bitmap id. */ + +/* Lookup bitmap number for symbol BITMAP. + Return 0 if not a bitmap. */ int -valid_fringe_bitmap_id_p (fringe_id) - int fringe_id; +lookup_fringe_bitmap (bitmap) + Lisp_Object bitmap; { - return (fringe_id >= NO_FRINGE_BITMAP - && fringe_id < max_used_fringe_bitmap - && (fringe_id < MAX_STANDARD_FRINGE_BITMAPS - || fringe_bitmaps[fringe_id] != NULL)); + 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; +{ + 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 @@ -491,7 +548,14 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which) } 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) @@ -518,7 +582,8 @@ draw_fringe_bitmap_1 (w, row, left_p, overlay, which) if (p.face == NULL) { - /* Why does this happen? ++kfs */ + /* This could happen after clearing face cache. + But it shouldn't happen anymore. ++kfs */ return; } @@ -635,8 +700,11 @@ draw_fringe_bitmap (w, row, left_p) 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 +731,35 @@ draw_row_fringe_bitmaps (w, row) } /* 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; + int no_fringe; { 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) - 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; @@ -685,27 +769,32 @@ draw_window_fringes (w) continue; draw_row_fringe_bitmaps (w, row); row->redraw_fringe_bitmaps_p = 0; + updated++; } + + return updated; } /* Recalculate the bitmaps to show in the fringes of window W. - If FORCE_P is 0, only mark rows with modified bitmaps for update in - redraw_fringe_bitmaps_p; else mark all rows for update. */ + Only mark rows with modified bitmaps for update in redraw_fringe_bitmaps_p. + + If KEEP_CURRENT_P is 0, update current_matrix too. */ int -update_window_fringes (w, force_p) +update_window_fringes (w, keep_current_p) struct window *w; - int force_p; + int keep_current_p; { struct glyph_row *row, *cur = 0; int yb = window_text_bottom_y (w); 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; @@ -713,23 +802,30 @@ update_window_fringes (w, force_p) 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 - 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; @@ -737,7 +833,7 @@ update_window_fringes (w, force_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; @@ -746,23 +842,31 @@ 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; - + 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)) + && !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; + } + + if (!done_bot) + { + 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; + 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 @@ -772,10 +876,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; @@ -799,24 +902,20 @@ update_window_fringes (w, force_p) 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->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 (row->indicate_empty_line_p && empty_pos <= 0) + else if (row->indicate_empty_line_p && EQ (empty_pos, Qleft)) 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; - 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; @@ -829,59 +928,64 @@ update_window_fringes (w, force_p) 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->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->indicate_top_line_p && arrow_pos > 0) + else if (row->indicate_top_line_p && EQ (arrow_top, Qright)) 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; - 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; - if (force_p - || row->y != cur->y + if (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 || right_face_id != cur->right_fringe_face_id || cur->redraw_fringe_bitmaps_p) { - redraw_p = row->redraw_fringe_bitmaps_p = cur->redraw_fringe_bitmaps_p = 1; - cur->left_fringe_bitmap = left; - cur->right_fringe_bitmap = right; - cur->left_fringe_face_id = left_face_id; - cur->right_fringe_face_id = right_face_id; + redraw_p = row->redraw_fringe_bitmaps_p = 1; + if (!keep_current_p) + { + cur->redraw_fringe_bitmaps_p = 1; + cur->left_fringe_bitmap = left; + cur->right_fringe_bitmap = right; + cur->left_fringe_face_id = left_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; - 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; + + 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 && !keep_current_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. @@ -891,11 +995,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). - 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 @@ -979,26 +1079,21 @@ compute_fringe_widths (f, redraw) 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; - 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) { - if (rif->destroy_fringe_bitmap) + if (rif && rif->destroy_fringe_bitmap) rif->destroy_fringe_bitmap (n); xfree (*fbp); *fbp = NULL; @@ -1007,6 +1102,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--; +} + + +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; } @@ -1017,7 +1137,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 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 @@ -1033,7 +1155,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 */ - 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */ + 0x3, 0xb, 0x7, 0xf }; /* 0011 1011 0111 1111 */ unsigned short *bits = fb->bits; int j; @@ -1061,14 +1183,24 @@ init_fringe_bitmap (which, fb, once_p) *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) { - 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; @@ -1079,46 +1211,48 @@ init_fringe_bitmap (which, fb, once_p) 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. -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. -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; - 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)) - h = fb.height = XINT (len); + fb.height = h; 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; } } - + if (NILP (width)) fb.width = 8; else @@ -1151,35 +1285,49 @@ Return new bitmap number, or nil of no more free bitmap slots. */) 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; - n < MAX_FRINGE_BITMAPS; + n < max_fringe_bitmaps; 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; - 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; @@ -1187,7 +1335,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 < 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; @@ -1200,48 +1348,50 @@ Return new bitmap number, or nil of no more free bitmap slots. */) 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, - 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. */) - (fringe_id, face) - Lisp_Object fringe_id, face; + (bitmap, face) + Lisp_Object bitmap, face; { + int n; 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)) { - 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"); } - 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, - 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 -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) Lisp_Object pos, window; { struct window *w; - struct buffer *old_buffer = NULL; struct glyph_row *row; int textpos; @@ -1263,8 +1413,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) - 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; } @@ -1277,7 +1430,6 @@ resp. Return nil if POS is not visible in WINDOW. */) void syms_of_fringe () { - defsubr (&Sdestroy_fringe_bitmap); defsubr (&Sdefine_fringe_bitmap); defsubr (&Sfringe_bitmaps_at_pos); @@ -1292,6 +1444,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; + 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. */ @@ -1310,9 +1478,18 @@ init_fringe () { 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 @@ -1322,6 +1499,9 @@ w32_init_fringe () { 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]; @@ -1334,12 +1514,15 @@ w32_reset_fringes () { /* 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); } -#endif +#endif /* HAVE_NTGUI */ #endif /* HAVE_WINDOW_SYSTEM */