PrevNextUpHome SophiaFramework UNIVERSE 5.3

9.3. Event Handling

9.3.1. Overview

In the responder system, the event is handled as follows:

  1. The BREW-defined event which occurs by interruption such as user operation or external factor will be dispatched from the BREW environment to the applet.
  2. In the applet, the event will be automatically handled by the SFYApplication::HandleEvent function.
  3. The SFYApplication::HandleEvent function will boot up the distributer and pass the event to it.
  4. The distributer will distribute the event to the appropriate reponders in the responder tree whose top is the root using the tracer rules.
  5. The responder which will receive the event will boot up the corresponding handler, if necessary.
  6. If the responder-defined events or the user-defined events occur during the execution of the above handler, their corresponding handlers will be booted up too.

The SFYApplication::HandleEvent function will be called when the applet receives the event from the BREW environment. As shown in the following implementation of the SFYApplication::HandleEvent function, the distributer will be booted up at the first timing point of each event loop with the SFYResponder::Distribute function.

Example 9.22. Implementation of the SFYApplication::HandleEvent function

// virtual function that will be called when the event dispatched from the BREW environment needs to be handled
/*protected virtual */Bool SFYApplication::HandleEvent(SFXEventConstRef event)
{
    // here describe the handling of the event dispatched from the BREW environment

    SFCError  error;
    Bool      result(false);

    // boot up the distributer to distribute the event using the tracer
    // first of all, the SFYDistributer instance bound with the root will receive the event
    // then, the event will be distributed to the responders in the responder tree according to the dispatching rules of the tracer
    // * _root is the root(SFZRoot)
    if ((error = _root->Distribute(event, &result)) == SFERR_NO_ERROR) {

        if (event.GetType() != SFEVT_APP_STOP && event.GetType() != SFEVT_APP_SUSPEND)) {  // if redrawing is necessary

            if (IsRenderable()) {  // if the screen can be redrawn (i.e., if no highest priority event handler is registered)

                 // boot up the renderer to redraw the responder tree below the root
                error = _root->Render();
            }
        }
    }
    if (error != SFERR_NO_ERROR) {

        // call HandleError() in case the fatal error such as insufficient memory during the initialization of the distributer or the renderer occurs
        if (HandleError(event, error)) {

            result = true;
        }
    }
    if ((event.GetType() == SFEVT_APP_SUSPEND) && IsRendererIntermissive()) {
        // if the back-up bitmap inside the renderer is released when an application suspends

        // terminate the renderer
        _renderer.Terminate();
    }
    return result;  // return "true" if the event has been handled, otherwise return "false"
}// SFYApplication::HandleEvent //

Reference: SFCApplication::HandleEvent | SFCApplication::IsRenderable | SFCApplication::HandleError | SFYApplication::IsRendererIntermissive | SFYResponder::Distribute | SFYResponder::Render | SFYRenderer::Initialize | SFYRenderer::Terminate | SFZRoot | Root | Tracer | Distributer | Renderer Drawing Event | Drawing Handler | Event Loop

[Note] Highest Priority Event Handler

See the description of the SFCApplication::RegisterBypass function.

9.3.2. Life Cycle

From the applet boot-up to its termination, a variety of events such as bootup, termination, suspend, resume, or key are dispatched from the BREW environment to the applet.

In the applet, the event-driven operation to receive and handle each event is repeated in the applet.

The following figure shows the typical life cycle of the applet.

Figure 9.17. Life cycle of the applet


Life cycle of the applet

It is troublesome to appropriately dispatch a variety of events which the applet receives.

Since the distributer of the responder system automatically dispatches each event to the appropriate handler functions, the program structure is very simple.

9.3.3. Booting up an Applet

Immediately after the user boots up the applet, the instance of the application class inheriting from SFYApplication will be created in the applet.

This application instance will make the root(SFZRoot) bound with the distributer and the renderer in itself.

Next, the SFEVT_APP_START event will be dispatched from the BREW environment to the applet, and the applet initialization will begin.

[Note] Note
Initialization processing such as creating a window is executed in the constructor of the application class or the handler for the SFEVT_APP_START event.

Figure 9.18. Sequence diagram: Booting up the applet


Sequence diagram: Booting up the applet

* The renderer and the root are omitted from the figure since they are hardly related with this sequence.

9.3.4. Terminating an Applet

When the user terminates the applet by selecting the QUIT option in the menu or by pressing the POWER key, the SFEVT_APP_NO_CLOSE event is dispatched from the BREW environment to the applet.

When this event is received, the applet must return "false" to terminate itself(i.e., if "true" is returned, the applet will not terminate).

Then the SFEVT_APP_STOP event will be dispatched from the BREW environment to the applet, and the applet will begin to terminate.

If theevent handling on the SFEVT_APP_STOP event finishes normally, the distributer, the renderer, and the responders such as a window or the root will be released, and the application instance itself will be also automatically released.

[Note] Note
Finalization such as destroying a window is executed in the destructor of the application class or the handler for the SFEVT_APP_STOP event.

Figure 9.19. Sequence diagram: Terminating the applet


