Chapter 4. Writing Applications

In this chapter we show how GPE applications are implemented and what is different in comparison with Gnome and plain GTK applications. The major part of information about application development in this chapter is very generic and not directly limited to GPE applications, so it might be useful even if you do not intend to write a GPE application.

4.1. A GPE Application Step by Step

4.1.1. Overview

To get an idea about how GPE applications look like and how they use the GTK toolkit we look at a simple GPE application first. We will use an example application for this called gpe-hello. You can get the source for this either from the GPE CVS or as a tarball from http://www.handhelds.org/~philippe. You will also need to install libgpewidget-dev on your development system to be able to compile and run it.

4.1.2. Good Practices

We try to encourage good coding styles and prefer to have GPE applications that use the autotools for configuration. Please comment your code as much as possible. Also compile your programs with -Wall to catch as much as possible potential errors. This makes it easier for you and anybody else that will try to fix the inevitable bugs, and help you write good programs.

Also you need to pay much attention to memory usage. So make sure you do not introduce memory leaks. As most systems where GPE (will) run(s) on are limited in memory and cannot afford memory leaks. Lots of tools like valgrind and memprof are available to check for this kind of errors.

Last but not least, for your program to become an official GPE application it needs to be released under a free license like the GNU GPL/LGPL or the BSD license.

4.1.3. Introducing the GPE Application Skeleton

