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