[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30. The Redisplay Mechanism

The redisplay mechanism is one of the most complicated sections of XEmacs, especially from a conceptual standpoint. This is doubly so because, unlike for the basic aspects of the Lisp interpreter, the computer science theories of how to efficiently handle redisplay are not well-developed.

When working with the redisplay mechanism, remember the Golden Rules of Redisplay:

  1. It Is Better To Be Correct Than Fast.
  2. Thou Shalt Not Run Elisp From Within Redisplay.
  3. It Is Better To Be Fast Than Not To Be.

[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.1 Critical Redisplay Sections

The following paragraphs are way out-of-date and inaccurate.

Within this section, we are defenseless and assume that the following cannot happen:

  1. garbage collection
  2. Lisp code evaluation
  3. frame size changes

We ensure (3) by calling hold_frame_size_changes(), which will cause any pending frame size changes to get put on hold till after the end of the critical section. (1) follows automatically if (2) is met. #### Unfortunately, there are some places where Lisp code can be called within this section. We need to remove them.

If Fsignal() is called during this critical section, we will abort().

If garbage collection is called during this critical section, we simply return. #### We should abort instead.

#### If a frame-size change does occur we should probably actually be preempting redisplay.

Begin up-to-date stuff


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.1.1 Nasty Bugs due to Reentrancy in Redisplay Structures handling QUIT

These are now fixed as of November 10, 2004.

Crash – reentrant regenerate_window()

Here is a crash I (ben) just got – November 9, 2004: It can sort of be reproduced by creating a bunch of frames, opening a bunch of large files (which may be fontlocking for awhile). and immediately start Alt-TAB-ing back and forth quickly and constantly scrolling up and down using the scrolling dial on your mouse.

 
Fatal error: assertion failed, file c:\xemacs\build\src\redisplay.c, line 5532,
!dy->locked

C backtrace:

assert_failed(const char * 0x012a4ff0 `string', int 5532, const char * 0x0127bea4 `string') line 3839
Dynarr_verify_mod_1(void * 0x023ad2b0, const char * 0x012a4ff0 `string', int 5532) line 1306 + 36 bytes
regenerate_window(window * 0x02f2ca88, long 40372, long 40372, int 2) line 5532 + 25 bytes
update_line_start_cache(window * 0x02f2ca88, long 40372, long 40401, long 40372, int 0) line 8543 + 19 bytes
point_in_line_start_cache(window * 0x02f2ca88, long 40372, int 0) line 7850 + 23 bytes
start_end_of_last_line(window * 0x02f2ca88, long 40372, int 1, int 1) line 8121 + 15 bytes
end_of_last_line_may_error(window * 0x02f2ca88, long 40372) line 8203 + 17 bytes
pixel_to_glyph_translation(frame * 0x02f2c900, int 291, int 317, int * 0x0082bb04, int * 0x0082bb00, int * 0x0082bafc, int * 0x0082baf8, window * * 0x0082bae8, long * 0x0082baf4, long * 0x0082baf0, long * 0x0082baec, long * 0x0082bb10, long * 0x0082bb0c) line 9336 + 32 bytes
mswindows_handle_mousewheel_event(long 49465600, int 0, int -240, tagPOINTS {...}) line 360 + 82 bytes
mswindows_wnd_proc(HWND__ * 0x00260a42, unsigned int 522, unsigned int 4279238656, long 29885130) line 3561 + 36 bytes
intercepted_wnd_proc(HWND__ * 0x00260a42, unsigned int 522, unsigned int 4279238656, long 29885130) line 2376
USER32! 77e11ef0()
USER32! 77e1204c()
USER32! 77e121af()
mswindows_drain_windows_queue(int 0) line 1330 + 9 bytes
emacs_mswindows_drain_queue() line 1339 + 7 bytes
event_stream_drain_queue() line 1785
event_stream_quit_p() line 1893
check_quit() line 938
check_what_happened() line 459
internal_equal(long 22180468, long 22180468, int 0) line 2823 + 14 bytes
update_image_instance(long 83498640, long 22180468) line 2121 + 18 bytes
image_instantiate(long 21418616, long 20663624, long 54932896, long 22180468, long 3) line 3403 + 13 bytes
va_call_trapping_problems_1(void * 0x0082cf94) line 5220 + 221 bytes
call_trapping_problems_2(long 83160440) line 4867 + 13 bytes
call_with_condition_handler(long (long, long, long)* 0x010cc4c0 flagged_a_squirmer(long, long, long), long 83160440, long (long)* 0x010cc440 call_trapping_problems_2(long), long 83160440) line 2129 + 7 bytes
call_trapping_problems_1(long 83160440) line 4874 + 23 bytes
internal_catch(long 21399864, long (long)* 0x010cc490 call_trapping_problems_1(long), long 83160440, int * volatile 0x0082ce4c, long * volatile 0x0082ce54) line 1527 + 7 bytes
call_trapping_problems(long 20908160, const char * 0x00000000, int 98315, call_trapping_problems_result * 0x00000000, long (void *)* 0x010cca30 va_call_trapping_problems_1(void *), void * 0x0082cf94) line 5147 + 32 bytes
call_with_suspended_errors(long (void)* 0x011448c0 image_instantiate(long, long, long, long, long), long 20663624, long 20908160, _error_behavior_struct_ {...}, int 5) line 5314 + 26 bytes
specifier_instance_from_inst_list(long 21418616, long 20663624, long 54932896, long 21673760, _error_behavior_struct_ {...}, int 1, long 3) line 2501 + 54 bytes
specifier_instance(long 21418616, long 20663624, long 54932896, _error_behavior_struct_ {...}, int 1, int 0, long 3) line 2614 + 64 bytes
glyph_image_instance(long 22692176, long 54932896, _error_behavior_struct_ {...}, int 1) line 3955 + 31 bytes
add_glyph_rune(position_redisplay_data_type * 0x0082d52c, glyph_block * 0x0082d454, int 0, int 0, glyph_cachel * 0x04f4e518) line 1972 + 26 bytes
create_text_block(window * 0x034635a0, display_line * 0x033bfb28, long 29860, prop_block_dynarr * * 0x0082d7b8, int 2) line 2827 + 30 bytes
generate_display_line(window * 0x034635a0, display_line * 0x033bfb28, int 1, long 29860, prop_block_dynarr * * 0x0082d7b8, int 2) line 979 + 38 bytes
regenerate_window(window * 0x034635a0, long 29860, long 25012, int 2) line 5607 + 30 bytes
update_line_start_cache(window * 0x034635a0, long 25012, long 28767, long 25012, int 0) line 8614 + 19 bytes
point_in_line_start_cache(window * 0x034635a0, long 25012, int 0) line 7850 + 23 bytes
start_end_of_last_line(window * 0x034635a0, long 25012, int 1, int 0) line 8121 + 15 bytes
end_of_last_line(window * 0x034635a0, long 25012) line 8197 + 17 bytes
Fwindow_end(long 54932896, long 20926544) line 1848 + 13 bytes
Ffuncall(int 3, long * 0x0082dbb8) line 3841 + 93 bytes
execute_optimized_program(const unsigned char * 0x032ceee8, int 7, long * 0x03289f40) line 823 + 16 bytes
funcall_compiled_function(long 52991916, int 1, long * 0x0082dfb0) line 3454 + 85 bytes
Ffuncall(int 2, long * 0x0082dfac) line 3880 + 17 bytes
execute_optimized_program(const unsigned char * 0x02f667d8, int 6, long * 0x01558748) line 823 + 16 bytes
funcall_compiled_function(long 22579576, int 3, long * 0x0082e3ac) line 3454 + 85 bytes
Ffuncall(int 4, long * 0x0082e3a8) line 3880 + 17 bytes
execute_optimized_program(const unsigned char * 0x03209c98, int 5, long * 0x03288c68) line 823 + 16 bytes
funcall_compiled_function(long 51656320, int 1, long * 0x0082e7a4) line 3454 + 85 bytes
Ffuncall(int 2, long * 0x0082e7a0) line 3880 + 17 bytes
execute_optimized_program(const unsigned char * 0x0082e9ec, int 4, long * 0x03224990) line 823 + 16 bytes
Fbyte_code(long 37927380, long 52578688, long 9) line 2564 + 70 bytes
Feval(long 51505420) line 3601 + 187 bytes
internal_catch(long 51959412, long (long)* 0x010c6f40 Feval(long), long 51505420, int * volatile 0x00000000, long * volatile 0x00000000) line 1527 + 7 bytes
execute_rare_opcode(long * 0x0082eee8, const unsigned char * 0x03248365, Opcode Bcatch) line 1380 + 24 bytes
execute_optimized_program(const unsigned char * 0x03248340, int 2, long * 0x02f3c0a0) line 715 + 17 bytes
funcall_compiled_function(long 51656276, int 0, long * 0x0082f444) line 3454 + 85 bytes
Ffuncall(int 1, long * 0x0082f440) line 3880 + 17 bytes
run_hook_with_args_in_buffer(buffer * 0x04ee9060, int 1, long * 0x0082f440, run_hooks_condition RUN_HOOKS_TO_COMPLETION) line 4361 + 13 bytes
run_hook_with_args(int 1, long * 0x0082f440, run_hooks_condition RUN_HOOKS_TO_COMPLETION) line 4374 + 23 bytes
run_hook(long 51959028) line 4443 + 13 bytes
safe_run_hook_trapping_problems_1(void * 0x013c73c0) line 5517 + 9 bytes
call_trapping_problems_2(long 83157920) line 4867 + 13 bytes
call_with_condition_handler(long (long, long, long)* 0x010cc4c0 flagged_a_squirmer(long, long, long), long 83157920, long (long)* 0x010cc440 call_trapping_problems_2(long), long 83157920) line 2129 + 7 bytes
call_trapping_problems_1(long 83157920) line 4874 + 23 bytes
internal_catch(long 21399864, long (long)* 0x010cc490 call_trapping_problems_1(long), long 83157920, int * volatile 0x0082f700, long * volatile 0x0082f708) line 1527 + 7 bytes
call_trapping_problems(long 20925944, const char * 0x00000000, int 131235, call_trapping_problems_result * 0x0082f830, long (void *)* 0x010cd990 safe_run_hook_trapping_problems_1(void *), void * 0x013c73c0) line 5147 + 32 bytes
safe_run_hook_trapping_problems(long 20741312, long 20739008, int 160) line 5543 + 36 bytes
run_pre_idle_hook() line 2084 + 24 bytes
redisplay() line 7224
Fnext_event(long 37363732, long 20928056) line 2263
Fcommand_loop_1() line 600 + 15 bytes
command_loop_1(long 20928056) line 512
condition_case_1(long 20925944, long (long)* 0x01096a80 command_loop_1(long), long 20928056, long (long, long)* 0x01096630 cmd_error(long, long), long 20928056) line 1918 + 7 bytes
command_loop_3() line 262 + 35 bytes
command_loop_2(long 20928056) line 277
internal_catch(long 20683712, long (long)* 0x010967a0 command_loop_2(long), long 20928056, int * volatile 0x00000000, long * volatile 0x00000000) line 1527 + 7 bytes
initial_command_loop(long 20928056) line 313 + 28 bytes
xemacs_21_5_b18_i586_pc_win32(int 1, unsigned short * * 0x0082fed0, unsigned short * * 0x00000000, int 0) line 2551
main(int 1, char * * 0x00e52610, char * * 0x00e52bb0) line 2992
mainCRTStartup() line 338 + 17 bytes
KERNEL32! 7c59893d()

Lisp backtrace:

  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (catch #<INTERNAL OBJECT (XEmacs bug?) (opaque, size=0) 0x1468938> ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  window-end(#<window on "signal.c<2>" 0x5e4a> t)
  # (unwind-protect ...)
  # bind (buffer we-are-screwed check-text-props window)
  lazy-lock-fontify-window(#<window on "signal.c<2>" 0x5e4a>)
  # bind (walk-windows-current walk-windows-start arg which-devices which-frames
 minibuf function)
  walk-windows(lazy-lock-fontify-window no-minibuf #<mswindows-frame "emacs" 0x5
e49>)
  # (unwind-protect ...)
  # bind (ssf65112 tick frame)
  lazy-lock-maybe-fontify-frame(#<mswindows-frame "emacs" 0x5e49>)
  # bind (frame starting-frame)
  byte-code("..." [starting-frame frame selected-frame frame-visible-p frame-min
ibuffer-only-p next-frame visible-nomini throw lazy-lock-frame-loop-done t lazy-
lock-maybe-fontify-frame] 4)
  # (catch lazy-lock-frame-loop-done ...)
  lazy-lock-pre-idle-fontify-windows()
  # (unwind-protect ...)
  # (catch #<INTERNAL OBJECT (XEmacs bug?) (opaque, size=0) 0x1468938> ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  (next-event "[internal]")
  # (condition-case ... . error)
  # (catch top-level ...)

Another Lisp trace of a similar situation (C stack trace not available):

 
Fatal error: assertion failed, file c:\xemacs\build\src\redisplay.c, line 5532,
!dy->locked

Lisp backtrace follows:

  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  scrollbar-page-down((#<window on "*grep*" 0x1a5f9>))
  (dispatch-event "[internal]")
  # (unwind-protect ...)
  # (catch #<INTERNAL OBJECT (XEmacs bug?) (opaque, size=0) 0x1468270> ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # (catch #<INTERNAL OBJECT (XEmacs bug?) (opaque, size=0) 0x1468270> ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  window-end(#<window on "*grep*" 0x1a5f9> t)
  # (unwind-protect ...)
  # bind (buffer we-are-screwed check-text-props window)
  lazy-lock-fontify-window(#<window on "*grep*" 0x1a5f9>)
  # bind (walk-windows-current walk-windows-start arg which-devices which-frames
 minibuf function)
  walk-windows(lazy-lock-fontify-window no-minibuf #<mswindows-frame "emacs" 0x1
9f64>)
  # (unwind-protect ...)
  # bind (ssf65112 tick frame)
  lazy-lock-maybe-fontify-frame(#<mswindows-frame "emacs" 0x19f64>)
  # bind (frame starting-frame)
  byte-code("..." [starting-frame frame selected-frame frame-visible-p frame-min
ibuffer-only-p next-frame visible-nomini throw lazy-lock-frame-loop-done t lazy-
lock-maybe-fontify-frame] 4)
  # (catch lazy-lock-frame-loop-done ...)
  lazy-lock-pre-idle-fontify-windows()
  # (unwind-protect ...)
  # (catch #<INTERNAL OBJECT (XEmacs bug?) (opaque, size=0) 0x1468270> ...)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  # (unwind-protect ...)
  # (unwind-protect ...)
  # bind (inhibit-quit)
  (next-event "[internal]")
  # (condition-case ... . error)
  # (catch top-level ...)

Crash – reentrant generate_displayable_area()

Original code said [Tricky tricky tricky. generate_displayable_area() can (could) be called reentrantly, and redisplay is not prepared to handle this:].

assert_failed(const char * 0x0129c8c8 ‘string’, int 5328, const char * 0x01274068 ‘string’) line 3620 Dynarr_verify_mod_1(void * 0x0250f228, const char * 0x0129c8c8 ‘string’, int 5328) line 1256 + 36 bytes generate_displayable_area(window * 0x02480028, long 38776292, int 0, int 0, int 265, int 169, display_line_dynarr * 0x0250f228, long 0, int 2) line 5328 + 25 bytes output_gutter(frame * 0x0228ad90, gutter_pos TOP_GUTTER, int 1) line 409 + 69 bytes redraw_exposed_gutter(frame * 0x0228ad90, gutter_pos TOP_GUTTER, int 8, int 23, int 249, int 127) line 687 + 15 bytes redraw_exposed_gutters(frame * 0x0228ad90, int 8, int 23, int 249, int 127) line 703 + 29 bytes mswindows_redraw_exposed_area(frame * 0x0228ad90, int 8, int 23, int 249, int 127) line 862 + 25 bytes mswindows_handle_paint(frame * 0x0228ad90) line 2176 + 25 bytes mswindows_wnd_proc(HWND__ * 0x001003e2, unsigned int 15, unsigned int 0, long 0) line 3233 + 45 bytes intercepted_wnd_proc(HWND__ * 0x001003e2, unsigned int 15, unsigned int 0, long 0) line 2488 USER32! 77e3a244() USER32! 77e14730() USER32! 77e1558a() NTDLL! KiUserCallbackDispatcher@12 + 19 bytes USER32! 77e14680() USER32! 77e1a792() qxeIsDialogMessage(HWND__ * 0x001003e2, tagMSG * 0x0082a93c {msg=0x0000000f wp=0x00000000 lp=0x00000000}) line 2298 + 14 bytes mswindows_is_dialog_msg(tagMSG * 0x0082a93c {msg=0x0000000f wp=0x00000000 lp=0x00000000}) line 165 + 13 bytes mswindows_drain_windows_queue(int 0) line 1282 + 9 bytes emacs_mswindows_drain_queue() line 1326 + 7 bytes event_stream_drain_queue() line 1887 event_stream_quit_p() line 1992 check_quit() line 993 unbind_to_hairy(int 35) line 5963 unbind_to_1(int 35, long 20888208) line 5945 + 200 bytes specifier_instance_from_inst_list(long 21379344, long 38135616, long 36220304, long 20888208, _error_behavior_struct_ {...}, int 1, long 3) line 2522 + 16 bytes specifier_instance(long 21379344, long 38135616, long 36220304, _error_behavior_struct_ {...}, int 1, int 0, long 3) line 2625 + 65 bytes specifier_instance_no_quit(long 21379344, long 38135616, long 36220304, _error_behavior_struct_ {...}, int 0, long 1) line 2658 + 31 bytes face_property_matching_instance(long 22612340, long 20860632, long 22530956, long 36220304, _error_behavior_struct_ {...}, int 0, long 1) line 565 + 48 bytes ensure_face_cachel_contains_charset(face_cachel * 0x0082b014, long 36220304, long 22530956) line 1104 + 35 bytes update_face_cachel_data(face_cachel * 0x0082b014, long 36220304, long 22612340) line 1304 + 19 bytes query_string_geometry(long 21110576, long 22612340, int * 0x00000000, int * 0x0082b5b4, int * 0x00000000, long 38852960) line 2370 + 23 bytes mswindows_widget_query_string_geometry(long 21110576, long 22612340, int * 0x0082b5b8, int * 0x0082b5b4, long 38852960) line 2914 + 25 bytes widget_query_string_geometry(long 21110576, long 22612340, int * 0x0082b5b8, int * 0x0082b5b4, long 38852960) line 514 + 32 bytes edit_field_query_geometry(long 38857648, int * 0x0082b7b4, int * 0x0082b7b8, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38852960) line 920 + 390 bytes widget_query_geometry(long 38857648, int * 0x0082b7b4, int * 0x0082b7b8, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38852960) line 567 + 26 bytes image_instance_query_geometry(long 38857648, int * 0x0082b7b4, int * 0x0082b7b8, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38852960) line 2015 + 26 bytes glyph_query_geometry(long 38853384, int * 0x0082b7b4, int * 0x0082b7b8, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38852960) line 4197 + 25 bytes layout_query_geometry(long 38852960, int * 0x0082b9cc, int * 0x0082b9d0, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38404624) line 1351 + 25 bytes widget_query_geometry(long 38852960, int * 0x0082b9cc, int * 0x0082b9d0, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38404624) line 567 + 26 bytes image_instance_query_geometry(long 38852960, int * 0x0082b9cc, int * 0x0082b9d0, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38404624) line 2015 + 26 bytes glyph_query_geometry(long 38537976, int * 0x0082b9cc, int * 0x0082b9d0, image_instance_geometry IMAGE_DESIRED_GEOMETRY, long 38404624) line 4197 + 25 bytes layout_layout(long 38404624, int 265, int 156, int -2, int -2, long 38273064) line 1468 + 23 bytes widget_layout(long 38404624, int 265, int 156, int -2, int -2, long 38273064) line 626 + 30 bytes image_instance_layout(long 38404624, int 265, int 156, int -2, int -2, long 38273064) line 2102 + 51 bytes glyph_ascent(long 38404624, long 38273064) line 4009 + 21 bytes update_glyph_cachel_data(window * 0x02480028, long 36201168, glyph_cachel * 0x0248c3d8) line 4272 + 13 bytes get_glyph_cachel_index(window * 0x02480028, long 36201168) line 4306 + 17 bytes add_glyph_rune(position_redisplay_data_type * 0x0082bf2c, glyph_block * 0x024bd028, int 0, int 0, glyph_cachel * 0x00000000) line 1800 + 15 bytes add_glyph_runes(position_redisplay_data_type * 0x0082bf2c, int 0) line 2085 + 31 bytes create_string_text_block(window * 0x02480028, long 38776292, display_line * 0x02514500, long 0, prop_block_dynarr * * 0x0082c13c, int 2) line 4907 + 14 bytes generate_string_display_line(window * 0x02480028, long 38776292, display_line * 0x02514500, long 0, prop_block_dynarr * * 0x0082c13c, int 2) line 5293 + 29 bytes generate_displayable_area(window * 0x02480028, long 38776292, int 0, int 0, int 265, int 169, display_line_dynarr * 0x0250f228, long 0, int 2) line 5372 + 29 bytes output_gutter(frame * 0x0228ad90, gutter_pos TOP_GUTTER, int 0) line 409 + 69 bytes update_frame_gutters(frame * 0x0228ad90) line 639 + 15 bytes redisplay_frame(frame * 0x0228ad90, int 1) line 6792 + 9 bytes redisplay_device(device * 0x0171df00, int 1) line 6911 + 11 bytes redisplay_without_hooks() line 6957 + 11 bytes redisplay_no_pre_idle_hook() line 7029 redisplay() line 7011 mswindows_wnd_proc(HWND__ * 0x001003e2, unsigned int 5, unsigned int 0, long 10223881) line 3424 intercepted_wnd_proc(HWND__ * 0x001003e2, unsigned int 5, unsigned int 0, long 10223881) line 2488 USER32! 77e3a244() USER32! 77e16362() USER32! 77e14c1a() USER32! 77e1dd30() mswindows_wnd_proc(HWND__ * 0x001003e2, unsigned int 71, unsigned int 0, long 8578308) line 3926 + 21 bytes intercepted_wnd_proc(HWND__ * 0x001003e2, unsigned int 71, unsigned int 0, long 8578308) line 2488 USER32! 77e3a244() USER32! 77e14730() USER32! 77e174b4() NTDLL! KiUserCallbackDispatcher@12 + 19 bytes mswindows_set_frame_size(frame * 0x0228ad90, int 265, int 156) line 355 internal_set_frame_size(frame * 0x0228ad90, int 265, int 156, int 0) line 2754 + 24 bytes Fset_frame_displayable_pixel_size(long 36220304, long 531, long 313, long 20888208) line 3004 + 32 bytes Ffuncall(int 4, long * 0x0082e778) line 3844 + 168 bytes execute_optimized_program(const unsigned char * 0x02286e48, int 40, long * 0x01529b80) line 609 + 16 bytes funcall_compiled_function(long 22433308, int 0, long * 0x0082ec08) line 3452 + 85 bytes Ffuncall(int 1, long * 0x0082ec04) line 3883 + 17 bytes execute_optimized_program(const unsigned char * 0x02286d40, int 6, long * 0x01548ddc) line 609 + 16 bytes funcall_compiled_function(long 22505864, int 11, long * 0x0082f00c) line 3452 + 85 bytes Ffuncall(int 12, long * 0x0082f008) line 3883 + 17 bytes execute_optimized_program(const unsigned char * 0x02503e38, int 47, long * 0x0152dc48) line 609 + 16 bytes funcall_compiled_function(long 22436784, int 0, long * 0x0082f534) line 3452 + 85 bytes Ffuncall(int 1, long * 0x0082f530) line 3883 + 17 bytes apply1(long 22436784, long 20888208) line 4458 + 11 bytes Fcall_interactively(long 20742816, long 20888208, long 20888208) line 460 + 13 bytes Ffuncall(int 2, long * 0x0082f8ec) line 3844 + 127 bytes call1(long 20854392, long 20742816) line 4489 + 11 bytes execute_command_event(command_builder * 0x01798f98, long 24439276) line 4198 + 69 bytes Fdispatch_event(long 24439276) line 4569 + 13 bytes Fcommand_loop_1() line 569 + 9 bytes command_loop_1(long 20888208) line 489 condition_case_1(long 20886024, long (long)* 0x010955a0 command_loop_1(long), long 20888208, long (long, long)* 0x01095150 cmd_error(long, long), long 20888208) line 1917 + 7 bytes command_loop_3() line 251 + 35 bytes command_loop_2(long 20888208) line 264 internal_catch(long 20650992, long (long)* 0x010952c0 command_loop_2(long), long 20888208, int * volatile 0x00000000, long * volatile 0x00000000) line 1527 + 7 bytes initial_command_loop(long 20888208) line 300 + 28 bytes xemacs_21_5_b10_i586_pc_win32(int 1, char * * 0x00e52620, char * * 0x00e52bb0, int 0) line 2356 main(int 1, char * * 0x00e52620, char * * 0x00e52bb0) line 2733 mainCRTStartup() line 338 + 17 bytes KERNEL32! 77ea847c()


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.2 Line Start Cache

The traditional scrolling code in Emacs breaks in a variable height world. It depends on the key assumption that the number of lines that can be displayed at any given time is fixed. This led to a complete separation of the scrolling code from the redisplay code. In order to fully support variable height lines, the scrolling code must actually be tightly integrated with redisplay. Only redisplay can determine how many lines will be displayed on a screen for any given starting point.

What is ideally wanted is a complete list of the starting buffer position for every possible display line of a buffer along with the height of that display line. Maintaining such a full list would be very expensive. We settle for having it include information for all areas which we happen to generate anyhow (i.e. the region currently being displayed) and for those areas we need to work with.

In order to ensure that the cache accurately represents what redisplay would actually show, it is necessary to invalidate it in many situations. If the buffer changes, the starting positions may no longer be correct. If a face or an extent has changed then the line heights may have altered. These events happen frequently enough that the cache can end up being constantly disabled. With this potentially constant invalidation when is the cache ever useful?

Even if the cache is invalidated before every single usage, it is necessary. Scrolling often requires knowledge about display lines which are actually above or below the visible region. The cache provides a convenient light-weight method of storing this information for multiple display regions. This knowledge is necessary for the scrolling code to always obey the First Golden Rule of Redisplay.

If the cache already contains all of the information that the scrolling routines happen to need so that it doesn’t have to go generate it, then we are able to obey the Third Golden Rule of Redisplay. The first thing we do to help out the cache is to always add the displayed region. This region had to be generated anyway, so the cache ends up getting the information basically for free. In those cases where a user is simply scrolling around viewing a buffer there is a high probability that this is sufficient to always provide the needed information. The second thing we can do is be smart about invalidating the cache.

TODO—Be smart about invalidating the cache. Potential places:

In case you’re wondering, the Second Golden Rule of Redisplay is not applicable.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.3 Redisplay Piece by Piece

Redisplay is complex and not very well documented. Chuck Thompson no longer works on XEmacs so this section is my [presumably Ben’s] take on the workings of redisplay.

Redisplay happens in three phases:

  1. Determine desired display in area that needs redisplay.

    Implemented in redisplay.c

  2. Compare desired display with current display

    Implemented in redisplay-output.c

  3. Output changes

    Implemented in redisplay-output.c, redisplay-x.c, redisplay-msw.c and redisplay-tty.c

Steps 1 and 2 are device-independent and relatively complex. Step 3 is mostly device-dependent.

Determining the desired display

Display attributes are stored in display_line structures. Each display_line consists of a set of display_block’s and each display_block contains a number of rune’s. Generally dynarr’s of display_line’s are held by each window representing the current display and the desired display.

The display_line structures are tightly tied to buffers which presents a problem for redisplay as this connection is bogus for the modeline. Hence the display_line generation routines are duplicated for generating the modeline. This means that the modeline display code has many bugs that the standard redisplay code does not. Perhaps the modeline redisplay could be unified with gutter redisplay (see below).

The guts of display_line generation are in create_text_block, which creates a single display line for the desired locale. This incrementally parses the characters on the current line and generates redisplay structures for each.

Gutter redisplay is different. Because the data to display is stored in a string we cannot use create_text_block. Instead we use create_text_string_block which performs the same function as create_text_block but for strings. Many of the complexities of create_text_block to do with cursor handling and selective display have been removed.

In the following, create_text_block only will be described, so keep in mind in the fact that modeline and gutter redisplay are somewhat different.

create_text_block takes a struct window *, the index of a line in the text (a Bytebpos) and a struct display_line *, as well as two arguments prop and type (as yet undocumented). Given the window, it can derive the relevant buffer, and use the Bytebpos to find the line of text. It then walks over the characters in the text and regenerates the display line information for each.

create_text_block calls out to extent_fragment_update to get information about faces (fonts and colors), which are represented as a face_index, an index into a table of merged faces. Faces must be merged because (1) a face may inherit properties from their parents and (2) faces may be only partially specified, in which case redisplay must fall back to faces associated with extents earlier in the extent order (see section Extent Ordering). Since getting complete information about a face involves instantantiating many specifiers, we keep a cache of this information, and a face_index is an index into the cache.

extent_fragment_update calls out to get_extent_fragment_face_cache_index, which in turn calls merge_face_cachel_data on each relevant face. merge_face_cachel_data is straightforward, except for font handling. In the case of fonts, the legacy XLFD model has a different font for each Mule charset (in fact, both the XLFD model of I18N and that of Mule are derived from the same root, ISO 2022, and so mesh well—or as well as anything based on ISO 2022 can). This means that merge_face_cachel_data has to iterate over the list of Mule charsets, and update the font for each one.

create_text_block is not responsible for creating face cachels. That is done by redisplay_output_layout, redisplay_text_width_string or redisplay_text_width_ichar_string, via ensure_face_cachel_complete, with the actual work being done by ensure_face_cachel_contains_charset.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.4 Modules for the Redisplay Mechanism

 
redisplay-output.c’
‘redisplay-msw.c’
‘redisplay-tty.c’
‘redisplay-x.c’
‘redisplay.c’
‘redisplay.h

These files provide the redisplay mechanism. As with many other subsystems in XEmacs, there is a clean separation between the general and device-specific support.

redisplay.c’ contains the bulk of the redisplay engine. These functions update the redisplay structures (which describe how the screen is to appear) to reflect any changes made to the state of any displayable objects (buffer, frame, window, etc.) since the last time that redisplay was called. These functions are highly optimized to avoid doing more work than necessary (since redisplay is called extremely often and is potentially a huge time sink), and depend heavily on notifications from the objects themselves that changes have occurred, so that redisplay doesn’t explicitly have to check each possible object. The redisplay mechanism also contains a great deal of caching to further speed things up; some of this caching is contained within the various displayable objects.

redisplay-output.c’ goes through the redisplay structures and converts them into calls to device-specific methods to actually output the screen changes.

redisplay-x.c’ and ‘redisplay-tty.c’ are two implementations of these redisplay output methods, for X frames and TTY frames, respectively.

 
indent.c

This module contains various functions and Lisp primitives for converting between buffer positions and screen positions. These functions call the redisplay mechanism to do most of the work, and then examine the redisplay structures to get the necessary information. This module needs work.

 
termcap.c’
‘terminfo.c’
‘tparam.c

These files contain functions for working with the termcap (BSD-style) and terminfo (System V style) databases of terminal capabilities and escape sequences, used when XEmacs is displaying in a TTY.

 
cm.c’
‘cm.h

These files provide some miscellaneous TTY-output functions and should probably be merged into ‘redisplay-tty.c’.


[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

30.5 Modules for other Display-Related Lisp Objects

 
faces.c’
‘faces.h
 
bitmaps.h’
‘glyphs-eimage.c’
‘glyphs-msw.c’
‘glyphs-msw.h’
‘glyphs-widget.c’
‘glyphs-x.c’
‘glyphs-x.h’
‘glyphs.c’
‘glyphs.h
 
fontcolor-msw.c’
‘fontcolor-msw.h’
‘fontcolor-tty.c’
‘fontcolor-tty.h’
‘fontcolor-x.c’
‘fontcolor-x.h’
‘fontcolor.c’
‘fontcolor.h
 
menubar-msw.c’
‘menubar-msw.h’
‘menubar-x.c’
‘menubar.c’
‘menubar.h
 
scrollbar-msw.c’
‘scrollbar-msw.h’
‘scrollbar-x.c’
‘scrollbar-x.h’
‘scrollbar.c’
‘scrollbar.h
 
toolbar-msw.c’
‘toolbar-x.c’
‘toolbar.c’
‘toolbar.h
 
font-lock.c

This file provides C support for syntax highlighting—i.e. highlighting different syntactic constructs of a source file in different colors, for easy reading. The C support is provided so that this is fast.


[ << ] [ >> ]           [Top] [Contents] [Index] [ ? ]

This document was generated by Aidan Kehoe on December 27, 2016 using texi2html 1.82.