Chapter contents:

Appendix A contents

This appendix presents the final hello world program and the necessary support files. This list does not include the files that result from Debianization.

Autoconfigure driver

# The package name is hhwX (hildon helloworld 10).
# This will be lowercased when automake will create the distribution
# directories. The version number is currently set at 0.1, but new
# distributed versions should change this number (no other variables
# need be touched).
AC_INIT(hhwX, 0.1)

# Tell automake to prepare for real work.
# Check for the C compiler.
# Check that 'install' program is available (used by the automake
# generated Makefiles).

# Check whether the necessary pkg-config packages are present. The
# PKG_CHECK_MODULES macro is supplied by pkg-config
# (/usr/share/aclocal/).
# The first parameter will be the variable name prefix that will be
# used to create two variables: one to hold the CFLAGS required by
# the packages, and one to hold the LDFLAGS (LIBS) required by the
# packages. The variable name prefix (HHW) can be chosen freely.
PKG_CHECK_MODULES(HHW, gtk+-2.0 hildon-1 hildon-fm-2 gnome-vfs-2.0 \
                       gconf-2.0 libosso)
# At this point HHW_CFLAGS will contain the necessary compiler flags
# and HHW_LIBS will contain the linker options necessary for all the
# packages listed above.
# Add the pkg-config supplied values to the ones that are used by
# Makefile or supplied by the user running ./configure.

# Generate the Makefile from

# Generate the service and desktop files based on the templates.
AC_OUTPUT(hhwX.desktop org.maemo.hhwX.service)

[ Contents of integration/hhwx-autotoolized/ ]

Automake configuration

# List of the filenames of binaries that this project will produce.
bin_PROGRAMS = hhwX

# For each binary file name, list the source files required for it to
# build. hhwX only consists of one program and that only requires one
# source code file. This is rather atypical.
hhwX_SOURCES = hhwX.c

# In order for the desktop and service to be copied into the correct
# places (and to support prefix-redirection), use the following
# configuration:
# We described two directories and gave automake a list of files
# which are to be copied into these directories on install. Without
# these directives, the desktop and service files would never be
# installed even if they would be distributed (using EXTRA_DIST).

[ Contents of integration/hhwx-autotoolized/ ]

Desktop file template for AF

[Desktop Entry]
Name=HelloWorld X

[ Contents of integration/hhwx-autotoolized/ ]

Service file template for AF

[D-BUS Service]

[ Contents of integration/hhwx-autotoolized/ ]

Development bootstrap (autogen)

# An utility script to setup the autoconf environment for the first
# time. Normally this script would be run when checking out a
# development version of the software from SVN/version control.
# Regular users expect to download .tar.gz/tar.bz2 source code
# instead, and those should come with with 'configure' script so that
# users do not require the autoconf/automake tools.

# Scan and copy the necessary macros into aclocal.m4.

# Generate from (and copy necessary support
# files, because of -ac).
automake -ac

# This step is not normally necessary, but documented here for your
# convenience. The files listed below need to be present to stop
# automake from complaining during various phases of operation.
# You also should consider maintaining these files separately once
# you release your project into the wild.

# Run autoconf (will create the 'configure'-script).

echo 'Ready to go (run configure)'

[ Contents of integration/hhwx-autotoolized/ ]

Development cleanup (antigen)

# An utility script to remove all generated files.
# Running will be required after running this script since
# the 'configure' script will also be removed.
# This script is mainly useful when testing autoconf/automake changes
# and as a part of their development process.

# If there's a Makefile, then run the 'distclean' target first (which
# will also remove the Makefile).
if test -f Makefile; then
  make distclean

# Remove all tar-files (assuming there are some packages).
rm -f *.tar.* *.tgz

# Also remove the autotools cache directory.
rm -Rf autom4te.cache

# Remove rest of the generated files.
rm -f aclocal.m4 configure depcomp install-sh missing

[ Contents of integration/hhwx-autotoolized/ ]

Program listing

 * hhwX.c (hildon_helloworld-10)
 * This maemo code example is licensed under a MIT-style license,
 * that can be found in the file called "License" in the same
 * directory as this file.
 * Copyright (c) 2007 Nokia Corporation. All rights reserved.
 * Source code of hhwX.c with comments.

