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:
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.