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