USERNAME PASSWORD LOST PASSWORD? REGISTER
"A Complete Mobile Application Development Environment"
Advertisement

Downloads
Documentation
Forums
Blog
Press
Bug Tracking
Creator IDs
Contact Us




Anatomy of a Native ALP Application PDF Print E-mail

The following describes the construction of a simple native application. Each step builds on the prior one.

  1. A C App
  2. Add GTK+ Minimal Code
  3. Basic ALP App Elements
  4. Parse Launch Code Parameters
  5. Separate UI Creation
  6. Add Relaunch Handler
  7. Userdata “Anchor Block”
  8. (lib)Glade Integration
  9. Saving and Restoring Application State
    1. Saving State in a File

Step 1: A C App

A “Hello World” application is just a little too bloated… Let’s start with a an even more minimal C program:

int main(int argc, char *argv[])
{
   return 0;
} // main()

Step 2: Add GTK+ Minimal Code

See http://www.gtk.org/tutorial/ for a more exhaustive tutorial. As a generic GTK application, this example does not have any way of exiting, but it does not matter because within the context of ALP, an application does not need to exit itself. See the next section for a more appropriate ALP app.

Since we are using GLib/GDK/GTK, we should take advantage of its abstractions and use GLib types gint and gchar instead of int and char. For persistent data or wireline protocols, use types listed in types.h (e.g., !!!).

#include <gtk/gtk.h>         // Gtk* gtk*()

gint main(gint argc, gchar *argv[])
{
   GtkWidget *winmain;       // App's main window
   gtk_init(&argc, &argv);   // Activate GTK UI
                             // Create the App's main window
   winmain = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
   // TODO: Add additional UI setup code here
   gtk_widget_show(winmain); // Show App Window

   gtk_main();               // Run the UI; dispatch UI events

   return 0;
} // main()

Step 3: Basic ALP App Elements

And if we want to build this for ALP, we need to start with the basics.

  • Make directories called rsc and src
  • Create an Icon
  • Define the Manifest.xml
<manifest name="com.mydomain.apps.my_appl">
   <application>
      <name>My Appl</name>
      <icon>myicon.png</icon>
   </application>
</manifest>

Code changes include:

  1. Rename main() to alp_main()
  2. Add a handler for request to shutdown the application (OnAppExit()).
  3. Register the handler of the ALP request to exit the application via alp_app_add_exit_handler().
#include <alp/alp.h>         // Alp* alp*() ALP*

#include <gtk/gtk.h>         // Gtk* gtk*()

// Respond to ALP system request to shutdown the application, so save App UI
// state and shut down the UI.
void onAppExit()
{
   gtk_main_quit();          // Tell GTK to exit its event loop
} // onAppExit()

gint alp_main(gint argc, gchar *argv[])
{
   GtkWidget *winmain;       // App's main window

   alp_app_add_exit_handler(onAppExit, NULL); // Register app exit handler

   gtk_init(&argc, &argv);   // Activate GTK UI
                             // Create the App's main window
   winmain = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
   // TODO: Add additional UI setup code here
   gtk_widget_show(winmain); // Show App Window

   gtk_main();               // Run the UI; dispatch UI events

   // TODO: Save application state information to restore

   return 0;
} // alp_main()

Step 4: Parse Launch Code Parameters

Now let’s prepare for a non-trival case…

gint alp_main(gint argc, gchar *argv[]) 
{
   GtkWidget *winmain=null;     // App's main window

   alp_app_add_exit_handler(onAppExit, NULL); // Register app exit handler

   while (argc--)
   {
      argv++;                // Next parameter
      if ( !strcmp(*argv, ALP_APP_PRIMARY) )
      {
         gtk_init(&argc, &argv);   // Activate GTK UI
                             // Create the App's main window
         winmain = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
         // TODO: Add additional UI setup code here
         gtk_widget_show(winmain);  // Show App Window

      } // if ALP_APP_PRIMARY
   } // while ()

   if (winmain)
      gtk_main();            // Run the UI; dispatch UI events

   // TODO: Save application state information to restore
   return 0;
} // alp_main()

Step 5: Separate UI Creation

GtkWindow *initializeUI( gpointer userdata )
{
   GtkWidget *winmain;          // App's main window
                                // Create the App's main window
   winmain = gtk_window_new(GTK_WINDOW_TOPLEVEL); 
   // TODO: Add additional UI setup code here
   gtk_widget_show(winmain);    // Show App Window
   return winmain;
} // initUI()

gint alp_main(gint argc, gchar *argv[]) 
{
   GtkWindow *winmain=NULL;

   alp_app_add_exit_handler(onAppExit, NULL); // Register app exit handler

   while (argc--)
   {
      argv++;                   // Next parameter
      if ( !strcmp(argv, ALP_APP_PRIMARY) )
      {
         gtk_init(&argc, &argv);   // Activate GTK UI

         winmain = initializeUI( NULL );

      } // if ALP_APP_PRIMARY
   } // while ()

   if (winmain)
      gtk_main();            // Run the UI; dispatch UI events

   // TODO: Save application state information to restore
   return 0;
} // alp_main()

Step 6: Add Relaunch Handler