Sequence diagram: Terminating the applet

In the above figure, the SFCApplication::Terminate function to terminate the applet will be executed after the user presses the button for termination on the window(win1).

* The renderer and the root are omitted from the figure since they are hardly related with this sequence.

9.3.5. Standard Tracer

The tracer manages the rules to dispatch the event to the appropriate responders.

The default dispatching rules are registered into the distributer of the responder system as the standard tracer.

If the tracer is not changed explicitly, the event will be dispatched according to the dispatching rules of the standard tracer. And the responder inherits the tracer rules from its parent responder.

[Note] Customizing the standard tracer

In general, the default settings are enough. There is no need to customize the standard tracer in almost all applet developments.

Three elements of the dispatching rule to register into the tracer are as follows:

  1. Distributing condition
  2. Processing order
  3. Overloading condition

Distributing condition

For the distributing condition, specify the state of the responder where the event will be dispatched.

One of the following can be specifiled:

  1. Focus[SFYTracer::STATE_FOCUS]: Dispatch an event to the focused responders.
  2. All[SFYTracer::STATE_ALL]: Dispatch an event to all responders.
  3. None[SFYTracer::STATE_NONE]: Dispatch an event to no child responders. In case of the dispatching rule of the tracer for the SFYDistributer class, an event will be dispatched to no responder including the root(SFZRoot).

The key event is dispatched to the focused responders since distributing condition is set to "Focus[SFYTracer::STATE_FOCUS]".

The bootup, termination, suspend, or resume event for the applet is dispatched to all responders since the distributing condition is set to "All[SFYTracer::STATE_ALL]".

[Caution] Method to receive the BREW-defined event whose dispatching rule is registered into the standard tracer with "distributing condition: None[SFYTracer::STATE_NONE]"

The BREW-defined event whose dispatching rule is registered into the standard tracer with "distributing condition: None[SFYTracer::STATE_NONE] will be distributed to no responder including the root(SFZRoot) which the SFYApplication class contains by default.

This is because the rules of the standard tracer are registered into the SFYDistributer instance.

To receive this event, you have to register its handler directly into the SFYDistributer instance as follows:

  1. Get the SFYDistributer instance with the SFYApplication::GetDistributer function.
  2. Register the handler for this event with the SFYDistributer::RegisterHandler function.
  3. Though this handler may be defined anywhere, not pointer to the responder but "null" will be passed via the "invoker" parameter. Note this matter in case the invoker parameter will be used.

Figure 9.20. SFEVT_KEY event: Distributing condition


SFEVT_KEY event: Distributing condition

The SFEVT_KEY event is dispatched to the focused responders.

Figure 9.21. Dispatching the SFEVT_APP_RESUME event


Dispatching the SFEVT_APP_RESUME event

The SFEVT_APP_RESUME event is dispatched to all responders.

Processing order

For the processing order, specify the priority order to boot up handlers.

One of the following can be specifiled:

  1. "from background to foreground[SFYTracer::ORDER_BACKWARD]": The handlers registered into the responder placed background are booted up first. If more than one handler are registered into the same responder, they will be booted up in the order to be registered.
  2. "from foreground to background[SFYTracer::ORDER_FORWARD]": The handlers registered into the responder placed foreground are booted up first. If more than one handler are registered into the same responder, they will be booted up in the reverse order to be registered.

Overloading condition

For the overloading condition, specify whether or not the handler processes an event duplicately.

One of the following can be specifiled:

  1. "Yes[true]": The event is duplicately handled. Even if the event is handled by the handler, it will be dispatched to the next responder if any.
  2. "No[false]": The event is not duplicately handled. If the event is handled by the handler, it will not be dispatched to other responders.

The key event is set to "from foreground to background [SFYTracer::ORDER_FORWARD]" for the Processing order. Therefore, it will be processed by the handlers of focused responders from foreground to background. If more than one handler are registered into the same responder, they will be booted up in the reverse order to be registered. Since it is set to "No" for the Overloading condition, the event handling ends there if the event is handled by the handler.

The SFEVT_APP_RESUME event is set to "from background to foreground [SFYTracer::ORDER_BACKWARD]" for the Processing order. Therefore, it will be processed by the handlers of focused responders from background to foreground. If more than one handler are registered into the same responder, they will be booted up in the reverse order to be registered. Since it is set to "Yes" for the Overloading condition, the next handler, if any, will be booted up after the event is processed by the handler.

Figure 9.22. SFEVT_KEY event: Processing order and Overloading condition


SFEVT_KEY event: Processing order and Overloading condition

The SFEVT_KEY event is processed by the handlers of focused responders from foreground to background.

  1. The SFEVT_KEY event is dispatched first to the focused SFYControl in the lowest child layer.
  2. If the event is handled by SFYControl, the event handling will end there. Otherwise it will be dispatched to SFZWindow, SFYControl's parent.
  3. If the event is handled by SFZWindow, the event handling will end there. Otherwise it will be dispatched to SFYApplication(SFZRoot), SFZWindow's parent.
  4. If the event is handled by SFYApplication(SFZRoot), the event handling will end there. Otherwise it will be returned to the BREW environment.
  5. When more than one handler for the SFEVT_KEY event are registered into the same responder, handlers are booted up in the reverse order to be registered.