#include <stdlib.h>
#include <hildon/hildon-program.h>
#include <hildon/hildon-color-button.h>
/* Pull in the Hildon Find toolbar declarations. */
#include <hildon/hildon-find-toolbar.h>
/* We need HildonFileChooserDialog.
     The include file is not in the same location as the other Hildon
     widgets, but instead is part of the hildon-fm-2 package. So
     in fact, the "hildon/"-prefix below points to a completely
     different directories than the ones above. */
#include <hildon/hildon-file-chooser-dialog.h>
/* A small notification window widget. */
#include <hildon/hildon-banner.h>
/* Pull in the GnomeVFS headers. */
#include <libgnomevfs/gnome-vfs.h>
/* Include the prototypes for GConf client functions. */
#include <gconf/gconf-client.h>
/* Pull in the LibOSSO library declarations. */
#include <libosso.h>

/* The application name -part of the GConf namespace. */
#define APP_NAME "hildon_hello"
/* This will be the root "directory" for our preferences. */
#define GC_ROOT  "/apps/Maemo/" APP_NAME "/"

/* Build up the D-Bus name for this application. */

/* Declare the two slant styles. */
enum {

 * This is all of the data that our application needs to run
 * properly. Rest of the data is not needed by our application so we
 * can leave that for GTK+ to handle (references and all).
typedef struct {
  /* Underlining active for text? Either TRUE or FALSE. */
  gboolean styleUseUnderline;
  /* Currently selected slant for text. Either STYLE_SLANT_NORMAL or
  gboolean styleSlant;

  /* The currently selected color. */
  GdkColor currentColor;

  /* Pointer to the label so that we can modify its contents when a
     file is loaded by the user. */
  GtkWidget* textLabel;

  /* Are we in fullscreen mode or not? */
  gboolean fullScreen;

  /* We need to keep pointers to these two widgets so that we can
     control their visibility from callbacks. */
  GtkWidget* findToolbar;
  GtkWidget* mainToolbar;
  /* We'll also keep visibility flags for both of the toolbars.

     You could also test widget-visibility like this:
     if (GTK_WIDGET_VISIBLE(widget)) { .. }; */
  gboolean findToolbarIsVisible;
  gboolean mainToolbarIsVisible;

  /* Pointer to our HildonProgram. */
  HildonProgram* program;
  /* Pointer to our main Window. */
  HildonWindow* window;
} ApplicationState;

