Build Fix -- compatibility issue with newer autoconf
[sxemacs] / src / ui / redisplay.c
1 /* Display generation from window structure and buffer text.
2    Copyright (C) 1994, 1995, 1996 Board of Trustees, University of Illinois.
3    Copyright (C) 1995 Free Software Foundation, Inc.
4    Copyright (C) 1995, 1996 Ben Wing.
5    Copyright (C) 1995 Sun Microsystems, Inc.
6    Copyright (C) 1996 Chuck Thompson.
7
8 This file is part of SXEmacs
9
10 SXEmacs is free software: you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 SXEmacs is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program.  If not, see <http://www.gnu.org/licenses/>. */
22
23
24 /* Synched up with:  Not in FSF. */
25
26 /* Author: Chuck Thompson */
27
28 /* Fixed up by Ben Wing for Mule */
29
30 /* This file has been Mule-ized. */
31
32 /*****************************************************************************
33  The Golden Rules of Redisplay
34
35  First:         It Is Better To Be Correct Than Fast
36  Second:        Thou Shalt Not Run Elisp From Within Redisplay
37  Third:         It Is Better To Be Fast Than Not To Be
38  ****************************************************************************/
39
40 #include <config.h>
41 #include "lisp.h"
42
43 #include "buffer.h"
44 #include "commands.h"
45 #include "debug.h"
46 #include "device.h"
47 #include "elhash.h"
48 #include "extents.h"
49 #include "faces.h"
50 #include "frame.h"
51 #include "glyphs.h"
52 #include "gutter.h"
53 #include "insdel.h"
54 #include "menubar.h"
55 #include "objects.h"
56 #include "process.h"
57 #include "redisplay.h"
58 #include "toolbar.h"
59 #include "window.h"
60 #include "line-number.h"
61 #ifdef FILE_CODING
62 #include "mule/file-coding.h"
63 #endif
64
65 #include "sysfile.h"
66
67 /* Note: We have to be careful throughout this code to properly handle
68    and differentiate between Bufbytes and Emchars.
69
70    Since strings are generally composed of Bufbytes, I've taken the tack
71    that any contiguous set of Bufbytes is called a "string", while
72    any contiguous set of Emchars is called an "array". */
73
74 /* Return value to indicate a failure by an add_*_rune routine to add
75    a rune, but no propagation information needs to be returned. */
76 #define ADD_FAILED (prop_block_dynarr *) 1
77
78 #define BEGIN_GLYPHS    0
79 #define END_GLYPHS      1
80 #define LEFT_GLYPHS     2
81 #define RIGHT_GLYPHS    3
82
83 #define VERTICAL_CLIP(w, display)                                       \
84     ((WINDOW_TTY_P (w) | (!display && scroll_on_clipped_lines))         \
85       ? INT_MAX                                                         \
86       : vertical_clip)
87
88 /* The following structures are completely private to redisplay.c so
89    we put them here instead of in a header file, for modularity. */
90
91 /* NOTE: Bytinds not Bufpos's in this structure. */
92
93 typedef struct position_redisplay_data_type {
94         /* This information is normally filled in by the create_*_block
95            routines and is used by the add_*_rune routines. */
96         Lisp_Object window;
97         /* if we are working with strings rather than buffers we need a
98            handle to the string */
99         Lisp_Object string;
100         struct device *d;
101         struct display_block *db;
102         struct display_line *dl;
103         Emchar ch;              /* Character that is to be added.  This is
104                                    used to communicate this information to
105                                    add_emchar_rune(). */
106         Lisp_Object last_charset;       /* The charset of the previous character.
107                                            Used to optimize some lookups -- we
108                                            only have to do some things when
109                                            the charset changes. */
110         face_index last_findex; /* The face index of the previous character.
111                                    Needed to ensure the validity of the
112                                    last_charset optimization. */
113
114         int last_char_width;    /* The width of the previous character. */
115         int font_is_bogus;      /* If true, it means we couldn't instantiate
116                                    the font for this charset, so we substitute
117                                    ~'s from the ASCII charset. */
118         Bytind bi_bufpos;
119         Bytind bi_endpos;
120         int pixpos;
121         int max_pixpos;
122         int blank_width;        /* Width of the blank that is to be added.
123                                    This is used to communicate this information
124                                    to add_blank_rune().
125
126                                    This is also used rather cheesily to
127                                    communicate the width of the eol-cursor-size
128                                    blank that exists at the end of the line.
129                                    add_emchar_rune() is called cheesily with
130                                    the non-printing char '\n', which is stuck
131                                    in the output routines with its width being
132                                    BLANK_WIDTH. */
133         Bytind bi_cursor_bufpos;        /* This stores the buffer position of the cursor. */
134         unsigned int cursor_type:3;
135         int cursor_x;           /* rune block cursor is at */
136         int start_col;          /* Number of character columns (each column has
137                                    a width of the default char width) that still
138                                    need to be skipped.  This is used for horizontal
139                                    scrolling, where a certain number of columns
140                                    (those off the left side of the screen) need
141                                    to be skipped before anything is displayed. */
142         Bytind bi_start_col_enabled;
143         int start_col_xoffset;  /* Number of pixels that still need to
144                                    be skipped.  This is used for
145                                    horizontal scrolling of glyphs, where we want
146                                    to be able to scroll over part of the glyph. */
147
148         int hscroll_glyph_width_adjust; /* how much the width of the hscroll
149                                            glyph differs from space_width (w).
150                                            0 if no hscroll glyph was used,
151                                            i.e. the window is not scrolled
152                                            horizontally.  Used in tab
153                                            calculations. */
154
155         /* Information about the face the text should be displayed in and
156            any begin-glyphs and end-glyphs. */
157         struct extent_fragment *ef;
158         face_index findex;
159
160         /* The height of a pixmap may either be predetermined if the user has set a
161            baseline value, or it may be dependent on whatever the line ascent and
162            descent values end up being, based just on font and pixmap-ascent
163            information.  In the first case we can immediately update the values, thus
164            their inclusion here.  In the last case we cannot determine the actual
165            contribution to the line height until we have finished laying out all text
166            on the line.  Thus we propagate the max height of such pixmaps and do a
167            final calculation (in calculate_baseline()) after all text has been added
168            to the line. */
169         int new_ascent;
170         int new_descent;
171         int max_pixmap_height;
172         int need_baseline_computation;
173         int end_glyph_width;    /* Well, it is the kitchen sink after all ... */
174
175         Lisp_Object result_str; /* String where we put the result of
176                                    generating a formatted string in the modeline. */
177         int is_modeline;        /* Non-zero if we're generating the modeline. */
178         Charcount modeline_charpos;     /* Number of chars used in result_str so far;
179                                            corresponds to bytepos. */
180         Bytecount bytepos;      /* Number of bytes used in result_str so far.
181                                    We don't actually copy the bytes into result_str
182                                    until the end because we don't know how big the
183                                    string is going to be until then. */
184 } pos_data;
185
186 enum prop_type {
187         PROP_STRING,
188         PROP_CHAR,
189         PROP_MINIBUF_PROMPT,
190         PROP_BLANK,
191         PROP_GLYPH
192 };
193
194 /* Data that should be propagated to the next line.  Either a single
195    Emchar, a string of Bufbyte's or a glyph.
196
197    The actual data that is propagated ends up as a Dynarr of these
198    blocks.
199
200    prop_blocks are used to indicate that data that was supposed to go
201    on the previous line couldn't actually be displayed. Generally this
202    shouldn't happen if we are clipping the end of lines. If we are
203    wrapping then we need to display the propagation data before moving
204    on. Its questionable whether we should wrap or clip glyphs in this
205    instance. Most e-lisp relies on clipping so we preserve this
206    behavior.
207
208    #### It's unclean that both Emchars and Bufbytes are here.
209    */
210
211 typedef struct prop_block prop_block;
212 struct prop_block {
213         enum prop_type type;
214
215         union data {
216                 struct {
217                         Bufbyte *str;
218                         Bytecount len;  /* length of the string. */
219                 } p_string;
220
221                 struct {
222                         Emchar ch;
223                         Bytind bi_cursor_bufpos;        /* NOTE: is in Bytinds */
224                         unsigned int cursor_type:3;
225                 } p_char;
226
227                 struct {
228                         int width;
229                         face_index findex;
230                 } p_blank;
231
232                 struct {
233                         /* Not used as yet, but could be used to wrap rather than clip glyphs. */
234                         int width;
235                         Lisp_Object glyph;
236                 } p_glyph;
237
238         } data;
239 };
240
241 typedef struct {
242         Dynarr_declare(prop_block);
243 } prop_block_dynarr;
244
245 static Charcount generate_fstring_runes(struct window *w, pos_data * data,
246                                         Charcount pos, Charcount min_pos,
247                                         Charcount max_pos, Lisp_Object elt,
248                                         int depth, int max_pixsize,
249                                         face_index findex, int type,
250                                         Charcount * offset,
251                                         Lisp_Object cur_ext);
252 static prop_block_dynarr *add_glyph_rune(pos_data * data,
253                                          struct glyph_block *gb,
254                                          int pos_type, int allow_cursor,
255                                          struct glyph_cachel *cachel);
256 static void add_glyph_rune_noret(pos_data * data,
257                                  struct glyph_block *gb,
258                                  int pos_type, int allow_cursor,
259                                  struct glyph_cachel *cachel);
260 static Bytind create_text_block(struct window *w, struct display_line *dl,
261                                 Bytind bi_start_pos, prop_block_dynarr ** prop,
262                                 int type);
263 static int create_overlay_glyph_block(struct window *w,
264                                       struct display_line *dl);
265 static void create_left_glyph_block(struct window *w,
266                                     struct display_line *dl, int overlay_width);
267 static void create_right_glyph_block(struct window *w, struct display_line *dl);
268 static void redisplay_windows(Lisp_Object window, int skip_selected);
269 static void decode_mode_spec(struct window *w, Emchar spec, int type);
270 static void free_display_line(struct display_line *dl);
271 static void update_line_start_cache(struct window *w, Bufpos from, Bufpos to,
272                                     Bufpos point, int no_regen);
273 static int point_visible(struct window *w, Bufpos point, int type);
274 static void calculate_yoffset(struct display_line *dl,
275                               struct display_block *fixup);
276 static void calculate_baseline(pos_data * data);
277
278 /* This used to be 10 but 30 seems to give much better performance. */
279 #define INIT_MAX_PREEMPTS       30
280 static int max_preempts;
281
282 #define REDISPLAY_PREEMPTION_CHECK                                      \
283 ((void)                                                                 \
284  (preempted =                                                           \
285   (!disable_preemption &&                                               \
286    ((preemption_count < max_preempts) || !NILP (Vexecuting_macro)) &&   \
287    (!INTERACTIVE || detect_input_pending ()))))
288
289 /*
290  * Redisplay global variables.
291  */
292
293 /* We need a third set of display structures for the cursor motion
294    routines.  We used to just give each window a third set.  However,
295    we always fully regenerate the structures when needed so there
296    isn't any reason we need more than a single set. */
297 display_line_dynarr *cmotion_display_lines;
298
299 /* We store the extents that we need to generate in a Dynarr and then
300    frob them all on at the end of generating the string.  We do it
301    this way rather than adding them as we generate the string because
302    we don't store the text into the resulting string until we're done
303    (to avoid having to resize the string multiple times), and we don't
304    want to go around adding extents to a string when the extents might
305    stretch off the end of the string. */
306 static EXTENT_dynarr *formatted_string_extent_dynarr;
307 static Bytecount_dynarr *formatted_string_extent_start_dynarr;
308 static Bytecount_dynarr *formatted_string_extent_end_dynarr;
309
310 /* #### probably temporary */
311 Fixnum cache_adjustment;
312
313 /* This holds a string representing the text corresponding to a single
314    modeline % spec. */
315 static Bufbyte_dynarr *mode_spec_bufbyte_string;
316
317 int in_display;                 /* 1 if in redisplay.  */
318
319 int disable_preemption;         /* Used for debugging redisplay and for
320                                    force-redisplay. */
321
322 /* We only allow max_preempts preemptions before we force a redisplay. */
323 static int preemption_count;
324
325 /* Minimum pixel height of clipped bottom display line. */
326 Fixnum vertical_clip;
327
328 /* Minimum visible pixel width of clipped glyphs at right margin. */
329 Fixnum horizontal_clip;
330
331 /* Nonzero means reading single-character input with prompt
332    so put cursor on minibuffer after the prompt.  */
333 int cursor_in_echo_area;
334 Lisp_Object Qcursor_in_echo_area;
335
336 /* Nonzero means truncate lines in all windows less wide than the frame */
337 int truncate_partial_width_windows;
338
339 /* non-nil if a buffer has changed since the last time redisplay completed */
340 int buffers_changed;
341 int buffers_changed_set;
342
343 /* non-nil if hscroll has changed somewhere or a buffer has been
344    narrowed or widened */
345 int clip_changed;
346 int clip_changed_set;
347
348 /* non-nil if any extent has changed since the last time redisplay completed */
349 int extents_changed;
350 int extents_changed_set;
351
352 /* non-nil if any face has changed since the last time redisplay completed */
353 int faces_changed;
354
355 /* Nonzero means some frames have been marked as garbaged */
356 int frame_changed;
357
358 /* non-zero if any of the builtin display glyphs (continuation,
359    hscroll, control-arrow, etc) is in need of updating
360    somewhere. */
361 int glyphs_changed;
362 int glyphs_changed_set;
363
364 /* non-zero if any subwindow has been deleted. */
365 int subwindows_changed;
366 int subwindows_changed_set;
367
368 /* non-zero if any displayed subwindow is in need of updating
369    somewhere. */
370 int subwindows_state_changed;
371 int subwindows_state_changed_set;
372
373 /* This variable is 1 if the icon has to be updated.
374  It is set to 1 when `frame-icon-glyph' changes. */
375 int icon_changed;
376 int icon_changed_set;
377
378 /* This variable is 1 if the menubar widget has to be updated.
379  It is set to 1 by set-menubar-dirty-flag and cleared when the widget
380  has been updated. */
381 int menubar_changed;
382 int menubar_changed_set;
383
384 /* true iff we should redraw the modelines on the next redisplay */
385 int modeline_changed;
386 int modeline_changed_set;
387
388 /* non-nil if point has changed in some buffer since the last time
389    redisplay completed */
390 int point_changed;
391 int point_changed_set;
392
393 /* non-nil if some frame has changed its size */
394 int size_changed;
395
396 /* non-nil if some device has signaled that it wants to change size */
397 int asynch_device_change_pending;
398
399 /* non-nil if any toolbar has changed */
400 int toolbar_changed;
401 int toolbar_changed_set;
402
403 /* Nonzero if some frame has changed the layout of internal elements
404    (gutters or toolbars). */
405 int frame_layout_changed;
406
407 /* non-nil if any gutter has changed */
408 int gutter_changed;
409 int gutter_changed_set;
410
411 /* non-nil if any window has changed since the last time redisplay completed */
412 int windows_changed;
413
414 /* non-nil if any frame's window structure has changed since the last
415    time redisplay completed */
416 int windows_structure_changed;
417
418 /* If non-nil, use vertical bar cursor. */
419 Lisp_Object Vbar_cursor;
420 Lisp_Object Qbar_cursor;
421
422 Lisp_Object Vvisible_bell;      /* If true and the terminal will support it
423                                    then the frame will flash instead of
424                                    beeping when an error occurs */
425
426 /* Nonzero means no need to redraw the entire frame on resuming
427    a suspended Emacs.  This is useful on terminals with multiple pages,
428    where one page is used for Emacs and another for all else. */
429 int no_redraw_on_reenter;
430
431 Lisp_Object Vwindow_system;     /* nil or a symbol naming the window system
432                                    under which emacs is running
433                                    ('x is the only current possibility) */
434 Lisp_Object Vinitial_window_system;
435
436 Lisp_Object Vglobal_mode_string;
437
438 /* The number of lines scroll a window by when point leaves the window; if
439   it is <=0 then point is centered in the window */
440 Fixnum scroll_step;
441
442 /* Scroll up to this many lines, to bring point back on screen. */
443 Fixnum scroll_conservatively;
444
445 /* Marker for where to display an arrow on top of the buffer text.  */
446 Lisp_Object Voverlay_arrow_position;
447 /* String to display for the arrow.  */
448 Lisp_Object Voverlay_arrow_string;
449
450 Lisp_Object Vwindow_size_change_functions;
451 Lisp_Object Vwindow_scroll_functions;
452 Lisp_Object Qredisplay_end_trigger_functions, Vredisplay_end_trigger_functions;
453
454 Lisp_Object Qbuffer_list_changed_hook, Vbuffer_list_changed_hook;
455
456 #define INHIBIT_REDISPLAY_HOOKS /* #### Until we've thought about
457                                    this more. */
458 #ifndef INHIBIT_REDISPLAY_HOOKS
459 /* #### Chuck says: I think this needs more thought.
460    Think about this for 19.14. */
461 Lisp_Object Vpre_redisplay_hook, Vpost_redisplay_hook;
462 Lisp_Object Qpre_redisplay_hook, Qpost_redisplay_hook;
463 #endif                          /* INHIBIT_REDISPLAY_HOOKS */
464
465 static Fixnum last_display_warning_tick;
466 static Fixnum display_warning_tick;
467 Lisp_Object Qdisplay_warning_buffer;
468 int inhibit_warning_display;
469
470 Lisp_Object Vleft_margin_width, Vright_margin_width;
471 Lisp_Object Vminimum_line_ascent, Vminimum_line_descent;
472 Lisp_Object Vuse_left_overflow, Vuse_right_overflow;
473 Lisp_Object Vtext_cursor_visible_p;
474
475 int column_number_start_at_one;
476
477 Lisp_Object Qtop_bottom;
478
479 #define WINDOW_SCROLLED(w) ((w)->hscroll > 0 || (w)->left_xoffset)
480 \f
481 /***************************************************************************/
482 /*                                                                         */
483 /*              low-level interfaces onto device routines                  */
484 /*                                                                         */
485 /***************************************************************************/
486
487 static int
488 redisplay_text_width_emchar_string(struct window *w, int findex,
489                                    Emchar * str, Charcount len)
490 {
491         unsigned char charsets[NUM_LEADING_BYTES];
492         Lisp_Object window;
493
494         find_charsets_in_emchar_string(charsets, str, len);
495         XSETWINDOW(window, w);
496         ensure_face_cachel_complete(WINDOW_FACE_CACHEL(w, findex), window,
497                                     charsets);
498         return DEVMETH(XDEVICE(FRAME_DEVICE(XFRAME(WINDOW_FRAME(w)))),
499                        text_width, (XFRAME(WINDOW_FRAME(w)),
500                                     WINDOW_FACE_CACHEL(w, findex), str, len));
501 }
502
503 static Emchar_dynarr *rtw_emchar_dynarr;
504
505 int
506 redisplay_text_width_string(struct window *w, int findex,
507                             Bufbyte * nonreloc, Lisp_Object reloc,
508                             Bytecount offset, Bytecount len)
509 {
510         if (!rtw_emchar_dynarr)
511                 rtw_emchar_dynarr = Dynarr_new(Emchar);
512         Dynarr_reset(rtw_emchar_dynarr);
513
514         fixup_internal_substring(nonreloc, reloc, offset, &len);
515         if (STRINGP(reloc))
516                 nonreloc = XSTRING_DATA(reloc);
517         convert_bufbyte_string_into_emchar_dynarr(nonreloc, len,
518                                                   rtw_emchar_dynarr);
519         return redisplay_text_width_emchar_string(w, findex,
520                                                   Dynarr_atp(rtw_emchar_dynarr,
521                                                              0),
522                                                   Dynarr_length
523                                                   (rtw_emchar_dynarr));
524 }
525
526 int
527 redisplay_frame_text_width_string(struct frame *f, Lisp_Object face,
528                                   Bufbyte * nonreloc, Lisp_Object reloc,
529                                   Bytecount offset, Bytecount len)
530 {
531         unsigned char charsets[NUM_LEADING_BYTES];
532         Lisp_Object frame;
533         struct face_cachel cachel;
534
535         if (!rtw_emchar_dynarr)
536                 rtw_emchar_dynarr = Dynarr_new(Emchar);
537         Dynarr_reset(rtw_emchar_dynarr);
538
539         fixup_internal_substring(nonreloc, reloc, offset, &len);
540         if (STRINGP(reloc))
541                 nonreloc = XSTRING_DATA(reloc);
542         convert_bufbyte_string_into_emchar_dynarr(nonreloc, len,
543                                                   rtw_emchar_dynarr);
544         find_charsets_in_bufbyte_string(charsets, nonreloc, len);
545         reset_face_cachel(&cachel);
546         cachel.face = face;
547         XSETFRAME(frame, f);
548         ensure_face_cachel_complete(&cachel, frame, charsets);
549         return DEVMETH(XDEVICE(FRAME_DEVICE(f)),
550                        text_width, (f, &cachel,
551                                     Dynarr_atp(rtw_emchar_dynarr, 0),
552                                     Dynarr_length(rtw_emchar_dynarr)));
553 }
554
555 /* Return the display block from DL of the given TYPE.  A display line
556    can have only one display block of each possible type.  If DL does
557    not have a block of type TYPE, one will be created and added to DL. */
558
559 struct display_block *get_display_block_from_line(struct display_line *dl,
560                                                   enum display_type type)
561 {
562         int elt;
563         struct display_block db;
564
565         /* Check if this display line already has a block of the desired type and
566            if so, return it. */
567         if (dl->display_blocks) {
568                 for (elt = 0; elt < Dynarr_length(dl->display_blocks); elt++) {
569                         if (Dynarr_at(dl->display_blocks, elt).type == type)
570                                 return Dynarr_atp(dl->display_blocks, elt);
571                 }
572
573                 /* There isn't an active block of the desired type, but there
574                    might still be allocated blocks we need to reuse. */
575                 if (elt < Dynarr_largest(dl->display_blocks)) {
576                         struct display_block *dbp =
577                             Dynarr_atp(dl->display_blocks, elt);
578
579                         /* 'add' the block to the list */
580                         Dynarr_increment(dl->display_blocks);
581
582                         /* initialize and return */
583                         dbp->type = type;
584                         return dbp;
585                 }
586         } else {
587                 /* This line doesn't have any display blocks, so initialize the display
588                    bock array. */
589                 dl->display_blocks = Dynarr_new(display_block);
590         }
591
592         /* The line doesn't have a block of the desired type so go ahead and create
593            one and add it to the line. */
594         xzero(db);
595         db.type = type;
596         db.runes = Dynarr_new(rune);
597         Dynarr_add(dl->display_blocks, db);
598
599         /* Return the newly added display block. */
600         elt = Dynarr_length(dl->display_blocks) - 1;
601
602         return Dynarr_atp(dl->display_blocks, elt);
603 }
604
605 static int tab_char_width(struct window *w)
606 {
607         struct buffer *b = XBUFFER(w->buffer);
608         int char_tab_width = XINT(b->tab_width);
609
610         if (char_tab_width <= 0 || char_tab_width > 1000)
611                 char_tab_width = 8;
612
613         return char_tab_width;
614 }
615
616 static int space_width(struct window *w)
617 {
618         /* While tabs are traditional composed of spaces, for variable-width
619            fonts the space character tends to give too narrow a value.  So
620            we use 'n' instead.  Except that we don't.  We use the default
621            character width for the default face.  If this is actually
622            defined by the font then it is probably the best thing to
623            actually use.  If it isn't, we have assumed it is 'n' and have
624            already calculated its width.  Thus we can avoid a call to
625            XTextWidth on X frames by just querying the default width. */
626         return XFONT_INSTANCE
627             (WINDOW_FACE_CACHEL_FONT(w, DEFAULT_INDEX, Vcharset_ascii))->width;
628 }
629
630 static int tab_pix_width(struct window *w)
631 {
632         return space_width(w) * tab_char_width(w);
633 }
634
635 /* Given a pixel position in a window, return the pixel location of
636    the next tabstop.  Tabs are calculated from the left window edge in
637    terms of spaces displayed in the default face.  Formerly the space
638    width was determined using the currently active face.  That method
639    leads to tabstops which do not line up. */
640
641 static int
642 next_tab_position(struct window *w, int start_pixpos, int left_pixpos)
643 {
644         int n_pos = left_pixpos;
645         int pix_tab_width = tab_pix_width(w);
646
647         /* Adjust n_pos for any hscrolling which has happened. */
648         if (WINDOW_SCROLLED(w))
649                 n_pos -= space_width(w) * (w->hscroll - 1) + w->left_xoffset;
650
651         while (n_pos <= start_pixpos)
652                 n_pos += pix_tab_width;
653
654         return n_pos;
655 }
656
657 /* For the given window, calculate the outside and margin boundaries for a
658    display line.  The whitespace boundaries must be calculated by the text
659    layout routines. */
660
661 layout_bounds calculate_display_line_boundaries(struct window * w, int modeline)
662 {
663         layout_bounds bounds;
664
665         /* Set the outermost boundaries which are the boundaries of the
666            window itself minus the gutters (and minus the scrollbars if this
667            is for the modeline). */
668         if (!modeline) {
669                 bounds.left_out = WINDOW_TEXT_LEFT(w);
670                 bounds.right_out = WINDOW_TEXT_RIGHT(w);
671         } else {
672                 bounds.left_out = WINDOW_MODELINE_LEFT(w);
673                 bounds.right_out = WINDOW_MODELINE_RIGHT(w);
674         }
675
676         /* The inner boundaries mark where the glyph margins are located. */
677         bounds.left_in = bounds.left_out + window_left_margin_width(w);
678         bounds.right_in = bounds.right_out - window_right_margin_width(w);
679
680         /* We cannot fully calculate the whitespace boundaries as they
681            depend on the contents of the line being displayed. */
682         bounds.left_white = bounds.left_in;
683         bounds.right_white = bounds.right_in;
684
685         return bounds;
686 }
687
688 /* This takes a display_block and its containing line and corrects the yoffset
689    of each glyph in the block to cater for the ascent of the line as a
690    whole. Must be called *after* the line-ascent is known! */
691
692 static void
693 calculate_yoffset(struct display_line *dl, struct display_block *fixup)
694 {
695         int i;
696         for (i = 0; i < Dynarr_length(fixup->runes); i++) {
697                 struct rune *r = Dynarr_atp(fixup->runes, i);
698                 if (r->type == RUNE_DGLYPH) {
699                         if (r->object.dglyph.ascent < dl->ascent)
700                                 r->object.dglyph.yoffset =
701                                     dl->ascent - r->object.dglyph.ascent +
702                                     r->object.dglyph.descent;
703                 }
704         }
705 }
706
707 /* Calculate the textual baseline (the ascent and descent values for the
708    display_line as a whole).
709
710    If the baseline is completely blank, or contains no manually positioned
711    glyphs, then the textual baseline is simply the baseline of the default font.
712    (The `contains no manually positioned glyphs' part is actually done for
713    us by `add_emchar_rune'.)
714
715    If the baseline contains pixmaps, and they're all manually positioned, then
716    the textual baseline location is constrained that way, and we need do no
717    work.
718
719    If the baseline contains pixmaps, and at least one is automatically
720    positioned, then the textual ascent is the largest ascent on the line, and
721    the textual descent is the largest descent (which is how things are set up at
722    entry to this function anyway): except that if the max_ascent + max_descent
723    is too small for the height of the line (say you've adjusted the baseline of
724    a short glyph, and there's a tall one next to it), then take the ascent and
725    descent for the line individually from the largest of the explicitly set
726    ascent/descent, and the rescaled ascent/descent of the default font, scaled
727    such that the largest glyph will fit.
728
729    This means that if you have a short glyph (but taller than the default
730    font's descent) forced right under the baseline, and a really tall
731    automatically positioned glyph, that the descent for the line is just big
732    enough for the manually positioned short glyph, and the tall one uses as
733    much of that space as the default font would were it as tall as the tall
734    glyph; but that the ascent is big enough for the tall glyph to fit.
735
736    This behaviour means that under no circumstances will changing the baseline
737    of a short glyph cause a tall glyph to move around; nor will it move the
738    textual baseline more than necessary. (Changing a tall glyph's baseline
739    might move the text's baseline arbitrarily, of course.) */
740
741 static void calculate_baseline(pos_data * data)
742 {
743         /* Blank line: baseline is default font's baseline. */
744
745         if (!data->new_ascent && !data->new_descent) {
746                 /* We've got a blank line so initialize these values from the default
747                    face. */
748                 default_face_font_info(data->window, &data->new_ascent,
749                                        &data->new_descent, 0, 0, 0);
750         }
751
752         /* No automatically positioned glyphs? Return at once. */
753         if (!data->need_baseline_computation)
754                 return;
755
756         /* Is the tallest glyph on the line automatically positioned?
757            If it's manually positioned, or it's automatically positioned
758            and there's enough room for it anyway, we need do no more work. */
759         if (data->max_pixmap_height > data->new_ascent + data->new_descent) {
760                 int default_font_ascent, default_font_descent,
761                     default_font_height;
762                 int scaled_default_font_ascent, scaled_default_font_descent;
763
764                 default_face_font_info(data->window, &default_font_ascent,
765                                        &default_font_descent,
766                                        &default_font_height, 0, 0);
767
768                 scaled_default_font_ascent = data->max_pixmap_height *
769                     default_font_ascent / default_font_height;
770
771                 data->new_ascent =
772                     max(data->new_ascent, scaled_default_font_ascent);
773
774                 /* The ascent may have expanded now. Do we still need to grow the descent,
775                    or are things big enough?
776
777                    The +1 caters for the baseline row itself. */
778                 if (data->max_pixmap_height >
779                     data->new_ascent + data->new_descent) {
780                         scaled_default_font_descent =
781                             (data->max_pixmap_height * default_font_descent /
782                              default_font_height) + 1;
783
784                         data->new_descent =
785                             max(data->new_descent, scaled_default_font_descent);
786                 }
787         }
788 }
789
790 /* Given a display line and a starting position, ensure that the
791    contents of the display line accurately represent the visual
792    representation of the buffer contents starting from the given
793    position when displayed in the given window.  The display line ends
794    when the contents of the line reach the right boundary of the given
795    window. */
796
797 static Bufpos
798 generate_display_line(struct window *w, struct display_line *dl, int bounds,
799                       Bufpos start_pos, prop_block_dynarr ** prop, int type)
800 {
801         Bufpos ret_bufpos;
802         int overlay_width;
803         struct buffer *b = XBUFFER(WINDOW_BUFFER(w));
804
805         /* If our caller hasn't already set the boundaries, then do so now. */
806         if (!bounds)
807                 dl->bounds = calculate_display_line_boundaries(w, 0);
808
809         /* Reset what this line is using. */
810         if (dl->display_blocks)
811                 Dynarr_reset(dl->display_blocks);
812         if (dl->left_glyphs) {
813                 Dynarr_free(dl->left_glyphs);
814                 dl->left_glyphs = 0;
815         }
816         if (dl->right_glyphs) {
817                 Dynarr_free(dl->right_glyphs);
818                 dl->right_glyphs = 0;
819         }
820
821         /* We aren't generating a modeline at the moment. */
822         dl->modeline = 0;
823
824         /* Create a display block for the text region of the line. */
825         {
826                 /* #### urk urk urk!!! Chuck fix this shit! */
827                 Bytind hacked_up_bytind =
828                     create_text_block(w, dl, bufpos_to_bytind(b, start_pos),
829                                       prop, type);
830                 if (hacked_up_bytind > BI_BUF_ZV(b))
831                         ret_bufpos = BUF_ZV(b) + 1;
832                 else
833                         ret_bufpos = bytind_to_bufpos(b, hacked_up_bytind);
834         }
835         dl->bufpos = start_pos;
836         if (dl->end_bufpos < dl->bufpos)
837                 dl->end_bufpos = dl->bufpos;
838
839         if (MARKERP(Voverlay_arrow_position)
840             && EQ(w->buffer, Fmarker_buffer(Voverlay_arrow_position))
841             && start_pos == marker_position(Voverlay_arrow_position)
842             && (STRINGP(Voverlay_arrow_string)
843                 || GLYPHP(Voverlay_arrow_string))) {
844                 overlay_width = create_overlay_glyph_block(w, dl);
845         } else
846                 overlay_width = 0;
847
848         /* If there are left glyphs associated with any character in the
849            text block, then create a display block to handle them. */
850         if (dl->left_glyphs != NULL && Dynarr_length(dl->left_glyphs))
851                 create_left_glyph_block(w, dl, overlay_width);
852
853         /* If there are right glyphs associated with any character in the
854            text block, then create a display block to handle them. */
855         if (dl->right_glyphs != NULL && Dynarr_length(dl->right_glyphs))
856                 create_right_glyph_block(w, dl);
857
858         /* In the future additional types of display blocks may be generated
859            here. */
860
861         w->last_redisplay_pos = ret_bufpos;
862
863         return ret_bufpos;
864 }
865
866 /* Adds an hscroll glyph to a display block.  If this is called, then
867    the block had better be empty.
868
869    Yes, there are multiple places where this function is called but
870    that is the way it has to be.  Each calling function has to deal
871    with bi_start_col_enabled a little differently depending on the
872    object being worked with. */
873
874 static prop_block_dynarr *add_hscroll_rune(pos_data * data)
875 {
876         struct glyph_block gb;
877         prop_block_dynarr *retval;
878         Bytind bi_old_cursor_bufpos = data->bi_cursor_bufpos;
879         unsigned int old_cursor_type = data->cursor_type;
880         Bytind bi_old_bufpos = data->bi_bufpos;
881
882         if (data->cursor_type == CURSOR_ON
883             && data->bi_cursor_bufpos >= data->bi_start_col_enabled
884             && data->bi_cursor_bufpos <= data->bi_bufpos) {
885                 data->bi_cursor_bufpos = data->bi_start_col_enabled;
886         } else {
887                 data->cursor_type = NO_CURSOR;
888         }
889
890         data->bi_endpos = data->bi_bufpos;
891         data->bi_bufpos = data->bi_start_col_enabled;
892
893         gb.extent = Qnil;
894         gb.glyph = Vhscroll_glyph;
895         {
896                 int oldpixpos = data->pixpos;
897                 retval = add_glyph_rune(data, &gb, BEGIN_GLYPHS, 0,
898                                         GLYPH_CACHEL(XWINDOW(data->window),
899                                                      HSCROLL_GLYPH_INDEX));
900                 data->hscroll_glyph_width_adjust =
901                     data->pixpos - oldpixpos -
902                     space_width(XWINDOW(data->window));
903         }
904         data->bi_endpos = 0;
905         data->bi_cursor_bufpos = bi_old_cursor_bufpos;
906         data->cursor_type = old_cursor_type;
907         data->bi_bufpos = bi_old_bufpos;
908
909         data->bi_start_col_enabled = 0;
910         return retval;
911 }
912
913 /* Adds a character rune to a display block.  If there is not enough room
914    to fit the rune on the display block (as determined by the MAX_PIXPOS)
915    then it adds nothing and returns ADD_FAILED.  If
916    NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't allow the char's height
917    to affect the total line height. (See add_intbyte_string_runes()). */
918
919 static prop_block_dynarr *add_emchar_rune_1(pos_data * data,
920                                             int no_contribute_to_line_height)
921 {
922         struct rune rb, *crb;
923         int width, local;
924
925         if (data->start_col) {
926                 data->start_col--;
927
928                 if (data->start_col)
929                         return NULL;
930         }
931
932         if (data->bi_start_col_enabled) {
933                 return add_hscroll_rune(data);
934         }
935
936         if (data->ch == '\n') {
937                 data->font_is_bogus = 0;
938                 /* Cheesy end-of-line pseudo-character. */
939                 width = data->blank_width;
940         } else {
941                 Lisp_Object charset = CHAR_CHARSET(data->ch);
942                 if (!EQ(charset, data->last_charset) ||
943                     data->findex != data->last_findex) {
944                         /* OK, we need to do things the hard way. */
945                         struct window *w = XWINDOW(data->window);
946                         struct face_cachel *cachel =
947                             WINDOW_FACE_CACHEL(w, data->findex);
948                         Lisp_Object font_instance =
949                             ensure_face_cachel_contains_charset(cachel,
950                                                                 data->window,
951                                                                 charset);
952                         Lisp_Font_Instance *fi;
953
954                         if (EQ(font_instance, Vthe_null_font_instance)) {
955                                 font_instance =
956                                     FACE_CACHEL_FONT(cachel, Vcharset_ascii);
957                                 data->font_is_bogus = 1;
958                         } else
959                                 data->font_is_bogus = 0;
960
961                         fi = XFONT_INSTANCE(font_instance);
962                         if (!fi->proportional_p)
963                                 /* sweetness and light. */
964                                 data->last_char_width = fi->width;
965                         else
966                                 data->last_char_width = -1;
967
968                         if (!no_contribute_to_line_height) {
969                                 data->new_ascent =
970                                     max(data->new_ascent, (int)fi->ascent);
971                                 data->new_descent =
972                                     max(data->new_descent, (int)fi->descent);
973                         }
974
975                         data->last_charset = charset;
976                         data->last_findex = data->findex;
977                 }
978
979                 width = data->last_char_width;
980                 if (width < 0) {
981                         /* bummer.  Proportional fonts. */
982                         width =
983                             redisplay_text_width_emchar_string(XWINDOW
984                                                                (data->window),
985                                                                data->findex,
986                                                                &data->ch, 1);
987                 }
988         }
989
990         if (data->max_pixpos != -1 && (data->pixpos + width > data->max_pixpos)) {
991                 return ADD_FAILED;
992         }
993
994         if (Dynarr_length(data->db->runes) < Dynarr_largest(data->db->runes)) {
995                 crb =
996                     Dynarr_atp(data->db->runes, Dynarr_length(data->db->runes));
997                 local = 0;
998         } else {
999                 crb = &rb;
1000                 local = 1;
1001         }
1002
1003         crb->findex = data->findex;
1004         crb->xpos = data->pixpos;
1005         crb->width = width;
1006         if (data->bi_bufpos) {
1007                 if (NILP(data->string))
1008                         crb->bufpos =
1009                             bytind_to_bufpos(XBUFFER
1010                                              (WINDOW_BUFFER
1011                                               (XWINDOW(data->window))),
1012                                              data->bi_bufpos);
1013                 else
1014                         crb->bufpos =
1015                             bytecount_to_charcount(XSTRING_DATA(data->string),
1016                                                    data->bi_bufpos);
1017         } else if (data->is_modeline)
1018                 crb->bufpos = data->modeline_charpos;
1019         else
1020                 /* Text but not in buffer */
1021                 crb->bufpos = 0;
1022         crb->type = RUNE_CHAR;
1023         crb->object.chr.ch = data->font_is_bogus ? '~' : data->ch;
1024         crb->endpos = 0;
1025
1026         if (data->cursor_type == CURSOR_ON) {
1027                 if (data->bi_bufpos == data->bi_cursor_bufpos) {
1028                         crb->cursor_type = CURSOR_ON;
1029                         data->cursor_x = Dynarr_length(data->db->runes);
1030                 } else
1031                         crb->cursor_type = CURSOR_OFF;
1032         } else if (data->cursor_type == NEXT_CURSOR) {
1033                 crb->cursor_type = CURSOR_ON;
1034                 data->cursor_x = Dynarr_length(data->db->runes);
1035                 data->cursor_type = NO_CURSOR;
1036         } else if (data->cursor_type == IGNORE_CURSOR)
1037                 crb->cursor_type = IGNORE_CURSOR;
1038         else
1039                 crb->cursor_type = CURSOR_OFF;
1040
1041         if (local)
1042                 Dynarr_add(data->db->runes, *crb);
1043         else
1044                 Dynarr_increment(data->db->runes);
1045
1046         data->pixpos += width;
1047
1048         return NULL;
1049 }
1050
1051 static prop_block_dynarr *add_emchar_rune(pos_data * data)
1052 {
1053         return add_emchar_rune_1(data, 0);
1054 }
1055
1056 /* Given a string C_STRING of length C_LENGTH, call add_emchar_rune for
1057    each character in the string.  Propagate any left-over data unless
1058    NO_PROP is non-zero.  If NO_CONTRIBUTE_TO_LINE_HEIGHT is non-zero, don't
1059    allow this character to increase the total height of the line. (This is
1060    used when the character is part of a text glyph.  In that case, the
1061    glyph code itself adjusts the line height as necessary, depending on
1062    whether glyph-contrib-p is true.) */
1063
1064 static prop_block_dynarr *add_bufbyte_string_runes(pos_data * data,
1065                                                    Bufbyte * c_string,
1066                                                    Bytecount c_length,
1067                                                    int no_prop,
1068                                                    int
1069                                                    no_contribute_to_line_height)
1070 {
1071         Bufbyte *pos, *end = c_string + c_length;
1072         prop_block_dynarr *prop;
1073
1074         /* #### This function is too simplistic.  It needs to do the same
1075            sort of character interpretation (display-table lookup,
1076            ctl-arrow checking), etc. that create_text_block() does.
1077            The functionality to do this in that routine needs to be
1078            modularized. */
1079
1080         for (pos = c_string; pos < end;) {
1081                 Bufbyte *old_pos = pos;
1082
1083                 data->ch = charptr_emchar(pos);
1084
1085                 prop = add_emchar_rune_1(data, no_contribute_to_line_height);
1086
1087                 if (prop) {
1088                         if (no_prop)
1089                                 return ADD_FAILED;
1090                         else {
1091                                 struct prop_block pb;
1092                                 Bytecount len = end - pos;
1093                                 prop = Dynarr_new(prop_block);
1094
1095                                 pb.type = PROP_STRING;
1096                                 pb.data.p_string.str =
1097                                         xnew_atomic_array(Bufbyte, len+1);
1098                                 xstrncpy((char *)pb.data.p_string.str,
1099                                         (char *)pos, len+1);
1100                                 pb.data.p_string.len = len;
1101
1102                                 Dynarr_add(prop, pb);
1103                                 return prop;
1104                         }
1105                 }
1106                 INC_CHARPTR(pos);
1107                 assert(pos <= end);
1108                 /* #### Duplicate code from add_string_to_fstring_db_runes
1109                    should we do more? */
1110                 data->bytepos += pos - old_pos;
1111         }
1112
1113         return NULL;
1114 }
1115
1116 /* Add a single rune of the specified width.  The area covered by this
1117    rune will be displayed in the foreground color of the associated
1118    face. */
1119
1120 static prop_block_dynarr *add_blank_rune(pos_data * data, struct window *w,
1121                                          int char_tab_width)
1122 {
1123         struct rune rb;
1124
1125         /* If data->start_col is not 0 then this call to add_blank_rune must have
1126            been to add it as a tab. */
1127         if (data->start_col) {
1128                 /* assert (w != NULL) */
1129                 prop_block_dynarr *retval;
1130
1131                 /* If we have still not fully scrolled horizontally, subtract
1132                    the width of this tab and return. */
1133                 if (char_tab_width < data->start_col) {
1134                         data->start_col -= char_tab_width;
1135                         return NULL;
1136                 } else if (char_tab_width == data->start_col)
1137                         data->blank_width = 0;
1138                 else {
1139                         int spcwid = space_width(w);
1140
1141                         if (spcwid >= data->blank_width)
1142                                 data->blank_width = 0;
1143                         else
1144                                 data->blank_width -= spcwid;
1145                 }
1146
1147                 data->start_col = 0;
1148                 retval = add_hscroll_rune(data);
1149
1150                 /* Could be caused by the handling of the hscroll rune. */
1151                 if (retval != NULL || !data->blank_width)
1152                         return retval;
1153         }
1154
1155         /* Blank runes are always calculated to fit. */
1156         assert(data->pixpos + data->blank_width <= data->max_pixpos);
1157
1158         rb.findex = data->findex;
1159         rb.xpos = data->pixpos;
1160         rb.width = data->blank_width;
1161         if (data->bi_bufpos)
1162                 rb.bufpos =
1163                     bytind_to_bufpos(XBUFFER
1164                                      (WINDOW_BUFFER(XWINDOW(data->window))),
1165                                      data->bi_bufpos);
1166         else
1167                 /* #### and this is really correct too? */
1168                 rb.bufpos = 0;
1169         rb.endpos = 0;
1170         rb.type = RUNE_BLANK;
1171
1172         if (data->cursor_type == CURSOR_ON) {
1173                 if (data->bi_bufpos == data->bi_cursor_bufpos) {
1174                         rb.cursor_type = CURSOR_ON;
1175                         data->cursor_x = Dynarr_length(data->db->runes);
1176                 } else
1177                         rb.cursor_type = CURSOR_OFF;
1178         } else if (data->cursor_type == NEXT_CURSOR) {
1179                 rb.cursor_type = CURSOR_ON;
1180                 data->cursor_x = Dynarr_length(data->db->runes);
1181                 data->cursor_type = NO_CURSOR;
1182         } else
1183                 rb.cursor_type = CURSOR_OFF;
1184
1185         Dynarr_add(data->db->runes, rb);
1186         data->pixpos += data->blank_width;
1187
1188         return NULL;
1189 }
1190
1191 static void add_blank_rune_noret(pos_data * data, struct window *w,
1192                                  int char_tab_width)
1193 {
1194         prop_block_dynarr *prop = add_blank_rune(data,w,char_tab_width);
1195         if (prop && prop != ADD_FAILED )
1196                 Dynarr_free(prop);
1197 }
1198
1199 /* Add runes representing a character in octal. */
1200
1201 #define ADD_NEXT_OCTAL_RUNE_CHAR do                             \
1202 {                                                               \
1203   if (add_failed || (add_failed = add_emchar_rune (data)))      \
1204     {                                                           \
1205       struct prop_block pb;                                     \
1206       if (!prop)                                                \
1207         prop = Dynarr_new (prop_block);                         \
1208                                                                 \
1209       pb.type = PROP_CHAR;                                      \
1210       pb.data.p_char.ch = data->ch;                             \
1211       pb.data.p_char.cursor_type = data->cursor_type;           \
1212       Dynarr_add (prop, pb);                                    \
1213     }                                                           \
1214 } while (0)
1215
1216 static prop_block_dynarr *add_octal_runes(pos_data * data)
1217 {
1218         prop_block_dynarr *add_failed, *prop = 0;
1219         Emchar orig_char = data->ch;
1220         unsigned int orig_cursor_type = data->cursor_type;
1221
1222         /* Initialize */
1223         add_failed = NULL;
1224
1225         if (data->start_col)
1226                 data->start_col--;
1227
1228         if (!data->start_col) {
1229                 if (data->bi_start_col_enabled) {
1230                         add_failed = add_hscroll_rune(data);
1231                 } else {
1232                         struct glyph_block gb;
1233                         struct window *w = XWINDOW(data->window);
1234
1235                         gb.extent = Qnil;
1236                         gb.glyph = Voctal_escape_glyph;
1237                         add_failed =
1238                             add_glyph_rune(data, &gb, BEGIN_GLYPHS, 1,
1239                                            GLYPH_CACHEL(w,
1240                                                         OCT_ESC_GLYPH_INDEX));
1241                 }
1242         }
1243
1244         /* We only propagate information if the glyph was partially
1245            added. */
1246         if (add_failed)
1247                 return add_failed;
1248
1249         data->cursor_type = IGNORE_CURSOR;
1250
1251         if (data->ch >= 0x100) {
1252                 /* If the character is an extended Mule character, it could have
1253                    up to 19 bits.  For the moment, we treat it as a seven-digit
1254                    octal number.  This is not that pretty, but whatever. */
1255                 data->ch = (7 & (orig_char >> 18)) + '0';
1256                 ADD_NEXT_OCTAL_RUNE_CHAR;
1257
1258                 data->ch = (7 & (orig_char >> 15)) + '0';
1259                 ADD_NEXT_OCTAL_RUNE_CHAR;
1260
1261                 data->ch = (7 & (orig_char >> 12)) + '0';
1262                 ADD_NEXT_OCTAL_RUNE_CHAR;
1263
1264                 data->ch = (7 & (orig_char >> 9)) + '0';
1265                 ADD_NEXT_OCTAL_RUNE_CHAR;
1266         }
1267
1268         data->ch = (7 & (orig_char >> 6)) + '0';
1269         ADD_NEXT_OCTAL_RUNE_CHAR;
1270
1271         data->ch = (7 & (orig_char >> 3)) + '0';
1272         ADD_NEXT_OCTAL_RUNE_CHAR;
1273
1274         data->ch = (7 & orig_char) + '0';
1275         ADD_NEXT_OCTAL_RUNE_CHAR;
1276
1277         (void)add_failed;
1278
1279         data->cursor_type = orig_cursor_type;
1280         if (prop && prop != ADD_FAILED )
1281                 Dynarr_free(prop);
1282         return NULL;
1283 }
1284
1285 #undef ADD_NEXT_OCTAL_RUNE_CHAR
1286
1287 /* Add runes representing a control character to a display block. */
1288
1289 static prop_block_dynarr *add_control_char_runes(pos_data * data,
1290                                                  struct buffer *b)
1291 {
1292         if (!NILP(b->ctl_arrow)) {
1293                 prop_block_dynarr *prop;
1294                 Emchar orig_char = data->ch;
1295                 unsigned int old_cursor_type = data->cursor_type;
1296
1297                 /* Initialize */
1298                 prop = NULL;
1299
1300                 if (data->start_col)
1301                         data->start_col--;
1302
1303                 if (!data->start_col) {
1304                         if (data->bi_start_col_enabled) {
1305                                 prop_block_dynarr *retval;
1306
1307                                 retval = add_hscroll_rune(data);
1308                                 if (retval)
1309                                         return retval;
1310                         } else {
1311                                 struct glyph_block gb;
1312                                 struct window *w = XWINDOW(data->window);
1313
1314                                 gb.extent = Qnil;
1315                                 gb.glyph = Vcontrol_arrow_glyph;
1316
1317                                 /* We only propagate information if the glyph was partially
1318                                    added. */
1319                                 prop = add_glyph_rune(data, &gb, BEGIN_GLYPHS, 1,
1320                                                       GLYPH_CACHEL(w, CONTROL_GLYPH_INDEX));
1321                                 if ( prop != NULL ) {
1322                                         if ( prop != ADD_FAILED )
1323                                                 Dynarr_free(prop);
1324                                         return ADD_FAILED;
1325                                 }
1326                         }
1327                 }
1328
1329                 if (orig_char == 0177)
1330                         data->ch = '?';
1331                 else
1332                         data->ch = orig_char ^ 0100;
1333                 data->cursor_type = IGNORE_CURSOR;
1334
1335                 if (add_emchar_rune(data)) {
1336                         struct prop_block pb;
1337                         if (!prop)
1338                                 prop = Dynarr_new(prop_block);
1339
1340                         pb.type = PROP_CHAR;
1341                         pb.data.p_char.ch = data->ch;
1342                         pb.data.p_char.cursor_type = data->cursor_type;
1343                         Dynarr_add(prop, pb);
1344                 }
1345
1346                 data->cursor_type = old_cursor_type;
1347                 return prop;
1348         } else {
1349                 return add_octal_runes(data);
1350         }
1351 }
1352
1353 static prop_block_dynarr *add_disp_table_entry_runes_1(pos_data * data,
1354                                                        Lisp_Object entry)
1355 {
1356         prop_block_dynarr *prop = NULL;
1357
1358         if (STRINGP(entry)) {
1359                 prop = add_bufbyte_string_runes(data,
1360                                                 XSTRING_DATA(entry),
1361                                                 XSTRING_LENGTH(entry), 0, 0);
1362         } else if (GLYPHP(entry)) {
1363                 if (data->start_col)
1364                         data->start_col--;
1365
1366                 if (!data->start_col && data->bi_start_col_enabled) {
1367                         prop = add_hscroll_rune(data);
1368                 } else {
1369                         struct glyph_block gb;
1370
1371                         gb.glyph = entry;
1372                         gb.extent = Qnil;
1373                         prop = add_glyph_rune(data, &gb, BEGIN_GLYPHS, 0, 0);
1374                 }
1375         } else if (CHAR_OR_CHAR_INTP(entry)) {
1376                 data->ch = XCHAR_OR_CHAR_INT(entry);
1377                 prop = add_emchar_rune(data);
1378         } else if (CONSP(entry)) {
1379                 if (EQ(XCAR(entry), Qformat)
1380                     && CONSP(XCDR(entry))
1381                     && STRINGP(XCAR(XCDR(entry)))) {
1382                         Lisp_Object format = XCAR(XCDR(entry));
1383                         Bytind len = XSTRING_LENGTH(format);
1384                         Bufbyte *src = XSTRING_DATA(format), *end = src + len;
1385                         Bufbyte *result = alloca_array(Bufbyte, len);
1386                         Bufbyte *dst = result;
1387
1388                         while (src < end) {
1389                                 Emchar c = charptr_emchar(src);
1390                                 INC_CHARPTR(src);
1391                                 if (c != '%' || src == end) {
1392                                         dst += set_charptr_emchar(dst, c);
1393                                 } else {
1394                                         c = charptr_emchar(src);
1395                                         INC_CHARPTR(src);
1396                                         switch (c) {
1397                                                 /*case 'x':
1398                                                    dst += long_to_string_base
1399                                                    ((char *)dst, data->ch, 16);
1400                                                    break; */
1401                                         case '%':
1402                                                 dst += set_charptr_emchar(
1403                                                         dst, '%');
1404                                                 break;
1405                                                 /* #### unimplemented */
1406                                         default:
1407                                                 ;
1408                                         }
1409                                 }
1410                         }
1411                         prop =
1412                             add_bufbyte_string_runes(data, result, dst - result,
1413                                                      0, 0);
1414                 }
1415         }
1416
1417         /* Else blow it off because someone added a bad entry and we don't
1418            have any safe way of signaling an error. */
1419         return prop;
1420 }
1421
1422 /* Given a display table entry, call the appropriate functions to
1423    display each element of the entry. */
1424
1425 static prop_block_dynarr *add_disp_table_entry_runes(pos_data * data,
1426                                                      Lisp_Object entry)
1427 {
1428         prop_block_dynarr *prop = NULL;
1429         if (VECTORP(entry)) {
1430                 Lisp_Vector *de = XVECTOR(entry);
1431                 EMACS_INT len = vector_length(de);
1432                 int elt;
1433
1434                 for (elt = 0; elt < len; elt++) {
1435                         if (NILP(vector_data(de)[elt]))
1436                                 continue;
1437                         else
1438                                 prop =
1439                                     add_disp_table_entry_runes_1(data,
1440                                                                  vector_data(de)
1441                                                                  [elt]);
1442                         /* Else blow it off because someone added a bad entry and we
1443                            don't have any safe way of signaling an error.  Hey, this
1444                            comment sounds familiar. */
1445
1446                         /* #### Still need to add any remaining elements to the
1447                            propagation information. */
1448                         if (prop)
1449                                 return prop;
1450                 }
1451         } else
1452                 prop = add_disp_table_entry_runes_1(data, entry);
1453         return prop;
1454 }
1455
1456 /* Add runes which were propagated from the previous line. */
1457
1458 static prop_block_dynarr *add_propagation_runes(prop_block_dynarr ** prop,
1459                                                 pos_data * data)
1460 {
1461         /* #### Remember to handle start_col parameter of data when the rest of
1462            this is finished. */
1463         /* #### Chuck -- I've redone this function a bit.  It looked like the
1464            case of not all the propagation blocks being added was not handled
1465            well. */
1466         /* #### Chuck -- I also think the double indirection of PROP is kind
1467            of bogus.  A cleaner solution is just to check for
1468            Dynarr_length (prop) > 0. */
1469         /* #### This function also doesn't even pay attention to ADD_FAILED!
1470            This is seriously fucked!  Seven ####'s in 130 lines -- is that a
1471            record? */
1472         int elt;
1473         prop_block_dynarr *add_failed;
1474         Bytind bi_old_cursor_bufpos = data->bi_cursor_bufpos;
1475         unsigned int old_cursor_type = data->cursor_type;
1476
1477         for (elt = 0; elt < Dynarr_length(*prop); elt++) {
1478                 struct prop_block *pb = Dynarr_atp(*prop, elt);
1479
1480                 switch (pb->type) {
1481                 case PROP_CHAR:
1482                         data->ch = pb->data.p_char.ch;
1483                         data->bi_cursor_bufpos =
1484                             pb->data.p_char.bi_cursor_bufpos;
1485                         data->cursor_type = pb->data.p_char.cursor_type;
1486                         add_failed = add_emchar_rune(data);
1487
1488                         if (add_failed)
1489                                 goto oops_no_more_space;
1490                         break;
1491                 case PROP_STRING:
1492                         if (pb->data.p_string.str)
1493                                 xfree(pb->data.p_string.str);
1494                         /* #### bogus bogus -- this doesn't do anything!
1495                            Should probably call add_bufbyte_string_runes(),
1496                            once that function is fixed. */
1497                         break;
1498                 case PROP_MINIBUF_PROMPT: {
1499                         face_index old_findex = data->findex;
1500                         Bytind bi_old_bufpos = data->bi_bufpos;
1501
1502                         data->findex = DEFAULT_INDEX;
1503                         data->bi_bufpos = 0;
1504                         data->cursor_type = NO_CURSOR;
1505
1506                         while (pb->data.p_string.len > 0) {
1507                                 data->ch =
1508                                         charptr_emchar(pb->data.p_string.
1509                                                        str);
1510                                 add_failed = add_emchar_rune(data);
1511
1512                                 if (add_failed) {
1513                                         data->findex = old_findex;
1514                                         data->bi_bufpos = bi_old_bufpos;
1515                                         goto oops_no_more_space;
1516                                 } else {
1517                                         /* Complicated equivalent of ptr++,
1518                                            len-- */
1519                                         Bufbyte *oldpos =
1520                                                 pb->data.p_string.str;
1521                                         INC_CHARPTR(pb->data.p_string.
1522                                                     str);
1523                                         pb->data.p_string.len -=
1524                                                 pb->data.p_string.str -
1525                                                 oldpos;
1526                                 }
1527                         }
1528
1529                         data->findex = old_findex;
1530                         /* ##### FIXME FIXME FIXME -- Upon successful return
1531                            from this function, data->bi_bufpos is automatically
1532                            incremented.  However, we don't want that to happen
1533                            if we were adding the minibuffer prompt. */
1534                         {
1535                                 struct buffer *buf =
1536                                         XBUFFER(WINDOW_BUFFER
1537                                                 (XWINDOW(data->window)));
1538                                 /* #### Chuck fix this shit or I'm gonna
1539                                    scream! */
1540                                 if (bi_old_bufpos > BI_BUF_BEGV(buf)) {
1541                                         data->bi_bufpos =
1542                                                 prev_bytind(buf,
1543                                                             bi_old_bufpos);
1544                                 } else {
1545                                         /* #### is this correct?
1546                                          * Does anyone know?
1547                                            Does anyone care? Is this a cheesy
1548                                            hack or what? */
1549                                         data->bi_bufpos =
1550                                                 BI_BUF_BEGV(buf) - 1;
1551                                 }
1552                         }
1553                 }
1554                         break;
1555                 case PROP_BLANK: {
1556                         /* #### I think it's unnecessary and misleading to
1557                            preserve the blank_width, as it implies that the
1558                            value carries over from one rune to the next,
1559                            which is wrong. */
1560                         int old_width = data->blank_width;
1561                         face_index old_findex = data->findex;
1562
1563                         data->findex = pb->data.p_blank.findex;
1564                         data->blank_width = pb->data.p_blank.width;
1565                         data->bi_cursor_bufpos = 0;
1566                         data->cursor_type = IGNORE_CURSOR;
1567
1568                         if (data->pixpos + data->blank_width >
1569                             data->max_pixpos)
1570                                 data->blank_width =
1571                                         data->max_pixpos - data->pixpos;
1572
1573                         /* We pass a bogus value of char_tab_width.  It
1574                            shouldn't matter because unless something is really
1575                            screwed up this call won't cause that arg to be
1576                            used. */
1577                         add_failed = add_blank_rune(
1578                                 data, XWINDOW(data->window), 0);
1579
1580                         /* This can happen in the case where we have a tab which
1581                            is wider than the window. */
1582                         if (data->blank_width != pb->data.p_blank.width) {
1583                                 pb->data.p_blank.width -=
1584                                         data->blank_width;
1585                                 add_failed = ADD_FAILED;
1586                         }
1587
1588                         data->findex = old_findex;
1589                         data->blank_width = old_width;
1590
1591                         if (add_failed)
1592                                 goto oops_no_more_space;
1593                 }
1594                         break;
1595
1596                 case PROP_GLYPH:
1597                 default:
1598                         abort();
1599                 }
1600         }
1601
1602       oops_no_more_space:
1603
1604         data->bi_cursor_bufpos = bi_old_cursor_bufpos;
1605         data->cursor_type = old_cursor_type;
1606         if (elt < Dynarr_length(*prop)) {
1607                 Dynarr_delete_many(*prop, 0, elt);
1608                 return *prop;
1609         } else {
1610                 Dynarr_free(*prop);
1611                 return NULL;
1612         }
1613 }
1614
1615 /* Add 'text layout glyphs at position POS_TYPE that are contained to
1616    the display block, but add all other types to the appropriate list
1617    of the display line.  They will be added later by different
1618    routines. */
1619
1620 static void add_glyph_rune_noret(pos_data * data,
1621                                  struct glyph_block *gb, int pos_type,
1622                                  int allow_cursor,
1623                                  struct glyph_cachel *cachel)
1624 {
1625         prop_block_dynarr *prop = add_glyph_rune(data,gb,pos_type,allow_cursor,cachel);
1626         if (prop && prop != ADD_FAILED )
1627                 Dynarr_free(prop);
1628 }
1629
1630 static prop_block_dynarr *add_glyph_rune(pos_data * data,
1631                                          struct glyph_block *gb, int pos_type,
1632                                          int allow_cursor,
1633                                          struct glyph_cachel *cachel)
1634 {
1635         struct window *w = XWINDOW(data->window);
1636
1637         /* If window faces changed, and glyph instance is text, then
1638            glyph sizes might have changed too */
1639         invalidate_glyph_geometry_maybe(gb->glyph, w);
1640
1641         /* This makes sure the glyph is in the cachels.
1642
1643            #### We do this to make sure the glyph is in the glyph cachels,
1644            so that the dirty flag can be reset after redisplay has
1645            finished. We should do this some other way, maybe by iterating
1646            over the window cache of subwindows. */
1647         get_glyph_cachel_index(w, gb->glyph);
1648
1649         /* A nil extent indicates a special glyph (ex. truncator). */
1650         if (NILP(gb->extent)
1651             || (pos_type == BEGIN_GLYPHS &&
1652                 extent_begin_glyph_layout(XEXTENT(gb->extent)) == GL_TEXT)
1653             || (pos_type == END_GLYPHS &&
1654                 extent_end_glyph_layout(XEXTENT(gb->extent)) == GL_TEXT)
1655             || pos_type == LEFT_GLYPHS || pos_type == RIGHT_GLYPHS) {
1656                 struct rune rb;
1657                 int width;
1658                 int xoffset = 0;
1659                 int ascent, descent;
1660                 Lisp_Object baseline;
1661                 Lisp_Object face;
1662                 Lisp_Object instance;
1663                 face_index findex;
1664                 prop_block_dynarr *retval = 0;
1665
1666                 if (cachel)
1667                         width = cachel->width;
1668                 else
1669                         width = glyph_width(gb->glyph, data->window);
1670
1671                 if (!width)
1672                         return NULL;
1673
1674                 if (data->start_col || data->start_col_xoffset) {
1675                         int glyph_char_width = width / space_width(w);
1676
1677                         /* If we still have not fully scrolled horizontally after
1678                            taking into account the width of the glyph, subtract its
1679                            width and return. */
1680                         if (glyph_char_width < data->start_col) {
1681                                 data->start_col -= glyph_char_width;
1682                                 return NULL;
1683                         } else if (glyph_char_width == data->start_col)
1684                                 width = 0;
1685                         else {
1686                                 xoffset = space_width(w) * data->start_col;
1687                                 width -= xoffset;
1688
1689                                 /* #### Can this happen? */
1690                                 if (width < 0)
1691                                         width = 0;
1692                         }
1693
1694                         data->start_col = 0;
1695                         retval = add_hscroll_rune(data);
1696
1697                         /* Could be caused by the handling of the hscroll rune. */
1698                         if (retval != NULL || !width)
1699                                 return retval;
1700                 } else
1701                         xoffset = 0;
1702
1703                 if (data->pixpos + width > data->max_pixpos) {
1704                         /* If this is the first object we are attempting to add to
1705                            the line then we ignore the horizontal_clip threshold.
1706                            Otherwise we will loop until the bottom of the window
1707                            continually failing to add this glyph because it is wider
1708                            than the window.  We could alternatively just completely
1709                            ignore the glyph and proceed from there but I think that
1710                            this is a better solution.
1711
1712                            This does, however, create a different problem in that we
1713                            can end up adding the object to every single line, never
1714                            getting any further - for instance an extent with a long
1715                            start-glyph that covers multitple following
1716                            characters.  */
1717                         if (Dynarr_length(data->db->runes)
1718                             && data->max_pixpos - data->pixpos <
1719                             horizontal_clip)
1720                                 return ADD_FAILED;
1721                         else {
1722                                 struct prop_block pb;
1723
1724                                 /* We need to account for the width of the end-of-line
1725                                    glyph if there is nothing more in the line to display,
1726                                    since we will not display it in this instance. It seems
1727                                    kind of gross doing it here, but otherwise we have to
1728                                    search the runes in create_text_block(). */
1729                                 if (data->ch == '\n')
1730                                         data->max_pixpos +=
1731                                             data->end_glyph_width;
1732                                 width = data->max_pixpos - data->pixpos;
1733                                 /* Add the glyph we are displaying, but clipping, to the
1734                                    propagation data so that we don't try and do it
1735                                    again. */
1736                                 retval = Dynarr_new(prop_block);
1737                                 pb.type = PROP_GLYPH;
1738                                 pb.data.p_glyph.glyph = gb->glyph;
1739                                 pb.data.p_glyph.width = width;
1740                                 Dynarr_add(retval, pb);
1741                         }
1742                 }
1743
1744                 if (cachel) {
1745                         ascent = cachel->ascent;
1746                         descent = cachel->descent;
1747                 } else {
1748                         ascent = glyph_ascent(gb->glyph, data->window);
1749                         descent = glyph_descent(gb->glyph, data->window);
1750                 }
1751
1752                 baseline = glyph_baseline(gb->glyph, data->window);
1753
1754                 rb.object.dglyph.descent = 0;   /* Gets reset lower down, if it is known. */
1755
1756                 if (glyph_contrib_p(gb->glyph, data->window)) {
1757                         /* A pixmap that has not had a baseline explicitly set.  Its
1758                            contribution will be determined later. */
1759                         if (NILP(baseline)) {
1760                                 int height = ascent + descent;
1761                                 data->need_baseline_computation = 1;
1762                                 data->max_pixmap_height =
1763                                     max(data->max_pixmap_height, height);
1764                         }
1765
1766                         /* A string so determine contribution normally. */
1767                         else if (EQ(baseline, Qt)) {
1768                                 data->new_ascent =
1769                                     max(data->new_ascent, ascent);
1770                                 data->new_descent =
1771                                     max(data->new_descent, descent);
1772                         }
1773
1774                         /* A pixmap with an explicitly set baseline.  We determine the
1775                            contribution here. */
1776                         else if (INTP(baseline)) {
1777                                 int height = ascent + descent;
1778                                 int pix_ascent, pix_descent;
1779
1780                                 pix_ascent = height * XINT(baseline) / 100;
1781                                 pix_descent = height - pix_ascent;
1782
1783                                 data->new_ascent =
1784                                     max(data->new_ascent, pix_ascent);
1785                                 data->new_descent =
1786                                     max(data->new_descent, pix_descent);
1787                                 data->max_pixmap_height =
1788                                     max(data->max_pixmap_height, height);
1789
1790                                 rb.object.dglyph.descent = pix_descent;
1791                         }
1792
1793                         /* Otherwise something is screwed up. */
1794                         else
1795                                 abort();
1796                 }
1797
1798                 face = glyph_face(gb->glyph, data->window);
1799                 if (NILP(face))
1800                         findex = data->findex;
1801                 else
1802                         findex = get_builtin_face_cache_index(w, face);
1803
1804                 instance = glyph_image_instance(gb->glyph, data->window,
1805                                                 ERROR_ME_NOT, 1);
1806                 if (TEXT_IMAGE_INSTANCEP(instance)) {
1807                         Lisp_Object string =
1808                             XIMAGE_INSTANCE_TEXT_STRING(instance);
1809                         face_index orig_findex = data->findex;
1810                         Bytind orig_bufpos = data->bi_bufpos;
1811                         Bytind orig_start_col_enabled =
1812                             data->bi_start_col_enabled;
1813
1814                         data->findex = findex;
1815                         data->bi_start_col_enabled = 0;
1816                         if (!allow_cursor)
1817                                 data->bi_bufpos = 0;
1818                         {
1819                                 prop_block_dynarr * tmp = NULL;
1820                                 tmp = add_bufbyte_string_runes(data,
1821                                                        XSTRING_DATA(string),
1822                                                        XSTRING_LENGTH(string),
1823                                                        0, 1);
1824                                 if(tmp)
1825                                         Dynarr_free(tmp);
1826                         }
1827                         data->findex = orig_findex;
1828                         data->bi_bufpos = orig_bufpos;
1829                         data->bi_start_col_enabled = orig_start_col_enabled;
1830                         return retval;
1831                 }
1832
1833                 rb.findex = findex;
1834                 rb.xpos = data->pixpos;
1835                 rb.width = width;
1836                 rb.bufpos = 0;  /* glyphs are never "at" anywhere */
1837                 if (data->bi_endpos)
1838                         /* #### is this necessary at all? */
1839                         rb.endpos = bytind_to_bufpos(XBUFFER(WINDOW_BUFFER(w)),
1840                                                      data->bi_endpos);
1841                 else
1842                         rb.endpos = 0;
1843                 rb.type = RUNE_DGLYPH;
1844                 rb.object.dglyph.glyph = gb->glyph;
1845                 rb.object.dglyph.extent = gb->extent;
1846                 rb.object.dglyph.xoffset = xoffset;
1847                 rb.object.dglyph.ascent = ascent;
1848                 rb.object.dglyph.yoffset = 0;   /* Until we know better, assume that it has
1849                                                    a normal (textual) baseline. */
1850
1851                 if (allow_cursor) {
1852                         rb.bufpos = bytind_to_bufpos(XBUFFER(WINDOW_BUFFER(w)),
1853                                                      data->bi_bufpos);
1854
1855                         if (data->cursor_type == CURSOR_ON) {
1856                                 if (data->bi_bufpos == data->bi_cursor_bufpos) {
1857                                         rb.cursor_type = CURSOR_ON;
1858                                         data->cursor_x =
1859                                             Dynarr_length(data->db->runes);
1860                                 } else
1861                                         rb.cursor_type = CURSOR_OFF;
1862                         } else if (data->cursor_type == NEXT_CURSOR) {
1863                                 rb.cursor_type = CURSOR_ON;
1864                                 data->cursor_x = Dynarr_length(data->db->runes);
1865                                 data->cursor_type = NO_CURSOR;
1866                         } else if (data->cursor_type == IGNORE_CURSOR)
1867                                 rb.cursor_type = IGNORE_CURSOR;
1868                         else if (data->cursor_type == NO_CURSOR)
1869                                 rb.cursor_type = NO_CURSOR;
1870                         else
1871                                 rb.cursor_type = CURSOR_OFF;
1872                 } else
1873                         rb.cursor_type = CURSOR_OFF;
1874
1875                 Dynarr_add(data->db->runes, rb);
1876                 data->pixpos += width;
1877
1878                 return retval;
1879         } else {
1880                 if (!NILP(glyph_face(gb->glyph, data->window)))
1881                         gb->findex =
1882                             get_builtin_face_cache_index(w,
1883                                                          glyph_face(gb->glyph,
1884                                                                     data->
1885                                                                     window));
1886                 else
1887                         gb->findex = data->findex;
1888
1889                 if (pos_type == BEGIN_GLYPHS) {
1890                         if (!data->dl->left_glyphs)
1891                                 data->dl->left_glyphs = Dynarr_new(glyph_block);
1892                         Dynarr_add(data->dl->left_glyphs, *gb);
1893                         return NULL;
1894                 } else if (pos_type == END_GLYPHS) {
1895                         if (!data->dl->right_glyphs)
1896                                 data->dl->right_glyphs =
1897                                     Dynarr_new(glyph_block);
1898                         Dynarr_add(data->dl->right_glyphs, *gb);
1899                         return NULL;
1900                 } else
1901                         abort();        /* there are no unknown types */
1902         }
1903
1904         return NULL;
1905 }
1906
1907 /* Add all glyphs at position POS_TYPE that are contained in the given
1908    data. */
1909
1910 static prop_block_dynarr *add_glyph_runes(pos_data * data)
1911 {
1912         /* #### This still needs to handle the start_col parameter.  Duh, Chuck,
1913            why didn't you just modify add_glyph_rune in the first place? */
1914         int elt;
1915         glyph_block_dynarr *glyph_arr = (data->ef->glyphs);
1916         prop_block_dynarr *prop;
1917
1918         for (elt = 0; elt < Dynarr_length(glyph_arr); elt++) {
1919                 struct glyph_block *gb = Dynarr_atp(glyph_arr, elt);
1920                 prop = add_glyph_rune(data, gb,
1921                                       gb->active ? END_GLYPHS : BEGIN_GLYPHS,
1922                                       0, 0);
1923
1924                 if (prop) {
1925                         /* #### Add some propagation information. */
1926                         return prop;
1927                 }
1928         }
1929
1930         Dynarr_reset(glyph_arr);
1931
1932         return NULL;
1933 }
1934
1935 /* Given a position for a buffer in a window, ensure that the given
1936    display line DL accurately represents the text on a line starting
1937    at the given position.
1938
1939    NOTE NOTE NOTE NOTE: This function works with and returns Bytinds.
1940    You must do appropriate conversion. */
1941
1942 static Bytind
1943 create_text_block(struct window *w, struct display_line *dl,
1944                   Bytind bi_start_pos, prop_block_dynarr ** prop, int type)
1945 {
1946         struct frame *f = XFRAME(w->frame);
1947         struct buffer *b = XBUFFER(w->buffer);
1948         struct device *d = XDEVICE(f->device);
1949
1950         pos_data data;
1951
1952         /* Don't display anything in the minibuffer if this window is not on
1953            a selected frame.  We consider all other windows to be active
1954            minibuffers as it simplifies the coding. */
1955         int active_minibuffer = (!MINI_WINDOW_P(w) ||
1956                                  (f == device_selected_frame(d)) ||
1957                                  is_surrogate_for_selected_frame(f));
1958
1959         int truncate_win = window_truncation_on(w);
1960
1961         /* If the buffer's value of selective_display is an integer then
1962            only lines that start with less than selective_display columns of
1963            space will be displayed.  If selective_display is t then all text
1964            after a ^M is invisible. */
1965         int selective = (INTP(b->selective_display)
1966                          ? XINT(b->selective_display)
1967                          : (!NILP(b->selective_display) ? -1 : 0));
1968
1969         /* The variable ctl-arrow allows the user to specify what characters
1970            can actually be displayed and which octal should be used for.
1971            #### This variable should probably have some rethought done to
1972            it.
1973
1974            #### It would also be really nice if you could specify that
1975            the characters come out in hex instead of in octal.  Mule
1976            does that by adding a ctl-hexa variable similar to ctl-arrow,
1977            but that's bogus -- we need a more general solution.  I
1978            think you need to extend the concept of display tables
1979            into a more general conversion mechanism.  Ideally you
1980            could specify a Lisp function that converts characters,
1981            but this violates the Second Golden Rule and besides would
1982            make things way way way way slow.
1983
1984            So instead, we extend the display-table concept, which was
1985            historically limited to 256-byte vectors, to one of the
1986            following:
1987
1988            a) A 256-entry vector, for backward compatibility;
1989            b) char-table, mapping characters to values;
1990            c) range-table, mapping ranges of characters to values;
1991            d) a list of the above.
1992
1993            The (d) option allows you to specify multiple display tables
1994            instead of just one.  Each display table can specify conversions
1995            for some characters and leave others unchanged.  The way the
1996            character gets displayed is determined by the first display table
1997            with a binding for that character.  This way, you could call a
1998            function `enable-hex-display' that adds a hex display-table to
1999            the list of display tables for the current buffer.
2000
2001            #### ...not yet implemented...  Also, we extend the concept of
2002            "mapping" to include a printf-like spec.  Thus you can make all
2003            extended characters show up as hex with a display table like
2004            this:
2005
2006            #s(range-table data ((256 524288) (format "%x")))
2007
2008            Since more than one display table is possible, you have
2009            great flexibility in mapping ranges of characters.  */
2010         Emchar printable_min = (CHAR_OR_CHAR_INTP(b->ctl_arrow)
2011                                 ? XCHAR_OR_CHAR_INT(b->ctl_arrow)
2012                                 : ((EQ(b->ctl_arrow, Qt)
2013                                     || EQ(b->ctl_arrow, Qnil))
2014                                    ? 255 : 160));
2015
2016         Lisp_Object face_dt, window_dt;
2017
2018         /* The text display block for this display line. */
2019         struct display_block *db = get_display_block_from_line(dl, TEXT);
2020
2021         /* The first time through the main loop we need to force the glyph
2022            data to be updated. */
2023         int initial = 1;
2024
2025         /* Apparently the new extent_fragment_update returns an end position
2026            equal to the position passed in if there are no more runs to be
2027            displayed. */
2028         int no_more_frags = 0;
2029
2030         Lisp_Object synch_minibuffers_value =
2031             symbol_value_in_buffer(Qsynchronize_minibuffers, w->buffer);
2032
2033         dl->used_prop_data = 0;
2034         dl->num_chars = 0;
2035         dl->line_continuation = 0;
2036
2037         xzero(data);
2038         data.ef = extent_fragment_new(w->buffer, f);
2039
2040         /* These values are used by all of the rune addition routines.  We add
2041            them to this structure for ease of passing. */
2042         data.d = d;
2043         XSETWINDOW(data.window, w);
2044         data.string = Qnil;
2045         data.db = db;
2046         data.dl = dl;
2047
2048         data.bi_bufpos = bi_start_pos;
2049         data.pixpos = dl->bounds.left_in;
2050         data.last_charset = Qunbound;
2051         data.last_findex = DEFAULT_INDEX;
2052         data.result_str = Qnil;
2053
2054         /* Set the right boundary adjusting it to take into account any end
2055            glyph.  Save the width of the end glyph for later use. */
2056         data.max_pixpos = dl->bounds.right_in;
2057         if (truncate_win)
2058                 data.end_glyph_width = GLYPH_CACHEL_WIDTH(w, TRUN_GLYPH_INDEX);
2059         else
2060                 data.end_glyph_width = GLYPH_CACHEL_WIDTH(w, CONT_GLYPH_INDEX);
2061         data.max_pixpos -= data.end_glyph_width;
2062
2063         if (cursor_in_echo_area && MINI_WINDOW_P(w) && echo_area_active(f)) {
2064                 data.bi_cursor_bufpos = BI_BUF_ZV(b);
2065                 data.cursor_type = CURSOR_ON;
2066         } else if (MINI_WINDOW_P(w) && !active_minibuffer)
2067                 data.cursor_type = NO_CURSOR;
2068         else if (w == XWINDOW(FRAME_SELECTED_WINDOW(f)) &&
2069                  EQ(DEVICE_CONSOLE(d), Vselected_console) &&
2070                  d ==
2071                  XDEVICE(CONSOLE_SELECTED_DEVICE(XCONSOLE(DEVICE_CONSOLE(d))))
2072                  && f == XFRAME(DEVICE_SELECTED_FRAME(d))) {
2073                 data.bi_cursor_bufpos = BI_BUF_PT(b);
2074                 data.cursor_type = CURSOR_ON;
2075         } else if (w == XWINDOW(FRAME_SELECTED_WINDOW(f))) {
2076                 data.bi_cursor_bufpos = bi_marker_position(w->pointm[type]);
2077                 data.cursor_type = CURSOR_ON;
2078         } else
2079                 data.cursor_type = NO_CURSOR;
2080         data.cursor_x = -1;
2081
2082         data.start_col = w->hscroll;
2083         data.start_col_xoffset = w->left_xoffset;
2084         data.bi_start_col_enabled = (w->hscroll ? bi_start_pos : 0);
2085         data.hscroll_glyph_width_adjust = 0;
2086
2087         /* We regenerate the line from the very beginning. */
2088         Dynarr_reset(db->runes);
2089
2090         /* Why is this less than or equal and not just less than?  If the
2091            starting position is already equal to the maximum we can't add
2092            anything else, right?  Wrong.  We might still have a newline to
2093            add.  A newline can use the room allocated for an end glyph since
2094            if we add it we know we aren't going to be adding any end
2095            glyph. */
2096
2097         /* #### Chuck -- I think this condition should be while (1).
2098            Otherwise if (e.g.) there is one begin-glyph and one end-glyph
2099            and the begin-glyph ends exactly at the end of the window, the
2100            end-glyph and text might not be displayed.  while (1) ensures
2101            that the loop terminates only when either (a) there is
2102            propagation data or (b) the end-of-line or end-of-buffer is hit.
2103
2104            #### Also I think you need to ensure that the operation
2105            "add begin glyphs; add end glyphs; add text" is atomic and
2106            can't get interrupted in the middle.  If you run off the end
2107            of the line during that operation, then you keep accumulating
2108            propagation data until you're done.  Otherwise, if the (e.g.)
2109            there's a begin glyph at a particular position and attempting
2110            to display that glyph results in window-end being hit and
2111            propagation data being generated, then the character at that
2112            position won't be displayed.
2113
2114            #### See also the comment after the end of this loop, below.
2115          */
2116         while (data.pixpos <= data.max_pixpos
2117                && (active_minibuffer || !NILP(synch_minibuffers_value))) {
2118                 /* #### This check probably should not be necessary. */
2119                 if (data.bi_bufpos > BI_BUF_ZV(b)) {
2120                         /* #### urk!  More of this lossage! */
2121                         data.bi_bufpos--;
2122                         goto done;
2123                 }
2124
2125                 /* If selective display was an integer and we aren't working on
2126                    a continuation line then find the next line we are actually
2127                    supposed to display. */
2128                 if (selective > 0 && (data.bi_bufpos == BI_BUF_BEGV(b)
2129                                       || BUF_FETCH_CHAR(b,
2130                                                         prev_bytind(b,
2131                                                                     data.
2132                                                                     bi_bufpos))
2133                                       == '\n')) {
2134                         while (bi_spaces_at_point(b, data.bi_bufpos) >=
2135                                selective) {
2136                                 data.bi_bufpos =
2137                                     bi_find_next_newline_no_quit(b,
2138                                                                  data.bi_bufpos,
2139                                                                  1);
2140                                 if (data.bi_bufpos >= BI_BUF_ZV(b)) {
2141                                         data.bi_bufpos = BI_BUF_ZV(b);
2142                                         goto done;
2143                                 }
2144                         }
2145                 }
2146
2147                 /* Check for face changes. */
2148                 if (initial
2149                     || (!no_more_frags && data.bi_bufpos == data.ef->end)) {
2150                         Lisp_Object last_glyph = Qnil;
2151
2152                         /* Deal with glyphs that we have already displayed. The
2153                            theory is that if we end up with a PROP_GLYPH in the
2154                            propagation data then we are clipping the glyph and there
2155                            can be no propagation data before that point. The theory
2156                            works because we always recalculate the extent-fragments
2157                            for propagated data, we never actually propagate the
2158                            fragments that still need to be displayed. */
2159                         if (*prop && Dynarr_atp(*prop, 0)->type == PROP_GLYPH) {
2160                                 last_glyph =
2161                                     Dynarr_atp(*prop, 0)->data.p_glyph.glyph;
2162                                 Dynarr_free(*prop);
2163                                 *prop = 0;
2164                         }
2165                         /* Now compute the face and begin/end-glyph information. */
2166                         data.findex =
2167                             /* Remember that the extent-fragment routines deal in Bytind's. */
2168                             extent_fragment_update(w, data.ef, data.bi_bufpos,
2169                                                    last_glyph);
2170
2171                         get_display_tables(w, data.findex, &face_dt,
2172                                            &window_dt);
2173
2174                         if (data.bi_bufpos == data.ef->end)
2175                                 no_more_frags = 1;
2176                 }
2177                 initial = 0;
2178
2179                 /* Determine what is next to be displayed.  We first handle any
2180                    glyphs returned by glyphs_at_bufpos.  If there are no glyphs to
2181                    display then we determine what to do based on the character at the
2182                    current buffer position. */
2183
2184                 /* If there are glyphs, add them to the line.  These are
2185                    the end glyphs for the previous run of text.  We add
2186                    them here rather than doing them at the end of handling
2187                    the previous run so that glyphs at the beginning and
2188                    end of a line are handled correctly. */
2189                 if (Dynarr_length (data.ef->glyphs) > 0) {
2190                         glyph_block_dynarr* tmpglyphs = 0;
2191                         /* #### I think this is safe, but could be wrong. */
2192                         data.ch = BI_BUF_FETCH_CHAR (b, data.bi_bufpos);
2193
2194                         *prop = add_glyph_runes (&data);
2195                         tmpglyphs = data.ef->glyphs;
2196
2197                         if (*prop)
2198                         {
2199                                 /* If we just clipped a glyph and we are
2200                                    at the end of a line and there are more
2201                                    glyphs to display then do appropriate
2202                                    processing to not get a continuation
2203                                    glyph. */
2204                                 if (*prop != ADD_FAILED
2205                                     && Dynarr_atp (*prop, 0)->type == PROP_GLYPH
2206                                     && data.ch == '\n') {
2207                                         /* If there are no more glyphs
2208                                            then do the normal processing.
2209
2210                                            #### This doesn't actually work
2211                                            if the same glyph is present
2212                                            more than once in the block. To
2213                                            solve this we would have to
2214                                            carry the index around which
2215                                            might be problematic since the
2216                                            fragment is recalculated for
2217                                            each line.  */
2218                                         if (EQ (Dynarr_end (tmpglyphs)->glyph,
2219                                                 Dynarr_atp (*prop, 0)->data.p_glyph.glyph)) {
2220                                                 Dynarr_free (*prop);
2221                                                 *prop = 0;
2222                                         }
2223                                         else {
2224                                                 data.blank_width = DEVMETH (d, eol_cursor_width, ());
2225                                                 add_emchar_rune (&data); /* discard prop data. */
2226                                                 goto done;
2227                                         }
2228                                 }
2229                                 else
2230                                         goto done;
2231                         }
2232                 }
2233
2234                 /* If the current position is covered by an invisible
2235                    extent, do nothing (except maybe add some
2236                    ellipses).  */
2237                 else if (data.ef->invisible) {
2238                         /* #### Chuck, perhaps you could look at this code?  I don't
2239                            really know what I'm doing. */
2240                         if (*prop) {
2241                                 Dynarr_free(*prop);
2242                                 *prop = 0;
2243                         }
2244
2245                         /* The extent fragment code only sets this when we should
2246                            really display the ellipses.  It makes sure the ellipses
2247                            don't get displayed more than once in a row. */
2248                         if (data.ef->invisible_ellipses) {
2249                                 struct glyph_block gb;
2250
2251                                 data.ef->invisible_ellipses_already_displayed =
2252                                     1;
2253                                 data.ef->invisible_ellipses = 0;
2254                                 gb.extent = Qnil;
2255                                 gb.glyph = Vinvisible_text_glyph;
2256                                 *prop =
2257                                     add_glyph_rune(&data, &gb, BEGIN_GLYPHS, 0,
2258                                                    GLYPH_CACHEL(w,
2259                                                                 INVIS_GLYPH_INDEX));
2260                                 /* Perhaps they shouldn't propagate if the very next thing
2261                                    is to display a newline (for compatibility with
2262                                    selective-display-ellipses)?  Maybe that's too
2263                                    abstruse. */
2264                                 if (*prop)
2265                                         goto done;
2266                         }
2267
2268                         /* If point is in an invisible region we place it on the
2269                            next visible character. */
2270                         if (data.cursor_type == CURSOR_ON
2271                             && data.bi_bufpos == data.bi_cursor_bufpos) {
2272                                 data.cursor_type = NEXT_CURSOR;
2273                         }
2274
2275                         /* #### What if we we're dealing with a display table? */
2276                         if (data.start_col)
2277                                 data.start_col--;
2278
2279                         if (data.bi_bufpos == BI_BUF_ZV(b))
2280                                 goto done;
2281                         else
2282                                 INC_BYTIND(b, data.bi_bufpos);
2283                 }
2284
2285                 /* If there is propagation data, then it represents the current
2286                    buffer position being displayed.  Add them and advance the
2287                    position counter.  This might also add the minibuffer
2288                    prompt. */
2289                 else if (*prop) {
2290                         dl->used_prop_data = 1;
2291                         *prop = add_propagation_runes(prop, &data);
2292
2293                         if (*prop)
2294                                 goto done;      /* gee, a really narrow window */
2295                         else if (data.bi_bufpos == BI_BUF_ZV(b))
2296                                 goto done;
2297                         else if (data.bi_bufpos < BI_BUF_BEGV(b))
2298                                 /* #### urk urk urk! Aborts are not very fun! Fix this please! */
2299                                 data.bi_bufpos = BI_BUF_BEGV(b);
2300                         else
2301                                 INC_BYTIND(b, data.bi_bufpos);
2302                 }
2303
2304                 /* If at end-of-buffer, we've already processed begin and
2305                    end-glyphs at this point and there's no text to process,
2306                    so we're done. */
2307                 else if (data.bi_bufpos == BI_BUF_ZV(b))
2308                         goto done;
2309
2310                 else {
2311                         Lisp_Object entry = Qnil;
2312                         /* Get the character at the current buffer position. */
2313                         data.ch = BI_BUF_FETCH_CHAR(b, data.bi_bufpos);
2314                         if (!NILP(face_dt) || !NILP(window_dt))
2315                                 entry =
2316                                     display_table_entry(data.ch, face_dt,
2317                                                         window_dt);
2318
2319                         /* If there is a display table entry for it, hand it off to
2320                            add_disp_table_entry_runes and let it worry about it. */
2321                         if (!NILP(entry) && !EQ(entry, make_char(data.ch))) {
2322                                 *prop =
2323                                     add_disp_table_entry_runes(&data, entry);
2324
2325                                 if (*prop)
2326                                         goto done;
2327                         }
2328
2329                         /* Check if we have hit a newline character.  If so, add a marker
2330                            to the line and end this loop. */
2331                         else if (data.ch == '\n') {
2332                                 /* We aren't going to be adding an end glyph so give its
2333                                    space back in order to make sure that the cursor can
2334                                    fit. */
2335                                 data.max_pixpos += data.end_glyph_width;
2336
2337                                 if (selective > 0
2338                                     && (bi_spaces_at_point
2339                                         (b, next_bytind(b, data.bi_bufpos))
2340                                         >= selective)) {
2341                                         if (!NILP
2342                                             (b->selective_display_ellipses)) {
2343                                                 struct glyph_block gb;
2344
2345                                                 gb.extent = Qnil;
2346                                                 gb.glyph =
2347                                                     Vinvisible_text_glyph;
2348                                                 add_glyph_rune_noret(&data, &gb,
2349                                                                      BEGIN_GLYPHS, 0,
2350                                                                      GLYPH_CACHEL(w,
2351                                                                                   INVIS_GLYPH_INDEX));
2352                                         } else {
2353                                                 /* Cheesy, cheesy, cheesy.  We mark the end of the
2354                                                    line with a special "character rune" whose width
2355                                                    is the EOL cursor width and whose character is
2356                                                    the non-printing character '\n'. */
2357                                                 data.blank_width =
2358                                                     DEVMETH(d, eol_cursor_width,
2359                                                             ());
2360                                                 *prop = add_emchar_rune(&data);
2361                                         }
2362
2363                                         /* We need to set data.bi_bufpos to the start of the
2364                                            next visible region in order to make this line
2365                                            appear to contain all of the invisible area.
2366                                            Otherwise, the line cache won't work
2367                                            correctly. */
2368                                         INC_BYTIND(b, data.bi_bufpos);
2369                                         while (bi_spaces_at_point
2370                                                (b,
2371                                                 data.bi_bufpos) >= selective) {
2372                                                 data.bi_bufpos =
2373                                                     bi_find_next_newline_no_quit
2374                                                     (b, data.bi_bufpos, 1);
2375                                                 if (data.bi_bufpos >=
2376                                                     BI_BUF_ZV(b)) {
2377                                                         data.bi_bufpos =
2378                                                             BI_BUF_ZV(b);
2379                                                         break;
2380                                                 }
2381                                         }
2382                                         if (BI_BUF_FETCH_CHAR
2383                                             (b,
2384                                              prev_bytind(b,
2385                                                          data.bi_bufpos)) ==
2386                                             '\n')
2387                                                 DEC_BYTIND(b, data.bi_bufpos);
2388                                 } else {
2389                                         data.blank_width =
2390                                             DEVMETH(d, eol_cursor_width, ());
2391                                         *prop = add_emchar_rune(&data);
2392                                 }
2393
2394                                 goto done;
2395                         }
2396
2397                         /* If the current character is ^M, and selective display is
2398                            enabled, then add the invisible-text-glyph if
2399                            selective-display-ellipses is set.  In any case, this
2400                            line is done. */
2401                         else if (data.ch == (('M' & 037)) && selective == -1) {
2402                                 Bytind bi_next_bufpos;
2403
2404                                 /* Find the buffer position at the end of the line. */
2405                                 bi_next_bufpos =
2406                                     bi_find_next_newline_no_quit(b,
2407                                                                  data.bi_bufpos,
2408                                                                  1);
2409                                 if (BI_BUF_FETCH_CHAR
2410                                     (b, prev_bytind(b, bi_next_bufpos))
2411                                     == '\n')
2412                                         DEC_BYTIND(b, bi_next_bufpos);
2413
2414                                 /* If the cursor is somewhere in the elided text make
2415                                    sure that the cursor gets drawn appropriately. */
2416                                 if (data.cursor_type == CURSOR_ON
2417                                     && (data.bi_cursor_bufpos >= data.bi_bufpos
2418                                         && data.bi_cursor_bufpos <
2419                                         bi_next_bufpos)) {
2420                                         data.cursor_type = NEXT_CURSOR;
2421                                 }
2422
2423                                 /* We won't be adding a truncation or continuation glyph
2424                                    so give up the room allocated for them. */
2425                                 data.max_pixpos += data.end_glyph_width;
2426
2427                                 if (!NILP(b->selective_display_ellipses)) {
2428                                         /* We don't propagate anything from the invisible
2429                                            text glyph if it fails to fit.  This is
2430                                            intentional. */
2431                                         struct glyph_block gb;
2432
2433                                         gb.extent = Qnil;
2434                                         gb.glyph = Vinvisible_text_glyph;
2435                                         add_glyph_rune(&data, &gb, BEGIN_GLYPHS,
2436                                                        1, GLYPH_CACHEL(w,
2437                                                                        INVIS_GLYPH_INDEX));
2438                                 }
2439
2440                                 /* Set the buffer position to the end of the line.  We
2441                                    need to do this before potentially adding a newline
2442                                    so that the cursor flag will get set correctly (if
2443                                    needed). */
2444                                 data.bi_bufpos = bi_next_bufpos;
2445
2446                                 if (NILP(b->selective_display_ellipses)
2447                                     || data.bi_cursor_bufpos == bi_next_bufpos) {
2448                                         /* We have to at least add a newline character so
2449                                            that the cursor shows up properly. */
2450                                         data.ch = '\n';
2451                                         data.blank_width =
2452                                             DEVMETH(d, eol_cursor_width, ());
2453                                         data.findex = DEFAULT_INDEX;
2454                                         data.start_col = 0;
2455                                         data.start_col_xoffset = 0;
2456                                         data.bi_start_col_enabled = 0;
2457
2458                                         add_emchar_rune(&data);
2459                                 }
2460
2461                                 /* This had better be a newline but doing it this way
2462                                    we'll see obvious incorrect results if it isn't.  No
2463                                    need to abort here. */
2464                                 data.ch = BI_BUF_FETCH_CHAR(b, data.bi_bufpos);
2465
2466                                 goto done;
2467                         }
2468
2469                         /* If the current character is considered to be printable, then
2470                            just add it. */
2471                         else if (data.ch >= printable_min) {
2472                                 *prop = add_emchar_rune(&data);
2473                                 if (*prop)
2474                                         goto done;
2475                         }
2476
2477                         /* If the current character is a tab, determine the next tab
2478                            starting position and add a blank rune which extends from the
2479                            current pixel position to that starting position. */
2480                         else if (data.ch == '\t') {
2481                                 int tab_start_pixpos = data.pixpos;
2482                                 int next_tab_start;
2483                                 int char_tab_width;
2484                                 int prop_width = 0;
2485
2486                                 if (data.start_col > 1)
2487                                         tab_start_pixpos -=
2488                                             (space_width(w) *
2489                                              (data.start_col - 1))
2490                                             + data.start_col_xoffset;
2491
2492                                 next_tab_start =
2493                                     next_tab_position(w, tab_start_pixpos,
2494                                                       dl->bounds.left_in +
2495                                                       data.
2496                                                       hscroll_glyph_width_adjust);
2497                                 if (next_tab_start > data.max_pixpos) {
2498                                         prop_width =
2499                                             next_tab_start - data.max_pixpos;
2500                                         next_tab_start = data.max_pixpos;
2501                                 }
2502                                 data.blank_width = next_tab_start - data.pixpos;
2503                                 char_tab_width =
2504                                     (next_tab_start -
2505                                      tab_start_pixpos) / space_width(w);
2506
2507                                 *prop =
2508                                     add_blank_rune(&data, w, char_tab_width);
2509
2510                                 /* add_blank_rune is only supposed to be called with
2511                                    sizes guaranteed to fit in the available space. */
2512                                 assert(!(*prop));
2513
2514                                 if (prop_width) {
2515                                         struct prop_block pb;
2516                                         *prop = Dynarr_new(prop_block);
2517
2518                                         pb.type = PROP_BLANK;
2519                                         pb.data.p_blank.width = prop_width;
2520                                         pb.data.p_blank.findex = data.findex;
2521                                         Dynarr_add(*prop, pb);
2522
2523                                         goto done;
2524                                 }
2525                         }
2526
2527                         /* If character is a control character, pass it off to
2528                            add_control_char_runes.
2529
2530                            The is_*() routines have undefined results on
2531                            arguments outside of the range [-1, 255].  (This
2532                            often bites people who carelessly use `char' instead
2533                            of `unsigned char'.)
2534                          */
2535                         else if (data.ch < 0x100 && iscntrl((Bufbyte) data.ch)) {
2536                                 *prop = add_control_char_runes(&data, b);
2537
2538                                 if (*prop)
2539                                         goto done;
2540                         }
2541
2542                         /* If the character is above the ASCII range and we have not
2543                            already handled it, then print it as an octal number. */
2544                         else if (data.ch >= 0200) {
2545                                 *prop = add_octal_runes(&data);
2546
2547                                 if (*prop)
2548                                         goto done;
2549                         }
2550
2551                         /* Assume the current character is considered to be printable,
2552                            then just add it. */
2553                         else {
2554                                 *prop = add_emchar_rune(&data);
2555                                 if (*prop)
2556                                         goto done;
2557                         }
2558
2559                         INC_BYTIND(b, data.bi_bufpos);
2560                 }
2561         }
2562
2563       done:
2564
2565         /* Determine the starting point of the next line if we did not hit the
2566            end of the buffer. */
2567         if (data.bi_bufpos < BI_BUF_ZV(b)
2568             && (active_minibuffer || !NILP(synch_minibuffers_value))) {
2569                 /* #### This check is not correct.  If the line terminated
2570                    due to a begin-glyph or end-glyph hitting window-end, then
2571                    data.ch will not point to the character at data.bi_bufpos.  If
2572                    you make the two changes mentioned at the top of this loop,
2573                    you should be able to say '(if (*prop))'.  That should also
2574                    make it possible to eliminate the data.bi_bufpos < BI_BUF_ZV (b)
2575                    check. */
2576
2577                 /* The common case is that the line ended because we hit a newline.
2578                    In that case, the next character is just the next buffer
2579                    position. */
2580                 if (data.ch == '\n') {
2581                         /* If data.start_col_enabled is still true, then the window is
2582                            scrolled far enough so that nothing on this line is visible.
2583                            We need to stick a truncation glyph at the beginning of the
2584                            line in that case unless the line is completely blank. */
2585                         if (data.bi_start_col_enabled) {
2586                                 if (data.cursor_type == CURSOR_ON) {
2587                                         if (data.bi_cursor_bufpos >=
2588                                             bi_start_pos
2589                                             && data.bi_cursor_bufpos <=
2590                                             data.bi_bufpos)
2591                                                 data.bi_cursor_bufpos =
2592                                                     data.bi_bufpos;
2593                                 }
2594                                 data.findex = DEFAULT_INDEX;
2595                                 data.start_col = 0;
2596                                 data.bi_start_col_enabled = 0;
2597
2598                                 if (data.bi_bufpos != bi_start_pos) {
2599                                         struct glyph_block gb;
2600
2601                                         gb.extent = Qnil;
2602                                         gb.glyph = Vhscroll_glyph;
2603                                         add_glyph_rune_noret(&data, &gb, BEGIN_GLYPHS,
2604                                                              0, GLYPH_CACHEL(w,
2605                                                                              HSCROLL_GLYPH_INDEX));
2606                                 } else {
2607                                         /* This duplicates code down below to add a newline to
2608                                            the end of an otherwise empty line. */
2609                                         data.ch = '\n';
2610                                         data.blank_width =
2611                                             DEVMETH(d, eol_cursor_width, ());
2612
2613                                         add_emchar_rune(&data);
2614                                 }
2615                         }
2616
2617                         INC_BYTIND(b, data.bi_bufpos);
2618                 }
2619
2620                 /* Otherwise we have a buffer line which cannot fit on one display
2621                    line. */
2622                 else {
2623                         struct glyph_block gb;
2624                         struct glyph_cachel *cachel;
2625
2626                         /* If the line is to be truncated then we actually have to look
2627                            for the next newline.  We also add the end-of-line glyph which
2628                            we know will fit because we adjusted the right border before
2629                            we starting laying out the line. */
2630                         data.max_pixpos += data.end_glyph_width;
2631                         data.findex = DEFAULT_INDEX;
2632                         gb.extent = Qnil;
2633
2634                         if (truncate_win) {
2635                                 Bytind bi_pos;
2636
2637                                 /* Now find the start of the next line. */
2638                                 bi_pos =
2639                                     bi_find_next_newline_no_quit(b,
2640                                                                  data.bi_bufpos,
2641                                                                  1);
2642
2643                                 /* If the cursor is past the truncation line then we
2644                                    make it appear on the truncation glyph.  If we've hit
2645                                    the end of the buffer then we also make the cursor
2646                                    appear unless eob is immediately preceded by a
2647                                    newline.  In that case the cursor should actually
2648                                    appear on the next line. */
2649                                 if (data.cursor_type == CURSOR_ON
2650                                     && data.bi_cursor_bufpos >= data.bi_bufpos
2651                                     && (data.bi_cursor_bufpos < bi_pos ||
2652                                         (bi_pos == BI_BUF_ZV(b)
2653                                          && (bi_pos == BI_BUF_BEGV(b)
2654                                              ||
2655                                              (BI_BUF_FETCH_CHAR
2656                                               (b, prev_bytind(b, bi_pos))
2657                                               != '\n')))))
2658                                         data.bi_cursor_bufpos = bi_pos;
2659                                 else
2660                                         data.cursor_type = NO_CURSOR;
2661
2662                                 data.bi_bufpos = bi_pos;
2663                                 gb.glyph = Vtruncation_glyph;
2664                                 cachel = GLYPH_CACHEL(w, TRUN_GLYPH_INDEX);
2665                         } else {
2666                                 /* The cursor can never be on the continuation glyph. */
2667                                 data.cursor_type = NO_CURSOR;
2668
2669                                 /* data.bi_bufpos is already at the start of the next line. */
2670
2671                                 dl->line_continuation = 1;
2672                                 gb.glyph = Vcontinuation_glyph;
2673                                 cachel = GLYPH_CACHEL(w, CONT_GLYPH_INDEX);
2674                         }
2675
2676                         add_glyph_rune_noret(&data, &gb, BEGIN_GLYPHS, 0, cachel);
2677
2678                         if (truncate_win && data.bi_bufpos == BI_BUF_ZV(b)
2679                             && BI_BUF_FETCH_CHAR(b,
2680                                                  prev_bytind(b,
2681                                                              BI_BUF_ZV(b))) !=
2682                             '\n')
2683                                 /* #### Damn this losing shit. */
2684                                 data.bi_bufpos++;
2685                 }
2686         } else if ((active_minibuffer || !NILP(synch_minibuffers_value))
2687                    && (!echo_area_active(f) || data.bi_bufpos == BI_BUF_ZV(b))) {
2688                 /* We need to add a marker to the end of the line since there is no
2689                    newline character in order for the cursor to get drawn.  We label
2690                    it as a newline so that it gets handled correctly by the
2691                    whitespace routines below. */
2692
2693                 data.ch = '\n';
2694                 data.blank_width = DEVMETH(d, eol_cursor_width, ());
2695                 data.findex = DEFAULT_INDEX;
2696                 data.start_col = 0;
2697                 data.start_col_xoffset = 0;
2698                 data.bi_start_col_enabled = 0;
2699
2700                 data.max_pixpos += data.blank_width;
2701                 add_emchar_rune(&data);
2702                 data.max_pixpos -= data.blank_width;
2703
2704                 /* #### urk!  Chuck, this shit is bad news.  Going around
2705                    manipulating invalid positions is guaranteed to result in
2706                    trouble sooner or later. */
2707                 data.bi_bufpos = BI_BUF_ZV(b) + 1;
2708         }
2709
2710         /* Calculate left whitespace boundary. */
2711         {
2712                 int elt = 0;
2713
2714                 /* Whitespace past a newline is considered right whitespace. */
2715                 while (elt < Dynarr_length(db->runes)) {
2716                         struct rune *rb = Dynarr_atp(db->runes, elt);
2717
2718                         if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ')
2719                             || rb->type == RUNE_BLANK) {
2720                                 dl->bounds.left_white += rb->width;
2721                                 elt++;
2722                         } else
2723                                 elt = Dynarr_length(db->runes);
2724                 }
2725         }
2726
2727         /* Calculate right whitespace boundary. */
2728         {
2729                 int elt = Dynarr_length(db->runes) - 1;
2730                 int done = 0;
2731
2732                 while (!done && elt >= 0) {
2733                         struct rune *rb = Dynarr_atp(db->runes, elt);
2734
2735                         if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100
2736                               && isspace(rb->object.chr.ch))
2737                             && !rb->type == RUNE_BLANK) {
2738                                 dl->bounds.right_white = rb->xpos + rb->width;
2739                                 done = 1;
2740                         }
2741
2742                         elt--;
2743
2744                 }
2745
2746                 /* The line is blank so everything is considered to be right
2747                    whitespace. */
2748                 if (!done)
2749                         dl->bounds.right_white = dl->bounds.left_in;
2750         }
2751
2752         /* Set the display blocks bounds. */
2753         db->start_pos = dl->bounds.left_in;
2754         if (Dynarr_length(db->runes)) {
2755                 struct rune *rb =
2756                     Dynarr_atp(db->runes, Dynarr_length(db->runes) - 1);
2757
2758                 db->end_pos = rb->xpos + rb->width;
2759         } else
2760                 db->end_pos = dl->bounds.right_white;
2761
2762         calculate_baseline(&data);
2763
2764         dl->ascent = data.new_ascent;
2765         dl->descent = data.new_descent;
2766
2767         {
2768                 unsigned short ascent =
2769                     (unsigned short)XINT(w->minimum_line_ascent);
2770
2771                 if (dl->ascent < ascent)
2772                         dl->ascent = ascent;
2773         }
2774         {
2775                 unsigned short descent =
2776                     (unsigned short)XINT(w->minimum_line_descent);
2777
2778                 if (dl->descent < descent)
2779                         dl->descent = descent;
2780         }
2781
2782         calculate_yoffset(dl, db);
2783
2784         dl->cursor_elt = data.cursor_x;
2785         /* #### lossage lossage lossage! Fix this shit! */
2786         if (data.bi_bufpos > BI_BUF_ZV(b))
2787                 dl->end_bufpos = BUF_ZV(b);
2788         else
2789                 dl->end_bufpos = bytind_to_bufpos(b, data.bi_bufpos) - 1;
2790         if (truncate_win)
2791                 data.dl->num_chars = column_at_point(b, dl->end_bufpos, 0);
2792         else
2793                 /* This doesn't correctly take into account tabs and control
2794                    characters but if the window isn't being truncated then this
2795                    value isn't going to end up being used anyhow. */
2796                 data.dl->num_chars = dl->end_bufpos - dl->bufpos;
2797
2798         /* #### handle horizontally scrolled line with text none of which
2799            was actually laid out. */
2800
2801         /* #### handle any remainder of overlay arrow */
2802
2803         if (*prop == ADD_FAILED)
2804                 *prop = NULL;
2805
2806         if (truncate_win && *prop) {
2807                 Dynarr_free(*prop);
2808                 *prop = NULL;
2809         }
2810
2811         extent_fragment_delete(data.ef);
2812
2813         /* #### If we started at EOB, then make sure we return a value past
2814            it so that regenerate_window will exit properly.  This is bogus.
2815            The main loop should get fixed so that it isn't necessary to call
2816            this function if we are already at EOB. */
2817
2818         if (data.bi_bufpos == BI_BUF_ZV(b) && bi_start_pos == BI_BUF_ZV(b))
2819                 return data.bi_bufpos + 1;      /* Yuck! */
2820         else
2821                 return data.bi_bufpos;
2822 }
2823
2824 /* Display the overlay arrow at the beginning of the given line. */
2825
2826 static int create_overlay_glyph_block(struct window *w, struct display_line *dl)
2827 {
2828         struct frame *f = XFRAME(w->frame);
2829         struct device *d = XDEVICE(f->device);
2830         pos_data data;
2831
2832         /* If Voverlay_arrow_string isn't valid then just fail silently. */
2833         if (!STRINGP(Voverlay_arrow_string) && !GLYPHP(Voverlay_arrow_string))
2834                 return 0;
2835
2836         xzero(data);
2837         data.ef = NULL;
2838         data.d = d;
2839         XSETWINDOW(data.window, w);
2840         data.db = get_display_block_from_line(dl, OVERWRITE);
2841         data.dl = dl;
2842         data.pixpos = dl->bounds.left_in;
2843         data.max_pixpos = dl->bounds.right_in;
2844         data.cursor_type = NO_CURSOR;
2845         data.cursor_x = -1;
2846         data.findex = DEFAULT_INDEX;
2847         data.last_charset = Qunbound;
2848         data.last_findex = DEFAULT_INDEX;
2849         data.result_str = Qnil;
2850         data.string = Qnil;
2851
2852         Dynarr_reset(data.db->runes);
2853
2854         if (STRINGP(Voverlay_arrow_string)) {
2855                 add_bufbyte_string_runes
2856                     (&data,
2857                      XSTRING_DATA(Voverlay_arrow_string),
2858                      XSTRING_LENGTH(Voverlay_arrow_string), 1, 0);
2859         } else if (GLYPHP(Voverlay_arrow_string)) {
2860                 struct glyph_block gb;
2861
2862                 gb.glyph = Voverlay_arrow_string;
2863                 gb.extent = Qnil;
2864                 add_glyph_rune_noret(&data, &gb, BEGIN_GLYPHS, 0, 0);
2865         }
2866
2867         calculate_baseline(&data);
2868
2869         dl->ascent = data.new_ascent;
2870         dl->descent = data.new_descent;
2871
2872         data.db->start_pos = dl->bounds.left_in;
2873         data.db->end_pos = data.pixpos;
2874
2875         calculate_yoffset(dl, data.db);
2876
2877         return data.pixpos - dl->bounds.left_in;
2878 }
2879
2880 /* Add a type of glyph to a margin display block. */
2881
2882 static int
2883 add_margin_runes(struct display_line *dl, struct display_block *db, int start,
2884                  int count, enum glyph_layout layout, int side,
2885                  Lisp_Object window)
2886 {
2887         glyph_block_dynarr *gbd = (side == LEFT_GLYPHS
2888                                    ? dl->left_glyphs : dl->right_glyphs);
2889         int elt, end;
2890         int reverse;
2891         struct window *w = XWINDOW(window);
2892         struct frame *f = XFRAME(w->frame);
2893         struct device *d = XDEVICE(f->device);
2894         pos_data data;
2895
2896         xzero(data);
2897         data.d = d;
2898         data.window = window;
2899         data.db = db;
2900         data.dl = dl;
2901         data.pixpos = start;
2902         data.cursor_type = NO_CURSOR;
2903         data.cursor_x = -1;
2904         data.last_charset = Qunbound;
2905         data.last_findex = DEFAULT_INDEX;
2906         data.result_str = Qnil;
2907         data.string = Qnil;
2908         data.new_ascent = dl->ascent;
2909         data.new_descent = dl->descent;
2910
2911         if ((layout == GL_WHITESPACE && side == LEFT_GLYPHS)
2912             || (layout == GL_INSIDE_MARGIN && side == RIGHT_GLYPHS)) {
2913                 reverse = 1;
2914                 elt = Dynarr_length(gbd) - 1;
2915                 end = 0;
2916         } else {
2917                 reverse = 0;
2918                 elt = 0;
2919                 end = Dynarr_length(gbd);
2920         }
2921
2922         while (count && ((!reverse && elt < end) || (reverse && elt >= end))) {
2923                 struct glyph_block *gb = Dynarr_atp(gbd, elt);
2924
2925                 if (NILP(gb->extent))
2926                         abort();        /* these should have been handled in add_glyph_rune */
2927
2928                 if (gb->active &&
2929                     ((side == LEFT_GLYPHS &&
2930                       extent_begin_glyph_layout(XEXTENT(gb->extent)) == layout)
2931                      || (side == RIGHT_GLYPHS &&
2932                          extent_end_glyph_layout(XEXTENT(gb->extent)) ==
2933                          layout))) {
2934                         data.findex = gb->findex;
2935                         data.max_pixpos = data.pixpos + gb->width;
2936                         add_glyph_rune_noret(&data, gb, side, 0, NULL);
2937                         count--;
2938                         gb->active = 0;
2939                 }
2940
2941                 (reverse ? elt-- : elt++);
2942         }
2943
2944         calculate_baseline(&data);
2945
2946         dl->ascent = data.new_ascent;
2947         dl->descent = data.new_descent;
2948
2949         calculate_yoffset(dl, data.db);
2950
2951         return data.pixpos;
2952 }
2953
2954 /* Add a blank to a margin display block. */
2955
2956 static void
2957 add_margin_blank(struct display_line *dl, struct display_block *db,
2958                  struct window *w, int xpos, int width, int side)
2959 {
2960         struct rune rb;
2961
2962         rb.findex = (side == LEFT_GLYPHS
2963                      ? get_builtin_face_cache_index(w, Vleft_margin_face)
2964                      : get_builtin_face_cache_index(w, Vright_margin_face));
2965         rb.xpos = xpos;
2966         rb.width = width;
2967         rb.bufpos = -1;
2968         rb.endpos = 0;
2969         rb.type = RUNE_BLANK;
2970         rb.cursor_type = CURSOR_OFF;
2971
2972         Dynarr_add(db->runes, rb);
2973 }
2974
2975 /* Display glyphs in the left outside margin, left inside margin and
2976    left whitespace area. */
2977
2978 static void
2979 create_left_glyph_block(struct window *w, struct display_line *dl,
2980                         int overlay_width)
2981 {
2982         Lisp_Object window;
2983
2984         int use_overflow = (NILP(w->use_left_overflow) ? 0 : 1);
2985         int elt, end_xpos;
2986         int out_end, in_out_start, in_in_end, white_out_start, white_in_start;
2987         int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
2988         int left_in_start = dl->bounds.left_in;
2989         int left_in_end = dl->bounds.left_in + overlay_width;
2990
2991         struct display_block *odb, *idb;
2992
2993         XSETWINDOW(window, w);
2994
2995         /* We have to add the glyphs to the line in the order outside,
2996            inside, whitespace.  However the precedence dictates that we
2997            determine how many will fit in the reverse order. */
2998
2999         /* Determine how many whitespace glyphs we can display and where
3000            they should start. */
3001         white_in_start = dl->bounds.left_white;
3002         white_out_start = left_in_start;
3003         white_out_cnt = white_in_cnt = 0;
3004         elt = 0;
3005
3006         while (elt < Dynarr_length(dl->left_glyphs)) {
3007                 struct glyph_block *gb = Dynarr_atp(dl->left_glyphs, elt);
3008
3009                 if (NILP(gb->extent))
3010                         abort();        /* these should have been handled in add_glyph_rune */
3011
3012                 if (extent_begin_glyph_layout(XEXTENT(gb->extent)) ==
3013                     GL_WHITESPACE) {
3014                         int width;
3015
3016                         width = glyph_width(gb->glyph, window);
3017
3018                         if (white_in_start - width >= left_in_end) {
3019                                 white_in_cnt++;
3020                                 white_in_start -= width;
3021                                 gb->width = width;
3022                                 gb->active = 1;
3023                         } else if (use_overflow
3024                                    && (white_out_start - width >
3025                                        dl->bounds.left_out)) {
3026                                 white_out_cnt++;
3027                                 white_out_start -= width;
3028                                 gb->width = width;
3029                                 gb->active = 1;
3030                         } else
3031                                 gb->active = 0;
3032                 }
3033
3034                 elt++;
3035         }
3036
3037         /* Determine how many inside margin glyphs we can display and where
3038            they should start.  The inside margin glyphs get whatever space
3039            is left after the whitespace glyphs have been displayed.  These
3040            are tricky to calculate since if we decide to use the overflow
3041            area we basically have to start over.  So for these we build up a
3042            list of just the inside margin glyphs and manipulate it to
3043            determine the needed info. */
3044         {
3045                 glyph_block_dynarr *ib;
3046                 int avail_in, avail_out;
3047                 int done = 0;
3048                 int marker = 0;
3049                 int used_in, used_out;
3050
3051                 elt = 0;
3052                 used_in = used_out = 0;
3053                 ib = Dynarr_new(glyph_block);
3054                 while (elt < Dynarr_length(dl->left_glyphs)) {
3055                         struct glyph_block *gb =
3056                             Dynarr_atp(dl->left_glyphs, elt);
3057
3058                         if (NILP(gb->extent))
3059                                 abort();        /* these should have been handled in add_glyph_rune */
3060
3061                         if (extent_begin_glyph_layout(XEXTENT(gb->extent)) ==
3062                             GL_INSIDE_MARGIN) {
3063                                 gb->width = glyph_width(gb->glyph, window);
3064                                 used_in += gb->width;
3065                                 Dynarr_add(ib, *gb);
3066                         }
3067
3068                         elt++;
3069                 }
3070
3071                 if (white_out_cnt)
3072                         avail_in = 0;
3073                 else {
3074                         avail_in = white_in_start - left_in_end;
3075                         if (avail_in < 0)
3076                                 avail_in = 0;
3077                 }
3078
3079                 if (!use_overflow)
3080                         avail_out = 0;
3081                 else
3082                         avail_out = white_out_start - dl->bounds.left_out;
3083
3084                 marker = 0;
3085                 while (!done && marker < Dynarr_length(ib)) {
3086                         int width = Dynarr_atp(ib, marker)->width;
3087
3088                         /* If everything now fits in the available inside margin
3089                            space, we're done. */
3090                         if (used_in <= avail_in)
3091                                 done = 1;
3092                         else {
3093                                 /* Otherwise see if we have room to move a glyph to the
3094                                    outside. */
3095                                 if (used_out + width <= avail_out) {
3096                                         used_out += width;
3097                                         used_in -= width;
3098                                 } else
3099                                         done = 1;
3100                         }
3101
3102                         if (!done)
3103                                 marker++;
3104                 }
3105
3106                 /* At this point we now know that everything from marker on goes in
3107                    the inside margin and everything before it goes in the outside
3108                    margin.  The stuff going into the outside margin is guaranteed
3109                    to fit, but we may have to trim some stuff from the inside. */
3110
3111                 in_in_end = left_in_end;
3112                 in_out_start = white_out_start;
3113                 in_out_cnt = in_in_cnt = 0;
3114
3115                 Dynarr_free(ib);
3116                 elt = 0;
3117                 while (elt < Dynarr_length(dl->left_glyphs)) {
3118                         struct glyph_block *gb =
3119                             Dynarr_atp(dl->left_glyphs, elt);
3120
3121                         if (NILP(gb->extent))
3122                                 abort();        /* these should have been handled in add_glyph_rune */
3123
3124                         if (extent_begin_glyph_layout(XEXTENT(gb->extent)) ==
3125                             GL_INSIDE_MARGIN) {
3126                                 int width = glyph_width(gb->glyph, window);
3127
3128                                 if (used_out) {
3129                                         in_out_cnt++;
3130                                         in_out_start -= width;
3131                                         gb->width = width;
3132                                         gb->active = 1;
3133                                         used_out -= width;
3134                                 } else if (in_in_end + width < white_in_start) {
3135                                         in_in_cnt++;
3136                                         in_in_end += width;
3137                                         gb->width = width;
3138                                         gb->active = 1;
3139                                 } else
3140                                         gb->active = 0;
3141                         }
3142
3143                         elt++;
3144                 }
3145         }
3146
3147         /* Determine how many outside margin glyphs we can display.  They
3148            always start at the left outside margin and can only use the
3149            outside margin space. */
3150         out_end = dl->bounds.left_out;
3151         out_cnt = 0;
3152         elt = 0;
3153
3154         while (elt < Dynarr_length(dl->left_glyphs)) {
3155                 struct glyph_block *gb = Dynarr_atp(dl->left_glyphs, elt);
3156
3157                 if (NILP(gb->extent))
3158                         abort();        /* these should have been handled in add_glyph_rune */
3159
3160                 if (extent_begin_glyph_layout(XEXTENT(gb->extent)) ==
3161                     GL_OUTSIDE_MARGIN) {
3162                         int width = glyph_width(gb->glyph, window);
3163
3164                         if (out_end + width <= in_out_start) {
3165                                 out_cnt++;
3166                                 out_end += width;
3167                                 gb->width = width;
3168                                 gb->active = 1;
3169                         } else
3170                                 gb->active = 0;
3171                 }
3172
3173                 elt++;
3174         }
3175
3176         /* Now that we know where everything goes, we add the glyphs as
3177            runes to the appropriate display blocks. */
3178         if (out_cnt || in_out_cnt || white_out_cnt) {
3179                 odb = get_display_block_from_line(dl, LEFT_OUTSIDE_MARGIN);
3180                 odb->start_pos = dl->bounds.left_out;
3181                 /* #### We should stop adding a blank to account for the space
3182                    between the end of the glyphs and the margin and instead set
3183                    this accordingly. */
3184                 odb->end_pos = dl->bounds.left_in;
3185                 Dynarr_reset(odb->runes);
3186         } else
3187                 odb = 0;
3188
3189         if (in_in_cnt || white_in_cnt) {
3190                 idb = get_display_block_from_line(dl, LEFT_INSIDE_MARGIN);
3191                 idb->start_pos = dl->bounds.left_in;
3192                 /* #### See above comment for odb->end_pos */
3193                 idb->end_pos = dl->bounds.left_white;
3194                 Dynarr_reset(idb->runes);
3195         } else
3196                 idb = 0;
3197
3198         /* First add the outside margin glyphs. */
3199         if (out_cnt)
3200                 end_xpos =
3201                     add_margin_runes(dl, odb, dl->bounds.left_out, out_cnt,
3202                                      GL_OUTSIDE_MARGIN, LEFT_GLYPHS, window);
3203         else
3204                 end_xpos = dl->bounds.left_out;
3205
3206         /* There may be blank space between the outside margin glyphs and
3207            the inside margin glyphs.  If so, add a blank. */
3208         if (in_out_cnt && (in_out_start - end_xpos)) {
3209                 add_margin_blank(dl, odb, w, end_xpos, in_out_start - end_xpos,
3210                                  LEFT_GLYPHS);
3211         }
3212
3213         /* Next add the inside margin glyphs which are actually in the
3214            outside margin. */
3215         if (in_out_cnt) {
3216                 end_xpos = add_margin_runes(dl, odb, in_out_start, in_out_cnt,
3217                                             GL_INSIDE_MARGIN, LEFT_GLYPHS,
3218                                             window);
3219         }
3220
3221         /* If we didn't add any inside margin glyphs to the outside margin,
3222            but are adding whitespace glyphs, then we need to add a blank
3223            here. */
3224         if (!in_out_cnt && white_out_cnt && (white_out_start - end_xpos)) {
3225                 add_margin_blank(dl, odb, w, end_xpos,
3226                                  white_out_start - end_xpos, LEFT_GLYPHS);
3227         }
3228
3229         /* Next add the whitespace margin glyphs which are actually in the
3230            outside margin. */
3231         if (white_out_cnt) {
3232                 end_xpos =
3233                     add_margin_runes(dl, odb, white_out_start, white_out_cnt,
3234                                      GL_WHITESPACE, LEFT_GLYPHS, window);
3235         }
3236
3237         /* We take care of clearing between the end of the glyphs and the
3238            start of the inside margin for lines which have glyphs.  */
3239         if (odb && (left_in_start - end_xpos)) {
3240                 add_margin_blank(dl, odb, w, end_xpos, left_in_start - end_xpos,
3241                                  LEFT_GLYPHS);
3242         }
3243
3244         /* Next add the inside margin glyphs which are actually in the
3245            inside margin. */
3246         if (in_in_cnt) {
3247                 end_xpos = add_margin_runes(dl, idb, left_in_end, in_in_cnt,
3248                                             GL_INSIDE_MARGIN, LEFT_GLYPHS,
3249                                             window);
3250         } else
3251                 end_xpos = left_in_end;
3252
3253         /* Make sure that the area between the end of the inside margin
3254            glyphs and the whitespace glyphs is cleared. */
3255         if (idb && (white_in_start - end_xpos > 0)) {
3256                 add_margin_blank(dl, idb, w, end_xpos,
3257                                  white_in_start - end_xpos, LEFT_GLYPHS);
3258         }
3259
3260         /* Next add the whitespace margin glyphs which are actually in the
3261            inside margin. */
3262         if (white_in_cnt) {
3263                 add_margin_runes(dl, idb, white_in_start, white_in_cnt,
3264                                  GL_WHITESPACE, LEFT_GLYPHS, window);
3265         }
3266
3267         /* Whitespace glyphs always end right next to the text block so
3268            there is nothing we have to make sure is cleared after them. */
3269 }
3270
3271 /* Display glyphs in the right outside margin, right inside margin and
3272    right whitespace area. */
3273
3274 static void create_right_glyph_block(struct window *w, struct display_line *dl)
3275 {
3276         Lisp_Object window;
3277
3278         int use_overflow = (NILP(w->use_right_overflow) ? 0 : 1);
3279         int elt, end_xpos;
3280         int out_start, in_out_end, in_in_start, white_out_end, white_in_end;
3281         int out_cnt, in_out_cnt, in_in_cnt, white_out_cnt, white_in_cnt;
3282
3283         struct display_block *odb, *idb;
3284
3285         XSETWINDOW(window, w);
3286
3287         /* We have to add the glyphs to the line in the order outside,
3288            inside, whitespace.  However the precedence dictates that we
3289            determine how many will fit in the reverse order. */
3290
3291         /* Determine how many whitespace glyphs we can display and where
3292            they should start. */
3293         white_in_end = dl->bounds.right_white;
3294         white_out_end = dl->bounds.right_in;
3295         white_out_cnt = white_in_cnt = 0;
3296         elt = 0;
3297
3298         while (elt < Dynarr_length(dl->right_glyphs)) {
3299                 struct glyph_block *gb = Dynarr_atp(dl->right_glyphs, elt);
3300
3301                 if (NILP(gb->extent))
3302                         abort();        /* these should have been handled in add_glyph_rune */
3303
3304                 if (extent_end_glyph_layout(XEXTENT(gb->extent)) ==
3305                     GL_WHITESPACE) {
3306                         int width = glyph_width(gb->glyph, window);
3307
3308                         if (white_in_end + width <= dl->bounds.right_in) {
3309                                 white_in_cnt++;
3310                                 white_in_end += width;
3311                                 gb->width = width;
3312                                 gb->active = 1;
3313                         } else if (use_overflow
3314                                    && (white_out_end + width <=
3315                                        dl->bounds.right_out)) {
3316                                 white_out_cnt++;
3317                                 white_out_end += width;
3318                                 gb->width = width;
3319                                 gb->active = 1;
3320                         } else
3321                                 gb->active = 0;
3322                 }
3323
3324                 elt++;
3325         }
3326
3327         /* Determine how many inside margin glyphs we can display and where
3328            they should start.  The inside margin glyphs get whatever space
3329            is left after the whitespace glyphs have been displayed.  These
3330            are tricky to calculate since if we decide to use the overflow
3331            area we basically have to start over.  So for these we build up a
3332            list of just the inside margin glyphs and manipulate it to
3333            determine the needed info. */
3334         {
3335                 glyph_block_dynarr *ib;
3336                 int avail_in, avail_out;
3337                 int done = 0;
3338                 int marker = 0;
3339                 int used_in, used_out;
3340
3341                 elt = 0;
3342                 used_in = used_out = 0;
3343                 ib = Dynarr_new(glyph_block);
3344                 while (elt < Dynarr_length(dl->right_glyphs)) {
3345                         struct glyph_block *gb =
3346                             Dynarr_atp(dl->right_glyphs, elt);
3347
3348                         if (NILP(gb->extent))
3349                                 abort();        /* these should have been handled in add_glyph_rune */
3350
3351                         if (extent_end_glyph_layout(XEXTENT(gb->extent)) ==
3352                             GL_INSIDE_MARGIN) {
3353                                 gb->width = glyph_width(gb->glyph, window);
3354                                 used_in += gb->width;
3355                                 Dynarr_add(ib, *gb);
3356                         }
3357
3358                         elt++;
3359                 }
3360
3361                 if (white_out_cnt)
3362                         avail_in = 0;
3363                 else
3364                         avail_in = dl->bounds.right_in - white_in_end;
3365
3366                 if (!use_overflow)
3367                         avail_out = 0;
3368                 else
3369                         avail_out = dl->bounds.right_out - white_out_end;
3370
3371                 marker = 0;
3372                 while (!done && marker < Dynarr_length(ib)) {
3373                         int width = Dynarr_atp(ib, marker)->width;
3374
3375                         /* If everything now fits in the available inside margin
3376                            space, we're done. */
3377                         if (used_in <= avail_in)
3378                                 done = 1;
3379                         else {
3380                                 /* Otherwise see if we have room to move a glyph to the
3381                                    outside. */
3382                                 if (used_out + width <= avail_out) {
3383                                         used_out += width;
3384                                         used_in -= width;
3385                                 } else
3386                                         done = 1;
3387                         }
3388
3389                         if (!done)
3390                                 marker++;
3391                 }
3392
3393                 /* At this point we now know that everything from marker on goes in
3394                    the inside margin and everything before it goes in the outside
3395                    margin.  The stuff going into the outside margin is guaranteed
3396                    to fit, but we may have to trim some stuff from the inside. */
3397
3398                 in_in_start = dl->bounds.right_in;
3399                 in_out_end = dl->bounds.right_in;
3400                 in_out_cnt = in_in_cnt = 0;
3401
3402                 Dynarr_free(ib);
3403                 elt = 0;
3404                 while (elt < Dynarr_length(dl->right_glyphs)) {
3405                         struct glyph_block *gb =
3406                             Dynarr_atp(dl->right_glyphs, elt);
3407
3408                         if (NILP(gb->extent))
3409                                 abort();        /* these should have been handled in add_glyph_rune */
3410
3411                         if (extent_end_glyph_layout(XEXTENT(gb->extent)) ==
3412                             GL_INSIDE_MARGIN) {
3413                                 int width = glyph_width(gb->glyph, window);
3414
3415                                 if (used_out) {
3416                                         in_out_cnt++;
3417                                         in_out_end += width;
3418                                         gb->width = width;
3419                                         gb->active = 1;
3420                                         used_out -= width;
3421                                 } else if (in_in_start - width >= white_in_end) {
3422                                         in_in_cnt++;
3423                                         in_in_start -= width;
3424                                         gb->width = width;
3425                                         gb->active = 1;
3426                                 } else
3427                                         gb->active = 0;
3428                         }
3429
3430                         elt++;
3431                 }
3432         }
3433
3434         /* Determine how many outside margin glyphs we can display.  They
3435            always start at the right outside margin and can only use the
3436            outside margin space. */
3437         out_start = dl->bounds.right_out;
3438         out_cnt = 0;
3439         elt = 0;
3440
3441         while (elt < Dynarr_length(dl->right_glyphs)) {
3442                 struct glyph_block *gb = Dynarr_atp(dl->right_glyphs, elt);
3443
3444                 if (NILP(gb->extent))
3445                         abort();        /* these should have been handled in add_glyph_rune */
3446
3447                 if (extent_end_glyph_layout(XEXTENT(gb->extent)) ==
3448                     GL_OUTSIDE_MARGIN) {
3449                         int width = glyph_width(gb->glyph, window);
3450
3451                         if (out_start - width >= in_out_end) {
3452                                 out_cnt++;
3453                                 out_start -= width;
3454                                 gb->width = width;
3455                                 gb->active = 1;
3456                         } else
3457                                 gb->active = 0;
3458                 }
3459
3460                 elt++;
3461         }
3462
3463         /* Now that we now where everything goes, we add the glyphs as runes
3464            to the appropriate display blocks. */
3465         if (out_cnt || in_out_cnt || white_out_cnt) {
3466                 odb = get_display_block_from_line(dl, RIGHT_OUTSIDE_MARGIN);
3467                 /* #### See comments before odb->start_pos init in
3468                    create_left_glyph_block */
3469                 odb->start_pos = dl->bounds.right_in;
3470                 odb->end_pos = dl->bounds.right_out;
3471                 Dynarr_reset(odb->runes);
3472         } else
3473                 odb = 0;
3474
3475         if (in_in_cnt || white_in_cnt) {
3476                 idb = get_display_block_from_line(dl, RIGHT_INSIDE_MARGIN);
3477                 idb->start_pos = dl->bounds.right_white;
3478                 /* #### See comments before odb->start_pos init in
3479                    create_left_glyph_block */
3480                 idb->end_pos = dl->bounds.right_in;
3481                 Dynarr_reset(idb->runes);
3482         } else
3483                 idb = 0;
3484
3485         /* First add the whitespace margin glyphs which are actually in the
3486            inside margin. */
3487         if (white_in_cnt) {
3488                 end_xpos = add_margin_runes(dl, idb, dl->bounds.right_white,
3489                                             white_in_cnt, GL_WHITESPACE,
3490                                             RIGHT_GLYPHS, window);
3491         } else
3492                 end_xpos = dl->bounds.right_white;
3493
3494         /* Make sure that the area between the end of the whitespace glyphs
3495            and the inside margin glyphs is cleared. */
3496         if (in_in_cnt && (in_in_start - end_xpos)) {
3497                 add_margin_blank(dl, idb, w, end_xpos, in_in_start - end_xpos,
3498                                  RIGHT_GLYPHS);
3499         }
3500
3501         /* Next add the inside margin glyphs which are actually in the
3502            inside margin. */
3503         if (in_in_cnt) {
3504                 end_xpos = add_margin_runes(dl, idb, in_in_start, in_in_cnt,
3505                                             GL_INSIDE_MARGIN, RIGHT_GLYPHS,
3506                                             window);
3507         }
3508
3509         /* If we didn't add any inside margin glyphs then make sure the rest
3510            of the inside margin area gets cleared. */
3511         if (idb && (dl->bounds.right_in - end_xpos)) {
3512                 add_margin_blank(dl, idb, w, end_xpos,
3513                                  dl->bounds.right_in - end_xpos, RIGHT_GLYPHS);
3514         }
3515
3516         /* Next add any whitespace glyphs in the outside margin. */
3517         if (white_out_cnt) {
3518                 end_xpos =
3519                     add_margin_runes(dl, odb, dl->bounds.right_in,
3520                                      white_out_cnt, GL_WHITESPACE, RIGHT_GLYPHS,
3521                                      window);
3522         } else
3523                 end_xpos = dl->bounds.right_in;
3524
3525         /* Next add any inside margin glyphs in the outside margin. */
3526         if (in_out_cnt) {
3527                 end_xpos = add_margin_runes(dl, odb, end_xpos, in_out_cnt,
3528                                             GL_INSIDE_MARGIN, RIGHT_GLYPHS,
3529                                             window);
3530         }
3531
3532         /* There may be space between any whitespace or inside margin glyphs
3533            in the outside margin and the actual outside margin glyphs. */
3534         if (odb && (out_start - end_xpos)) {
3535                 add_margin_blank(dl, odb, w, end_xpos, out_start - end_xpos,
3536                                  RIGHT_GLYPHS);
3537         }
3538
3539         /* Finally, add the outside margin glyphs. */
3540         if (out_cnt) {
3541                 add_margin_runes(dl, odb, out_start, out_cnt, GL_OUTSIDE_MARGIN,
3542                                  RIGHT_GLYPHS, window);
3543         }
3544 }
3545 \f
3546 /***************************************************************************/
3547 /*                                                                         */
3548 /*                            modeline routines                            */
3549 /*                                                                         */
3550 /***************************************************************************/
3551
3552 /* This function is also used in frame.c by `generate_title_string' */
3553 void
3554 generate_formatted_string_db(Lisp_Object format_str, Lisp_Object result_str,
3555                              struct window *w, struct display_line *dl,
3556                              struct display_block *db, face_index findex,
3557                              int min_pixpos, int max_pixpos, int type)
3558 {
3559         struct frame *f = XFRAME(w->frame);
3560         struct device *d = XDEVICE(f->device);
3561
3562         pos_data data;
3563         int c_pixpos;
3564         Charcount offset = 0;
3565
3566         xzero(data);
3567         data.d = d;
3568         data.db = db;
3569         data.dl = dl;
3570         data.findex = findex;
3571         data.pixpos = min_pixpos;
3572         data.max_pixpos = max_pixpos;
3573         data.cursor_type = NO_CURSOR;
3574         data.last_charset = Qunbound;
3575         data.last_findex = DEFAULT_INDEX;
3576         data.result_str = result_str;
3577         data.is_modeline = 1;
3578         data.string = Qnil;
3579         XSETWINDOW(data.window, w);
3580
3581         Dynarr_reset(formatted_string_extent_dynarr);
3582         Dynarr_reset(formatted_string_extent_start_dynarr);
3583         Dynarr_reset(formatted_string_extent_end_dynarr);
3584
3585         /* result_str is nil when we're building a frame or icon title. Otherwise,
3586            we're building a modeline, so the offset starts at the modeline
3587            horizontal scrolling amount */
3588         if (!NILP(result_str))
3589                 offset = w->modeline_hscroll;
3590         generate_fstring_runes(w, &data, 0, 0, -1, format_str, 0,
3591                                max_pixpos - min_pixpos, findex, type, &offset,
3592                                Qnil);
3593
3594         if (Dynarr_length(db->runes)) {
3595                 struct rune *rb =
3596                     Dynarr_atp(db->runes, Dynarr_length(db->runes) - 1);
3597                 c_pixpos = rb->xpos + rb->width;
3598         } else
3599                 c_pixpos = min_pixpos;
3600
3601         /* If we don't reach the right side of the window, add a blank rune
3602            to make up the difference.  This usually only occurs if the
3603            modeline face is using a proportional width font or a fixed width
3604            font of a different size from the default face font. */
3605
3606         if (c_pixpos < max_pixpos) {
3607                 data.pixpos = c_pixpos;
3608                 data.blank_width = max_pixpos - data.pixpos;
3609
3610                 add_blank_rune(&data, NULL, 0);
3611         }
3612
3613         /* Now create the result string and frob the extents into it. */
3614         if (!NILP(result_str)) {
3615                 int elt;
3616                 Bytecount len;
3617                 Bufbyte *strdata;
3618                 struct buffer *buf = XBUFFER(WINDOW_BUFFER(w));
3619
3620                 in_modeline_generation = 1;
3621
3622                 detach_all_extents(result_str);
3623                 resize_string(XSTRING(result_str), -1,
3624                               data.bytepos - XSTRING_LENGTH(result_str));
3625
3626                 strdata = XSTRING_DATA(result_str);
3627
3628                 for (elt = 0, len = 0; elt < Dynarr_length(db->runes); elt++) {
3629                         if (Dynarr_atp(db->runes, elt)->type == RUNE_CHAR) {
3630                                 len += (set_charptr_emchar
3631                                         (strdata + len, Dynarr_atp(db->runes,
3632                                                                    elt)->object.
3633                                          chr.ch));
3634                         }
3635                 }
3636
3637                 for (elt = 0;
3638                      elt < Dynarr_length(formatted_string_extent_dynarr);
3639                      elt++) {
3640                         Lisp_Object extent = Qnil;
3641                         Lisp_Object child;
3642
3643                         XSETEXTENT(extent,
3644                                    Dynarr_at(formatted_string_extent_dynarr,
3645                                              elt));
3646                         child =
3647                             Fgethash(extent, buf->modeline_extent_table, Qnil);
3648                         if (NILP(child)) {
3649                                 child = Fmake_extent(Qnil, Qnil, result_str);
3650                                 Fputhash(extent, child,
3651                                          buf->modeline_extent_table);
3652                         }
3653                         Fset_extent_parent(child, extent);
3654                         set_extent_endpoints
3655                             (XEXTENT(child),
3656                              Dynarr_at(formatted_string_extent_start_dynarr,
3657                                        elt),
3658                              Dynarr_at(formatted_string_extent_end_dynarr, elt),
3659                              result_str);
3660                 }
3661
3662                 in_modeline_generation = 0;
3663         }
3664 }
3665
3666 /* Ensure that the given display line DL accurately represents the
3667    modeline for the given window. */
3668 static void
3669 generate_modeline(struct window *w, struct display_line *dl, int type)
3670 {
3671         struct buffer *b = XBUFFER(w->buffer);
3672         struct frame *f = XFRAME(w->frame);
3673         struct device *d = XDEVICE(f->device);
3674
3675         /* Unlike display line and rune pointers, this one can't change underneath
3676            our feet. */
3677         struct display_block *db = get_display_block_from_line(dl, TEXT);
3678         int max_pixpos, min_pixpos, ypos_adj;
3679         Lisp_Object font_inst;
3680
3681         /* This will actually determine incorrect inside boundaries for the
3682            modeline since it ignores the margins.  However being aware of this fact
3683            we never use those values anywhere so it doesn't matter. */
3684         dl->bounds = calculate_display_line_boundaries(w, 1);
3685
3686         /* We are generating a modeline. */
3687         dl->modeline = 1;
3688         dl->cursor_elt = -1;
3689
3690         /* Reset the runes on the modeline. */
3691         Dynarr_reset(db->runes);
3692
3693         if (!WINDOW_HAS_MODELINE_P(w)) {
3694                 struct rune rb;
3695
3696                 /* If there is a horizontal scrollbar, don't add anything. */
3697                 if (window_scrollbar_height(w))
3698                         return;
3699
3700                 dl->ascent = DEVMETH(d, divider_height, ());
3701                 dl->descent = 0;
3702                 /* The modeline is at the bottom of the gutters. */
3703                 dl->ypos = WINDOW_BOTTOM(w);
3704
3705                 rb.findex = MODELINE_INDEX;
3706                 rb.xpos = dl->bounds.left_out;
3707                 rb.width = dl->bounds.right_out - dl->bounds.left_out;
3708                 rb.bufpos = 0;
3709                 rb.endpos = 0;
3710                 rb.type = RUNE_HLINE;
3711                 rb.object.hline.thickness = 1;
3712                 rb.object.hline.yoffset = 0;
3713                 rb.cursor_type = NO_CURSOR;
3714
3715                 if (!EQ(Qzero, w->modeline_shadow_thickness)
3716                     && FRAME_WIN_P(f)) {
3717                         int shadow_thickness = MODELINE_SHADOW_THICKNESS(w);
3718
3719                         dl->ypos -= shadow_thickness;
3720                         rb.xpos += shadow_thickness;
3721                         rb.width -= 2 * shadow_thickness;
3722                 }
3723
3724                 Dynarr_add(db->runes, rb);
3725                 return;
3726         }
3727
3728         /* !!#### not right; needs to compute the max height of
3729            all the charsets */
3730         font_inst = WINDOW_FACE_CACHEL_FONT(w, MODELINE_INDEX, Vcharset_ascii);
3731
3732         dl->ascent = XFONT_INSTANCE(font_inst)->ascent;
3733         dl->descent = XFONT_INSTANCE(font_inst)->descent;
3734
3735         min_pixpos = dl->bounds.left_out;
3736         max_pixpos = dl->bounds.right_out;
3737
3738         if (!EQ(Qzero, w->modeline_shadow_thickness) && FRAME_WIN_P(f)) {
3739                 int shadow_thickness = MODELINE_SHADOW_THICKNESS(w);
3740
3741                 ypos_adj = shadow_thickness;
3742                 min_pixpos += shadow_thickness;
3743                 max_pixpos -= shadow_thickness;
3744         } else
3745                 ypos_adj = 0;
3746
3747         generate_formatted_string_db(b->modeline_format,
3748                                      b->generated_modeline_string, w, dl, db,
3749                                      MODELINE_INDEX, min_pixpos, max_pixpos,
3750                                      type);
3751
3752         /* The modeline is at the bottom of the gutters.  We have to wait to
3753            set this until we've generated the modeline in order to account
3754            for any embedded faces. */
3755         dl->ypos = WINDOW_BOTTOM(w) - dl->descent - ypos_adj;
3756 }
3757
3758 static Charcount
3759 add_string_to_fstring_db_runes(pos_data * data, const Bufbyte * str,
3760                                Charcount pos, Charcount min_pos,
3761                                Charcount max_pos)
3762 {
3763         /* This function has been Mule-ized. */
3764         Charcount end;
3765         const Bufbyte *cur_pos = str;
3766         struct display_block *db = data->db;
3767
3768         data->blank_width = space_width(XWINDOW(data->window));
3769         while (Dynarr_length(db->runes) < pos)
3770                 add_blank_rune_noret(data, NULL, 0);
3771
3772         end = (Dynarr_length(db->runes) +
3773                bytecount_to_charcount(str, strlen((const char *)str)));
3774         if (max_pos != -1)
3775                 end = min(max_pos, end);
3776
3777         while (pos < end && *cur_pos) {
3778                 const Bufbyte *old_cur_pos = cur_pos;
3779                 int succeeded;
3780
3781                 data->ch = charptr_emchar(cur_pos);
3782                 succeeded = (add_emchar_rune(data) != ADD_FAILED);
3783                 INC_CHARPTR(cur_pos);
3784                 if (succeeded) {
3785                         pos++;
3786                         data->modeline_charpos++;
3787                         data->bytepos += cur_pos - old_cur_pos;
3788                 }
3789         }
3790
3791         while (Dynarr_length(db->runes) < min_pos &&
3792                (data->pixpos + data->blank_width <= data->max_pixpos))
3793                 add_blank_rune_noret(data, NULL, 0);
3794
3795         return Dynarr_length(db->runes);
3796 }
3797
3798 /* #### Urk!  Should also handle begin-glyphs and end-glyphs in
3799    modeline extents. */
3800 static Charcount
3801 add_glyph_to_fstring_db_runes(pos_data * data, Lisp_Object glyph,
3802                               Charcount pos, Charcount min_pos,
3803                               Charcount max_pos, Lisp_Object extent)
3804 {
3805         /* This function has been Mule-ized. */
3806         Charcount end;
3807         struct display_block *db = data->db;
3808         struct glyph_block gb;
3809
3810         data->blank_width = space_width(XWINDOW(data->window));
3811         while (Dynarr_length(db->runes) < pos)
3812                 add_blank_rune_noret(data, NULL, 0);
3813
3814         end = Dynarr_length(db->runes) + 1;
3815         if (max_pos != -1)
3816                 end = min(max_pos, end);
3817
3818         gb.glyph = glyph;
3819         gb.extent = extent;
3820         add_glyph_rune_noret(data, &gb, BEGIN_GLYPHS, 0, 0);
3821         pos++;
3822
3823         while (Dynarr_length(db->runes) < pos &&
3824                (data->pixpos + data->blank_width <= data->max_pixpos))
3825                 add_blank_rune_noret(data, NULL, 0);
3826
3827         return Dynarr_length(db->runes);
3828 }
3829
3830 /* If max_pos is == -1, it is considered to be infinite.  The same is
3831    true of max_pixsize. */
3832 #define SET_CURRENT_MODE_CHARS_PIXSIZE                                  \
3833   if (Dynarr_length (data->db->runes))                                  \
3834     cur_pixsize = data->pixpos - Dynarr_atp (data->db->runes, 0)->xpos; \
3835   else                                                                  \
3836     cur_pixsize = 0;
3837
3838 /* Note that this function does "positions" in terms of characters and
3839    not in terms of columns.  This is necessary to make the formatting
3840    work correctly when proportional width fonts are used in the
3841    modeline. */
3842 static Charcount
3843 generate_fstring_runes(struct window *w, pos_data * data, Charcount pos,
3844                        Charcount min_pos, Charcount max_pos,
3845                        Lisp_Object elt, int depth, int max_pixsize,
3846                        face_index findex, int type, Charcount * offset,
3847                        Lisp_Object cur_ext)
3848 {
3849         /* This function has been Mule-ized. */
3850         /* #### The other losing things in this function are:
3851
3852            -- C zero-terminated-string lossage.
3853            -- Non-printable characters should be converted into something
3854            appropriate (e.g. ^F) instead of blindly being printed anyway.
3855          */
3856
3857       tail_recurse:
3858         if (depth > 10)
3859                 goto invalid;
3860
3861         depth++;
3862
3863         if (STRINGP(elt)) {
3864                 /* A string.  Add to the display line and check for %-constructs
3865                    within it. */
3866
3867                 Bufbyte *this = XSTRING_DATA(elt);
3868
3869                 while ((pos < max_pos || max_pos == -1) && *this) {
3870                         Bufbyte *last = this;
3871
3872                         while (*this && *this != '%')
3873                                 this++;
3874
3875                         if (this != last) {
3876                                 /* No %-construct */
3877                                 Charcount size =
3878                                     bytecount_to_charcount(last, this - last);
3879
3880                                 if (size <= *offset)
3881                                         *offset -= size;
3882                                 else {
3883                                         Charcount tmp_max =
3884                                             (max_pos ==
3885                                              -1 ? pos + size -
3886                                              *offset : min(pos + size - *offset,
3887                                                            max_pos));
3888                                         const Bufbyte *tmp_last =
3889                                             charptr_n_addr(last, *offset);
3890
3891                                         pos =
3892                                             add_string_to_fstring_db_runes(data,
3893                                                                            tmp_last,
3894                                                                            pos,
3895                                                                            pos,
3896                                                                            tmp_max);
3897                                         *offset = 0;
3898                                 }
3899                         } else {        /* *this == '%' */
3900
3901                                 Charcount spec_width = 0;
3902
3903                                 this++; /* skip over '%' */
3904
3905                                 /* We can't allow -ve args due to the "%-" construct.
3906                                  * Argument specifies minwidth but not maxwidth
3907                                  * (maxwidth can be specified by
3908                                  * (<negative-number> . <stuff>) modeline elements)
3909                                  */
3910                                 while (isdigit(*this)) {
3911                                         spec_width =
3912                                             spec_width * 10 + (*this - '0');
3913                                         this++;
3914                                 }
3915                                 spec_width += pos;
3916
3917                                 if (*this == 'M') {
3918                                         pos =
3919                                             generate_fstring_runes(w, data, pos,
3920                                                                    spec_width,
3921                                                                    max_pos,
3922                                                                    Vglobal_mode_string,
3923                                                                    depth,
3924                                                                    max_pixsize,
3925                                                                    findex, type,
3926                                                                    offset,
3927                                                                    cur_ext);
3928                                 } else if (*this == '-') {
3929                                         Charcount num_to_add;
3930
3931                                         if (max_pixsize < 0)
3932                                                 num_to_add = 0;
3933                                         else if (max_pos != -1)
3934                                                 num_to_add = max_pos - pos;
3935                                         else {
3936                                                 int cur_pixsize;
3937                                                 int dash_pixsize;
3938                                                 Bufbyte ch = '-';
3939                                                 SET_CURRENT_MODE_CHARS_PIXSIZE;
3940
3941                                                 dash_pixsize =
3942                                                     redisplay_text_width_string
3943                                                     (w, findex, &ch, Qnil, 0,
3944                                                      1);
3945
3946                                                 num_to_add =
3947                                                     (max_pixsize -
3948                                                      cur_pixsize) /
3949                                                     dash_pixsize;
3950                                                 num_to_add++;
3951                                         }
3952
3953                                         while (num_to_add--)
3954                                                 pos =
3955                                                     add_string_to_fstring_db_runes
3956                                                     (data, (const Bufbyte *)"-",
3957                                                      pos, pos, max_pos);
3958                                 } else if (*this != 0) {
3959                                         Emchar ch = charptr_emchar(this);
3960                                         Bufbyte *str;
3961                                         Charcount size;
3962
3963                                         decode_mode_spec(w, ch, type);
3964
3965                                         str =
3966                                             Dynarr_atp(mode_spec_bufbyte_string,
3967                                                        0);
3968                                         size = bytecount_to_charcount
3969                                             /* Skip the null character added by `decode_mode_spec' */
3970                                             (str,
3971                                              Dynarr_length
3972                                              (mode_spec_bufbyte_string)) - 1;
3973
3974                                         if (size <= *offset)
3975                                                 *offset -= size;
3976                                         else {
3977                                                 const Bufbyte *tmp_str =
3978                                                     charptr_n_addr(str,
3979                                                                    *offset);
3980
3981                                                 /* #### NOTE: I don't understand why a tmp_max is not
3982                                                    computed and used here as in the plain string case
3983                                                    above. -- dv */
3984                                                 pos =
3985                                                     add_string_to_fstring_db_runes
3986                                                     (data, tmp_str, pos, pos,
3987                                                      max_pos);
3988                                                 *offset = 0;
3989                                         }
3990                                 }
3991
3992                                 /* NOT this++.  There could be any sort of character at
3993                                    the current position. */
3994                                 INC_CHARPTR(this);
3995                         }
3996
3997                         if (max_pixsize > 0) {
3998                                 int cur_pixsize;
3999                                 SET_CURRENT_MODE_CHARS_PIXSIZE;
4000
4001                                 if (cur_pixsize >= max_pixsize)
4002                                         break;
4003                         }
4004                 }
4005         } else if (SYMBOLP(elt)) {
4006                 /* A symbol: process the value of the symbol recursively
4007                    as if it appeared here directly. */
4008                 Lisp_Object tem = symbol_value_in_buffer(elt, w->buffer);
4009
4010                 if (!UNBOUNDP(tem)) {
4011                         /* If value is a string, output that string literally:
4012                            don't check for % within it.  */
4013                         if (STRINGP(tem)) {
4014                                 Bufbyte *str = XSTRING_DATA(tem);
4015                                 Charcount size = XSTRING_CHAR_LENGTH(tem);
4016
4017                                 if (size <= *offset)
4018                                         *offset -= size;
4019                                 else {
4020                                         const Bufbyte *tmp_str =
4021                                             charptr_n_addr(str, *offset);
4022
4023                                         /* #### NOTE: I don't understand why a tmp_max is not
4024                                            computed and used here as in the plain string case
4025                                            above. -- dv */
4026                                         pos =
4027                                             add_string_to_fstring_db_runes(data,
4028                                                                            tmp_str,
4029                                                                            pos,
4030                                                                            min_pos,
4031                                                                            max_pos);
4032                                         *offset = 0;
4033                                 }
4034                         }
4035                         /* Give up right away for nil or t.  */
4036                         else if (!EQ(tem, elt)) {
4037                                 elt = tem;
4038                                 goto tail_recurse;
4039                         }
4040                 }
4041         } else if (GENERIC_SPECIFIERP(elt)) {
4042                 Lisp_Object window, tem;
4043                 XSETWINDOW(window, w);
4044                 tem = specifier_instance_no_quit(elt, Qunbound, window,
4045                                                  ERROR_ME_NOT, 0, Qzero);
4046                 if (!UNBOUNDP(tem)) {
4047                         elt = tem;
4048                         goto tail_recurse;
4049                 }
4050         } else if (CONSP(elt)) {
4051                 /* A cons cell: four distinct cases.
4052                  * - If first element is a string or a cons, process all the elements
4053                  *   and effectively concatenate them.
4054                  * - If first element is a negative number, truncate displaying cdr to
4055                  *   at most that many characters.  If positive, pad (with spaces)
4056                  *   to at least that many characters.
4057                  * - If first element is another symbol, process the cadr or caddr
4058                  *   recursively according to whether the symbol's value is non-nil or
4059                  *   nil.
4060                  * - If first element is an extent, process the cdr recursively
4061                  *   and handle the extent's face.
4062                  */
4063
4064                 Lisp_Object car, tem;
4065
4066                 car = XCAR(elt);
4067                 if (SYMBOLP(car)) {
4068                         elt = XCDR(elt);
4069                         if (!CONSP(elt))
4070                                 goto invalid;
4071
4072                         tem = symbol_value_in_buffer(car, w->buffer);
4073                         /* elt is now the cdr, and we know it is a cons cell.
4074                            Use its car if CAR has a non-nil value.  */
4075                         if (!UNBOUNDP(tem)) {
4076                                 if (!NILP(tem)) {
4077                                         elt = XCAR(elt);
4078                                         goto tail_recurse;
4079                                 }
4080                         }
4081                         /* Symbol's value is nil (or symbol is unbound)
4082                          * Get the cddr of the original list
4083                          * and if possible find the caddr and use that.
4084                          */
4085                         elt = XCDR(elt);
4086                         if (NILP(elt)) ;
4087                         else if (!CONSP(elt))
4088                                 goto invalid;
4089                         else {
4090                                 elt = XCAR(elt);
4091                                 goto tail_recurse;
4092                         }
4093                 } else if (INTP(car)) {
4094                         Charcount lim = XINT(car);
4095
4096                         elt = XCDR(elt);
4097
4098                         if (lim < 0) {
4099                                 /* Negative int means reduce maximum width.
4100                                  * DO NOT change MIN_PIXPOS here!
4101                                  * (20 -10 . foo) should truncate foo to 10 col
4102                                  * and then pad to 20.
4103                                  */
4104                                 if (max_pos == -1)
4105                                         max_pos = pos - lim;
4106                                 else
4107                                         max_pos = min(max_pos, pos - lim);
4108                         } else if (lim > 0) {
4109                                 /* Padding specified.  Don't let it be more than
4110                                  * current maximum.
4111                                  */
4112                                 lim += pos;
4113                                 if (max_pos != -1 && lim > max_pos)
4114                                         lim = max_pos;
4115                                 /* If that's more padding than already wanted, queue it.
4116                                  * But don't reduce padding already specified even if
4117                                  * that is beyond the current truncation point.
4118                                  */
4119                                 if (lim > min_pos)
4120                                         min_pos = lim;
4121                         }
4122                         goto tail_recurse;
4123                 } else if (STRINGP(car) || CONSP(car)) {
4124                         int limit = 50;
4125
4126                         /* LIMIT is to protect against circular lists.  */
4127                         while (CONSP(elt) && --limit > 0
4128                                && (pos < max_pos || max_pos == -1)) {
4129                                 pos =
4130                                     generate_fstring_runes(w, data, pos, pos,
4131                                                            max_pos, XCAR(elt),
4132                                                            depth, max_pixsize,
4133                                                            findex, type, offset,
4134                                                            cur_ext);
4135                                 elt = XCDR(elt);
4136                         }
4137                 } else if (EXTENTP(car)) {
4138                         struct extent *ext = XEXTENT(car);
4139
4140                         if (EXTENT_LIVE_P(ext)) {
4141                                 face_index old_findex = data->findex;
4142                                 Lisp_Object face;
4143                                 Lisp_Object font_inst;
4144                                 face_index new_findex;
4145                                 Bytecount start = data->bytepos;
4146
4147                                 face = extent_face(ext);
4148                                 if (FACEP(face)) {
4149                                         /* #### needs to merge faces, sigh */
4150                                         /* #### needs to handle list of faces */
4151                                         new_findex =
4152                                             get_builtin_face_cache_index(w,
4153                                                                          face);
4154                                         /* !!#### not right; needs to compute the max height of
4155                                            all the charsets */
4156                                         font_inst =
4157                                             WINDOW_FACE_CACHEL_FONT(w,
4158                                                                     new_findex,
4159                                                                     Vcharset_ascii);
4160
4161                                         data->dl->ascent = max(data->dl->ascent,
4162                                                                XFONT_INSTANCE
4163                                                                (font_inst)->
4164                                                                ascent);
4165                                         data->dl->descent =
4166                                             max(data->dl->descent,
4167                                                 XFONT_INSTANCE(font_inst)->
4168                                                 descent);
4169                                 } else
4170                                         new_findex = old_findex;
4171
4172                                 data->findex = new_findex;
4173                                 pos =
4174                                     generate_fstring_runes(w, data, pos, pos,
4175                                                            max_pos, XCDR(elt),
4176                                                            depth - 1,
4177                                                            max_pixsize,
4178                                                            new_findex, type,
4179                                                            offset, car);
4180                                 data->findex = old_findex;
4181                                 Dynarr_add(formatted_string_extent_dynarr, ext);
4182                                 Dynarr_add(formatted_string_extent_start_dynarr,
4183                                            start);
4184                                 Dynarr_add(formatted_string_extent_end_dynarr,
4185                                            data->bytepos);
4186                         }
4187                 }
4188         } else if (GLYPHP(elt)) {
4189                 /* Glyphs are considered as one character with respect to the modeline
4190                    horizontal scrolling facility. -- dv */
4191                 if (*offset > 0)
4192                         *offset -= 1;
4193                 else
4194                         pos =
4195                             add_glyph_to_fstring_db_runes(data, elt, pos, pos,
4196                                                           max_pos, cur_ext);
4197         } else {
4198               invalid:
4199                 {
4200                         char *str = GETTEXT("*invalid*");
4201                         Charcount size = (Charcount) strlen(str);       /* is this ok ?? -- dv */
4202
4203                         if (size <= *offset)
4204                                 *offset -= size;
4205                         else {
4206                                 const Bufbyte *tmp_str =
4207                                     charptr_n_addr((const Bufbyte *)str,
4208                                                    *offset);
4209
4210                                 /* #### NOTE: I don't understand why a tmp_max is not computed and
4211                                    used here as in the plain string case above. -- dv */
4212                                 pos =
4213                                     add_string_to_fstring_db_runes(data,
4214                                                                    tmp_str, pos,
4215                                                                    min_pos,
4216                                                                    max_pos);
4217                                 *offset = 0;
4218                         }
4219                 }
4220         }
4221
4222         if (min_pos > pos) {
4223                 add_string_to_fstring_db_runes(data, (const Bufbyte *)"", pos,
4224                                                min_pos, -1);
4225         }
4226
4227         return pos;
4228 }
4229
4230 /* Update just the modeline.  Assumes the desired display structs.  If
4231    they do not have a modeline block, it does nothing. */
4232 static void regenerate_modeline(struct window *w)
4233 {
4234         display_line_dynarr *dla = window_display_lines(w, DESIRED_DISP);
4235
4236         if (!Dynarr_length(dla) || !Dynarr_atp(dla, 0)->modeline)
4237                 return;
4238         else {
4239                 generate_modeline(w, Dynarr_atp(dla, 0), DESIRED_DISP);
4240                 redisplay_update_line(w, 0, 0, 0);
4241         }
4242 }
4243
4244 /* Make sure that modeline display line is present in the given
4245    display structs if the window has a modeline and update that
4246    line.  Returns true if a modeline was needed. */
4247 static int ensure_modeline_generated(struct window *w, int type)
4248 {
4249         int need_modeline;
4250
4251         /* minibuffer windows don't have modelines */
4252         if (MINI_WINDOW_P(w))
4253                 need_modeline = 0;
4254         /* windows which haven't had it turned off do */
4255         else if (WINDOW_HAS_MODELINE_P(w))
4256                 need_modeline = 1;
4257         /* windows which have it turned off don't have a divider if there is
4258            a horizontal scrollbar */
4259         else if (window_scrollbar_height(w))
4260                 need_modeline = 0;
4261         /* and in this case there is none */
4262         else
4263                 need_modeline = 1;
4264
4265         if (need_modeline) {
4266                 display_line_dynarr *dla;
4267
4268                 dla = window_display_lines(w, type);
4269
4270                 /* We don't care if there is a display line which is not
4271                    currently a modeline because it is definitely going to become
4272                    one if we have gotten to this point. */
4273                 if (Dynarr_length(dla) == 0) {
4274                         if (Dynarr_largest(dla) > 0) {
4275                                 struct display_line *mlp = Dynarr_atp(dla, 0);
4276                                 Dynarr_add(dla, *mlp);
4277                         } else {
4278                                 struct display_line modeline;
4279                                 xzero(modeline);
4280                                 Dynarr_add(dla, modeline);
4281                         }
4282                 }
4283
4284                 /* If we're adding a new place marker go ahead and generate the
4285                    modeline so that it is available for use by
4286                    window_modeline_height. */
4287                 generate_modeline(w, Dynarr_atp(dla, 0), type);
4288         }
4289
4290         return need_modeline;
4291 }
4292
4293 /* #### Kludge or not a kludge.  I tend towards the former. */
4294 int real_current_modeline_height(struct window *w)
4295 {
4296         Fset_marker(w->start[CMOTION_DISP], w->start[CURRENT_DISP], w->buffer);
4297         Fset_marker(w->pointm[CMOTION_DISP], w->pointm[CURRENT_DISP],
4298                     w->buffer);
4299
4300         if (ensure_modeline_generated(w, CMOTION_DISP)) {
4301                 display_line_dynarr *dla =
4302                     window_display_lines(w, CMOTION_DISP);
4303
4304                 if (Dynarr_length(dla)) {
4305                         if (Dynarr_atp(dla, 0)->modeline)
4306                                 return (Dynarr_atp(dla, 0)->ascent +
4307                                         Dynarr_atp(dla, 0)->descent);
4308                 }
4309         }
4310         return 0;
4311 }
4312 \f
4313 /***************************************************************************/
4314 /*                                                                         */
4315 /*                            displayable string routines                  */
4316 /*                                                                         */
4317 /***************************************************************************/
4318
4319 /* Given a position for a string in a window, ensure that the given
4320    display line DL accurately represents the text on a line starting
4321    at the given position.
4322
4323    Yes, this is duplicating the code of create_text_block, but it
4324    looked just too hard to change create_text_block to handle strings
4325    *and* buffers. We already make a distinction between the two
4326    elsewhere in the code so I think unifying them would require a
4327    complete MULE rewrite. Besides, the other distinction is that these
4328    functions cover text that the user *cannot edit* so we can remove
4329    everything to do with cursors, minibuffers etc. Eventually the
4330    modeline routines should be modified to use this code as it copes
4331    with many more types of display situation. */
4332
4333 static Bufpos
4334 create_string_text_block(struct window *w, Lisp_Object disp_string,
4335                          struct display_line *dl,
4336                          Bufpos start_pos,
4337                          prop_block_dynarr ** prop, face_index default_face)
4338 {
4339         struct frame *f = XFRAME(w->frame);
4340         /* Note that a lot of the buffer controlled stuff has been left in
4341            because you might well want to make use of it (selective display
4342            etc), its just the buffer text that we do not use. However, it
4343            seems to be possible for buffer to be nil sometimes so protect
4344            against this case. */
4345         struct buffer *b = BUFFERP(w->buffer) ? XBUFFER(w->buffer) : 0;
4346         struct device *d = XDEVICE(f->device);
4347         Lisp_String *s = XSTRING(disp_string);
4348
4349         /* we're working with these a lot so precalculate them */
4350         Bytecount slen = XSTRING_LENGTH(disp_string);
4351         Bytecount bi_string_zv = slen;
4352         Bytind bi_start_pos = charcount_to_bytecount(string_data(s), start_pos);
4353
4354         pos_data data;
4355
4356         int truncate_win = b ? window_truncation_on(w) : 0;
4357
4358         /* We're going to ditch selective display for static text, it's an
4359            FSF thing and invisible extents are the way to go here.
4360            Implementing it also relies on a number of buffer-specific
4361            functions that we don't have the luxury of being able to use
4362            here. */
4363
4364         /* The variable ctl-arrow allows the user to specify what characters
4365            can actually be displayed and which octal should be used for.
4366            #### This variable should probably have some rethought done to
4367            it.
4368
4369            #### It would also be really nice if you could specify that
4370            the characters come out in hex instead of in octal.  Mule
4371            does that by adding a ctl-hexa variable similar to ctl-arrow,
4372            but that's bogus -- we need a more general solution.  I
4373            think you need to extend the concept of display tables
4374            into a more general conversion mechanism.  Ideally you
4375            could specify a Lisp function that converts characters,
4376            but this violates the Second Golden Rule and besides would
4377            make things way way way way slow.
4378
4379            So instead, we extend the display-table concept, which was
4380            historically limited to 256-byte vectors, to one of the
4381            following:
4382
4383            a) A 256-entry vector, for backward compatibility;
4384            b) char-table, mapping characters to values;
4385            c) range-table, mapping ranges of characters to values;
4386            d) a list of the above.
4387
4388            The (d) option allows you to specify multiple display tables
4389            instead of just one.  Each display table can specify conversions
4390            for some characters and leave others unchanged.  The way the
4391            character gets displayed is determined by the first display table
4392            with a binding for that character.  This way, you could call a
4393            function `enable-hex-display' that adds a hex display-table to
4394            the list of display tables for the current buffer.
4395
4396            #### ...not yet implemented...  Also, we extend the concept of
4397            "mapping" to include a printf-like spec.  Thus you can make all
4398            extended characters show up as hex with a display table like
4399            this:
4400
4401            #s(range-table data ((256 524288) (format "%x")))
4402
4403            Since more than one display table is possible, you have
4404            great flexibility in mapping ranges of characters.  */
4405         Emchar printable_min = b ? (CHAR_OR_CHAR_INTP(b->ctl_arrow)
4406                                     ? XCHAR_OR_CHAR_INT(b->ctl_arrow)
4407                                     : ((EQ(b->ctl_arrow, Qt)
4408                                         || EQ(b->ctl_arrow, Qnil))
4409                                        ? 255 : 160)) : 255;
4410
4411         Lisp_Object face_dt, window_dt;
4412
4413         /* The text display block for this display line. */
4414         struct display_block *db = get_display_block_from_line(dl, TEXT);
4415
4416         /* The first time through the main loop we need to force the glyph
4417            data to be updated. */
4418         int initial = 1;
4419
4420         /* Apparently the new extent_fragment_update returns an end position
4421            equal to the position passed in if there are no more runs to be
4422            displayed. */
4423         int no_more_frags = 0;
4424
4425         dl->used_prop_data = 0;
4426         dl->num_chars = 0;
4427         dl->line_continuation = 0;
4428
4429         /* set up faces to use for clearing areas, used by
4430            output_display_line */
4431         dl->default_findex = default_face;
4432         if (default_face) {
4433                 dl->left_margin_findex = default_face;
4434                 dl->right_margin_findex = default_face;
4435         } else {
4436                 dl->left_margin_findex =
4437                     get_builtin_face_cache_index(w, Vleft_margin_face);
4438                 dl->right_margin_findex =
4439                     get_builtin_face_cache_index(w, Vright_margin_face);
4440         }
4441
4442         xzero(data);
4443         data.ef = extent_fragment_new(disp_string, f);
4444
4445         /* These values are used by all of the rune addition routines.  We add
4446            them to this structure for ease of passing. */
4447         data.d = d;
4448         XSETWINDOW(data.window, w);
4449         data.db = db;
4450         data.dl = dl;
4451
4452         data.bi_bufpos = bi_start_pos;
4453         data.pixpos = dl->bounds.left_in;
4454         data.last_charset = Qunbound;
4455         data.last_findex = default_face;
4456         data.result_str = Qnil;
4457         data.string = disp_string;
4458
4459         /* Set the right boundary adjusting it to take into account any end
4460            glyph.  Save the width of the end glyph for later use. */
4461         data.max_pixpos = dl->bounds.right_in;
4462         data.max_pixpos -= data.end_glyph_width;
4463
4464         data.cursor_type = NO_CURSOR;
4465         data.cursor_x = -1;
4466
4467         data.start_col = 0;
4468         /* I don't think we want this, string areas should not scroll with
4469            the window
4470            data.start_col = w->hscroll;
4471            data.bi_start_col_enabled = (w->hscroll ? bi_start_pos : 0);
4472          */
4473         data.bi_start_col_enabled = 0;
4474         data.hscroll_glyph_width_adjust = 0;
4475
4476         /* We regenerate the line from the very beginning. */
4477         Dynarr_reset(db->runes);
4478
4479         /* Why is this less than or equal and not just less than?  If the
4480            starting position is already equal to the maximum we can't add
4481            anything else, right?  Wrong.  We might still have a newline to
4482            add.  A newline can use the room allocated for an end glyph since
4483            if we add it we know we aren't going to be adding any end
4484            glyph. */
4485
4486         /* #### Chuck -- I think this condition should be while (1).
4487            Otherwise if (e.g.) there is one begin-glyph and one end-glyph
4488            and the begin-glyph ends exactly at the end of the window, the
4489            end-glyph and text might not be displayed.  while (1) ensures
4490            that the loop terminates only when either (a) there is
4491            propagation data or (b) the end-of-line or end-of-buffer is hit.
4492
4493            #### Also I think you need to ensure that the operation
4494            "add begin glyphs; add end glyphs; add text" is atomic and
4495            can't get interrupted in the middle.  If you run off the end
4496            of the line during that operation, then you keep accumulating
4497            propagation data until you're done.  Otherwise, if the (e.g.)
4498            there's a begin glyph at a particular position and attempting
4499            to display that glyph results in window-end being hit and
4500            propagation data being generated, then the character at that
4501            position won't be displayed.
4502
4503            #### See also the comment after the end of this loop, below.
4504          */
4505         while (data.pixpos <= data.max_pixpos) {
4506                 /* #### This check probably should not be necessary. */
4507                 if (data.bi_bufpos > bi_string_zv) {
4508                         /* #### urk!  More of this lossage! */
4509                         data.bi_bufpos--;
4510                         goto done;
4511                 }
4512
4513                 /* Check for face changes. */
4514                 if (initial
4515                     || (!no_more_frags && data.bi_bufpos == data.ef->end)) {
4516                         Lisp_Object last_glyph = Qnil;
4517                         /* Deal with clipped glyphs that we have already displayed. */
4518                         if (*prop && Dynarr_atp(*prop, 0)->type == PROP_GLYPH) {
4519                                 last_glyph =
4520                                     Dynarr_atp(*prop, 0)->data.p_glyph.glyph;
4521                                 Dynarr_free(*prop);
4522                                 *prop = 0;
4523                         }
4524                         /* Now compute the face and begin/end-glyph information. */
4525                         data.findex =
4526                             /* Remember that the extent-fragment routines deal in Bytind's. */
4527                             extent_fragment_update(w, data.ef, data.bi_bufpos,
4528                                                    last_glyph);
4529                         /* This is somewhat cheesy but the alternative is to
4530                            propagate default_face into extent_fragment_update. */
4531                         if (data.findex == DEFAULT_INDEX)
4532                                 data.findex = default_face;
4533
4534                         get_display_tables(w, data.findex, &face_dt,
4535                                            &window_dt);
4536
4537                         if (data.bi_bufpos == data.ef->end)
4538                                 no_more_frags = 1;
4539                 }
4540                 initial = 0;
4541
4542                 /* Determine what is next to be displayed.  We first handle any
4543                    glyphs returned by glyphs_at_bufpos.  If there are no glyphs to
4544                    display then we determine what to do based on the character at the
4545                    current buffer position. */
4546
4547                 /* If there are glyphs, add them to the line.  We add the end
4548                    glyphs for the previous run of text here rather than doing
4549                    them at the end of handling the previous run so that glyphs
4550                    at the beginning and end of a line are handled correctly. */
4551                 if (Dynarr_length(data.ef->glyphs) > 0) {
4552                         data.ch = string_char(s, data.bi_bufpos);
4553                         *prop = add_glyph_runes(&data);
4554
4555                         if (*prop)
4556                                 goto done;
4557                 }
4558
4559                 /* If the current position is covered by an invisible extent, do
4560                    nothing (except maybe add some ellipses). */
4561                 else if (data.ef->invisible) {
4562                         /* #### Chuck, perhaps you could look at this code?  I don't
4563                            really know what I'm doing. */
4564                         if (*prop) {
4565                                 Dynarr_free(*prop);
4566                                 *prop = 0;
4567                         }
4568
4569                         /* The extent fragment code only sets this when we should
4570                            really display the ellipses.  It makes sure the ellipses
4571                            don't get displayed more than once in a row. */
4572                         if (data.ef->invisible_ellipses) {
4573                                 struct glyph_block gb;
4574
4575                                 data.ef->invisible_ellipses_already_displayed =
4576                                     1;
4577                                 data.ef->invisible_ellipses = 0;
4578                                 gb.extent = Qnil;
4579                                 gb.glyph = Vinvisible_text_glyph;
4580                                 *prop =
4581                                     add_glyph_rune(&data, &gb, BEGIN_GLYPHS, 0,
4582                                                    GLYPH_CACHEL(w,
4583                                                                 INVIS_GLYPH_INDEX));
4584                                 /* Perhaps they shouldn't propagate if the very next thing
4585                                    is to display a newline (for compatibility with
4586                                    selective-display-ellipses)?  Maybe that's too
4587                                    abstruse. */
4588                                 if (*prop)
4589                                         goto done;
4590                         }
4591
4592                         /* #### What if we're dealing with a display table? */
4593                         if (data.start_col)
4594                                 data.start_col--;
4595
4596                         if (data.bi_bufpos == bi_string_zv)
4597                                 goto done;
4598                         else
4599                                 INC_CHARBYTIND(string_data(s), data.bi_bufpos);
4600                 }
4601
4602                 /* If there is propagation data, then it represents the current
4603                    buffer position being displayed.  Add them and advance the
4604                    position counter.  This might also add the minibuffer
4605                    prompt. */
4606                 else if (*prop) {
4607                         dl->used_prop_data = 1;
4608                         *prop = add_propagation_runes(prop, &data);
4609
4610                         if (*prop)
4611                                 goto done;      /* gee, a really narrow window */
4612                         else if (data.bi_bufpos == bi_string_zv)
4613                                 goto done;
4614                         else if (data.bi_bufpos < 0)
4615                                 /* #### urk urk urk! Aborts are not very fun! Fix this please! */
4616                                 data.bi_bufpos = 0;
4617                         else
4618                                 INC_CHARBYTIND(string_data(s), data.bi_bufpos);
4619                 }
4620
4621                 /* If at end-of-buffer, we've already processed begin and
4622                    end-glyphs at this point and there's no text to process,
4623                    so we're done. */
4624                 else if (data.bi_bufpos == bi_string_zv)
4625                         goto done;
4626
4627                 else {
4628                         Lisp_Object entry = Qnil;
4629                         /* Get the character at the current buffer position. */
4630                         data.ch = string_char(s, data.bi_bufpos);
4631                         if (!NILP(face_dt) || !NILP(window_dt))
4632                                 entry =
4633                                     display_table_entry(data.ch, face_dt,
4634                                                         window_dt);
4635
4636                         /* If there is a display table entry for it, hand it off to
4637                            add_disp_table_entry_runes and let it worry about it. */
4638                         if (!NILP(entry) && !EQ(entry, make_char(data.ch))) {
4639                                 *prop =
4640                                     add_disp_table_entry_runes(&data, entry);
4641
4642                                 if (*prop)
4643                                         goto done;
4644                         }
4645
4646                         /* Check if we have hit a newline character.  If so, add a marker
4647                            to the line and end this loop. */
4648                         else if (data.ch == '\n') {
4649                                 /* We aren't going to be adding an end glyph so give its
4650                                    space back in order to make sure that the cursor can
4651                                    fit. */
4652                                 data.max_pixpos += data.end_glyph_width;
4653                                 goto done;
4654                         }
4655
4656                         /* If the current character is considered to be printable, then
4657                            just add it. */
4658                         else if (data.ch >= printable_min) {
4659                                 *prop = add_emchar_rune(&data);
4660                                 if (*prop)
4661                                         goto done;
4662                         }
4663
4664                         /* If the current character is a tab, determine the next tab
4665                            starting position and add a blank rune which extends from the
4666                            current pixel position to that starting position. */
4667                         else if (data.ch == '\t') {
4668                                 int tab_start_pixpos = data.pixpos;
4669                                 int next_tab_start;
4670                                 int char_tab_width;
4671                                 int prop_width = 0;
4672
4673                                 if (data.start_col > 1)
4674                                         tab_start_pixpos -=
4675                                             (space_width(w) *
4676                                              (data.start_col - 1));
4677
4678                                 next_tab_start =
4679                                     next_tab_position(w, tab_start_pixpos,
4680                                                       dl->bounds.left_in +
4681                                                       data.
4682                                                       hscroll_glyph_width_adjust);
4683                                 if (next_tab_start > data.max_pixpos) {
4684                                         prop_width =
4685                                             next_tab_start - data.max_pixpos;
4686                                         next_tab_start = data.max_pixpos;
4687                                 }
4688                                 data.blank_width = next_tab_start - data.pixpos;
4689                                 char_tab_width =
4690                                     (next_tab_start -
4691                                      tab_start_pixpos) / space_width(w);
4692
4693                                 *prop =
4694                                     add_blank_rune(&data, w, char_tab_width);
4695
4696                                 /* add_blank_rune is only supposed to be called with
4697                                    sizes guaranteed to fit in the available space. */
4698                                 assert(!(*prop));
4699
4700                                 if (prop_width) {
4701                                         struct prop_block pb;
4702                                         *prop = Dynarr_new(prop_block);
4703
4704                                         pb.type = PROP_BLANK;
4705                                         pb.data.p_blank.width = prop_width;
4706                                         pb.data.p_blank.findex = data.findex;
4707                                         Dynarr_add(*prop, pb);
4708
4709                                         goto done;
4710                                 }
4711                         }
4712
4713                         /* If character is a control character, pass it off to
4714                            add_control_char_runes.
4715
4716                            The is_*() routines have undefined results on
4717                            arguments outside of the range [-1, 255].  (This
4718                            often bites people who carelessly use `char' instead
4719                            of `unsigned char'.)
4720                          */
4721                         else if (data.ch < 0x100 && iscntrl((Bufbyte) data.ch)) {
4722                                 *prop = add_control_char_runes(&data, b);
4723
4724                                 if (*prop)
4725                                         goto done;
4726                         }
4727
4728                         /* If the character is above the ASCII range and we have not
4729                            already handled it, then print it as an octal number. */
4730                         else if (data.ch >= 0200) {
4731                                 *prop = add_octal_runes(&data);
4732
4733                                 if (*prop)
4734                                         goto done;
4735                         }
4736
4737                         /* Assume the current character is considered to be printable,
4738                            then just add it. */
4739                         else {
4740                                 *prop = add_emchar_rune(&data);
4741                                 if (*prop)
4742                                         goto done;
4743                         }
4744
4745                         INC_CHARBYTIND(string_data(s), data.bi_bufpos);
4746                 }
4747         }
4748
4749       done:
4750
4751         /* Determine the starting point of the next line if we did not hit the
4752            end of the buffer. */
4753         if (data.bi_bufpos < bi_string_zv) {
4754                 /* #### This check is not correct.  If the line terminated
4755                    due to a begin-glyph or end-glyph hitting window-end, then
4756                    data.ch will not point to the character at data.bi_bufpos.  If
4757                    you make the two changes mentioned at the top of this loop,
4758                    you should be able to say '(if (*prop))'.  That should also
4759                    make it possible to eliminate the data.bi_bufpos < BI_BUF_ZV (b)
4760                    check. */
4761
4762                 /* The common case is that the line ended because we hit a newline.
4763                    In that case, the next character is just the next buffer
4764                    position. */
4765                 if (data.ch == '\n') {
4766                         INC_CHARBYTIND(string_data(s), data.bi_bufpos);
4767                 }
4768
4769                 /* Otherwise we have a buffer line which cannot fit on one display
4770                    line. */
4771                 else {
4772                         struct glyph_block gb;
4773                         struct glyph_cachel *cachel;
4774
4775                         /* If the line is to be truncated then we actually have to look
4776                            for the next newline.  We also add the end-of-line glyph which
4777                            we know will fit because we adjusted the right border before
4778                            we starting laying out the line. */
4779                         data.max_pixpos += data.end_glyph_width;
4780                         data.findex = default_face;
4781                         gb.extent = Qnil;
4782
4783                         if (truncate_win) {
4784                                 Bytind bi_pos;
4785
4786                                 /* Now find the start of the next line. */
4787                                 bi_pos =
4788                                     bi_find_next_emchar_in_string(s, '\n',
4789                                                                   data.
4790                                                                   bi_bufpos, 1);
4791
4792                                 data.cursor_type = NO_CURSOR;
4793                                 data.bi_bufpos = bi_pos;
4794                                 gb.glyph = Vtruncation_glyph;
4795                                 cachel = GLYPH_CACHEL(w, TRUN_GLYPH_INDEX);
4796                         } else {
4797                                 /* The cursor can never be on the continuation glyph. */
4798                                 data.cursor_type = NO_CURSOR;
4799
4800                                 /* data.bi_bufpos is already at the start of the next line. */
4801
4802                                 dl->line_continuation = 1;
4803                                 gb.glyph = Vcontinuation_glyph;
4804                                 cachel = GLYPH_CACHEL(w, CONT_GLYPH_INDEX);
4805                         }
4806
4807                         if (data.end_glyph_width)
4808                                 add_glyph_rune_noret(&data, &gb, BEGIN_GLYPHS, 0,
4809                                                      cachel);
4810
4811                         if (truncate_win && data.bi_bufpos == bi_string_zv) {
4812                                 const Bufbyte *endb =
4813                                     charptr_n_addr(string_data(s),
4814                                                    bi_string_zv);
4815                                 DEC_CHARPTR(endb);
4816                                 if (charptr_emchar(endb) != '\n') {
4817                                         /* #### Damn this losing shit. */
4818                                         data.bi_bufpos++;
4819                                 }
4820                         }
4821                 }
4822         } else if (data.bi_bufpos == bi_string_zv) {
4823                 /* create_text_block () adds a bogus \n marker here which screws
4824                    up subwindow display. Since we never have a cursor in the
4825                    gutter we can safely ignore it. */
4826         }
4827         /* Calculate left whitespace boundary. */
4828         {
4829                 int elt = 0;
4830
4831                 /* Whitespace past a newline is considered right whitespace. */
4832                 while (elt < Dynarr_length(db->runes)) {
4833                         struct rune *rb = Dynarr_atp(db->runes, elt);
4834
4835                         if ((rb->type == RUNE_CHAR && rb->object.chr.ch == ' ')
4836                             || rb->type == RUNE_BLANK) {
4837                                 dl->bounds.left_white += rb->width;
4838                                 elt++;
4839                         } else
4840                                 elt = Dynarr_length(db->runes);
4841                 }
4842         }
4843
4844         /* Calculate right whitespace boundary. */
4845         {
4846                 int elt = Dynarr_length(db->runes) - 1;
4847                 int done = 0;
4848
4849                 while (!done && elt >= 0) {
4850                         struct rune *rb = Dynarr_atp(db->runes, elt);
4851
4852                         if (!(rb->type == RUNE_CHAR && rb->object.chr.ch < 0x100
4853                               && isspace(rb->object.chr.ch))
4854                             && !rb->type == RUNE_BLANK) {
4855                                 dl->bounds.right_white = rb->xpos + rb->width;
4856                                 done = 1;
4857                         }
4858
4859                         elt--;
4860
4861                 }
4862
4863                 /* The line is blank so everything is considered to be right
4864                    whitespace. */
4865                 if (!done)
4866                         dl->bounds.right_white = dl->bounds.left_in;
4867         }
4868
4869         /* Set the display blocks bounds. */
4870         db->start_pos = dl->bounds.left_in;
4871         if (Dynarr_length(db->runes)) {
4872                 struct rune *rb =
4873                     Dynarr_atp(db->runes, Dynarr_length(db->runes) - 1);
4874
4875                 db->end_pos = rb->xpos + rb->width;
4876         } else
4877                 db->end_pos = dl->bounds.right_white;
4878
4879         calculate_baseline(&data);
4880
4881         dl->ascent = data.new_ascent;
4882         dl->descent = data.new_descent;
4883
4884         {
4885                 unsigned short ascent =
4886                     (unsigned short)XINT(w->minimum_line_ascent);
4887
4888                 if (dl->ascent < ascent)
4889                         dl->ascent = ascent;
4890         }
4891         {
4892                 unsigned short descent =
4893                     (unsigned short)XINT(w->minimum_line_descent);
4894
4895                 if (dl->descent < descent)
4896                         dl->descent = descent;
4897         }
4898
4899         calculate_yoffset(dl, db);
4900
4901         dl->cursor_elt = data.cursor_x;
4902         /* #### lossage lossage lossage! Fix this shit! */
4903         if (data.bi_bufpos > bi_string_zv)
4904                 dl->end_bufpos =
4905                     buffer_or_string_bytind_to_bufpos(disp_string,
4906                                                       bi_string_zv);
4907         else
4908                 dl->end_bufpos =
4909                     buffer_or_string_bytind_to_bufpos(disp_string,
4910                                                       data.bi_bufpos) - 1;
4911         if (truncate_win)
4912                 data.dl->num_chars =
4913                     string_column_at_point(s, dl->end_bufpos,
4914                                            b ? XINT(b->tab_width) : 8);
4915         else
4916                 /* This doesn't correctly take into account tabs and control
4917                    characters but if the window isn't being truncated then this
4918                    value isn't going to end up being used anyhow. */
4919                 data.dl->num_chars = dl->end_bufpos - dl->bufpos;
4920
4921         /* #### handle horizontally scrolled line with text none of which
4922            was actually laid out. */
4923
4924         /* #### handle any remainder of overlay arrow */
4925
4926         if (*prop == ADD_FAILED)
4927                 *prop = NULL;
4928
4929         if (truncate_win && *prop) {
4930                 Dynarr_free(*prop);
4931                 *prop = NULL;
4932         }
4933
4934         extent_fragment_delete(data.ef);
4935
4936         /* #### If we started at EOB, then make sure we return a value past
4937            it so that regenerate_window will exit properly.  This is bogus.
4938            The main loop should get fixed so that it isn't necessary to call
4939            this function if we are already at EOB. */
4940
4941         if (data.bi_bufpos == bi_string_zv && bi_start_pos == bi_string_zv)
4942                 return bytecount_to_charcount(string_data(s), data.bi_bufpos) + 1;      /* Yuck! */
4943         else
4944                 return bytecount_to_charcount(string_data(s), data.bi_bufpos);
4945 }
4946
4947 /* Given a display line and a starting position, ensure that the
4948    contents of the display line accurately represent the visual
4949    representation of the buffer contents starting from the given
4950    position when displayed in the given window.  The display line ends
4951    when the contents of the line reach the right boundary of the given
4952    window.
4953
4954    This is very similar to generate_display_line but with the same
4955    limitations as create_string_text_block. I have taken the liberty
4956    of fixing the bytind stuff though.*/
4957
4958 static Bufpos
4959 generate_string_display_line(struct window *w, Lisp_Object disp_string,
4960                              struct display_line *dl,
4961                              Bufpos start_pos,
4962                              prop_block_dynarr ** prop, face_index default_face)
4963 {
4964         Bufpos ret_bufpos;
4965
4966         /* you must set bounds before calling this. */
4967
4968         /* Reset what this line is using. */
4969         if (dl->display_blocks)
4970                 Dynarr_reset(dl->display_blocks);
4971         if (dl->left_glyphs) {
4972                 Dynarr_free(dl->left_glyphs);
4973                 dl->left_glyphs = 0;
4974         }
4975         if (dl->right_glyphs) {
4976                 Dynarr_free(dl->right_glyphs);
4977                 dl->right_glyphs = 0;
4978         }
4979
4980         /* We aren't generating a modeline at the moment. */
4981         dl->modeline = 0;
4982
4983         /* Create a display block for the text region of the line. */
4984         ret_bufpos = create_string_text_block(w, disp_string, dl, start_pos,
4985                                               prop, default_face);
4986         dl->bufpos = start_pos;
4987         if (dl->end_bufpos < dl->bufpos)
4988                 dl->end_bufpos = dl->bufpos;
4989
4990         /* If there are left glyphs associated with any character in the
4991            text block, then create a display block to handle them. */
4992         if (dl->left_glyphs != NULL && Dynarr_length(dl->left_glyphs))
4993                 create_left_glyph_block(w, dl, 0);
4994
4995         /* If there are right glyphs associated with any character in the
4996            text block, then create a display block to handle them. */
4997         if (dl->right_glyphs != NULL && Dynarr_length(dl->right_glyphs))
4998                 create_right_glyph_block(w, dl);
4999
5000         return ret_bufpos;
5001 }
5002
5003 /* This is ripped off from regenerate_window. All we want to do is
5004    loop through elements in the string creating display lines until we
5005    have covered the provided area. Simple really.  */
5006 void
5007 generate_displayable_area(struct window *w, Lisp_Object disp_string,
5008                           int xpos, int ypos, int width, int height,
5009                           display_line_dynarr * dla,
5010                           Bufpos start_pos, face_index default_face)
5011 {
5012         int yend = ypos + height;
5013         Charcount s_zv;
5014
5015         prop_block_dynarr *prop = 0;
5016         layout_bounds bounds;
5017         assert(dla);
5018
5019         Dynarr_reset(dla);
5020         /* if there's nothing to do then do nothing. code after this assumes
5021            there is something to do. */
5022         if (NILP(disp_string))
5023                 return;
5024
5025         s_zv = XSTRING_CHAR_LENGTH(disp_string);
5026
5027         bounds.left_out = xpos;
5028         bounds.right_out = xpos + width;
5029         /* The inner boundaries mark where the glyph margins are located. */
5030         bounds.left_in = bounds.left_out + window_left_margin_width(w);
5031         bounds.right_in = bounds.right_out - window_right_margin_width(w);
5032         /* We cannot fully calculate the whitespace boundaries as they
5033            depend on the contents of the line being displayed. */
5034         bounds.left_white = bounds.left_in;
5035         bounds.right_white = bounds.right_in;
5036
5037         while (ypos < yend) {
5038                 struct display_line dl;
5039                 struct display_line *dlp;
5040                 Bufpos next_pos;
5041                 int local;
5042
5043                 if (Dynarr_length(dla) < Dynarr_largest(dla)) {
5044                         dlp = Dynarr_atp(dla, Dynarr_length(dla));
5045                         local = 0;
5046                 } else {
5047
5048                         xzero(dl);
5049                         dlp = &dl;
5050                         local = 1;
5051                 }
5052
5053                 dlp->bounds = bounds;
5054                 dlp->offset = 0;
5055                 next_pos =
5056                     generate_string_display_line(w, disp_string, dlp, start_pos,
5057                                                  &prop, default_face);
5058                 /* we need to make sure that we continue along the line if there
5059                    is more left to display otherwise we just end up redisplaying
5060                    the same chunk over and over again. */
5061                 if (next_pos == start_pos && next_pos < s_zv)
5062                         start_pos++;
5063                 else
5064                         start_pos = next_pos;
5065
5066                 dlp->ypos = ypos + dlp->ascent;
5067                 ypos = dlp->ypos + dlp->descent;
5068
5069                 if (ypos > yend) {
5070                         int visible_height = dlp->ascent + dlp->descent;
5071
5072                         dlp->clip = (ypos - yend);
5073                         visible_height -= dlp->clip;
5074
5075                         if (visible_height < VERTICAL_CLIP(w, 1)) {
5076                                 if (local)
5077                                         free_display_line(dlp);
5078                                 break;
5079                         }
5080                 } else
5081                         dlp->clip = 0;
5082
5083                 Dynarr_add(dla, *dlp);
5084
5085                 /* #### This type of check needs to be done down in the
5086                    generate_display_line call. */
5087                 if (start_pos >= s_zv)
5088                         break;
5089         }
5090
5091         if (prop)
5092                 Dynarr_free(prop);
5093 }
5094 \f
5095 /***************************************************************************/
5096 /*                                                                         */
5097 /*                        window-regeneration routines                     */
5098 /*                                                                         */
5099 /***************************************************************************/
5100
5101 /* For a given window and starting position in the buffer it contains,
5102    ensure that the TYPE display lines accurately represent the
5103    presentation of the window.  We pass the buffer instead of getting
5104    it from the window since redisplay_window may have temporarily
5105    changed it to the echo area buffer. */
5106
5107 static void
5108 regenerate_window(struct window *w, Bufpos start_pos, Bufpos point, int type)
5109 {
5110         struct frame *f = XFRAME(w->frame);
5111         struct buffer *b = XBUFFER(w->buffer);
5112         int ypos = WINDOW_TEXT_TOP(w);
5113         int yend;               /* set farther down */
5114         int yclip = WINDOW_TEXT_TOP_CLIP(w);
5115         int force;
5116
5117         prop_block_dynarr *prop;
5118         layout_bounds bounds;
5119         display_line_dynarr *dla;
5120         int need_modeline;
5121
5122         /* The lines had better exist by this point. */
5123         if (!(dla = window_display_lines(w, type))) {
5124                 abort();
5125                 return;
5126         }
5127         Dynarr_reset(dla);
5128         w->max_line_len = 0;
5129
5130         /* Normally these get updated in redisplay_window but it is possible
5131            for this function to get called from some other points where that
5132            update may not have occurred.  This acts as a safety check. */
5133         if (!Dynarr_length(w->face_cachels))
5134                 reset_face_cachels(w);
5135         if (!Dynarr_length(w->glyph_cachels))
5136                 reset_glyph_cachels(w);
5137
5138         Fset_marker(w->start[type], make_int(start_pos), w->buffer);
5139         Fset_marker(w->pointm[type], make_int(point), w->buffer);
5140         w->last_point_x[type] = -1;
5141         w->last_point_y[type] = -1;
5142
5143         /* Make sure a modeline is in the structs if needed. */
5144         need_modeline = ensure_modeline_generated(w, type);
5145
5146         /* Wait until here to set this so that the structs have a modeline
5147            generated in the case where one didn't exist. */
5148         yend = WINDOW_TEXT_BOTTOM(w);
5149
5150         bounds = calculate_display_line_boundaries(w, 0);
5151
5152         /* 97/3/14 jhod: stuff added here to support pre-prompts (used for input systems) */
5153         if (MINI_WINDOW_P(w)
5154             && (!NILP(Vminibuf_prompt) || !NILP(Vminibuf_preprompt))
5155             && !echo_area_active(f)
5156             && start_pos == BUF_BEGV(b)) {
5157                 struct prop_block pb;
5158                 Lisp_Object string;
5159                 prop = Dynarr_new(prop_block);
5160
5161                 string = concat2(Vminibuf_preprompt, Vminibuf_prompt);
5162                 pb.type = PROP_MINIBUF_PROMPT;
5163                 pb.data.p_string.str = XSTRING_DATA(string);
5164                 pb.data.p_string.len = XSTRING_LENGTH(string);
5165                 Dynarr_add(prop, pb);
5166         } else
5167                 prop = 0;
5168
5169         /* When we are computing things for scrolling purposes, make
5170            sure at least one line is always generated */
5171         force = (type == CMOTION_DISP);
5172
5173         /* Make sure this is set always */
5174         /* Note the conversion at end */
5175         w->window_end_pos[type] = start_pos;
5176         while (ypos < yend || force) {
5177                 struct display_line dl;
5178                 struct display_line *dlp;
5179                 int local;
5180
5181                 if (Dynarr_length(dla) < Dynarr_largest(dla)) {
5182                         dlp = Dynarr_atp(dla, Dynarr_length(dla));
5183                         local = 0;
5184                 } else {
5185
5186                         xzero(dl);
5187                         dlp = &dl;
5188                         local = 1;
5189                 }
5190
5191                 dlp->bounds = bounds;
5192                 dlp->offset = 0;
5193                 start_pos =
5194                     generate_display_line(w, dlp, 1, start_pos, &prop, type);
5195
5196                 if (yclip > dlp->ascent) {
5197                         /* this should never happen, but if it does just display the
5198                            whole line */
5199                         yclip = 0;
5200                 }
5201
5202                 dlp->ypos = (ypos + dlp->ascent) - yclip;
5203                 ypos = dlp->ypos + dlp->descent;
5204
5205                 /* See if we've been asked to start midway through a line, for
5206                    partial display line scrolling. */
5207                 if (yclip) {
5208                         dlp->top_clip = yclip;
5209                         yclip = 0;
5210                 } else
5211                         dlp->top_clip = 0;
5212
5213                 if (ypos > yend) {
5214                         int visible_height = dlp->ascent + dlp->descent;
5215
5216                         dlp->clip = (ypos - yend);
5217                         /* Although this seems strange we could have a single very
5218                            tall line visible for which we need to account for both
5219                            the top clip and the bottom clip. */
5220                         visible_height -= (dlp->clip + dlp->top_clip);
5221
5222                         if (visible_height < VERTICAL_CLIP(w, 1) && !force) {
5223                                 if (local)
5224                                         free_display_line(dlp);
5225                                 break;
5226                         }
5227                 } else
5228                         dlp->clip = 0;
5229
5230                 if (dlp->cursor_elt != -1) {
5231                         /* #### This check is steaming crap.  Have to get things
5232                            fixed so when create_text_block hits EOB, we're done,
5233                            period. */
5234                         if (w->last_point_x[type] == -1) {
5235                                 w->last_point_x[type] = dlp->cursor_elt;
5236                                 w->last_point_y[type] = Dynarr_length(dla);
5237                         } else {
5238                                 /* #### This means that we've added a cursor at EOB
5239                                    twice.  Yuck oh yuck. */
5240                                 struct display_block *db =
5241                                     get_display_block_from_line(dlp, TEXT);
5242
5243                                 Dynarr_atp(db->runes,
5244                                            dlp->cursor_elt)->cursor_type =
5245                                     NO_CURSOR;
5246                                 dlp->cursor_elt = -1;
5247                         }
5248                 }
5249
5250                 if (dlp->num_chars > w->max_line_len)
5251                         w->max_line_len = dlp->num_chars;
5252
5253                 Dynarr_add(dla, *dlp);
5254
5255                 /* #### This isn't right, but it is close enough for now. */
5256                 w->window_end_pos[type] = start_pos;
5257
5258                 /* #### This type of check needs to be done down in the
5259                    generate_display_line call. */
5260                 if (start_pos > BUF_ZV(b))
5261                         break;
5262
5263                 force = 0;
5264         }
5265
5266         if (prop)
5267                 Dynarr_free(prop);
5268
5269         /* #### More not quite right, but close enough. */
5270         /* Ben sez: apparently window_end_pos[] is measured
5271            as the number of characters between the window end and the
5272            end of the buffer?  This seems rather weirdo.  What's
5273            the justification for this?
5274
5275            JV sez: Because BUF_Z (b) would be a good initial value, however
5276            that can change. This representation allows initalizing with 0.
5277          */
5278         w->window_end_pos[type] = BUF_Z(b) - w->window_end_pos[type];
5279
5280         if (need_modeline) {
5281                 /* We know that this is the right thing to use because we put it
5282                    there when we first started working in this function. */
5283                 generate_modeline(w, Dynarr_atp(dla, 0), type);
5284         }
5285 }
5286
5287 #define REGEN_INC_FIND_START_END                \
5288   do {                                          \
5289     /* Determine start and end of lines. */     \
5290     if (!Dynarr_length (cdla))                  \
5291       return 0;                                 \
5292     else                                        \
5293       {                                         \
5294         if (Dynarr_atp (cdla, 0)->modeline && Dynarr_atp (ddla, 0)->modeline) \
5295           {                                     \
5296             dla_start = 1;                      \
5297           }                                     \
5298         else if (!Dynarr_atp (cdla, 0)->modeline \
5299                  && !Dynarr_atp (ddla, 0)->modeline) \
5300           {                                     \
5301             dla_start = 0;                      \
5302           }                                     \
5303         else                                    \
5304           abort ();     /* structs differ */    \
5305                                                 \
5306         dla_end = Dynarr_length (cdla) - 1;     \
5307       }                                         \
5308                                                 \
5309     start_pos = (Dynarr_atp (cdla, dla_start)->bufpos \
5310                  + Dynarr_atp (cdla, dla_start)->offset); \
5311     /* If this isn't true, then startp has changed and we need to do a \
5312        full regen. */                           \
5313     if (startp != start_pos)                    \
5314       return 0;                                 \
5315                                                 \
5316     /* Point is outside the visible region so give up. */ \
5317     if (pointm < start_pos)                     \
5318       return 0;                                 \
5319                                                 \
5320   } while (0)
5321
5322 /* This attempts to incrementally update the display structures.  It
5323    returns a boolean indicating success or failure.  This function is
5324    very similar to regenerate_window_incrementally and is in fact only
5325    called from that function.  However, because of the nature of the
5326    changes it deals with it sometimes makes different assumptions
5327    which can lead to success which are much more difficult to make
5328    when dealing with buffer changes. */
5329
5330 static int
5331 regenerate_window_extents_only_changed(struct window *w, Bufpos startp,
5332                                        Bufpos pointm,
5333                                        Charcount beg_unchanged,
5334                                        Charcount end_unchanged)
5335 {
5336         struct buffer *b = XBUFFER(w->buffer);
5337         display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
5338         display_line_dynarr *ddla = window_display_lines(w, DESIRED_DISP);
5339
5340         int dla_start = 0;
5341         int dla_end, line;
5342         int first_line, last_line;
5343         Bufpos start_pos;
5344         /* Don't define this in the loop where it is used because we
5345            definitely want its value to survive between passes. */
5346         prop_block_dynarr *prop = NULL;
5347
5348         /* If we don't have any buffer change recorded but the modiff flag has
5349            been incremented, then fail.  I'm not sure of the exact circumstances
5350            under which this can happen, but I believe that it is probably a
5351            reasonable happening. */
5352         if (!point_visible(w, pointm, CURRENT_DISP)
5353             || XINT(w->last_modified[CURRENT_DISP]) < BUF_MODIFF(b))
5354                 return 0;
5355
5356         /* If the cursor is moved we attempt to update it.  If we succeed we
5357            go ahead and proceed with the optimization attempt. */
5358         if (!EQ(Fmarker_buffer(w->last_point[CURRENT_DISP]), w->buffer)
5359             || pointm != marker_position(w->last_point[CURRENT_DISP])) {
5360                 struct frame *f = XFRAME(w->frame);
5361                 struct device *d = XDEVICE(f->device);
5362                 struct frame *sel_f = device_selected_frame(d);
5363                 int success = 0;
5364
5365                 if (w->last_point_x[CURRENT_DISP] != -1
5366                     && w->last_point_y[CURRENT_DISP] != -1) {
5367
5368                         if (redisplay_move_cursor(w, pointm, WINDOW_TTY_P(w))) {
5369                                 /* Always regenerate the modeline in case it is
5370                                    displaying the current line or column. */
5371                                 regenerate_modeline(w);
5372                                 success = 1;
5373                         }
5374                 } else if (w != XWINDOW(FRAME_SELECTED_WINDOW(sel_f))) {
5375                         if (f->modeline_changed)
5376                                 regenerate_modeline(w);
5377                         success = 1;
5378                 }
5379
5380                 if (!success)
5381                         return 0;
5382         }
5383
5384         if (beg_unchanged == -1 && end_unchanged == -1)
5385                 return 1;
5386
5387         /* assert: There are no buffer modifications or they are all below the
5388            visible region.  We assume that regenerate_window_incrementally has
5389            not called us unless this is true.  */
5390
5391         REGEN_INC_FIND_START_END;
5392
5393         /* If the changed are starts before the visible area, give up. */
5394         if (beg_unchanged < startp)
5395                 return 0;
5396
5397         /* Find what display line the extent changes first affect. */
5398         line = dla_start;
5399         while (line <= dla_end) {
5400                 struct display_line *dl = Dynarr_atp(cdla, line);
5401                 Bufpos lstart = dl->bufpos + dl->offset;
5402                 Bufpos lend = dl->end_bufpos + dl->offset;
5403
5404                 if (beg_unchanged >= lstart && beg_unchanged <= lend)
5405                         break;
5406
5407                 line++;
5408         }
5409
5410         /* If the changes are below the visible area then if point hasn't
5411            moved return success otherwise fail in order to be safe. */
5412         if (line > dla_end) {
5413                 if (EQ(Fmarker_buffer(w->last_point[CURRENT_DISP]), w->buffer)
5414                     && pointm == marker_position(w->last_point[CURRENT_DISP]))
5415                         return 1;
5416                 else
5417                         return 0;
5418         }
5419
5420         /* At this point we know what line the changes first affect.  We now
5421            begin redrawing lines as long as we are still in the affected
5422            region and the line's size and positioning don't change.
5423            Otherwise we fail.  If we fail we will have altered the desired
5424            structs which could lead to an assertion failure.  However, if we
5425            fail the next thing that is going to happen is a full regen so we
5426            will actually end up being safe. */
5427         w->last_modified[DESIRED_DISP] = make_int(BUF_MODIFF(b));
5428         w->last_facechange[DESIRED_DISP] = make_int(BUF_FACECHANGE(b));
5429         Fset_marker(w->last_start[DESIRED_DISP], make_int(startp), w->buffer);
5430         Fset_marker(w->last_point[DESIRED_DISP], make_int(pointm), w->buffer);
5431
5432         first_line = last_line = line;
5433         while (line <= dla_end) {
5434                 Bufpos old_start, old_end, new_start;
5435                 struct display_line *cdl = Dynarr_atp(cdla, line);
5436                 struct display_line *ddl = Dynarr_atp(ddla, line);
5437                 struct display_block *db;
5438                 int initial_size;
5439
5440                 assert(cdl->bufpos == ddl->bufpos);
5441                 assert(cdl->end_bufpos == ddl->end_bufpos);
5442                 assert(cdl->offset == ddl->offset);
5443
5444                 db = get_display_block_from_line(ddl, TEXT);
5445                 initial_size = Dynarr_length(db->runes);
5446                 old_start = ddl->bufpos + ddl->offset;
5447                 old_end = ddl->end_bufpos + ddl->offset;
5448
5449                 /* If this is the first line being updated and it used
5450                    propagation data, fail.  Otherwise we'll be okay because
5451                    we'll have the necessary propagation data. */
5452                 if (line == first_line && ddl->used_prop_data)
5453                         return 0;
5454
5455                 new_start =
5456                     generate_display_line(w, ddl, 0, ddl->bufpos + ddl->offset,
5457                                           &prop, DESIRED_DISP);
5458                 (void)new_start; // Silence set-not-read warning.
5459
5460                 ddl->offset = 0;
5461
5462                 /* #### If there is propagated stuff the fail.  We could
5463                    probably actually deal with this if the line had propagated
5464                    information when originally created by a full
5465                    regeneration. */
5466                 if (prop) {
5467                         Dynarr_free(prop);
5468                         return 0;
5469                 }
5470
5471                 /* If any line position parameters have changed or a
5472                    cursor has disappeared or disappeared, fail.  */
5473                 db = get_display_block_from_line(ddl, TEXT);
5474                 if (cdl->ypos != ddl->ypos
5475                     || cdl->ascent != ddl->ascent
5476                     || cdl->descent != ddl->descent
5477                     || cdl->top_clip != ddl->top_clip
5478                     || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
5479                     || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1)
5480                     || old_start != ddl->bufpos
5481                     || old_end != ddl->end_bufpos
5482                     || initial_size != Dynarr_length(db->runes)) {
5483                         return 0;
5484                 }
5485
5486                 if (ddl->cursor_elt != -1) {
5487                         w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
5488                         w->last_point_y[DESIRED_DISP] = line;
5489                 }
5490
5491                 last_line = line;
5492
5493                 /* If the extent changes end on the line we just updated then
5494                    we're done.  Otherwise go on to the next line. */
5495                 if (end_unchanged <= ddl->end_bufpos)
5496                         break;
5497                 else
5498                         line++;
5499         }
5500
5501         redisplay_update_line(w, first_line, last_line, 1);
5502         return 1;
5503 }
5504
5505 /* Attempt to update the display data structures based on knowledge of
5506    the changed region in the buffer.  Returns a boolean indicating
5507    success or failure.  If this function returns a failure then a
5508    regenerate_window _must_ be performed next in order to maintain
5509    invariants located here. */
5510
5511 static int
5512 regenerate_window_incrementally(struct window *w, Bufpos startp, Bufpos pointm)
5513 {
5514         struct buffer *b = XBUFFER(w->buffer);
5515         display_line_dynarr *cdla = window_display_lines(w, CURRENT_DISP);
5516         display_line_dynarr *ddla = window_display_lines(w, DESIRED_DISP);
5517         Charcount beg_unchanged, end_unchanged;
5518         Charcount extent_beg_unchanged, extent_end_unchanged;
5519
5520         int dla_start = 0;
5521         int dla_end, line;
5522         Bufpos start_pos;
5523
5524         /* If this function is called, the current and desired structures
5525            had better be identical.  If they are not, then that is a bug. */
5526         assert(Dynarr_length(cdla) == Dynarr_length(ddla));
5527
5528         /* We don't handle minibuffer windows yet.  The minibuffer prompt
5529            screws us up. */
5530         if (MINI_WINDOW_P(w))
5531                 return 0;
5532
5533         extent_beg_unchanged = BUF_EXTENT_BEGIN_UNCHANGED(b);
5534         extent_end_unchanged = (BUF_EXTENT_END_UNCHANGED(b) == -1
5535                                 ? -1 : BUF_Z(b) - BUF_EXTENT_END_UNCHANGED(b));
5536
5537         /* If nothing has changed in the buffer, then make sure point is ok
5538            and succeed. */
5539         if (BUF_BEGIN_UNCHANGED(b) == -1 && BUF_END_UNCHANGED(b) == -1)
5540                 return regenerate_window_extents_only_changed(w, startp, pointm,
5541                                                               extent_beg_unchanged,
5542                                                               extent_end_unchanged);
5543
5544         /* We can't deal with deleted newlines. */
5545         if (BUF_NEWLINE_WAS_DELETED(b))
5546                 return 0;
5547
5548         beg_unchanged = BUF_BEGIN_UNCHANGED(b);
5549         end_unchanged = (BUF_END_UNCHANGED(b) == -1
5550                          ? -1 : BUF_Z(b) - BUF_END_UNCHANGED(b));
5551
5552         REGEN_INC_FIND_START_END;
5553
5554         /* If the changed area starts before the visible area, give up. */
5555         if (beg_unchanged < startp)
5556                 return 0;
5557
5558         /* Find what display line the buffer changes first affect. */
5559         line = dla_start;
5560         while (line <= dla_end) {
5561                 struct display_line *dl = Dynarr_atp(cdla, line);
5562                 Bufpos lstart = dl->bufpos + dl->offset;
5563                 Bufpos lend = dl->end_bufpos + dl->offset;
5564
5565                 if (beg_unchanged >= lstart && beg_unchanged <= lend)
5566                         break;
5567
5568                 line++;
5569         }
5570
5571         /* If the changes are below the visible area then if point hasn't
5572            moved return success otherwise fail in order to be safe. */
5573         if (line > dla_end)
5574                 return regenerate_window_extents_only_changed(w, startp, pointm,
5575                                                               extent_beg_unchanged,
5576                                                               extent_end_unchanged);
5577         else
5578                 /* At this point we know what line the changes first affect.  We
5579                    now redraw that line.  If the changes are contained within it
5580                    we are going to succeed and can update just that one line.
5581                    Otherwise we fail.  If we fail we will have altered the desired
5582                    structs which could lead to an assertion failure.  However, if
5583                    we fail the next thing that is going to happen is a full regen
5584                    so we will actually end up being safe. */
5585         {
5586                 Bufpos new_start;
5587                 prop_block_dynarr *prop = NULL;
5588                 struct display_line *cdl = Dynarr_atp(cdla, line);
5589                 struct display_line *ddl = Dynarr_atp(ddla, line);
5590
5591                 assert(cdl->bufpos == ddl->bufpos);
5592                 assert(cdl->end_bufpos == ddl->end_bufpos);
5593                 assert(cdl->offset == ddl->offset);
5594
5595                 /* If the line continues to next display line, fail. */
5596                 if (ddl->line_continuation)
5597                         return 0;
5598
5599                 /* If the line was generated using propagation data, fail. */
5600                 if (ddl->used_prop_data)
5601                         return 0;
5602
5603                 new_start =
5604                     generate_display_line(w, ddl, 0, ddl->bufpos + ddl->offset,
5605                                           &prop, DESIRED_DISP);
5606                 (void)new_start; // Silence set-not-read warning.
5607
5608                 ddl->offset = 0;
5609
5610                 /* If there is propagated stuff then it is pretty much a
5611                    guarantee that more than just the one line is affected. */
5612                 if (prop) {
5613                         Dynarr_free(prop);
5614                         return 0;
5615                 }
5616
5617                 /* If the line continues to next display line, fail. */
5618                 if (ddl->line_continuation)
5619                         return 0;
5620
5621                 /* If any line position parameters have changed or a
5622                    cursor has disappeared or disappeared, fail. */
5623                 if (cdl->ypos != ddl->ypos
5624                     || cdl->ascent != ddl->ascent
5625                     || cdl->descent != ddl->descent
5626                     || cdl->top_clip != ddl->top_clip
5627                     || (cdl->cursor_elt != -1 && ddl->cursor_elt == -1)
5628                     || (cdl->cursor_elt == -1 && ddl->cursor_elt != -1)) {
5629                         return 0;
5630                 }
5631
5632                 /* If the changed area also ends on this line, then we may be in
5633                    business.  Update everything and return success. */
5634                 if (end_unchanged >= ddl->bufpos
5635                     && end_unchanged <= ddl->end_bufpos) {
5636                         w->last_modified[DESIRED_DISP] =
5637                             make_int(BUF_MODIFF(b));
5638                         w->last_facechange[DESIRED_DISP] =
5639                             make_int(BUF_FACECHANGE(b));
5640                         Fset_marker(w->last_start[DESIRED_DISP],
5641                                     make_int(startp), w->buffer);
5642                         Fset_marker(w->last_point[DESIRED_DISP],
5643                                     make_int(pointm), w->buffer);
5644
5645                         if (ddl->cursor_elt != -1) {
5646                                 w->last_point_x[DESIRED_DISP] = ddl->cursor_elt;
5647                                 w->last_point_y[DESIRED_DISP] = line;
5648                         }
5649
5650                         redisplay_update_line(w, line, line, 1);
5651                         regenerate_modeline(w);
5652
5653                         /* #### For now we just flush the cache until this has been
5654                            tested.  After that is done, this should correct the
5655                            cache directly. */
5656                         Dynarr_reset(w->line_start_cache);
5657
5658                         /* Adjust the extent changed boundaries to remove any
5659                            overlap with the buffer changes since we've just
5660                            successfully updated that area. */
5661                         if (extent_beg_unchanged != -1
5662                             && extent_beg_unchanged >= beg_unchanged
5663                             && extent_beg_unchanged < end_unchanged)
5664                                 extent_beg_unchanged = end_unchanged;
5665
5666                         if (extent_end_unchanged != -1
5667                             && extent_end_unchanged >= beg_unchanged
5668                             && extent_end_unchanged < end_unchanged)
5669                                 extent_end_unchanged = beg_unchanged - 1;
5670
5671                         if (extent_end_unchanged <= extent_beg_unchanged)
5672                                 extent_beg_unchanged = extent_end_unchanged =
5673                                     -1;
5674
5675                         /* This could lead to odd results if it fails, but since the
5676                            buffer changes update succeeded this probably will to.
5677                            We already know that the extent changes start at or after
5678                            the line because we checked before entering the loop. */
5679                         if (extent_beg_unchanged != -1
5680                             && extent_end_unchanged != -1
5681                             && ((extent_beg_unchanged < ddl->bufpos)
5682                                 || (extent_end_unchanged > ddl->end_bufpos)))
5683                                 return regenerate_window_extents_only_changed(w,
5684                                                                               startp,
5685                                                                               pointm,
5686                                                                               extent_beg_unchanged,
5687                                                                               extent_end_unchanged);
5688                         else
5689                                 return 1;
5690                 }
5691         }
5692
5693         /* Oh, well. */
5694         return 0;
5695 }
5696
5697 /* Given a window and a point, update the given display lines such
5698    that point is displayed in the middle of the window.
5699    Return the window's new start position. */
5700
5701 static Bufpos
5702 regenerate_window_point_center(struct window *w, Bufpos point, int type)
5703 {
5704         Bufpos startp;
5705
5706         /* We need to make sure that the modeline is generated so that the
5707            window height can be calculated correctly. */
5708         ensure_modeline_generated(w, type);
5709
5710         startp = start_with_line_at_pixpos(w, point, window_half_pixpos(w));
5711         regenerate_window(w, startp, point, type);
5712         Fset_marker(w->start[type], make_int(startp), w->buffer);
5713
5714         return startp;
5715 }
5716
5717 /* Given a window and a set of display lines, return a boolean
5718    indicating whether the given point is contained within. */
5719
5720 static int point_visible(struct window *w, Bufpos point, int type)
5721 {
5722         struct buffer *b = XBUFFER(w->buffer);
5723         display_line_dynarr *dla = window_display_lines(w, type);
5724         int first_line;
5725
5726         if (Dynarr_length(dla) && Dynarr_atp(dla, 0)->modeline)
5727                 first_line = 1;
5728         else
5729                 first_line = 0;
5730
5731         if (Dynarr_length(dla) > first_line) {
5732                 Bufpos start, end;
5733                 struct display_line *dl = Dynarr_atp(dla, first_line);
5734
5735                 start = dl->bufpos;
5736                 end = BUF_Z(b) - w->window_end_pos[type] - 1;
5737
5738                 if (point >= start && point <= end) {
5739                         if (!MINI_WINDOW_P(w) && scroll_on_clipped_lines) {
5740                                 dl = Dynarr_atp(dla, Dynarr_length(dla) - 1);
5741
5742                                 if (point >= (dl->bufpos + dl->offset)
5743                                     && point <= (dl->end_bufpos + dl->offset))
5744                                         return !dl->clip;
5745                                 else
5746                                         return 1;
5747                         } else
5748                                 return 1;
5749                 } else
5750                         return 0;
5751         } else
5752                 return 0;
5753 }
5754
5755 /* Return pixel position the middle of the window, not including the
5756    modeline and any potential horizontal scrollbar. */
5757
5758 int window_half_pixpos(struct window *w)
5759 {
5760         return WINDOW_TEXT_TOP(w) + (WINDOW_TEXT_HEIGHT(w) >> 1);
5761 }
5762
5763 /* Return the display line which is currently in the middle of the
5764    window W for display lines TYPE. */
5765
5766 int line_at_center(struct window *w, int type, Bufpos start, Bufpos point)
5767 {
5768         display_line_dynarr *dla;
5769         int half;
5770         int elt;
5771         int first_elt = (MINI_WINDOW_P(w) ? 0 : 1);
5772
5773         if (type == CMOTION_DISP)
5774                 regenerate_window(w, start, point, type);
5775
5776         dla = window_display_lines(w, type);
5777         half = window_half_pixpos(w);
5778
5779         for (elt = first_elt; elt < Dynarr_length(dla); elt++) {
5780                 struct display_line *dl = Dynarr_atp(dla, elt);
5781                 int line_bot = dl->ypos + dl->descent;
5782
5783                 if (line_bot > half)
5784                         return elt;
5785         }
5786
5787         /* We may not have a line at the middle if the end of the buffer is
5788            being displayed. */
5789         return -1;
5790 }
5791
5792 /* Return a value for point that would place it at the beginning of
5793    the line which is in the middle of the window. */
5794
5795 Bufpos point_at_center(struct window * w, int type, Bufpos start, Bufpos point)
5796 {
5797         /* line_at_center will regenerate the display structures, if necessary. */
5798         int line = line_at_center(w, type, start, point);
5799
5800         if (line == -1)
5801                 return BUF_ZV(XBUFFER(w->buffer));
5802         else {
5803                 display_line_dynarr *dla = window_display_lines(w, type);
5804                 struct display_line *dl = Dynarr_atp(dla, line);
5805
5806                 return dl->bufpos;
5807         }
5808 }
5809
5810 /* For a given window, ensure that the current visual representation
5811    is accurate. */
5812
5813 static void redisplay_window(Lisp_Object window, int skip_selected)
5814 {
5815         struct window *w = XWINDOW(window);
5816         struct frame *f = XFRAME(w->frame);
5817         struct device *d = XDEVICE(f->device);
5818         Lisp_Object old_buffer = w->buffer;
5819         Lisp_Object the_buffer = w->buffer;
5820         struct buffer *b;
5821         int echo_active = 0;
5822         int startp = 1;
5823         int pointm;
5824         int old_startp = 1;
5825         int old_pointm = 1;
5826         int selected_in_its_frame;
5827         int selected_globally;
5828         int skip_output = 0;
5829         int truncation_changed;
5830         int inactive_minibuffer =
5831             (MINI_WINDOW_P(w) &&
5832              (f != device_selected_frame(d)) &&
5833              !is_surrogate_for_selected_frame(f));
5834
5835         /* #### In the new world this function actually does a bunch of
5836            optimizations such as buffer-based scrolling, but none of that is
5837            implemented yet. */
5838
5839         /* If this is a combination window, do its children; that's all.
5840            The selected window is always a leaf so we don't check for
5841            skip_selected here. */
5842         if (!NILP(w->vchild)) {
5843                 redisplay_windows(w->vchild, skip_selected);
5844                 return;
5845         }
5846         if (!NILP(w->hchild)) {
5847                 redisplay_windows(w->hchild, skip_selected);
5848                 return;
5849         }
5850
5851         /* Is this window the selected window on its frame? */
5852         selected_in_its_frame = (w == XWINDOW(FRAME_SELECTED_WINDOW(f)));
5853         selected_globally =
5854             selected_in_its_frame &&
5855             EQ(DEVICE_CONSOLE(d), Vselected_console) &&
5856             XDEVICE(CONSOLE_SELECTED_DEVICE(XCONSOLE(DEVICE_CONSOLE(d)))) == d
5857             && XFRAME(DEVICE_SELECTED_FRAME(d)) == f;
5858         if (skip_selected && selected_in_its_frame)
5859                 return;
5860
5861         /* It is possible that the window is not fully initialized yet. */
5862         if (NILP(w->buffer))
5863                 return;
5864
5865         if (MINI_WINDOW_P(w) && echo_area_active(f)) {
5866                 w->buffer = the_buffer = Vecho_area_buffer;
5867                 echo_active = 1;
5868         }
5869
5870         b = XBUFFER(w->buffer);
5871
5872         if (echo_active) {
5873                 old_pointm = selected_globally ? BUF_PT(b)
5874                     : marker_position(w->pointm[CURRENT_DISP]);
5875                 pointm = 1;
5876         } else {
5877                 if (selected_globally) {
5878                         pointm = BUF_PT(b);
5879                 } else {
5880                         pointm = marker_position(w->pointm[CURRENT_DISP]);
5881
5882                         if (pointm < BUF_BEGV(b))
5883                                 pointm = BUF_BEGV(b);
5884                         else if (pointm > BUF_ZV(b))
5885                                 pointm = BUF_ZV(b);
5886                 }
5887         }
5888         Fset_marker(w->pointm[DESIRED_DISP], make_int(pointm), the_buffer);
5889
5890         /* If the buffer has changed we have to invalidate all of our face
5891            cache elements. */
5892         if ((!echo_active && b != window_display_buffer(w))
5893             || !Dynarr_length(w->face_cachels)
5894             || f->faces_changed)
5895                 reset_face_cachels(w);
5896         else
5897                 mark_face_cachels_as_not_updated(w);
5898
5899         /* Ditto the glyph cache elements, although we do *not* invalidate
5900            the cache purely because glyphs have changed - this is now
5901            handled by the dirty flag. */
5902         if ((!echo_active && b != window_display_buffer(w))
5903             || !Dynarr_length(w->glyph_cachels) || f->faces_changed)
5904                 reset_glyph_cachels(w);
5905         else
5906                 mark_glyph_cachels_as_not_updated(w);
5907
5908         /* If the marker's buffer is not the window's buffer, then we need
5909            to find a new starting position. */
5910         if (!MINI_WINDOW_P(w)
5911             && !EQ(Fmarker_buffer(w->start[CURRENT_DISP]), w->buffer)) {
5912                 startp =
5913                     regenerate_window_point_center(w, pointm, DESIRED_DISP);
5914
5915                 goto regeneration_done;
5916         }
5917
5918         if (echo_active) {
5919                 old_startp = marker_position(w->start[CURRENT_DISP]);
5920                 startp = 1;
5921         } else {
5922                 startp = marker_position(w->start[CURRENT_DISP]);
5923                 if (startp < BUF_BEGV(b))
5924                         startp = BUF_BEGV(b);
5925                 else if (startp > BUF_ZV(b))
5926                         startp = BUF_ZV(b);
5927         }
5928         Fset_marker(w->start[DESIRED_DISP], make_int(startp), the_buffer);
5929
5930         truncation_changed = (find_window_mirror(w)->truncate_win !=
5931                               window_truncation_on(w));
5932
5933         /* If w->force_start is set, then some function set w->start and we
5934            should display from there and change point, if necessary, to
5935            ensure that it is visible. */
5936         if (w->force_start || inactive_minibuffer) {
5937                 w->force_start = 0;
5938                 w->last_modified[DESIRED_DISP] = Qzero;
5939                 w->last_facechange[DESIRED_DISP] = Qzero;
5940
5941                 regenerate_window(w, startp, pointm, DESIRED_DISP);
5942
5943                 if (!point_visible(w, pointm, DESIRED_DISP)
5944                     && !inactive_minibuffer) {
5945                         pointm = point_at_center(w, DESIRED_DISP, 0, 0);
5946
5947                         if (selected_globally)
5948                                 BUF_SET_PT(b, pointm);
5949
5950                         Fset_marker(w->pointm[DESIRED_DISP], make_int(pointm),
5951                                     the_buffer);
5952
5953                         /* #### BUFU amounts of overkill just to get the cursor
5954                            location marked properly.  FIX ME FIX ME FIX ME */
5955                         regenerate_window(w, startp, pointm, DESIRED_DISP);
5956                 }
5957
5958                 goto regeneration_done;
5959         }
5960
5961         /* If nothing has changed since the last redisplay, then we just
5962            need to make sure that point is still visible. */
5963         if (XINT(w->last_modified[CURRENT_DISP]) >= BUF_MODIFF(b)
5964             && XINT(w->last_facechange[CURRENT_DISP]) >= BUF_FACECHANGE(b)
5965             && pointm >= startp
5966             /* This check is to make sure we restore the minibuffer after a
5967                temporary change to the echo area. */
5968             && !(MINI_WINDOW_P(w) && f->buffers_changed)
5969             && !f->frame_changed && !truncation_changed
5970             /* check whether start is really at the beginning of a line  GE */
5971             && (!w->start_at_line_beg || beginning_of_line_p(b, startp))
5972             ) {
5973                 /* Check if the cursor has actually moved. */
5974                 if (EQ(Fmarker_buffer(w->last_point[CURRENT_DISP]), w->buffer)
5975                     && pointm == marker_position(w->last_point[CURRENT_DISP])
5976                     && selected_globally
5977                     && !w->windows_changed
5978                     && !f->clip_changed
5979                     && !f->extents_changed
5980                     && !f->faces_changed
5981                     && !f->glyphs_changed && !f->subwindows_changed
5982                     /*      && !f->subwindows_state_changed */
5983                     && !f->point_changed && !f->windows_structure_changed) {
5984                         /* If not, we're done. */
5985                         if (f->modeline_changed)
5986                                 regenerate_modeline(w);
5987
5988                         skip_output = 1;
5989                         goto regeneration_done;
5990                 } else {
5991                         /* If the new point is visible in the redisplay structures,
5992                            then let the output update routines handle it, otherwise
5993                            do things the hard way. */
5994                         if (!w->windows_changed
5995                             && !f->clip_changed
5996                             && !f->extents_changed
5997                             && !f->faces_changed
5998                             && !f->glyphs_changed && !f->subwindows_changed
5999                             /*              && !f->subwindows_state_changed */
6000                             && !f->windows_structure_changed) {
6001                                 if (point_visible(w, pointm, CURRENT_DISP)
6002                                     && w->last_point_x[CURRENT_DISP] != -1
6003                                     && w->last_point_y[CURRENT_DISP] != -1) {
6004                                         if (redisplay_move_cursor
6005                                             (w, pointm, FRAME_TTY_P(f))) {
6006                                                 /* Always regenerate in case it is displaying
6007                                                    the current line or column. */
6008                                                 regenerate_modeline(w);
6009
6010                                                 skip_output = 1;
6011                                                 goto regeneration_done;
6012                                         }
6013                                 } else if (!selected_in_its_frame
6014                                            && !f->point_changed) {
6015                                         if (f->modeline_changed)
6016                                                 regenerate_modeline(w);
6017
6018                                         skip_output = 1;
6019                                         goto regeneration_done;
6020                                 }
6021                         }
6022
6023                         /* If we weren't able to take the shortcut method, then use
6024                            the brute force method. */
6025                         regenerate_window(w, startp, pointm, DESIRED_DISP);
6026
6027                         if (point_visible(w, pointm, DESIRED_DISP))
6028                                 goto regeneration_done;
6029                 }
6030         }
6031
6032         /* Check if the starting point is no longer at the beginning of a
6033            line, in which case find a new starting point.  We also recenter
6034            if our start position is equal to point-max.  Otherwise we'll end
6035            up with a blank window. */
6036         else if (((w->start_at_line_beg || MINI_WINDOW_P(w))
6037                   && !(startp == BUF_BEGV(b)
6038                        || BUF_FETCH_CHAR(b, startp - 1) == '\n'))
6039                  || (pointm == startp &&
6040                      EQ(Fmarker_buffer(w->last_start[CURRENT_DISP]), w->buffer)
6041                      && startp < marker_position(w->last_start[CURRENT_DISP]))
6042                  || (startp == BUF_ZV(b))) {
6043                 startp =
6044                     regenerate_window_point_center(w, pointm, DESIRED_DISP);
6045
6046                 goto regeneration_done;
6047         }
6048         /* See if we can update the data structures locally based on
6049            knowledge of what changed in the buffer. */
6050         else if (!w->windows_changed
6051                  && !f->clip_changed
6052                  && !f->faces_changed
6053                  && !f->glyphs_changed && !f->subwindows_changed
6054                  /*      && !f->subwindows_state_changed */
6055                  && !f->windows_structure_changed
6056                  && !f->frame_changed
6057                  && !truncation_changed
6058                  && pointm >= startp
6059                  && regenerate_window_incrementally(w, startp, pointm)) {
6060                 if (f->modeline_changed
6061                     || XINT(w->last_modified[CURRENT_DISP]) < BUF_MODIFF(b)
6062                     || XINT(w->last_facechange[CURRENT_DISP]) <
6063                     BUF_FACECHANGE(b))
6064                         regenerate_modeline(w);
6065
6066                 skip_output = 1;
6067                 goto regeneration_done;
6068         }
6069         /* #### This is where a check for structure based scrolling would go. */
6070         /* If all else fails, try just regenerating and see what happens. */
6071         else {
6072                 regenerate_window(w, startp, pointm, DESIRED_DISP);
6073
6074                 if (point_visible(w, pointm, DESIRED_DISP))
6075                         goto regeneration_done;
6076         }
6077
6078         /* We still haven't gotten the window regenerated with point
6079            visible.  Next we try scrolling a little and see if point comes
6080            back onto the screen. */
6081         if (scroll_step > 0) {
6082                 int scrolled = scroll_conservatively;
6083                 for (; scrolled >= 0; scrolled -= scroll_step) {
6084                         startp = vmotion(w, startp,
6085                                          (pointm <
6086                                           startp) ? -scroll_step : scroll_step,
6087                                          0);
6088                         regenerate_window(w, startp, pointm, DESIRED_DISP);
6089
6090                         if (point_visible(w, pointm, DESIRED_DISP))
6091                                 goto regeneration_done;
6092                 }
6093         }
6094
6095         /* We still haven't managed to get the screen drawn with point on
6096            the screen, so just center it and be done with it. */
6097         startp = regenerate_window_point_center(w, pointm, DESIRED_DISP);
6098
6099       regeneration_done:
6100
6101         /* If the window's frame is changed then reset the current display
6102            lines in order to force a full repaint. */
6103         if (f->frame_changed) {
6104                 display_line_dynarr *cla =
6105                     window_display_lines(w, CURRENT_DISP);
6106
6107                 Dynarr_reset(cla);
6108         }
6109
6110         /* Must do this before calling redisplay_output_window because it
6111            sets some markers on the window. */
6112         if (echo_active) {
6113                 w->buffer = old_buffer;
6114                 Fset_marker(w->pointm[DESIRED_DISP], make_int(old_pointm),
6115                             old_buffer);
6116                 Fset_marker(w->start[DESIRED_DISP], make_int(old_startp),
6117                             old_buffer);
6118         }
6119
6120         /* These also have to be set before calling redisplay_output_window
6121            since it sets the CURRENT_DISP values based on them. */
6122         w->last_modified[DESIRED_DISP] = make_int(BUF_MODIFF(b));
6123         w->last_facechange[DESIRED_DISP] = make_int(BUF_FACECHANGE(b));
6124         Fset_marker(w->last_start[DESIRED_DISP], make_int(startp), w->buffer);
6125         Fset_marker(w->last_point[DESIRED_DISP], make_int(pointm), w->buffer);
6126
6127         if (!skip_output) {
6128                 Bufpos start = marker_position(w->start[DESIRED_DISP]);
6129                 Bufpos end = (w->window_end_pos[DESIRED_DISP] == -1 ? BUF_ZV(b)
6130                               : BUF_Z(b) - w->window_end_pos[DESIRED_DISP] - 1);
6131                 /* Don't pollute the cache if not sure if we are correct */
6132                 if (w->start_at_line_beg)
6133                         update_line_start_cache(w, start, end, pointm, 1);
6134                 redisplay_output_window(w);
6135                 /*
6136                  * If we just displayed the echo area, the line start cache is
6137                  * no longer valid, because the minibuffer window is associated
6138                  * with the window now.
6139                  */
6140                 if (echo_active)
6141                         w->line_cache_last_updated = make_int(-1);
6142         }
6143
6144         /* #### This should be dependent on face changes and will need to be
6145            somewhere else once tty updates occur on a per-frame basis. */
6146         mark_face_cachels_as_clean(w);
6147
6148         /* The glyph cachels only get dirty if someone changed something.
6149            Since redisplay has now effectively ended we can reset the dirty
6150            flag since everything must be up-to-date. */
6151         if (glyphs_changed)
6152                 mark_glyph_cachels_as_clean(w);
6153
6154         w->windows_changed = 0;
6155 }
6156
6157 /* Call buffer_reset_changes for all buffers present in any window
6158    currently visible in all frames on all devices.  #### There has to
6159    be a better way to do this. */
6160
6161 static int reset_buffer_changes_mapfun(struct window *w, void *ignored_closure)
6162 {
6163         buffer_reset_changes(XBUFFER(w->buffer));
6164         return 0;
6165 }
6166
6167 static void reset_buffer_changes(void)
6168 {
6169         Lisp_Object frmcons, devcons, concons;
6170
6171         FRAME_LOOP_NO_BREAK(frmcons, devcons, concons) {
6172                 struct frame *f = XFRAME(XCAR(frmcons));
6173
6174                 if (FRAME_REPAINT_P(f))
6175                         map_windows(f, reset_buffer_changes_mapfun, 0);
6176         }
6177 }
6178
6179 /* Ensure that all windows underneath the given window in the window
6180    hierarchy are correctly displayed. */
6181
6182 static void redisplay_windows(Lisp_Object window, int skip_selected)
6183 {
6184         for (; !NILP(window); window = XWINDOW(window)->next) {
6185                 redisplay_window(window, skip_selected);
6186         }
6187 }
6188
6189 static int call_redisplay_end_triggers(struct window *w, void *closure)
6190 {
6191         Bufpos lrpos = w->last_redisplay_pos;
6192         w->last_redisplay_pos = 0;
6193         if (!NILP(w->buffer)
6194             && !NILP(w->redisplay_end_trigger)
6195             && lrpos > 0) {
6196                 Bufpos pos;
6197
6198                 if (MARKERP(w->redisplay_end_trigger)
6199                     && XMARKER(w->redisplay_end_trigger)->buffer != 0)
6200                         pos = marker_position(w->redisplay_end_trigger);
6201                 else if (INTP(w->redisplay_end_trigger))
6202                         pos = XINT(w->redisplay_end_trigger);
6203                 else {
6204                         w->redisplay_end_trigger = Qnil;
6205                         return 0;
6206                 }
6207
6208                 if (lrpos >= pos) {
6209                         Lisp_Object window;
6210                         XSETWINDOW(window, w);
6211                         va_run_hook_with_args_in_buffer(XBUFFER(w->buffer),
6212                                                         Qredisplay_end_trigger_functions,
6213                                                         2, window,
6214                                                         w->
6215                                                         redisplay_end_trigger);
6216                         w->redisplay_end_trigger = Qnil;
6217                 }
6218         }
6219
6220         return 0;
6221 }
6222
6223 /* Ensure that all windows on the given frame are correctly displayed. */
6224
6225 int redisplay_frame(struct frame *f, int preemption_check)
6226 {
6227         struct device *d = XDEVICE(f->device);
6228
6229         if (preemption_check
6230             && !DEVICE_IMPL_FLAG(d, XDEVIMPF_DONT_PREEMPT_REDISPLAY)) {
6231                 /* The preemption check itself takes a lot of time,
6232                    so normally don't do it here.  We do it if called
6233                    from Lisp, though (`redisplay-frame'). */
6234                 int preempted;
6235
6236                 REDISPLAY_PREEMPTION_CHECK;
6237                 if (preempted)
6238                         return 1;
6239         }
6240
6241         if (!internal_equal(f->old_buffer_alist, f->buffer_alist, 0)) {
6242                 Lisp_Object frame;
6243
6244                 f->old_buffer_alist = Freplace_list(f->old_buffer_alist,
6245                                                     f->buffer_alist);
6246                 XSETFRAME(frame, f);
6247                 va_run_hook_with_args(Qbuffer_list_changed_hook, 1, frame);
6248         }
6249
6250         /* Before we put a hold on frame size changes, attempt to process
6251            any which are already pending. */
6252         if (f->size_change_pending)
6253                 change_frame_size(f, f->new_height, f->new_width, 0);
6254
6255         /* If frame size might need to be changed, due to changed size
6256            of toolbars, scrollbars etc, change it now */
6257         if (f->size_slipped) {
6258                 adjust_frame_size(f);
6259                 assert(!f->size_slipped);
6260         }
6261
6262         /* The menubar, toolbar, and icon updates must be done before
6263            hold_frame_size_changes is called and we are officially
6264            'in_display'.  They may eval lisp code which may call Fsignal.
6265            If in_display is set Fsignal will abort. */
6266
6267 #ifdef HAVE_MENUBARS
6268         /* Update the menubar.  It is done first since it could change
6269            the menubar's visibility.  This way we avoid having flashing
6270            caused by an Expose event generated by the visibility change
6271            being handled. */
6272         update_frame_menubars(f);
6273 #endif                          /* HAVE_MENUBARS */
6274 #ifdef HAVE_TOOLBARS
6275         /* Update the toolbars geometry. We don't update the toolbars
6276            themselves at this point since the space they are trying to
6277            occupy may currently by occupied by gutter elements. Instead we
6278            update the geometry, then update the gutter geometry, then update
6279            the gutters - which will cause mapped windows to be repositioned
6280            - and finally update the toolbars. */
6281         update_frame_toolbars_geometry(f);
6282 #endif                          /* HAVE_TOOLBARS */
6283         /* Gutter update proper has to be done inside display when no frame
6284            size changes can occur, thus we separately update the gutter
6285            geometry here if it needs it. */
6286         update_frame_gutter_geometry(f);
6287
6288         /* If we clear the frame we have to force its contents to be redrawn. */
6289         if (f->clear)
6290                 f->frame_changed = 1;
6291
6292         /* Invalidate the subwindow caches. We use subwindows_changed here
6293            to cause subwindows to get instantiated. This is because
6294            subwindows_state_changed is less strict - dealing with things
6295            like the clicked state of button. We have to do this before
6296            redisplaying the gutters as subwindows get unmapped in the
6297            process. */
6298         if (f->frame_changed)
6299                 reset_frame_subwindow_instance_cache(f);
6300
6301         if (f->frame_changed || f->subwindows_changed) {
6302                 /* we have to do this so the gutter gets regenerated. */
6303                 reset_gutter_display_lines(f);
6304         }
6305
6306         hold_frame_size_changes();
6307
6308         /* ----------------- BEGIN CRITICAL REDISPLAY SECTION ---------------- */
6309         /* Within this section, we are defenseless and assume that the
6310            following cannot happen:
6311
6312            1) garbage collection
6313            2) Lisp code evaluation
6314            3) frame size changes
6315
6316            We ensure (3) by calling hold_frame_size_changes(), which
6317            will cause any pending frame size changes to get put on hold
6318            till after the end of the critical section.  (1) follows
6319            automatically if (2) is met.  #### Unfortunately, there are
6320            some places where Lisp code can be called within this section.
6321            We need to remove them.
6322
6323            If Fsignal() is called during this critical section, we
6324            will abort().
6325
6326            If garbage collection is called during this critical section,
6327            we simply return. #### We should abort instead.
6328
6329            #### If a frame-size change does occur we should probably
6330            actually be preempting redisplay. */
6331
6332         MAYBE_DEVMETH(d, frame_output_begin, (f));
6333
6334         /* Erase the frame before outputting its contents. */
6335         if (f->clear) {
6336                 MAYBE_DEVMETH(d, clear_frame, (f));
6337         }
6338
6339         /* We can now update the gutters, safe in the knowledge that our
6340            efforts won't get undone. */
6341
6342         /* This can call lisp, but redisplay is protected by binding
6343            inhibit_quit.  More importantly the code involving display lines
6344            *assumes* that GC will not happen and so does not GCPRO
6345            anything. Since we use this code the whole time with the gutters
6346            we cannot allow GC to happen when manipulating the gutters. */
6347         update_frame_gutters(f);
6348
6349         /* Do the selected window first. */
6350         redisplay_window(FRAME_SELECTED_WINDOW(f), 0);
6351
6352         /* Then do the rest. */
6353         redisplay_windows(f->root_window, 1);
6354
6355         MAYBE_DEVMETH(d, frame_output_end, (f));
6356
6357         update_frame_title(f);
6358
6359 #ifdef HAVE_TOOLBARS
6360         /* Finally update the toolbars. It seems its possible to get in a
6361            cycle between updating the gutter and the toolbars. Basically we
6362            want to end up with both being up-to-date and this doesn't seem
6363            possible in a single pass. */
6364         update_frame_toolbars(f);
6365 #endif                          /* HAVE_TOOLBARS */
6366
6367         CLASS_RESET_CHANGED_FLAGS(f);
6368         f->window_face_cache_reset = 0;
6369         f->echo_area_garbaged = 0;
6370         f->clear = 0;
6371
6372         if (!f->size_change_pending)
6373                 f->size_changed = 0;
6374
6375         /* ----------------- END CRITICAL REDISPLAY SECTION ---------------- */
6376
6377         /* Allow frame size changes to occur again.
6378
6379            #### what happens if changes to other frames happen? */
6380         unhold_one_frame_size_changes(f);
6381
6382         map_windows(f, call_redisplay_end_triggers, 0);
6383         return 0;
6384 }
6385
6386 /* Ensure that all frames on the given device are correctly displayed.
6387    If AUTOMATIC is non-zero, and the device implementation indicates
6388    no automatic redisplay, as printers do, then the device is not
6389    redisplayed. AUTOMATIC is set to zero when called from lisp
6390    functions (redraw-device) and (redisplay-device), and to non-zero
6391    when called from "lazy" redisplay();
6392 */
6393
6394 static int redisplay_device(struct device *d, int automatic)
6395 {
6396         Lisp_Object frame, frmcons;
6397         int size_change_failed = 0;
6398         struct frame *f;
6399
6400         if (automatic && DEVICE_IMPL_FLAG(d, XDEVIMPF_NO_AUTO_REDISPLAY))
6401                 return 0;
6402
6403         if (DEVICE_STREAM_P(d)) /* nothing to do */
6404                 return 0;
6405
6406         /* It is possible that redisplay has been called before the
6407            device is fully initialized, or that the console implementation
6408            allows frameless devices.  If so then continue with the next
6409            device. */
6410         if (NILP(DEVICE_SELECTED_FRAME(d)))
6411                 return 0;
6412
6413         if (!DEVICE_IMPL_FLAG(d, XDEVIMPF_DONT_PREEMPT_REDISPLAY)) {
6414                 int preempted;
6415                 REDISPLAY_PREEMPTION_CHECK;
6416                 if (preempted)
6417                         return 1;
6418         }
6419
6420         /* Always do the selected frame first. */
6421         frame = DEVICE_SELECTED_FRAME(d);
6422
6423         f = XFRAME(frame);
6424
6425         if (f->icon_changed || f->windows_changed)
6426                 update_frame_icon(f);
6427
6428         if (FRAME_REPAINT_P(f)) {
6429                 if (CLASS_REDISPLAY_FLAGS_CHANGEDP(f)) {
6430                         int preempted = redisplay_frame(f, 0);
6431                         if (preempted)
6432                                 return 1;
6433                 }
6434
6435                 /* If the frame redisplay did not get preempted, then this flag
6436                    should have gotten set to 0.  It might be possible for that
6437                    not to happen if a size change event were to occur at an odd
6438                    time.  To make sure we don't miss anything we simply don't
6439                    reset the top level flags until the condition ends up being
6440                    in the right state. */
6441                 if (f->size_changed)
6442                         size_change_failed = 1;
6443         }
6444
6445         DEVICE_FRAME_LOOP(frmcons, d) {
6446                 f = XFRAME(XCAR(frmcons));
6447
6448                 if (f == XFRAME(DEVICE_SELECTED_FRAME(d)))
6449                         continue;
6450
6451                 if (f->icon_changed || f->windows_changed)
6452                         update_frame_icon(f);
6453
6454                 if (FRAME_REPAINT_P(f)) {
6455                         if (CLASS_REDISPLAY_FLAGS_CHANGEDP(f)) {
6456                                 int preempted = redisplay_frame(f, 0);
6457                                 if (preempted)
6458                                         return 1;
6459                         }
6460
6461                         if (f->size_change_pending)
6462                                 size_change_failed = 1;
6463                 }
6464         }
6465
6466         /* If we get here then we redisplayed all of our frames without
6467            getting preempted so mark ourselves as clean. */
6468         CLASS_RESET_CHANGED_FLAGS(d);
6469
6470         if (!size_change_failed)
6471                 d->size_changed = 0;
6472
6473         return 0;
6474 }
6475
6476 static Lisp_Object restore_profiling_redisplay_flag(Lisp_Object val)
6477 {
6478         profiling_redisplay_flag = XINT(val);
6479         return Qnil;
6480 }
6481
6482 /* Ensure that all windows on all frames on all devices are displaying
6483    the current contents of their respective buffers. */
6484
6485 static void redisplay_without_hooks(void)
6486 {
6487         Lisp_Object devcons, concons;
6488         int size_change_failed = 0;
6489         int count = specpdl_depth();
6490
6491         if (profiling_active) {
6492                 record_unwind_protect(restore_profiling_redisplay_flag,
6493                                       make_int(profiling_redisplay_flag));
6494                 profiling_redisplay_flag = 1;
6495         }
6496
6497         if (asynch_device_change_pending)
6498                 handle_asynch_device_change();
6499
6500         if (!GLOBAL_REDISPLAY_FLAGS_CHANGEDP &&
6501             !disable_preemption && preemption_count < max_preempts)
6502                 goto done;
6503
6504         DEVICE_LOOP_NO_BREAK(devcons, concons) {
6505                 struct device *d = XDEVICE(XCAR(devcons));
6506                 int preempted;
6507
6508                 if (CLASS_REDISPLAY_FLAGS_CHANGEDP(d)) {
6509                         preempted = redisplay_device(d, 1);
6510
6511                         if (preempted) {
6512                                 preemption_count++;
6513                                 RESET_CHANGED_SET_FLAGS;
6514                                 goto done;
6515                         }
6516
6517                         /* See comment in redisplay_device. */
6518                         if (d->size_changed)
6519                                 size_change_failed = 1;
6520                 }
6521         }
6522         preemption_count = 0;
6523
6524         /* Mark redisplay as accurate */
6525         GLOBAL_RESET_CHANGED_FLAGS;
6526         RESET_CHANGED_SET_FLAGS;
6527
6528         if (faces_changed) {
6529                 mark_all_faces_as_clean();
6530                 faces_changed = 0;
6531         }
6532
6533         if (!size_change_failed)
6534                 size_changed = 0;
6535
6536         reset_buffer_changes();
6537
6538       done:
6539         unbind_to(count, Qnil);
6540 }
6541
6542 void redisplay(void)
6543 {
6544         if (last_display_warning_tick != display_warning_tick &&
6545             !inhibit_warning_display) {
6546                 /* If an error occurs during this function, oh well.
6547                    If we report another warning, we could get stuck in an
6548                    infinite loop reporting warnings. */
6549                 call0_trapping_errors(0, Qdisplay_warning_buffer);
6550                 last_display_warning_tick = display_warning_tick;
6551         }
6552         /* The run_hook_trapping_errors functions are smart enough not
6553            to do any evalling if the hook function is empty, so there
6554            should not be any significant time loss.  All places in the
6555            C code that call redisplay() are prepared to handle GCing,
6556            so we should be OK. */
6557 #ifndef INHIBIT_REDISPLAY_HOOKS
6558         run_hook_trapping_errors("Error in pre-redisplay-hook",
6559                                  Qpre_redisplay_hook);
6560 #endif                          /* INHIBIT_REDISPLAY_HOOKS */
6561
6562         redisplay_without_hooks();
6563
6564 #ifndef INHIBIT_REDISPLAY_HOOKS
6565         run_hook_trapping_errors("Error in post-redisplay-hook",
6566                                  Qpost_redisplay_hook);
6567 #endif                          /* INHIBIT_REDISPLAY_HOOKS */
6568 }
6569
6570 static char window_line_number_buf[32];
6571
6572 /* Efficiently determine the window line number, and return a pointer
6573    to its printed representation.  Do this regardless of whether
6574    line-number-mode is on.  The first line in the buffer is counted as
6575    1.  If narrowing is in effect, the lines are counted from the
6576    beginning of the visible portion of the buffer.  */
6577 static char *window_line_number(struct window *w, int type)
6578 {
6579         struct device *d = XDEVICE(XFRAME(w->frame)->device);
6580         struct buffer *b = XBUFFER(w->buffer);
6581         /* Be careful in the order of these tests. The first clause will
6582            fail if DEVICE_SELECTED_FRAME == Qnil (since w->frame cannot be).
6583            This can occur when the frame title is computed really early */
6584         Bufpos pos =
6585             ((EQ(DEVICE_SELECTED_FRAME(d), w->frame) &&
6586               (w == XWINDOW(FRAME_SELECTED_WINDOW(device_selected_frame(d)))) &&
6587               EQ(DEVICE_CONSOLE(d), Vselected_console) &&
6588               XDEVICE(CONSOLE_SELECTED_DEVICE(XCONSOLE(DEVICE_CONSOLE(d)))) ==
6589               d)
6590              ? BUF_PT(b)
6591              : marker_position(w->pointm[type]));
6592         EMACS_INT line;
6593
6594         line = buffer_line_number(b, pos, 1);
6595
6596         long_to_string(window_line_number_buf, line + 1, sizeof(window_line_number_buf));
6597
6598         return window_line_number_buf;
6599 }
6600
6601 /* Given a character representing an object in a modeline
6602    specification, return a string (stored into the global array
6603    `mode_spec_bufbyte_string') with the information that object
6604    represents.
6605
6606    This function is largely unchanged from previous versions of the
6607    redisplay engine.
6608
6609    Warning! This code is also used for frame titles and can be called
6610    very early in the device/frame update process!  JV
6611 */
6612
6613 static void decode_mode_spec(struct window *w, Emchar spec, int type)
6614 {
6615         Lisp_Object obj = Qnil;
6616         const char *str = NULL;
6617         struct buffer *b = XBUFFER(w->buffer);
6618
6619         Dynarr_reset(mode_spec_bufbyte_string);
6620
6621         switch (spec) {
6622                 /* print buffer name */
6623         case 'b':
6624                 obj = b->name;
6625                 break;
6626
6627                 /* print visited file name */
6628         case 'f':
6629                 obj = b->filename;
6630                 break;
6631
6632                 /* print the current column */
6633         case 'c': {
6634                 Lisp_Object tmp = Fselected_window(Qnil);
6635                 Bufpos pt = (w == XWINDOW(tmp))
6636                         ? BUF_PT(b)
6637                         : marker_position(w->pointm[type]);
6638                 int col =
6639                         column_at_point(b, pt,
6640                                         1) + !!column_number_start_at_one;
6641                 char buf[sizeof(long)*3+1];
6642
6643                 long_to_string(buf, col, sizeof(buf));
6644
6645                 Dynarr_add_many(mode_spec_bufbyte_string,
6646                                 (const Bufbyte *)buf, strlen(buf));
6647
6648                 goto decode_mode_spec_done;
6649         }
6650                 /* print the file coding system */
6651         case 'C': {
6652 #ifdef FILE_CODING
6653                 Lisp_Object codesys = b->buffer_file_coding_system;
6654                 /* Be very careful here not to get an error. */
6655                 if (NILP(codesys) || SYMBOLP(codesys)
6656                     || CODING_SYSTEMP(codesys)) {
6657                         codesys = Ffind_coding_system(codesys);
6658                         if (CODING_SYSTEMP(codesys))
6659                                 obj = XCODING_SYSTEM_MNEMONIC(codesys);
6660                 }
6661 #endif                          /* FILE_CODING */
6662         }
6663                 break;
6664
6665                 /* print the current line number */
6666         case 'l':
6667                 str = window_line_number(w, type);
6668                 break;
6669
6670                 /* print value of mode-name (obsolete) */
6671         case 'm':
6672                 obj = b->mode_name;
6673                 break;
6674
6675                 /* print hyphen and frame number, if != 1 */
6676         case 'N': {
6677 #ifdef HAVE_TTY
6678                 struct frame *f = XFRAME(w->frame);
6679                 if (FRAME_TTY_P(f) && f->order_count > 1
6680                     && f->order_count <= 99999999) {
6681                         /* Naughty, naughty */
6682                         const size_t order_strmax = sizeof(f->order_count)*3+2;
6683                         char *writable_str = alloca_array(char, order_strmax);
6684                         int n = snprintf(writable_str, order_strmax, "-%d", f->order_count);
6685                         assert(n>=0 && (size_t)n < order_strmax);
6686                         str = writable_str;
6687                 }
6688 #endif                          /* HAVE_TTY */
6689         }
6690                 break;
6691
6692                 /* print Narrow if appropriate */
6693         case 'n':
6694                 if (BUF_BEGV(b) > BUF_BEG(b)
6695                     || BUF_ZV(b) < BUF_Z(b))
6696                         str = " Narrow";
6697                 break;
6698
6699                 /* print %, * or hyphen, if buffer is read-only, modified or
6700                    neither */
6701         case '*':
6702                 str = (!NILP(b->read_only)
6703                        ? "%" : ((BUF_MODIFF(b) > BUF_SAVE_MODIFF(b))
6704                                 ? "*" : "-"));
6705                 break;
6706
6707                 /* print * or hyphen -- XEmacs change to allow a buffer to be
6708                    read-only but still indicate whether it is modified. */
6709         case '+':
6710                 str = ((BUF_MODIFF(b) > BUF_SAVE_MODIFF(b))
6711                        ? "*" : (!NILP(b->read_only)
6712                                 ? "%" : "-"));
6713                 break;
6714
6715                 /* #### defined in 19.29 decode_mode_spec, but not in
6716                    modeline-format doc string. */
6717                 /* This differs from %* in that it ignores read-only-ness. */
6718         case '&':
6719                 str = ((BUF_MODIFF(b) > BUF_SAVE_MODIFF(b))
6720                        ? "*" : "-");
6721                 break;
6722
6723                 /* print process status */
6724         case 's':
6725                 obj = Fget_buffer_process(w->buffer);
6726                 if (NILP(obj))
6727                         str = GETTEXT("no process");
6728                 else
6729                         obj = Fsymbol_name(Fprocess_status(obj));
6730                 break;
6731
6732                 /* Print name of selected frame.  */
6733         case 'S':
6734                 obj = XFRAME(w->frame)->name;
6735                 break;
6736
6737                 /* indicate TEXT or BINARY */
6738         case 't':
6739                 /* #### NT does not use this any more. Now what? */
6740                 str = "T";
6741                 break;
6742
6743                 /* print percent of buffer above top of window, or Top, Bot or
6744                    All */
6745         case 'p': {
6746                 Bufpos pos = marker_position(w->start[type]);
6747
6748                 /* This had better be while the desired lines are being done. */
6749                 if (w->window_end_pos[type] <= BUF_Z(b) - BUF_ZV(b)) {
6750                         if (pos <= BUF_BEGV(b))
6751                                 str = "All";
6752                         else
6753                                 str = "Bottom";
6754                 } else if (pos <= BUF_BEGV(b)) {
6755                         str = "Top";
6756                 } else {
6757                         /* This hard limit is ok since the string it will hold
6758                            has a fixed maximum length of 3.  But just to be
6759                            safe... */
6760                         char buf[sizeof(long)*3+4];
6761                         int n;
6762                         Charcount chars = pos - BUF_BEGV(b);
6763                         Charcount total = BUF_ZV(b) - BUF_BEGV(b);
6764
6765                         /* Avoid overflow on big buffers */
6766                         int percent = total > LONG_MAX / 200 ?
6767                                 (chars + total / 200) / (total / 100) :
6768                                 (chars * 100 + total / 2) / total;
6769
6770                         /* We can't normally display a 3-digit number, so get us
6771                            a 2-digit number that is close. */
6772                         if (percent == 100)
6773                                 percent = 99;
6774
6775                         n = snprintf(buf, sizeof(buf), "%d%%", percent);
6776                         assert(n>=0 && (size_t)n < sizeof(buf));
6777                         Dynarr_add_many(mode_spec_bufbyte_string,
6778                                         (Bufbyte *) buf, strlen(buf));
6779
6780                         goto decode_mode_spec_done;
6781                 }
6782                 break;
6783         }
6784
6785                 /* print percent of buffer above bottom of window, perhaps plus
6786                    Top, or print Bottom or All */
6787         case 'P': {
6788                 Bufpos toppos = marker_position(w->start[type]);
6789                 Bufpos botpos = BUF_Z(b) - w->window_end_pos[type];
6790
6791                 /* botpos is only accurate as of the last redisplay, so we can
6792                    only treat it as a hint.  In particular, after erase-buffer,
6793                    botpos may be negative. */
6794                 if (botpos < toppos)
6795                         botpos = toppos;
6796
6797                 if (botpos >= BUF_ZV(b)) {
6798                         if (toppos <= BUF_BEGV(b))
6799                                 str = "All";
6800                         else
6801                                 str = "Bottom";
6802                 } else {
6803                         /* This hard limit is ok since the string it will hold
6804                            has a fixed maximum length of around 6.  But just to
6805                            be safe... */
6806                         char buf[sizeof(long)*3+6];
6807                         int n;
6808                         Charcount chars = botpos - BUF_BEGV(b);
6809                         Charcount total = BUF_ZV(b) - BUF_BEGV(b);
6810
6811                         /* Avoid overflow on big buffers */
6812                         int percent = total > LONG_MAX / 200 ?
6813                                 (chars + total / 200) / (total / 100) :
6814                                 (chars * 100 + total / 2) / max(total, 1);
6815
6816                         /* We can't normally display a 3-digit number, so get us
6817                            a 2-digit number that is close. */
6818                         if (percent == 100)
6819                                 percent = 99;
6820
6821                         if (toppos <= BUF_BEGV(b))
6822                                 n = snprintf(buf, sizeof(buf), "Top%d%%", percent);
6823                         else
6824                                 n = snprintf(buf, sizeof(buf), "%d%%", percent);
6825                         assert(n>=0 && (size_t)n < sizeof(buf));
6826                         Dynarr_add_many(mode_spec_bufbyte_string,
6827                                         (Bufbyte *) buf, strlen(buf));
6828
6829                         goto decode_mode_spec_done;
6830                 }
6831                 break;
6832         }
6833
6834                 /* print % */
6835         case '%':
6836                 str = "%";
6837                 break;
6838
6839                 /* print one [ for each recursive editing level. */
6840         case '[': {
6841                 int i;
6842
6843                 if (command_loop_level > 5) {
6844                         str = "[[[... ";
6845                         break;
6846                 }
6847
6848                 for (i = 0; i < command_loop_level; i++)
6849                         Dynarr_add(mode_spec_bufbyte_string, '[');
6850
6851                 goto decode_mode_spec_done;
6852         }
6853
6854                 /* print one ] for each recursive editing level. */
6855         case ']': {
6856                 int i;
6857
6858                 if (command_loop_level > 5) {
6859                         str = "...]]]";
6860                         break;
6861                 }
6862
6863                 for (i = 0; i < command_loop_level; i++)
6864                         Dynarr_add(mode_spec_bufbyte_string, ']');
6865
6866                 goto decode_mode_spec_done;
6867         }
6868
6869                 /* print infinitely many dashes -- handle at top level now */
6870         case '-':
6871                 break;
6872
6873         default:
6874                 break;
6875         }
6876
6877         if (STRINGP(obj)) {
6878                 Dynarr_add_many(mode_spec_bufbyte_string,
6879                                 XSTRING_DATA(obj), XSTRING_LENGTH(obj));
6880         } else if (str) {
6881                 Dynarr_add_many(mode_spec_bufbyte_string,
6882                                 (const Bufbyte*)str, strlen(str));
6883         }
6884
6885 decode_mode_spec_done:
6886         Dynarr_add(mode_spec_bufbyte_string, '\0');
6887         return;
6888 }
6889
6890 /* Given a display line, free all of its data structures. */
6891
6892 static void free_display_line(struct display_line *dl)
6893 {
6894         int block;
6895
6896         if (dl->display_blocks) {
6897                 for (block = 0; block < Dynarr_largest(dl->display_blocks);
6898                      block++) {
6899                         struct display_block *db =
6900                             Dynarr_atp(dl->display_blocks, block);
6901
6902                         Dynarr_free(db->runes);
6903                 }
6904
6905                 Dynarr_free(dl->display_blocks);
6906                 dl->display_blocks = NULL;
6907         }
6908
6909         if (dl->left_glyphs) {
6910                 Dynarr_free(dl->left_glyphs);
6911                 dl->left_glyphs = NULL;
6912         }
6913
6914         if (dl->right_glyphs) {
6915                 Dynarr_free(dl->right_glyphs);
6916                 dl->right_glyphs = NULL;
6917         }
6918 }
6919
6920 /* Given an array of display lines, free them and all data structures
6921    contained within them. */
6922
6923 void free_display_lines(display_line_dynarr * dla)
6924 {
6925         int line;
6926
6927         for (line = 0; line < Dynarr_largest(dla); line++) {
6928                 free_display_line(Dynarr_atp(dla, line));
6929         }
6930
6931         Dynarr_free(dla);
6932 }
6933
6934 /* Call internal free routine for each set of display lines. */
6935
6936 void free_display_structs(struct window_mirror *mir)
6937 {
6938         if (mir->current_display_lines) {
6939                 free_display_lines(mir->current_display_lines);
6940                 mir->current_display_lines = 0;
6941         }
6942
6943         if (mir->desired_display_lines) {
6944                 free_display_lines(mir->desired_display_lines);
6945                 mir->desired_display_lines = 0;
6946         }
6947 }
6948 \f
6949 static void mark_glyph_block_dynarr(glyph_block_dynarr * gba)
6950 {
6951         if (gba) {
6952                 glyph_block *gb = Dynarr_atp(gba, 0);
6953                 glyph_block *gb_last = Dynarr_atp(gba, Dynarr_length(gba));
6954
6955                 for (; gb < gb_last; gb++) {
6956                         if (!NILP(gb->glyph))
6957                                 mark_object(gb->glyph);
6958                         if (!NILP(gb->extent))
6959                                 mark_object(gb->extent);
6960                 }
6961         }
6962 }
6963
6964 /* See the comment in image_instantiate_cache_result as to why marking
6965    the glyph will also mark the image_instance. */
6966 void mark_redisplay_structs(display_line_dynarr * dla)
6967 {
6968         display_line *dl = Dynarr_atp(dla, 0);
6969         display_line *dl_last = Dynarr_atp(dla, Dynarr_length(dla));
6970
6971         for (; dl < dl_last; dl++) {
6972                 display_block_dynarr *dba = dl->display_blocks;
6973                 display_block *db = Dynarr_atp(dba, 0);
6974                 display_block *db_last = Dynarr_atp(dba, Dynarr_length(dba));
6975
6976                 for (; db < db_last; db++) {
6977                         rune_dynarr *ra = db->runes;
6978                         rune *r = Dynarr_atp(ra, 0);
6979                         rune *r_last = Dynarr_atp(ra, Dynarr_length(ra));
6980
6981                         for (; r < r_last; r++) {
6982                                 if (r->type == RUNE_DGLYPH) {
6983                                         if (!NILP(r->object.dglyph.glyph))
6984                                                 mark_object(r->object.dglyph.
6985                                                             glyph);
6986                                         if (!NILP(r->object.dglyph.extent))
6987                                                 mark_object(r->object.dglyph.
6988                                                             extent);
6989                                 }
6990                         }
6991                 }
6992
6993                 mark_glyph_block_dynarr(dl->left_glyphs);
6994                 mark_glyph_block_dynarr(dl->right_glyphs);
6995         }
6996 }
6997
6998 static void mark_window_mirror(struct window_mirror *mir)
6999 {
7000         mark_redisplay_structs(mir->current_display_lines);
7001         mark_redisplay_structs(mir->desired_display_lines);
7002
7003         if (mir->next)
7004                 mark_window_mirror(mir->next);
7005
7006         if (mir->hchild)
7007                 mark_window_mirror(mir->hchild);
7008         else if (mir->vchild)
7009                 mark_window_mirror(mir->vchild);
7010 }
7011
7012 void mark_redisplay(void)
7013 {
7014         Lisp_Object frmcons, devcons, concons;
7015
7016         FRAME_LOOP_NO_BREAK(frmcons, devcons, concons) {
7017                 struct frame *f = XFRAME(XCAR(frmcons));
7018                 mark_window_mirror(f->root_mirror);
7019                 mark_gutters(f);
7020         }
7021 }
7022 \f
7023 /*****************************************************************************
7024  Line Start Cache Description and Rationale
7025
7026  The traditional scrolling code in Emacs breaks in a variable height world.
7027  It depends on the key assumption that the number of lines that can be
7028  displayed at any given time is fixed.  This led to a complete separation
7029  of the scrolling code from the redisplay code.  In order to fully support
7030  variable height lines, the scrolling code must actually be tightly
7031  integrated with redisplay.  Only redisplay can determine how many lines
7032  will be displayed on a screen for any given starting point.
7033
7034  What is ideally wanted is a complete list of the starting buffer position
7035  for every possible display line of a buffer along with the height of that
7036  display line.  Maintaining such a full list would be very expensive.  We
7037  settle for having it include information for all areas which we happen to
7038  generate anyhow (i.e. the region currently being displayed) and for those
7039  areas we need to work with.
7040
7041  In order to ensure that the cache accurately represents what redisplay
7042  would actually show, it is necessary to invalidate it in many situations.
7043  If the buffer changes, the starting positions may no longer be correct.
7044  If a face or an extent has changed then the line heights may have altered.
7045  These events happen frequently enough that the cache can end up being
7046  constantly disabled.  With this potentially constant invalidation when is
7047  the cache ever useful?
7048
7049  Even if the cache is invalidated before every single usage, it is
7050  necessary.  Scrolling often requires knowledge about display lines which
7051  are actually above or below the visible region.  The cache provides a
7052  convenient light-weight method of storing this information for multiple
7053  display regions.  This knowledge is necessary for the scrolling code to
7054  always obey the First Golden Rule of Redisplay.
7055
7056  If the cache already contains all of the information that the scrolling
7057  routines happen to need so that it doesn't have to go generate it, then we
7058  are able to obey the Third Golden Rule of Redisplay.  The first thing we
7059  do to help out the cache is to always add the displayed region.  This
7060  region had to be generated anyway, so the cache ends up getting the
7061  information basically for free.  In those cases where a user is simply
7062  scrolling around viewing a buffer there is a high probability that this is
7063  sufficient to always provide the needed information.  The second thing we
7064  can do is be smart about invalidating the cache.
7065
7066  TODO -- Be smart about invalidating the cache.  Potential places:
7067
7068  + Insertions at end-of-line which don't cause line-wraps do not alter the
7069    starting positions of any display lines.  These types of buffer
7070    modifications should not invalidate the cache.  This is actually a large
7071    optimization for redisplay speed as well.
7072
7073  + Buffer modifications frequently only affect the display of lines at and
7074    below where they occur.  In these situations we should only invalidate
7075    the part of the cache starting at where the modification occurs.
7076
7077  In case you're wondering, the Second Golden Rule of Redisplay is not
7078  applicable.
7079  ****************************************************************************/
7080
7081 /* This will get used quite a bit so we don't want to be constantly
7082    allocating and freeing it. */
7083 static line_start_cache_dynarr *internal_cache;
7084
7085 /* Makes internal_cache represent the TYPE display structs and only
7086    the TYPE display structs. */
7087
7088 static void update_internal_cache_list(struct window *w, int type)
7089 {
7090         int line;
7091         display_line_dynarr *dla = window_display_lines(w, type);
7092
7093         Dynarr_reset(internal_cache);
7094         for (line = 0; line < Dynarr_length(dla); line++) {
7095                 struct display_line *dl = Dynarr_atp(dla, line);
7096
7097                 if (dl->modeline)
7098                         continue;
7099                 else {
7100                         struct line_start_cache lsc;
7101
7102                         lsc.start = dl->bufpos;
7103                         lsc.end = dl->end_bufpos;
7104                         lsc.height = dl->ascent + dl->descent;
7105
7106                         Dynarr_add(internal_cache, lsc);
7107                 }
7108         }
7109 }
7110
7111 /* Reset the line cache if necessary.  This should be run at the
7112    beginning of any function which access the cache. */
7113
7114 static void validate_line_start_cache(struct window *w)
7115 {
7116         struct buffer *b = XBUFFER(w->buffer);
7117         struct frame *f = XFRAME(w->frame);
7118
7119         if (!w->line_cache_validation_override) {
7120                 /* f->extents_changed used to be in here because extent face and
7121                    size changes can cause text shifting.  However, the extent
7122                    covering the region is constantly having its face set and
7123                    priority altered by the mouse code.  This means that the line
7124                    start cache is constantly being invalidated.  This is bad
7125                    since the mouse code also triggers heavy usage of the cache.
7126                    Since it is an unlikely that f->extents being changed
7127                    indicates that the cache really needs to be updated and if it
7128                    does redisplay will catch it pretty quickly we no longer
7129                    invalidate the cache if it is set.  This greatly speeds up
7130                    dragging out regions with the mouse. */
7131                 if (XINT(w->line_cache_last_updated) < BUF_MODIFF(b)
7132                     || f->faces_changed || f->clip_changed) {
7133                         Dynarr_reset(w->line_start_cache);
7134                 }
7135         }
7136 }
7137
7138 /* Return the very first buffer position contained in the given
7139    window's cache, or -1 if the cache is empty.  Assumes that the
7140    cache is valid. */
7141
7142 static Bufpos line_start_cache_start(struct window *w)
7143 {
7144         line_start_cache_dynarr *cache = w->line_start_cache;
7145
7146         if (!Dynarr_length(cache))
7147                 return -1;
7148         else
7149                 return Dynarr_atp(cache, 0)->start;
7150 }
7151
7152 /* Return the very last buffer position contained in the given
7153    window's cache, or -1 if the cache is empty.  Assumes that the
7154    cache is valid. */
7155
7156 static Bufpos line_start_cache_end(struct window *w)
7157 {
7158         line_start_cache_dynarr *cache = w->line_start_cache;
7159
7160         if (!Dynarr_length(cache))
7161                 return -1;
7162         else
7163                 return Dynarr_atp(cache, Dynarr_length(cache) - 1)->end;
7164 }
7165
7166 /* Return the index of the line POINT is contained within in window
7167    W's line start cache.  It will enlarge the cache or move the cache
7168    window in order to have POINT be present in the cache.  MIN_PAST is
7169    a guarantee of the number of entries in the cache present on either
7170    side of POINT (unless a buffer boundary is hit).  If MIN_PAST is -1
7171    then it will be treated as 0, but the cache window will not be
7172    allowed to shift.  Returns -1 if POINT cannot be found in the cache
7173    for any reason. */
7174
7175 int point_in_line_start_cache(struct window *w, Bufpos point, int min_past)
7176 {
7177         struct buffer *b = XBUFFER(w->buffer);
7178         line_start_cache_dynarr *cache = w->line_start_cache;
7179         unsigned int top, bottom;
7180         EMACS_INT pos;
7181
7182         validate_line_start_cache(w);
7183         w->line_cache_validation_override++;
7184
7185         /* Let functions pass in negative values, but we still treat -1
7186            specially. */
7187         /* #### bogosity alert */
7188         if (min_past < 0 && min_past != -1)
7189                 min_past = -min_past;
7190
7191         if (!Dynarr_length(cache) || line_start_cache_start(w) > point
7192             || line_start_cache_end(w) < point) {
7193                 int loop;
7194                 int win_char_height = window_char_height(w, 1);
7195
7196                 /* Occasionally we get here with a 0 height
7197                    window. find_next_newline_no_quit will abort if we pass it a
7198                    count of 0 so handle that case. */
7199                 if (!win_char_height)
7200                         win_char_height = 1;
7201
7202                 if (!Dynarr_length(cache)) {
7203                         Bufpos from = find_next_newline_no_quit(b, point, -1);
7204                         Bufpos to =
7205                             find_next_newline_no_quit(b, from, win_char_height);
7206
7207                         update_line_start_cache(w, from, to, point, 0);
7208
7209                         if (!Dynarr_length(cache)) {
7210                                 w->line_cache_validation_override--;
7211                                 return -1;
7212                         }
7213                 }
7214
7215                 assert(Dynarr_length(cache));
7216
7217                 loop = 0;
7218                 while (line_start_cache_start(w) > point
7219                        && (loop < cache_adjustment || min_past == -1)) {
7220                         Bufpos from, to;
7221
7222                         from = line_start_cache_start(w);
7223                         if (from <= BUF_BEGV(b))
7224                                 break;
7225
7226                         from =
7227                             find_next_newline_no_quit(b, from,
7228                                                       -win_char_height);
7229                         to = line_start_cache_end(w);
7230
7231                         update_line_start_cache(w, from, to, point, 0);
7232                         loop++;
7233                 }
7234
7235                 if (line_start_cache_start(w) > point) {
7236                         Bufpos from, to;
7237
7238                         from = find_next_newline_no_quit(b, point, -1);
7239                         if (from >= BUF_ZV(b)) {
7240                                 to = find_next_newline_no_quit(b, from,
7241                                                                -win_char_height);
7242                                 from = to;
7243                                 to = BUF_ZV(b);
7244                         } else
7245                                 to = find_next_newline_no_quit(b, from,
7246                                                                win_char_height);
7247
7248                         update_line_start_cache(w, from, to, point, 0);
7249                 }
7250
7251                 loop = 0;
7252                 while (line_start_cache_end(w) < point
7253                        && (loop < cache_adjustment || min_past == -1)) {
7254                         Bufpos from, to;
7255
7256                         to = line_start_cache_end(w);
7257                         if (to >= BUF_ZV(b))
7258                                 break;
7259
7260                         from = line_start_cache_end(w);
7261                         to = find_next_newline_no_quit(b, from,
7262                                                        win_char_height);
7263
7264                         update_line_start_cache(w, from, to, point, 0);
7265                         loop++;
7266                 }
7267
7268                 if (line_start_cache_end(w) < point) {
7269                         Bufpos from, to;
7270
7271                         from = find_next_newline_no_quit(b, point, -1);
7272                         if (from >= BUF_ZV(b)) {
7273                                 to = find_next_newline_no_quit(b, from,
7274                                                                -win_char_height);
7275                                 from = to;
7276                                 to = BUF_ZV(b);
7277                         } else
7278                                 to = find_next_newline_no_quit(b, from,
7279                                                                win_char_height);
7280
7281                         update_line_start_cache(w, from, to, point, 0);
7282                 }
7283         }
7284
7285         assert(Dynarr_length(cache));
7286
7287         if (min_past == -1)
7288                 min_past = 0;
7289
7290         /* This could happen if the buffer is narrowed. */
7291         if (line_start_cache_start(w) > point
7292             || line_start_cache_end(w) < point) {
7293                 w->line_cache_validation_override--;
7294                 return -1;
7295         }
7296
7297       find_point_loop:
7298
7299         top = Dynarr_length(cache) - 1;
7300         bottom = 0;
7301
7302         while (1) {
7303                 EMACS_INT new_pos;
7304                 Bufpos start, end;
7305
7306                 pos = (bottom + top + 1) >> 1;
7307                 start = Dynarr_atp(cache, pos)->start;
7308                 end = Dynarr_atp(cache, pos)->end;
7309
7310                 if (point >= start && point <= end) {
7311                         if (pos < min_past
7312                             && line_start_cache_start(w) > BUF_BEGV(b)) {
7313                                 Bufpos from =
7314                                     find_next_newline_no_quit(b,
7315                                                               line_start_cache_start
7316                                                               (w),
7317                                                               -min_past - 1);
7318                                 Bufpos to = line_start_cache_end(w);
7319
7320                                 update_line_start_cache(w, from, to, point, 0);
7321                                 goto find_point_loop;
7322                         } else if ((Dynarr_length(cache) - pos - 1) < min_past
7323                                    && line_start_cache_end(w) < BUF_ZV(b)) {
7324                                 Bufpos from = line_start_cache_end(w);
7325                                 Bufpos to = find_next_newline_no_quit(b, from,
7326                                                                       (min_past
7327                                                                        ?
7328                                                                        min_past
7329                                                                        : 1));
7330
7331                                 update_line_start_cache(w, from, to, point, 0);
7332                                 goto find_point_loop;
7333                         } else {
7334                                 w->line_cache_validation_override--;
7335                                 return pos;
7336                         }
7337                 } else if (point > end)
7338                         bottom = pos + 1;
7339                 else if (point < start)
7340                         top = pos - 1;
7341                 else
7342                         abort();
7343
7344                 new_pos = (bottom + top + 1) >> 1;
7345                 if (pos == new_pos) {
7346                         w->line_cache_validation_override--;
7347                         return -1;
7348                 }
7349         }
7350 }
7351
7352 /* Return a boolean indicating if POINT would be visible in window W
7353    if display of the window was to begin at STARTP. */
7354
7355 int point_would_be_visible(struct window *w, Bufpos startp, Bufpos point)
7356 {
7357         struct buffer *b = XBUFFER(w->buffer);
7358         int pixpos = -WINDOW_TEXT_TOP_CLIP(w);
7359         int bottom = WINDOW_TEXT_HEIGHT(w);
7360         int start_elt;
7361
7362         /* If point is before the intended start it obviously can't be visible. */
7363         if (point < startp)
7364                 return 0;
7365
7366         /* If point or start are not in the accessible buffer range, then
7367            fail. */
7368         if (startp < BUF_BEGV(b) || startp > BUF_ZV(b)
7369             || point < BUF_BEGV(b) || point > BUF_ZV(b))
7370                 return 0;
7371
7372         validate_line_start_cache(w);
7373         w->line_cache_validation_override++;
7374
7375         start_elt = point_in_line_start_cache(w, startp, 0);
7376         if (start_elt == -1) {
7377                 w->line_cache_validation_override--;
7378                 return 0;
7379         }
7380
7381         assert(line_start_cache_start(w) <= startp
7382                && line_start_cache_end(w) >= startp);
7383
7384         while (1) {
7385                 int height;
7386
7387                 /* Expand the cache if necessary. */
7388                 if (start_elt == Dynarr_length(w->line_start_cache)) {
7389                         Bufpos old_startp =
7390                             Dynarr_atp(w->line_start_cache,
7391                                        start_elt - 1)->start;
7392
7393                         start_elt = point_in_line_start_cache(w, old_startp,
7394                                                               window_char_height
7395                                                               (w, 0));
7396
7397                         /* We've already actually processed old_startp, so increment
7398                            immediately. */
7399                         start_elt++;
7400
7401                         /* If this happens we didn't add any extra elements.  Bummer. */
7402                         if (start_elt == Dynarr_length(w->line_start_cache)) {
7403                                 w->line_cache_validation_override--;
7404                                 return 0;
7405                         }
7406                 }
7407
7408                 height = Dynarr_atp(w->line_start_cache, start_elt)->height;
7409
7410                 if (pixpos + height > bottom) {
7411                         if (bottom - pixpos < VERTICAL_CLIP(w, 0)) {
7412                                 w->line_cache_validation_override--;
7413                                 return 0;
7414                         }
7415                 }
7416
7417                 pixpos += height;
7418                 if (point <= Dynarr_atp(w->line_start_cache, start_elt)->end) {
7419                         w->line_cache_validation_override--;
7420                         return 1;
7421                 }
7422
7423                 start_elt++;
7424         }
7425 }
7426
7427 /* For the given window W, if display starts at STARTP, what will be
7428    the buffer position at the beginning or end of the last line
7429    displayed.  The end of the last line is also know as the window end
7430    position.
7431
7432    WARNING: It is possible that redisplay failed to layout any lines for the
7433    windows. Under normal circumstances this is rare. However it seems that it
7434    does occur in the following situation: A mouse event has come in and we
7435    need to compute its location in a window. That code (in
7436    pixel_to_glyph_translation) already can handle 0 as an error return value.
7437
7438    #### With a little work this could probably be reworked as just a
7439    call to start_with_line_at_pixpos. */
7440
7441 static Bufpos
7442 start_end_of_last_line(struct window *w, Bufpos startp, int end, int may_error)
7443 {
7444         struct buffer *b = XBUFFER(w->buffer);
7445         line_start_cache_dynarr *cache = w->line_start_cache;
7446         int pixpos = 0;
7447         int bottom = WINDOW_TEXT_HEIGHT(w);
7448         Bufpos cur_start;
7449         int start_elt;
7450
7451         validate_line_start_cache(w);
7452         w->line_cache_validation_override++;
7453
7454         if (startp < BUF_BEGV(b))
7455                 startp = BUF_BEGV(b);
7456         else if (startp > BUF_ZV(b))
7457                 startp = BUF_ZV(b);
7458         cur_start = startp;
7459
7460         start_elt = point_in_line_start_cache(w, cur_start, 0);
7461         if (start_elt == -1)
7462                 return may_error ? 0 : startp;
7463
7464         while (1) {
7465                 int height = Dynarr_atp(cache, start_elt)->height;
7466
7467                 cur_start = Dynarr_atp(cache, start_elt)->start;
7468
7469                 if (pixpos + height > bottom) {
7470                         /* Adjust for any possible clip. */
7471                         if (bottom - pixpos < VERTICAL_CLIP(w, 0))
7472                                 start_elt--;
7473
7474                         if (start_elt < 0) {
7475                                 w->line_cache_validation_override--;
7476                                 if (end)
7477                                         return BUF_ZV(b);
7478                                 else
7479                                         return BUF_BEGV(b);
7480                         } else {
7481                                 w->line_cache_validation_override--;
7482                                 if (end)
7483                                         return Dynarr_atp(cache,
7484                                                           start_elt)->end;
7485                                 else
7486                                         return Dynarr_atp(cache,
7487                                                           start_elt)->start;
7488                         }
7489                 }
7490
7491                 pixpos += height;
7492                 start_elt++;
7493                 if (start_elt == Dynarr_length(cache)) {
7494                         Bufpos from = line_start_cache_end(w);
7495                         int win_char_height = window_char_height(w, 0);
7496                         Bufpos to = find_next_newline_no_quit(b, from,
7497                                                               (win_char_height
7498                                                                ? win_char_height
7499                                                                : 1));
7500
7501                         /* We've hit the end of the bottom so that's what it is. */
7502                         if (from >= BUF_ZV(b)) {
7503                                 w->line_cache_validation_override--;
7504                                 return BUF_ZV(b);
7505                         }
7506
7507                         update_line_start_cache(w, from, to, BUF_PT(b), 0);
7508
7509                         /* Updating the cache invalidates any current indexes. */
7510                         start_elt =
7511                             point_in_line_start_cache(w, cur_start, -1) + 1;
7512                 }
7513         }
7514 }
7515
7516 /* For the given window W, if display starts at STARTP, what will be
7517    the buffer position at the beginning of the last line displayed. */
7518
7519 Bufpos start_of_last_line(struct window * w, Bufpos startp)
7520 {
7521         return start_end_of_last_line(w, startp, 0, 0);
7522 }
7523
7524 /* For the given window W, if display starts at STARTP, what will be
7525    the buffer position at the end of the last line displayed.  This is
7526    also know as the window end position. */
7527
7528 Bufpos end_of_last_line(struct window * w, Bufpos startp)
7529 {
7530         return start_end_of_last_line(w, startp, 1, 0);
7531 }
7532
7533 static Bufpos end_of_last_line_may_error(struct window *w, Bufpos startp)
7534 {
7535         return start_end_of_last_line(w, startp, 1, 1);
7536 }
7537
7538 /* For window W, what does the starting position have to be so that
7539    the line containing POINT will cover pixel position PIXPOS. */
7540
7541 Bufpos start_with_line_at_pixpos(struct window * w, Bufpos point, int pixpos)
7542 {
7543         struct buffer *b = XBUFFER(w->buffer);
7544         int cur_elt;
7545         Bufpos cur_pos, prev_pos = point;
7546         int point_line_height;
7547         int pixheight = pixpos - WINDOW_TEXT_TOP(w);
7548
7549         validate_line_start_cache(w);
7550         w->line_cache_validation_override++;
7551
7552         cur_elt = point_in_line_start_cache(w, point, 0);
7553         /* #### See comment in update_line_start_cache about big minibuffers. */
7554         if (cur_elt < 0) {
7555                 w->line_cache_validation_override--;
7556                 return point;
7557         }
7558
7559         point_line_height = Dynarr_atp(w->line_start_cache, cur_elt)->height;
7560
7561         while (1) {
7562                 cur_pos = Dynarr_atp(w->line_start_cache, cur_elt)->start;
7563
7564                 pixheight -= Dynarr_atp(w->line_start_cache, cur_elt)->height;
7565
7566                 /* Do not take into account the value of vertical_clip here.
7567                    That is the responsibility of the calling functions. */
7568                 if (pixheight < 0) {
7569                         w->line_cache_validation_override--;
7570                         if (-pixheight > point_line_height)
7571                                 /* We can't make the target line cover pixpos, so put it
7572                                    above pixpos.  That way it will at least be visible. */
7573                                 return prev_pos;
7574                         else
7575                                 return cur_pos;
7576                 }
7577
7578                 cur_elt--;
7579                 while (cur_elt < 0) {
7580                         Bufpos from, to;
7581                         int win_char_height;
7582
7583                         if (cur_pos <= BUF_BEGV(b)) {
7584                                 w->line_cache_validation_override--;
7585                                 return BUF_BEGV(b);
7586                         }
7587
7588                         win_char_height = window_char_height(w, 0);
7589                         if (!win_char_height)
7590                                 win_char_height = 1;
7591
7592                         from =
7593                             find_next_newline_no_quit(b, cur_pos,
7594                                                       -win_char_height);
7595                         to = line_start_cache_end(w);
7596                         update_line_start_cache(w, from, to, point, 0);
7597
7598                         cur_elt = point_in_line_start_cache(w, cur_pos, 2) - 1;
7599                         assert(cur_elt >= -1);
7600                         /* This used to be cur_elt>=0 under the assumption that if
7601                            point is in the top line and not at BUF_BEGV, then
7602                            setting the window_start to a newline before the start of
7603                            the first line will always cause scrolling.
7604
7605                            However in my (jv) opinion this is wrong.  That new line
7606                            can be hidden in various ways: invisible extents, an
7607                            explicit window-start not at a newline character etc.
7608                            The existence of those are indeed known to create crashes
7609                            on that assert.  So we have no option but to continue the
7610                            search if we found point at the top of the line_start_cache
7611                            again. */
7612                         cur_pos = Dynarr_atp(w->line_start_cache, 0)->start;
7613                 }
7614                 prev_pos = cur_pos;
7615         }
7616 }
7617
7618 /* For window W, what does the starting position have to be so that
7619    the line containing point is on display line LINE.  If LINE is
7620    positive it is considered to be the number of lines from the top of
7621    the window (0 is the top line).  If it is negative the number is
7622    considered to be the number of lines from the bottom (-1 is the
7623    bottom line). */
7624
7625 Bufpos
7626 start_with_point_on_display_line(struct window *w, Bufpos point, int line)
7627 {
7628         validate_line_start_cache(w);
7629         w->line_cache_validation_override++;
7630
7631         if (line >= 0) {
7632                 int cur_elt = point_in_line_start_cache(w, point, line);
7633
7634                 if (cur_elt - line < 0)
7635                         cur_elt = 0;    /* Hit the top */
7636                 else
7637                         cur_elt -= line;
7638
7639                 w->line_cache_validation_override--;
7640                 return Dynarr_atp(w->line_start_cache, cur_elt)->start;
7641         } else {
7642                 /* The calculated value of pixpos is correct for the bottom line
7643                    or what we want when line is -1.  Therefore we subtract one
7644                    because we have already handled one line. */
7645                 int new_line = -line - 1;
7646                 int cur_elt = point_in_line_start_cache(w, point, new_line);
7647                 int pixpos = WINDOW_TEXT_BOTTOM(w);
7648                 Bufpos retval, search_point;
7649
7650                 /* If scroll_on_clipped_lines is false, the last "visible" line of
7651                    the window covers the pixel at WINDOW_TEXT_BOTTOM (w) - 1.
7652                    If s_o_c_l is true, then we don't want to count a clipped
7653                    line, so back up from the bottom by the height of the line
7654                    containing point. */
7655                 if (scroll_on_clipped_lines)
7656                         pixpos -=
7657                             Dynarr_atp(w->line_start_cache, cur_elt)->height;
7658                 else
7659                         pixpos -= 1;
7660
7661                 if (cur_elt + new_line >= Dynarr_length(w->line_start_cache)) {
7662                         /* Hit the bottom of the buffer. */
7663                         int adjustment =
7664                             (cur_elt + new_line) -
7665                             Dynarr_length(w->line_start_cache) + 1;
7666                         Lisp_Object window;
7667                         int defheight;
7668
7669                         XSETWINDOW(window, w);
7670                         default_face_height_and_width(window, &defheight, 0);
7671
7672                         cur_elt = Dynarr_length(w->line_start_cache) - 1;
7673
7674                         pixpos -= (adjustment * defheight);
7675                         if (pixpos < WINDOW_TEXT_TOP(w))
7676                                 pixpos = WINDOW_TEXT_TOP(w);
7677                 } else
7678                         cur_elt = cur_elt + new_line;
7679
7680                 search_point = Dynarr_atp(w->line_start_cache, cur_elt)->start;
7681
7682                 retval = start_with_line_at_pixpos(w, search_point, pixpos);
7683                 w->line_cache_validation_override--;
7684                 return retval;
7685         }
7686 }
7687
7688 /* This is used to speed up vertical scrolling by caching the known
7689    buffer starting positions for display lines.  This allows the
7690    scrolling routines to avoid costly calls to regenerate_window.  If
7691    NO_REGEN is true then it will only add the values in the DESIRED
7692    display structs which are in the given range.
7693
7694    Note also that the FROM/TO values are minimums.  It is possible
7695    that this function will actually add information outside of the
7696    lines containing those positions.  This can't hurt but it could
7697    possibly help.
7698
7699    #### We currently force the cache to have only 1 contiguous region.
7700    It might help to make the cache a dynarr of caches so that we can
7701    cover more areas.  This might, however, turn out to be a lot of
7702    overhead for too little gain. */
7703
7704 static void
7705 update_line_start_cache(struct window *w, Bufpos from, Bufpos to,
7706                         Bufpos point, int no_regen)
7707 {
7708         struct buffer *b = XBUFFER(w->buffer);
7709         line_start_cache_dynarr *cache = w->line_start_cache;
7710         Bufpos low_bound, high_bound;
7711
7712         validate_line_start_cache(w);
7713         w->line_cache_validation_override++;
7714
7715         if (from < BUF_BEGV(b))
7716                 from = BUF_BEGV(b);
7717         if (to > BUF_ZV(b))
7718                 to = BUF_ZV(b);
7719
7720         if (from > to) {
7721                 w->line_cache_validation_override--;
7722                 return;
7723         }
7724
7725         if (Dynarr_length(cache)) {
7726                 low_bound = line_start_cache_start(w);
7727                 high_bound = line_start_cache_end(w);
7728
7729                 /* Check to see if the desired range is already in the cache. */
7730                 if (from >= low_bound && to <= high_bound) {
7731                         w->line_cache_validation_override--;
7732                         return;
7733                 }
7734
7735                 /* Check to make sure that the desired range is adjacent to the
7736                    current cache.  If not, invalidate the cache. */
7737                 if (to < low_bound || from > high_bound) {
7738                         Dynarr_reset(cache);
7739                         low_bound = high_bound = -1;
7740                 }
7741         } else {
7742                 low_bound = high_bound = -1;
7743         }
7744
7745         w->line_cache_last_updated = make_int(BUF_MODIFF(b));
7746
7747         /* This could be integrated into the next two sections, but it is easier
7748            to follow what's going on by having it separate. */
7749         if (no_regen) {
7750                 Bufpos start, end;
7751
7752                 update_internal_cache_list(w, DESIRED_DISP);
7753                 if (!Dynarr_length(internal_cache)) {
7754                         w->line_cache_validation_override--;
7755                         return;
7756                 }
7757
7758                 start = Dynarr_atp(internal_cache, 0)->start;
7759                 end =
7760                     Dynarr_atp(internal_cache,
7761                                Dynarr_length(internal_cache) - 1)->end;
7762
7763                 /* We aren't allowed to generate additional information to fill in
7764                    gaps, so if the DESIRED structs don't overlap the cache, reset the
7765                    cache. */
7766                 if (Dynarr_length(cache)) {
7767                         if (end < low_bound || start > high_bound)
7768                                 Dynarr_reset(cache);
7769
7770                         /* #### What should really happen if what we are doing is
7771                            extending a line (the last line)? */
7772                         if (Dynarr_length(cache) == 1
7773                             && Dynarr_length(internal_cache) == 1)
7774                                 Dynarr_reset(cache);
7775                 }
7776
7777                 if (!Dynarr_length(cache)) {
7778                         Dynarr_add_many(cache, Dynarr_atp(internal_cache, 0),
7779                                         Dynarr_length(internal_cache));
7780                         w->line_cache_validation_override--;
7781                         return;
7782                 }
7783
7784                 /* An extra check just in case the calling function didn't pass in
7785                    the bounds of the DESIRED structs in the first place. */
7786                 if (start >= low_bound && end <= high_bound) {
7787                         w->line_cache_validation_override--;
7788                         return;
7789                 }
7790
7791                 /* At this point we know that the internal cache partially overlaps
7792                    the main cache. */
7793                 if (start < low_bound) {
7794                         int ic_elt = Dynarr_length(internal_cache) - 1;
7795                         while (ic_elt >= 0) {
7796                                 if (Dynarr_atp(internal_cache, ic_elt)->start <
7797                                     low_bound)
7798                                         break;
7799                                 else
7800                                         ic_elt--;
7801                         }
7802
7803                         if (!(ic_elt >= 0)) {
7804                                 Dynarr_reset(cache);
7805                                 Dynarr_add_many(cache,
7806                                                 Dynarr_atp(internal_cache, 0),
7807                                                 Dynarr_length(internal_cache));
7808                                 w->line_cache_validation_override--;
7809                                 return;
7810                         }
7811
7812                         Dynarr_insert_many_at_start(cache,
7813                                                     Dynarr_atp(internal_cache,
7814                                                                0), ic_elt + 1);
7815                 }
7816
7817                 if (end > high_bound) {
7818                         int ic_elt = 0;
7819
7820                         while (ic_elt < Dynarr_length(internal_cache)) {
7821                                 if (Dynarr_atp(internal_cache, ic_elt)->start >
7822                                     high_bound)
7823                                         break;
7824                                 else
7825                                         ic_elt++;
7826                         }
7827
7828                         if (!(ic_elt < Dynarr_length(internal_cache))) {
7829                                 Dynarr_reset(cache);
7830                                 Dynarr_add_many(cache,
7831                                                 Dynarr_atp(internal_cache, 0),
7832                                                 Dynarr_length(internal_cache));
7833                                 w->line_cache_validation_override--;
7834                                 return;
7835                         }
7836
7837                         Dynarr_add_many(cache,
7838                                         Dynarr_atp(internal_cache, ic_elt),
7839                                         Dynarr_length(internal_cache) - ic_elt);
7840                 }
7841
7842                 w->line_cache_validation_override--;
7843                 return;
7844         }
7845
7846         if (!Dynarr_length(cache) || from < low_bound) {
7847                 Bufpos startp = find_next_newline_no_quit(b, from, -1);
7848                 int marker = 0;
7849                 int old_lb = low_bound;
7850
7851                 while (startp < old_lb || low_bound == -1) {
7852                         int ic_elt;
7853                         Bufpos new_startp;
7854
7855                         regenerate_window(w, startp, point, CMOTION_DISP);
7856                         update_internal_cache_list(w, CMOTION_DISP);
7857
7858                         /* If this assert is triggered then regenerate_window failed
7859                            to layout a single line. This is not possible since we
7860                            force at least a single line to be layout for CMOTION_DISP */
7861                         assert(Dynarr_length(internal_cache));
7862                         assert(startp == Dynarr_atp(internal_cache, 0)->start);
7863
7864                         ic_elt = Dynarr_length(internal_cache) - 1;
7865                         if (low_bound != -1) {
7866                                 while (ic_elt >= 0) {
7867                                         if (Dynarr_atp(internal_cache, ic_elt)->
7868                                             start < old_lb)
7869                                                 break;
7870                                         else
7871                                                 ic_elt--;
7872                                 }
7873                         }
7874                         assert(ic_elt >= 0);
7875
7876                         new_startp =
7877                             Dynarr_atp(internal_cache, ic_elt)->end + 1;
7878
7879                         /*
7880                          * Handle invisible text properly:
7881                          * If the last line we're inserting has the same end as the
7882                          * line before which it will be added, merge the two lines.
7883                          */
7884                         if (Dynarr_length(cache) &&
7885                             Dynarr_atp(internal_cache, ic_elt)->end ==
7886                             Dynarr_atp(cache, marker)->end) {
7887                                 Dynarr_atp(cache, marker)->start
7888                                     = Dynarr_atp(internal_cache, ic_elt)->start;
7889                                 Dynarr_atp(cache, marker)->height
7890                                     =
7891                                     Dynarr_atp(internal_cache, ic_elt)->height;
7892                                 ic_elt--;
7893                         }
7894
7895                         if (ic_elt >= 0) {      /* we still have lines to add.. */
7896                                 Dynarr_insert_many(cache,
7897                                                    Dynarr_atp(internal_cache,
7898                                                               0), ic_elt + 1,
7899                                                    marker);
7900                                 marker += (ic_elt + 1);
7901                         }
7902
7903                         if (startp < low_bound || low_bound == -1)
7904                                 low_bound = startp;
7905                         startp = new_startp;
7906                         if (startp > BUF_ZV(b)) {
7907                                 w->line_cache_validation_override--;
7908                                 return;
7909                         }
7910                 }
7911         }
7912
7913         assert(Dynarr_length(cache));
7914         assert(from >= low_bound);
7915
7916         /* Readjust the high_bound to account for any changes made while
7917            correcting the low_bound. */
7918         high_bound = Dynarr_atp(cache, Dynarr_length(cache) - 1)->end;
7919
7920         if (to > high_bound) {
7921                 Bufpos startp =
7922                     Dynarr_atp(cache, Dynarr_length(cache) - 1)->end + 1;
7923
7924                 do {
7925                         regenerate_window(w, startp, point, CMOTION_DISP);
7926                         update_internal_cache_list(w, CMOTION_DISP);
7927
7928                         /* See comment above about regenerate_window failing. */
7929                         assert(Dynarr_length(internal_cache));
7930
7931                         Dynarr_add_many(cache, Dynarr_atp(internal_cache, 0),
7932                                         Dynarr_length(internal_cache));
7933                         high_bound =
7934                             Dynarr_atp(cache, Dynarr_length(cache) - 1)->end;
7935                         startp = high_bound + 1;
7936                 }
7937                 while (to > high_bound);
7938         }
7939
7940         w->line_cache_validation_override--;
7941         assert(to <= high_bound);
7942 }
7943 \f
7944 /* Given x and y coordinates in characters, relative to a window,
7945    return the pixel location corresponding to those coordinates.  The
7946    pixel location returned is the center of the given character
7947    position.  The pixel values are generated relative to the window,
7948    not the frame.
7949
7950    The modeline is considered to be part of the window. */
7951
7952 void
7953 glyph_to_pixel_translation(struct window *w, int char_x, int char_y,
7954                            int *pix_x, int *pix_y)
7955 {
7956         display_line_dynarr *dla = window_display_lines(w, CURRENT_DISP);
7957         int num_disp_lines, modeline;
7958         Lisp_Object window;
7959         int defheight, defwidth;
7960
7961         XSETWINDOW(window, w);
7962         default_face_height_and_width(window, &defheight, &defwidth);
7963
7964         /* If we get a bogus value indicating somewhere above or to the left of
7965            the window, use the first window line or character position
7966            instead. */
7967         if (char_y < 0)
7968                 char_y = 0;
7969         if (char_x < 0)
7970                 char_x = 0;
7971
7972         num_disp_lines = Dynarr_length(dla);
7973         modeline = 0;
7974         if (num_disp_lines) {
7975                 if (Dynarr_atp(dla, 0)->modeline) {
7976                         num_disp_lines--;
7977                         modeline = 1;
7978                 }
7979         }
7980
7981         /* First check if the y position intersects the display lines. */
7982         if (char_y < num_disp_lines) {
7983                 struct display_line *dl = Dynarr_atp(dla, char_y + modeline);
7984                 struct display_block *db =
7985                     get_display_block_from_line(dl, TEXT);
7986
7987                 *pix_y = (dl->ypos - dl->ascent +
7988                           ((unsigned int)(dl->ascent + dl->descent -
7989                                           dl->clip) >> 1));
7990
7991                 if (char_x < Dynarr_length(db->runes)) {
7992                         struct rune *rb = Dynarr_atp(db->runes, char_x);
7993
7994                         *pix_x = rb->xpos + (rb->width >> 1);
7995                 } else {
7996                         int last_rune = Dynarr_length(db->runes) - 1;
7997                         struct rune *rb = Dynarr_atp(db->runes, last_rune);
7998
7999                         char_x -= last_rune;
8000
8001                         *pix_x = rb->xpos + rb->width;
8002                         *pix_x += ((char_x - 1) * defwidth);
8003                         *pix_x += (defwidth >> 1);
8004                 }
8005         } else {
8006                 /* It didn't intersect, so extrapolate.  #### For now, we include the
8007                    modeline in this since we don't have true character positions in
8008                    it. */
8009
8010                 if (!Dynarr_length(w->face_cachels))
8011                         reset_face_cachels(w);
8012
8013                 char_y -= num_disp_lines;
8014
8015                 if (Dynarr_length(dla)) {
8016                         struct display_line *dl =
8017                             Dynarr_atp(dla, Dynarr_length(dla) - 1);
8018                         *pix_y = dl->ypos + dl->descent - dl->clip;
8019                 } else
8020                         *pix_y = WINDOW_TEXT_TOP(w);
8021
8022                 *pix_y += (char_y * defheight);
8023                 *pix_y += (defheight >> 1);
8024
8025                 *pix_x = WINDOW_TEXT_LEFT(w);
8026                 /* Don't adjust by one because this is still the unadjusted value. */
8027                 *pix_x += (char_x * defwidth);
8028                 *pix_x += (defwidth >> 1);
8029         }
8030
8031         if (*pix_x > w->pixel_left + w->pixel_width)
8032                 *pix_x = w->pixel_left + w->pixel_width;
8033         if (*pix_y > w->pixel_top + w->pixel_height)
8034                 *pix_y = w->pixel_top + w->pixel_height;
8035
8036         *pix_x -= w->pixel_left;
8037         *pix_y -= w->pixel_top;
8038 }
8039
8040 /* Given a display line and a position, determine if there is a glyph
8041    there and return information about it if there is. */
8042
8043 static void
8044 get_position_object(struct display_line *dl, Lisp_Object * obj1,
8045                     Lisp_Object * obj2, int x_coord, int *low_x_coord,
8046                     int *high_x_coord)
8047 {
8048         struct display_block *db;
8049         int elt;
8050         int block =
8051             get_next_display_block(dl->bounds, dl->display_blocks, x_coord, 0);
8052
8053         /* We use get_next_display_block to get the actual display block
8054            that would be displayed at x_coord. */
8055
8056         if (block == NO_BLOCK)
8057                 return;
8058         else
8059                 db = Dynarr_atp(dl->display_blocks, block);
8060
8061         for (elt = 0; elt < Dynarr_length(db->runes); elt++) {
8062                 struct rune *rb = Dynarr_atp(db->runes, elt);
8063
8064                 if (rb->xpos <= x_coord && x_coord < (rb->xpos + rb->width)) {
8065                         if (rb->type == RUNE_DGLYPH) {
8066                                 *obj1 = rb->object.dglyph.glyph;
8067                                 *obj2 = rb->object.dglyph.extent;
8068                         } else {
8069                                 *obj1 = Qnil;
8070                                 *obj2 = Qnil;
8071                         }
8072
8073                         if (low_x_coord)
8074                                 *low_x_coord = rb->xpos;
8075                         if (high_x_coord)
8076                                 *high_x_coord = rb->xpos + rb->width;
8077
8078                         return;
8079                 }
8080         }
8081 }
8082
8083 #define UPDATE_CACHE_RETURN                                             \
8084   do {                                                                  \
8085     d->pixel_to_glyph_cache.valid = 1;                                  \
8086     d->pixel_to_glyph_cache.low_x_coord = low_x_coord;                  \
8087     d->pixel_to_glyph_cache.high_x_coord = high_x_coord;                \
8088     d->pixel_to_glyph_cache.low_y_coord = low_y_coord;                  \
8089     d->pixel_to_glyph_cache.high_y_coord = high_y_coord;                \
8090     d->pixel_to_glyph_cache.frame = f;                                  \
8091     d->pixel_to_glyph_cache.col = *col;                                 \
8092     d->pixel_to_glyph_cache.row = *row;                                 \
8093     d->pixel_to_glyph_cache.obj_x = *obj_x;                             \
8094     d->pixel_to_glyph_cache.obj_y = *obj_y;                             \
8095     d->pixel_to_glyph_cache.w = *w;                                     \
8096     d->pixel_to_glyph_cache.bufpos = *bufpos;                           \
8097     d->pixel_to_glyph_cache.closest = *closest;                         \
8098     d->pixel_to_glyph_cache.modeline_closest = *modeline_closest;       \
8099     d->pixel_to_glyph_cache.obj1 = *obj1;                               \
8100     d->pixel_to_glyph_cache.obj2 = *obj2;                               \
8101     d->pixel_to_glyph_cache.retval = position;                          \
8102     RETURN_SANS_WARNINGS position;                                      \
8103   } while (0)
8104
8105 /* Given x and y coordinates in pixels relative to a frame, return
8106    information about what is located under those coordinates.
8107
8108    The return value will be one of:
8109
8110      OVER_TOOLBAR:      over one of the 4 frame toolbars
8111      OVER_MODELINE:     over a modeline
8112      OVER_BORDER:       over an internal border
8113      OVER_NOTHING:      over the text area, but not over text
8114      OVER_OUTSIDE:      outside of the frame border
8115      OVER_TEXT:         over text in the text area
8116
8117    OBJ1 is one of
8118
8119      -- a toolbar button
8120      -- a glyph
8121      -- nil if the coordinates are not over a glyph or a toolbar button.
8122
8123    OBJ2 is one of
8124
8125      -- an extent, if the coordinates are over a glyph in the text area
8126      -- nil otherwise.
8127
8128    If the coordinates are over a glyph, OBJ_X and OBJ_Y give the
8129    equivalent coordinates relative to the upper-left corner of the glyph.
8130
8131    If the coordinates are over a character, OBJ_X and OBJ_Y give the
8132    equivalent coordinates relative to the upper-left corner of the character.
8133
8134    Otherwise, OBJ_X and OBJ_Y are undefined.
8135    */
8136
8137 int
8138 pixel_to_glyph_translation(struct frame *f, int x_coord, int y_coord,
8139                            int *col, int *row, int *obj_x, int *obj_y,
8140                            struct window **w, Bufpos * bufpos,
8141                            Bufpos * closest, Charcount * modeline_closest,
8142                            Lisp_Object * obj1, Lisp_Object * obj2)
8143 {
8144         struct device *d;
8145         struct pixel_to_glyph_translation_cache *cache;
8146         Lisp_Object window;
8147         int frm_left, frm_right, frm_top, frm_bottom;
8148         int low_x_coord, high_x_coord, low_y_coord, high_y_coord;
8149         int position = OVER_NOTHING;
8150         int device_check_failed = 0;
8151         display_line_dynarr *dla;
8152
8153         /* This is a safety valve in case this got called with a frame in
8154            the middle of being deleted. */
8155         if (!DEVICEP(f->device) || !DEVICE_LIVE_P(XDEVICE(f->device))) {
8156                 device_check_failed = 1;
8157                 d = NULL, cache = NULL; /* Warning suppression */
8158         } else {
8159                 d = XDEVICE(f->device);
8160                 cache = &d->pixel_to_glyph_cache;
8161         }
8162
8163         if (!device_check_failed
8164             && cache->valid
8165             && cache->frame == f
8166             && cache->low_x_coord <= x_coord
8167             && cache->high_x_coord > x_coord
8168             && cache->low_y_coord <= y_coord && cache->high_y_coord > y_coord) {
8169                 *col = cache->col;
8170                 *row = cache->row;
8171                 *obj_x = cache->obj_x;
8172                 *obj_y = cache->obj_y;
8173                 *w = cache->w;
8174                 *bufpos = cache->bufpos;
8175                 *closest = cache->closest;
8176                 *modeline_closest = cache->modeline_closest;
8177                 *obj1 = cache->obj1;
8178                 *obj2 = cache->obj2;
8179
8180                 return cache->retval;
8181         } else {
8182                 *col = 0;
8183                 *row = 0;
8184                 *obj_x = 0;
8185                 *obj_y = 0;
8186                 *w = 0;
8187                 *bufpos = 0;
8188                 *closest = 0;
8189                 *modeline_closest = -1;
8190                 *obj1 = Qnil;
8191                 *obj2 = Qnil;
8192
8193                 low_x_coord = x_coord;
8194                 high_x_coord = x_coord + 1;
8195                 low_y_coord = y_coord;
8196                 high_y_coord = y_coord + 1;
8197         }
8198
8199         if (device_check_failed)
8200                 return OVER_NOTHING;
8201
8202         frm_left = FRAME_LEFT_BORDER_END(f);
8203         frm_right = FRAME_RIGHT_BORDER_START(f);
8204         frm_top = FRAME_TOP_BORDER_END(f);
8205         frm_bottom = FRAME_BOTTOM_BORDER_START(f);
8206
8207         /* Check if the mouse is outside of the text area actually used by
8208            redisplay. */
8209         if (y_coord < frm_top) {
8210                 if (y_coord >= FRAME_TOP_BORDER_START(f)) {
8211                         low_y_coord = FRAME_TOP_BORDER_START(f);
8212                         high_y_coord = frm_top;
8213                         position = OVER_BORDER;
8214                 } else if (y_coord >= 0) {
8215                         low_y_coord = 0;
8216                         high_y_coord = FRAME_TOP_BORDER_START(f);
8217                         position = OVER_TOOLBAR;
8218                 } else {
8219                         low_y_coord = y_coord;
8220                         high_y_coord = 0;
8221                         position = OVER_OUTSIDE;
8222                 }
8223         } else if (y_coord >= frm_bottom) {
8224                 if (y_coord < FRAME_BOTTOM_BORDER_END(f)) {
8225                         low_y_coord = frm_bottom;
8226                         high_y_coord = FRAME_BOTTOM_BORDER_END(f);
8227                         position = OVER_BORDER;
8228                 } else if (y_coord < FRAME_PIXHEIGHT(f)) {
8229                         low_y_coord = FRAME_BOTTOM_BORDER_END(f);
8230                         high_y_coord = FRAME_PIXHEIGHT(f);
8231                         position = OVER_TOOLBAR;
8232                 } else {
8233                         low_y_coord = FRAME_PIXHEIGHT(f);
8234                         high_y_coord = y_coord;
8235                         position = OVER_OUTSIDE;
8236                 }
8237         }
8238
8239         if (position != OVER_TOOLBAR && position != OVER_BORDER) {
8240                 if (x_coord < frm_left) {
8241                         if (x_coord >= FRAME_LEFT_BORDER_START(f)) {
8242                                 low_x_coord = FRAME_LEFT_BORDER_START(f);
8243                                 high_x_coord = frm_left;
8244                                 position = OVER_BORDER;
8245                         } else if (x_coord >= 0) {
8246                                 low_x_coord = 0;
8247                                 high_x_coord = FRAME_LEFT_BORDER_START(f);
8248                                 position = OVER_TOOLBAR;
8249                         } else {
8250                                 low_x_coord = x_coord;
8251                                 high_x_coord = 0;
8252                                 position = OVER_OUTSIDE;
8253                         }
8254                 } else if (x_coord >= frm_right) {
8255                         if (x_coord < FRAME_RIGHT_BORDER_END(f)) {
8256                                 low_x_coord = frm_right;
8257                                 high_x_coord = FRAME_RIGHT_BORDER_END(f);
8258                                 position = OVER_BORDER;
8259                         } else if (x_coord < FRAME_PIXWIDTH(f)) {
8260                                 low_x_coord = FRAME_RIGHT_BORDER_END(f);
8261                                 high_x_coord = FRAME_PIXWIDTH(f);
8262                                 position = OVER_TOOLBAR;
8263                         } else {
8264                                 low_x_coord = FRAME_PIXWIDTH(f);
8265                                 high_x_coord = x_coord;
8266                                 position = OVER_OUTSIDE;
8267                         }
8268                 }
8269         }
8270 #ifdef HAVE_TOOLBARS
8271         if (position == OVER_TOOLBAR) {
8272                 *obj1 = toolbar_button_at_pixpos(f, x_coord, y_coord);
8273                 *obj2 = Qnil;
8274                 *w = 0;
8275                 UPDATE_CACHE_RETURN;
8276         }
8277 #endif                          /* HAVE_TOOLBARS */
8278
8279         /* We still have to return the window the pointer is next to and its
8280            relative y position even if it is outside the x boundary. */
8281         if (x_coord < frm_left)
8282                 x_coord = frm_left;
8283         else if (x_coord > frm_right)
8284                 x_coord = frm_right;
8285
8286         /* Same in reverse. */
8287         if (y_coord < frm_top)
8288                 y_coord = frm_top;
8289         else if (y_coord > frm_bottom)
8290                 y_coord = frm_bottom;
8291
8292         /* Find what window the given coordinates are actually in. */
8293         window = f->root_window;
8294         *w = find_window_by_pixel_pos(x_coord, y_coord, window);
8295
8296         /* If we didn't find a window, we're done. */
8297         if (!*w) {
8298                 UPDATE_CACHE_RETURN;
8299         } else if (position != OVER_NOTHING) {
8300                 *closest = 0;
8301                 *modeline_closest = -1;
8302
8303                 if (high_y_coord <= frm_top || high_y_coord >= frm_bottom) {
8304                         *w = 0;
8305                         UPDATE_CACHE_RETURN;
8306                 }
8307         }
8308
8309         /* Check if the window is a minibuffer but isn't active. */
8310         if (MINI_WINDOW_P(*w) && !minibuf_level) {
8311                 /* Must reset the window value since some callers will ignore
8312                    the return value if it is set. */
8313                 *w = 0;
8314                 UPDATE_CACHE_RETURN;
8315         }
8316
8317         /* See if the point is over window vertical divider */
8318         if (window_needs_vertical_divider(*w)) {
8319                 int div_x_high = WINDOW_RIGHT(*w);
8320                 int div_x_low = div_x_high - window_divider_width(*w);
8321                 int div_y_high = WINDOW_BOTTOM(*w);
8322                 int div_y_low = WINDOW_TOP(*w);
8323
8324                 if (div_x_low < x_coord && x_coord <= div_x_high &&
8325                     div_y_low < y_coord && y_coord <= div_y_high) {
8326                         low_x_coord = div_x_low;
8327                         high_x_coord = div_x_high;
8328                         low_y_coord = div_y_low;
8329                         high_y_coord = div_y_high;
8330                         position = OVER_V_DIVIDER;
8331                         UPDATE_CACHE_RETURN;
8332                 }
8333         }
8334
8335         dla = window_display_lines(*w, CURRENT_DISP);
8336
8337         for (*row = 0; *row < Dynarr_length(dla); (*row)++) {
8338                 int really_over_nothing = 0;
8339                 struct display_line *dl = Dynarr_atp(dla, *row);
8340
8341                 if ((int)(dl->ypos - dl->ascent) <= y_coord
8342                     && y_coord <= (int)(dl->ypos + dl->descent)) {
8343                         int check_margin_glyphs = 0;
8344                         struct display_block *db =
8345                             get_display_block_from_line(dl, TEXT);
8346                         struct rune *rb = 0;
8347
8348                         if (x_coord < dl->bounds.left_white
8349                             || x_coord >= dl->bounds.right_white)
8350                                 check_margin_glyphs = 1;
8351
8352                         low_y_coord = dl->ypos - dl->ascent;
8353                         high_y_coord = dl->ypos + dl->descent + 1;
8354
8355                         if (position == OVER_BORDER
8356                             || position == OVER_OUTSIDE
8357                             || check_margin_glyphs) {
8358                                 int x_check, left_bound;
8359
8360                                 if (check_margin_glyphs) {
8361                                         x_check = x_coord;
8362                                         left_bound = dl->bounds.left_white;
8363                                 } else {
8364                                         x_check = high_x_coord;
8365                                         left_bound = frm_left;
8366                                 }
8367
8368                                 if (Dynarr_length(db->runes)) {
8369                                         if (x_check <= left_bound) {
8370                                                 if (dl->modeline)
8371                                                         *modeline_closest =
8372                                                             Dynarr_atp(db->
8373                                                                        runes,
8374                                                                        0)->
8375                                                             bufpos;
8376                                                 else
8377                                                         *closest =
8378                                                             Dynarr_atp(db->
8379                                                                        runes,
8380                                                                        0)->
8381                                                             bufpos;
8382                                         } else {
8383                                                 if (dl->modeline)
8384                                                         *modeline_closest =
8385                                                             Dynarr_atp(db->
8386                                                                        runes,
8387                                                                        Dynarr_length
8388                                                                        (db->
8389                                                                         runes) -
8390                                                                        1)->
8391                                                             bufpos;
8392                                                 else
8393                                                         *closest =
8394                                                             Dynarr_atp(db->
8395                                                                        runes,
8396                                                                        Dynarr_length
8397                                                                        (db->
8398                                                                         runes) -
8399                                                                        1)->
8400                                                             bufpos;
8401                                         }
8402
8403                                         if (dl->modeline)
8404                                                 *modeline_closest += dl->offset;
8405                                         else
8406                                                 *closest += dl->offset;
8407                                 } else {
8408                                         /* #### What should be here. */
8409                                         if (dl->modeline)
8410                                                 *modeline_closest = 0;
8411                                         else
8412                                                 *closest = 0;
8413                                 }
8414
8415                                 if (check_margin_glyphs) {
8416                                         if (x_coord < dl->bounds.left_in
8417                                             || x_coord >= dl->bounds.right_in) {
8418                                                 /* If we are over the outside margins then we
8419                                                    know the loop over the text block isn't going
8420                                                    to accomplish anything.  So we go ahead and
8421                                                    set what information we can right here and
8422                                                    return. */
8423                                                 (*row)--;
8424                                                 *obj_y =
8425                                                     y_coord - (dl->ypos -
8426                                                                dl->ascent);
8427                                                 get_position_object(dl, obj1,
8428                                                                     obj2,
8429                                                                     x_coord,
8430                                                                     &low_x_coord,
8431                                                                     &high_x_coord);
8432
8433                                                 UPDATE_CACHE_RETURN;
8434                                         }
8435                                 } else
8436                                         UPDATE_CACHE_RETURN;
8437                         }
8438
8439                         for (*col = 0; *col <= Dynarr_length(db->runes);
8440                              (*col)++) {
8441                                 int past_end =
8442                                     (*col == Dynarr_length(db->runes));
8443
8444                                 if (!past_end)
8445                                         rb = Dynarr_atp(db->runes, *col);
8446
8447                                 if (past_end ||
8448                                     (rb->xpos <= x_coord
8449                                      && x_coord < rb->xpos + rb->width)) {
8450                                         if (past_end) {
8451                                                 (*col)--;
8452                                                 rb = Dynarr_atp(db->runes,
8453                                                                 *col);
8454                                         }
8455
8456                                         *bufpos = rb->bufpos + dl->offset;
8457                                         low_x_coord = rb->xpos;
8458                                         high_x_coord = rb->xpos + rb->width;
8459
8460                                         if (rb->type == RUNE_DGLYPH) {
8461                                                 int elt = *col + 1;
8462
8463                                                 /* Find the first character after the glyph. */
8464                                                 while (elt <
8465                                                        Dynarr_length(db->
8466                                                                      runes)) {
8467                                                         if (Dynarr_atp
8468                                                             (db->runes,
8469                                                              elt)->type !=
8470                                                             RUNE_DGLYPH) {
8471                                                                 if (dl->
8472                                                                     modeline)
8473                                                                         *modeline_closest
8474                                                                             =
8475                                                                             (Dynarr_atp
8476                                                                              (db->
8477                                                                               runes,
8478                                                                               elt)->
8479                                                                              bufpos
8480                                                                              +
8481                                                                              dl->
8482                                                                              offset);
8483                                                                 else
8484                                                                         *closest
8485                                                                             =
8486                                                                             (Dynarr_atp
8487                                                                              (db->
8488                                                                               runes,
8489                                                                               elt)->
8490                                                                              bufpos
8491                                                                              +
8492                                                                              dl->
8493                                                                              offset);
8494                                                                 break;
8495                                                         }
8496
8497                                                         elt++;
8498                                                 }
8499
8500                                                 /* In this case we failed to find a non-glyph
8501                                                    character so we return the last position
8502                                                    displayed on the line. */
8503                                                 if (elt ==
8504                                                     Dynarr_length(db->runes)) {
8505                                                         if (dl->modeline)
8506                                                                 *modeline_closest
8507                                                                     =
8508                                                                     dl->
8509                                                                     end_bufpos +
8510                                                                     dl->offset;
8511                                                         else
8512                                                                 *closest =
8513                                                                     dl->
8514                                                                     end_bufpos +
8515                                                                     dl->offset;
8516                                                         really_over_nothing = 1;
8517                                                 }
8518                                         } else {
8519                                                 if (dl->modeline)
8520                                                         *modeline_closest =
8521                                                             rb->bufpos +
8522                                                             dl->offset;
8523                                                 else
8524                                                         *closest =
8525                                                             rb->bufpos +
8526                                                             dl->offset;
8527                                         }
8528
8529                                         if (dl->modeline) {
8530                                                 *row =
8531                                                     window_displayed_height(*w);
8532
8533                                                 if (position == OVER_NOTHING)
8534                                                         position =
8535                                                             OVER_MODELINE;
8536
8537                                                 if (rb->type == RUNE_DGLYPH) {
8538                                                         *obj1 =
8539                                                             rb->object.dglyph.
8540                                                             glyph;
8541                                                         *obj2 =
8542                                                             rb->object.dglyph.
8543                                                             extent;
8544                                                 } else if (rb->type ==
8545                                                            RUNE_CHAR) {
8546                                                         *obj1 = Qnil;
8547                                                         *obj2 = Qnil;
8548                                                 } else {
8549                                                         *obj1 = Qnil;
8550                                                         *obj2 = Qnil;
8551                                                 }
8552
8553                                                 UPDATE_CACHE_RETURN;
8554                                         } else if (past_end
8555                                                    || (rb->type == RUNE_CHAR
8556                                                        && rb->object.chr.ch ==
8557                                                        '\n')) {
8558                                                 (*row)--;
8559                                                 /* At this point we may have glyphs in the right
8560                                                    inside margin. */
8561                                                 if (check_margin_glyphs)
8562                                                         get_position_object(dl,
8563                                                                             obj1,
8564                                                                             obj2,
8565                                                                             x_coord,
8566                                                                             &low_x_coord,
8567                                                                             &high_x_coord);
8568                                                 UPDATE_CACHE_RETURN;
8569                                         } else {
8570                                                 (*row)--;
8571                                                 if (rb->type == RUNE_DGLYPH) {
8572                                                         *obj1 =
8573                                                             rb->object.dglyph.
8574                                                             glyph;
8575                                                         *obj2 =
8576                                                             rb->object.dglyph.
8577                                                             extent;
8578                                                 } else if (rb->type ==
8579                                                            RUNE_CHAR) {
8580                                                         *obj1 = Qnil;
8581                                                         *obj2 = Qnil;
8582                                                 } else {
8583                                                         *obj1 = Qnil;
8584                                                         *obj2 = Qnil;
8585                                                 }
8586
8587                                                 *obj_x = x_coord - rb->xpos;
8588                                                 *obj_y =
8589                                                     y_coord - (dl->ypos -
8590                                                                dl->ascent);
8591
8592                                                 /* At this point we may have glyphs in the left
8593                                                    inside margin. */
8594                                                 if (check_margin_glyphs)
8595                                                         get_position_object(dl,
8596                                                                             obj1,
8597                                                                             obj2,
8598                                                                             x_coord,
8599                                                                             0,
8600                                                                             0);
8601
8602                                                 if (position == OVER_NOTHING
8603                                                     && !really_over_nothing)
8604                                                         position = OVER_TEXT;
8605
8606                                                 UPDATE_CACHE_RETURN;
8607                                         }
8608                                 }
8609                         }
8610                 }
8611         }
8612
8613         *row = Dynarr_length(dla) - 1;
8614         if (FRAME_WIN_P(f)) {
8615                 int bot_elt = Dynarr_length(dla) - 1;
8616
8617                 if (bot_elt >= 0) {
8618                         struct display_line *dl = Dynarr_atp(dla, bot_elt);
8619                         int adj_area = y_coord - (dl->ypos + dl->descent);
8620                         Lisp_Object lwin;
8621                         int defheight;
8622
8623                         XSETWINDOW(lwin, *w);
8624                         default_face_height_and_width(lwin, 0, &defheight);
8625
8626                         *row += (adj_area / defheight);
8627                 }
8628         }
8629
8630         /* #### This should be checked out some more to determine what
8631            should really be going on. */
8632         if (!MARKERP((*w)->start[CURRENT_DISP]))
8633                 *closest = 0;
8634         else
8635                 *closest = end_of_last_line_may_error(*w,
8636                                                       marker_position((*w)->
8637                                                                       start
8638                                                                       [CURRENT_DISP]));
8639         *col = 0;
8640         UPDATE_CACHE_RETURN;
8641 }
8642
8643 #undef UPDATE_CACHE_RETURN
8644 \f
8645 /***************************************************************************/
8646 /*                                                                         */
8647 /*                             Lisp functions                              */
8648 /*                                                                         */
8649 /***************************************************************************/
8650
8651 DEFUN("redisplay-echo-area", Fredisplay_echo_area, 0, 0, 0,     /*
8652 Ensure that all minibuffers are correctly showing the echo area.
8653 */
8654       ())
8655 {
8656         Lisp_Object devcons, concons;
8657
8658         DEVICE_LOOP_NO_BREAK(devcons, concons) {
8659                 struct device *d = XDEVICE(XCAR(devcons));
8660                 Lisp_Object frmcons;
8661
8662                 DEVICE_FRAME_LOOP(frmcons, d) {
8663                         struct frame *f = XFRAME(XCAR(frmcons));
8664
8665                         if (FRAME_REPAINT_P(f) && FRAME_HAS_MINIBUF_P(f)) {
8666                                 Lisp_Object window = FRAME_MINIBUF_WINDOW(f);
8667
8668                                 MAYBE_DEVMETH(d, frame_output_begin, (f));
8669
8670                                 /*
8671                                  * If the frame size has changed, there may be random
8672                                  * chud on the screen left from previous messages
8673                                  * because redisplay_frame hasn't been called yet.
8674                                  * Clear the screen to get rid of the potential mess.
8675                                  */
8676                                 if (f->echo_area_garbaged) {
8677                                         MAYBE_DEVMETH(d, clear_frame, (f));
8678                                         f->echo_area_garbaged = 0;
8679                                 }
8680                                 redisplay_window(window, 0);
8681                                 MAYBE_DEVMETH(d, frame_output_end, (f));
8682
8683                                 call_redisplay_end_triggers(XWINDOW(window), 0);
8684                         }
8685                 }
8686         }
8687
8688         return Qnil;
8689 }
8690
8691 static Lisp_Object restore_disable_preemption_value(Lisp_Object value)
8692 {
8693         disable_preemption = XINT(value);
8694         return Qnil;
8695 }
8696
8697 DEFUN("redraw-frame", Fredraw_frame, 0, 2, 0,   /*
8698 Clear frame FRAME and output again what is supposed to appear on it.
8699 FRAME defaults to the selected frame if omitted.
8700 Normally, redisplay is preempted as normal if input arrives.  However,
8701 if optional second arg NO-PREEMPT is non-nil, redisplay will not stop for
8702 input and is guaranteed to proceed to completion.
8703 */
8704       (frame, no_preempt))
8705 {
8706         struct frame *f = decode_frame(frame);
8707         int count = specpdl_depth();
8708
8709         if (!NILP(no_preempt)) {
8710                 record_unwind_protect(restore_disable_preemption_value,
8711                                       make_int(disable_preemption));
8712                 disable_preemption++;
8713         }
8714
8715         f->clear = 1;
8716         redisplay_frame(f, 1);
8717
8718         /* See the comment in Fredisplay_frame. */
8719         RESET_CHANGED_SET_FLAGS;
8720
8721         return unbind_to(count, Qnil);
8722 }
8723
8724 DEFUN("redisplay-frame", Fredisplay_frame, 0, 2, 0,     /*
8725 Ensure that FRAME's contents are correctly displayed.
8726 This differs from `redraw-frame' in that it only redraws what needs to
8727 be updated, as opposed to unconditionally clearing and redrawing
8728 the frame.
8729 FRAME defaults to the selected frame if omitted.
8730 Normally, redisplay is preempted as normal if input arrives.  However,
8731 if optional second arg NO-PREEMPT is non-nil, redisplay will not stop for
8732 input and is guaranteed to proceed to completion.
8733 */
8734       (frame, no_preempt))
8735 {
8736         struct frame *f = decode_frame(frame);
8737         int count = specpdl_depth();
8738
8739         if (!NILP(no_preempt)) {
8740                 record_unwind_protect(restore_disable_preemption_value,
8741                                       make_int(disable_preemption));
8742                 disable_preemption++;
8743         }
8744
8745         redisplay_frame(f, 1);
8746
8747         /* If we don't reset the global redisplay flags here, subsequent
8748            changes to the display will not get registered by redisplay
8749            because it thinks it already has registered changes. If you
8750            really knew what you were doing you could confuse redisplay by
8751            calling Fredisplay_frame while updating another frame. We assume
8752            that if you know what you are doing you will not be that
8753            stupid. */
8754         RESET_CHANGED_SET_FLAGS;
8755
8756         return unbind_to(count, Qnil);
8757 }
8758
8759 DEFUN("redraw-device", Fredraw_device, 0, 2, 0, /*
8760 Clear device DEVICE and output again what is supposed to appear on it.
8761 DEVICE defaults to the selected device if omitted.
8762 Normally, redisplay is preempted as normal if input arrives.  However,
8763 if optional second arg NO-PREEMPT is non-nil, redisplay will not stop for
8764 input and is guaranteed to proceed to completion.
8765 */
8766       (device, no_preempt))
8767 {
8768         struct device *d = decode_device(device);
8769         Lisp_Object frmcons;
8770         int count = specpdl_depth();
8771
8772         if (!NILP(no_preempt)) {
8773                 record_unwind_protect(restore_disable_preemption_value,
8774                                       make_int(disable_preemption));
8775                 disable_preemption++;
8776         }
8777
8778         DEVICE_FRAME_LOOP(frmcons, d) {
8779                 XFRAME(XCAR(frmcons))->clear = 1;
8780         }
8781         redisplay_device(d, 0);
8782
8783         /* See the comment in Fredisplay_frame. */
8784         RESET_CHANGED_SET_FLAGS;
8785
8786         return unbind_to(count, Qnil);
8787 }
8788
8789 DEFUN("redisplay-device", Fredisplay_device, 0, 2, 0,   /*
8790 Ensure that DEVICE's contents are correctly displayed.
8791 This differs from `redraw-device' in that it only redraws what needs to
8792 be updated, as opposed to unconditionally clearing and redrawing
8793 the device.
8794 DEVICE defaults to the selected device if omitted.
8795 Normally, redisplay is preempted as normal if input arrives.  However,
8796 if optional second arg NO-PREEMPT is non-nil, redisplay will not stop for
8797 input and is guaranteed to proceed to completion.
8798 */
8799       (device, no_preempt))
8800 {
8801         struct device *d = decode_device(device);
8802         int count = specpdl_depth();
8803
8804         if (!NILP(no_preempt)) {
8805                 record_unwind_protect(restore_disable_preemption_value,
8806                                       make_int(disable_preemption));
8807                 disable_preemption++;
8808         }
8809
8810         redisplay_device(d, 0);
8811
8812         /* See the comment in Fredisplay_frame. */
8813         RESET_CHANGED_SET_FLAGS;
8814
8815         return unbind_to(count, Qnil);
8816 }
8817
8818 /* Big lie.  Big lie.  This will force all modelines to be updated
8819    regardless if the all flag is set or not.  It remains in existence
8820    solely for backwards compatibility. */
8821 DEFUN("redraw-modeline", Fredraw_modeline, 0, 1, 0,     /*
8822 Force the modeline of the current buffer to be redisplayed.
8823 With optional non-nil ALL, force redisplay of all modelines.
8824 */
8825       (all))
8826 {
8827         MARK_MODELINE_CHANGED;
8828         return Qnil;
8829 }
8830
8831 DEFUN("force-cursor-redisplay", Fforce_cursor_redisplay, 0, 1, 0,       /*
8832 Force an immediate update of the cursor on FRAME.
8833 FRAME defaults to the selected frame if omitted.
8834 */
8835       (frame))
8836 {
8837         redisplay_redraw_cursor(decode_frame(frame), 1);
8838         return Qnil;
8839 }
8840 \f
8841 /***************************************************************************/
8842 /*                                                                         */
8843 /*                     Lisp-variable change triggers                       */
8844 /*                                                                         */
8845 /***************************************************************************/
8846
8847 static void
8848 margin_width_changed_in_frame(Lisp_Object specifier, struct frame *f,
8849                               Lisp_Object oldval)
8850 {
8851         /* Nothing to be done? */
8852 }
8853
8854 int
8855 redisplay_variable_changed(Lisp_Object sym, Lisp_Object * val,
8856                            Lisp_Object in_object, int flags)
8857 {
8858         /* #### clip_changed should really be renamed something like
8859            global_redisplay_change. */
8860         MARK_CLIP_CHANGED;
8861         return 0;
8862 }
8863
8864 /* This is called if the built-in glyphs have their properties
8865    changed. */
8866 void
8867 redisplay_glyph_changed(Lisp_Object glyph, Lisp_Object property,
8868                         Lisp_Object locale)
8869 {
8870         if (WINDOWP(locale)) {
8871                 MARK_FRAME_GLYPHS_CHANGED(XFRAME
8872                                           (WINDOW_FRAME(XWINDOW(locale))));
8873         } else if (FRAMEP(locale)) {
8874                 MARK_FRAME_GLYPHS_CHANGED(XFRAME(locale));
8875         } else if (DEVICEP(locale)) {
8876                 Lisp_Object frmcons;
8877                 DEVICE_FRAME_LOOP(frmcons, XDEVICE(locale))
8878                     MARK_FRAME_GLYPHS_CHANGED(XFRAME(XCAR(frmcons)));
8879         } else if (CONSOLEP(locale)) {
8880                 Lisp_Object frmcons, devcons;
8881                 CONSOLE_FRAME_LOOP_NO_BREAK(frmcons, devcons, XCONSOLE(locale))
8882                     MARK_FRAME_GLYPHS_CHANGED(XFRAME(XCAR(frmcons)));
8883         } else {                /* global or buffer */
8884
8885                 Lisp_Object frmcons, devcons, concons;
8886                 FRAME_LOOP_NO_BREAK(frmcons, devcons, concons)
8887                     MARK_FRAME_GLYPHS_CHANGED(XFRAME(XCAR(frmcons)));
8888         }
8889 }
8890
8891 static void
8892 text_cursor_visible_p_changed(Lisp_Object specifier, struct window *w,
8893                               Lisp_Object oldval)
8894 {
8895         if (XFRAME(w->frame)->init_finished)
8896                 Fforce_cursor_redisplay(w->frame);
8897 }
8898
8899 #if defined MEMORY_USAGE_STATS && !(defined HAVE_BDWGC && defined EF_USE_BDWGC)
8900 \f
8901 /***************************************************************************/
8902 /*                                                                         */
8903 /*                        memory usage computation                         */
8904 /*                                                                         */
8905 /***************************************************************************/
8906
8907 static int
8908 compute_rune_dynarr_usage(rune_dynarr * dyn, struct overhead_stats *ovstats)
8909 {
8910         return dyn ? Dynarr_memory_usage(dyn, ovstats) : 0;
8911 }
8912
8913 static int
8914 compute_display_block_dynarr_usage(display_block_dynarr * dyn,
8915                                    struct overhead_stats *ovstats)
8916 {
8917         int total, i;
8918
8919         if (!dyn)
8920                 return 0;
8921
8922         total = Dynarr_memory_usage(dyn, ovstats);
8923         for (i = 0; i < Dynarr_largest(dyn); i++)
8924                 total +=
8925                     compute_rune_dynarr_usage(Dynarr_at(dyn, i).runes, ovstats);
8926
8927         return total;
8928 }
8929
8930 static int
8931 compute_glyph_block_dynarr_usage(glyph_block_dynarr * dyn,
8932                                  struct overhead_stats *ovstats)
8933 {
8934         return dyn ? Dynarr_memory_usage(dyn, ovstats) : 0;
8935 }
8936
8937 int
8938 compute_display_line_dynarr_usage(display_line_dynarr * dyn,
8939                                   struct overhead_stats *ovstats)
8940 {
8941         int total, i;
8942
8943         if (!dyn)
8944                 return 0;
8945
8946         total = Dynarr_memory_usage(dyn, ovstats);
8947         for (i = 0; i < Dynarr_largest(dyn); i++) {
8948                 struct display_line *dl = &Dynarr_at(dyn, i);
8949                 total +=
8950                     compute_display_block_dynarr_usage(dl->display_blocks,
8951                                                        ovstats);
8952                 total +=
8953                     compute_glyph_block_dynarr_usage(dl->left_glyphs, ovstats);
8954                 total +=
8955                     compute_glyph_block_dynarr_usage(dl->right_glyphs, ovstats);
8956         }
8957
8958         return total;
8959 }
8960
8961 int
8962 compute_line_start_cache_dynarr_usage(line_start_cache_dynarr * dyn,
8963                                       struct overhead_stats *ovstats)
8964 {
8965         return dyn ? Dynarr_memory_usage(dyn, ovstats) : 0;
8966 }
8967
8968 #endif                          /* MEMORY_USAGE_STATS */
8969 \f
8970 /***************************************************************************/
8971 /*                                                                         */
8972 /*                              initialization                             */
8973 /*                                                                         */
8974 /***************************************************************************/
8975
8976 void init_redisplay(void)
8977 {
8978         disable_preemption = 0;
8979         preemption_count = 0;
8980         max_preempts = INIT_MAX_PREEMPTS;
8981
8982 #ifndef PDUMP
8983         if (!initialized)
8984 #endif
8985         {
8986                 if (!cmotion_display_lines)
8987                         cmotion_display_lines = Dynarr_new(display_line);
8988                 if (!mode_spec_bufbyte_string)
8989                         mode_spec_bufbyte_string = Dynarr_new(Bufbyte);
8990                 if (!formatted_string_extent_dynarr)
8991                         formatted_string_extent_dynarr = Dynarr_new(EXTENT);
8992                 if (!formatted_string_extent_start_dynarr)
8993                         formatted_string_extent_start_dynarr =
8994                             Dynarr_new(Bytecount);
8995                 if (!formatted_string_extent_end_dynarr)
8996                         formatted_string_extent_end_dynarr =
8997                             Dynarr_new(Bytecount);
8998                 if (!internal_cache)
8999                         internal_cache = Dynarr_new(line_start_cache);
9000         }
9001
9002         /* window system is nil when in -batch mode */
9003         if (!initialized || noninteractive)
9004                 return;
9005
9006         /* If the user wants to use a window system, we shouldn't bother
9007            initializing the terminal.  This is especially important when the
9008            terminal is so dumb that emacs gives up before and doesn't bother
9009            using the window system.
9010
9011            If the DISPLAY environment variable is set, try to use X, and die
9012            with an error message if that doesn't work.  */
9013
9014 #ifdef HAVE_X_WINDOWS
9015         if (!strcmp(display_use, "x")) {
9016                 /* Some stuff checks this way early. */
9017                 Vwindow_system = Qx;
9018                 Vinitial_window_system = Qx;
9019                 return;
9020         }
9021 #endif                          /* HAVE_X_WINDOWS */
9022
9023 #ifdef HAVE_TTY
9024         /* If no window system has been specified, try to use the terminal.  */
9025         if (!isatty(0)) {
9026                 stderr_out("SXEmacs: standard input is not a tty\n");
9027                 exit(1);
9028         }
9029
9030         /* Look at the TERM variable */
9031         if (!getenv("TERM")) {
9032                 stderr_out
9033                     ("Please set the environment variable TERM; see tset(1).\n");
9034                 exit(1);
9035         }
9036
9037         Vinitial_window_system = Qtty;
9038         return;
9039 #else                           /* not HAVE_TTY */
9040         /* No DISPLAY specified, and no TTY support. */
9041         stderr_out("SXEmacs: Cannot open display.\n\
9042 Please set the environmental variable DISPLAY to an appropriate value.\n");
9043         exit(1);
9044 #endif
9045         /* Unreached. */
9046 }
9047
9048 void syms_of_redisplay(void)
9049 {
9050         defsymbol(&Qcursor_in_echo_area, "cursor-in-echo-area");
9051 #ifndef INHIBIT_REDISPLAY_HOOKS
9052         defsymbol(&Qpre_redisplay_hook, "pre-redisplay-hook");
9053         defsymbol(&Qpost_redisplay_hook, "post-redisplay-hook");
9054 #endif                          /* INHIBIT_REDISPLAY_HOOKS */
9055         defsymbol(&Qdisplay_warning_buffer, "display-warning-buffer");
9056         defsymbol(&Qbar_cursor, "bar-cursor");
9057         defsymbol(&Qredisplay_end_trigger_functions,
9058                   "redisplay-end-trigger-functions");
9059         defsymbol(&Qtop_bottom, "top-bottom");
9060         defsymbol(&Qbuffer_list_changed_hook, "buffer-list-changed-hook");
9061
9062         DEFSUBR(Fredisplay_echo_area);
9063         DEFSUBR(Fredraw_frame);
9064         DEFSUBR(Fredisplay_frame);
9065         DEFSUBR(Fredraw_device);
9066         DEFSUBR(Fredisplay_device);
9067         DEFSUBR(Fredraw_modeline);
9068         DEFSUBR(Fforce_cursor_redisplay);
9069 }
9070
9071 void vars_of_redisplay(void)
9072 {
9073
9074 #if 0
9075         staticpro(&last_arrow_position);
9076         staticpro(&last_arrow_string);
9077         last_arrow_position = Qnil;
9078         last_arrow_string = Qnil;
9079 #endif                          /* 0 */
9080
9081         /* #### Probably temporary */
9082         DEFVAR_INT("redisplay-cache-adjustment", &cache_adjustment      /*
9083 \(Temporary) Setting this will impact the performance of the internal
9084 line start cache.
9085                                                                          */ );
9086         cache_adjustment = 2;
9087
9088         DEFVAR_INT_MAGIC("pixel-vertical-clip-threshold", &vertical_clip        /*
9089 Minimum pixel height for clipped bottom display line.
9090 A clipped line shorter than this won't be displayed.
9091                                                                                  */ ,
9092                          redisplay_variable_changed);
9093         vertical_clip = 5;
9094
9095         DEFVAR_INT_MAGIC("pixel-horizontal-clip-threshold", &horizontal_clip    /*
9096 Minimum visible area for clipped glyphs at right boundary.
9097 Clipped glyphs shorter than this won't be displayed.
9098 Only pixmap glyph instances are currently allowed to be clipped.
9099                                                                                  */ ,
9100                          redisplay_variable_changed);
9101         horizontal_clip = 5;
9102
9103         DEFVAR_LISP("global-mode-string", &Vglobal_mode_string  /*
9104 String displayed by modeline-format's "%m" specification.
9105                                                                  */ );
9106         Vglobal_mode_string = Qnil;
9107
9108         DEFVAR_LISP_MAGIC("overlay-arrow-position", &Voverlay_arrow_position    /*
9109 Marker for where to display an arrow on top of the buffer text.
9110 This must be the beginning of a line in order to work.
9111 See also `overlay-arrow-string'.
9112                                                                                  */ ,
9113                           redisplay_variable_changed);
9114         Voverlay_arrow_position = Qnil;
9115
9116         DEFVAR_LISP_MAGIC("overlay-arrow-string", &Voverlay_arrow_string        /*
9117 String or glyph to display as an arrow.  See also `overlay-arrow-position'.
9118 \(Note that despite the name of this variable, it can be set to a glyph as
9119 well as a string.)
9120                                                                                  */ ,
9121                           redisplay_variable_changed);
9122         Voverlay_arrow_string = Qnil;
9123
9124         DEFVAR_INT("scroll-step", &scroll_step  /*
9125 *The number of lines to try scrolling a window by when point moves out.
9126 If that fails to bring point back on frame, point is centered instead.
9127 If this is zero, point is always centered after it moves off screen.
9128                                                  */ );
9129         scroll_step = 0;
9130
9131         DEFVAR_INT("scroll-conservatively", &scroll_conservatively      /*
9132 *Scroll up to this many lines, to bring point back on screen.
9133                                                                          */ );
9134         scroll_conservatively = 0;
9135
9136         DEFVAR_BOOL_MAGIC("truncate-partial-width-windows", &truncate_partial_width_windows     /*
9137 *Non-nil means truncate lines in all windows less than full frame wide.
9138                                                                                                  */ ,
9139                           redisplay_variable_changed);
9140         truncate_partial_width_windows = 1;
9141
9142         DEFVAR_LISP("visible-bell", &Vvisible_bell      /*
9143 *Non-nil substitutes a visual signal for the audible bell.
9144
9145 Default behavior is to flash the whole screen.  On some platforms,
9146 special effects are available using the following values:
9147
9148 'display       Flash the whole screen (ie, the default behavior).
9149 'top-bottom    Flash only the top and bottom lines of the selected frame.
9150
9151 When effects are unavailable on a platform, the visual bell is the
9152 default, whole screen.  (Currently only X supports any special effects.)
9153                                                          */ );
9154         Vvisible_bell = Qnil;
9155
9156         DEFVAR_BOOL("no-redraw-on-reenter", &no_redraw_on_reenter       /*
9157 *Non-nil means no need to redraw entire frame after suspending.
9158 A non-nil value is useful if the terminal can automatically preserve
9159 Emacs's frame display when you reenter Emacs.
9160 It is up to you to set this variable if your terminal can do that.
9161                                                                          */ );
9162         no_redraw_on_reenter = 0;
9163
9164         DEFVAR_LISP("window-system", &Vwindow_system    /*
9165 A symbol naming the window-system under which Emacs is running,
9166 such as `x', or nil if emacs is running on an ordinary terminal.
9167
9168 Do not use this variable, except for GNU Emacs compatibility, as it
9169 gives wrong values in a multi-device environment.  Use `console-type'
9170 instead.
9171                                                          */ );
9172         Vwindow_system = Qnil;
9173
9174         /* #### Temporary shit until window-system is eliminated. */
9175         DEFVAR_CONST_LISP("initial-window-system", &Vinitial_window_system      /*
9176 DON'T TOUCH
9177                                                                                  */ );
9178         Vinitial_window_system = Qnil;
9179
9180         DEFVAR_BOOL("cursor-in-echo-area", &cursor_in_echo_area /*
9181 Non-nil means put cursor in minibuffer, at end of any message there.
9182                                                                  */ );
9183         cursor_in_echo_area = 0;
9184
9185         /* #### Shouldn't this be generalized as follows:
9186
9187            if nil, use block cursor.
9188            if a number, use a bar cursor of that width.
9189            Otherwise, use a 1-pixel bar cursor.
9190
9191            #### Or better yet, this variable should be trashed entirely
9192            (use a Lisp-magic variable to maintain compatibility)
9193            and a specifier `cursor-shape' added, which allows a block
9194            cursor, a bar cursor, a flashing block or bar cursor,
9195            maybe a caret cursor, etc. */
9196
9197         DEFVAR_LISP("bar-cursor", &Vbar_cursor  /*
9198 *Use vertical bar cursor if non-nil.  If t width is 1 pixel, otherwise 2.
9199                                                  */ );
9200         Vbar_cursor = Qnil;
9201
9202 #ifndef INHIBIT_REDISPLAY_HOOKS
9203         xxDEFVAR_LISP("pre-redisplay-hook", &Vpre_redisplay_hook        /*
9204 Function or functions to run before every redisplay.
9205                                                                          */ );
9206         Vpre_redisplay_hook = Qnil;
9207
9208         xxDEFVAR_LISP("post-redisplay-hook", &Vpost_redisplay_hook      /*
9209 Function or functions to run after every redisplay.
9210                                                                          */ );
9211         Vpost_redisplay_hook = Qnil;
9212 #endif                          /* INHIBIT_REDISPLAY_HOOKS */
9213
9214         DEFVAR_LISP("buffer-list-changed-hook", &Vbuffer_list_changed_hook      /*
9215 Function or functions to call when a frame's buffer list has changed.
9216 This is called during redisplay, before redisplaying each frame.
9217 Functions on this hook are called with one argument, the frame.
9218                                                                                  */ );
9219         Vbuffer_list_changed_hook = Qnil;
9220
9221         DEFVAR_INT("display-warning-tick", &display_warning_tick        /*
9222 Bump this to tell the C code to call `display-warning-buffer'
9223 at next redisplay.  You should not normally change this; the function
9224 `display-warning' automatically does this at appropriate times.
9225                                                                          */ );
9226         display_warning_tick = 0;
9227
9228         DEFVAR_BOOL("inhibit-warning-display", &inhibit_warning_display /*
9229 Non-nil means inhibit display of warning messages.
9230 You should *bind* this, not set it.  Any pending warning messages
9231 will be displayed when the binding no longer applies.
9232                                                                          */ );
9233         /* reset to 0 by startup.el after the splash screen has displayed.
9234            This way, the warnings don't obliterate the splash screen. */
9235         inhibit_warning_display = 1;
9236
9237         DEFVAR_LISP("window-size-change-functions", &Vwindow_size_change_functions      /*
9238 Not currently implemented.
9239 Functions called before redisplay, if window sizes have changed.
9240 The value should be a list of functions that take one argument.
9241 Just before redisplay, for each frame, if any of its windows have changed
9242 size since the last redisplay, or have been split or deleted,
9243 all the functions in the list are called, with the frame as argument.
9244                                                                                          */ );
9245         Vwindow_size_change_functions = Qnil;
9246
9247         DEFVAR_LISP("window-scroll-functions", &Vwindow_scroll_functions        /*
9248 Not currently implemented.
9249 Functions to call before redisplaying a window with scrolling.
9250 Each function is called with two arguments, the window
9251 and its new display-start position.  Note that the value of `window-end'
9252 is not valid when these functions are called.
9253                                                                                  */ );
9254         Vwindow_scroll_functions = Qnil;
9255
9256         DEFVAR_LISP("redisplay-end-trigger-functions", &Vredisplay_end_trigger_functions        /*
9257 See `set-window-redisplay-end-trigger'.
9258                                                                                                  */ );
9259         Vredisplay_end_trigger_functions = Qnil;
9260
9261         DEFVAR_BOOL("column-number-start-at-one", &column_number_start_at_one   /*
9262 *Non-nil means column display number starts at 1.
9263                                                                                  */ );
9264         column_number_start_at_one = 0;
9265 }
9266
9267 void specifier_vars_of_redisplay(void)
9268 {
9269         DEFVAR_SPECIFIER("left-margin-width", &Vleft_margin_width       /*
9270 *Width of left margin.
9271 This is a specifier; use `set-specifier' to change it.
9272                                                                          */ );
9273         Vleft_margin_width = Fmake_specifier(Qnatnum);
9274         set_specifier_fallback(Vleft_margin_width, list1(Fcons(Qnil, Qzero)));
9275         set_specifier_caching(Vleft_margin_width,
9276                               offsetof(struct window, left_margin_width),
9277                               some_window_value_changed,
9278                               offsetof(struct frame, left_margin_width),
9279                               margin_width_changed_in_frame, 0);
9280
9281         DEFVAR_SPECIFIER("right-margin-width", &Vright_margin_width     /*
9282 *Width of right margin.
9283 This is a specifier; use `set-specifier' to change it.
9284                                                                          */ );
9285         Vright_margin_width = Fmake_specifier(Qnatnum);
9286         set_specifier_fallback(Vright_margin_width, list1(Fcons(Qnil, Qzero)));
9287         set_specifier_caching(Vright_margin_width,
9288                               offsetof(struct window, right_margin_width),
9289                               some_window_value_changed,
9290                               offsetof(struct frame, right_margin_width),
9291                               margin_width_changed_in_frame, 0);
9292
9293         DEFVAR_SPECIFIER("minimum-line-ascent", &Vminimum_line_ascent   /*
9294 *Minimum ascent height of lines.
9295 This is a specifier; use `set-specifier' to change it.
9296                                                                          */ );
9297         Vminimum_line_ascent = Fmake_specifier(Qnatnum);
9298         set_specifier_fallback(Vminimum_line_ascent, list1(Fcons(Qnil, Qzero)));
9299         set_specifier_caching(Vminimum_line_ascent,
9300                               offsetof(struct window, minimum_line_ascent),
9301                               some_window_value_changed, 0, 0, 0);
9302
9303         DEFVAR_SPECIFIER("minimum-line-descent", &Vminimum_line_descent /*
9304 *Minimum descent height of lines.
9305 This is a specifier; use `set-specifier' to change it.
9306                                                                          */ );
9307         Vminimum_line_descent = Fmake_specifier(Qnatnum);
9308         set_specifier_fallback(Vminimum_line_descent,
9309                                list1(Fcons(Qnil, Qzero)));
9310         set_specifier_caching(Vminimum_line_descent,
9311                               offsetof(struct window, minimum_line_descent),
9312                               some_window_value_changed, 0, 0, 0);
9313
9314         DEFVAR_SPECIFIER("use-left-overflow", &Vuse_left_overflow       /*
9315 *Non-nil means use the left outside margin as extra whitespace when
9316 displaying 'whitespace or 'inside-margin glyphs.
9317 This is a specifier; use `set-specifier' to change it.
9318                                                                          */ );
9319         Vuse_left_overflow = Fmake_specifier(Qboolean);
9320         set_specifier_fallback(Vuse_left_overflow, list1(Fcons(Qnil, Qnil)));
9321         set_specifier_caching(Vuse_left_overflow,
9322                               offsetof(struct window, use_left_overflow),
9323                               some_window_value_changed, 0, 0, 0);
9324
9325         DEFVAR_SPECIFIER("use-right-overflow", &Vuse_right_overflow     /*
9326 *Non-nil means use the right outside margin as extra whitespace when
9327 displaying 'whitespace or 'inside-margin glyphs.
9328 This is a specifier; use `set-specifier' to change it.
9329                                                                          */ );
9330         Vuse_right_overflow = Fmake_specifier(Qboolean);
9331         set_specifier_fallback(Vuse_right_overflow, list1(Fcons(Qnil, Qnil)));
9332         set_specifier_caching(Vuse_right_overflow,
9333                               offsetof(struct window, use_right_overflow),
9334                               some_window_value_changed, 0, 0, 0);
9335
9336         DEFVAR_SPECIFIER("text-cursor-visible-p", &Vtext_cursor_visible_p       /*
9337 *Non-nil means the text cursor is visible (this is usually the case).
9338 This is a specifier; use `set-specifier' to change it.
9339                                                                                  */ );
9340         Vtext_cursor_visible_p = Fmake_specifier(Qboolean);
9341         set_specifier_fallback(Vtext_cursor_visible_p, list1(Fcons(Qnil, Qt)));
9342         set_specifier_caching(Vtext_cursor_visible_p,
9343                               offsetof(struct window, text_cursor_visible_p),
9344                               text_cursor_visible_p_changed, 0, 0, 0);
9345
9346 }