1 /* Synchronize redisplay structures and output changes.
2 Copyright (C) 1994, 1995 Board of Trustees, University of Illinois.
3 Copyright (C) 1995, 1996 Ben Wing.
4 Copyright (C) 1996 Chuck Thompson.
6 This file is part of XEmacs.
8 XEmacs is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by the
10 Free Software Foundation; either version 2, or (at your option) any
13 XEmacs is distributed in the hope that it will be useful, but WITHOUT
14 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 You should have received a copy of the GNU General Public License
19 along with XEmacs; see the file COPYING. If not, write to
20 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
21 Boston, MA 02111-1307, USA. */
23 /* Synched up with: Not in FSF. */
25 /* This file has been Mule-ized. */
27 /* Author: Chuck Thompson */
37 #include "redisplay.h"
40 static int compare_runes (struct window *w, struct rune *crb,
42 static void redraw_cursor_in_window (struct window *w,
43 int run_end_begin_glyphs);
45 /*****************************************************************************
48 Synchronize the given rune blocks.
49 ****************************************************************************/
51 sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
54 int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra))
55 ? Dynarr_largest (cra)
56 : Dynarr_length (dra));
60 /* #### Doing this directly breaks the encapsulation. But, the
61 running time of this function has a measurable impact on
62 redisplay performance so avoiding all excess overhead is a
63 good thing. Is all of this true? */
64 memcpy (cra->base, dra->base, sizeof (struct rune) * max_move);
65 Dynarr_set_size (cra, max_move);
70 for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++)
73 struct rune *drb = Dynarr_atp (dra, rune_elt);
76 memcpy (crb, drb, sizeof (struct rune));
77 Dynarr_add (cra, *crb);
81 /*****************************************************************************
82 sync_display_line_structs
84 For the given LINE in window W, make the current display line equal
85 the desired display line.
86 ****************************************************************************/
88 sync_display_line_structs (struct window *w, int line, int do_blocks,
89 display_line_dynarr *cdla,
90 display_line_dynarr *ddla)
92 int cdla_len = Dynarr_length (cdla);
94 struct display_line dl, *clp, *dlp;
97 dlp = Dynarr_atp (ddla, line);
98 if (line >= Dynarr_largest (cdla))
101 clp->display_blocks = Dynarr_new (display_block);
105 clp = Dynarr_atp (cdla, line);
106 if (clp->display_blocks)
107 Dynarr_reset (clp->display_blocks);
108 if (clp->left_glyphs)
110 Dynarr_free (clp->left_glyphs);
111 clp->left_glyphs = 0;
113 if (clp->right_glyphs)
115 Dynarr_free (clp->right_glyphs);
116 clp->right_glyphs = 0;
120 display_block_dynarr *tdb = clp->display_blocks;
122 memcpy (clp, dlp, sizeof (struct display_line));
123 clp->display_blocks = tdb;
124 clp->left_glyphs = 0;
125 clp->right_glyphs = 0;
128 if (!do_blocks && line >= cdla_len)
130 Dynarr_add (cdla, *clp);
134 for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++)
136 struct display_block db, *cdb;
137 struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt);
139 if (db_elt >= Dynarr_largest (clp->display_blocks))
142 memcpy (cdb, ddb, sizeof (struct display_block));
143 cdb->runes = Dynarr_new (rune);
144 Dynarr_add (clp->display_blocks, *cdb);
150 cdb = Dynarr_atp (clp->display_blocks, db_elt);
152 memcpy (cdb, ddb, sizeof (struct display_block));
154 Dynarr_increment (clp->display_blocks);
157 sync_rune_structs (w, cdb->runes, ddb->runes);
160 if (line >= cdla_len)
161 Dynarr_add (cdla, *clp);
164 /*****************************************************************************
167 Compare to runes to see if each of their fields is equal. If so,
168 return true otherwise return false.
169 ****************************************************************************/
171 compare_runes (struct window *w, struct rune *crb, struct rune *drb)
173 /* Do not compare the values of bufpos and endpos. They do not
174 affect the display characteristics. */
176 if ((crb->findex != drb->findex) ||
177 (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
179 else if (crb->xpos != drb->xpos)
181 else if (crb->width != drb->width)
183 else if (crb->cursor_type != drb->cursor_type)
185 else if (crb->type != drb->type)
187 else if (crb->type == RUNE_CHAR &&
188 (crb->object.chr.ch != drb->object.chr.ch))
190 else if (crb->type == RUNE_DGLYPH &&
191 (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
192 !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
193 crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
195 else if (crb->type == RUNE_HLINE &&
196 (crb->object.hline.thickness != drb->object.hline.thickness ||
197 crb->object.hline.yoffset != drb->object.hline.yoffset))
203 /*****************************************************************************
204 get_next_display_block
206 Return the next display starting at or overlapping START_POS. Return
207 the start of the next region in NEXT_START.
208 ****************************************************************************/
210 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba,
211 int start_pos, int *next_start)
213 int next_display_block = NO_BLOCK;
217 /* If we don't find a display block covering or starting at
218 start_pos, then we return the starting point of the next display
219 block or the next division boundary, whichever is closer to
223 if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
224 *next_start = bounds.left_in;
225 else if (start_pos < bounds.left_white)
226 *next_start = bounds.left_white;
227 else if (start_pos < bounds.right_white)
228 *next_start = bounds.right_white;
229 else if (start_pos < bounds.right_in)
230 *next_start = bounds.right_in;
231 else if (start_pos <= bounds.right_out)
232 *next_start = bounds.right_out;
237 for (block = 0; block < Dynarr_length (dba); block++)
239 struct display_block *db = Dynarr_atp (dba, block);
241 if (db->start_pos <= start_pos && db->end_pos > start_pos)
243 if ((int) db->type > priority)
246 next_display_block = block;
248 *next_start = db->end_pos;
251 else if (next_start && db->start_pos > start_pos)
253 if (db->start_pos < *next_start)
254 *next_start = db->start_pos;
258 return next_display_block;
261 /*****************************************************************************
262 get_cursor_size_and_location
264 Return the information defining the pixel location of the cursor.
265 ****************************************************************************/
267 get_cursor_size_and_location (struct window *w, struct display_block *db,
269 int *cursor_start, int *cursor_width,
274 int defheight, defwidth;
276 if (Dynarr_length (db->runes) <= cursor_location)
279 XSETWINDOW (window, w);
281 rb = Dynarr_atp (db->runes, cursor_location);
282 *cursor_start = rb->xpos;
284 default_face_height_and_width (window, &defheight, &defwidth);
285 *cursor_height = defheight;
287 if (rb->type == RUNE_BLANK)
288 *cursor_width = defwidth;
290 *cursor_width = rb->width;
293 /*****************************************************************************
294 compare_display_blocks
296 Given two display blocks, output only those areas where they differ.
297 ****************************************************************************/
299 compare_display_blocks (struct window *w, struct display_line *cdl,
300 struct display_line *ddl, int c_block, int d_block,
301 int start_pixpos, int cursor_start, int cursor_width,
304 struct frame *f = XFRAME (w->frame);
305 struct device *d = XDEVICE (f->device);
307 struct display_block *cdb, *ddb;
313 cdb = Dynarr_atp (cdl->display_blocks, c_block);
314 ddb = Dynarr_atp (ddl->display_blocks, d_block);
316 assert (cdb->type == ddb->type);
319 stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes));
322 (!Dynarr_length (ddb->runes)
324 : (Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->xpos +
325 Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->width));
327 /* If the new block type is not text and the cursor status is
328 changing and it overlaps the position of this block then force a
329 full redraw of the block in order to make sure that the cursor is
331 if (ddb->type != TEXT
333 /* I'm not sure exactly what this code wants to do, but it's
334 * not right--it doesn't update when cursor_elt changes from, e.g.,
335 * 0 to 8, and the new or old cursor loc overlaps this block.
336 * I've replaced it with the more conservative test below.
337 * -dkindred@cs.cmu.edu 23-Mar-1997 */
338 && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
339 || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
340 && (ddl->cursor_elt == -1 ||
343 && (cursor_start + cursor_width) >= start_pixpos
344 && cursor_start <= block_end))
346 && (cdl->cursor_elt != ddl->cursor_elt)
351 if (f->windows_structure_changed ||
354 cdl->ypos != ddl->ypos ||
355 cdl->ascent != ddl->ascent ||
356 cdl->descent != ddl->descent ||
357 cdl->clip != ddl->clip ||
367 while (start_pos < 0 && elt < stop_pos)
369 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
370 Dynarr_atp (ddb->runes, elt)))
380 /* If nothing has changed in the area where the blocks overlap, but
381 there are new blocks in the desired block, then adjust the start
382 point accordingly. */
383 if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes))
384 start_pos = stop_pos;
389 if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes))
392 stop_pos = Dynarr_length (ddb->runes);
396 /* If the lines have the same number of runes and we are not
397 forcing a full redraw because the display line has
398 changed position then we try and optimize how much of the
399 line we actually redraw by scanning backwards from the
400 end for the first changed rune. This optimization is
401 almost always triggered by face changes. */
403 int elt = Dynarr_length (ddb->runes) - 1;
405 while (elt > start_pos)
407 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
408 Dynarr_atp (ddb->runes, elt)))
416 DEVMETH (d, output_display_block, (w, ddl, d_block, start_pos,
417 stop_pos, start_pixpos,
418 cursor_start, cursor_width,
426 /*****************************************************************************
429 Clear the lefthand outside border.
430 ****************************************************************************/
432 clear_left_border (struct window *w, int y, int height)
434 struct frame *f = XFRAME (w->frame);
435 struct device *d = XDEVICE (f->device);
438 XSETWINDOW (window, w);
439 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
440 FRAME_LEFT_BORDER_START (f), y,
441 FRAME_BORDER_WIDTH (f), height));
444 /*****************************************************************************
447 Clear the righthand outside border.
448 ****************************************************************************/
450 clear_right_border (struct window *w, int y, int height)
452 struct frame *f = XFRAME (w->frame);
453 struct device *d = XDEVICE (f->device);
456 XSETWINDOW (window, w);
457 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
458 FRAME_RIGHT_BORDER_START (f),
459 y, FRAME_BORDER_WIDTH (f), height));
462 /*****************************************************************************
465 Ensure that the contents of the given display line is correct
466 on-screen. The force_ parameters are used by redisplay_move_cursor
467 to correctly update cursor locations and only cursor locations.
468 ****************************************************************************/
470 output_display_line (struct window *w, display_line_dynarr *cdla,
471 display_line_dynarr *ddla, int line, int force_start,
475 struct frame *f = XFRAME (w->frame);
476 struct device *d = XDEVICE (f->device);
477 struct buffer *b = XBUFFER (w->buffer);
478 struct buffer *old_b = window_display_buffer (w);
479 struct display_line *cdl, *ddl;
480 display_block_dynarr *cdba, *ddba;
481 int start_pixpos, end_pixpos;
482 int cursor_start, cursor_width, cursor_height;
484 int force = (force_start >= 0 || force_end >= 0);
485 int clear_border = 0;
488 if (cdla && line < Dynarr_length (cdla))
490 cdl = Dynarr_atp (cdla, line);
491 cdba = cdl->display_blocks;
499 ddl = Dynarr_atp (ddla, line); /* assert line < Dynarr_length (ddla) */
500 ddba = ddl->display_blocks;
502 if (force_start >= 0 && force_start >= ddl->bounds.left_out)
503 start_pixpos = force_start;
505 start_pixpos = ddl->bounds.left_out;
507 if (force_end >= 0 && force_end < ddl->bounds.right_out)
508 end_pixpos = force_end;
510 end_pixpos = ddl->bounds.right_out;
512 /* Get the cursor parameters. */
513 if (ddl->cursor_elt != -1)
515 struct display_block *db;
517 /* If the lines cursor parameter is not -1 then it indicates
518 which rune in the TEXT block contains the cursor. This means
519 that there must be at least one display block. The TEXT
520 block, if present, must always be the first display block. */
521 assert (Dynarr_length (ddba) != 0);
523 db = Dynarr_atp (ddba, 0);
524 assert (db->type == TEXT);
526 get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start,
527 &cursor_width, &cursor_height);
531 cursor_start = cursor_width = cursor_height = 0;
534 /* The modeline should only have a single block and it had better be
538 /* The shadow thickness check is necessary if only the sign of
540 if (cdba && !w->shadow_thickness_changed)
542 must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0,
543 start_pixpos, 0, 0, 0);
547 DEVMETH (d, output_display_block, (w, ddl, 0, 0, -1, start_pixpos,
556 while (!ddl->modeline && start_pixpos < end_pixpos)
559 int next_start_pixpos;
561 block = get_next_display_block (ddl->bounds, ddba, start_pixpos,
564 /* If we didn't find a block then we should blank the area
565 between start_pos and next_start if necessary. */
566 if (block == NO_BLOCK)
568 /* We only erase those areas which were actually previously
569 covered by a display block unless the window structure
570 changed. In that case we clear all areas since the current
571 structures may actually represent a different buffer. */
572 while (start_pixpos < next_start_pixpos)
578 old_block = get_next_display_block (ddl->bounds, cdba,
579 start_pixpos, &block_end);
582 old_block = NO_BLOCK;
583 block_end = next_start_pixpos;
586 if (!cdba || old_block != NO_BLOCK || b != old_b ||
587 f->windows_structure_changed ||
590 (cdl && (cdl->ypos != ddl->ypos ||
591 cdl->ascent != ddl->ascent ||
592 cdl->descent != ddl->descent ||
593 cdl->clip != ddl->clip)))
595 int x, y, width, height;
600 y = ddl->ypos - ddl->ascent;
601 width = min (next_start_pixpos, block_end) - x;
602 height = ddl->ascent + ddl->descent - ddl->clip;
604 if (x < ddl->bounds.left_in)
605 face = Vleft_margin_face;
606 else if (x < ddl->bounds.right_in)
607 face = Vdefault_face;
608 else if (x < ddl->bounds.right_out)
609 face = Vright_margin_face;
617 XSETWINDOW (window, w);
619 /* Clear the empty area. */
620 DEVMETH (d, clear_region,
621 (window, get_builtin_face_cache_index (w,
623 x, y, width, height));
625 /* Mark that we should clear the border. This is
626 necessary because italic fonts may leave
627 droppings in the border. */
632 start_pixpos = min (next_start_pixpos, block_end);
637 struct display_block *cdb, *ddb;
642 old_block = get_next_display_block (ddl->bounds, cdba,
643 start_pixpos, &block_end);
645 old_block = NO_BLOCK;
647 ddb = Dynarr_atp (ddba, block);
648 cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
650 /* If there was formerly no block over the current
651 region or if it was a block of a different type, then
652 output the entire ddb. Otherwise, compare cdb and
653 ddb and output only the changed region. */
654 if (!force && cdb && ddb->type == cdb->type && b == old_b)
656 must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
658 cursor_start, cursor_width,
667 for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
669 struct rune *rb = Dynarr_atp (ddb->runes, elt);
671 if (start_pixpos >= rb->xpos
672 && start_pixpos < rb->xpos + rb->width)
675 if (end_pixpos > rb->xpos
676 && end_pixpos <= rb->xpos + rb->width)
679 if (last_elt > Dynarr_length (ddb->runes))
680 last_elt = Dynarr_length (ddb->runes);
686 DEVMETH (d, output_display_block, (w, ddl, block, first_elt,
689 cursor_start, cursor_width,
693 start_pixpos = next_start_pixpos;
697 /* Clear the internal border if we are next to it and the window
698 structure or frame size has changed or if something caused
699 clear_border to be tripped. */
700 /* #### Doing this on f->clear sucks but is necessary because of
701 window-local background values. */
702 if (f->windows_structure_changed || f->faces_changed || clear_border
705 int y = ddl->ypos - ddl->ascent;
706 int height = ddl->ascent + ddl->descent - ddl->clip;
710 y -= MODELINE_SHADOW_THICKNESS (w);
711 height += (2 * MODELINE_SHADOW_THICKNESS (w));
714 if (window_is_leftmost (w))
715 clear_left_border (w, y, height);
716 if (window_is_rightmost (w))
717 clear_right_border (w, y, height);
721 sync_display_line_structs (w, line, must_sync, cdla, ddla);
724 /*****************************************************************************
725 redisplay_move_cursor
727 For the given window W, move the cursor to NEW_POINT. Returns a
728 boolean indicating success or failure.
729 ****************************************************************************/
731 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
732 #define ADJ_ENDPOS (rb->endpos + dl->offset)
735 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
737 struct frame *f = XFRAME (w->frame);
738 struct device *d = XDEVICE (f->device);
740 display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
741 struct display_line *dl;
742 struct display_block *db;
744 int x = w->last_point_x[CURRENT_DISP];
745 int y = w->last_point_y[CURRENT_DISP];
748 * Bail if cursor_in_echo_area is non-zero and we're fiddling with
749 * the cursor in a non-active minibuffer window, since that is a
750 * special case that is handled elsewhere and this function need
751 * not handle it. Return 1 so the caller will assume we
754 if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
755 w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
758 if (y < 0 || y >= Dynarr_length (cla))
761 dl = Dynarr_atp (cla, y);
762 db = get_display_block_from_line (dl, TEXT);
764 if (x < 0 || x >= Dynarr_length (db->runes))
767 rb = Dynarr_atp (db->runes, x);
769 if (rb->cursor_type == CURSOR_OFF)
771 else if (ADJ_BUFPOS == new_point
772 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
773 && (new_point <= ADJ_ENDPOS)))
775 w->last_point_x[CURRENT_DISP] = x;
776 w->last_point_y[CURRENT_DISP] = y;
777 Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
784 DEVMETH (d, output_begin, (d));
786 /* #### This is a gross kludge. Cursor handling is such a royal
788 if (rb->type == RUNE_DGLYPH &&
789 (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
790 EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
791 rb->cursor_type = NO_CURSOR;
793 rb->cursor_type = CURSOR_OFF;
795 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
798 w->last_point_x[CURRENT_DISP] = -1;
799 w->last_point_y[CURRENT_DISP] = -1;
800 Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
802 /* If this isn't the selected frame, then erasing the old cursor is
803 all we actually had to do. */
804 if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
807 DEVMETH (d, output_end, (d));
812 /* This should only occur in the minibuffer. */
815 w->last_point_x[CURRENT_DISP] = 0;
816 w->last_point_y[CURRENT_DISP] = y;
817 Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
819 rb = Dynarr_atp (db->runes, 0);
820 rb->cursor_type = CURSOR_ON;
823 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
826 DEVMETH (d, output_end, (d));
835 if (ADJ_BUFPOS < new_point)
841 else /* (rb->bufpos + dl->offset) > new_point */
858 while ((up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)))
860 dl = Dynarr_atp (cla, cur_dl);
861 db = get_display_block_from_line (dl, TEXT);
864 cur_rb = Dynarr_length (db->runes) - 1;
866 while ((!scroll_on_clipped_lines || !dl->clip) &&
867 (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
869 rb = Dynarr_atp (db->runes, cur_rb);
871 if (rb->cursor_type != IGNORE_CURSOR
872 && rb->cursor_type != NO_CURSOR &&
873 (ADJ_BUFPOS == new_point
874 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
875 && (new_point <= ADJ_BUFPOS))))
877 rb->cursor_type = CURSOR_ON;
878 dl->cursor_elt = cur_rb;
881 output_display_line (w, 0, cla, cur_dl, rb->xpos,
882 rb->xpos + rb->width);
884 w->last_point_x[CURRENT_DISP] = cur_rb;
885 w->last_point_y[CURRENT_DISP] = cur_dl;
886 Fset_marker (w->last_point[CURRENT_DISP],
887 make_int (ADJ_BUFPOS), w->buffer);
890 DEVMETH (d, output_end, (d));
894 (up ? cur_rb++ : cur_rb--);
897 (up ? (cur_rb = 0) : (first = 0));
898 (up ? cur_dl++ : cur_dl--);
903 DEVMETH (d, output_end, (d));
909 /*****************************************************************************
910 redraw_cursor_in_window
912 For the given window W, redraw the cursor if it is contained within
914 ****************************************************************************/
916 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
918 struct frame *f = XFRAME (w->frame);
919 struct device *d = XDEVICE (f->device);
921 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
922 struct display_line *dl;
923 struct display_block *db;
926 int x = w->last_point_x[CURRENT_DISP];
927 int y = w->last_point_y[CURRENT_DISP];
929 if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
930 !echo_area_active (f) && minibuf_level == 0)
932 MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0));
935 if (y < 0 || y >= Dynarr_length (dla))
938 if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
939 !is_surrogate_for_selected_frame (f))
942 dl = Dynarr_atp (dla, y);
943 db = get_display_block_from_line (dl, TEXT);
945 if (x < 0 || x >= Dynarr_length (db->runes))
948 rb = Dynarr_atp (db->runes, x);
950 /* Don't call the output routine if the block isn't actually the
952 if (rb->cursor_type == CURSOR_ON)
954 MAYBE_DEVMETH (d, set_final_cursor_coords,
955 (f, dl->ypos - 1, rb->xpos));
957 if (run_end_begin_meths)
958 DEVMETH (d, output_begin, (d));
960 output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
962 if (run_end_begin_meths)
963 DEVMETH (d, output_end, (d));
967 /*****************************************************************************
968 redisplay_redraw_cursor
970 For the given frame F, redraw the cursor on the selected window.
971 This is used to update the cursor after focus changes.
972 ****************************************************************************/
974 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
978 if (!cursor_in_echo_area)
979 window = FRAME_SELECTED_WINDOW (f);
980 else if (FRAME_HAS_MINIBUF_P (f))
981 window = FRAME_MINIBUF_WINDOW (f);
985 redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths);
988 /*****************************************************************************
989 redisplay_clear_top_of_window
991 If window is topmost, clear the internal border above it.
992 ****************************************************************************/
994 redisplay_clear_top_of_window (struct window *w)
997 XSETWINDOW (window, w);
999 if (!NILP (Fwindow_highest_p (window)))
1001 struct frame *f = XFRAME (w->frame);
1002 struct device *d = XDEVICE (f->device);
1003 int x, y, width, height;
1006 width = w->pixel_width;
1008 if (window_is_leftmost (w))
1010 x -= FRAME_BORDER_WIDTH (f);
1011 width += FRAME_BORDER_WIDTH (f);
1013 if (window_is_rightmost (w))
1014 width += FRAME_BORDER_WIDTH (f);
1016 y = FRAME_TOP_BORDER_START (f) - 1;
1017 height = FRAME_BORDER_HEIGHT (f) + 1;
1019 DEVMETH (d, clear_region, (window, DEFAULT_INDEX, x, y, width, height));
1023 /*****************************************************************************
1024 redisplay_clear_bottom_of_window
1026 Clear window from right below the last display line to right above
1027 the modeline. The calling function can limit the area actually
1028 erased by setting min_start and/or max_end to positive values.
1029 ****************************************************************************/
1031 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
1032 int min_start, int max_end)
1034 struct frame *f = XFRAME (w->frame);
1035 struct device *d = XDEVICE (f->device);
1037 int ddla_len = Dynarr_length (ddla);
1039 ypos2 = WINDOW_TEXT_BOTTOM (w);
1040 #ifdef HAVE_SCROLLBARS
1041 /* This adjustment is to catch the intersection of any scrollbars. */
1042 if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p))
1043 ypos2 += window_scrollbar_height (w);
1048 if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
1050 ypos1 = WINDOW_TEXT_TOP (w);
1051 #ifdef HAVE_SCROLLBARS
1052 /* This adjustment is to catch the intersection of any scrollbars. */
1053 if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p))
1054 ypos1 -= window_scrollbar_height (w);
1059 struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
1060 ypos1 = dl->ypos + dl->descent - dl->clip;
1064 ypos1 = WINDOW_TEXT_TOP (w);
1066 /* #### See if this can be made conditional on the frame
1068 if (MINI_WINDOW_P (w))
1069 ypos2 += FRAME_BORDER_HEIGHT (f);
1071 if (min_start >= 0 && ypos1 < min_start)
1073 if (max_end >= 0 && ypos2 > max_end)
1079 DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1082 /*****************************************************************************
1083 redisplay_update_line
1085 This is used during incremental updates to update a single line and
1086 correct the offsets on all lines below it. At the moment
1087 update_values is false if we are only updating the modeline.
1088 ****************************************************************************/
1090 redisplay_update_line (struct window *w, int first_line, int last_line,
1093 struct frame *f = XFRAME (w->frame);
1094 struct device *d = XDEVICE (f->device);
1096 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1097 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1099 DEVMETH (d, output_begin, (d));
1101 while (first_line <= last_line)
1103 Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
1104 Dynarr_atp (cdla, first_line)->bufpos);
1105 Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
1106 Dynarr_atp (ddla, first_line)->bufpos);
1108 assert (Dynarr_length (cdla) == Dynarr_length (ddla));
1110 /* Output the changes. */
1111 output_display_line (w, cdla, ddla, first_line, -1, -1);
1113 /* Update the offsets. */
1116 int cur_line = first_line + 1;
1117 while (cur_line < Dynarr_length (cdla))
1119 Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
1120 Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
1125 /* Update the window_end_pos and other settings. */
1128 w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
1130 if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
1132 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1133 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1140 /* Update the window max line length. We have to scan the entire
1141 set of display lines otherwise we might not detect if the max is
1142 supposed to shrink. */
1147 w->max_line_len = 0;
1148 while (line < Dynarr_length (ddla))
1150 struct display_line *dl = Dynarr_atp (ddla, line);
1153 w->max_line_len = max (dl->num_chars, w->max_line_len);
1159 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1160 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1161 Fset_marker (w->last_point[CURRENT_DISP],
1162 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1163 Fset_marker (w->last_start[CURRENT_DISP],
1164 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1166 /* We don't bother updating the vertical scrollbars here. This
1167 gives us a performance increase while having minimal loss of
1168 quality to the scrollbar slider size and position since when this
1169 function is called we know that the changes to the buffer were
1170 very localized. We have to update the horizontal scrollbars,
1171 though, because this routine could cause a change which has a
1172 larger impact on their sizing. */
1173 /* #### See if we can get away with only calling this if
1174 max_line_len is greater than the window_char_width. */
1175 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
1177 extern int stupid_vertical_scrollbar_drag_hack;
1179 update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack);
1180 stupid_vertical_scrollbar_drag_hack = 1;
1184 /* This has to be done after we've updated the values. We don't
1185 call output_end for tty frames. Redisplay will do this after all
1186 tty windows have been updated. This cuts down on cursor
1188 if (FRAME_TTY_P (f))
1189 redisplay_redraw_cursor (f, 0);
1191 DEVMETH (d, output_end, (d));
1194 /*****************************************************************************
1195 redisplay_output_window
1197 For the given window W, ensure that the current display lines are
1198 equal to the desired display lines, outputing changes as necessary.
1200 #### Fuck me. This just isn't going to cut it for tty's. The output
1201 decisions for them must be based on the contents of the entire frame
1202 because that is how the available output capabilities think. The
1203 solution is relatively simple. Create redisplay_output_frame. This
1204 will basically merge all of the separate window display structs into
1205 a single one for the frame. This combination structure will be able
1206 to be passed to the same output_display_line which works for windows
1207 on X frames and the right things will happen. It just takes time to
1209 ****************************************************************************/
1211 redisplay_output_window (struct window *w)
1213 struct frame *f = XFRAME (w->frame);
1214 struct device *d = XDEVICE (f->device);
1216 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1217 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1219 int cdla_len = Dynarr_length (cdla);
1220 int ddla_len = Dynarr_length (ddla);
1223 int need_to_clear_bottom = 0;
1224 int need_to_clear_start = -1;
1225 int need_to_clear_end = -1;
1227 /* Backgrounds may have changed or windows may have gone away
1228 leaving dividers lying around. */
1229 if (f->faces_changed
1230 || f->windows_structure_changed
1231 || w->shadow_thickness_changed)
1232 need_to_clear_bottom = 1;
1234 /* The first thing we do is determine if we are going to need to
1235 clear the bottom of the window. We only need to do this if the
1236 bottom of the current display lines is below the bottom of the
1237 desired display lines. Note that the number of lines is
1238 irrelevant. Only the position matters. We also clear to the
1239 bottom of the window if the modeline has shifted position. */
1240 /* #### We can't blindly not clear the bottom if f->clear is true
1241 since there might be a window-local background. However, for
1242 those cases where there isn't, clearing the end of the window in
1244 if (!need_to_clear_bottom)
1246 struct display_line *cdl, *ddl;
1248 /* If the modeline has changed position or size, clear the bottom
1250 if (!need_to_clear_bottom)
1255 cdl = Dynarr_atp (cdla, 0);
1257 ddl = Dynarr_atp (ddla, 0);
1260 need_to_clear_bottom = 1;
1261 else if ((!cdl->modeline && ddl->modeline)
1262 || (cdl->modeline && !ddl->modeline))
1263 need_to_clear_bottom = 1;
1264 else if (cdl->ypos != ddl->ypos ||
1265 cdl->ascent != ddl->ascent ||
1266 cdl->descent != ddl->descent ||
1267 cdl->clip != ddl->clip)
1268 need_to_clear_bottom = 1;
1270 /* #### This kludge is to make sure the modeline shadows get
1271 redrawn if the modeline position shifts. */
1272 if (need_to_clear_bottom)
1273 w->shadow_thickness_changed = 1;
1276 if (!need_to_clear_bottom)
1281 cdl = Dynarr_atp (cdla, cdla_len - 1);
1283 ddl = Dynarr_atp (ddla, ddla_len - 1);
1286 need_to_clear_bottom = 1;
1289 int cdl_bottom, ddl_bottom;
1291 cdl_bottom = cdl->ypos + cdl->descent;
1292 ddl_bottom = ddl->ypos + ddl->descent;
1294 if (cdl_bottom > ddl_bottom)
1296 need_to_clear_bottom = 1;
1297 need_to_clear_start = ddl_bottom;
1298 need_to_clear_end = cdl_bottom;
1304 /* Perform any output initialization. */
1305 DEVMETH (d, output_begin, (d));
1307 /* If the window's structure has changed clear the internal border
1308 above it if it is topmost (the function will check). */
1309 if (f->windows_structure_changed)
1310 redisplay_clear_top_of_window (w);
1312 /* Output each line. */
1313 for (line = 0; line < Dynarr_length (ddla); line++)
1315 output_display_line (w, cdla, ddla, line, -1, -1);
1318 /* If the number of display lines has shrunk, adjust. */
1319 if (cdla_len > ddla_len)
1321 Dynarr_length (cdla) = ddla_len;
1324 /* Output a vertical divider between windows, if necessary. */
1325 if (window_needs_vertical_divider (w)
1326 && (f->windows_structure_changed || f->clear))
1328 DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
1331 /* Clear the rest of the window, if necessary. */
1332 if (need_to_clear_bottom)
1334 redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
1338 w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
1339 Fset_marker (w->start[CURRENT_DISP],
1340 make_int (marker_position (w->start[DESIRED_DISP])),
1342 Fset_marker (w->pointm[CURRENT_DISP],
1343 make_int (marker_position (w->pointm[DESIRED_DISP])),
1345 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1346 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1347 Fset_marker (w->last_start[CURRENT_DISP],
1348 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1349 Fset_marker (w->last_point[CURRENT_DISP],
1350 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1351 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1352 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1353 w->shadow_thickness_changed = 0;
1355 set_window_display_buffer (w, XBUFFER (w->buffer));
1356 find_window_mirror (w)->truncate_win = window_truncation_on (w);
1358 /* Overkill on invalidating the cache. It is very bad for it to not
1359 get invalidated when it should be. */
1360 INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
1362 /* We don't call output_end for tty frames. Redisplay will do this
1363 after all tty windows have been updated. This cuts down on
1365 if (FRAME_TTY_P (f))
1366 redisplay_redraw_cursor (f, 0);
1368 DEVMETH (d, output_end, (d));
1370 #ifdef HAVE_SCROLLBARS
1371 update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);