comparison src/redisplay-output.c @ 0:376386a54a3c r19-14

Import from CVS: tag r19-14
author cvs
date Mon, 13 Aug 2007 08:45:50 +0200
parents
children 0293115a14e9
comparison
equal deleted inserted replaced
-1:000000000000 0:376386a54a3c
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.
5
6 This file is part of XEmacs.
7
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
11 later version.
12
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
16 for more details.
17
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. */
22
23 /* Synched up with: Not in FSF. */
24
25 /* This file has been Mule-ized. */
26
27 /* Author: Chuck Thompson */
28
29 #include <config.h>
30 #include "lisp.h"
31 #include "debug.h"
32
33 #include "buffer.h"
34 #include "window.h"
35 #include "frame.h"
36 #include "device.h"
37 #include "glyphs.h"
38 #include "redisplay.h"
39 #include "faces.h"
40
41 #include "sysdep.h"
42
43 static int compare_runes (struct window *w, struct rune *crb,
44 struct rune *drb);
45 static void redraw_cursor_in_window (struct window *w,
46 int run_end_begin_glyphs);
47 void redisplay_output_window (struct window *w);
48
49 /*****************************************************************************
50 sync_rune_structs
51
52 Synchronize the given rune blocks.
53 ****************************************************************************/
54 static void
55 sync_rune_structs (struct window *w, rune_dynarr *cra, rune_dynarr *dra)
56 {
57 int rune_elt;
58 int max_move = ((Dynarr_length (dra) > Dynarr_largest (cra))
59 ? Dynarr_largest (cra)
60 : Dynarr_length (dra));
61
62 if (max_move)
63 {
64 /* #### Doing this directly breaks the encapsulation. But, the
65 running time of this function has a measurable impact on
66 redisplay performance so avoiding all excess overhead is a
67 good thing. Is all of this true? */
68 memcpy (cra->base, dra->base, sizeof (struct rune) * max_move);
69 Dynarr_set_size (cra, max_move);
70 }
71 else
72 Dynarr_reset (cra);
73
74 for (rune_elt = max_move; rune_elt < Dynarr_length (dra); rune_elt++)
75 {
76 struct rune rb, *crb;
77 struct rune *drb = Dynarr_atp (dra, rune_elt);
78
79 crb = &rb;
80 memcpy (crb, drb, sizeof (struct rune));
81 Dynarr_add (cra, *crb);
82 }
83 }
84
85 /*****************************************************************************
86 sync_display_line_structs
87
88 For the given LINE in window W, make the current display line equal
89 the desired display line.
90 ****************************************************************************/
91 static void
92 sync_display_line_structs (struct window *w, int line, int do_blocks,
93 display_line_dynarr *cdla,
94 display_line_dynarr *ddla)
95 {
96 int cdla_len = Dynarr_length (cdla);
97
98 struct display_line dl, *clp, *dlp;
99 int db_elt;
100
101 dlp = Dynarr_atp (ddla, line);
102 if (line >= Dynarr_largest (cdla))
103 {
104 clp = &dl;
105 clp->display_blocks = Dynarr_new (struct display_block);
106 }
107 else
108 {
109 clp = Dynarr_atp (cdla, line);
110 if (clp->display_blocks)
111 Dynarr_reset (clp->display_blocks);
112 if (clp->left_glyphs)
113 {
114 Dynarr_free (clp->left_glyphs);
115 clp->left_glyphs = 0;
116 }
117 if (clp->right_glyphs)
118 {
119 Dynarr_free (clp->right_glyphs);
120 clp->right_glyphs = 0;
121 }
122 }
123 {
124 display_block_dynarr *tdb = clp->display_blocks;
125
126 memcpy (clp, dlp, sizeof (struct display_line));
127 clp->display_blocks = tdb;
128 clp->left_glyphs = 0;
129 clp->right_glyphs = 0;
130 }
131
132 if (!do_blocks && line >= cdla_len)
133 {
134 Dynarr_add (cdla, *clp);
135 return;
136 }
137
138 for (db_elt = 0; db_elt < Dynarr_length (dlp->display_blocks); db_elt++)
139 {
140 struct display_block db, *cdb;
141 struct display_block *ddb = Dynarr_atp (dlp->display_blocks, db_elt);
142
143 if (db_elt >= Dynarr_largest (clp->display_blocks))
144 {
145 cdb = &db;
146 memcpy (cdb, ddb, sizeof (struct display_block));
147 cdb->runes = Dynarr_new (struct rune);
148 Dynarr_add (clp->display_blocks, *cdb);
149 }
150 else
151 {
152 rune_dynarr *tr;
153
154 cdb = Dynarr_atp (clp->display_blocks, db_elt);
155 tr = cdb->runes;
156 memcpy (cdb, ddb, sizeof (struct display_block));
157 cdb->runes = tr;
158 Dynarr_increment (clp->display_blocks);
159 }
160
161 sync_rune_structs (w, cdb->runes, ddb->runes);
162 }
163
164 if (line >= cdla_len)
165 Dynarr_add (cdla, *clp);
166 }
167
168 /*****************************************************************************
169 compare_runes
170
171 Compare to runes to see if each of their fields is equal. If so,
172 return true otherwise return false.
173 ****************************************************************************/
174 static int
175 compare_runes (struct window *w, struct rune *crb, struct rune *drb)
176 {
177 /* Do not compare the values of bufpos and endpos. They do not
178 affect the display characteristics. */
179
180 if ((crb->findex != drb->findex) ||
181 (WINDOW_FACE_CACHEL_DIRTY (w, drb->findex)))
182 return 0;
183 else if (crb->xpos != drb->xpos)
184 return 0;
185 else if (crb->width != drb->width)
186 return 0;
187 else if (crb->cursor_type != drb->cursor_type)
188 return 0;
189 else if (crb->type != drb->type)
190 return 0;
191 else if (crb->type == RUNE_CHAR &&
192 (crb->object.chr.ch != drb->object.chr.ch))
193 return 0;
194 else if (crb->type == RUNE_DGLYPH &&
195 (!EQ (crb->object.dglyph.glyph, drb->object.dglyph.glyph) ||
196 !EQ (crb->object.dglyph.extent, drb->object.dglyph.extent) ||
197 crb->object.dglyph.xoffset != drb->object.dglyph.xoffset))
198 return 0;
199 else if (crb->type == RUNE_HLINE &&
200 (crb->object.hline.thickness != drb->object.hline.thickness ||
201 crb->object.hline.yoffset != drb->object.hline.yoffset))
202 return 0;
203 else
204 return 1;
205 }
206
207 /*****************************************************************************
208 get_next_display_block
209
210 Return the next display starting at or overlapping START_POS. Return
211 the start of the next region in NEXT_START.
212 ****************************************************************************/
213 int
214 get_next_display_block (layout_bounds bounds, display_block_dynarr *dba,
215 int start_pos, int *next_start)
216 {
217 int next_display_block = NO_BLOCK;
218 int priority = -1;
219 int block;
220
221 /* If we don't find a display block covering or starting at
222 start_pos, then we return the starting point of the next display
223 block or the next division boundary, whichever is closer to
224 start_pos. */
225 if (next_start)
226 {
227 if (start_pos >= bounds.left_out && start_pos < bounds.left_in)
228 *next_start = bounds.left_in;
229 else if (start_pos < bounds.left_white)
230 *next_start = bounds.left_white;
231 else if (start_pos < bounds.right_white)
232 *next_start = bounds.right_white;
233 else if (start_pos < bounds.right_in)
234 *next_start = bounds.right_in;
235 else if (start_pos <= bounds.right_out)
236 *next_start = bounds.right_out;
237 else
238 abort ();
239 }
240
241 for (block = 0; block < Dynarr_length (dba); block++)
242 {
243 struct display_block *db = Dynarr_atp (dba, block);
244
245 if (db->start_pos <= start_pos && db->end_pos > start_pos)
246 {
247 if ((int) db->type > priority)
248 {
249 priority = db->type;
250 next_display_block = block;
251 if (next_start)
252 *next_start = db->end_pos;
253 }
254 }
255 else if (next_start && db->start_pos > start_pos)
256 {
257 if (db->start_pos < *next_start)
258 *next_start = db->start_pos;
259 }
260 }
261
262 return next_display_block;
263 }
264
265 /*****************************************************************************
266 get_cursor_size_and_location
267
268 Return the information defining the pixel location of the cursor.
269 ****************************************************************************/
270 static void
271 get_cursor_size_and_location (struct window *w, struct display_block *db,
272 int cursor_location,
273 int *cursor_start, int *cursor_width,
274 int *cursor_height)
275 {
276 struct rune *rb;
277 Lisp_Object window = Qnil;
278 int defheight, defwidth;
279
280 if (Dynarr_length (db->runes) <= cursor_location)
281 abort ();
282
283 XSETWINDOW (window, w);
284
285 rb = Dynarr_atp (db->runes, cursor_location);
286 *cursor_start = rb->xpos;
287
288 default_face_height_and_width (window, &defheight, &defwidth);
289 *cursor_height = defheight;
290
291 if (rb->type == RUNE_BLANK)
292 *cursor_width = defwidth;
293 else
294 *cursor_width = rb->width;
295 }
296
297 /*****************************************************************************
298 compare_display_blocks
299
300 Given two display blocks, output only those areas where they differ.
301 ****************************************************************************/
302 static int
303 compare_display_blocks (struct window *w, struct display_line *cdl,
304 struct display_line *ddl, int c_block, int d_block,
305 int start_pixpos, int cursor_start, int cursor_width,
306 int cursor_height)
307 {
308 struct frame *f = XFRAME (w->frame);
309 struct device *d = XDEVICE (f->device);
310
311 struct display_block *cdb, *ddb;
312 int start_pos;
313 int stop_pos;
314 int force = 0;
315 int block_end;
316
317 cdb = Dynarr_atp (cdl->display_blocks, c_block);
318 ddb = Dynarr_atp (ddl->display_blocks, d_block);
319
320 assert (cdb->type == ddb->type);
321
322 start_pos = -1;
323 stop_pos = min (Dynarr_length (cdb->runes), Dynarr_length (ddb->runes));
324
325 block_end =
326 (!Dynarr_length (ddb->runes)
327 ? 0
328 : (Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->xpos +
329 Dynarr_atp (ddb->runes, Dynarr_length (ddb->runes) - 1)->width));
330
331 /* If the new block type is not text and the cursor status is
332 changing and it overlaps the position of this block then force a
333 full redraw of the block in order to make sure that the cursor is
334 updated properly. */
335 if (ddb->type != TEXT
336 && ((cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
337 || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1))
338 && (ddl->cursor_elt == -1 ||
339 (cursor_start
340 && cursor_width
341 && (cursor_start + cursor_width) >= start_pixpos
342 && cursor_start <= block_end)))
343 force = 1;
344
345 if (f->windows_structure_changed ||
346 f->faces_changed ||
347 cdl->ypos != ddl->ypos ||
348 cdl->ascent != ddl->ascent ||
349 cdl->descent != ddl->descent ||
350 cdl->clip != ddl->clip ||
351 force)
352 {
353 start_pos = 0;
354 force = 1;
355 }
356 else
357 {
358 int elt = 0;
359
360 while (start_pos < 0 && elt < stop_pos)
361 {
362 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
363 Dynarr_atp (ddb->runes, elt)))
364 {
365 start_pos = elt;
366 }
367 else
368 {
369 elt++;
370 }
371 }
372
373 /* If nothing has changed in the area where the blocks overlap, but
374 there are new blocks in the desired block, then adjust the start
375 point accordingly. */
376 if (elt == stop_pos && stop_pos < Dynarr_length (ddb->runes))
377 start_pos = stop_pos;
378 }
379
380 if (start_pos >= 0)
381 {
382 if ((Dynarr_length (ddb->runes) != Dynarr_length (cdb->runes))
383 || force)
384 {
385 stop_pos = Dynarr_length (ddb->runes);
386 }
387 else
388 {
389 /* If the lines have the same number of runes and we are not
390 forcing a full redraw because the display line has
391 changed position then we try and optimize how much of the
392 line we actually redraw by scanning backwards from the
393 end for the first changed rune. This optimization is
394 almost always triggered by face changes. */
395
396 int elt = Dynarr_length (ddb->runes) - 1;
397
398 while (elt > start_pos)
399 {
400 if (!compare_runes (w, Dynarr_atp (cdb->runes, elt),
401 Dynarr_atp (ddb->runes, elt)))
402 break;
403 else
404 elt--;
405 }
406 stop_pos = elt + 1;
407 }
408
409 DEVMETH (d, output_display_block, (w, ddl, d_block, start_pos,
410 stop_pos, start_pixpos,
411 cursor_start, cursor_width,
412 cursor_height));
413 return 1;
414 }
415
416 return 0;
417 }
418
419 /*****************************************************************************
420 clear_left_border
421
422 Clear the lefthand outside border.
423 ****************************************************************************/
424 static void
425 clear_left_border (struct window *w, int y, int height)
426 {
427 struct frame *f = XFRAME (w->frame);
428 struct device *d = XDEVICE (f->device);
429 Lisp_Object window;
430
431 XSETWINDOW (window, w);
432 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
433 FRAME_LEFT_BORDER_START (f), y,
434 FRAME_BORDER_WIDTH (f), height));
435 }
436
437 /*****************************************************************************
438 clear_right_border
439
440 Clear the righthand outside border.
441 ****************************************************************************/
442 static void
443 clear_right_border (struct window *w, int y, int height)
444 {
445 struct frame *f = XFRAME (w->frame);
446 struct device *d = XDEVICE (f->device);
447 Lisp_Object window;
448
449 XSETWINDOW (window, w);
450 DEVMETH (d, clear_region, (window, DEFAULT_INDEX,
451 FRAME_RIGHT_BORDER_START (f),
452 y, FRAME_BORDER_WIDTH (f), height));
453 }
454
455 /*****************************************************************************
456 output_display_line
457
458 Ensure that the contents of the given display line is correct
459 on-screen. The force_ parameters are used by redisplay_move_cursor
460 to correctly update cursor locations and only cursor locations.
461 ****************************************************************************/
462 void
463 output_display_line (struct window *w, display_line_dynarr *cdla,
464 display_line_dynarr *ddla, int line, int force_start,
465 int force_end)
466
467 {
468 struct frame *f = XFRAME (w->frame);
469 struct device *d = XDEVICE (f->device);
470 struct buffer *b = XBUFFER (w->buffer);
471 struct buffer *old_b = window_display_buffer (w);
472 struct display_line *cdl, *ddl;
473 display_block_dynarr *cdba, *ddba;
474 int start_pixpos, end_pixpos;
475 int cursor_start, cursor_width, cursor_height;
476
477 int force = (force_start >= 0 || force_end >= 0);
478 int clear_border = 0;
479 int must_sync = 0;
480
481 if (cdla && line < Dynarr_length (cdla))
482 {
483 cdl = Dynarr_atp (cdla, line);
484 cdba = cdl->display_blocks;
485 }
486 else
487 {
488 cdl = NULL;
489 cdba = NULL;
490 }
491
492 ddl = Dynarr_atp (ddla, line); /* assert line < Dynarr_length (ddla) */
493 ddba = ddl->display_blocks;
494
495 if (force_start >= 0 && force_start >= ddl->bounds.left_out)
496 start_pixpos = force_start;
497 else
498 start_pixpos = ddl->bounds.left_out;
499
500 if (force_end >= 0 && force_end < ddl->bounds.right_out)
501 end_pixpos = force_end;
502 else
503 end_pixpos = ddl->bounds.right_out;
504
505 /* Get the cursor parameters. */
506 if (ddl->cursor_elt != -1)
507 {
508 struct display_block *db;
509
510 /* If the lines cursor parameter is not -1 then it indicates
511 which rune in the TEXT block contains the cursor. This means
512 that there must be at least one display block. The TEXT
513 block, if present, must always be the first display block. */
514 assert (Dynarr_length (ddba) != 0);
515
516 db = Dynarr_atp (ddba, 0);
517 assert (db->type == TEXT);
518
519 get_cursor_size_and_location (w, db, ddl->cursor_elt, &cursor_start,
520 &cursor_width, &cursor_height);
521 }
522 else
523 {
524 cursor_start = cursor_width = cursor_height = 0;
525 }
526
527 /* The modeline should only have a single block and it had better be
528 a TEXT block. */
529 if (ddl->modeline)
530 {
531 /* The shadow thickness check is necesssary if only the sign of
532 the size changed. */
533 if (cdba && !w->shadow_thickness_changed)
534 {
535 must_sync |= compare_display_blocks (w, cdl, ddl, 0, 0,
536 start_pixpos, 0, 0, 0);
537 }
538 else
539 {
540 DEVMETH (d, output_display_block, (w, ddl, 0, 0, -1, start_pixpos,
541 0, 0, 0));
542 must_sync = 1;
543 }
544
545 if (must_sync)
546 clear_border = 1;
547 }
548
549 while (!ddl->modeline && start_pixpos < end_pixpos)
550 {
551 int block;
552 int next_start_pixpos;
553
554 block = get_next_display_block (ddl->bounds, ddba, start_pixpos,
555 &next_start_pixpos);
556
557 /* If we didn't find a block then we should blank the area
558 between start_pos and next_start if necessary. */
559 if (block == NO_BLOCK)
560 {
561 /* We only erase those areas which were actually previously
562 covered by a display block unless the window structure
563 changed. In that case we clear all areas since the current
564 structures may actually represent a different buffer. */
565 while (start_pixpos < next_start_pixpos)
566 {
567 int block_end;
568 int old_block;
569
570 if (cdba)
571 old_block = get_next_display_block (ddl->bounds, cdba,
572 start_pixpos, &block_end);
573 else
574 {
575 old_block = NO_BLOCK;
576 block_end = next_start_pixpos;
577 }
578
579 if (!cdba || old_block != NO_BLOCK || b != old_b ||
580 f->windows_structure_changed ||
581 f->faces_changed ||
582 force ||
583 (cdl && (cdl->ypos != ddl->ypos ||
584 cdl->ascent != ddl->ascent ||
585 cdl->descent != ddl->descent ||
586 cdl->clip != ddl->clip)))
587 {
588 int x, y, width, height;
589 Lisp_Object face;
590
591 must_sync = 1;
592 x = start_pixpos;
593 y = ddl->ypos - ddl->ascent;
594 width = min (next_start_pixpos, block_end) - x;
595 height = ddl->ascent + ddl->descent - ddl->clip;
596
597 if (x < ddl->bounds.left_in)
598 face = Vleft_margin_face;
599 else if (x < ddl->bounds.right_in)
600 face = Vdefault_face;
601 else if (x < ddl->bounds.right_out)
602 face = Vright_margin_face;
603 else
604 face = Qnil;
605
606 if (!NILP (face))
607 {
608 Lisp_Object window;
609
610 XSETWINDOW (window, w);
611
612 /* Clear the empty area. */
613 DEVMETH (d, clear_region,
614 (window, get_builtin_face_cache_index (w,
615 face),
616 x, y, width, height));
617
618 /* Mark that we should clear the border. This is
619 necessary because italic fonts may leave
620 droppings in the border. */
621 clear_border = 1;
622 }
623 }
624
625 start_pixpos = min (next_start_pixpos, block_end);
626 }
627 }
628 else
629 {
630 struct display_block *cdb, *ddb;
631 int block_end;
632 int old_block;
633
634 if (cdba)
635 old_block = get_next_display_block (ddl->bounds, cdba,
636 start_pixpos, &block_end);
637 else
638 old_block = NO_BLOCK;
639
640 ddb = Dynarr_atp (ddba, block);
641 cdb = (old_block != NO_BLOCK ? Dynarr_atp (cdba, old_block) : 0);
642
643 /* If there was formerly no block over the current
644 region or if it was a block of a different type, then
645 output the entire ddb. Otherwise, compare cdb and
646 ddb and output only the changed region. */
647 if (!force && cdb && ddb->type == cdb->type && b == old_b)
648 {
649 must_sync |= compare_display_blocks (w, cdl, ddl, old_block,
650 block, start_pixpos,
651 cursor_start, cursor_width,
652 cursor_height);
653 }
654 else
655 {
656 int elt;
657 int first_elt = 0;
658 int last_elt = -1;
659
660 for (elt = 0; elt < Dynarr_length (ddb->runes); elt++)
661 {
662 struct rune *rb = Dynarr_atp (ddb->runes, elt);
663
664 if (start_pixpos >= rb->xpos
665 && start_pixpos < rb->xpos + rb->width)
666 first_elt = elt;
667
668 if (end_pixpos > rb->xpos
669 && end_pixpos <= rb->xpos + rb->width)
670 {
671 last_elt = elt + 1;
672 if (last_elt > Dynarr_length (ddb->runes))
673 last_elt = Dynarr_length (ddb->runes);
674 break;
675 }
676 }
677
678 must_sync = 1;
679 DEVMETH (d, output_display_block, (w, ddl, block, first_elt,
680 last_elt,
681 start_pixpos,
682 cursor_start, cursor_width,
683 cursor_height));
684 }
685
686 start_pixpos = next_start_pixpos;
687 }
688 }
689
690 /* Clear the internal border if we are next to it and the window
691 structure or frame size has changed or if something caused
692 clear_border to be tripped. */
693 /* #### Doing this on f->clear sucks but is necessary because of
694 window-local background values. */
695 if (f->windows_structure_changed || f->faces_changed || clear_border
696 || f->clear)
697 {
698 int y = ddl->ypos - ddl->ascent;
699 int height = ddl->ascent + ddl->descent - ddl->clip;
700
701 if (ddl->modeline)
702 {
703 y -= MODELINE_SHADOW_THICKNESS (w);
704 height += (2 * MODELINE_SHADOW_THICKNESS (w));
705 }
706
707 if (window_is_leftmost (w))
708 clear_left_border (w, y, height);
709 if (window_is_rightmost (w))
710 clear_right_border (w, y, height);
711 }
712
713 if (cdla)
714 sync_display_line_structs (w, line, must_sync, cdla, ddla);
715 }
716
717 /*****************************************************************************
718 redisplay_move_cursor
719
720 For the given window W, move the cursor to NEW_POINT. Returns a
721 boolean indicating success or failure.
722 ****************************************************************************/
723
724 #define ADJ_BUFPOS (rb->bufpos + dl->offset)
725 #define ADJ_ENDPOS (rb->endpos + dl->offset)
726
727 int
728 redisplay_move_cursor (struct window *w, Bufpos new_point, int no_output_end)
729 {
730 struct frame *f = XFRAME (w->frame);
731 struct device *d = XDEVICE (f->device);
732
733 display_line_dynarr *cla = window_display_lines (w, CURRENT_DISP);
734 struct display_line *dl;
735 struct display_block *db;
736 struct rune *rb;
737
738 int x = w->last_point_x[CURRENT_DISP];
739 int y = w->last_point_y[CURRENT_DISP];
740
741 if (y < 0 || y >= Dynarr_length (cla))
742 return 0;
743
744 dl = Dynarr_atp (cla, y);
745 db = get_display_block_from_line (dl, TEXT);
746
747 if (x < 0 || x >= Dynarr_length (db->runes))
748 return 0;
749
750 rb = Dynarr_atp (db->runes, x);
751
752 if (rb->cursor_type == CURSOR_OFF)
753 return 0;
754 else if (ADJ_BUFPOS == new_point
755 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
756 && (new_point <= ADJ_ENDPOS)))
757 {
758 w->last_point_x[CURRENT_DISP] = x;
759 w->last_point_y[CURRENT_DISP] = y;
760 Fset_marker (w->last_point[CURRENT_DISP], make_int (ADJ_BUFPOS),
761 w->buffer);
762 dl->cursor_elt = x;
763 return 1;
764 }
765 else
766 {
767 DEVMETH (d, output_begin, (d));
768
769 /* #### This is a gross kludge. Cursor handling is such a royal
770 pain in the ass. */
771 if (rb->type == RUNE_DGLYPH &&
772 (EQ (rb->object.dglyph.glyph, Vtruncation_glyph) ||
773 EQ (rb->object.dglyph.glyph, Vcontinuation_glyph)))
774 rb->cursor_type = NO_CURSOR;
775 else
776 rb->cursor_type = CURSOR_OFF;
777 dl->cursor_elt = -1;
778 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
779 }
780
781 w->last_point_x[CURRENT_DISP] = -1;
782 w->last_point_y[CURRENT_DISP] = -1;
783 Fset_marker (w->last_point[CURRENT_DISP], Qnil, w->buffer);
784
785 /* If this isn't the selected frame, then erasing the old cursor is
786 all we actually had to do. */
787 if (w != XWINDOW (FRAME_SELECTED_WINDOW (device_selected_frame (d))))
788 {
789 if (!no_output_end)
790 DEVMETH (d, output_end, (d));
791
792 return 1;
793 }
794
795 /* This should only occur in the minibuffer. */
796 if (new_point == 0)
797 {
798 w->last_point_x[CURRENT_DISP] = 0;
799 w->last_point_y[CURRENT_DISP] = y;
800 Fset_marker (w->last_point[CURRENT_DISP], Qzero, w->buffer);
801
802 rb = Dynarr_atp (db->runes, 0);
803 rb->cursor_type = CURSOR_ON;
804 dl->cursor_elt = 0;
805
806 output_display_line (w, 0, cla, y, rb->xpos, rb->xpos + rb->width);
807
808 if (!no_output_end)
809 DEVMETH (d, output_end, (d));
810 return 1;
811 }
812 else
813 {
814 int cur_rb = 0;
815 int first = 0;
816 int cur_dl, up;
817
818 if (ADJ_BUFPOS < new_point)
819 {
820 up = 1;
821 cur_rb = x + 1;
822 cur_dl = y;
823 }
824 else /* (rb->bufpos + dl->offset) > new_point */
825 {
826 up = 0;
827
828 if (!x)
829 {
830 cur_dl = y - 1;
831 first = 0;
832 }
833 else
834 {
835 cur_rb = x - 1;
836 cur_dl = y;
837 first = 1;
838 }
839 }
840
841 while ((up ? (cur_dl < Dynarr_length (cla)) : (cur_dl >= 0)))
842 {
843 dl = Dynarr_atp (cla, cur_dl);
844 db = get_display_block_from_line (dl, TEXT);
845
846 if (!up && !first)
847 cur_rb = Dynarr_length (db->runes) - 1;
848
849 while ((!scroll_on_clipped_lines || !dl->clip) &&
850 (up ? (cur_rb < Dynarr_length (db->runes)) : (cur_rb >= 0)))
851 {
852 rb = Dynarr_atp (db->runes, cur_rb);
853
854 if (rb->cursor_type != IGNORE_CURSOR
855 && rb->cursor_type != NO_CURSOR &&
856 (ADJ_BUFPOS == new_point
857 || (ADJ_ENDPOS && (new_point >= ADJ_BUFPOS)
858 && (new_point <= ADJ_BUFPOS))))
859 {
860 rb->cursor_type = CURSOR_ON;
861 dl->cursor_elt = cur_rb;
862
863
864 output_display_line (w, 0, cla, cur_dl, rb->xpos,
865 rb->xpos + rb->width);
866
867 w->last_point_x[CURRENT_DISP] = cur_rb;
868 w->last_point_y[CURRENT_DISP] = cur_dl;
869 Fset_marker (w->last_point[CURRENT_DISP],
870 make_int (ADJ_BUFPOS), w->buffer);
871
872 if (!no_output_end)
873 DEVMETH (d, output_end, (d));
874 return 1;
875 }
876
877 (up ? cur_rb++ : cur_rb--);
878 }
879
880 (up ? (cur_rb = 0) : (first = 0));
881 (up ? cur_dl++ : cur_dl--);
882 }
883 }
884
885 if (!no_output_end)
886 DEVMETH (d, output_end, (d));
887 return 0;
888 }
889 #undef ADJ_BUFPOS
890 #undef ADJ_ENDPOS
891
892 /*****************************************************************************
893 redraw_cursor_in_window
894
895 For the given window W, redraw the cursor if it is contained within
896 the window.
897 ****************************************************************************/
898 static void
899 redraw_cursor_in_window (struct window *w, int run_end_begin_meths)
900 {
901 struct frame *f = XFRAME (w->frame);
902 struct device *d = XDEVICE (f->device);
903
904 display_line_dynarr *dla = window_display_lines (w, CURRENT_DISP);
905 struct display_line *dl;
906 struct display_block *db;
907 struct rune *rb;
908
909 int x = w->last_point_x[CURRENT_DISP];
910 int y = w->last_point_y[CURRENT_DISP];
911
912 if (y < 0 || y >= Dynarr_length (dla))
913 return;
914
915 if (MINI_WINDOW_P (w) && f != device_selected_frame (d) &&
916 !is_surrogate_for_selected_frame (f))
917 return;
918
919 dl = Dynarr_atp (dla, y);
920 db = get_display_block_from_line (dl, TEXT);
921
922 if (x < 0 || x >= Dynarr_length (db->runes))
923 return;
924
925 rb = Dynarr_atp (db->runes, x);
926
927 /* Don't call the output routine if the block isn't actually the
928 cursor. */
929 if (rb->cursor_type == CURSOR_ON)
930 {
931 if (run_end_begin_meths)
932 DEVMETH (d, output_begin, (d));
933
934 output_display_line (w, 0, dla, y, rb->xpos, rb->xpos + rb->width);
935
936 if (run_end_begin_meths)
937 DEVMETH (d, output_end, (d));
938 }
939 }
940
941 /*****************************************************************************
942 redisplay_redraw_cursor
943
944 For the given frame F, redraw the cursor on the selected window.
945 This is used to update the cursor after focus changes.
946 ****************************************************************************/
947 void
948 redisplay_redraw_cursor (struct frame *f, int run_end_begin_meths)
949 {
950 struct window *w = XWINDOW (FRAME_SELECTED_WINDOW (f));
951
952 redraw_cursor_in_window (w, run_end_begin_meths);
953 }
954
955 /*****************************************************************************
956 redisplay_clear_top_of_window
957
958 If window is topmost, clear the internal border above it.
959 ****************************************************************************/
960 static void
961 redisplay_clear_top_of_window (struct window *w)
962 {
963 Lisp_Object window;
964 XSETWINDOW (window, w);
965
966 if (!NILP (Fwindow_highest_p (window)))
967 {
968 struct frame *f = XFRAME (w->frame);
969 struct device *d = XDEVICE (f->device);
970 int x, y, width, height;
971
972 x = w->pixel_left;
973 width = w->pixel_width;
974
975 if (window_is_leftmost (w))
976 {
977 x -= FRAME_BORDER_WIDTH (f);
978 width += FRAME_BORDER_WIDTH (f);
979 }
980 if (window_is_rightmost (w))
981 width += FRAME_BORDER_WIDTH (f);
982
983 y = FRAME_TOP_BORDER_START (f) - 1;
984 height = FRAME_BORDER_HEIGHT (f) + 1;
985
986 DEVMETH (d, clear_region, (window, DEFAULT_INDEX, x, y, width, height));
987 }
988 }
989
990 /*****************************************************************************
991 redisplay_clear_bottom_of_window
992
993 Clear window from right below the last display line to right above
994 the modeline. The calling function can limit the area actually
995 erased by setting min_start and/or max_end to positive values.
996 ****************************************************************************/
997 void
998 redisplay_clear_bottom_of_window (struct window *w, display_line_dynarr *ddla,
999 int min_start, int max_end)
1000 {
1001 struct frame *f = XFRAME (w->frame);
1002 struct device *d = XDEVICE (f->device);
1003 int ypos1, ypos2;
1004 int ddla_len = Dynarr_length (ddla);
1005
1006 ypos2 = WINDOW_TEXT_BOTTOM (w);
1007 #ifdef HAVE_SCROLLBARS
1008 /* This adjustment is to catch the intersection of any scrollbars. */
1009 if (f->windows_structure_changed && !f->scrollbar_on_top)
1010 ypos2 += window_scrollbar_height (w);
1011 #endif
1012
1013 if (ddla_len)
1014 {
1015 if (ddla_len == 1 && Dynarr_atp (ddla, 0)->modeline)
1016 {
1017 ypos1 = WINDOW_TEXT_TOP (w);
1018 #ifdef HAVE_SCROLLBARS
1019 /* This adjustment is to catch the intersection of any scrollbars. */
1020 if (f->windows_structure_changed && f->scrollbar_on_top)
1021 ypos1 -= window_scrollbar_height (w);
1022 #endif
1023 }
1024 else
1025 {
1026 struct display_line *dl = Dynarr_atp (ddla, ddla_len - 1);
1027 ypos1 = dl->ypos + dl->descent - dl->clip;
1028 }
1029 }
1030 else
1031 ypos1 = WINDOW_TEXT_TOP (w);
1032
1033 /* #### See if this can be made conditional on the frame
1034 changing size. */
1035 if (MINI_WINDOW_P (w))
1036 ypos2 += FRAME_BORDER_HEIGHT (f);
1037
1038 if (min_start >= 0 && ypos1 < min_start)
1039 ypos1 = min_start;
1040 if (max_end >= 0 && ypos2 > max_end)
1041 ypos2 = max_end;
1042
1043 if (ypos2 <= ypos1)
1044 return;
1045
1046 DEVMETH (d, clear_to_window_end, (w, ypos1, ypos2));
1047 }
1048
1049 /*****************************************************************************
1050 redisplay_update_line
1051
1052 This is used during incremental updates to update a single line and
1053 correct the offsets on all lines below it. At the moment
1054 update_values is false if we are only updating the modeline.
1055 ****************************************************************************/
1056 void
1057 redisplay_update_line (struct window *w, int first_line, int last_line,
1058 int update_values)
1059 {
1060 struct frame *f = XFRAME (w->frame);
1061 struct device *d = XDEVICE (f->device);
1062
1063 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1064 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1065
1066 DEVMETH (d, output_begin, (d));
1067
1068 while (first_line <= last_line)
1069 {
1070 Charcount old_len = (Dynarr_atp (cdla, first_line)->end_bufpos -
1071 Dynarr_atp (cdla, first_line)->bufpos);
1072 Charcount new_len = (Dynarr_atp (ddla, first_line)->end_bufpos -
1073 Dynarr_atp (ddla, first_line)->bufpos);
1074
1075 assert (Dynarr_length (cdla) == Dynarr_length (ddla));
1076
1077 /* Output the changes. */
1078 output_display_line (w, cdla, ddla, first_line, -1, -1);
1079
1080 /* Update the offsets. */
1081 if (update_values)
1082 {
1083 int cur_line = first_line + 1;
1084 while (cur_line < Dynarr_length (cdla))
1085 {
1086 Dynarr_atp (cdla, cur_line)->offset += (new_len - old_len);
1087 Dynarr_atp (ddla, cur_line)->offset += (new_len - old_len);
1088 cur_line++;
1089 }
1090 }
1091
1092 /* Update the window_end_pos and other settings. */
1093 if (update_values)
1094 {
1095 w->window_end_pos[CURRENT_DISP] -= (new_len - old_len);
1096
1097 if (Dynarr_atp (ddla, first_line)->cursor_elt != -1)
1098 {
1099 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1100 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1101 }
1102 }
1103
1104 first_line++;
1105 }
1106
1107 /* Update the window max line length. We have to scan the entire
1108 set of display lines otherwise we might not detect if the max is
1109 supposed to shrink. */
1110 if (update_values)
1111 {
1112 int line = 0;
1113
1114 w->max_line_len = 0;
1115 while (line < Dynarr_length (ddla))
1116 {
1117 struct display_line *dl = Dynarr_atp (ddla, line);
1118
1119 if (!dl->modeline)
1120 w->max_line_len = max (dl->num_chars, w->max_line_len);
1121
1122 line++;
1123 }
1124 }
1125
1126 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1127 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1128 Fset_marker (w->last_point[CURRENT_DISP],
1129 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1130 Fset_marker (w->last_start[CURRENT_DISP],
1131 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1132
1133 /* We don't bother updating the vertical scrollbars here. This
1134 gives us a performance increase while having minimal loss of
1135 quality to the scrollbar slider size and position since when this
1136 function is called we know that the changes to the buffer were
1137 very localized. We have to update the horizontal scrollbars,
1138 though, because this routine could cause a change which has a
1139 larger impact on their sizing. */
1140 /* #### See if we can get away with only calling this if
1141 max_line_len is greater than the window_char_width. */
1142 #ifdef HAVE_SCROLLBARS
1143 update_window_scrollbars (w, NULL, 1, 1);
1144 #endif
1145
1146 /* This has to be done after we've updated the values. We don't
1147 call output_end for tty frames. Redisplay will do this after all
1148 tty windows have been updated. This cuts down on cursor
1149 flicker. */
1150 if (FRAME_TTY_P (f))
1151 redisplay_redraw_cursor (f, 0);
1152 else
1153 DEVMETH (d, output_end, (d));
1154 }
1155
1156 /*****************************************************************************
1157 redisplay_output_window
1158
1159 For the given window W, ensure that the current display lines are
1160 equal to the desired display lines, outputing changes as necessary.
1161
1162 #### Fuck me. This just isn't going to cut it for tty's. The output
1163 decisions for them must be based on the contents of the entire frame
1164 because that is how the available output capabilities think. The
1165 solution is relatively simple. Create redisplay_output_frame. This
1166 will basically merge all of the separate window display structs into
1167 a single one for the frame. This combination structure will be able
1168 to be passed to the same output_display_line which works for windows
1169 on X frames and the right things will happen. It just takes time to
1170 do.
1171 ****************************************************************************/
1172 void
1173 redisplay_output_window (struct window *w)
1174 {
1175 struct frame *f = XFRAME (w->frame);
1176 struct device *d = XDEVICE (f->device);
1177
1178 display_line_dynarr *cdla = window_display_lines (w, CURRENT_DISP);
1179 display_line_dynarr *ddla = window_display_lines (w, DESIRED_DISP);
1180
1181 int cdla_len = Dynarr_length (cdla);
1182 int ddla_len = Dynarr_length (ddla);
1183
1184 int line;
1185 int need_to_clear_bottom = 0;
1186 int need_to_clear_start = -1;
1187 int need_to_clear_end = -1;
1188
1189 /* Backgrounds may have changed or windows may have gone away
1190 leaving dividers lying around. */
1191 if (f->faces_changed
1192 || f->windows_structure_changed
1193 || w->shadow_thickness_changed)
1194 need_to_clear_bottom = 1;
1195
1196 /* The first thing we do is determine if we are going to need to
1197 clear the bottom of the window. We only need to do this if the
1198 bottom of the current display lines is below the bottom of the
1199 desired display lines. Note that the number of lines is
1200 irrelevant. Only the position matters. We also clear to the
1201 bottom of the window if the modeline has shifted position. */
1202 /* #### We can't blindly not clear the bottom if f->clear is true
1203 since there might be a window-local background. However, for
1204 those cases where there isn't, clearing the end of the window in
1205 this case sucks. */
1206 if (!need_to_clear_bottom)
1207 {
1208 struct display_line *cdl, *ddl;
1209
1210 /* If the modeline has changed position or size, clear the bottom
1211 of the window. */
1212 if (!need_to_clear_bottom)
1213 {
1214 cdl = ddl = 0;
1215
1216 if (cdla_len)
1217 cdl = Dynarr_atp (cdla, 0);
1218 if (ddla_len)
1219 ddl = Dynarr_atp (ddla, 0);
1220
1221 if (!cdl || !ddl)
1222 need_to_clear_bottom = 1;
1223 else if ((!cdl->modeline && ddl->modeline)
1224 || (cdl->modeline && !ddl->modeline))
1225 need_to_clear_bottom = 1;
1226 else if (cdl->ypos != ddl->ypos ||
1227 cdl->ascent != ddl->ascent ||
1228 cdl->descent != ddl->descent ||
1229 cdl->clip != ddl->clip)
1230 need_to_clear_bottom = 1;
1231
1232 /* #### This kludge is to make sure the modeline shadows get
1233 redrawn if the modeline position shifts. */
1234 if (need_to_clear_bottom)
1235 w->shadow_thickness_changed = 1;
1236 }
1237
1238 if (!need_to_clear_bottom)
1239 {
1240 cdl = ddl = 0;
1241
1242 if (cdla_len)
1243 cdl = Dynarr_atp (cdla, cdla_len - 1);
1244 if (ddla_len)
1245 ddl = Dynarr_atp (ddla, ddla_len - 1);
1246
1247 if (!cdl || !ddl)
1248 need_to_clear_bottom = 1;
1249 else
1250 {
1251 int cdl_bottom, ddl_bottom;
1252
1253 cdl_bottom = cdl->ypos + cdl->descent;
1254 ddl_bottom = ddl->ypos + ddl->descent;
1255
1256 if (cdl_bottom > ddl_bottom)
1257 {
1258 need_to_clear_bottom = 1;
1259 need_to_clear_start = ddl_bottom;
1260 need_to_clear_end = cdl_bottom;
1261 }
1262 }
1263 }
1264 }
1265
1266 /* Perform any output initialization. */
1267 DEVMETH (d, output_begin, (d));
1268
1269 /* If the window's structure has changed clear the internal border
1270 above it if it is topmost (the function will check). */
1271 if (f->windows_structure_changed)
1272 redisplay_clear_top_of_window (w);
1273
1274 /* Output each line. */
1275 for (line = 0; line < Dynarr_length (ddla); line++)
1276 {
1277 output_display_line (w, cdla, ddla, line, -1, -1);
1278 }
1279
1280 /* If the number of display lines has shrunk, adjust. */
1281 if (cdla_len > ddla_len)
1282 {
1283 Dynarr_length (cdla) = ddla_len;
1284 }
1285
1286 /* Output a vertical divider between windows, if necessary. */
1287 if (window_needs_vertical_divider (w)
1288 && (f->windows_structure_changed || f->clear))
1289 {
1290 DEVMETH (d, output_vertical_divider, (w, f->windows_structure_changed));
1291 }
1292
1293 /* Clear the rest of the window, if necessary. */
1294 if (need_to_clear_bottom)
1295 {
1296 redisplay_clear_bottom_of_window (w, ddla, need_to_clear_start,
1297 need_to_clear_end);
1298 }
1299
1300 w->window_end_pos[CURRENT_DISP] = w->window_end_pos[DESIRED_DISP];
1301 Fset_marker (w->start[CURRENT_DISP],
1302 make_int (marker_position (w->start[DESIRED_DISP])),
1303 w->buffer);
1304 Fset_marker (w->pointm[CURRENT_DISP],
1305 make_int (marker_position (w->pointm[DESIRED_DISP])),
1306 w->buffer);
1307 w->last_modified[CURRENT_DISP] = w->last_modified[DESIRED_DISP];
1308 w->last_facechange[CURRENT_DISP] = w->last_facechange[DESIRED_DISP];
1309 Fset_marker (w->last_start[CURRENT_DISP],
1310 Fmarker_position (w->last_start[DESIRED_DISP]), w->buffer);
1311 Fset_marker (w->last_point[CURRENT_DISP],
1312 Fmarker_position (w->last_point[DESIRED_DISP]), w->buffer);
1313 w->last_point_x[CURRENT_DISP] = w->last_point_x[DESIRED_DISP];
1314 w->last_point_y[CURRENT_DISP] = w->last_point_y[DESIRED_DISP];
1315 w->shadow_thickness_changed = 0;
1316
1317 set_window_display_buffer (w, XBUFFER (w->buffer));
1318 find_window_mirror (w)->truncate_win = window_truncation_on (w);
1319
1320 /* Overkill on invalidating the cache. It is very bad for it to not
1321 get invalidated when it should be. */
1322 INVALIDATE_DEVICE_PIXEL_TO_GLYPH_CACHE (d);
1323
1324 /* We don't call output_end for tty frames. Redisplay will do this
1325 after all tty windows have been updated. This cuts down on
1326 cursor flicker. */
1327 if (FRAME_TTY_P (f))
1328 redisplay_redraw_cursor (f, 0);
1329 else
1330 DEVMETH (d, output_end, (d));
1331
1332 #ifdef HAVE_SCROLLBARS
1333 update_window_scrollbars (w, NULL, !MINI_WINDOW_P (w), 0);
1334 #endif
1335 }