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