Redraw stores store the sequence of drawing commands representing window contents. Whenever possible, the Window Server performs server-initiated redraws by repeating the sequence of stored commands, rather than by sending redraw requests to the client. This minimises the number of client-server transactions and means that redraws are done as soon as the server detects that they are needed. This topic explains some of the background to redraw stores.
Variant: Both (ScreenPlay and non-ScreenPlay). Target audience: Device creators.
The classes involved with redraw stores are as follows:
Figure: Redraw stores class diagram
CWsRedrawMsgWindow
is the class representing
a redraw store. Draw commands are stored in a number of segments,
stored in the nested class CRedrawSegment
.
Redraw drawing takes place as follows:
A call to RWindow::Invalidate()
causes either the whole window, or
a rectangle within it, to be marked as invalid.
Next, a call
to RWindow::BeginRedraw()
is made, either for the
whole window or for a rectangle within it.
Draw operations take place.
Finally there
is a call to RWindow::EndRedraw()
.
In this sequence, the draw operations within the BeginRedraw()
and EndRedraw()
brackets are interpreted as replacing whatever drawing was previously present in the affected
rectangle.
It is important to bracket all drawing within BeginRedraw(TRect)
and EndRedraw(TRect)
calls. In ScreenPlay, the
Window Server ignores all drawing not within BeginRedraw()
and EndRedraw()
brackets and triggers a full-window
redraw. In debug builds, there is an option to panic clients violating
this convention.
For more information, see Redraw Drawing.
When the Window Server
receives a batch of redraw drawing, everything between a BeginRedraw/EndRedraw
bracket is stored in a single redraw segment. The segment is
marked as ESegmentTypePendingRedraw
while it is being
received, and ESegmentTypeRedraw
once it is complete.
Redraw segments have a region to which they apply. For ESegmentTypeRedraw
, the region is initially set to be the
rectangle passed into the BeginRedraw()
call. When
a newESegmentTypeRedraw
is created, its region is
subtracted from the regions of all existing segments. This reflects
the fact that redraw drawing replaces existing drawing. If,
as a consequence of new redraw drawing, the region of an existing
segment becomes empty, that segment is discarded. Its drawing has
been replaced everywhere, so it is no longer needed.
What
happens to drawing that is received between an EndRedraw
and the next BeginRedraw
—and which is therefore non-redraw drawing —depends on which variant is in use:
In ScreenPlay, non-redraw drawing is not stored in a segment but instead triggers the Window Server to invalidate the entire window. This means that the client application must then perform a full window redraw.
In the non-ScreenPlay
variant, non-redraw drawing is stored in a segment marked as ESegmentTypeNonRedraw
. For these segments the region is
initially set to be the whole window and does not affect the regions
of existing segments, because non-redraw drawing is drawn over existing
drawing.
When playback is required, the redraw store goes through the redraw segments and replays them if the region for the segment intersects the region that is to be redrawn. It follows from the way that they are managed that the regions of redraw segments are mutually disjoint. This means that in ScreenPlay they can be replayed in any order. This is also true in the non-ScreenPlay when there are only redraw segments present.
In the non-ScreenPlay variant, any non-redraw segments are replayed in earliest-first order, because they draw on top of earlier drawing.
Variant: Non-ScreenPlay only.
Non-redraw segments can cause inefficient operation of redraw stores. For this reason, in the non-ScreenPlay variant where non-redraw segments are still used, the Window Server "ages" them. That is, non-redraw segments are considered to have a finite lifetime, after which they are discarded. When a non-redraw segment is discarded, the Window Server makes a redraw request to the client asking it to provide new draw operations for the invalid region.
The lifetime
for non-redraw segments is set in the WSINI.INI file using the parameter NONREDRAWAGELIMIT
, followed
by a duration in microseconds. If this line is not present in the WSINI.INI
, a default of one second is used.
Variant: Both (ScreenPlay and non-ScreenPlay).
Another WSINI.INI file setting that affects redraw storing is ATOMICREDRAWS
. If this parameter is present, new draw operations
received after a BeginRedraw()
are not considered
valid until the corresponding EndRedraw()
is received.
In particular, a new segment does not replace existing segments until
it is complete. This has the consequence that if redraw store playback
is required before the EndRedraw()
for a new segment
is received, draw operations from old segments for that region are
used instead. Thus drawing within Begin/EndRedraw
brackets can be considered as an atomic operation. This eliminates
one potential source of flicker.