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 */
38 #include "redisplay.h"
43 static int compare_runes (struct window *w, struct rune *crb,
45 static void redraw_cursor_in_window (struct window *w,
46 int run_end_begin_glyphs);
48 /*****************************************************************************
51 Synchronize the given rune blocks.
52 ****************************************************************************/
54 sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
57 int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra))
58 ? Dynarr_largest (cra)
59 : Dynarr_length (dra));
63 /* #### Doing this directly breaks the encapsulation. But, the
64 running time of this function has a measurable impact on
65 redisplay performance so avoiding all excess overhead is a
66 good thing. Is all of this true? */
67 memcpy (cra->base, dra->base, sizeof (struct rune) * max_move);
68 Dynarr_set_size (cra, max_move);
73 for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++)
76 struct rune *drb = Dynarr_atp (dra, rune_elt);
79 memcpy (crb, drb, sizeof (struct rune));
80 Dynarr_add (cra, *crb);
84 /*****************************************************************************
85 sync_display_line_structs
87 For the given LINE in window W, make the current display line equal
88 the desired display line.
89 ****************************************************************************/
91 sync_display_line_structs (struct window *w, int line, int do_blocks,
92 display_line_dynarr *cdla,
93 display_line_dynarr *ddla)
95 int cdla_len = Dynarr_length (cdla);
97 struct display_line dl, *clp, *dlp;
100 dlp = Dynarr_atp (ddla, line);
101 if (line >= Dynarr_largest (cdla))
104 clp->display_blocks = Dynarr_new (display_block);
108 clp = Dynarr_atp (cdla, line);
109 if (clp->display_blocks)
110 Dynarr_reset (clp->display_blocks);
111 if (clp->left_glyphs)
113 Dynarr_free (clp->left_glyphs);
114 clp->left_glyphs = 0;
116 if (clp->right_glyphs)
118 Dynarr_free (clp->right_glyphs);
119 clp->right_glyphs = 0;
123 display_block_dynarr *tdb = clp->display_blocks;
125 memcpy (clp, dlp, sizeof (struct display_line));
126 clp->display_blocks = tdb;
127 clp->left_glyphs = 0;
128 clp->right_glyphs = 0;
131 if (!do_blocks && line >= cdla_len)
133 Dynarr_add (cdla, *clp);
137 for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++)
139 struct display_block db, *cdb;
140 struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt);
142 if (db_elt >= Dynarr_largest (clp->display_blocks))
145 memcpy (cdb, ddb, sizeof (struct display_block));
146 cdb->runes = Dynarr_new (rune);
147 Dynarr_add (clp->display_blocks, *cdb);
153 cdb = Dynarr_atp (clp->display_blocks, db_elt);
155 memcpy (cdb, ddb, sizeof (struct display_block));
157 Dynarr_increment (clp->display_blocks);
160 sync_rune_structs (w, cdb->runes, ddb->runes);
163 if (line >= cdla_len)
164 Dynarr_add (cdla, *clp);
167 /*****************************************************************************
170 Compare to runes to see if each of their fields is equal. If so,
171 return true otherwise return false.
172 ****************************************************************************/
174 compare_runes (struct window *w, struct rune *crb, struct rune *drb)
176 /* Do not compare the values of bufpos and endpos. They do not
177 affect the display characteristics. */
179 if ((crb->findex != drb->findex) ||
180 (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
182 else if (crb->xpos != drb->xpos)
184 else if (crb->width != drb->width)
186 else if (crb->cursor_type != drb->cursor_type)
188 else if (crb->type != drb->type)
190 else if (crb->type == RUNE_CHAR &&
191 (crb->object.chr.ch != drb->object.chr.ch))
193 else if (crb->type == RUNE_DGLYPH &&
194 (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
195 !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
196 crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
198 else if (crb->type == RUNE_HLINE &&
199 (crb->object.hline.thickness != drb->object.hline.thickness ||
200 crb->object.hline.yoffset != drb->object.hline.yoffset))
206 /*****************************************************************************
207 get_next_display_block
209 Return the next display starting at or overlapping START_POS. Return
210 the start of the next region in NEXT_START.
211 ****************************************************************************/
213 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba,
214 int start_pos, int *next_start)
216 int next_display_block = NO_BLOCK;
220 /* If we don't find a display block covering or starting at
221 start_pos, then we return the starting point of the next display
222 block or the next division boundary, whichever is closer to
226 if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
227 *next_start = bounds.left_in;
228 else if (start_pos < bounds.left_white)
229 *next_start = bounds.left_white;
230 else if (start_pos < bounds.right_white)
231 *next_start = bounds.right_white;
232 else if (start_pos < bounds.right_in)
233 *next_start = bounds.right_in;
234 else if (start_pos <= bounds.right_out)
235 *next_start = bounds.right_out;
240 for (block = 0; block < Dynarr_length (dba); block++)
242 struct display_block *db = Dynarr_atp (dba, block);
244 if (db->start_pos <= start_pos && db->end_pos > start_pos)
246 if ((int) db->type > priority)
249 next_display_block = block;
251 *next_start = db->end_pos;
254 else if (next_start && db->start_pos > start_pos)
256 if (db->start_pos < *next_start)
257 *next_start = db->start_pos;
261 return next_display_block;
264 /*****************************************************************************
265 get_cursor_size_and_location
267 Return the information defining the pixel location of the cursor.
268 ****************************************************************************/
270 get_cursor_size_and_location (struct window *w, struct display_block *db,
272 int *cursor_start, int *cursor_width,
277 int defheight, defwidth;
279 if (Dynarr_length (db->runes) <= cursor_location)
282 XSETWINDOW (window, w);
284 rb = Dynarr_atp (db->runes, cursor_location);
285 *cursor_start = rb->xpos;
287 default_face_height_and_width (window, &defheight, &defwidth);
288 *cursor_height = defheight;
290 if (rb->type == RUNE_BLANK)
291 *cursor_width = defwidth;
293 *cursor_width = rb->width;
296 /*****************************************************************************
297 compare_display_blocks
299 Given two display blocks, output only those areas where they differ.
300 ****************************************************************************/
302 compare_display_blocks (struct window *w, struct display_line *cdl,
303 struct display_line *ddl, int c_block, int d_block,
304 int start_pixpos, int cursor_start, int cursor_width,
307 struct frame *f = XFRAME (w->frame);
308 struct device *d = XDEVICE (f->device);
310 struct display_block *cdb, *ddb;
316 cdb = Dynarr_atp (cdl->display_blocks, c_block);
317 ddb = Dynarr_atp (ddl->display_blocks, d_block);
319 assert (cdb->type == ddb->type);
322 stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes));
325 (!Dynarr_length (ddb->runes)
327 : (Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->xpos +
328 Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->width));
330 /* If the new block type is not text and the cursor status is
331 changing and it overlaps the position of this block then force a
332 full redraw of the block in order to make sure that the cursor is
334 if (ddb->type != TEXT
336 /* I'm not sure exactly what this code wants to do, but it's
337 * not right--it doesn't update when cursor_elt changes from, e.g.,
338 * 0 to 8, and the new or old cursor loc overlaps this block.
339 * I've replaced it with the more conservative test below.
340 * -dkindred@cs.cmu.edu 23-Mar-1997 */
341 && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
342 || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
343 && (ddl->cursor_elt == -1 ||
346 && (cursor_start + cursor_width) >= start_pixpos
347 && cursor_start <= block_end))
349 && (cdl->cursor_elt != ddl->cursor_elt)
354 if (f->windows_structure_changed ||
357 cdl->ypos != ddl->ypos ||
358 cdl->ascent != ddl->ascent ||
359 cdl->descent != ddl->descent ||
360 cdl->clip != ddl->clip ||
370 while (start_pos < 0 && elt < stop_pos)
372 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
373 Dynarr_atp (ddb->runes, elt)))
383 /* If nothing has changed in the area where the blocks overlap, but
384 there are new blocks in the desired block, then adjust the start
385 point accordingly. */
386 if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes))
387 start_pos = stop_pos;
392 if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes))
395 stop_pos = Dynarr_length (ddb->runes);
399 /* If the lines have the same number of runes and we are not
400 forcing a full redraw because the display line has
401 changed position then we try and optimize how much of the
402 line we actually redraw by scanning backwards from the
403 end for the first changed rune. This optimization is
404 almost always triggered by face changes. */
406 int elt = Dynarr_length (ddb->runes) - 1;
408 while (elt > start_pos)
410 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
411 Dynarr_atp (ddb->runes, elt)))
419 DEVMETH (d, output_display_block, (w, ddl, d_block, start_pos,
420 stop_pos, start_pixpos,
421 cursor_start, cursor_width,
429 /*****************************************************************************
432 Clear the lefthand outside border.
433 ****************************************************************************/
435 clear_left_border (struct window *w, int y, int height)
437 struct frame *f = XFRAME (w->frame);
438 struct device *d = XDEVICE (f->device);
441 XSETWINDOW (window, w);
442 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
443 FRAME_LEFT_BORDER_START (f), y,
444 FRAME_BORDER_WIDTH (f), height));
447 /*****************************************************************************
450 Clear the righthand outside border.
451 ****************************************************************************/
453 clear_right_border (struct window *w, int y, int height)
455 struct frame *f = XFRAME (w->frame);
456 struct device *d = XDEVICE (f->device);
459 XSETWINDOW (window, w);
460 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
461 FRAME_RIGHT_BORDER_START (f),
462 y, FRAME_BORDER_WIDTH (f), height));
465 /*****************************************************************************
468 Ensure that the contents of the given display line is correct
469 on-screen. The force_ parameters are used by redisplay_move_cursor
470 to correctly update cursor locations and only cursor locations.
471 ****************************************************************************/
473 output_display_line (struct window *w, display_line_dynarr *cdla,
474 display_line_dynarr *ddla, int line, int force_start,
478 struct frame *f = XFRAME (w->frame);
479 struct device *d = XDEVICE (f->device);
480 struct buffer *b = XBUFFER (w->buffer);
481 struct buffer *old_b = window_display_buffer (w);
482 struct display_line *cdl, *ddl;
483 display_block_dynarr *cdba, *ddba;
484 int start_pixpos, end_pixpos;
485 int cursor_start, cursor_width, cursor_height;
487 int force = (force_start >= 0 || force_end >= 0);
488 int clear_border = 0;
491 if (cdla && line < Dynarr_length (cdla))
493 cdl = Dynarr_atp (cdla, line);
494 cdba = cdl->display_blocks;
502 ddl = Dynarr_atp (ddla, line); /* assert line < Dynarr_length (ddla) */
503 ddba = ddl->display_blocks;
505 if (force_start >= 0 && force_start >= ddl->bounds.left_out)
506 start_pixpos = force_start;
508 start_pixpos = ddl->bounds.left_out;
510 if (force_end >= 0 && force_end < ddl->bounds.right_out)
511 end_pixpos = force_end;
513 end_pixpos = ddl->bounds.right_out;
515 /* Get the cursor parameters. */
516 if (ddl->cursor_elt != -1)
518 struct display_block *db;
520 /* If the lines cursor parameter is not -1 then it indicates
521 which rune in the TEXT block contains the cursor. This means
522 that there must be at least one display block. The TEXT
523 block, if present, must always be the first display block. */
524 assert (Dynarr_length (ddba) != 0);
526 db = Dynarr_atp (ddba, 0);
527 assert (db->type == TEXT);
529 get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start,
530 &cursor_width, &cursor_height);
534 cursor_start = cursor_width = cursor_height = 0;
537 /* The modeline should only have a single block and it had better be
541 /* The shadow thickness check is necesssary if only the sign of
543 if (cdba && !w->shadow_thickness_changed)
545 must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0,
546 start_pixpos, 0, 0, 0);
550 DEVMETH (d, output_display_block, (w, ddl, 0, 0, -1, start_pixpos,
559 while (!ddl->modeline && start_pixpos < end_pixpos)
562 int next_start_pixpos;
564 block = get_next_display_block (ddl->bounds, ddba, start_pixpos,
567 /* If we didn't find a block then we should blank the area
568 between start_pos and next_start if necessary. */
569 if (block == NO_BLOCK)
571 /* We only erase those areas which were actually previously
572 covered by a display block unless the window structure
573 changed. In that case we clear all areas since the current
574 structures may actually represent a different buffer. */
575 while (start_pixpos < next_start_pixpos)
581 old_block = get_next_display_block (ddl->bounds, cdba,
582 start_pixpos, &block_end);
585 old_block = NO_BLOCK;
586 block_end = next_start_pixpos;
589 if (!cdba || old_block != NO_BLOCK || b != old_b ||
590 f->windows_structure_changed ||
593 (cdl && (cdl->ypos != ddl->ypos ||
594 cdl->ascent != ddl->ascent ||
595 cdl->descent != ddl->descent ||
596 cdl->clip != ddl->clip)))
598 int x, y, width, height;
603 y = ddl->ypos - ddl->ascent;
604 width = min (next_start_pixpos, block_end) - x;
605 height = ddl->ascent + ddl->descent - ddl->clip;
607 if (x < ddl->bounds.left_in)
608 face = Vleft_margin_face;
609 else if (x < ddl->bounds.right_in)
610 face = Vdefault_face;
611 else if (x < ddl->bounds.right_out)
612 face = Vright_margin_face;
620 XSETWINDOW (window, w);
622 /* Clear the empty area. */
623 DEVMETH (d, clear_region,
624 (window, get_builtin_face_cache_index (w,
626 x, y, width, height));
628 /* Mark that we should clear the border. This is
629 necessary because italic fonts may leave
630 droppings in the border. */
635 start_pixpos = min (next_start_pixpos, block_end);
640 struct display_block *cdb, *ddb;
645 old_block = get_next_display_block (ddl->bounds, cdba,
646 start_pixpos, &block_end);
648 old_block = NO_BLOCK;
650 ddb = Dynarr_atp (ddba, block);
651 cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
653 /* If there was formerly no block over the current
654 region or if it was a block of a different type, then
655 output the entire ddb. Otherwise, compare cdb and
656 ddb and output only the changed region. */
657 if (!force && cdb && ddb->type == cdb->type && b == old_b)
659 must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
661 cursor_start, cursor_width,
670 for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
672 struct rune *rb = Dynarr_atp (ddb->runes, elt);
674 if (start_pixpos >= rb->xpos
675 && start_pixpos < rb->xpos + rb->width)
678 if (end_pixpos > rb->xpos
679 && end_pixpos <= rb->xpos + rb->width)
682 if (last_elt > Dynarr_length (ddb->runes))
683 last_elt = Dynarr_length (ddb->runes);
689 DEVMETH (d, output_display_block, (w, ddl, block, first_elt,
692 cursor_start, cursor_width,
696 start_pixpos = next_start_pixpos;
700 /* Clear the internal border if we are next to it and the window
701 structure or frame size has changed or if something caused
702 clear_border to be tripped. */
703 /* #### Doing this on f->clear sucks but is necessary because of
704 window-local background values. */
705 if (f->windows_structure_changed || f->faces_changed || clear_border
708 int y = ddl->ypos - ddl->ascent;
709 int height = ddl->ascent + ddl->descent - ddl->clip;
713 y -= MODELINE_SHADOW_THICKNESS (w);
714 height += (2 * MODELINE_SHADOW_THICKNESS (w));
717 if (window_is_leftmost (w))
718 clear_left_border (w, y, height);
719 if (window_is_rightmost (w))
720 clear_right_border (w, y, height);
724 sync_display_line_structs (w, line, must_sync, cdla, ddla);
727 /*****************************************************************************
728 redisplay_move_cursor
730 For the given window W, move the cursor to NEW_POINT. Returns a
731 boolean indicating success or failure.
732 ****************************************************************************/
734 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
735 #define ADJ_ENDPOS (rb->endpos + dl->offset)
738 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
740 struct frame *f = XFRAME (w->frame);
741 struct device *d = XDEVICE (f->device);
743 display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
744 struct display_line *dl;
745 struct display_block *db;
747 int x = w->last_point_x[CURRENT_DISP];
748 int y = w->last_point_y[CURRENT_DISP];
751 * Bail if cursor_in_echo_area is non-zero and we're fiddling with
752 * the cursor in a non-active minibuffer window, since that is a
753 * special case that is handled elsewhere and this function need
754 * not handle it. Return 1 so the caller will assume we
757 if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
758 w != XWINDOW (FRAME_SELECTED_WINDOW (f)))
761 if (y < 0 || y >= Dynarr_length (cla))
764 dl = Dynarr_atp (cla, y);
765 db = get_display_block_from_line (dl, TEXT);
767 if (x < 0 || x >= Dynarr_length (db->runes))
770 rb = Dynarr_atp (db->runes, x);
772 if (rb->cursor_type == CURSOR_OFF)
774 else if (ADJ_BUFPOS == new_point
775 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
776 && (new_point <= ADJ_ENDPOS)))
778 w->last_point_x[CURRENT_DISP] = x;
779 w->last_point_y[CURRENT_DISP] = y;
780 Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
787 DEVMETH (d, output_begin, (d));
789 /* #### This is a gross kludge. Cursor handling is such a royal
791 if (rb->type == RUNE_DGLYPH &&
792 (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
793 EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
794 rb->cursor_type = NO_CURSOR;
796 rb->cursor_type = CURSOR_OFF;
798 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
801 w->last_point_x[CURRENT_DISP] = -1;
802 w->last_point_y[CURRENT_DISP] = -1;
803 Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
805 /* If this isn't the selected frame, then erasing the old cursor is
806 all we actually had to do. */
807 if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
810 DEVMETH (d, output_end, (d));
815 /* This should only occur in the minibuffer. */
818 w->last_point_x[CURRENT_DISP] = 0;
819 w->last_point_y[CURRENT_DISP] = y;
820 Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
822 rb = Dynarr_atp (db->runes, 0);
823 rb->cursor_type = CURSOR_ON;
826 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
829 DEVMETH (d, output_end, (d));
838 if (ADJ_BUFPOS < new_point)
844 else /* (rb->bufpos + dl->offset) > new_point */
861 while ((up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)))
863 dl = Dynarr_atp (cla, cur_dl);
864 db = get_display_block_from_line (dl, TEXT);
867 cur_rb = Dynarr_length (db->runes) - 1;
869 while ((!scroll_on_clipped_lines || !dl->clip) &&
870 (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
872 rb = Dynarr_atp (db->runes, cur_rb);
874 if (rb->cursor_type != IGNORE_CURSOR
875 && rb->cursor_type != NO_CURSOR &&
876 (ADJ_BUFPOS == new_point
877 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
878 && (new_point <= ADJ_BUFPOS))))
880 rb->cursor_type = CURSOR_ON;
881 dl->cursor_elt = cur_rb;
884 output_display_line (w, 0, cla, cur_dl, rb->xpos,
885 rb->xpos + rb->width);
887 w->last_point_x[CURRENT_DISP] = cur_rb;
888 w->last_point_y[CURRENT_DISP] = cur_dl;
889 Fset_marker (w->last_point[CURRENT_DISP],
890 make_int (ADJ_BUFPOS), w->buffer);
893 DEVMETH (d, output_end, (d));
897 (up ? cur_rb++ : cur_rb--);
900 (up ? (cur_rb = 0) : (first = 0));
901 (up ? cur_dl++ : cur_dl--);
906 DEVMETH (d, output_end, (d));
912 /*****************************************************************************
913 redraw_cursor_in_window
915 For the given window W, redraw the cursor if it is contained within
917 ****************************************************************************/
919 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
921 struct frame *f = XFRAME (w->frame);
922 struct device *d = XDEVICE (f->device);
924 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
925 struct display_line *dl;
926 struct display_block *db;
929 int x = w->last_point_x[CURRENT_DISP];
930 int y = w->last_point_y[CURRENT_DISP];
932 if (cursor_in_echo_area && MINI_WINDOW_P (w) &&
933 !echo_area_active (f) && minibuf_level == 0)
935 MAYBE_DEVMETH (d, set_final_cursor_coords, (f, w->pixel_top, 0));
938 if (y < 0 || y >= Dynarr_length (dla))
941 if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
942 !is_surrogate_for_selected_frame (f))
945 dl = Dynarr_atp (dla, y);
946 db = get_display_block_from_line (dl, TEXT);
948 if (x < 0 || x >= Dynarr_length (db->runes))
951 rb = Dynarr_atp (db->runes, x);
953 /* Don't call the output routine if the block isn't actually the
955 if (rb->cursor_type == CURSOR_ON)
957 MAYBE_DEVMETH (d, set_final_cursor_coords,
958 (f, dl->ypos - 1, rb->xpos));
960 if (run_end_begin_meths)
961 DEVMETH (d, output_begin, (d));
963 output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
965 if (run_end_begin_meths)
966 DEVMETH (d, output_end, (d));
970 /*****************************************************************************
971 redisplay_redraw_cursor
973 For the given frame F, redraw the cursor on the selected window.
974 This is used to update the cursor after focus changes.
975 ****************************************************************************/
977 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
981 if (!cursor_in_echo_area)
982 window = FRAME_SELECTED_WINDOW (f);
983 else if (FRAME_HAS_MINIBUF_P (f))
984 window = FRAME_MINIBUF_WINDOW (f);
988 redraw_cursor_in_window (XWINDOW (window), run_end_begin_meths);
991 /*****************************************************************************
992 redisplay_clear_top_of_window
994 If window is topmost, clear the internal border above it.
995 ****************************************************************************/
997 redisplay_clear_top_of_window (struct window *w)
1000 XSETWINDOW (window, w);
1002 if (!NILP (Fwindow_highest_p (window)))
1004 struct frame *f = XFRAME (w->frame);
1005 struct device *d = XDEVICE (f->device);
1006 int x, y, width, height;
1009 width = w->pixel_width;
1011 if (window_is_leftmost (w))
1013 x -= FRAME_BORDER_WIDTH (f);
1014 width += FRAME_BORDER_WIDTH (f);
1016 if (window_is_rightmost (w))
1017 width += FRAME_BORDER_WIDTH (f);
1019 y = FRAME_TOP_BORDER_START (f) - 1;
1020 height = FRAME_BORDER_HEIGHT (f) + 1;
1022 DEVMETH (d, clear_region, (window, DEFAULT_INDEX, x, y, width, height));
1026 /*****************************************************************************
1027 redisplay_clear_bottom_of_window
1029 Clear window from right below the last display line to right above
1030 the modeline. The calling function can limit the area actually
1031 erased by setting min_start and/or max_end to positive values.
1032 ****************************************************************************/
1034 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
1035 int min_start, int max_end)
1037 struct frame *f = XFRAME (w->frame);
1038 struct device *d = XDEVICE (f->device);
1040 int ddla_len = Dynarr_length (ddla);
1042 ypos2 = WINDOW_TEXT_BOTTOM (w);
1043 #ifdef HAVE_SCROLLBARS
1044 /* This adjustment is to catch the intersection of any scrollbars. */
1045 if (f->windows_structure_changed && NILP (w->scrollbar_on_top_p))
1046 ypos2 += window_scrollbar_height (w);
1051 if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
1053 ypos1 = WINDOW_TEXT_TOP (w);
1054 #ifdef HAVE_SCROLLBARS
1055 /* This adjustment is to catch the intersection of any scrollbars. */
1056 if (f->windows_structure_changed && !NILP (w->scrollbar_on_top_p))
1057 ypos1 -= window_scrollbar_height (w);
1062 struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
1063 ypos1 = dl->ypos + dl->descent - dl->clip;
1067 ypos1 = WINDOW_TEXT_TOP (w);
1069 /* #### See if this can be made conditional on the frame
1071 if (MINI_WINDOW_P (w))
1072 ypos2 += FRAME_BORDER_HEIGHT (f);
1074 if (min_start >= 0 && ypos1 < min_start)
1076 if (max_end >= 0 && ypos2 > max_end)
1082 DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1085 /*****************************************************************************
1086 redisplay_update_line
1088 This is used during incremental updates to update a single line and
1089 correct the offsets on all lines below it. At the moment
1090 update_values is false if we are only updating the modeline.
1091 ****************************************************************************/
1093 redisplay_update_line (struct window *w, int first_line, int last_line,
1096 struct frame *f = XFRAME (w->frame);
1097 struct device *d = XDEVICE (f->device);
1099 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1100 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1102 DEVMETH (d, output_begin, (d));
1104 while (first_line <= last_line)
1106 Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
1107 Dynarr_atp (cdla, first_line)->bufpos);
1108 Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
1109 Dynarr_atp (ddla, first_line)->bufpos);
1111 assert (Dynarr_length (cdla) == Dynarr_length (ddla));
1113 /* Output the changes. */
1114 output_display_line (w, cdla, ddla, first_line, -1, -1);
1116 /* Update the offsets. */
1119 int cur_line = first_line + 1;
1120 while (cur_line < Dynarr_length (cdla))
1122 Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
1123 Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
1128 /* Update the window_end_pos and other settings. */
1131 w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
1133 if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
1135 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1136 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1143 /* Update the window max line length. We have to scan the entire
1144 set of display lines otherwise we might not detect if the max is
1145 supposed to shrink. */
1150 w->max_line_len = 0;
1151 while (line < Dynarr_length (ddla))
1153 struct display_line *dl = Dynarr_atp (ddla, line);
1156 w->max_line_len = max (dl->num_chars, w->max_line_len);
1162 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1163 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1164 Fset_marker (w->last_point[CURRENT_DISP],
1165 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1166 Fset_marker (w->last_start[CURRENT_DISP],
1167 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1169 /* We don't bother updating the vertical scrollbars here. This
1170 gives us a performance increase while having minimal loss of
1171 quality to the scrollbar slider size and position since when this
1172 function is called we know that the changes to the buffer were
1173 very localized. We have to update the horizontal scrollbars,
1174 though, because this routine could cause a change which has a
1175 larger impact on their sizing. */
1176 /* #### See if we can get away with only calling this if
1177 max_line_len is greater than the window_char_width. */
1178 #if defined(HAVE_SCROLLBARS) && defined(HAVE_X_WINDOWS)
1180 extern int stupid_vertical_scrollbar_drag_hack;
1182 update_window_scrollbars (w, NULL, 1, stupid_vertical_scrollbar_drag_hack);
1183 stupid_vertical_scrollbar_drag_hack = 1;
1187 /* This has to be done after we've updated the values. We don't
1188 call output_end for tty frames. Redisplay will do this after all
1189 tty windows have been updated. This cuts down on cursor
1191 if (FRAME_TTY_P (f))
1192 redisplay_redraw_cursor (f, 0);
1194 DEVMETH (d, output_end, (d));
1197 /*****************************************************************************
1198 redisplay_output_window
1200 For the given window W, ensure that the current display lines are
1201 equal to the desired display lines, outputing changes as necessary.
1203 #### Fuck me. This just isn't going to cut it for tty's. The output
1204 decisions for them must be based on the contents of the entire frame
1205 because that is how the available output capabilities think. The
1206 solution is relatively simple. Create redisplay_output_frame. This
1207 will basically merge all of the separate window display structs into
1208 a single one for the frame. This combination structure will be able
1209 to be passed to the same output_display_line which works for windows
1210 on X frames and the right things will happen. It just takes time to
1212 ****************************************************************************/
1214 redisplay_output_window (struct window *w)
1216 struct frame *f = XFRAME (w->frame);
1217 struct device *d = XDEVICE (f->device);
1219 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1220 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1222 int cdla_len = Dynarr_length (cdla);
1223 int ddla_len = Dynarr_length (ddla);
1226 int need_to_clear_bottom = 0;
1227 int need_to_clear_start = -1;
1228 int need_to_clear_end = -1;
1230 /* Backgrounds may have changed or windows may have gone away
1231 leaving dividers lying around. */
1232 if (f->faces_changed
1233 || f->windows_structure_changed
1234 || w->shadow_thickness_changed)
1235 need_to_clear_bottom = 1;
1237 /* The first thing we do is determine if we are going to need to
1238 clear the bottom of the window. We only need to do this if the
1239 bottom of the current display lines is below the bottom of the
1240 desired display lines. Note that the number of lines is
1241 irrelevant. Only the position matters. We also clear to the
1242 bottom of the window if the modeline has shifted position. */
1243 /* #### We can't blindly not clear the bottom if f->clear is true
1244 since there might be a window-local background. However, for
1245 those cases where there isn't, clearing the end of the window in
1247 if (!need_to_clear_bottom)
1249 struct display_line *cdl, *ddl;
1251 /* If the modeline has changed position or size, clear the bottom
1253 if (!need_to_clear_bottom)
1258 cdl = Dynarr_atp (cdla, 0);
1260 ddl = Dynarr_atp (ddla, 0);
1263 need_to_clear_bottom = 1;
1264 else if ((!cdl->modeline && ddl->modeline)
1265 || (cdl->modeline && !ddl->modeline))
1266 need_to_clear_bottom = 1;
1267 else if (cdl->ypos != ddl->ypos ||
1268 cdl->ascent != ddl->ascent ||
1269 cdl->descent != ddl->descent ||
1270 cdl->clip != ddl->clip)
1271 need_to_clear_bottom = 1;
1273 /* #### This kludge is to make sure the modeline shadows get
1274 redrawn if the modeline position shifts. */
1275 if (need_to_clear_bottom)
1276 w->shadow_thickness_changed = 1;
1279 if (!need_to_clear_bottom)
1284 cdl = Dynarr_atp (cdla, cdla_len - 1);
1286 ddl = Dynarr_atp (ddla, ddla_len - 1);
1289 need_to_clear_bottom = 1;
1292 int cdl_bottom, ddl_bottom;
1294 cdl_bottom = cdl->ypos + cdl->descent;
1295 ddl_bottom = ddl->ypos + ddl->descent;
1297 if (cdl_bottom > ddl_bottom)
1299 need_to_clear_bottom = 1;
1300 need_to_clear_start = ddl_bottom;
1301 need_to_clear_end = cdl_bottom;
1307 /* Perform any output initialization. */
1308 DEVMETH (d, output_begin, (d));
1310 /* If the window's structure has changed clear the internal border
1311 above it if it is topmost (the function will check). */
1312 if (f->windows_structure_changed)
1313 redisplay_clear_top_of_window (w);
1315 /* Output each line. */
1316 for (line = 0; line < Dynarr_length (ddla); line++)
1318 output_display_line (w, cdla, ddla, line, -1, -1);
1321 /* If the number of display lines has shrunk, adjust. */
1322 if (cdla_len > ddla_len)
1324 Dynarr_length (cdla) = ddla_len;
1327 /* Output a vertical divider between windows, if necessary. */
1328 if (window_needs_vertical_divider (w)
1329 && (f->windows_structure_changed || f->clear))
1331 DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
1334 /* Clear the rest of the window, if necessary. */
1335 if (need_to_clear_bottom)
1337 redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
1341 w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
1342 Fset_marker (w->start[CURRENT_DISP],
1343 make_int (marker_position (w->start[DESIRED_DISP])),
1345 Fset_marker (w->pointm[CURRENT_DISP],
1346 make_int (marker_position (w->pointm[DESIRED_DISP])),
1348 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1349 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1350 Fset_marker (w->last_start[CURRENT_DISP],
1351 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1352 Fset_marker (w->last_point[CURRENT_DISP],
1353 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1354 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1355 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1356 w->shadow_thickness_changed = 0;
1358 set_window_display_buffer (w, XBUFFER (w->buffer));
1359 find_window_mirror (w)->truncate_win = window_truncation_on (w);
1361 /* Overkill on invalidating the cache. It is very bad for it to not
1362 get invalidated when it should be. */
1363 INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
1365 /* We don't call output_end for tty frames. Redisplay will do this
1366 after all tty windows have been updated. This cuts down on
1368 if (FRAME_TTY_P (f))
1369 redisplay_redraw_cursor (f, 0);
1371 DEVMETH (d, output_end, (d));
1373 #ifdef HAVE_SCROLLBARS
1374 update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);