Settings of the standard tracer

The standard tracer is set as follows:

Table 9.3. Standard tracer

Event type Distributing condition Processing order Overloading condition
SFEVT_APP_START All from background to foreground Yes
SFEVT_APP_STOP All from foreground to background Yes
SFEVT_APP_RESUME All from background to foreground Yes
SFEVT_APP_SUSPEND All from foreground to background Yes
from SFEVT_APP_CONFIG to SFEVT_APP_START_WINDOW No from foreground to background No
from SFEVT_KEY to SFEVT_KEY_HOOK_RELEASE Focus from foreground to background No
from SFEVT_COMMAND to SFEVT_CTL_TEXT_MODECHANGED Focus from foreground to background No
from SFEVT_DIALOG_INIT to SFEVT_COPYRIGHT_END Focus from foreground to background No
from SFEVT_ALARM to SFEVT_NOTIFY_FAILURE No from foreground to background No
from SFEVT_FLIP to SFEVT_SCR_ROTATE No from foreground to background No
from SFEVT_CB_CUT to SFEVT_CB_PASTE No from foreground to background No
[Warning] Warning

A BREW-defined event or user-defined event is distributed to the responders according to the tracer rules. A responder-defined event must not be distributed using the tracer.

To distribute the user-defined event, register its dispatching rule into the tracer.

[Caution] Method to receive the BREW-defined event whose dispatching rule is registered into the standard tracer with "distributing condition: None[SFYTracer::STATE_NONE]"

The BREW-defined event whose dispatching rule is registered into the standard tracer with "distributing condition: None[SFYTracer::STATE_NONE] will be distributed to no responder including the root(SFZRoot) which the SFYApplication class contains by default.

This is because the rules of the standard tracer are registered into the SFYDistributer instance.

To receive this event, you have to register its handler directly into the SFYDistributer instance as follows:

  1. Get the SFYDistributer instance with the SFYApplication::GetDistributer function.
  2. Register the handler for this event with the SFYDistributer::RegisterHandler function.
  3. Though this handler may be defined anywhere, not pointer to the responder but "null" will be passed via the "invoker" parameter. Note this matter in case the invoker parameter will be used.

Example 9.23. Registering the dispatching rule into the tracer

USRResponder::USRResponder(Void) static_throws
{
    if (static_try()) {

        ...

        static_throw(RegisterTracer(
            SFXEventRange(SFEVT_KEY, SFEVT_KEY, AVK_SOFT1, AVK_SOFT4),
            SFYTracer::ORDER_FORWARD, SFYTracer::STATE_ALL, false
        ));

        ...
    }
}
[Tip] Tip

A dispatching rule is registerred into the tracer with the SFYResponder::RegisterTracer / SFYDistributer::RegisterTracer function.

Reference: Tracer | Distributer | Event | Handler

9.3.6. Handler

Handler is the function which actually processes an event dispatched to the responder.

With the SFYResponder::RegisterHandler / SFYDistributer::RegisterHandler function, the handler for an event is registered into the responder or the SFYDistributer instance bound with the root(SFZRoot) which the application class contains internally.

For the same event, more than one handler can be registered into the same responder.

For instance, when more than one handler are registered for the SELECT key event of the SFEVT_KEY event type into window, the handler to be registered last will be booted up since its processing order of dispatching rule of the standard tracer is "from foreground to background".

If this handler returns "true", the event handling will end there. On the contrary if it returns "false", the handler to be registered second-to-last will be booted up. Event handling regarding to this window continues until any handler returns "true" or there is no handler to be booted up.

[Note] Positional relationship of the handlers

The handler registered first is placed backmost, and the handler registered last is placed foremost.

Example 9.24. Registering the handler

USRResponder::USRResponder(Void) static_throws
{
    if (static_try()) {

        ...

        static_throw(RegisterHandler(
            SFXEventRange(SFEVT_KEY, SFEVT_KEY, SFP16_BEGIN, SFP16_END),
            XANDLER_INTERNAL(OnKey)
        ));

        ...
    }
}
[Tip] Tip
A handler is registered with the SFYResponder::RegisterHandler function.

Example 9.25. Implementing the handler

XANDLER_IMPLEMENT_BOOLEVENT(USRResponder, OnKey, invoker, event)
{
    switch (event.GetP16()) {

        case AVK_SELECT:

            TRACE("select key was pressed.");
            return true;

        case AVK_CLR:

            TRACE("clear key was pressed.");
            return true;

        default:

            TRACE("unknown key was pressed.");
            return true;
    }

    return false;
}
[Important] IMPORTANT

The handler will return "true" if the event is handled. Otherwise, it will return "false".

If some handlers return "true", the responder system will boot up the renderer to redraw the responder tree if necessary.

[Tip] Tip
For more details, see the default implementation of the SFYApplication::HandleEvent function.

Reference: Handler | Event | SFYResponder::RegisterHandler | SFYDistributer::RegisterHandler