Display Control and Mapping in the Window Server Client

ScreenPlay provides support for externally connected displays, such as TV-out. Previous versions of Symbian and the non-ScreenPlay variant consider the size of each display to be fixed, assuming it to be built into the phone. However, for High-Definition Multimedia Interface (HDMI) and composite video connectors, there is a range of resolutions that can change dynamically. ScreenPlay provides an optional feature that supports switching between resolutions at runtime and notifies Window Server clients when there are changes to the resolution and connectedness.

This topic builds on the introduction in Dynamic Resolution Switching.

The CWsScreenDevice Window Server client-side API has a GetInterface() function, which you can use to return pointers to the MDisplayControl and MDisplayMapping interfaces or null if the interface is not supported. For example:

// Establish connection and get display control interface.
class CWindowClient : public CBase
    {
    ...
    RWsSession iSession;
    CWsScreenDevice* iScreenDevice;
    MDisplayControl* iDisplayControl;
    MDisplayMapping* iDisplayMapping;
    TWsDisplayChangedEvent iLastEvent;
    }
    
void CWindowClient::ConstructL(TInt aDisplayNumber)
    {
    User::LeaveIfError(iSession.Connect());
    iScreenDevice = new(ELeave) CWsScreenDevice(iSession);
    User::LeaveIfError(iScreenDevice->Construct(aDisplayNumber));
    iDisplayControl = iScreenDevice->GetInterface(EDisplayControl);
    User::LeaveIfNull(iDisplayControl);
    iDisplayMapping = iScreenDevice->GetInterface(EDisplayMapping);
    User::LeaveIfNull(iDisplayMapping);
    }

In addition, CWsScreenDevice provides the IsCurrentModeDynamic() and IsModeDynamic() functions for querying whether the current screen mode and a given screen mode are dynamic. If a screen mode is dynamic, the application extent always fills the full UI space and the area returned by CWsScreenDevice::SizeInPixels() always matches the actual resolution that is in use. However, the MDisplayMapping interface also provides features that enable you to draw outside the application UI extent.

MDisplayControl

The MDisplayControl interface provides Window Server clients with functions for setting and getting the current display configuration, getting a list of available resolutions and enabling display change event notifications (EEventDisplayChanged). The following diagram shows the class hierarchy.

Figure 1. Display control class diagram

For a diagram of the TDisplayConfiguration class hierarchy, see the Common Graphics Headers Component Overview.

Once you have obtained the MDisplayControl interface, you can call GetResolutions() on it. For example:

// Get available resolutions
RArray<MDisplayControl::TResolution> resolutions;
User::LeaveIfError(iDisplayControl->GetResolutions(resolutions));
          
// Use resolution list.
       

You can use the EnableDisplayChangedEvents() function to register for notifications of the EEventDisplayChanged event. This is generated when the display device is attached or detached or there is a change in the current resolution, the resolution list or the current configuration. For example, this can be generated by a render stage or the composition engine in response to a hardware event (such as an external display being connected or disconnected). The event is sometimes, but not always, triggered by a change in the screen mode.

There are therefore two aspects to the event in that it can be triggered by a display change or a configuration change. Typically you check the event against the previous one to see what has changed.

The following table provides a summary of how this event compares to EEventScreenDeviceChanged.

Action EEventScreenDeviceChanged EEventDisplayChanged

Screen mode change

Always triggers this event

Triggers this event only if it causes a change in the configuration.

Display configuration change

Generally does not trigger this event

Generally triggers this event

The following example first registers for notification of EEventDisplayChanged events and then changes the screen mode. The second part illustrates a simplified handler for the events. It demonstrates checking the event against the previous one to see whether the resolution or configuration has changed.

// Establish connection and get display control interface.

iDisplayControl->EnableDisplayChangeEvents(ETrue);

iScreenDevice->SetScreenMode(2);    // Number depends on WSINI.INI config.
iScreenDevice->SetAppScreenMode(2); // Ensure application windows are
                                    // shown in the new mode.
...
    
// Simplified event handler.
TWsEvent event;
iSession.GetEvent(event);
    
switch (event.Type())
    {
    case EEventScreenDeviceChanged:
        {
        TSize screenSize = iScreenDevice->SizeInPixels();
        // Re-layout windows for new application screen dimensions
        }
        break;
    case Redraw:
        {
        // Draw content of window
        }
        break;
    case EEventDisplayChanged:
        {
        TWsDisplayChangedEvent* newEvent;
        newEvent = event.DisplayChanged();

        if (newEvent->iResolutionListChangeId !=
            iLastEvent.iResolutionListChangeId)
            {
            // ...
            }
        
        if (newEvent->iConfigurationChangeId !=
            iLastEvent.iConfigurationChangeId)
            {
            TDisplayConfiguration config;
            User::LeaveIfError(
                iDisplayControl->GetConfiguration(config)));
            // Handle updated configuration
            // May be entirely handled by screen device changed event
            }
        iLastEvent = *newEvent;
        }
        break;
    }

Here is an example of setting a new display resolution:

TDisplayConfiguration config;
config.SetResolution(TSize(1280, 720));
config.SetRotation(MDisplayControl::ERotation180);
          
User::LeaveIfError(iDisplayControl->SetConfiguration(config));

MDisplayMapping

The MDisplayMapping interface enables Window Server clients to map between coordinate spaces, allowing for translation and scaling of coordinates. For example, suppose an application is to draw a virtual keyboard outside of the application's extent. This requires knowing the extent of both the application and the full UI area. The application can use the MDisplayMapping interface to get this information, so that the virtual keyboard can be drawn within the full UI area but outside of the application's extent.

Figure 2. Display mapping class diagram

The MDisplayMapping interface is very flexible. UIDs are used to signify the application UI coordinate space, the full UI space, the composition/display coordinate space (which may be a different scale to the UI coordinate space) and the Direct Screen Access (DSA) space (which may match the full UI space, or be offset relative to the application UI space).

The MapCoordinates() function takes a rectangle, a source space and a target space and returns the correspondingly mapped rectangle in the target space. To map a point, use a rectangle with a width and height of one pixel, because the scaling between UI space and composition/display space may enlarge (or sometimes reduce) the rectangle’s size.

For example, consider the following diagram, in which the outer rectangle represents the display area and the inner one represents the application space (screen mode).

Figure 3. Display area and application extent

The display resolution is 1280 x 720, the application size is 176 x 208 and a virtual resolution of 426 x 240 has been introduced, which gives a scaling factor of three in each direction. All pixels are approximately square, for simplicity. The application area has been centered in the display, giving an X offset of (426-176)/2 and a Y offset of (240-208)/2, or (125, 16).

To put a window on screen to fill the display, create a rectangle positioned at (0,0) with a size of the current resolution (426 x 240). Then pass this in with a source space of the full UI and target space of the application. This results in a rectangle of the same size but at offset (125,16).

In addition, to use an external surface at the real resolution, pass this rectangle in with a source space of the application UI and a target space of the composition/display. This results in a rectangle with size of 1280 x 720, which you can then use when creating the surface. Because the UI surface and external surface are scaled independently, the UI memory requirements can remain low, even with high resolution video, viewfinder and games. For an example code snippet, see External Surfaces Overview.

Related reference
The wsini.ini File Reference