Home · All Classes · Main Classes · Deprecated

Writing prestartable and lazy shutdown applications

An application that has been prestarted (or lazily shut down) can show its window almost without a delay when it is released from the prestarted state. MeeGo Touch supports prestarting and lazy shutdown of application services, that is, applications that are started by calling launch() (or some other application-specific method) in their D-Bus interface.

Prestarted applications are started to a special prestarted state during boot by a daemon called Applifed. In that state, they are running in the background in their mainloop but do not show or do anything. If an application gets terminated, Applifed prestarts it again automatically.

When the user closes an application, lazy shutdown allows an application to enter the prestarted state instead of terminating it. This allows the next application to start up very quickly. Automatically prestarted applications can use lazy shutdown as well.

Terminology

Prestarting an application

If an application supports prestarting, it must set the prestart mode with MApplication::setPrestartMode(), regardless of the command line parameters, before using any other parts of the prestarting API. It is recommended to do this during or immediately after instantiating the MApplication class.

It is important to notice that before entering the prestarted state application should do all the initializations that can be done before calling MWindow::show(). Some initializations eg. MApplicationPage::createContent are done only after MWindow::show() is called and prestarted state is released. In practice this means that window is visible for the user only after MApplicationPage::createContent() is finished.

Example:

// example.cpp
// Minimal prestartable and lazy shutdownable application

#include <MApplication>
#include <MApplicationWindow>

int main(int argc, char ** argv)
{
    MApplication app(argc, argv);
    MApplication::setPrestartMode(M::LazyShutdown);

    MApplicationWindow window;
    window.show();

    return app.exec();
}

Start the application to the prestarted state as follows.

$ ./example -prestart &

An application enters the prestarted state if it is started with the -prestart commandline argument and it sets the prestart mode before showing any windows. If either one of these conditions does not hold, the application enters the running state.

The MApplicationWindow::show() method can be called even if the application is in the prestarted state. The window will not become visible to the user until the application is launched.

MApplication::isPrestarted() can be used to check if the application is currently in the prestarted state.

Releasing application from the prestarted state

If the launch() method in MApplication's D-Bus interface is called (for instance, when the user taps the application icon) and the application is in the prestarted state, the application is released from the prestarted state and allowed to continue to the running state. Make sure that the application registers exactly the same D-Bus service that is defined in the corresponding .service file. Contradictory services may lead to longer start-up times.

The default launch from the application grid can be simulated. For example:

$ dbus-send --dest=com.nokia.example --print-reply --type="method_call" /org/maemo/m com.nokia.MApplicationIf.launch

The application can also be released from the prestarted state in the code by calling MApplication::setPrestarted(false). This is equivalent to the D-Bus launch().

The application can react to the launch by connecting the MApplication::prestartReleased() signal, or by overriding MApplication::releasePrestart() handler. The default handler shows the active window of a single-window application, if one exists. Note: default handler shows the window in the state where it was when it entered the prestart state. For example if application was minimized when entering the prestart state it will be shown as minimized when releasing it. If application developer wants to change this behaviour so that window isalways maximized it can be achieved for example by overriding MApplication::releasePrestart() handler and calling raise() for the active window.

For multi-window applications, the default handler does nothing. They must explicitly release the application from the prestarted state by calling MApplication::setPrestarted(false) and show the window after that.

Returning to the prestarted state

An application returns from running to prestarted state if its prestarted mode is set to M::LazyShutdown or M::LazyShutdownMultiWindow and its last window is closed.

The application can react to restoring the prestarted state by connecting to the MApplication::prestartRestored() signal, or by overriding the MApplication::restorePrestart() event handler. The default implementation of MApplication::restorePrestart() hides all the open windows.

The application can also return to the prestarted state in the code by calling MApplication::setPrestarted(true). This effectively calls the MApplication::restorePrestart() event handler if one of the lazy shutdown modes is set.

Prestarting during boot and enabling lazy shutdown

To enable lazy shutdown of the application or make the application prestartable during device boot, -prestart must be added to the .service -file of the application:

[D-BUS Service]
Name=com.nokia.example
Exec=/usr/bin/example -prestart

Note: The above modification enables starting up and prestarting the application. It does not cause the application to start up or prestart at boot.

If Applifed is used for prestarting applications at boot, its configuration file is located in /etc/prestart. This file contains the names of the prestartable D-Bus services and the prestarting priority among other things, such as CPU-load thresholds.

Boot time prestart configuration is typically part of the platform-specific configurations, and is not provided in application packages.

Sudden deaths in the prestarted state

Applications in the prestarted state never interact with the user. They should not take care of any critical tasks, since configuration politics determine whether or not the applications is prestarted at all. Thus, the applications in the prestarted state are ideal candidates for suspending and killing when the system resources run low. Therefore, application developers must be aware that an application in the prestarted state may be killed with KILL signal at any time without any warning.

Prestarting multi-window applications

Multi-window applications can be prestarted by using LazyShutdownMultiWindow and TerminateOnCloseMultiWindow modes. As opposed to single-window applications, no window is shown by default when the launch() method is called from the D-Bus interface. The window is shown as follows:

1. The code releases the application from the prestarted state.

2. The code that handles the D-Bus call shows the window.

See the following example:

void MultiWindowApplication::activateWindow(int index)
{
    // This is the real handler for D-Bus method activateWindow(int)
    // that shows a window (and page) of the given index. 

    if (index >= 0 && index < NUM_WINDOWS)  {

        // Force release from prestart if in prestarted state.
        // This is important, because it sets the internal state.
        if (isPrestarted()) {
            setPrestarted(false);
        }

        // Show the desired window
        m_window[index]->show();
        m_window[index]->activateWindow();
        m_window[index]->raise();

        // Show the page and activate it
        m_mainPage[index]->appear();
        m_mainPage[index]->activateWidgets();
    }
}

