Server-Initiated vs. Application-Initiated Redrawing

This topic introduces the reasons that the screen display may need to be updated and the difference between redrawing that is initiated by an application and that initiated by the Window Server.

Variant: Both (ScreenPlay and non-ScreenPlay). Target audience: Application developers.

Introduction

The Window Server maintains the UI display taking into account the region, ordinal position and visibility requirements of all displayable windows. The UI may be updated for several reasons:

  • at direct application request by an application drawing to a window through a CWindowGc

  • due to regions of the display becoming invalid

  • due to actions internal to the Window Server, such as pointer cursor movements.

When a window is moved, resized, or otherwise manipulated by an application, it may cause parts of other windows to become invalid so that they must be redrawn. The Window Server maintains a list of all invalid regions and causes them to be redrawn in one of several ways:

  • for a region with no window, the Window Server redraws the invalid region in the default background color

  • for a blank window, the Window Server redraws the invalid region in the window's color

  • for a backed-up window, the invalid region is redrawn from a backup bitmap maintained by the Window Server

  • if the invalid region is owned by an animation DLL, the Window Server invokes the animation DLL directly to redraw the area: the region is then valid again

  • for a normal RWindow, whenever possible, the Window Server replays the sequence of drawing commands stored in the redraw stores. However, sometimes this is not possible, because, for example, the redraw stores have been lost due to low memory conditions. In these circumstances, the Window Server generates a redraw event and sends it to the application. This is described in more detail below.

Window Server-initiated redrawing

When the Window Server needs to repaint a standard RWindow window and it is not possible to do this by replaying the drawing commands stored in the redraw stores, it sends a TWsRedrawEvent message to the client.

It is part of the client's contract with the Window Server to listen for these events and respond to them by performing a redraw. The normal way for a client application to do this is through an active object, which is sometimes called a redrawer. This is normally provided by the application framework and should have a lower priority than the active objects for standard events. The client issues an asynchronous request for the next redraw event, calling the RWsSession::RedrawReady() function.

The redrawer's RunL() function (which handles the completed request) calls RWsSession::GetRedraw(). This gets the TWsRedrawEvent, which contains the handle of the window and the rectangle within it that needs to be redrawn and then does the redraw. This involves:

  1. Calling RWindow::BeginRedraw() on the relevant window and passing in the rectangle.

  2. Issuing the CWindowGc drawing commands that define how to draw the area of the window specified by the rectangle passed in the TWsRedrawEvent. These drawing commands must exactly match what was drawn originally, because the Window Server clips the drawing to the passed rectangle.

  3. Calling RWindow::EndRedraw().

At the end of the redrawer’s RunL(), a call is made to RWsSession::RedrawReady() to enable the client to listen for further requests from the Window Server.

The following diagram demonstrates that typically the RunL() starts with a GetRedraw() and ends with a call to RedrawReady().

Figure: Window Server-initiated redraw

A redrawer's RunL() function must not perform any non-redraw drawing (that is, any drawing operations that are not bracketed within the calls to BeginRedraw() and EndRedraw()). If it does, this causes a panic with code 79 (EWservPanicWindowBeginRedrawNotCalled) in the ScreenPlay variant. This is to avoid the infinite loop that would otherwise be caused by an endless cycle of the non-redraw drawing within the RunL() triggering a Window Server-initiated redraw.

Application-initiated redrawing

An application initiates redrawing when it wants to update the UI to reflect a change of state. There are two scenarios, which we describe under separate headings below.

The "draw now" scenario

The "draw now" redraw scenario is when an application wants to push a state change to a window immediately. Typically the application does this by calling CCoeControl::DrawNow(). However, it is possible to achieve the same results using RWindow and CWindowGc calls directly. To illustrate how to do this, consider a digital clock application that updates the time displayed in the window from 12:02 to 12:03.

The application does the following:

  1. Calls RWindow::Invalidate(), optionally passing in the bounding rectangle. When called without passing in a rectangle, this function invalidates the entire window.

  2. Calls RWindow::BeginRedraw(). If the application passed a bounding rectangle to Invalidate(), it must pass the same bounding rectangle to BeginRedraw(). If the application did not pass a bounding rectangle to Invalidate(), it must not pass one to BeginRedraw().

  3. Issues the CWindowGc draw commands.

  4. Calls RWindow::EndRedraw().

Figure: Application-initiated redrawing, "draw now" scenario

The "draw deferred" scenario

The "draw deferred" redraw scenario is when an application simply marks a window or a rectangle within a window as invalid. This eventually triggers a Window Server-initiated redraw. Typically the application does this by calling CCoeControl::DrawDeferred(). However, it is also possible to do this by calling RWindow::Invalidate().

Figure: Application-initiated redrawing, "draw deferred" scenario

This approach is useful when the data to be displayed might be updated frequently but it is not necessary to update the display instantaneously.

To illustrate how it works, consider a window that has a rectangle that is used to display icons (a star, a cross and a triangle) that represent three different events that can occur in the application. Suppose the events can occur in quick succession. If you use the "draw now" approach when each event occurs, the Window Server updates the display separately for each one, as shown in the following diagram.

Figure: Icons displayed using the "draw now" approach

However, if you use the "draw deferred" approach when each event occurs, the Window Server may not update the display for each one. For example, the Window Server does not update the display when it is superceded by a later call.

Figure: Icons displayed using the "draw deferred" approach

If it is important that the display is updated immediately, you would generally use the "draw now" approach. However, if a short delay in the display being updated is unlikely to inconvenience the user, the "draw deferred" approach might be appropriate and has a performance advantage.

Related concepts