If you unpack the tarball you will see that it already contains quite a lot of files. They all have a specific function but are not always needed as some of them are auto-generated (these auto-generated files should not be placed in CVS. However try to use as much as possible of those.

Table 4-1. Example Project Files

FilenameDescription
gpe-hello.cApplication implementation.
gpe-hello.pngApplication icon.
gpe-hello.dektop.inDesktop entry file base.
configure.acAutotools support file (autoconf).
Makefile.amAutotools support file (automake).
gpe-dist.amSome generic GPE make targets.
autogen.shShellscript to generate initial autoconf and automake files.
ChangeLogContains a short description of changes and versioning.
AUTHORSLists all the contributors to the program.
INSTALLInstructions on how to build and install your program.
READMEShort description of your program and miscellaneous information.
LICENSEContains a copy of the license under which you distribute your program.
TODOA list of items/features you plan to implement in upcoming versions.

For a detailed secription of the autotools setup for GPE applications see the "Building and Testing" section below. For more generic information check out the GNU autoconf, automake and intltool manuals.

4.1.4. Walking through the Code

Currently this example only contains one file of C sourcecode containing the most important basic concepts of a GPE application. The file gpe-hello.c looks like this:

Each file should start with a header identifying its author, license and purpose. In order to make code easy to maintain and reusable in other open source applications this is very important. For important code which likely to have many contributors and/or changes it might be useful to keep a simple changelog at the end of the file header. Some contact information or a short description of the programs purpose are always useful too.


        
        /*
	 * gpe-hello v0.1
	 *
	 * Tutorial program to learn programming for GPE 
	 *
	 * Copyright (c) 2005 Philippe De Swert, Florian Boor
	 *
	 * Contact : philippedeswert@scarlet.be
	 * 	
	 * This program is free software; you can redistribute it and/or modify
	 * it under the terms of the GNU General Public License as published by
	 * the Free Software Foundation; either version 2, or (at your option)
	 * any later version.
	 *
	 * This program is distributed in the hope that it will be useful,
	 * but WITHOUT ANY WARRANTY; without even the implied warranty of
	 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	 * GNU General Public License for more details.
	 */

	/* the usual suspects */
	#include <string.h>
	#include <unistd.h>
	#include <stdio.h>
	#include <stddef.h>
	#include <stdlib.h>

	/* gtk includes */
	#include <gtk/gtk.h>
	#include <glib.h>

	/* internationalisation aka i8n */
	#include <libintl.h>
	#include <locale.h> 

	/* gpe includes */
	#include <gpe/init.h>           /* gpe_application_init */
	#include <gpe/errorbox.h>       /* gpe_error_box */
	#include <gpe/pixmaps.h>        /* gpe_load_icons */
	#include <gpe/picturebutton.h>  /* gpe_button_new_from_stock */
	#include <gpe/spacing.h>        /* gpe_get_border, gpe_get_boxspacing */

	#define _(x) gettext(x)
	//#define DEBUG /* uncomment this if you want debug output*/

	/*
	 * This struct holds all pixmaps handled by libgpewidget functions.
	 * It consists of a set of identifiers and icon files. For files in the
	 * default GPE icon location you can omit the path and the extension.
	 */
	struct gpe_icon my_icons[] = 
	{
	  { "hello", PREFIX "/share/pixmaps/gpe-hello.png" },
	  {NULL, NULL}
	};

	/* Just do someting... this displays a nasty error box */
	static void 
	hello_box (void)
	{
	 gpe_error_box(_("Welcome to GPE!"));
	}


	/* 
	 * This creates the toolbar, it is not essential to have this code in a 
	 * separate function, but it makes the code easier to read.
	 */
	static GtkWidget*
	toolbar_create(void)
	{
	  GtkWidget *toolbar;
	  GtkToolItem *item;
  
  	  /* Create a toolbar widget and define its orientation. The size and layout
	   * is defined externally via xsettings. */
	  toolbar = gtk_toolbar_new();
	  gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);

	  /* Create a tool button and add it to the leftmost free position.*/
	  item = gtk_tool_button_new_from_stock(GTK_STOCK_ABOUT);
	  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
	
	  /* Connect "clicked" signal of the toolbutton. */
  	  g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(hello_box), NULL);

  	  /* Create a separator taking up the free space to the end of the toolbar. */
	  item = gtk_separator_tool_item_new();
	  gtk_separator_tool_item_set_draw(GTK_SEPARATOR_TOOL_ITEM(item), FALSE);
	  gtk_tool_item_set_expand(item, TRUE);
	  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
    
	  /* Create the close button and add it to the leftmost free position.*/
	  item = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
	  gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);

	  /* Connect "clicked" signal of the toolbutton to close the application. */
	  g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(gtk_main_quit), NULL);
	  return toolbar;
	}

	int
	main (int argc, char *argv[])
	{
	  GtkWidget *app;
	  GtkWidget *contentbox, *quit_button, *hello_button;
	  GtkWidget *mainbox, *toolbar, *textarea;
	
	  if (gpe_application_init (&argc, &argv) == FALSE)
	    exit (1);

	  if (gpe_load_icons (my_icons) == FALSE)
	    exit (1);
	
	  /* create application window */
	  app = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  
	  g_signal_connect (G_OBJECT (app), "delete-event", gtk_main_quit, NULL);
	  gtk_window_set_title (GTK_WINDOW (app), "GPE HELLO");
  
	  gtk_widget_realize (app);

	  /* show icon in window decoration */
	  gpe_set_window_icon (app, "hello");

	  /* call function creating main window toolbar, see above */
	  toolbar = toolbar_create();
  
	  /* the text area is an example widget taking up the major part of the window */
	  textarea = gtk_text_view_new();

	  /* create boxes */
	  contentbox = gtk_hbox_new (FALSE, gpe_get_boxspacing());
	  mainbox = gtk_vbox_new (FALSE, gpe_get_boxspacing());

	  /* set border with */
	  gtk_container_set_border_width(GTK_CONTAINER(contentbox), gpe_get_border());

	  /* add a hello & quit button with a gtk stock icon */
	  hello_button = gpe_button_new_from_stock(GTK_STOCK_ABOUT, GPE_BUTTON_TYPE_BOTH);
	  quit_button = gpe_button_new_from_stock(GTK_STOCK_QUIT, GPE_BUTTON_TYPE_BOTH);

	  /* attach signals to the buttons */
	  g_signal_connect(GTK_OBJECT(hello_button), "clicked",
	                   G_CALLBACK(hello_box), NULL);
	  g_signal_connect(GTK_OBJECT(quit_button), "clicked",
        	           G_CALLBACK(gtk_main_quit), NULL);

	  /* add buttons to the box */
	  gtk_box_pack_start(GTK_BOX(contentbox), hello_button, TRUE, TRUE, 0);
	  gtk_box_pack_start(GTK_BOX(contentbox), quit_button, TRUE, TRUE, 0);

	  /* pack the box with buttons and and the toolbar to the main box */
	  gtk_box_pack_start(GTK_BOX(mainbox), toolbar, FALSE, TRUE, 0);
	  gtk_box_pack_start(GTK_BOX(mainbox), textarea, TRUE, TRUE, 0);
	  gtk_box_pack_start(GTK_BOX(mainbox), contentbox, FALSE, TRUE, 0);

	  /* add the main box to the window */
	  gtk_container_add (GTK_CONTAINER (app), mainbox);

	  /* make everything visible and start the main loop */
	  gtk_widget_show_all (app);
	  gtk_main ();

	  exit (0);
	}
        
    

For people having done gtk development before this will definitely seem familiar. For people having no GTK+ experience at all don't worry, it is not that hard to understand.

The first thing that is essential for a (gpe) application, the correct includes. Make sure you at least include gpe/init.h! The comments in the code point out which functions are used (in this example) from the used GPE includes.

One of the first things you will notice is the gpe_icon struct. This contains the references to all the custom icons you need or want to use. In the example we only load one icon and the PREFIX will be filled in at compile time by a compiler flag (more about this later).

Every GPE program has a main() routine that will start with a gpe_application_init() function. This function is similar to gtk_application_init() but does some extra gpe initialisation to make sure all GPE applications will have a more or less consistent behaviour and looks.The gpe_load_icons() function will pre-load the icons you have defined in the gpe-icon struct and makes them available for use in your application.

The gpe-hello application is a very basic application (otherwise we would need to spend too much time explaining.=) It will pop up a window with two buttons, a hello one and a quit button. When pushing on the hello button a small box (actually an error box) will pop up saying hello to you, the quit button will of course make the application exit. Knowing this you can very well see what happens. The window is created, the title is set and we use a GPE specific function to set the icon (gpe_set_window_icon (app, "hello")) as you can see the hello string we pass to the function is the name of the icon we loaded previously.