; * src/xdisp.c: Improve the introductory commentary.

This commit is contained in:
Eli Zaretskii 2020-04-24 18:09:20 +03:00
parent a92ca1f177
commit 369761b36d

View file

@ -30,8 +30,9 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
Updating the display is triggered by the Lisp interpreter when it Updating the display is triggered by the Lisp interpreter when it
decides it's time to do it. This is done either automatically for decides it's time to do it. This is done either automatically for
you as part of the interpreter's command loop or as the result of you as part of the interpreter's command loop or as the result of
calling Lisp functions like `sit-for'. The C function `redisplay' calling Lisp functions like `sit-for'. The C function
in xdisp.c is the only entry into the inner redisplay code. `redisplay_internal' in xdisp.c is the only entry into the inner
redisplay code.
The following diagram shows how redisplay code is invoked. As you The following diagram shows how redisplay code is invoked. As you
can see, Lisp calls redisplay and vice versa. can see, Lisp calls redisplay and vice versa.
@ -89,7 +90,15 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
second glyph matrix is constructed, the so called `desired glyph second glyph matrix is constructed, the so called `desired glyph
matrix' or short `desired matrix'. Current and desired matrix are matrix' or short `desired matrix'. Current and desired matrix are
then compared to find a cheap way to update the display, e.g. by then compared to find a cheap way to update the display, e.g. by
reusing part of the display by scrolling lines. reusing part of the display by scrolling lines. The actual update
of the display of each window by comparing the desired and the
current matrix is done by `update_window', which calls functions
which draw to the glass (those functions are specific to the type
of the window's frame: X, w32, NS, etc.).
Once the display of a window on the glass has been updated, its
desired matrix is used to update the corresponding rows of the
current matrix, and then the desired matrix is discarded.
You will find a lot of redisplay optimizations when you start You will find a lot of redisplay optimizations when you start
looking at the innards of redisplay. The overall goal of all these looking at the innards of redisplay. The overall goal of all these
@ -119,13 +128,13 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
. try_window . try_window
This function performs the full redisplay of a single window This function performs the full, unoptimized, redisplay of a
assuming that its fonts were not changed and that the cursor single window assuming that its fonts were not changed and that
will not end up in the scroll margins. (Loading fonts requires the cursor will not end up in the scroll margins. (Loading
re-adjustment of dimensions of glyph matrices, which makes this fonts requires re-adjustment of dimensions of glyph matrices,
method impossible to use.) which makes this method impossible to use.)
These optimizations are tried in sequence (some can be skipped if The optimizations are tried in sequence (some can be skipped if
it is known that they are not applicable). If none of the it is known that they are not applicable). If none of the
optimizations were successful, redisplay calls redisplay_windows, optimizations were successful, redisplay calls redisplay_windows,
which performs a full redisplay of all windows. which performs a full redisplay of all windows.
@ -145,38 +154,62 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
Desired matrices. Desired matrices.
Desired matrices are always built per Emacs window. The function Desired matrices are always built per Emacs window. It is
`display_line' is the central function to look at if you are important to know that a desired matrix is in general "sparse": it
interested. It constructs one row in a desired matrix given an only has some of the glyph rows "enabled". This is because
redisplay tries to optimize its work, and thus only generates
glyphs for rows that need to be updated on the screen. Rows that
don't need to be updated are left "disabled", and their contents
should be ignored.
The function `display_line' is the central function to look at if
you are interested in how the rows of the desired matrix are
produced. It constructs one row in a desired matrix given an
iterator structure containing both a buffer position and a iterator structure containing both a buffer position and a
description of the environment in which the text is to be description of the environment in which the text is to be
displayed. But this is too early, read on. displayed. But this is too early, read on.
Glyph rows.
A glyph row is an array of `struct glyph', where each glyph element
describes a "display element" to be shown on the screen. More
accurately, a glyph row can have up to 3 different arrays of
glyphs: one each for every display margins, and one for the "text
area", where buffer text is displayed. The text-area glyph array
is always present, whereas the arrays for the marginal areas are
present (non-empty) only if the corresponding display margin is
shown in the window. If the glyph array for a marginal area is not
present its beginning and end coincide, i.e. such arrays are
actually empty (they contain no glyphs). Frame glyph matrics, used
on text-mode terminals (see below) never have marginal areas, they
treat the entire frame-wide row of glyphs as a single large "text
area".
Iteration over buffer and strings. Iteration over buffer and strings.
Characters and pixmaps displayed for a range of buffer text depend Characters and pixmaps displayed for a range of buffer text depend
on various settings of buffers and windows, on overlays and text on various settings of buffers and windows, on overlays and text
properties, on display tables, on selective display. The good news properties, on display tables, on selective display. The good news
is that all this hairy stuff is hidden behind a small set of is that all this hairy stuff is hidden behind a small set of
interface functions taking an iterator structure (struct it) interface functions taking an iterator structure (`struct it')
argument. argument.
Iteration over things to be displayed is then simple. It is Iteration over things to be displayed is then simple. It is
started by initializing an iterator with a call to init_iterator, started by initializing an iterator with a call to `init_iterator',
passing it the buffer position where to start iteration. For passing it the buffer position where to start iteration. For
iteration over strings, pass -1 as the position to init_iterator, iteration over strings, pass -1 as the position to `init_iterator',
and call reseat_to_string when the string is ready, to initialize and call `reseat_to_string' when the string is ready, to initialize
the iterator for that string. Thereafter, calls to the iterator for that string. Thereafter, calls to
get_next_display_element fill the iterator structure with relevant `get_next_display_element' fill the iterator structure with
information about the next thing to display. Calls to relevant information about the next thing to display. Calls to
set_iterator_to_next move the iterator to the next thing. `set_iterator_to_next' move the iterator to the next thing.
Besides this, an iterator also contains information about the Besides this, an iterator also contains information about the
display environment in which glyphs for display elements are to be display environment in which glyphs for display elements are to be
produced. It has fields for the width and height of the display, produced. It has fields for the width and height of the display,
the information whether long lines are truncated or continued, a the information whether long lines are truncated or continued, a
current X and Y position, and lots of other stuff you can better current X and Y position, the face currently in effect, and lots of
see in dispextern.h. other stuff you can better see in dispextern.h.
The "stop position". The "stop position".
@ -184,57 +217,62 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
infrequently. These include the face of the characters, whether infrequently. These include the face of the characters, whether
text is invisible, the object (buffer or display or overlay string) text is invisible, the object (buffer or display or overlay string)
being iterated, character composition info, etc. For any given being iterated, character composition info, etc. For any given
buffer or string position, the sources of information that buffer or string position, the sources of information that affects
affects the display can be determined by calling the appropriate the display can be determined by calling the appropriate
primitives, such as Fnext_single_property_change, but both these primitives, such as `Fnext_single_property_change', but both these
calls and the processing of their return values is relatively calls and the processing of their return values is relatively
expensive. To optimize redisplay, the display engine checks these expensive. To optimize redisplay, the display engine checks these
sources of display information only when needed. To that end, it sources of display information only when needed, not for every
always maintains the position of the next place where it must stop character. To that end, it always maintains the position of the
and re-examine all those potential sources. This is called "stop next place where it must stop and re-examine all those potential
position" and is stored in the stop_charpos field of the iterator. sources. This is called "the stop position" and is stored in the
The stop position is updated by compute_stop_pos, which is called `stop_charpos' field of the iterator. The stop position is updated
whenever the iteration reaches the current stop position and by `compute_stop_pos', which is called whenever the iteration
processes it. Processing a stop position is done by handle_stop, reaches the current stop position and processes it. Processing a
which invokes a series of handlers, one each for every potential stop position is done by `handle_stop', which invokes a series of
source of display-related information; see the it_props array for handlers, one each for every potential source of display-related
those handlers. For example, one handler is handle_face_prop, information; see the `it_props' array for those handlers. For
which detects changes in face properties, and supplies the face ID example, one handler is `handle_face_prop', which detects changes
that the iterator will use for all the glyphs it generates up to in face properties, and supplies the face ID that the iterator will
the next stop position; this face ID is the result of realizing the use for all the glyphs it generates up to the next stop position;
face specified by the relevant text properties at this position. this face ID is the result of "realizing" the face specified by the
Each handler called by handle_stop processes the sources of display relevant text properties at this position (see xfaces.c). Each
handler called by `handle_stop' processes the sources of display
information for which it is "responsible", and returns a value information for which it is "responsible", and returns a value
which tells handle_stop what to do next. which tells `handle_stop' what to do next.
Once handle_stop returns, the information it stores in the iterator Once `handle_stop' returns, the information it stores in the
fields will not be refreshed until the iteration reaches the next iterator fields will not be refreshed until the iteration reaches
stop position, which is computed by compute_stop_pos called at the the next stop position, which is computed by `compute_stop_pos'
end of handle_stop. compute_stop_pos examines the buffer's or called at the end of `handle_stop'. `compute_stop_pos' examines
string's interval tree to determine where the text properties the buffer's or string's interval tree to determine where the text
change, finds the next position where overlays and character properties change, finds the next position where overlays and
composition can change, and stores in stop_charpos the closest character composition can change, and stores in `stop_charpos' the
position where any of these factors should be reconsidered. closest position where any of these factors should be reconsidered.
Handling of the stop position is done as part of the code in
`get_next_display_element'.
Producing glyphs. Producing glyphs.
Glyphs in a desired matrix are normally constructed in a loop Glyphs in a desired matrix are normally constructed in a loop
calling get_next_display_element and then PRODUCE_GLYPHS. The call calling `get_next_display_element' and then `PRODUCE_GLYPHS'. The
to PRODUCE_GLYPHS will fill the iterator structure with pixel call to `PRODUCE_GLYPHS' will fill the iterator structure with
information about the element being displayed and at the same time pixel information about the element being displayed and at the same
produce glyphs for it. If the display element fits on the line time will produce glyphs for it. If the display element fits on
being displayed, set_iterator_to_next is called next, otherwise the the line being displayed, `set_iterator_to_next' is called next,
glyphs produced are discarded. The function display_line is the otherwise the glyphs produced are discarded, and `display_line'
workhorse of filling glyph rows in the desired matrix with glyphs. marks this glyph row as a "continued line". The function
In addition to producing glyphs, it also handles line truncation `display_line' is the workhorse of filling glyph rows in the
and continuation, word wrap, and cursor positioning (for the desired matrix with glyphs. In addition to producing glyphs, it
latter, see also set_cursor_from_row). also handles line truncation and continuation, word wrap, and
cursor positioning (for the latter, see `set_cursor_from_row').
Frame matrices. Frame matrices.
That just couldn't be all, could it? What about terminal types not That just couldn't be all, could it? What about terminal types not
supporting operations on sub-windows of the screen (a.k.a. "TTY" or supporting operations on sub-windows of the screen (a.k.a. "TTY" or
"text-mode terminal")? To update the display on such a terminal, "text-mode terminals")? To update the display on such a terminal,
window-based glyph matrices are not well suited. To be able to window-based glyph matrices are not well suited. To be able to
reuse part of the display (scrolling lines up and down), we must reuse part of the display (scrolling lines up and down), we must
instead have a view of the whole screen. This is what `frame instead have a view of the whole screen. This is what `frame
@ -252,19 +290,62 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
using the frame matrices, which allows frame-global optimization of using the frame matrices, which allows frame-global optimization of
what is actually written to the glass. what is actually written to the glass.
To be honest, there is a little bit more done, but not much more. Frame matrices don't have marginal areas, only a text area. That
If you plan to extend that code, take a look at dispnew.c. The is, the entire row of glyphs that spans the width of a text-mode
function build_frame_matrix is a good starting point. frame is treated as a single large "text area" for the purposes of
manipulating and updating a frame glyph matrix.
To be honest, there is a little bit more done for frame matrices,
but not much more. If you plan to extend that code, take a look at
dispnew.c. The function build_frame_matrix is a good starting
point.
Simulating display.
Some of Emacs commands and functions need to take display layout
into consideration. For example, C-n moves to the next screen
line, but to implement that, Emacs needs to find the buffer
position which is directly below the cursor position on display.
This is not trivial when buffer display includes variable-size
elements such as different fonts, tall images, etc.
To solve this problem, the display engine implements several
functions that can move through buffer text in the same manner as
`display_line' and `display_string' do, but without producing any
glyphs for the glyph matrices. The workhorse of this is
`move_it_in_display_line_to'. Its code and logic are very similar
to `display_line', but it differs in two important aspects: it
doesn't produce glyphs for any glyph matrix, and it returns a
status telling the caller how it ended the iteration: whether it
reached the required position, hit the end of line, arrived at the
window edge without exhausting the buffer's line, etc. Since the
glyphs are not produced, the layout information available to the
callers of this function is what is recorded in `struct it' by the
iteration process.
Several higher-level functions call `move_it_in_display_line_to' to
perform more complex tasks: `move_it_by_lines' can move N lines up
or down from a given buffer position and `move_it_to' can move to a
given buffer position or to a given X or Y pixel coordinate.
These functions are called by the display engine itself as well,
when it needs to make layout decisions before producing the glyphs.
For example, one of the first things to decide when redisplaying a
window is where to put the `window-start' position; if the window
is to be recentered (the default), Emacs makes that decision by
starting from the position of point, then moving up the number of
lines corresponding to half the window height using
`move_it_by_lines'.
Bidirectional display. Bidirectional display.
Bidirectional display adds quite some hair to this already complex Bidirectional display adds quite some hair to this already complex
design. The good news are that a large portion of that hairy stuff design. The good news are that a large portion of that hairy stuff
is hidden in bidi.c behind only 3 interfaces. bidi.c implements a is hidden in bidi.c behind only 3 interfaces. bidi.c implements a
reordering engine which is called by set_iterator_to_next and reordering engine which is called by `set_iterator_to_next' and
returns the next character to display in the visual order. See returns the next character to display in the visual order. See
commentary on bidi.c for more details. As far as redisplay is commentary on bidi.c for more details. As far as redisplay is
concerned, the effect of calling bidi_move_to_visually_next, the concerned, the effect of calling `bidi_move_to_visually_next', the
main interface of the reordering engine, is that the iterator gets main interface of the reordering engine, is that the iterator gets
magically placed on the buffer or string position that is to be magically placed on the buffer or string position that is to be
displayed next in the visual order. In other words, a linear displayed next in the visual order. In other words, a linear
@ -279,27 +360,27 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
monotonously changing with vertical positions. Also, accounting monotonously changing with vertical positions. Also, accounting
for face changes, overlays, etc. becomes more complex because for face changes, overlays, etc. becomes more complex because
non-linear iteration could potentially skip many positions with non-linear iteration could potentially skip many positions with
changes, and then cross them again on the way back (see such changes, and then cross them again on the way back (see
handle_stop_backwards)... `handle_stop_backwards')...
One other prominent effect of bidirectional display is that some One other prominent effect of bidirectional display is that some
paragraphs of text need to be displayed starting at the right paragraphs of text need to be displayed starting at the right
margin of the window---the so-called right-to-left, or R2L margin of the window---the so-called right-to-left, or R2L
paragraphs. R2L paragraphs are displayed with R2L glyph rows, paragraphs. R2L paragraphs are displayed with R2L glyph rows,
which have their reversed_p flag set. The bidi reordering engine which have their `reversed_p' flag set. The bidi reordering engine
produces characters in such rows starting from the character which produces characters in such rows starting from the character which
should be the rightmost on display. PRODUCE_GLYPHS then reverses should be the rightmost on display. `PRODUCE_GLYPHS' then reverses
the order, when it fills up the glyph row whose reversed_p flag is the order, when it fills up the glyph row whose `reversed_p' flag
set, by prepending each new glyph to what is already there, instead is set, by prepending each new glyph to what is already there,
of appending it. When the glyph row is complete, the function instead of appending it. When the glyph row is complete, the
extend_face_to_end_of_line fills the empty space to the left of the function `extend_face_to_end_of_line' fills the empty space to the
leftmost character with special glyphs, which will display as, left of the leftmost character with special glyphs, which will
well, empty. On text terminals, these special glyphs are simply display as, well, empty. On text terminals, these special glyphs
blank characters. On graphics terminals, there's a single stretch are simply blank characters. On graphics terminals, there's a
glyph of a suitably computed width. Both the blanks and the single stretch glyph of a suitably computed width. Both the blanks
stretch glyph are given the face of the background of the line. and the stretch glyph are given the face of the background of the
This way, the terminal-specific back-end can still draw the glyphs line. This way, the terminal-specific back-end can still draw the
left to right, even for R2L lines. glyphs left to right, even for R2L lines.
Bidirectional display and character compositions. Bidirectional display and character compositions.
@ -310,23 +391,23 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
Emacs display supports this by providing "character compositions", Emacs display supports this by providing "character compositions",
most of which is implemented in composite.c. During the buffer most of which is implemented in composite.c. During the buffer
scan that delivers characters to PRODUCE_GLYPHS, if the next scan that delivers characters to `PRODUCE_GLYPHS', if the next
character to be delivered is a composed character, the iteration character to be delivered is a composed character, the iteration
calls composition_reseat_it and next_element_from_composition. If calls `composition_reseat_it' and `next_element_from_composition'.
they succeed to compose the character with one or more of the If they succeed to compose the character with one or more of the
following characters, the whole sequence of characters that were following characters, the whole sequence of characters that were
composed is recorded in the `struct composition_it' object that is composed is recorded in the `struct composition_it' object that is
part of the buffer iterator. The composed sequence could produce part of the buffer iterator. The composed sequence could produce
one or more font glyphs (called "grapheme clusters") on the screen. one or more font glyphs (called "grapheme clusters") on the screen.
Each of these grapheme clusters is then delivered to PRODUCE_GLYPHS Each of these grapheme clusters is then delivered to
in the direction corresponding to the current bidi scan direction `PRODUCE_GLYPHS' in the direction corresponding to the current bidi
(recorded in the scan_dir member of the `struct bidi_it' object scan direction (recorded in the `scan_dir' member of the `struct
that is part of the iterator). In particular, if the bidi iterator bidi_it' object that is part of the iterator). In particular, if
currently scans the buffer backwards, the grapheme clusters are the bidi iterator currently scans the buffer backwards, the
delivered back to front. This reorders the grapheme clusters as grapheme clusters are delivered back to front. This reorders the
appropriate for the current bidi context. Note that this means grapheme clusters as appropriate for the current bidi context.
that the grapheme clusters are always stored in the LGSTRING object Note that this means that the grapheme clusters are always stored
(see composite.c) in the logical order. in the `LGSTRING' object (see composite.c) in the logical order.
Moving an iterator in bidirectional text Moving an iterator in bidirectional text
without producing glyphs. without producing glyphs.
@ -337,18 +418,18 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
As far as the iterator is concerned, the geometry of such rows is As far as the iterator is concerned, the geometry of such rows is
still left to right, i.e. the iterator "thinks" the first character still left to right, i.e. the iterator "thinks" the first character
is at the leftmost pixel position. The iterator does not know that is at the leftmost pixel position. The iterator does not know that
PRODUCE_GLYPHS reverses the order of the glyphs that the iterator `PRODUCE_GLYPHS' reverses the order of the glyphs that the iterator
delivers. This is important when functions from the move_it_* delivers. This is important when functions from the `move_it_*'
family are used to get to certain screen position or to match family are used to get to certain screen position or to match
screen coordinates with buffer coordinates: these functions use the screen coordinates with buffer coordinates: these functions use the
iterator geometry, which is left to right even in R2L paragraphs. iterator geometry, which is left to right even in R2L paragraphs.
This works well with most callers of move_it_*, because they need This works well with most callers of `move_it_*', because they need
to get to a specific column, and columns are still numbered in the to get to a specific column, and columns are still numbered in the
reading order, i.e. the rightmost character in a R2L paragraph is reading order, i.e. the rightmost character in a R2L paragraph is
still column zero. But some callers do not get well with this; a still column zero. But some callers do not get well with this; a
notable example is mouse clicks that need to find the character notable example is mouse clicks that need to find the character
that corresponds to certain pixel coordinates. See that corresponds to certain pixel coordinates. See
buffer_posn_from_coords in dispnew.c for how this is handled. */ `buffer_posn_from_coords' in dispnew.c for how this is handled. */
#include <config.h> #include <config.h>
#include <stdlib.h> #include <stdlib.h>