 * Turns the delete event from the top-level Window into a window
 * destruction signal (by returning FALSE).
static gboolean cbEventDelete(GtkWidget* widget, GdkEvent* event,
                              ApplicationState* app) {
  return FALSE;

 * Handles the 'destroy' signal by quitting the application.
static void cbActionTopDestroy(GtkWidget* widget,
                               ApplicationState* app) {

 * Create a file chooser dialog and return a filename that user
 * selects.
 * Parameters:
 * - application state: we need a pointer to the main application
 *   window and HildonProgram is extended from GtkWindow, so we'll
 *   use that. This is because we want to create a modal dialog
 *   (which normally would be a bad idea, but not always for
 *   applications designed for maemo).
 * - what kind of file chooser should be displayed:
 * Returns:
 * - A newly allocated string that we need to free ourselves or NULL
 *   if user will cancel the dialog.
static gchar* runFileChooser(ApplicationState* app,
                             GtkFileChooserAction style) {

  GtkWidget* dialog = NULL;
  gchar* filename = NULL;

  g_assert(app != NULL);

  g_print("runFilechooser: invoked\n");

  /* Create the dialog (not shown yet). */
  dialog = hildon_file_chooser_dialog_new(GTK_WINDOW(app->window),

  /* Enable its visibility. */

  /* Divert the GTK+ main loop to handle events from this dialog.
     We'll return into this function when the dialog will be exited
     by the user. The dialog resources will still be allocated at
     that point. */
  g_print(" running dialog\n");
  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) {
    /* We got something from the dialog at least. Copy a point to it
       into filename and we'll return that to caller shortly. */
    filename =
  g_print(" dialog completed\n");

  /* Destroy all the resources of the dialog. */

  if (filename != NULL) {
    g_print(" user selected filename '%s'\n", filename);
  } else {
    g_print(" user didn't select any filename\n");

  return filename;

 * Utility function to print a GnomeVFS I/O related error message to
 * standard error (not seen by the user in graphical mode).
static void dbgFileError(GnomeVFSResult errCode, const gchar* uri) {
  g_printerr("Error while accessing '%s': %s\n", uri,

 * We read in the file selected by the user if possible and set the
 * contents of the file as the new Label content.
 * If reading the file will fail, we leave the label unchanged.
static void cbActionOpen(GtkWidget* widget, ApplicationState* app) {

  gchar* filename = NULL;
  /* We need to use URIs with GnomeVFS, so declare one here. */
  gchar* uri = NULL;

  g_assert(app != NULL);
  /* Bad things will happen if these two widgets don't exist. */

  g_print("cbActionOpen invoked\n");

  /* Ask the user to select a file to open. */
  filename = runFileChooser(app, GTK_FILE_CHOOSER_ACTION_OPEN);
  if (filename) {
    /* This will point to loaded data buffer. */
    gchar* buffer = NULL;
    /* Pointer to a structure describing an open GnomeVFS "file". */
    GnomeVFSHandle* fileHandle = NULL;
    /* Structure to hold information about a "file", initialized to
       zero. */
    GnomeVFSFileInfo fileInfo = {};
    /* Result code from the GnomeVFS operations. */
    GnomeVFSResult result;
    /* Size of the file (in bytes) that we'll read in. */
    GnomeVFSFileSize fileSize = 0;
    /* Number of bytes that were read in successfully. */
    GnomeVFSFileSize readCount = 0;

    g_print("  you chose to load file '%s'\n", filename);

    /* Convert the filename into an GnomeVFS URI. */
    uri = gnome_vfs_get_uri_from_local_path(filename);
    /* We don't need the original filename anymore. */
    filename = NULL;
    /* Should not happen since we got a filename before. */
    g_assert(uri != NULL);
    /* Attempt to get file size first. We need to get information
       about the file and aren't interested in other than the very
       basic information, so we'll use the INFO_DEFAULT setting. */
    result = gnome_vfs_get_file_info(uri, &fileInfo,
    if (result != GNOME_VFS_OK) {
      /* There was a failure. Print a debug error message and break
         out into error handling. */
      dbgFileError(result, uri);
      goto error;

    /* We got the information (maybe). Let's check whether it
       contains the data that we need. */
    if (fileInfo.valid_fields & GNOME_VFS_FILE_INFO_FIELDS_SIZE) {
      /* Yes, we got the file size. */
      fileSize = fileInfo.size;
    } else {
      g_printerr("Couldn't get the size of file!\n");
      goto error;

    /* By now we have the file size to read in. Check for some limits
       first. */
    if (fileSize > 1024*100) {
      g_printerr("Loading over 100KiB files is not supported!\n");
      goto error;
    /* Refuse to load empty files. */
    if (fileSize == 0) {
      g_printerr("Refusing to load an empty file\n");
      goto error;

    /* Allocate memory for the contents and fill it with zeroes.
         We leave space for the terminating zero so that we can pass
         this buffer as gchar to string functions and it is
         guaranteed to be terminated, even if the file doesn't end
         with binary zero (odds of that happening are small). */
    buffer = g_malloc0(fileSize+1);
    if (buffer == NULL) {
      g_printerr("Failed to allocate %u bytes for buffer\n",
      goto error;

    /* Open the file.

       - A pointer to the location where to store the address of the
         new GnomeVFS file handle (created internally in open).
       - uri: What to open (needs to be GnomeVFS URI).
       - open-flags: Flags that tell what we plan to use the handle
         for. This will affect how permissions are checked by the
         Linux kernel. */

    result = gnome_vfs_open(&fileHandle, uri, GNOME_VFS_OPEN_READ);
    if (result != GNOME_VFS_OK) {
      dbgFileError(result, uri);
      goto error;
    /* File opened succesfully, read its contents in. */
    result = gnome_vfs_read(fileHandle, buffer