Notifications can be sent to an application whether it is running or not. If the program is running, it is shut down before the new launch codes are sent. To avoid disturbing the running application to handle the notification this inefficient way, we can register a relaunch handler callback function to handle such notifications while the program is running. (If the program is not running, then the notification launch code is passed to alp_main() in the fashion as shown above.

A relaunch handler accepts argc and argv parameters just like a main() does and the parsing of these parameters is exactly the same as alp_main() would, so we can move most of the code from the main function to the relaunch handler.

void onLaunchRelaunch( int argc, char *argv[], void *userdata )
{
   while (argc--)
   {
      argv++;                   // Next parameter
      if ( !strcmp(argv, ALP_APP_PRIMARY) )
      {
         gtk_init(&argc, &argv);   // Activate GTK UI

         *(GtkWindow **)userdata = initializeUI( NULL );

      } // if ALP_APP_PRIMARY
   } // while ()
} // void onLaunchRelaunch()

gint alp_main(gint argc, gchar *argv[]) 
{
   GtkWindow *winmain=NULL;

   alp_app_add_exit_handler(onAppExit, NULL); // Register app exit handler

   alp_add_relaunch_handler( onLaunchRelaunch, &winmain );

   onLaunchRelaunch( argc, argv, &winmain );

   if (winmain)
      gtk_main();            // Run the UI; dispatch UI events

   // TODO: Save application state information to restore
   return 0;
} // alp_main()

Step 7: Userdata “Anchor Block”

To consolidate application specific data and propogate it to the necessary functions without relying on globals, we use a common struct.

typedef struct UserData_s {
   // TODO: Fill in app specific fields
} UserData_t;
typedef struct UserData_s {
   GtkWidget *winmain;          // App's main window
} UserData_t;

void onLaunchRelaunch( int argc, char *argv[], void *data )
{
   UserData_t *userdata = (UserData_t *)data;
   while (argc--)
   {
      argv++;                   // Next parameter
      if ( !strcmp(argv, ALP_APP_PRIMARY) )
      {
         gtk_init(&argc, &argv); // Activate GTK UI

         userdata->winmain = initializeUI( data );

      } // if ALP_APP_PRIMARY
   } // while ()
} // void onLaunchRelaunch()

gint alp_main(gint argc, gchar *argv[]) 
{
   UserData_t *userdata=g_malloc(sizeof(UserData_t));
   memset(userdata, 0, sizeof(UserData_t));  // Commonly set fields to 0, NULL, false, etc.

   alp_app_add_exit_handler(onAppExit, userdata); // Register app exit handler

   alp_add_relaunch_handler( onLaunchRelaunch, userdata );

   onLaunchRelaunch( argc, argv, userdata );

   if (userdata->winmain)
      gtk_main();            // Run the UI; dispatch UI events

   // TODO: Save application state information to restore
   g_free( userdata );
   return 0;
} // alp_main()

Step 8: (lib)Glade Integration

We can be lazy about coding our UI and let Glade do it. It also means we can let someone else work on presentation while I code.

  1. Generate a project .glade file using Glade3.
  2. Add code to utilize the Glade definition file.
.
.
.
#include <glade/glade.h> // glade*()
.
.
.
GtkWindow *initializeUI( gpointer userdata ) { // Load/activate UI defintion GladeXML* glade; // Glade "DOM" instance glade = alp_bundle_acquire_glade_xml("app_ui.glade", NULL ); // TODO: Add hard-coded UI initialization here. // Enable any Glade defined signal handlers glade_xml_signal_autoconnect(xml); return GTK_WINDOW( glade_xml_widget_get( glade, "mainwindow" ) ); } // initializeUI()
.
.
.

Step 9: Saving and Restoring Application State

ALP application processes can be started and stopped at any time by the system. In order to give the user the impression that the app is running continuously, save and restore the state when the process is entered and exited. So, let’s add a couple of entry points to allow us to do that, generically, doInitializeApp() and doTerminateApp(). There is no prespecified method to store the application state; it can be saved in files, Global Settings, SQL, or elsewhere.

It might be convenient to represent the “live” version of the application state in the UserData_t struct.

void doInitializeApp( UserData_t *userdata )
{
   // TODO: Restore application state
} // doInitializeApp()

void doTerminateApp( UserData_t *userdata )
{
   // TODO: Save application state
} // doTerminateApp()

gint alp_main(gint argc, gchar *argv[]) 
{
   UserData_t *userdata=g_malloc(sizeof(UserData_t));
   memset(userdata, 0, sizeof(UserData_t));  // Commonly set fields to 0, NULL, false, etc.
   doInitializeApp( userdata );

   alp_app_add_exit_handler(onAppExit, userdata); // Register app exit handler

   alp_add_relaunch_handler( onLaunchRelaunch, userdata );

   onLaunchRelaunch( argc, argv, userdata );

   if (userdata->winmain)
      gtk_main();            // Run the UI; dispatch UI events

   doTerminateApp( userdata );
   g_free( userdata );
   return 0;
} // alp_main()

Step 9a: Saving State in a File

File data cannot just be stored anywhere, it has to be stored in an appication specific area in the filesystem. Rather than assume the location of the path, use alp_bundle_rw_pathname() to allow the system to return the path dynamically.

gchar* alp_bundle_rw_pathname(
  AlpBundle  index,  
  const char *file_path,  
  gboolean  vivify 
 )  
.
.
.
#define STATE_FILE "appstate.dat"
.
.
.
void doInitializeApp( UserData_t *userdata ) { gchar *state_file=alp_bundle_rw_pathname( alp_bundle_application(), STATE_FILE, FALSE ); if ( state_file ) { // TODO: Restore application state from file. g_free(state_file); } } // doInitializeApp() void doTerminateApp( UserData_t *userdata ) { gchar *state_file=alp_bundle_rw_pathname( alp_bundle_application(), STATE_FILE, TRUE); // TODO: Save application state to file g_free(state_file); } // doTerminateApp()
 


© 2008 ACCESS Developer Network    |    Joomla! is Free Software released under the GNU/GPL License.    |    ACCESS Global Website
Events Support Community Platforms Home