How to write maemo desktop plugins for maemo
This document has been reviewed for maemo 3.x.
This document is released under the GPL license.
Author:Karoliina Salminen karoliina.t.salminen (at) nokia.com>
Introduction to maemo desktop architecture
This tutorial shows how to write maemo desktop's Status Bar, Task Navigator, Control Panel and Home plugins.
Maemo desktop consists of three subcomponents: task navigator, Home and status bar. They support additional plugins that are displayed on each these components and which extend the functionality of the host application. The plugins are opened by the host application with dlopen and the plugin has to implement an API, which the host application (TN, Home or SB) then calls. This document is a tutorial, it explains how to use the plugin API and how to write plugins that work well with the maemo desktop.
Home plugins
As a new feature for IT2007, home plugins can be now resized if the resizability flag is mentioned on the plugin's .desktop-file.
Each home applet needs to provide a .desktop file. The .desktop files must be placed in the /usr/share/applications/hildon-home directory.
You need to provide a .desktop file for each plugin. The applets must not implement hildon_home_applet_lib_properties, but implement instead hildon_home_applet_lib_settings (described later in this tutorial).
The Home applet .desktop file is named as home<yourappletsname>.desktop
and resides under /usr/share/applications/hildon-home
.
The contents of the .desktop file are:
[Desktop Entry] Name=your_logical_name_here Comment=engineering english name of applet Type=HildonHomeApplet X-home-applet=lib_some_applet_name_.so X-home-applet-resizable=YES X-home-applet-minwidth=400 X-home-applet-maxheight=200
The following is an example metar-applet.desktop
[Desktop Entry] Name=metar-applet Comment=Aviation Weather Home Applet Type=HildonHomeApplet X-home-applet=libmetar_applet.so
API required to implement for a simple applet with no information to state save A simple applet must implement the following functions:
hildon_home_applet_lib_initialize void hildon_home_applet_lib_deinitialize
Other API functions can remain empty and return NULL when a pointer return value is required. The required #include statement is:
#include <hildon-home-plugin/hildon-home-plugin-interface.h>
hildon_home_applet_lib_initialize:
/** * @hildon_home_applet_lib_initialize * * @param state_data Not in use * * @param state_size Not in use * @param widget Return parameter the Applet should fill in with * it's main widget. * @returns A pointer to applet specific data * * Applet initialization. * This is called when Home loads the applet. It may load it self * in initial state or in state given. It creates a GtkWidget that * Home will use to display the applet. */ void *hildon_home_applet_lib_initialize(void *state_data, int *state_size, GtkWidget **widget);
The following is an example implementation:
void* hildon_home_applet_lib_initialize (void *state_data, int *state_size, GtkWidget **widget) { osso_context_t *osso; /* Initialize libosso */ osso = osso_initialize ("METAR_APP", "0.1", FALSE, NULL); if (!osso) { g_debug ("Error initializing the osso" "maemo metar applet"); return NULL; } /* * Call private function metar_ui_init which does the initialization * for this applet. It returns the GtkWidget which is then returned * to Home. The function content could be implemented here too, but for * maintainability reasons it has been moved to different function in different * source file. */ (*widget) = metar_ui_init (osso); g_debug ("Initialized maemo metar applet"); /* Libosso context is returned to Home */ return (void*)osso; }
Related functions in the accompanying metar-ui.c in this example applet are as follows:
/* Test button */ static void test_button_clicked (GtkButton* button, gpointer data) { printf("Hello world. You clicked the test button!\n"); } /* Create the widget for the applet that is returned to the caller (maemo desktop) */ static void metar_ui_create_home_applet (void) { /* Create the main widget of the applet */ app->frame1 = gtk_frame_new(NULL); gtk_widget_set_size_request ( GTK_WIDGET (app->frame1), APPLET_X_SIZE, APPLET_Y_SIZE ); /* Create one vbox */ app->vbox0 = gtk_vbox_new (TRUE, 2); /* Hello world label */ app->label0 = gtk_label_new ("Hello world"); /* Test button */ app->button0 = gtk_button_new_with_label (("Test button")); gtk_signal_connect (GTK_OBJECT (app->button0), "clicked", GTK_SIGNAL_FUNC (test_button_clicked), (gpointer) 1); /* Set the main widget frame1 to contain vbox0 */ gtk_container_add (GTK_CONTAINER (app->frame1), app->vbox0); /* Add first the label */ gtk_box_pack_start(GTK_BOX(app->vbox0), app->label0, FALSE, FALSE, 0); /* The button comes below the label */ gtk_box_pack_start(GTK_BOX(app->vbox0), app->button0, FALSE, FALSE, 0); /* Hack needed to get the applet themed correctly. This string can be found from gtkrc.Hildon Desktop -file. Please look at it for more information. With string osso-rss-feed-reader it is possible to achieve propably best results for a simple applet */ /* NOTE: FIXME: The skin is drawn inside the applet area so you can't use the border area to draw widgets on it, otherwise your widgets will appear on top of the skin graphics like in this quick'n'dirty example */ gtk_widget_set_name (GTK_WIDGET (app->frame1), "osso-rss-feed-reader"); /* Finally show the thing */ gtk_widget_show_all (GTK_WIDGET (app->frame1)); } /* Init UI */ GtkWidget* metar_ui_init (osso_context_t* osso) { if (!app) { /* Create the struct for storing the globals nicely inside a namespace */ app = g_new0 (MetarApp, 1); app->osso = osso; /* The UI initialization could be inside this function, but I did choose to put it to another function */ metar_ui_create_home_applet (); } /* IMPORTANT! This returns the main widget of the applet (frame1) to maemo desktop */ return app->frame1; }
hildon_home_applet_lib_deinitialize:
/** * @hildon_home_applet_lib_deinitialize * * @param applet_data Applet data as returned by applet_initialize. * * Called when Home unloads the applet from memory. * Applet should deallocate all the resources needed. * */ void hildon_home_applet_lib_deinitialize(void *applet_data);
The following is an example implementation:
void hildon_home_applet_lib_deinitialize (void *applet_data) { osso_context_t *osso = (osso_context_t*)applet_data; /* Call private function which deinitializes your UI. Not necessary required to be separate, but for maintainability reasons it may be cleaner to place it to different file than this API implementation */ metar_ui_quit (); /* Deinitialize libosso */ osso_deinitialize (osso); }
Accompanying functions in this example in metar-ui.c are:
void metar_ui_quit (void) { /* This is for freeing the stuff allocated earlier */ if (app) { g_free (app); app = NULL; } }
hildon_home_applet_lib_background:
This function is called when your applet is backgrounded. In other words, the clock applet, for example, does not need to update its display when it is not shown. Home calls hildon_home_applet_lib_foreground again when it is necessary to continue updating the display of the applet again periodically.
/** * @hildon_home_applet_lib_background * * @param applet_data Applet data as returned by applet_initialize. * * Called when Home goes to background. * Applet should stop all timers when this is called. */ void hildon_home_applet_lib_background(void *applet_data);
You do not need to implement this for a simple applet, so it can be left empty as follows:
void hildon_home_applet_lib_background (void *applet_data) { return; }
hildon_home_applet_lib_foreground:
This function can be used to start, for example, timers in the applet if it has been backgrounded and is then brought up. For example, a clock applet that updates itself periodically does not need updates when it is on background - to do so in an embedded system wastes resources and the battery. Restart your periodic updates when Home calls this function.
The prototype of hildon_home_applet_lib_foreground is:
/** * @hildon_home_applet_lib_foreground * * @param applet_data Applet data as returned by applet_initialize. * * Called when Home goes to foreground. * Applet should start periodic UI updates again if needed. */ void hildon_home_applet_lib_foreground(void *applet_data);
For a simple applet this can be also left empty:
void hildon_home_applet_lib_foreground (void *applet_data) { return; }
hildon_home_applet_lib_save_state
Prototype of hildon_home_applet_lib_save_state
/** * @hildon_home_applet_lib_save_state * * @param applet_data Applet data as returned by applet_initialize. * * @param state_data Applet allocates memory for state data and * stores pointer here. * Must be freed by the calling application * * @param state_size Applet stores the size of the state data * allocated here. The size is measured in * sizeof(void) units. * * @returns 0 if successful. * * Method called to save the UI state of the applet */ int hildon_home_applet_lib_save_state (void *applet_data, void **state_data, int *state_size);
If you do not need the saving state, leave it empty with the following implementation (just set the state data to NULL and state size 0).
int hildon_home_applet_lib_save_state (void *applet_data, void **state_data, int *state_size) { /* we don't want to save state in a simple weather applet */ (*state_data) = NULL; if (state_size) { (*state_size) = 0; } else { g_debug ("State_size pointer was not pointing to right place"); } return 1; }
If your applet needs the saving state, just fill up the **state_data with your data. Home stores the data and initialises the applet next time with the saved data in hildon_home_applet_lib_initialize. Assign state data size in *state_size return value. The return value (int) is an error code. Return 0 if successful.
hildon_home_applet_lib_settings:
The following is the prototype of hildon_home_applet_lib_settings
/** * @hildon_home_applet_lib_settings * * @param applet_data Applet data as returned by applet_initialize. * @param parent The toplevel applet GTK window * * Called when the applet needs to open a settings dialog * This allows applet to provide Home e.g. a menu item widget * that is connected to an action specified by the applet */ GtkWidget *hildon_home_applet_lib_settings(void *applet_data, GtkWindow *parent);
An example implementation for a simple applet (can be left empty):
GtkWidget* hildon_home_applet_lib_settings (void *applet_data, GtkWindow *parent) { return NULL; }
Writing status bar plugins
The maemo status bar can contain user-defined items. Plugin places etc. properties can be set with the Task Navigator and Status bar configuration applet found from Control Panel ("Navigation applet").
To make your own status bar plugin, you need to make a shared object with certain functions in it.
NOTE: maemo desktop was changed to dynamically link to the libhildonstatusbar.so library as statically linking it made it impossible to use the statusbaritem API from the plugins (the type system was confused by having two instances of the get_type() function in memory).
Status Bar plugins are divided into three categories, namely: permanent, conditional and temporal. Permanent plugins are shown all the time. Conditional and temporal plugins are shown only when the condition is fullfilled.
Desktop file
Each plugin have to offer a desktop-file:
[Desktop Entry] Name=<logical name identifier> Icon=<logical icon identifier> Category=<permanent/conditional/temporal>, the default value is permanent if the key value read fails. X-status-bar-plugin=lib<plugin name>.so Mandatory=<true/false>, if not set, the default value is false
The .desktop file shall be placed in ${datadir}/applications/hildon-status-bar/
Status bar functions
The most important function is the entry function, which is called when the library is opened. This function defines the other functions needed for the plugin operation. The entry function's name depends on the name of your library. It is [your lib name]_entry, for example for a plugin called hello, the entry function is called hello_entry. The following example illustrates the entry function:
/* Definition of HildonStatusBarPluginFn_st */ #include <hildon-status-bar-lib/hildon-status-bar-item.h> #include <gtk/gtk.h> void *hello_initialize(HildonStatusBarItem *item, GtkWidget **button); void hello_destroy(void *data); void hello_update(void *data, gint value1, gint value2, const gchar *str); int hello_get_priority(void *data); /* You have to also include prototype of your entry function */ void hello_entry(HildonStatusBarPluginFn_st *fn); void hello_entry(HildonStatusBarPluginFn_st *fn) { /* Sanity check */ if (fn == NULL) { return; } fn->initialize = hello_initialize; fn->destroy = hello_destroy; fn->update = hello_update; fn->get_priority = hello_get_priority; }
The entry tells the status bar which functions are called at certain events. On the first event, the initialize function is called. The return value of initialize is passed to destroy, update and get_priority functions.
To make it possible to destroy an item, the first parameter of initialize must be stored for later use. The second parameter must be initialised to a new button that is the graphical representation of the plugin. The size of the plugin button should be 40x40 pixels. If any g_timeouts or such are used, the IDs of these must be stored for removal (if not removed, the entire status bar probably crashes). The following example illustrates the initialize function:
struct HelloPlugin { HildonStatusBarItem *item; GtkWidget *button; /* Add here any data for your plugin. */ }; void *hello_initialize(HildonStatusBarItem *item, GtkWidget **button) { GtkWidget *image = NULL; struct HelloPlugin *hello = g_new0(struct HelloPlugin, 1); hello->item = item; *button = hello->button = gtk_button_new(); image = gtk_image_new_from_file("hello.png"); /* Should be 40x40 */ gtk_container_add( GTK_CONTAINER(*button), GTK_WIDGET(image)); /* Here could add some gconf_notify's, g_timeouts or such. */ gtk_widget_show_all(*button); return (void *)hello; }
The plugin is now initialized. The following example illustrates the update function, which is called whenever the plugin receives events. The plugin interface allows three parameters to be given to the plugin: two integers and one string. The plugin can use the parameters as it wants. In the example, the first integer value is used to define whether to show the plugin.
When the item is destroyed, the destroy function is called. It should free all the memory and release all the notifys that can lead to the plugin code. The widget must not be destroyed here, the status bar takes care of that. The following example illustrates the destroy function:
void hello_destroy(void *data) { if (!data) { return; } /* You should do g_source_removes and gconf_client_notify_removes here. */ g_free(data); }
void [plugin_name]_set_conditional( void *data, gboolean conditional_status);
this function purposes is to provide an interface to conditional and temporal plugins for setting a plugin. Boolean value describes if a plugin is shown(TRUE) and respectively, is not shown(FALSE). Function is an optional e.g. permanent plugins do not need to implement this.
Example:
/* Called by the desktop process whenever the * hildon_status_bar_update_conditional is emitted on the * SB item */ static void hello_set_conditional (HelloSb *data, gboolean visible) { if (!data) return; if (visible) { if (!data->button) { data->button = gtk_button_new_with_label ("H"); g_signal_connect_swapped (data->button, "clicked", G_CALLBACK (hello_clicked), data); gtk_widget_show_all (data->button); } } else { gtk_widget_destroy (data->button); data->button = NULL; } hildon_status_bar_item_set_button (data->item, data->button); }
The API provides now, also a new signal for notifying StatusBar? a conditional plugin status changes:
void (*hildon_status_bar_update_conditional) (HildonStatusBarItem * self, gboolean conditional_status);
in which, the boolean parameter's purposes is to notify Status Bar whether a plugin need to be shown or then need to be hide.
Conditional plugins do not need to create the button in the initialize API call, but can leave the button parameter as NULL. To specify the button that will be inserted in the Status Bar, the plugin will need to call
void hildon_status_bar_item_set_button (HildonStatusBarItem *item, GtkWidget *button);
in the set_conditional() implementation of the plugin.
Changing the conditional status
If a plugin is permanent e.g is shown all the time, it doesn't need to implement set_conditional function. But, otherwise if it is a conditional or a temporal one, it implements set_conditional function. At StatusBar? initialization the default is that those plugins are not shown.
When a plugin needs to change its status it emits "hildon_status_bar_update_conditional" signal:
gboolean is_shown = FALSE; g_signal_emit_by_name(item, "hildon_status_bar_update_conditional", !is_shown);
After emitting the signal, StatusBarItem itself sets conditional function and StatusBar shows plugin at the position where a user has configured it.
Destroying the plugin
There is now need for more frequent reloading and as well removing of plugins. Hence, because at least some existing permanent plugins haven't included yet in their _destroy function dbus deinitialization (osso_deinitialize), not later than now all plugins should include it.
There exists the possibility of avoiding reloading of plugins by setting the plugin as mandatory in the .desktop file, so that it is never unloaded under any circumstances. If so, the plugin can not be unselected in control panel navigator applet.
Statusbar plugins .desktop files
Building the shared object
The shared object can be built like any normal binary, by only giving the "-shared" flag to gcc:
[sbox-SDK_PC: ~] > gcc -shared `pkg-config gtk+-2.0 libosso --libs --cflags` hello.c -o libhello.so
The binary produced by gcc must be installed to the path specified in the "hildon-status-bar-lib pkg-config" entry. This path can be obtained with pkg-config hildon-status-bar-lib --variable=pluginlibdir. By default, it is /usr/lib/hildon-status-bar.
Writing Hildon Control Panel plugins
Hildon Control Panel follows the same approach with its plugins than the other components in the maemo desktop environment. Control panel is a standardized place for put settings changeable by the end users for applications, servers etc. in the system.
The Control Panel is divided to categories: General, Connectivity, Personalisation, Extras.
.desktop file for Control Panel plugins
Each Control Panel applet has to provide a .desktop file of the following format:
[Desktop Entry] Name=<logical applet name identifier> Comment=Task Navigator Control Panel Applet Type=HildonControlPanelPlugin Icon=<logical icon name identifier> Categories=<general/connectivity/personalisation/extras>, from which the extras is the default value, in case the key value read fails. X-control-panel-plugin=lib<applet name>.so
Execute Hildon Control Panel calls this function to run the plugin.
Prototype
osso_return_t execute(osso_context_t * osso, gpointer data);
Parameter explanations
*osso - The osso context of the application that executes the plugin.
data - The GTK toplevel widget. It is needed so that the widgets created by the plugin can be made a child of the main application that utilizes the plugin. Type is gpointer so that the plugin does not need to depend on GTK (in which case it should ignore the parameter).
Save_state - This method is called to tell the plugin to do state saving. Called by the host application, e.g. Hildon Control Panel.
Prototype:
osso_return_t save_state(osso_context_t *osso, osso_state_t *state);
Parameters:
osso Osso context of the application running the plugin.
state_data The save_state should allocate memory for state save data here. This must be freed by the calling function.
How to create a makefiles and package for your applet
You now have enough information to create a simple Home applet. It contains just an eventbox with savable state. In the build process of applets, autotools are used. autogen.sh
, configure.ac
and Makefile.am
are created in
addition to the actual applet source code.
The directory structure of the package is:
/metar_applet /metar_applet/debian /metar_applet/data /metar_applet/src
Firstly, the autogen.sh script (this script does not contain anything applet-specific details.):
#!/bin/sh set -x libtoolize --automake aclocal-1.7 || aclocal autoconf autoheader automake-1.7 --add-missing --foreign || automake --add-missing --foreign
The configure.ac
file is as follows:
AC_PREREQ(2.59) AC_INIT(maemo-metar-applet, 0.1, karoliina.t.salminen@nokia.com) AM_INIT_AUTOMAKE AM_CONFIG_HEADER(config.h) dnl ################## dnl This script generates host names dnl ################## AC_CANONICAL_HOST dnl ################## dnl Check for installed programs that is needed dnl ################## AC_PROG_CC AM_PROG_CC_STDC AC_PROG_INSTALL AC_PROG_RANLIB AC_PROG_INTLTOOL([0.21]) AC_PROG_LIBTOOL AM_PATH_GLIB_2_0 AC_CHECK_PROG(HAVE_PKG_CONFIG, pkg-config, yes, no) if test "x$HAVE_PKG_CONFIG" = "xno"; then AC_MSG_ERROR([You need to install pkg-config tool]) fi dnl ################## dnl Compiler flags, note that the -ansi flag is not used because dnl in that case the rint fuction is not awailable in math.h dnl ################## CFLAGS="$CFLAGS -g -Wall -Werror -ansi -Wmissing-prototypes -Wmissing-declarations" dnl ################## dnl Check needed headers, like C standard headers, GLib, GStreamer etc. dnl ################## AC_HEADER_STDC GLIB_REQUIRED=2.6.0 GTK_REQUIRED=2.4.0 LIBOSSO_REQUIRED=0.8.3 HILDON_LGPL_REQUIRED=0.9.14 HILDON_LIBS_REQUIRED=0.9.15 HILDON_HOME=2.2 GMODULE=2.6 LIBXML=2.6 GNOMEVFS_REQUIRED=2.8.3 PKG_CHECK_MODULES(METAR, [ glib-2.0 >= $GLIB_REQUIRED, gtk+-2.0 >= $GTK_REQUIRED, libosso >= $LIBOSSO_REQUIRED, hildon-lgpl >= $HILDON_LGPL_REQUIRED, hildon-libs >= $HILDON_LIBS_REQUIRED, hildon-home >= $HILDON_HOME, gmodule-2.0 >= $GMODULE, libxml-2.0 >= $LIBXML, gnome-vfs-2.0 >= $GNOMEVFS_REQUIRED ]) PKG_CHECK_MODULES(GNOME_VFS, gnome-vfs-2.0 >= 2.8.3) AC_SUBST(GNOME_VFS_CFLAGS) AC_SUBST(GNOME_VFS_LIBS) dnl ################## dnl directories dnl ################## localedir=`pkg-config osso-af-settings --variable=localedir` AC_SUBST(localedir) metarpluginlibdir="/usr/lib/metar-applet-home" AC_SUBST(metarpluginlibdir) AC_DEFINE_UNQUOTED(METAR_PLUGIN_DIR, "${metarpluginlibdir}",[Dir where plugins are stored]) pluginlibdir="/usr/lib/hildon-home" AC_SUBST(pluginlibdir) AC_CONFIG_FILES([Makefile src/Makefile data/Makefile ]) AC_OUTPUT
The package config file is used to provide information about the installation directory of the compiled plugin by querying the value of pluginlibdir variable. All version numbers for various components above should be interpreted as illustrative only.
The master Makefile.am
is:
SUBDIRS = src data EXTRA_DIST= \ autogen.sh \ intltool-extract.in \ intltool-merge.in \ intltool-update.in \ debian/rules \ debian/control \ debian/copyright \ debian/changelog \ debian/maemo-metar-applet.install deb_dir = $(top_builddir)/debian-build INCLUDES = $(DEPS_CFLAGS) deb: dist -mkdir $(deb_dir) cd $(deb_dir) && tar xzf ../$(top_builddir)/$(PACKAGE)-$(VERSION).tar.gz cd $(deb_dir)/$(PACKAGE)-$(VERSION) && dpkg-buildpackage -rfakeroot -rm -rf $(deb_dir)/$(PACKAGE)-$(VERSION)
Makefile.am
of the src
subdirectory:
pluginlib_LTLIBRARIES = libmetar_applet.la common_CFLAGS = \ $(METAR_CFLAGS) \ -DPREFIX=\"$(prefix)\" \ -DLOCALEDIR=\"$(localedir)\" common_LDADD = \ $(METAR_LIBS) libmetar_applet_la_LDFLAGS= -module -avoid-version libmetar_applet_la_CFLAGS = $(common_CFLAGS) libmetar_applet_la_LIBADD = $(common_LDADD) libmetar_applet_la_SOURCES = \ metar-ui.h \ metar-ui.c \ metar-loader.h \ metar-loader.c \ metar-applet.c
Makefile.am of data directory:
homeapplet_desktopdir=/usr/share/applications/hildon-home homeapplet_desktop_DATA=metar-applet.desktop EXTRA_DIST=$(homeapplet_desktop_DATA)
The debian/control is as follows:
Source: maemo-metar-applet Section: misc Priority: optional Maintainer: Karoliina Salminen <karoliina.t.salminen@nokia.com> Build-Depends: libgtk2.0-dev (>=2.4.0-1), pkg-config, libosso-dev, hildon-lgpl-dev, hildon-libs-dev, intltool (>= 0.21), hildon-home-dev (>=2.2.1), libxml2-dev (>=2.6), libosso-gnomevfs2-dev Standards-Version: 3.6.1 Package: maemo-metar-applet S ection: user/internet Architecture: any Depends: ${shlibs:Depends},${launcher:Depends} Description: Maemo Metar home panel applet Home panel applet for showing aviation weather.
The debian/changelog is:
maemo-metar-applet (0.1) experimental; urgency=low * Created package -- Karoliina Salminen <karoliina.t.salminen@nokia.com> Tue, 30 May 2006 10:04:45 +0200
The debian/rules are:
#!/usr/bin/make -f # export DH_VERBOSE=1 # These are used for cross-compiling and for saving the configure script # from having to guess our platform (since we know it already) DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) CFLAGS = -Wall -g PACKAGENAME = maemo-isearch-applet ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS))) CFLAGS += -O0 else CFLAGS += -O2 endif ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS))) INSTALL_PROGRAM += -s endif config.status: dh_testdir # Add here commands to configure the package. CFLAGS="$(CFLAGS)" ./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info build: build-stamp build-stamp: config.status dh_testdir # Add here commands to compile the package. $(MAKE) touch build-stamp clean: dh_testdir dh_testroot rm -f build-stamp configure-stamp # Add here commands to clean up after the build process. -$(MAKE) clean dh_clean install: build dh_testdir dh_testroot dh_clean -k dh_installdirs # Add here commands to install the package $(MAKE) install DESTDIR=$(CURDIR)/debian/tmp # Build architecture-independent files here. binary-indep: build install # We have nothing to do by default. # Build architecture-dependent files here. binary-arch: build install dh_testdir dh_testroot # dh_installchangelogs dh_installdocs # dh_installexamples dh_install -v --sourcedir=debian/build # dh_installmenu # dh_installdebconf # dh_installlogrotate # dh_installemacsen # dh_installpam # dh_installmime # dh_installinit # dh_installcron # dh_installinfo # dh_installman dh_link dh_strip dh_compress dh_fixperms # dh_perl # dh_python dh_makeshlibs dh_installdeb dh_shlibdeps -V dh_gencontrol dh_md5sums dh_builddeb binary: binary-indep binary-arch .PHONY: build clean binary-indep binary-arch binary install configure
The debian/maemo-metar-applet.install is:
usr/lib/metar-applet-home/*.so usr/lib/hildon-home/*.so
data/metar-applet.desktop:
[Desktop Entry] Name=metar-applet Comment=Aviation Weather Home Applet Type=HildonHomeApplet X-home-applet=libmetar_applet.so
Code examples
The following tar.gz packages contain C source code examples that demonstrate how to use the maemo desktop Plugins. Enjoy.
NOTE: If you have problems running the ./configure-script, try running ./autogen.sh first
Improve this page