Maemo 4.0 Porting Guide
This document has been reviewed for maemo 4.0.
This document describes porting existing GTK+ applications to the maemo 4.0 environment.
This tutorial is best studied with the Maemo 4.0 Tutorial and How to write new applications in maemo 4.0
Porting existing application to maemo 4.0
Describes how to port an existing application to maemo 4.0.
Overview
This section describes the porting process of an application to maemo platform [1]. When starting to port an application to maemo platform, the first phase is to set up the development environment, described in the section 2 of the maemo SDK Tutorial [2]. The actual porting after that is described in this document.
Introduction
Application that is used as an example for porting is Monkey Bubble [3], a GNOME/GTK+ based game. It has simple controls, and supports network play. Monkey Bubble version 0.4.1 is used in this example. The ported version for maemo 4.0 can be found (both source package and binaries) in maemo.org
Monkey Bubble interface consists of the main window, menus and a couple of dialogs.
Illustration 1 Monkey Bubble main window
The Illustration 1 is a screenshot of the main window with an ongoing game. Game is played with configurable keys, defaults are the arrow keys: left, right and up. Target is to make all the bubbles disappear. When three or more bubbles with the same color are grouped, they will disappear.
Illustration 2 Network game window
The Illustration 2 is a screenshot of the network game window, where user can join a network game. It includes field for selecting server, status about players and game and control buttons.
Application File Structure
Monkey Bubble already has a nicely structured source tree, so there was no need to modify it. XML-formatted Glade[4] files can be found in data directory. Help files can be found in help directory. Graphics can be found in pixmaps directory. Localization files are located in po directory. Audio files can be found in sounds directory. The source code itself is located under src directory in subdirectories, such as audio, input, monkey, net, ui, util and view.
./po ./data ./pixmaps ./pixmaps/bubbles ./pixmaps/frozen-bubble ./pixmaps/snake ./pixmaps/number ./sounds ./src ./src/util ./src/input ./src/monkey ./src/view ./src/audio ./src/net ./src/ui ./help ./help/C ./help/frSee also Creating Application Files Structure in How to write new applications in maemo 4.0.
Requirements and Configure Changes
Monkey Bubble already uses GNU autotools, so the needed Makefile.am and configure.in files are there. Only autogen.sh was missing, so it was created. More about GNU autotools use can be read from GNU development tools tutorial [5]. Chapters 5, 6 and 7 discuss the changes needed in Makefile.am and configure.ac files.
autogen.sh
#!/bin/sh set -x glib-gettextize --copy --force libtoolize --automake intltoolize --copy --force --automake aclocal-1.7 autoconf autoheader automake-1.7 --add-missing --foreign
Remember to set this executable with chmod a+x autogen.sh
.
Maemo SDK meets most of the Monkey Bubble requirements. Biggest exceptions are libgnomeui, bonobo and librsvg. After checking the sources, the libgnomeui and bonobo dependencies can be removed. So, librsvg and its dependencies are additionally needed to be installed.
Start from librsvg installation. One version is available in Chinook extras. Install from there the following packages:
librsvg2-2 librsvg2-common librsvg2-dev
Then the configure.in
file needs to be modified. Dependency to libgnomeui-2.0
must be
removed. And because the UI is going to be hildonized,
hildon-1
and libosso
need to be added to the list
between PKG_CHECK_MODULES(UI,[
and
following ])
.
From Makefile.am
, remove the help
from SUBDIRS list, because the provided help is incompatible
with Hildon help framework. Remove
line help/Makefile
from configure.in
AC_OUTPUT
section
as well. Additionally, help can be implemented but it is out of
the scope of this HOW-TO.
After the changes, autogen.sh
must be executed
to apply the changes.
Basic porting
Localization and src/ui/main.c
The very first thing is to get Monkey Bubble to work on maemo environment. For localization, Monkey Bubble uses bonobo. It must be replaced with compatible localization, described in more detail in Localization HOW-TO [9].
First, localization must be initialized in src/ui/main.c
. The following lines must be removed from it:
#include <bonobo/bonobo-i18n.h> #include <libgnomeui/gnome-ui-init.h>
These lines must be added:
#include <locale.h> #include <libintl.h>
And new lines in the main()
function before bindtextdomain
function call:
if(!g_thread_supported()) { g_thread_init(NULL); } setlocale(LC_ALL, ""); bind_textdomain_codeset(PACKAGE, "UTF-8");
Remove also the gnome_program_init
function call.
For the localization to work, the line #include <bonobo/bonobo-i18n.h>
needs to be removed. In order to make the strings localizable, they need to be wrapped in gettext("String")
calls. In practice, writing gettext()
for every string is tedious. The common practice is to set the following #defines. The N_ is used for gettext_noop()
,
but it is not available, so the macro does nothing. So the following lines
must be added to the beginning of every file using localization:
#include <libintl.h> #define _(String) gettext(String) #define N_(String) (String)
Files using localization include the following:
src/ui/keyboard-properties.c src/ui/ui-network-client.c src/ui/ui-network-server.c src/ui/ui-main.c
Removing GNOME features
Next thing is to remove other GNOME functionality. File src/ui/ui-main.c
is next to edit. Remove the following include lines:
#include <libgnomeui/gnome-about.h> #include <libgnome/gnome-sound.h> #include <libgnome/gnome-help.h>
Then comment out contents of functions about
and show_help_content
, and remove completely function show_error_dialog
and its prototype from the beginning.
Now the game can be configured and compiled with following commands:
./autogen.sh ./configure make
Everything should go fine and the game should be compiled properly. When trying to install and run the game, the following should be seen:
Illustration 3 Monkey Bubble on maemo
This is fine, but it can be seen that the borders and menus are not hildonized. Also, if menu functionality is tried, they will not fit there nicely. So the next step is customization.
User Interface Changes
Hildonizing Main View
Monkey bubble uses Glade[4] for its UI creation. Unfortunately, Glade does not support Hildon, so some changes have to be made.
First of all, in data/monkey-bubble.glade
the main_window type GtkWindow
must be changed to GtkVBox
.
Then all window properties, except "visible" must be removed. After that,
the menu must be removed. That is done by removing completely the child
containing GtkMenuBar
and its subchildren.
Next the src/ui/ui-main.c
function ui_main_new
should be changed. Add following lines to the beginning of the function, and remove the KeyboardProperties * kp;
line:
HildonProgram * program; GtkWidget * container; GtkWidget * main_menu;
Then make following modifications; the old code is commented out and new lines added after it:
/* PRIVATE(ui_main)->window = glade_xml_get_widget( PRIVATE(ui_main)->glade_xml, "main_window"); */ container = glade_xml_get_widget( PRIVATE(ui_main)->glade_xml, "main_window"); program = HILDON_PROGRAM(hildon_program_get_instance()); PRIVATE(ui_main)->window = hildon_window_new(); g_signal_connect_swapped(PRIVATE(ui_main)->window ,"destroy",GTK_SIGNAL_FUNC(quit_program),ui_main); hildon_program_add_window(program, HILDON_WINDOW(PRIVATE(ui_main)->window)); gtk_container_add(GTK_CONTAINER(PRIVATE(ui_main)->window), GTK_WIDGET(container)); g_set_application_name(_("Monkey Bubble"));
Because the menu was removed from the Glade file,
it must be constructed manually in Hildon-compatible way. Also, not
all the functionality provided by the old menu is needed, so things can be left
out. Needed parts are new game, join network game, pause and quit.
Such a tiny menu can be constructed after gtk_box_pack_end
function call:
main_menu = gtk_menu_new(); item = gtk_menu_item_new_with_label(_("New game")); g_signal_connect_swapped( item,"activate",GTK_SIGNAL_FUNC(new_1_player_game),ui_main); gtk_menu_append(main_menu, item); item = gtk_menu_item_new_with_label(_("Join network game")); g_signal_connect_swapped( item,"activate",GTK_SIGNAL_FUNC(new_network_game),ui_main); gtk_menu_append(main_menu, item); item = gtk_menu_item_new_with_label(_("Pause")); g_signal_connect_swapped( item,"activate",GTK_SIGNAL_FUNC(pause_game),ui_main); gtk_menu_append(main_menu, item); item = gtk_menu_item_new_with_label(_("Quit")); g_signal_connect_swapped( item,"activate",GTK_SIGNAL_FUNC(quit_program),ui_main); gtk_menu_append(main_menu, item); hildon_window_set_menu(HILDON_WINDOW(PRIVATE(ui_main)->window), GTK_MENU(main_menu)); gtk_widget_show_all(GTK_WIDGET(main_menu));
After that the code related to the old menu can be removed, starting from the next line and ending to g_signal_connect_swapped
function call, the latter being the last removed line. Also the unneeded functions and their prototypes need to be removed:
ui_main_new_2_player_game new_2_player_game new_network_server stop_game about show_help_content show_preferences_dialog
Remember to add proper include to the beginning of the file:
#include <hildon/hildon-program.h>
Now the main view and menu should be hildonized properly and look like:
Illustration 4 Hildonized Monkey Bubble on maemo
Hildonizing Network Window
The Network game window shown in the Illustration 5 is still GtkWindow, and is not hildonized properly. The solution is to make it GtkVBox and place it under a new GtkDialog.
Illustration 5 Network game window
The starting point here is the glade file located at data/netgame.glade
. Change the GtkWindow to GtkVBox and remove all properties except "visible". Change GtkScrolledWindow
widget property "height_request" to the value 200 to make everything
fit on the screen. A close button is also missing now, because Monkey
Bubble relies on the close button of GtkWindow. There is a nice place
between "quit game" and "ready" buttons. You can just copy-paste the
whole child containing "quit_button" widget, rename it as
"close_button", change the number values of the other widgets name
under it for example to 9 to prevent collisions and change the GtkLabel
"Quit game" to "Close". That is enough for the glade file.
Next, the src/ui/ui-network-client.c
and ui_network_client_new
functions. Add this line to the beginning of the function:
GtkWidget * container;
Make following changes to create a new GtkDialog and show network_window contents under it. Old code is commented out and the new lines added after it:
/* PRIVATE(ngl)->window = glade_xml_get_widget( PRIVATE(ngl)->glade_xml, "network_window"); */ PRIVATE(ngl)->window = gtk_dialog_new(); gtk_window_set_title(GTK_WINDOW(PRIVATE(ngl)->window), _("Network game")); container = glade_xml_get_widget( PRIVATE(ngl)->glade_xml, "network_window"); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(PRIVATE(ngl)->window)->vbox), container); item = glade_xml_get_widget( PRIVATE(ngl)->glade_xml, "close_button"); g_signal_connect_swapped( item,"clicked",GTK_SIGNAL_FUNC(close_signal),ngl);
And to the end of the ui_network_client_new
function, before return, add the following line:
gtk_widget_show_all(GTK_WIDGET(PRIVATE(ngl)->window));
A new function is needed, called close_signal
, which is called when the close button is pressed. Add this function before the ui_network_client_new
function:
static gboolean close_signal(gpointer callback_data, guint callback_action, GtkWidget *widget) { UiNetworkClient * self; self = UI_NETWORK_CLIENT(callback_data); quit_signal(callback_data, callback_action, widget); gtk_widget_hide_all(PRIVATE(self)->window); return FALSE; }
There is still one problem: The new close button
is located in "connected_game_hbox" widget, which is set insensitive
when not connected to the server. The ability to close the window is
always needed. The sensitivity of the other widgets has to be changed properly. Add
this new function after the previously added close_signal
function:
void connected_set_sensitive(UiNetworkClient * ngl, gboolean sensitive) { set_sensitive( glade_xml_get_widget( PRIVATE(ngl)->glade_xml ,"scrolledwindow2"), sensitive); set_sensitive( glade_xml_get_widget( PRIVATE(ngl)->glade_xml ,"quit_button"), sensitive); set_sensitive( glade_xml_get_widget( PRIVATE(ngl)->glade_xml ,"ready_button"), sensitive); }
There is one gtk_widget_set_sensitive
function call in ui_network_client_new
and multiple set_sensitive
calls for connected_game_hbox
; replace these with:
connected_set_sensitive(ngl, FALSE);
There is also one call in recv_network_xml_message
function, where the boolean value must be TRUE.
That is all; network game dialog should be now hildonized and contain a new close button. The "quit game", "ready" and player list should change their sensitivity properly upon connected and disconnected states.
Illustration 6 Hildonized network game dialog
State Saving
Maemo supports state saving and background killing application. Application can later be loaded up again with the same state as before. See Maemo tutorial for more information. This section describes the steps needed to make Monkey Bubble support state savings.
State Saving Changes in src/ui
some new files need to be created, first file for global data src/ui/global.h
:
#ifndef GLOBAL_H #define GLOBAL_H #include <libosso.h> #include "game-1-player.h" #define MONKEY_TEMP "/tmp/monkey_level_state" struct GlobalData { osso_context_t *osso; Game1Player *game; }; struct StateData { int game; int level; int score; int loadmap; }; extern struct StateData state; extern struct GlobalData global; #endif
Second one is src/ui/state.h
:
#ifndef STATE_H #define STATE_H #include <glib.h> gboolean state_load(void); gboolean state_save(void); void state_clear(void); #endif
Then src/ui/state.c
, implementing loading, saving and cleaning the state:
#include <libosso.h> #include "state.h" #include "global.h" struct StateData state; gboolean state_load(void) { osso_state_t osso_state; osso_return_t ret; osso_state.state_size = sizeof(struct StateData); osso_state.state_data = &state; ret = osso_state_read(global.osso, &osso_state); if (ret != OSSO_OK) return FALSE; return TRUE; } gboolean state_save(void) { osso_state_t osso_state; osso_return_t ret; osso_state.state_size = sizeof(struct StateData); osso_state.state_data = &state; ret = osso_state_write(global.osso, &osso_state); if (ret != OSSO_OK) return FALSE; return TRUE; } void state_clear(void) { state.game = 0; state.level = 0; state.score = 0; state.loadmap = 0; state_save(); }
These must be added to src/ui/Makefile.am
to monkey_bubble_SOURCES
list before $(NULL)
:
state.c state.h global.h \
Some changes to src/ui/main.c
, new includes, definitions and functions:
#include <libosso.h> #include "state.h" #include "global.h" #include "game-1-player.h" #define APPNAME "monkey_bubble" #define APPVERSION "0.0.1" struct GlobalData global; static void _top_cb(const char *args, gpointer data) { } static void _hw_cb(osso_hw_state_t * state, gpointer data) { if(state->shutdown_ind) { state_save(); gtk_main_quit(); } } osso_context_t *osso_init(void) { osso_context_t *osso = osso_initialize(APPNAME, APPVERSION, TRUE, NULL); if (OSSO_OK != osso_application_set_top_cb(osso, _top_cb, NULL)) return NULL; if (OSSO_OK != osso_hw_set_event_cb(osso, NULL, _hw_cb, NULL)) return NULL; return osso; }
And change the main()
function as follows:
global.osso = osso_init(); if (!global.osso) { perror("osso_init"); exit(1); } global.game = NULL; gtk_init(); /* This line already exists */ if (!state_load()) { perror("state_load"); } /* .... */ if (state.game == 1) { continue_game(); } gtk_main (); /* This line already exists */
Set the topmost callback in src/ui/ui-main.c
. It saves the current level and state when Monkey Bubble loses its topmost status, and sets the hibernate flag properly. New continue_game
function to continue after loading state:
#include "global.h" #include "state.h" static void ui_main_topmost_cb(GObject *self, GParamSpec *property_param, gpointer null) { HildonProgram *program = HILDON_PROGRAM(self); if (program == NULL) return; if (hildon_program_get_is_topmost(program)) { hildon_program_set_can_hibernate(program, FALSE); } else { if (state.game == 1 && global.game!=NULL) { game_1_player_save(global.game); state.loadmap=1; } state_save(); hildon_program_set_can_hibernate(program, TRUE); } } void continue_game(void) { UiMain * ui_main; ui_main = ui_main_get_instance(); ui_main_new_1_player_game(ui_main); }
In addition to the ui_main_new()
function, after g_set_application_name
function call:
g_signal_connect(G_OBJECT(program), "notify::is-topmost", G_CALLBACK(ui_main_topmost_cb), NULL);
To the new_1_player_game
function, add before ui_main_new_1_player_game
function call:
state_clear();
Function prototype must be added to src/ui/ui-main.h
:
void continue_game(void);
To game-1-player-manager.c
following changes to keep track of level and scores and continue from last level and score:
#include "global.h" /* ... */ static gboolean startnew_function(gpointer data) { /* ... */ PRIVATE(manager)->current_level++; state.level = PRIVATE(manager)->current_level; /* New line */ /* ... */ } static void game_1_player_manager_state_changed(Game * game, Game1PlayerManager * manager) { /* ... */ PRIVATE(manager)->current_score = game_1_player_get_score( GAME_1_PLAYER(game)); state.score = PRIVATE(manager)->current_score; /* New line */ /* ... */ } void game_1_player_manager_start(GameManager * g) { /* ... */ /* Old code: PRIVATE(manager)->current_level = 0; PRIVATE(manager)->current_score = 0; Replace with: */ if (state.game == 1 && state.level > 0 ) { PRIVATE(manager)->current_level = state.level; PRIVATE(manager)->current_score = state.score; } else { state.level = 0; PRIVATE(manager)->current_level = 0; PRIVATE(manager)->current_score = 0; } state.game = 1; /* ... */ }
The changes to src/ui/game-1-player.c
to save and load the level state:
#include "global.h" void game_1_player_save(Game1Player *game) { monkey_save(PRIVATE(game)->monkey, MONKEY_TEMP); } Game1Player * game_1_player_new(GtkWidget * window,MonkeyCanvas * canvas, int level,gint score) { /* ... */ /* Old code: PRIVATE(game)->monkey = monkey_new_level_from_file(DATADIR"/monkey-bubble/levels", level); Replace with: */ if (state.loadmap==1) { PRIVATE(game)->monkey = monkey_new_level_from_file(MONKEY_TEMP, 0); state.loadmap = 0; } else { PRIVATE(game)->monkey = monkey_new_level_from_file(DATADIR"/monkey-bubble/levels", level); } /* ... */ }
Add function prototype to src/ui/game-1-player.h
:
void game_1_player_save(Game1Player *game);
State Saving Changes in src/monkey
Add save feature to src/monkey/board.c
:
void board_save_to_file (Board * board, const char *filename) { #define MUL 4 GError *error = NULL; GIOChannel *channel; gint i, j, s=0; gchar buffer[COLUMN_COUNT*3+2]; gsize written = 0; if (PRIVATE(board)->bubble_array==NULL) return; channel = g_io_channel_new_file (filename, "w+", &error); if (channel == NULL) return; for (i = 0; i < ROW_COUNT; i++) { for (j = 0; j < COLUMN_COUNT*MUL; j++) buffer[j] = ' '; if (i%2==1) { s = 2; } else { s = 0; } for (j = 0; j < COLUMN_COUNT; j++) { Bubble *b; Color c; if (s>0 && (j+1==COLUMN_COUNT)) break; b = PRIVATE(board)->bubble_array[i*COLUMN_COUNT+j]; if (b!=NULL) { c = bubble_get_color(b); buffer[j*MUL+s] = '0'+(int)c; } else { buffer[j*MUL+s] = '-'; } } buffer[COLUMN_COUNT*MUL]='\n'; buffer[COLUMN_COUNT*MUL+1]=0; g_io_channel_write_chars(channel, (const gchar *)&buffer, -1, &written, &error); } g_io_channel_shutdown (channel, TRUE, &error); g_io_channel_unref (channel); }
And function prototype to src/monkey/board.h
:
void board_save_to_file (Board * board, const char *filename);
Provide a call to this function in src/monkey/playground.c
:
void playground_save(Playground * self, const gchar * level_filename) { board_save_to_file(PRIVATE(self)->board, level_filename); }
And function prototype to src/monkey/playground.h
:
void playground_save(Playground * self, const gchar * level_filename);
Finally, a call to the save feature in src/monkey/monkey.c
:
void monkey_save(Monkey *monkey, const gchar * filename) { playground_save(PRIVATE(monkey)->playground, filename); }
And function prototype to src/monkey/monkey.h
:
void monkey_save(Monkey *monkey, const gchar * filename);
Now the game should be saving its state, and be background killable. It can be tested by setting Monkey Bubble to background (for example by starting another application) and issuing following commands (in scratchbox):
dbus-send --system /com/nokia/ke_recv/bgkill_on com.nokia.ke_recv.bgkill_on.bgkill_on dbus-send --system /com/nokia/ke_recv/bgkill_off com.nokia.ke_recv.bgkill_off.bgkill_off
After changing back to Monkey Bubble, it should show banner "Monkey Bubble - resuming".
Network Changes
For the networking code we do not need to do any specific changes to the existing code, but in order for the application to provide a network connection selection dialog or to automatically select a proper connection, the LibConIC library must be used.
The best place for network connection changes is
before opening the join network dialog. So, let's make
modifications to src/ui/ui-main.c
file.
First add a proper header:
#include <conic.h>
After that, we'll modify the new_network_game
function which is called when a new network game is launched.
Remove the old code and replace it with this:
ConIcConnection *ic; ic = con_ic_connection_new(); g_signal_connect(ic, "connection-event", (GCallback)network_connected, NULL); con_ic_connection_connect(ic, CON_IC_CONNECT_FLAG_NONE);
The code creates a new ConIcConnection and connects the
connection-event signal. This signal is called when
a connection event happens.
After that, it calls connect signal in order to request
a new connection. We have to do one more thing, specify
what happens when a connection event comes.
That is handled in new network_connected
function,
which is implemented as follows:
static void network_connected(ConIcConnection *cnx, ConIcConnectionEvent *event, gpointer user_data) { UiNetworkClient * ngl; switch (con_ic_connection_event_get_status(event)) { case CON_IC_STATUS_CONNECTED: ngl = ui_network_client_new(); break; case CON_IC_STATUS_DISCONNECTED: case CON_IC_STATUS_DISCONNECTING: default: break; } }
This function simply checks which status the event gives
us and if it is CON_IC_STATUS_CONNECTED
,
it creates a new client window, where the user is able to
connect to a server.
There is still one more thing to do. We must add
conic
to
configure.in
into the list following
PKG_CHECK_MODULES for UI.
After these changes, starting a new network game will ensure that there is a network connection available.
Integration to Menu
Application Packaging
This section describes how Monkey Bubble sources were modified to make .deb package building possible. Actual packaging operation after that is specified in another document.
1) Rename Monkey Bubble source directory to maemo-monkey-bubble-0.0.1:
mv monkey-bubble-0.4.0 maemo-monkey-bubble-0.0.1
2) Package source dir maemo-monkey-bubble-0.0.1/ in maemo-monkey-bubble-0.0.1.tar.gz
tar czvf maemo-monkey-bubble-0.0.1.tar.gz maemo-monkey-bubble-0.0.1
3) Go to the source directory
cd maemo-monkey-bubble-0.0.1
4) Set full name environment variable:
export DEBFULLNAME="Mr Maemo"
Now the actual work can be started. Debian New Maintainers' Guide [6] might be useful in this phase.
5) Make initial debianization:
dh_make -e xxxxxxx.xxxxxx@maemo.org -f ../maemo-monkey-bubble-0.0.1.tar.gz
6) Next dh_make will ask a question, and print a summary of the package:
Type of package: single binary, multiple binary, library, or kernel module? [s/m/l/k] s Maintainer name : Mr Maemo Email-Address : xxxxxxx.xxxxxx@maemo.org Date : Thu, 14 Dec 2006 10:42:18 +0200 Package Name : maemo-monkey-bubble Version : 0.0.1 Type of Package : Single Hit <enter> to confirm:
7) Modify debian dir. Only files changelog, compat,
control, copyright, docs and rules are needed. In the control file,
packages hildon-1 (>= 0.14.8)
, librsvg2-2
and libglade2
must be added to Depends. You should also set the Section field into user/games
to make the package compatible with Application Manager. After that, the
package structure is ok. Then
the configuration files need to be changed to be able to build the package.
N.B. libglade2 must be installed from Maemo repositories [10]. ARMEL Debian packages of librsvg2-2 and librsvg2-common is available at garage.maemo.org [11].
8) Because the key definition dialog was disabled, definitions need to be set in debian/postinst
:
#!/bin/sh set -e case "$1" in configure) gconftool-2 -s /apps/monkey-bubble/player_1_shoot --type=string Up gconftool-2 -s /apps/monkey-bubble/player_1_left --type=string Left gconftool-2 -s /apps/monkey-bubble/player_1_right --type=string Right ;; abort-upgrade|abort-remove|abort-deconfigure) ;; *) echo "postinst called with unknown argument \`$1'" >&2 exit 1 ;; esac exit 0
It should be set executable with chmod a+x debian/postinst
.
9) A link to the desktop file must be added to /etc/others-menu/extra_applications
to show it in menu. Link is created by making a debian/maemo-monkey-bubble.links
file with following contents:
usr/share/applications/hildon/monkey-bubble.desktop etc/others-menu/extra_applications/monkey-bubble.desktop
10) Add the file maemo-monkey-bubble.files to list all the files that will be installed by the package.
11) Add following lines in configure.in:
PKG_CHECK_MODULES(HILDON, hildon-1 >= 0.14.8) AC_SUBST(HILDON_LIBS) AC_SUBST(HILDON_CFLAGS)
12) Make following two changes in Makefile.am (remember to use tab to indent):
Add items in EXTRA_DIST before $(NULL):
autogen.sh \ debian/changelog \ debian/compat \ debian/copyright \ debian/control \ debian/rules \ debian/docs \
Add deb rule:
deb: dist -mkdir $(top_builddir)/debian-build cd $(top_builddir)/debian-build && tar zxf ../$(top_builddir)/$(PACKAGE)-$(VERSION).tar.gz cd $(top_builddir)/debian-build/$(PACKAGE)-$(VERSION) && dpkg-buildpackage -rfakeroot -rm -rf $(top_builddir)/debian-build/$(PACKAGE)-$(VERSION)
Now the source dir should be ready for packaging, described in Maemo SDK Tutorial [7].
If you want to create a package that is usable with the Application Manager, see document Making a package for the Application Manager.
Modified Monkey Bubble sources and binaries can be found from garage.maemo.org [11].
References
[1] Maemo SDK Tutorial 2nd chapter
[2] Maemo SDK Tutorial 3rd chapter
[3] http://home.gna.org/monkeybubble/
[5] http://autotoolset.sourceforge.net/tutorial.html
[6] http://www.debian.org/doc/manuals/maint-guide/
[7] Maemo SDK Tutorial chapter 4 #BuildingApps
[8] Debian packages
[10] Maemo repository for libglade2
[11] garage.maemo.org
[12] Maemo desktop plug-ins tutorial
[13] Maemo Connectivity Architecture
Improve this page