Development Guides: Simple Applications
Porting an Existing GTK Application

Introduction
This guide is designed to give Moblin project developers information on porting an existing GTK-based GUI application from your desktop to the Moblin environment. We will describe the major steps and considerations. This document will also provide a full example project, useful tips, and resources.

This document assumes that the reader is/has:

This guide is not a complete programming manual for Moblin developers, and doesn't provide intensive programming reference for Moblin application developers, however, it does provide an introduction, a high level technical overview, and an entry level programming guide to Moblin application developers, who intend to work on Moblin with an existing GTK code base.

The first part of this guide provides outlined steps and considerations for developers who want to port GTK-based applications to Moblin.The second part will demonstrate steps described in the first part of the document by porting a sample project, "Cire", from the desktop to Moblin.

Major Porting Considerations and Steps

Overview
GTK+ is a multi-platform toolkit for creating GUIs. Offering a complete set of widgets, GTK+ is widely used for projects in Linux desktop arena and becomes the UI framework for GNOME projects, as well.

Hildon, introduced by Nokia in its Maemo open source project, extends GTK+ with enhanced widget collections and other useful libraries. The enhanced widget collection, and tools used to accelerate Hildon application development, form the so-called "Hildon Application Framework" for Maemo platform. GNOME-Mobile project may potentially use Hildon Application Framework, as well.

The Moblin application is based on Hildon. Due to the similarity between GTK+ and Hildon, porting an existing application from GTK to Moblin is generally not a difficult task, however, there are still a few things that need to be considered to make the application "perfect" in a MID platform, as opposed to a desktop environment.

Porting Considerations
Since MIDs are based on Low Power on Intel® Architecture (LPIA) , they support the x86 instruction set and full-featured Linux OS. Most GTK-based applications should work in Moblin with little modification. However, considering that a MID is a small mobile device, many factors should be taken into account during porting, besides just "making it work". Some porting considerations are discussed below and more detailed references are provided at the end of this section.

Hildonization
The Moblin application is based on Hildon. The first thing you need to do, when porting, is to "Hildonize" the application, which includes using HildonProgram object as the reference for the application instance, using the HildonWindow object as the reference for the main window, using Hildonized widgets, instead of standard GTK+ widgets, and using Hildon enhanced communication (LibOSSO) mechanism, as much as possible.

As we can see in the sample in the following section, Hildonizing an application doesn't necessarily require a lot of re-coding. Specifying Hildon libraries in the Makefile and adding a few lines of initialization code at application startup will do most of the job.

Hildonizing the application is generally a requirement for porting an application to Moblin. By doing this, the application will have Hildon-style widgets and appearance, which is a much friendlier UI for MID devices.

Screen Resolution
The Moblin application is required to support both 1024x600 and 800x480 screen resolutions. During porting, developers should consider UI layout, font size, and other UI elements to avoid control overlap, unreadable text, or frequent window scroll. Code may also need to be revisited to make sure the application can be properly displayed in both centered and full-screen modes, at two different screen resolutions.

User Interface Design
Like any other platform, Moblin also has some system components, such as the marquee (the task bar) and the status bar (to display WiFi status, battery status, or application specific information, etc), which need to be displayed along with application, which require that the design of the application's UI follows some rules

In general, the application UI design is required to follow the guidelines described in "Mobile Internet Device Application User Interface Design Guide", which can be found here.

Input Method
MIDs, like many other mobile devices, has a restricted screen size and may lack a standard built-in keyboard and mouse. When porting applications from the desktop to Moblin, developers must handle the onscreen keyboard whenever input is needed. It may include a bunch of tasks, such as launching the onscreen keyboard, handling events, and re-packing the UI, when the onscreen keyboard is displayed, etc. Actually, in Moblin, the onscreen soft keyboard is a built-in component and an application is generally transparent to it. The only thing an application needs to be aware of is good UI design to accommodate the onscreen keyboard because it occupies a lot of space when its launched.

Although not a requirement, making the ported application finger- and stylus-friendly is recommended. For instance, applications accept finger or stylus tapping as primary mouse button clicks and cannot interpret when a user intends to right-click. Applications that rely on context-menus need to make the menu options accessible by another means. If a user touches a widget, applications will likely interpret this as a mouse-click. There are features that developers can add and techniques they can follow that can significantly improve the user experience, and make the application more attractive and intuitive.

Power Management
Power savings is always a consideration for any battery-supplied device, now even within the computer industry. Although it is not required, it would be great if developers for Moblin applications could review the application logic and simplify features to make the application aware of system power status, optimize for tickless-idle, and maintain minimum computing during idle.

For more information, tips, tools and tricks, refer to Lesswatts.