A multi-window application enters the prestarted state when all its windows are closed. Closed windows can be cleaned up, for instance, by the closeEvent handler of each window, or when restoring the prestarted state if all windows are closed.

Controlling window closing on lazy shutdown

The default behavior on window close varies depending on the prestart mode. On LazyShutdown and LazyShutdownMultiWindow windows are hidden by default. On TerminateOnClose and TerminateOnCloseMultWindow windows are really closed, just like when application has not been prestarted.

To change the default closing behaviour, override the closeEvent handler of the window and use MWindow::setCloseOnLazyShutdown. See the following example:

#include <MApplication>
#include <MApplicationWindow>
#include <MApplicationPage>
#include <MComboBox>
#include <MDebug>
#include <QStringList>

class MyWindow : public MApplicationWindow
{
public:
    MyWindow();

protected:
    virtual void closeEvent(QCloseEvent *event);

private:
    MApplicationPage *page;
    MComboBox *comboBox;
};

MyWindow::MyWindow() 
{
    page = new MApplicationPage();
    page->setTitle("closeEvent example app");
    comboBox = new MComboBox();
    comboBox->setTitle("What should closeEvent do?");
    QStringList stringList;
    stringList << "Ignore closeEvent" << "Hide window (LazyShutdown)" << "Really close window";
    comboBox->addItems(stringList);
    page->setCentralWidget(comboBox);
    page->appear();
}

void MyWindow::closeEvent(QCloseEvent *event)
{
    switch (comboBox->currentIndex()) {
    case 0: 
        mDebug("MyWindow") << "Ignore closeEvent(). Window is not closed.";
        event->ignore(); 
        break;
    case 1: 
        mDebug("MyWindow") << "Lazy shutdown - hide the window";
        setCloseOnLazyShutdown(false);
        event->accept(); 
        break;
    case 2:
    default: 
        mDebug("MyWindow") << "Lazy shutdown - really close the window";
        setCloseOnLazyShutdown(true);
        event->accept(); 
        break;
    }
}

int main(int argc, char **argv)
{
    MApplication app(argc, argv);
    MApplication::setPrestartMode(M::LazyShutdown);

    MyWindow *window = new MyWindow();
    window->show();
 
    return app.exec();
}

Example of using handlers

The following example shows a skeleton of a single-window application. If -prestart command line argument starts an application, it connects the signal for restoring the prestarted state to the slot that resets the page displayed in the window. Note: Showing and hiding the window does not require any actions from the application developer in single-window applications. For more information, see the default event handlers above.

// More complex LazyShutdown example using signals.
// Using M::TerminateOnClose is just as simple, you'd just
// set that mode without handling any prestart
// restores or resets.

class MainPage: public MApplicationPage 
{
public slots:
    // Activate widgets here
    void activateWidgets();

    // Deactivate widgets and reset state
    void resetState();
};

int main(int argc, char ** argv)
{
    MApplication app(argc, argv);
    MApplication::setPrestartMode(M::LazyShutdown);

    MApplicationWindow window;
    window.show();

    MainPage mainPage;
    mainPage.appear();

    // Reset the state of the page shown on the window
    // when application returns from the running state
    // to the prestarted state
    app.connect(&app, SIGNAL(prestartRestored()), 
                &mainPage, SLOT(resetState()));

    // Activate widgets when released from the prestarted state
    app.connect(&app, SIGNAL(prestartReleased()), 
                &mainPage, SLOT(activateWidgets()));

    // Check if app is NOT in the prestarted state. This might
    // happen for example if the application is launched from the 
    // application grid before Applifed has prestarted it or if it's
    // started without -prestart.

    if (!app.isPrestarted()) {
        // Activate widgets now
        mainPage.activateWidgets();
    }

    return app.exec();
}
// Example of an application that supports LazyShutdown -prestarting using virtual handlers 
// (cannot be compiled due to missing implementation for the example page):

class MyApplication : public MApplication
{
    Q_OBJECT

public:
    MyApplication(int argc, char ** argv);
    ~MyApplication();

    // Re-implementation
    virtual void releasePrestart();

    // Re-implementation
    virtual void restorePrestart();

private:

    // Main window
    MApplicationWindow * m_window;

    // MApplicationPage -derived page
    MainPage * m_page;
};

MyApplication::MyApplication(int argc, char ** argv) :
    MApplication(argc, argv)
{
    // Use the LazyShutdown mode
    setPrestartMode(M::LazyShutdown);

    m_window = new MApplicationWindow;
    m_window->show();

    m_page = new MApplicationPage;
    m_page->appear();

    // Run activateWidgets() here to setup things 
    // if app is NOT in the prestarted state, otherwise it 
    // will be called from the handler method.

    if (!isPrestarted()) {
        m_page->activateWidgets();
    }
}

void MyApplication::releasePrestart()
{
    // Your stuff here
    m_page->activateWidgets();

    // Call the default implementation to show the window.
    MApplication::releasePrestart();
}

void MyApplication::restorePrestart()
{
    // Your stuff here
    m_page->deactivateAndResetWidgets();

    // Call the default implementation to hide the window.
    MApplication::restorePrestart();
}

MyApplication::~MyApplication()
{
    delete m_window;
    delete m_page;
}

int main(int argc, char ** argv)
{
    MyApplication app(argc, argv);
    return app.exec();
}

Copyright © 2010 Nokia Corporation
MeeGo Touch