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

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