More to Consider
The above requirements and recommendations are certainly not the full set to consider when making a port from GTK to Moblin "perfect". Many other factors, such as feature simplification, performance, and stability/robustness should also be considered during the process. ...

General Porting Steps
Below is a list of recommended general porting steps. Each step will be explained by sample code in the following chapter.

  1. Modify the build file and make the GTK application build-able in the Moblin Image Creator-created Moblin developed environment.
  2. Run and test unmodified applications in the Moblin target. Fix issues, if there are any.
  3. Hildonize the application and test it again in the Moblin target.
  4. Analyze test result and redesign the UI, if possible.
  5. Port for new UI design, input method, screen resolution, etc.
  6. Perform the final build and test in the Moblin Image Creator target or real MID device.

Porting "Cire" from GNOME Desktop to Moblin

Overview
Cire is a Free and Open-Source Program for keeping an electronic journal or diary. It is a program based on GTK. It can be used to keep a Personal Diary, keep a log of progress on a programming project, or encrypt messages to friends (put the Message in a Diary File, encrypt it, send friend the diary file, have them decrypt it).

The source code is under GPL v2 and can be downloaded from http://cire.sourceforge.net

You can also download our Cire application from here.

It is may be beneficial to check out Cire on your desktop system to make sure that you understand how the UI looks and operates in its native environment. After downloading and extracting the Cire source, you can configure, make, and install the software on your workstation and run the application with the command cire -g

The below figure shows the Cire program running on a desktop:

Figure 3-1: Cire Running on Desktop.

As we begin porting Cire, we will need to build the code on a mobile platform. We can use Moblin Image Creator to create a target file-system and build-environment, and do all of our porting work as a chroot into the target. Before modifying code, this document assumes the Moblin development environment has already been set up and configured using the Moblin Image Creator. If you need help setting up the target environment using the Moblin Image Creator, or using the Moblin Image Creator to program applications for mobile devices, refer to our guides, Installing Moblin Image Creator and Using Moblin Image Creator.

Porting Step 1: Build and Run on Moblin
As the first step of porting, making the program build-able and run-able on the Moblin target image is the first thing we need to do.

Cire is a relatively simple program and doesn't use any additional lib other than GTK. Due to the similarity between MID and desktop platforms, Cire can be built and run directly on Moblin without any modification. Use the commands below to build Cire and send the executable to Moblin Target. The "--prefix" option is optional, depending on how you set up your Moblin target system. If you just develop Cire in a target, you can just ignore the option and use "./configure" directly.

Cire itself has several different type of UI built-in. Because we are going to check GUI, we need to use "cire -g" to launch the GTK-based UI. From the target's terminal, use the following commands to build and run Cire:
# cd src/cire-0.14.0
# ./configure -prefix=/usr
# make
# make install

The program can now be launched in the Moblin target:
# cire -g
If you ran the application now, it would look like this:
Figure 3-2: Unmodified Cire Running on Moblin.

Porting Step 2: Hildonize Cire
After Cire is build-able and run-able on Moblin, we can then further use Hildon as the application framework. To use Hildon, you need to include the Hildon libraries in the build file "configure.ac".

We should add the following snippets to the file configure.ac, which is found in the cire-0.14.0 folder:
AC_ARG_WITH(
    hildon,
    AC_HELP_STRING( [--with-hildon], [build the hildon user interface (default=yes)] ),
    [
        if test $withval = "no"
        then
            build_hildon="false"
        else
            build_hildon="true"
        fi
    ],
    [ build_hildon="true" ]
)

