static void draw_fringe_bitmap_1 (struct window *w, struct glyph_row *row, int left_p, int overlay, int which) { struct frame *f = XFRAME (WINDOW_FRAME (w)); struct draw_fringe_bitmap_params p; struct fringe_bitmap *fb; int period; int face_id = DEFAULT_FACE_ID; int offset, header_line_height; 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; offset = row->left_fringe_offset; } else { which = row->right_fringe_bitmap; face_id = row->right_fringe_face_id; offset = row->right_fringe_offset; } if (face_id == DEFAULT_FACE_ID) { Lisp_Object face = fringe_faces[which]; face_id = NILP (face) ? lookup_named_face (f, Qfringe, 0) : lookup_derived_face (f, face, FRINGE_FACE_ID, 0); if (face_id < 0) face_id = FRINGE_FACE_ID; } fb = get_fringe_bitmap_data (which); period = fb->period; /* Convert row to frame coordinates. */ p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y) + offset; p.which = which; p.bits = fb->bits; p.wd = fb->width; p.h = fb->height; p.dh = (period > 0 ? (p.y % period) : 0); p.h -= p.dh; /* 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); if (p.face == NULL) { /* This could happen after clearing face cache. But it shouldn't happen anymore. ++kfs */ return; } PREPARE_FACE_FOR_DISPLAY (f, p.face); /* 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); int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? LEFT_MARGIN_AREA : TEXT_AREA)); if (p.wd > wd) p.wd = wd; p.x = x - p.wd - (wd - p.wd) / 2; 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) && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w)) ? 1 : 0); p.bx = x - wd; p.nx = wd; } } else { int x = window_box_right (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? RIGHT_MARGIN_AREA : TEXT_AREA)); int wd = WINDOW_RIGHT_FRINGE_WIDTH (w); if (p.wd > wd) p.wd = wd; 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 || p.y > p.by || p.y + p.h < p.by + p.ny) { p.bx = x; p.nx = wd; } } FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p); }
int update_window_fringes (struct window *w, 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 boundary_top = Qnil, boundary_bot = Qnil; Lisp_Object arrow_top = Qnil, arrow_bot = Qnil; Lisp_Object empty_pos; 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; /* top_ind_rn is set to a nonnegative value whenver row->indicate_bob_p is set, so it's OK that top_row_ends_at_zv_p is not initialized here. Similarly for bot_ind_rn, row->indicate_eob_p and bot_row_ends_at_zv_p. */ int top_row_ends_at_zv_p IF_LINT (= 0), bot_row_ends_at_zv_p IF_LINT (= 0); if (w->pseudo_window_p) return 0; if (!MINI_WINDOW_P (w) && (ind = BVAR (XBUFFER (w->buffer), indicate_buffer_boundaries), !NILP (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 /* Anything else means boundary on left and no arrows. */ boundary_top = boundary_bot = Qleft; } top_ind_rn = bot_ind_rn = -1; if (!NILP (ind)) { for (y = w->vscroll, rn = 0; y < yb && rn < nrows; y += row->height, ++rn) { row = w->desired_matrix->rows + rn; if (!row->enabled_p) row = w->current_matrix->rows + rn; 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 (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); top_ind_rn = rn; } 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)) row->indicate_eob_p = !NILP (boundary_bot), bot_ind_rn = rn; else if (y + row->height >= yb) row->indicate_bottom_line_p = !NILP (arrow_bot), bot_ind_rn = rn; } } } } empty_pos = BVAR (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; y < MAX_BITMAP_CACHE; y++) bitmap_cache[y] = -1; #define LEFT_FRINGE(cache, which, partial_p) \ (bitmap_cache[cache*4+partial_p] >= 0 \ ? bitmap_cache[cache*4+partial_p] \ : (bitmap_cache[cache*4+partial_p] = \ get_logical_fringe_bitmap (w, which, 0, partial_p))) #define RIGHT_FRINGE(cache, which, partial_p) \ (bitmap_cache[cache*4+2+partial_p] >= 0 \ ? bitmap_cache[cache*4+2+partial_p] \ : (bitmap_cache[cache*4+2+partial_p] = \ get_logical_fringe_bitmap (w, which, 1, partial_p))) /* 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; int left_offset, right_offset; int periodic_p; row = w->desired_matrix->rows + rn; cur = w->current_matrix->rows + rn; if (!row->enabled_p) 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) left = NO_FRINGE_BITMAP; else if (row->left_user_fringe_bitmap != NO_FRINGE_BITMAP) { left = row->left_user_fringe_bitmap; left_face_id = row->left_user_fringe_face_id; } else if ((!row->reversed_p && row->truncated_on_left_p) || (row->reversed_p && row->truncated_on_right_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, 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)) { 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 ((!row->reversed_p && MATRIX_ROW_CONTINUATION_LINE_P (row)) || (row->reversed_p && row->continued_p)) 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); 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)) { 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; /* Decide which bitmap to draw in the right fringe. */ if (WINDOW_RIGHT_FRINGE_WIDTH (w) == 0) right = NO_FRINGE_BITMAP; else if (row->right_user_fringe_bitmap != NO_FRINGE_BITMAP) { right = row->right_user_fringe_bitmap; right_face_id = row->right_user_fringe_face_id; } else if ((!row->reversed_p && row->truncated_on_right_p) || (row->reversed_p && row->truncated_on_left_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, 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)) { 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->reversed_p && row->continued_p) || (row->reversed_p && MATRIX_ROW_CONTINUATION_LINE_P (row))) right = RIGHT_FRINGE (4, Qcontinuation, 0); else if (row->indicate_top_line_p && EQ (arrow_top, Qright)) { 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)) { 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; 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 || 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 || 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; 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; cur->left_fringe_offset = left_offset; cur->right_fringe_offset = right_offset; cur->fringe_bitmap_periodic_p = periodic_p; } } if (row->overlay_arrow_bitmap < 0) row->overlay_arrow_bitmap = get_logical_fringe_bitmap (w, Qoverlay_arrow, 0, 0); if (row->overlay_arrow_bitmap != cur->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_offset = left_offset; row->right_fringe_offset = right_offset; row->fringe_bitmap_periodic_p = periodic_p; } return redraw_p && !keep_current_p; }
static void draw_fringe_bitmap_1 (struct window *w, struct glyph_row *row, int left_p, int overlay, int which) { struct frame *f = XFRAME (WINDOW_FRAME (w)); struct draw_fringe_bitmap_params p; struct fringe_bitmap *fb; int period; int face_id = DEFAULT_FACE_ID; int offset, header_line_height; 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; offset = row->left_fringe_offset; } else { which = row->right_fringe_bitmap; face_id = row->right_fringe_face_id; offset = row->right_fringe_offset; } if (face_id == DEFAULT_FACE_ID) { Lisp_Object face = fringe_faces[which]; face_id = NILP (face) ? lookup_named_face (f, Qfringe, false) : lookup_derived_face (f, face, FRINGE_FACE_ID, 0); if (face_id < 0) face_id = FRINGE_FACE_ID; } fb = get_fringe_bitmap_data (which); period = fb->period; /* Convert row to frame coordinates. */ p.y = WINDOW_TO_FRAME_PIXEL_Y (w, row->y) + offset; p.which = which; p.bits = fb->bits; p.wd = fb->width; p.h = fb->height; p.dh = (period > 0 ? (p.y % period) : 0); p.h -= p.dh; /* 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_OR_NULL (f, face_id); if (p.face == NULL) { /* This could happen after clearing face cache. But it shouldn't happen anymore. ++kfs */ return; } prepare_face_for_display (f, p.face); /* 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); int x = window_box_left (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? LEFT_MARGIN_AREA : TEXT_AREA)); if (p.wd > wd) p.wd = wd; p.x = x - p.wd - (wd - p.wd) / 2; 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) /* This could be wrong when we allow window local right dividers - but the window on the left is hard to get. */ && !FRAME_RIGHT_DIVIDER_WIDTH (f) && !WINDOW_HAS_VERTICAL_SCROLL_BAR (w) /* But don't reduce the fringe width if the window has a left margin, because that means we are not in danger of drawing over the vertical border, and OTOH leaving out that one pixel leaves behind traces of the cursor, if it was in column zero before drawing non-empty margin area. */ && w->left_margin_cols == 0) ? 1 : 0); p.bx = x - wd; p.nx = wd; } } else { int x = window_box_right (w, (WINDOW_HAS_FRINGES_OUTSIDE_MARGINS (w) ? RIGHT_MARGIN_AREA : TEXT_AREA)); int wd = WINDOW_RIGHT_FRINGE_WIDTH (w); if (p.wd > wd) p.wd = wd; 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 || p.y > p.by || p.y + p.h < p.by + p.ny) { p.bx = x; p.nx = wd; } } if (p.x >= WINDOW_BOX_LEFT_EDGE_X (w) && (p.x + p.wd) <= WINDOW_BOX_LEFT_EDGE_X (w) + WINDOW_PIXEL_WIDTH (w)) FRAME_RIF (f)->draw_fringe_bitmap (w, row, &p); }