if test $build_hildon = "true"
then
    PKG_CHECK_MODULES(
        GTK,
        gtk+-2.0 >= 2.0.2,
        [
            AC_DEFINE(BUILD_GTK_UI)
            LIBS="$LIBS $GTK_LIBS"
            CFLAGS="$CFLAGS $GTK_CFLAGS"
        ],
        [ AC_MSG_WARN([Couldn't find GTK, building without it.]) ]
    )

    PKG_CHECK_MODULES(
        HILDON,
        hildon-1,
        [
            AC_DEFINE([ENABLE_HILDON],[],[Build with Hildon App Framework])
            LIBS="$LIBS $HILDON_LIBS"
            CFLAGS="$CFLAGS $HILDON_CFLAGS"
        ],
        [ AC_MSG_WARN([Couldn't find lib Hildon]) ]
    )
    else
    PKG_CHECK_MODULES(
        GTK,
        gtk+-2.0 >= 2.0.2,
        [
            AC_DEFINE(BUILD_GTK_UI)
            LIBS="$LIBS $GTK_LIBS"
            CFLAGS="$CFLAGS $GTK_CFLAGS"
        ],
        [ AC_MSG_WARN([Couldn't find GTK, building without it.]) ]
    )
fi
...

As minimum requirements, HildonWindow and HildonProgram need to be used as main program instances and window objects. Open the file src/gtk_ui_main.c and find the following lines:
#ifdef BUILD_GTK_UI

#include "main.h"

And add the following lines:
#ifdef BUILD_GTK_UI

#ifdef ENABLE_HILDON
#include<hildon-1/hildon/hildon-program.h>
#include <hildon-1/hildon/hildon-window.h>
#endif


#include "main.h"

In the gtk_ui_main() function, find the lines:
/************ main window **********/
data.window_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);
set_title_bar_text(&data, "Untitled");

And change them to:
/************ main window **********/
#ifdef ENABLE_HILDON
hildonProgram = HILDON_PROGRAM(hildon_program_get_instance());
data.window_main = hildon_window_new();
hildon_program_add_window(hildonProgram,
HILDON_WINDOW(data.window_main));
#else
data.window_main = gtk_window_new(GTK_WINDOW_TOPLEVEL);
set_title_bar_text(&data, "Untitled");
#endif

The program can now be launched in the Moblin target. Note that the UI elements, such as all the menu items, are now Hildon style (with light blue color).

Figure 3-3: Hildonized Cire Running on Moblin.

Porting Step 3: UI Design Review
So far, the application runs, but not "perfectly" in MID, so let's take a close look:

  • Hildonization: basic Hildon integration is done, but there's more to add, such as the Hildon menu, toolbar, and LibOSSO integration, etc.
  • Screen resolution: the main UI of the app is sizable and looks good in both 800x480 and 1024x600 resolutions. Leave it unmodified.
  • Dialogs: these are designed for the desktop and look ugly on the MID.
  • Simplicity: the application needs to be simplified. There are too many menu items, and they are displayed too compactly, which is not suitable for finger or stylus use.
  • Input Method: The Moblin built-in, onscreen keyboard works well for Cire. The re-sizeable main UI makes the application work well in both onscreen present and non-present states. The compact menu items are not finger or stylus friendly.
  • App Framework Integration: needs a desktop file to show and launch this application on the Moblin home screen. Registering to LibOSSO is required for Moblin applications.
In the following section, changes will be applied based on the points made above.

Porting Step 4: Coding to Refine UI
To make this application looks native in Moblin, we choose to add a hildon toolbar, instead of the complex menu items because the toolbar button is much easier to reach on a MID device. We will also refine the menu to hildon style, which has only one menu under the application title bar. We will continue to edit src/gtk_ui_main.c and add a few functions to do so.

  • Add a new function "create_hildon_toolbar" to create a Hildon-style toolbar and connect signal handlers to each toolbar item. The Hildon-style toolbar will show up at the bottom of screen in a separate pane from the main UI window.
  • Add a new function "create_hildon_menu" to create Hildon-style menu items, reformat the menu layouts, and connect signal handlers to each menu item.
  • Add, to the "gtk_ui_main" function, the necessary code to display our newly created menu and toolbar, listed above.

Here's the code to do this:
//
// Code to illustrate how to create hildon toolbar. Code snippet from
// gtk_ui_main.c
//
GtkWidget*
create_hildon_toolbar( struct gtk_ui_data *data )
{
    GtkToolbar *toolbar    = NULL;
    GtkToolItem *tbDairyNew = NULL, *tbDairyOpen = NULL,

    /* create toolbar butoons and install them into toolbar widget */
    toolbar    = GTK_TOOLBAR(gtk_toolbar_new());
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);

    tbDairyNew = gtk_tool_button_new_from_stock(GTK_STOCK_NEW);
    tbDairyOpen = gtk_tool_button_new_from_stock(GTK_STOCK_OPEN);

    ...

    gtk_toolbar_insert(toolbar, tbDairyNew, -1);
    gtk_toolbar_insert(toolbar, tbDairyOpen, -1);

    ...

    /* connect event handler to each toolbar button */
    g_signal_connect(G_OBJECT(tbDairyNew), "clicked",
            G_CALLBACK(hildon_toolbar_diary_new_activate), data);
    g_signal_connect(G_OBJECT(tbDairyOpen), "clicked",
            G_CALLBACK(hildon_toolbar_diary_open_activate), data);
    ...

    return GTK_WIDGET(toolbar);
}

int
gtk_ui_main( int argc, char** argv)
{
...

    #ifdef ENABLE_HILDON
        /* create hildon toolbar */
        data.hildonMainToolbar = create_hildon_toolbar(&data);
        hildon_window_add_toolbar(HILDON_WINDOW(data.window_main),
            GTK_TOOLBAR(data.hildonMainToolbar));
        /* create hildon menu */
        data.menu_bar_main = create_hildon_menu(&data);
        hildon_program_set_common_menu(
                data.hildonProgram,
                GTK_MENU(data.menu_bar_main));

    #else
        data.menu_bar_main = create_menu_bar(data.window_main, &data);
        gtk_box_pack_start( GTK_BOX(data.vbox_main), data.menu_bar_main,
            FALSE, FALSE, 0);
    #endif
...
}

Now, the application would look like this:

Figure 3-4: Refined Hildon UI with Toolbar Displayed.

Similarly to toolbar, you must refine the menu. The menu bar is reduced to one strip with all items inside.

This Hildon-style menu occupies no space in the application area and can be launched directly, by clicking the application title bar on the marquee.

We have highlighted some of the changes made to the code below:
//
// Code to illustruate hildon menu creation.
//
GtkItemFactoryEntry menu_items[] = {
    { "/_Diary", NULL, NULL, 0, "" },
    { "/Diary/_New", "N", G_CALLBACK(diary_new_activate),
        0, "", GTK_STOCK_NEW },
    { "/Diary/_Open...", "O", G_CALLBACK(diary_open_activate),
        0, "", GTK_STOCK_OPEN },
    { "/Diary/---", NULL, NULL, 0, "" },
    { "/Diary/_Save", "S", G_CALLBACK(diary_save_activate),
         0, "", GTK_STOCK_SAVE },

...
};

GtkWidget*
create_hildon_menu( struct gtk_ui_data *data )
{
    GtkAccelGroup *accel_group = NULL;
    GtkWidget *main_menu = NULL;

    g_assert(data != NULL);
    accel_group = gtk_accel_group_new ();

    data->item_factory = gtk_item_factory_new ( GTK_TYPE_MENU, "
",
accel_group);

    /* Generates the menu items */
     gtk_item_factory_create_items (data->item_factory,
        data->n_factory_items,
        data->menu_factory_items, data);

    gtk_window_add_accel_group( GTK_WINDOW(data->window_main),
        accel_group);

    main_menu = gtk_item_factory_get_widget (data->item_factory,
"
");
    hildon_program_set_common_menu(data->hildonProgram,
GTK_MENU(main_menu));

    return main_menu;
}

As shown below, the menu is now Hildon-style and the main UI works well with the Moblin onscreen keyboard:

Figure 3-5: Refined Hildon Menu with Onscreen Keyboard Launched.

Porting Step 5: Application Framework Integration
A Moblin application needs to be integrated with the Moblin Application Framework. To do this, the minimum requirement for an application is to register with LibOSSO. This is done in the gtk_ui_main() function.

The following code shows how to register to and deregister from LibOSSO:
//
// Code sample to register and de-register with libosso
//
/* Register to libosso */
data.osso_ctx = osso_initialize (OSSO_MOBLIN_CIRE_SERVICE,
         OSSO_MOBLIN_CIRE_VERSION,
        TRUE, NULL);
g_assert (data.osso_ctx != NULL);
...

/* deinit osso */
if (data.osso_ctx != NULL)
{
    osso_deinitialize (data.osso_ctx);
}

In our example "Moblin-Cire", we implemented only the minimum registration part, but it may not enough for a real application to be functional. Refer to corresponding LibOSSO and Moblin application framework documentation for more detailed descriptions of how to implement the desktop file, the D-Bus service file and how to use LibOSSO commands.

Porting Step 6: Final Build and Test
So far, the major work to port "cire" to "moblin-cire" is done. As the last step, it is necessary to rebuild and test the application.

The "moblin-cire" should have the same UI shown in Figure 3-5 and all functions should work except "find entry" and "preference" dialogs, which were not intended to be part of this sample.

Reference Documents
The following documents were used as references in the writing of this document. Refer to these documents for further details.

  1. Maemo Online Training: Technology Overview - http://maemo.org/maemo_training_material/maemo4.x/html/maemo_Technology_Overview
  2. Maemo Online Training: Application Development - http://maemo.org/maemo_training_material/maemo4.x/html/maemo_Application_Development/index.html
  3. Maemo Online Training: Platform Development - http://maemo.org/maemo_training_material/maemo4.x/html/maemo_Platform_Development/index.html
  4. Maemo 4 Architecture: http://maemo.org/development/documentation/how-tos/4-x/maemo_architecture.html
  5. Hildon Reference Manual: http://maemo.org/api_refs/4.0/hildon/index.html
  6. LibOSSO Documentation: http://maemo.org/api_refs/4.0/libosso/index.html