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

Downloads
Documentation
Forums
Blog
Press
Contact Us




Coding for the User Interface PDF Print E-mail

The ACCESS Linux Platform Application Model ^TOP^

Application Architecture ^TOP^

Palm OS applications have historically been structured as monolithic blocks of code. These applications were responsible for managing their domain data, presenting views of the data, and handling interaction with the user. One of the advantages of this approach was that it provided the potential for reducing overall code size by sharing code between the three responsibilities. The downside of this approach was that it made change of any kind difficult, and reuse outside the applications impractical.

What is an ACCESS Linux Platform Application?

To support change, and reuse, ACCESS Linux Platform applications need to be structured in such a way that the three basic responsibilities of any application are decoupled. There are two relevant design patterns that have been used successfully for many years. They are:

  • Model-View-Controller
  • Document-View

The primary difference between these two patterns is that the Document-View pattern decouples the data management from the presentation and control, but the presentation and control are coupled. The Model-View-Controller pattern decouples all three. The diagram below illustrates the interaction between the different parts of the M-V-C pattern.

Figure 6.1  Model-View-Controller

Another advantage of separating the model from the presentation and control is that multiple views and controllers can share the same model. For example, a view of the user's contacts could be displayed at the same time that a background sync, or exchange, was using the model to access contact information. Note that in this case, the sync client and exchange are acting as "Views" even though there may be no UI.

ACCESS Linux Platform applications must follow at least the Document-View pattern. That is, they must separate all the data management responsibilities for their application from any UI and control logic. For example, the PIM applications implement their respective models as shared libraries that can be unit tested independent of any view or control.

For more in-depth descriptions of the Model-View-Controller pattern, refer to:

Model

The diagram below illustrates the different responsibilities of a data model.

Figure 6.2  Data Model

Application State

Data models are responsible for maintaining application state. The state can contain non-persistent data; however the primary type of state maintained is persistent. The PIM applications and Media Selector use a SQLite database to maintain persistent data, although there is no requirement that a data model use SQLite or any other type of database. For example, a data model could maintain its persistent data in a file.

The question of '''where''' a data model maintains its persistent state is addressed by the use of the Bundle Manager.

Bundles

Bundles for ACCESS Linux Platform applications have the structure diagramed below. Keep in mind that while bundles for ACCESS Linux Platform applications currently correspond to a directory hierarchy in /opt/alp/bundles, this won't always be the case. In particular, bundles provided as "bar" files, i.e. compressed bundles, similar in intent to jar files, will probably be implemented as cramfs file systems. Consequently, don't assume you can directly open a file in a bundle, e.g. a resource.

Figure 6.3  Bundle structure

Bundle data is split into read-only, and read-write areas. The static bundle data, including any code and resources, is installed when the application bundle is added to the device. The location where the application needs to store its dynamic data is provided by the Bundle Manager, and will be somewhere under /var/opt/alp/bundles.

Concurrent Access

Data models are responsible for arbitrating access to their data from multiple processes. The PIM applications rely on the SQLite implementation to handle concurrent access. If a data model is implemented by maintaining its state in a file, it could use the file system to support concurrent access, as long as the granularity was sufficient. Otherwise, the data model would need to provide additional support for finer granularity access.

Updates

Data models are responsible for all changes to their internal state. In particular, they are responsible for maintaining the consistency of their data (which might involve validating change requests), and tracking changes.

Notification

Data models are responsible for notifying all interested parties that their state has changed. The current plan is for the data model to use the Notification Manager to send change notification to anyone that has registered to be notified. In general, views only need to register for change notification when they are running (foreground or background) since they will request the latest data from the data model when they start up.

Although the Notification Manager provides the ability for the data model to send a variety of notifications that distinguish between types of changes, in order to allow views to optimize what they refresh, I strongly suggest starting out with a simple, "something changed". If view optimizations end up being required, additional notifications can be added.

Data References

Data models can provide references (or links) to their data by returning the LUID (Locally Unique ID) associated with the referenced data. For example, the Media Selector data model will provide LUIDs to ringtones for the Contacts application. The support for references is a consequence of supporting synchronization (See Referential Data). The LUID that is used as a reference is guaranteed to be unique on the device and will persist across synchronizations.

Application Startup ^TOP^

The lifecycle begins when the Application Server invokes an application's main entry point. The application examines its arguments (in argc and argv) in order to determine what action to perform. It then continues execution until either its task is finished, or the Application Server requests that it exit. There are a variety of standard launch arguments, but applications can also define their own. Some of the more common ones are:

ALP_APP_PRIMARY
The application is being launched as the main UI application, and should display its full UI. The current primary application will exit or move to the background. If the application receiving this launch code is already running, it should make sure that its full UI is visible.
ALP_APP_BACKGROUNDED
The application is no longer the primary application, but will be allowed to remain running in the background. It should hide its full UI. It can still do some UI if necessary (dialogs, for instance), but it is no longer the "main UI application." If the application receiving this launch code has no background activity to perform, it can simply exit—but this launch code will generally only be sent to applications which indicate a need for background execution.
ALP_APP_EXCHANGE
The application is being launched or relaunched to run an exchange handler. The exchange request is encoded in argv[2].
ALP_APP_NOTIFY
The application is being launched or relaunched to handle a notification. The notification details are encoded in the ALP_NOTIFY_LAUNCH parameter.
ALP_APP_ALARM
The application is being launched because one of its alarms went off. The launch code is followed by the reference number of the alarm.
ALP_APP_FIND
The application should search for a particular term.

The most common launch code is ALP_APP_PRIMARY. An application launched with ALP_APP_PRIMARY will continue execution until a new primary application is launched.

Application Execution ^TOP^

ACCESS Linux Platform applications generally behave like generic GTK applications during execution. They will use GTK to display some UI, and run gtk_main() until it is time for them to quit.

The major departure from GTK is the fact that the Application Server only supports running a single instance of any given application. If a running application is launched again, the new launch arguments are delivered to it through a "relaunch handler," (set using alp_app_set_relaunch_handler()); it is expected to update its state accordingly. This might mean fulfilling an exchange request, showing or hiding UI, etc. Applications which fall into this category include those that support or require both primary and background execution, register for system notifications, register with Exchange Manager to handle any particular content types, etc.

It's worth noting that unless the application goes out of its way to use certain platform-specific facilities (by specifying that the application can be run in the background, registering for notifications or alarms, registering with the Exchange Manager, etc.), it will probably never be launched while it is already running, and there will be no need for it to register a relaunch handler. This provides a somewhat easier transition for developers familiar with GTK. If the Application Server receives a launch request for the running application and that application has no relaunch handler, the application will be shut down and launched again with the new launch arguments. This is inefficient, but guarantees that the launch arguments are obeyed. The inefficiency is considered acceptable since this is expected to happen only rarely.

Application Shutdown ^TOP^

The Application Server maintains the traditional Palm OS model of having the system tell the application when to exit. While an application may exit at any time of its own accord, it should also be sure to always obey an exit request from the Application Server. Applications which need to perform cleanup before exiting register callback handlers to receive the exit request and respond by returning from alp_main() after performing any necessary cleanup. The application may add (and remove) multiple callbacks in order to associate different types of cleanup with the current program state (for example, if the application displays a dialog, it can also register an exit handler to dismiss that dialog). Exit handlers are always executed in order, starting with the most recently added. If the application does not register any exit handlers, then the Application Server client-side library raises a SIGTERM signal instead. This provides a mechanism for exit notification which is more familiar to UNIX developers, and may be sufficient for simple applications.

In either case, if the application does not cease execution within a short time frame (a few seconds), the Application Server sends a SIGKILL, and a warning dialog may be displayed to the user (as much to make sure developers handle the notification as to warn users). There are no functions available to applications for resetting this timer. Applications with a genuine need for a lengthy exit procedure should instead specify ALP_APP_PROP_BACKGROUND_REQUIRED in their manifest file, and register a relaunch handler. When the Application Server relaunches the application in the background, it can run its lengthy exit procedure and return from alp_main() to terminate.

Application Server ^TOP^

The Application Server (which is packaged as the Application Manager) provides the following services:

  • An application launching mechanism and the management of application lifetimes.
  • The routing of launch requests to the existing instance if the application is currently running.
  • Coordination of the "main UI application."
  • Default behavior for certain important system events, such as hard key handling and clamshell open/close.
  • A set of global system services, including system-wide find and the clipboard.

The Application Server runs in its own process. Applications run in their own processes and control their own UI. This simple mapping of applications to processes provides a secure, stable model for application execution. The Application Server preserves the old Palm OS behavior of having one main UI application at a time. When the user runs a new application, the system either asks the current one to exit or moves it to the background. Finally, the Application Server only runs a single instance of any given application at one time.

Applications can express a preference in their manifest file for whether or not they can or should be run in the background. The choices are:

unsupported
Background execution is not supported. The application can only be run in the foreground. If the user switches to another application, the current application will be asked to exit. This is the default value if no preference is expressed.
supported
Both foreground and background execution are supported.
preferred
The application prefers to run in the background as long as sufficient resources are available.
required
Foreground execution is not supported. The application can only be run in the background. Applications so tagged need to be extremely careful with resource usage.

The Application Server maintains a list of currently running applications, and keeps track of which one is the primary or main UI application. This special status is used to coordinate the display and hiding of UI when the user switches between applications. Note that an application that is not the main UI application may still display UI under exceptional circumstances—but this should be done rarely, and it should be done in the form of modal dialogs. For example, this might be done when a background application needs to ask the user for a password.


NOTE: ACCESS expects that most applications will not run in background mode.

Application Launch ^TOP^

As discussed in "Launching and Launch Codes", all ACCESS Linux Platform applications need to export (at a minimum) their main entry point, which has the signature:

int alp_main(int argc, char *argv[])

Launch codes, in the form of C strings, are passed as argv array elements. For those launch codes that are accompanied by parameters, you'll find their parameters immediately following the launch code in the argv array.

Constants are defined for the various system-wide launch codes in the Application Manager header file (appmgr.h); use them instead of the actual strings in your code. For instance, instead of the string "--alp-primary" (the launch code that indicates that you have primary control over the user interface), use ALP_APP_PRIMARY.

Because launch codes are strings, you need to use a C string comparison function such as strcmp() to compare each argv array element (except for argv[0], which contains the name of the bundle) with those launch codes that you expect. For instance, the following could be used if you are only interested in ALP_APP_PRIMARY:


	bool regularLaunch; 
 
	// launch codes (and any parameters) begin at argv[1] 
	regularLaunch = false; 
	for(i = 1; i < argc; i++){ 
		if(strcmp(argv[i], ALP_APP_PRIMARY) == 0){ 
			regularLaunch = true; 
		} 
	} 
 
	if(regularLaunch){ 
		// we're the "primary UI" app 
	} else { 
		// we didn't receive ALP_APP_PRIMARY 
	} 

If your launch code is accompanied by one or more parameters (see Table 4.3), be sure to deal with those parameters accordingly. A launch code's parameters will immediately follow the launch code in the argv array. See "An Example of Launching and Relaunching" for an illustration of the launch codes and parameters that are sent to an application that receives a variety of launch codes.

Handling Launch Codes ^TOP^

When you are the primary UI application, you can consider that you have full control over the UI. Call gtk_init(), set up your user interface, and then begin your main loop by calling gtk_main().

Be conscious of the fact that you can receive multiple launch codes at one time. For instance, if your application is running when the user initiates a Find request, and your application has indicated that it should process such requests, it will receive both an ALP_APP_PRIMARY and an ALP_APP_FIND launch code. Be sure to examine the entire contents of the argv array when launched or relaunched.

If you anticipate receiving launch codes when you are not the primary application—an alarm, say, that might trigger when the user is running some other application, or perhaps a notification—it is very important that you recognize that some other application, and not yours, is the primary UI application. Not being the main UI application imposes a couple of responsibilities upon your application:

  • You shouldn't interact with the UI (except, perhaps, through a dialog). The user is running a different application at this time that expects to be in full control of the user interface. If ALP_APP_PRIMARY is not among the launch codes you have received, do not call any GTK or Glade functions.
  • You need to handle the launch code quickly, and then return. An inordinate amount of processing on the part of your application will affect the perceived performance of the primary UI application, causing it to pause or appear to slow down.

Relaunch Handlers ^TOP^

If you anticipate receiving launch codes while your application is running, you'll likely want to register a relaunch handler. Without a relaunch handler, every time a launch code is sent to your application while it is running, the Application Manager first sends a signal to your application forcing it to quit. It then relaunches your application, passing the launch code as it does so. This means that your application will have to save its state, tear down its UI, and then rebuild its UI and restore its state once it is relaunched, just to handle a launch code such as ALP_APP_FIND or ALP_APP_ALARM.

A relaunch handler provides a mechanism whereby the Application Manager can pass launch codes to your running application without forcing it to exit.

Your relaunch handler has a prototype that is very similar to that used by alp_main():


void *MyRelaunchHandler(int argc, char *argv[], gpointer cbData) 

Launch codes are passed as strings through the argv array, just as in alp_main(). The only difference is in the cbData parameter, which allows you to pass an application-specific pointer value between the code registering the relaunch handler and the handler itself. This pointer can be used to indicate a block of data that is shared between the mainline code and the handler.

Registering a Relaunch Handler

Use the alp_app_set_relaunch_handler() function to register a relaunch handler.


alp_app_set_relaunch_handler(MyRelaunchHandler, NULL); 

The only two parameters are the pointer to your relaunch handler, and a pointer to the application-specific data block. This latter parameter is only needed if you need a mechanism for sharing data between the code registering the relaunch handler and the handler itself. If you have no such need, simply set the second parameter to NULL.

The relaunch handler will only be called if the Application Manager needs to pass a launch code to your application while it is already running. If it is not running, the Application Manager will pass any launch codes to it by invoking its alp_main() entry point.

Note that there can only be a single relaunch handler registered for a given application at one time. To change the relaunch handler to a different function, simply call alp_app_set_relaunch_handler() a again and supply a pointer to the new function. If you have a need to "unregister" your relaunch handler, supply a NULL value for the function pointer, like this:


alp_app_set_relaunch_handler(NULL, NULL); 

If you unregister your relaunch handler, any launch codes will once again be delivered to your application through alp_main().

An Example of Launching and Relaunching

To illustrate how your application is launched and relaunched, consider a simple application that sets a time-delayed alarm (the alarm goes off after 30 minutes, say). When the alarm is triggered, the application then posts an alert to the Attention Manager. We'll assume that the application registers for a relaunch handler (but note that it doesn't necessarily need to; without one, the invocations of the relaunch handler in steps 3 and 4 below would simply be replaced by invocations of alp_main(), with the same argv values, instead).

  1. The application is launched. (It remains running throughout the following steps.)

    The alp_main() function is called with a single argv value:
    argv[0] = --alp-primary.

  2. The alarm is set.
  3. The alarm is triggered.

    The relaunch handler is called with three argv values:
    argv[0] = bar:com.access.apps.alarmtest
    argv[1] = --alp-alarm
    argv[2] = 0

    Note that the final argument is the 32-bit alarm identifier that was specified when the alarm was set. Also note that the ALP_APP_PRIMARY launch code ("--alp-primary") is not included, even though the application is indeed the primary UI application. Because the relaunch handler was called, you are already running, and should know whether or not you are the main UI application.

  4. The Attention Manager brings the alarm to the user's attention, and the user selects the "Go To" button.

    The relaunch handler is called with four argv values:
    argv[0] = bar:com.access.apps.alarmtest
    argv[1] = --alp-primary
    argv[2] = --alp-display
    argv[3] = aUniqueString

    Here, the final argument is the unique string that helps uniquely identify the alert, supplied when the alert was posted.

For another example, showing the launch codes that are received by an application running in the background, see Chapter 14, "Background Processing."

Handling and Broadcasting Notifications ^TOP^

As described in the section "Notifications," notifications are general system-level or application-level events that can be broadcast to multiple registered receivers. While most notifications are generated by the operating system, it is possible for applications to create and broadcast their own types of notification (but note that unless someone knows to register for such a custom notification type, the broadcast will fall on deaf ears).

A given notification is not sent to a particular application unless that application has specifically registered for notifications of that type. The Notification Manager provides functions that allow your applications to register for notifications, as well as to:

  • unregister previously registered notifications
  • signal the completion of a notification
  • broadcast notifications

There are a great many notifications defined by the Platform; as of this writing there were over 100, as listed in Table 6.1. This list is not static, however. For the most up-to-date information, see the header files provided in the ACCESS Linux Platform SDK as well as those provided by the Hiker Application Framework. Nearly all are defined using constants with names beginning with ALP_NOTIFY_EVENT_.

Registering for Notifications ^TOP^

Applications do not receive any notifications by default. To receive a particular notification, you must register for that notification. With one exception, which will be covered shortly, you register for notifications by calling either alp_notify_register() or alp_notify_register_launch().

There are a couple of differences between these two APIs, but the fundamental difference lies in the persistence of the registration. If you call alp_notify_register(), your application will only receive notifications as long as the application is running. Once your application exits, it unregisters for all notifications that were registered for using this API.

alp_notify_register_launch(), on the other hand, creates a persistent registration that lives on after your application exits. In fact, such registrations even survive a system reboot. Thus, you need to use this API with care, and be sure to explicitly unregister (using alp_notify_unregister_launch()) for notifications registered for using this API when you no longer need the notification. Because of the overhead involved in sending a notification to a non-running application, unneeded registrations can have a negative affect on overall system performance. Thus, alp_notify_register_launch() should be used with great care.

When registering for multiple notifications, you needn't register for all of them using only one or the other API. For instance, if you wanted to register for a "time change" notification as well as a "boot" notification, you could follow the example shown in Listing 6.1.

Listing 6.1  Registering for notifications


// register for the time change notification 
err = alp_notify_register( 
	ALP_NOTIFY_EVENT_SYSTEM_CHANGE, 
	myNotificationHandler, 
	NULL, 
	ALP_NOTIFY_PRIORITY_NORMAL, 
	0); 
 
// register for the boot notification 
err = alp_notify_register_launch( 
	"bar:com.access.apps.NotifyTest", 
	ALP_NOTIFY_EVENT_NOTIFY_BOOT, 
	ALP_NOTIFY_PRIORITY_NORMAL, 
	0); 

Notice that in addition to the persistence of the registration, another key difference between the two registration APIs is the way in which the notification is delivered to your application. Because a registration made with alp_notify_register_launch() can result in a notification sent to your application even when it is not running, the notification is sent using the standard launch mechanism. Thus, you supply the name of your bundle and the notification is delivered through alp_main() or your relaunch handler, as appropriate.

On the other hand, because your application must be running in order to receive a notification registered for using alp_notify_register(), the notification can be delivered in a more efficient fashion. The second parameter passed to alp_notify_register() is a pointer to a notification handler, which is called directly when the notification is sent to your application. Your notification handler must have a prototype as defined by the AlpNotifyCallbackProc typedef; something like this:


int myNotificationHandler(const char *notifyType, 
	void *details, int length, int *handled, 
	const char *appID, void *userData){ 
 
	// process the notification here 
 
	alp_notify_done(appID, 0, 0); 
 
	return(ALP_NOTIFY_CALLBACK_CONTINUE); 
} 

Notification Type Strings

The "notification type" parameter that you supply to the alp_notify_register_launch() and alp_notify_register() functions is a string that looks something like this:

"/alp/notify/boot/"

The various header files provided in the SDK define constants for all of the notifications broadcast by the operating system. Just about all can be used as-is, as was shown in Listing 6.1. However, a couple of these constants only contain the first part of the notification type string;

Notification types are provided as strings


alp_notify_register(
    ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE ALP_PREFS_VOLUME_SILENTMODE,
    (AlpNotifyCallbackProc *)silent_mode_change_callback, 
    NULL, ALP_NOTIFY_PRIORITY_NORMAL, 0); 

Registration Priorities

When a single notification is broadcast to multiple receivers, the Notification Manager takes into the account the priority values supplied when the receivers registered for the notification and sends the notification to those receivers in priority order. If two or more receivers registered with the same priority, the first receiver to register for the notification with that priority receives the notification first.

Usually you pass a value of ALP_NOTIFY_PRIORITY_NORMAL for the priority. To specify that you want to receive the notification before or after most other handlers for notifications of this type, specify one of the other ALP_NOTIFY_PRIORITY_* constants.

Application Installation Notifications

As mentioned earlier, there is one exception to the rule that you register for notifications using one of the two alp_notify_register... APIs. Calling one of those APIs obviously means that your code has to be running. But what if your application needs to be notified that it has been installed? It cannot register for such a notification through an API call since it has yet to run. Accordingly, there is a <notifications> element that, when added to your application's manifest file, causes your application to be notified (with ALP_NOTIFY_EVENT_NOTIFY_REGISTER) at the time it is registered with the Application Manager server. Listing 6.2 shows a Manifest.xml file with a <notifications> element added. To enable the application registration notification, add all three lines of the <notifications> element as shown in the listing to your application's manifest file.

Listing 6.2  A manifest file with a <notifications> element


<?xml version="1.0" encoding="UTF-8"?> 
 
<manifest name="com.access.apps.NotifyTest"> 
	<application> 
		<name>NotifyTest</name> 
		<icon>icon.jpg</icon> 
	</application> 
	<notifications> 
		<register/> 
	</notifications> 
</manifest> 

It is important to be aware that when you receive the ALP_NOTIFY_EVENT_NOTIFY_REGISTER notification, signifying that your application has just been registered with the Application Manager server, it is not accompanied by the ALP_APP_PRIMARY launch code. You are not the primary UI application at this time, and thus should not assume control of the user interface. Do your work quickly, acknowledge the notification, and return. Typically, applications responding to this notification register for other notifications of interest.

Global Settings Notifications

As discussed in "Preferences and Global Settings," the Global Settings Service provides a unified mechanism that allow applications to get and set both application preference and device-specific settings. Application preferences aren't likely to be changed outside of your application, but depending upon the purpose of your application you may want to register for notification of system-level changes made by the user—in a preferences panel, for instance. "Change Notification" discusses the kinds of notifications that are sent out and how to register for them. Note that the notification keys for a great many preferences settings are declared in /alp/alppreferences.h.

System Boot and Notification Persistence

Notifications registered for using alp_notify_register_launch() persist across a system reset. Thus, if your application registers for a notification using this API and then the system is rebooted, your application need not re-register for the notification. This is important to note, since it reduces the need to register for a system boot notification (ALP_NOTIFY_EVENT_NOTIFY_BOOT) in response to which you would otherwise be re-registering for other notifications.

If you nevertheless need to register for a boot notification, see Listing 6.1 for an example. Note that it makes no sense to use alp_notify_register() to register for a boot notification, since the registration won't persist beyond the lifetime of your application, and since your application is shut down in the process of rebooting, the registration won't be in force when the system is brought back up.

When to Register for Various Notifications

Keeping in mind that launching an application on a system running Linux and GTK+ (as ACCESS Linux Platform is) has a cost. Unless you absolutely need to, don't register for boot notifications (ALP_NOTIFY_EVENT_NOTIFY_BOOT). If you must, keep your handling of this notification to a minimum. In particular, do not call gtk_init() or perform any UI-related activities, and don't register for other notifications here. Applications that need to perform some type of hardware configuration may need to do this in response to a boot notification. Be aware that if your application isn't present when the device is booted, it won't receive this notification. Thus, when your application is first installed and run, any hardware configuration that your application performs in response to the boot notification won't have been done.

Instead, applications should register for the Install notification (ALP_NOTIFY_EVENT_NOTIFY_REGISTER); this notification is sent to your application only when it is registered with the Application Manager server. As part of handling this notification, you can register for other notifications, register with the Exchange Manager, and the like.

When your application starts or otherwise gains control you should check for things that need to be true when your application is running. For instance, you might want to re-read your global settings keys. Or, if you expect particular files in /home, check for them when your application starts. While you may have done some or all of this in response to the install notification, since then the user or another program may have altered things.

Unregistering for Notifications ^TOP^

Notification registrations made with alp_notify_register() are automatically unregistered when your application exits. All registrations made by your application are automatically unregistered when your application is deleted. At all other times, however, your notification registrations persist. For performance reasons, it is very important that you unregister for notifications as soon as your application no longer needs to know about them.

If you registered for a notification with alp_notify_register_launch(), unregister for it by calling alp_notify_unregister_launch(). Similarly, registrations made using alp_notify_register() should be unregistered by calling alp_notify_unregister(). In either case, set the flags parameter—which is reserved for future use—to zero.

Receiving Notifications ^TOP^

The mechanics of receiving a notification depend upon how you registered for the notification. If you specified a bundle name (using alp_notify_register(), or, indirectly, by registering for an "application registered" notification in your manifest file), notifications are delivered to your application as launch codes. They are either passed to alp_main(), or, if your application is running and you have registered a relaunch handler, to your relaunch handler. If you registered by calling alp_notify_register_launch() and supplying the name of a callback function, the notification is delivered to your application via parameters to that function.

Regardless of how you receive the notification, the general steps you take in the body of your notification handler are the same.

Notification Callback Functions

If you have registered for a notification by specifying a callback function, when that notification is broadcast your callback is passed the name of the notification (in the notifyType parameter) along with a notification-specific structure (details is a pointer to the structure, and length indicates the size of the structure, in bytes).


IMPORTANT: Before dereferencing the details pointer, ensure that length is non-zero. If length is zero, the details pointer is not valid.

appID identifies the application (such as "bar:com.access.apps.notifytest") or operating system component (such as "bundlemgr_d") who broadcast the notification. The userData parameter is passed through from the alp_notify_register() call; use it if you want to pass application-specific data from the code registering for the notification to the code handling the notification. The remaining parameter, handled, will be discussed in "Coordinating Among Multiple Handlers."

Listing 6.3 illustrates the basics of just such a notification callback function.

Listing 6.3  Handling notifications in a callback


int myNotificationHandler(const char *notifyType, 
	void *details, int length, int *handled, 
	const char *appID, void *userData){ 
 
	// process the notification here 
 
	alp_notify_done("bar:com.access.apps.notifytest", 0, 0); 
 
	return(ALP_NOTIFY_CALLBACK_CONTINUE); 
} 

Notifications Passed Through Launch Codes

If you have registered for a notification using alp_notify_register_launch(), when the notification is issued the Notification Manager instructs the Application Manager to launch or relaunch the application as appropriate, passing the notification through the argv parameter to alp_main() or through the argv parameter to the relaunch handler1. Your application needs to parse the argv array to get the notification type and any notification-specific data.

In walking through argv, you'll know you have a notification if you encounter an ALP_APP_NOTIFY launch code. That is, one of the elements of argv is set to "--alp-notify". When you encounter this launch code, the following two argv elements contain the notification details structure (encoded as a string, and prepended with "--alp-notify-details=") and the notification type (prepended with "--alp-notify-type="). That is, the relevant portion of the argv string array looks like this:

argv[n] = "--alp-notify"

argv[n+1] = "--alp-notify-details=details_structure_as_string"

argv[n+2] = "--alp-notify-type=notification_type"

Parsing the contents of the string containing the notification details is a relatively complex process made simple through the use of the alp_notify_details() function. Pass it a pointer to the argv array element that represents the notification parameters, along with a pointer to an AlpNotifyLaunch data structure, and the function will parse the string and populate the data structure. The AlpNotifyDetails structure is defined like this:


typedef struct _AlpNotifyLaunch AlpNotifyLaunch; 
struct _AlpNotifyLaunch { 
	int handled; 
	int length; 
	char details[ALP_NOTIFY_MAX_DETAILS_SIZE+1]; 
	char notifyType[ALP_NOTIFY_MAX_NOTIFY_SIZE+1]; 
	char appID[ALP_NOTIFY_MAX_APPID_SIZE+1]; 
}; 

Any notification-specific details (see Table 6.1 for information on what, if anything, is included with each type of notification) will be found in the details element. Note that details is a fixed-length array; the actual length of the data in the array is specified by length. Be aware that length can be zero!

notifyType identifies the type of notification ("/alp/system/change/time", for example). appID identifies the application (such as "bar:com.access.apps.notifytest") or operating system component (such as "bundlemgr_d") who broadcast the notification. The handled element will be discussed below, under "Coordinating Among Multiple Handlers."

Listing 6.4 shows one way to walk the contents of the argv array and handle (in this case) two different notification types. Listing 6.5 shows a different way to accomplish the same basic task from within a relaunch handler. In both cases, alp_notify_details() is used to populate the notification structure with the contents of the appropriate argv array element.

Listing 6.4  Handling notifications in alp_main()


argc--; argv++;    // argv[0] is the name of the app 
 
if(argc >0 && NULL != *argv) { 
	if(!strcmp(*argv, ALP_APP_NOTIFY)) {	// Got a notification 
		argc--; argv++;    // consume launch code 
 
		AlpNotifyLaunch notification; 
		int notify_size; 
	 
		notify_size = alp_notify_details(*argv, &notification); 
		argc--; argv++;    // consume notification details 
		 
		if(!strcmp(notification.notifyType,
               ALP_NOTIFY_EVENT_NOTIFY_REGISTER)) { 
			// handle the register notification 
		} else if(!strcmp(notification.notifyType,
            ALP_NOTIFY_EVENT_SYSTEM_CHANGE)) { 
			// handle time / date / zone changes 
		} else { 
			// Not a notification that we are expecting 
		} 
 
		alp_notify_done("bar:com.access.apps.notifytest", 0, 0); 
	} 
	// handle other (non-notification) launch codes here 
} 

Listing 6.5  Handling notifications in a relaunch handler


static void my_relaunch_handler(int argc, char *argv[],
                                gpointer cbData) { 
	AlpNotifyLaunch notification; 
	int notify_size; 
 
	if (argc > 1){ 
		// argv[0] is, by convention, the name of the app 
		if (strcmp(argv[1], ALP_APP_PRIMARY) == 0) { 
			// switch to foreground 
		} else if (!strcmp(argv[1], ALP_APP_BACKGROUNDED)) { 
			// switch to background 
		} else if(argc > 2 &&  
		          !strcmp(argv[1], ALP_APP_NOTIFY)) { 
			notify_size = alp_notify_details(argv[2],
			    &notification); 
			prv_hello_notifications_handler(argv[3], details,
			    details_size); 
 
			alp_notify_done("bar:com.access.apps.notifytest",  
				0, 0); 
		} 
	} 
} 

Verifying the Notification Type

If you receive notifications through launch codes (either using a relaunch handler or alp_main()), or if you designate a single notification handling callback when registering for multiple notifications, you'll need to examine the received notification so you can determine how to handle it. The code in Listing 6.4 illustrates the use of the strcmp() function to distinguish between notification types.

It is important to note, however, that certain notification strings extend beyond the constant string values defined in the header files that are part of the Hiker Application Framework and the ACCESS Linux Platform SDK. For instance, when registering for notification of a change to a global settings value (see "Global Settings Notifications"), the notification type string is "/alp/globalsettings/keychange/" (ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE) plus the key string. For example, a change to the key "oma/apps/calendar/fontsize" causes a notification to be broadcast with the notification type "/alp/globalsettings/keychange/oma/apps/calendar/fontsize". As well, having registered for a change to a global settings key, your application will be notified when there are changes to that key or to a prefix of that key. For instance, if your application registered for "oma/apps", it would be notified when any of the following keys changed: "oma/apps/calendar/fontsize", "oma/apps/date/background-image", or "oma/apps".

Accordingly, there are some situations where you may want to use a string comparison function other than strcmp(). For instance, you might choose to use strstr():


if (strstr(argv[nameIndex], ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE))	{ 
	// handle key change notifications here 
} 

Or, you could use strncmp():


if(!strncmp(launch.notifyType, ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE,
    strlen(ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE)))	{ 
	// handle key change notifications here 
} 

However you choose to handle the situation, be aware that you need to properly handle all notifications you receive, whether or not you are interested in them. Of course, handling any extraneous notifications likely involves no more than simply calling alp_notify_done() or returning from your notification handling callback function.

Handling Notifications ^TOP^

It is very important that applications check for notifications as early as they can, keeping the notification-handling code path as short as possible. Do not make any unnecessary calls before handling notifications, either in alp_main() or in a relaunch handler. In particular, do not call gtk_init() before handling notifications unless the notification handler needs GTK.

Upon receipt of a notification, your application should do whatever processing is appropriate, and then, if you registered for the notification using alp_notify_register_launch(), call alp_notify_done() to signal that the notification should be passed on to the next registered application or server in the queue.


NOTE: If you registered for the notification by calling alp_notify_register() and specifying a callback function, you shouldn't call alp_notify_done(). The Notification Manager waits until your callback function returns before passing the notification on to the next registered application or server in the queue. If you want to allow the notification to be passed on before your callback does its work, create a new function where the actual work is done, specify it to g_idle_add(), and then return from your callback.

alp_notify_done() takes three parameters, the first of which is the string that was specified when the notification was registered for (for applications, this is typically the bundle name). The second and third parameters give you some measure of control over subsequent handlers for the same notification.

You can actually call alp_notify_done() before you start a large amount of work—in response to the register notification, for instance—to let notification processing continue in parallel. However, note that this will cause the system to start up multiple applications at one time, consuming additional memory and CPU cycles. Generally, it is best to do only as much processing as is absolutely necessary, and then call alp_notify_done() when your work is complete.


IMPORTANT: A notification sent to your application is not sent on to other registered consumers until you call alp_notify_done() or until you return from your callback function. Accordingly, you must call alp_notify_done() each time you receive a notification through a launch code. If you do not, you delay processing of that notification for the rest of the system. Note that you must call it for all notifications you receive in this manner, not just for notifications you are specifically interested in.
Coordinating Among Multiple Handlers

The second parameter to alp_notify_done() is an advisory flag that indicates to subsequent notification handlers whether or not you have handled the notification. This flag is advisory only: the system does nothing with it (in particular, it does not cancel the notification), and other notification handlers may or may not choose to act upon it. It is initially set to zero; whatever value you supply in your call to alp_notify_done() is passed on to those notification handlers that follow yours in the queue. As an example of where this flag could be useful, suppose your ACCESS Linux Platform device has two separate phone dialer applications installed, each of which can handle an incoming phone call. When the first dialer in the queue receives a notification indicating that a voice call is coming in, it can handle the call and then set the handled flag to indicate to the second dialer that the call has been handled. The second dialer, noticing the state of the handled flag, would not handle the call but might perform other functions such as updating its call log.

Note that the value of the handled flag is only valid for a single instance of the notification (that is, the flag is reset to zero for the next broadcast of the same notification type). Also note that there are no specific values defined for this flag, other than a value of zero indicates "not handled."

Preventing Subsequent Handlers

Unlike the handled flag, the third parameter passed to alp_notify_done(), status, does affect if and how subsequent notification handlers receive the notification. Normally you would pass a value of ALP_NOTIFY_CALLBACK_CONTINUE to have the next registered notification handler in the queue receive the notification. However, if you pass a value of ALP_NOTIFY_CALLBACK_CANCEL, the Notification Manager will not send this particular notification instance to any remaining handlers in the queue. Note that you should only pass this value if you have handled the notification such that no other application could possibly care about it, which is rare.

Sending Notifications ^TOP^

Call alp_notify_broadcast() to broadcast a notification asynchronously. To block until all registered clients have been notified, you have two options:

  • Call alp_notify_broadcast() and supply the ALP_NOTIFY_BROADCAST_FLAG_SYNC flag.
  • Call alp_notify_broadcast_sync(). This function works much like alp_notify_broadcast() when called with the ALP_NOTIFY_BROADCAST_FLAG_SYNC flag, except you can specify a timeout interval after which the function should return even if all registered clients have yet to be notified. alp_notify_broadcast_sync() also returns the value of the handled flag, unlike alp_notify_broadcast().

As shown in Figure 4.7, notifications in a given queue are broadcast one after the other. Notifications are normally added to the end of the specified queue, but you can supply the ALP_NOTIFY_BROADCAST_FLAG_IMMEDIATE to place a notification at the head of the queue.

Notification-Specific Data

Using the details argument to either of the notification broadcast calls, you can pass a small amount of data to the notification handlers. This data is packed into a single buffer and is limited to 256 bytes (specify the length of the buffer with the length argument). This data is notification-specific and is not interpreted by the Notification Manager in any way.

Broadcast Priority

When a single notification is broadcast to multiple receivers, the Notification Manager takes into the account the priority values supplied when the receivers registered for the notification and sends the notification to those receivers in priority order. If two or more receivers registered with the same priority, the first receiver to register for the notification with that priority receives the notification first.

Table 6.1  System notification details 

Notification

Details

ALP_FLIGHTMODE_OPERATION_IN_PROGRESS

AlpFlightModeProgressNotifyType

ALP_FLIGHTMODE_PRIVATE_ENABLER_STATE_CONFIRMATION

AlpFlightModeEnablerStateConfirmationType

ALP_FLIGHTMODE_SILENT_MODE_HAS_CHANGED

AlpFlightModeHasChangedNotifyType

ALP_HS_NOTIFY_EVENT_BEGIN

None

ALP_HS_NOTIFY_EVENT_END

None

ALP_NOTIFY_EVENT_ATTN_ALERT1

AlpNotifyEventAttnAlert

ALP_NOTIFY_EVENT_BUNDLE_COPY

AlpNotifyEventBundleCopy

ALP_NOTIFY_EVENT_BUNDLE_DELETE

AlpNotifyEventBundleDelete

ALP_NOTIFY_EVENT_BUNDLE_MOVE

AlpNotifyEventBundleMove

ALP_NOTIFY_EVENT_BUNDLE_NAME_ADDED

AlpNotifyEventBundleNameAdded

ALP_NOTIFY_EVENT_BUNDLE_NAME_CHANGED

AlpNotifyEventBundleNameChanged

ALP_NOTIFY_EVENT_BUNDLE_NAME_REMOVED

AlpNotifyEventBundleNameRemoved

ALP_NOTIFY_EVENT_BUNDLE_REGISTER

AlpNotifyEventBundleRegister

ALP_NOTIFY_EVENT_BUNDLE_RESET_EVERYTHING

None

ALP_NOTIFY_EVENT_BUNDLE_UNREGISTER

AlpNotifyEventBundleUnregister

ALP_NOTIFY_EVENT_CNC_AVAILABILITY

ALP_NOTIFY_EVENT_CNC_CONNECTION

AlpNotifyEventCncConnection

ALP_NOTIFY_EVENT_DEVICE_ADDED

The udi string from the AlpVolumeSvcsFSinfo struct

ALP_NOTIFY_EVENT_DEVICE_REMOVED

The udi string from the AlpVolumeSvcsFSinfo struct

ALP_NOTIFY_EVENT_DIRECTORY_UPDATED

A string containing the full path to the directory with the changed contents.

ALP_NOTIFY_EVENT_FORMATS_CHANGE

ALP_NOTIFY_EVENT_FORMATS_CHANGE_DATE

ALP_NOTIFY_EVENT_FORMATS_CHANGE_LOCATION

ALP_NOTIFY_EVENT_FORMATS_CHANGE_NUMBER

ALP_NOTIFY_EVENT_FORMATS_CHANGE_TIME

ALP_NOTIFY_EVENT_FORMATS_CHANGE_WEEK

ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE2

A string containing the name of the key that changed

ALP_NOTIFY_EVENT_GRAS_DB_CHANGE

AlpGRASDBChangeEventDetails

ALP_NOTIFY_EVENT_GRAS_DBENVELOP_CHANGE

AlpGRASDBEnvelopChangeEventDetails

ALP_NOTIFY_EVENT_GRAS_PATH_CHANGE

A string containing the new path

ALP_NOTIFY_EVENT_GRAS_STORAGE_REMOVED

None

ALP_NOTIFY_EVENT_LOCALE_FORMAT_CHANGED

None

ALP_NOTIFY_EVENT_LOCALE_SYSTEM_CHANGED

None

ALP_NOTIFY_EVENT_NOTIFY_BOOT

None

ALP_NOTIFY_EVENT_NOTIFY_INSTALL

None

ALP_NOTIFY_EVENT_NOTIFY_REGISTER

None

ALP_NOTIFY_EVENT_POSTAL

(mask)

ALP_NOTIFY_EVENT_POSTAL_ACCOUNT

(mask)

ALP_NOTIFY_EVENT_POSTAL_ACCOUNT_STATUS_CHANGE

AlpNotifyEventAccountStatusChange

ALP_NOTIFY_EVENT_POSTAL_ENVELOPE

(mask)

ALP_NOTIFY_EVENT_POSTAL_ENVELOPE_NEW

AlpNotifyEventEnvelopeNew

ALP_NOTIFY_EVENT_POSTAL_ENVELOPE_STATUS_CHANGE

AlpNotifyEventEnvelopeStatusChange

ALP_NOTIFY_EVENT_POSTAL_FOLDER

(mask)

ALP_NOTIFY_EVENT_POSTAL_FOLDER_STATUS_CHANGE

AlpNotifyEventFolderStatusChange

ALP_NOTIFY_EVENT_POSTAL_IMPS

(mask)

ALP_NOTIFY_EVENT_POSTAL_IMPS_PRESENCE

(mask)

ALP_NOTIFY_EVENT_POSTAL_IMPS_PRESENCE_AUTH

AlpNotifyEventImpsPresenceAuth

ALP_NOTIFY_EVENT_POSTAL_IMPS_PRESENCE_UPDATE

AlpNotifyEventImpsPresenceUpdate

ALP_NOTIFY_EVENT_POSTAL_IMPS_SESSION

(mask)

ALP_NOTIFY_EVENT_POSTAL_IMPS_SESSION_INFO

AlpNotifyEventImpsSessionInfo

ALP_NOTIFY_EVENT_POSTAL_POP_RECEIVE_DONE

AlpNotifyEventPopReceive

ALP_NOTIFY_EVENT_POSTAL_SESSION

(mask)

ALP_NOTIFY_EVENT_POSTAL_SESSION_RECEIVING_PROGRESS

AlpNotifyEventSessionReceivingProgress

ALP_NOTIFY_EVENT_POSTAL_SESSION_STATUS_CHANGE

AlpNotifyEventSessionStatusChange

ALP_NOTIFY_EVENT_POSTAL_SMTP

(mask)

ALP_NOTIFY_EVENT_POSTAL_SMTP_VALIDATE

(mask)

ALP_NOTIFY_EVENT_POSTAL_SMTP_VALIDATE_BAD_AUTH_SMTP

AlpNotifyEventSMTPAccountValidate

ALP_NOTIFY_EVENT_POSTAL_SMTP_VALIDATE_NO_CONNECT_SMTP

AlpNotifyEventSMTPAccountValidate

ALP_NOTIFY_EVENT_POSTAL_SMTP_VALIDATE_NO_SERVER_SMTP

AlpNotifyEventSMTPAccountValidate

ALP_NOTIFY_EVENT_POSTAL_SMTP_VALIDATE_SUCCESS_SMTP

AlpNotifyEventSMTPAccountValidate

ALP_NOTIFY_EVENT_POWER_BATT_CHANGE

AlpPowerBattEventDetails

ALP_NOTIFY_EVENT_POWER_BATT_STATE_CHANGE

AlpPowerBattEventDetails

ALP_NOTIFY_EVENT_POWER_SLEEP

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_SLEEP_TO_SEMI_WAKE

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_SLEEP_TO_SLEEP

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_WAKE

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_WAKE_STATE_CHANGE

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_WAKE_TO_FULL_WAKE

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_POWER_WAKE_TO_SEMI_WAKE

AlpPowerWakeStateEventDetails

ALP_NOTIFY_EVENT_SYSTEM_CHANGE

None

ALP_NOTIFY_EVENT_SYSTEM_CHANGE_TIME

None

ALP_NOTIFY_EVENT_SYSTEM_CHANGE_ZONE

None

ALP_NOTIFY_EVENT_TEL

(mask)

ALP_NOTIFY_EVENT_TEL_CAT

ALP_NOTIFY_EVENT_TEL_CAT_LAUNCH_CMD_END_SESSION

ALP_NOTIFY_EVENT_TEL_CAT_LAUNCH_CMD_EXEC_CMD

ALP_NOTIFY_EVENT_TEL_CAT_ME_ANSWER

ALP_NOTIFY_EVENT_TEL_CAT_SIM_ANSWER

ALP_NOTIFY_EVENT_TEL_DTC

ALP_NOTIFY_EVENT_TEL_DTC_CLOSED

ALP_NOTIFY_EVENT_TEL_DTC_STARTED

ALP_NOTIFY_EVENT_TEL_NO_PHONE_PROFILE_AVAILABLE

None

ALP_NOTIFY_EVENT_TEL_NWK

ALP_NOTIFY_EVENT_TEL_NWK_GPRS_REGISTRATION

ALP_NOTIFY_EVENT_TEL_NWK_SIGNAL_LEVEL

ALP_NOTIFY_EVENT_TEL_NWK_STATUS

ALP_NOTIFY_EVENT_TEL_NWK_TIME

ALP_NOTIFY_EVENT_TEL_NWK_USSD_ANSWER

ALP_NOTIFY_EVENT_TEL_PHB

ALP_NOTIFY_EVENT_TEL_PHB_ACCESS

ALP_NOTIFY_EVENT_TEL_PHONE_PROFILE_AVAILABLE

A uint32_t containing the profile ID

ALP_NOTIFY_EVENT_TEL_POW

ALP_NOTIFY_EVENT_TEL_POW_BATTERY_CHARGE_LEVEL

ALP_NOTIFY_EVENT_TEL_POW_BATTERY_CONNECTION_STATUS

ALP_NOTIFY_EVENT_TEL_POW_CONNECTION

ALP_NOTIFY_EVENT_TEL_PS

ALP_NOTIFY_EVENT_TEL_PS_EVENT_REPORTING

ALP_NOTIFY_EVENT_TEL_SMS

ALP_NOTIFY_EVENT_TEL_SMS_ACCESS

ALP_NOTIFY_EVENT_TEL_SMS_INCOMING_MESSAGE

ALP_NOTIFY_EVENT_TEL_SPC

ALP_NOTIFY_EVENT_TEL_SPC_BUSY

ALP_NOTIFY_EVENT_TEL_SPC_CALL_CHANGE

ALP_NOTIFY_EVENT_TEL_SPC_CALLERID_AVAILABLE

ALP_NOTIFY_EVENT_TEL_SPC_NO_CARRIER

ALP_NOTIFY_EVENT_TEL_STY

ALP_NOTIFY_EVENT_TEL_STY_AUTHENTICATED

ALP_NOTIFY_EVENT_TEL_STY_AUTHENTICATION_CANCELED

ALP_NOTIFY_EVENT_TEL_TIME_ZONE_CHANGED

ALP_NOTIFY_EVENT_TEL_VOICE_MESSAGE_WAITING_FLAG

ALP_NOTIFY_EVENT_TIMEZONE_CHANGE_TZ

None

ALP_NOTIFY_EVENT_VOLUME_ADDED

The udi string from the AlpVolumeSvcsFSinfo struct

ALP_NOTIFY_EVENT_VOLUME_REMOVED

The udi string from the AlpVolumeSvcsFSinfo struct

ALP_POSTAL_NOTIFICATION_SESSION_RECEIVING_PROGRESS

AlpNotifyEventSessionReceivingProgress

ALP_POSTAL_NOTIFICATION_SESSION_SENDING_PROGRESS

AlpNotifyEventSessionSendingProgress

ALP_POSTAL_NOTIFICATION_SESSION_STATUS_CHANGE

AlpNotifyEventSessionStatusChange

1. This notification string has the alert type appended to it. Accordingly, you must use strncmp() when comparing a notification string against ALP_NOTIFY_EVENT_ATTN_ALERT.
2. This notification string has the key name appended to it.Accordingly, you must use strncmp() when comparing a notification string against ALP_NOTIFY_EVENT_GLOBAL_SETTINGS_KEY_CHANGE.

The Main Event Loop ^TOP^

When GTK+ application that has been minimally converted to an ACCESS Linux Platform application is run, it doesn't understand any of the platform-specific messages that would allow it to fully participate in the ACCESS Linux Platform environment. For example, when your application is running and you press the Home key to return to the Launcher, your application won't receive any information telling it to quit. Consequently, the Application Server will wait a small amount of time, then kill your application. If your application had cached data, your data would be lost.

There are several different messages your application can register to receive, depending on which services you choose to use. The most important message to handle is the "quit" message. To add and remove the handler(s) needed to receive the "quit" message, use alp_app_add_exit_handler().

Supporting the Clipboard ^TOP^

The Clipboard Utilities are a simple set of functions that greatly simplify the process of implementing Cut/Copy/Paste operations. Each function (there are three, one for each operation) simply determines which widget under the same top level as a specified widget has the focus, and emits the appropriate signal on it (cut_clipboard, copy_clipboard, or paste_clipboard, respectively). Note that the appropriate signal is emitted even if the top-level widget itself does not have focus, or if the focused widget is not a GtkEntry or GtkTextView.

These functions are most useful when implementing Cut, Copy, and Paste menu items for a window which contains multiple text widgets, possibly of differing types (for example, GtkEntry versus GtkTextView). Using these functions, the menu handling code does not need to know which text widget has focus, or what type of widget it is.

The code in Listing 6.6 shows all that most Glade applications need to do in order to add Cut/Copy/Paste functionality. This code assumes a single application window named "mainwindow", and assumes that you have previously declared and initialized a global variable named "gXML" with the results of alp_bundle_acquire_glade_xml(). Simply by adding this code to your application and then setting the "activate" signal of the cut, copy, and paste menu items to the name of the appropriate function in this sample code, the user will be able to cut and/or copy any of the window's selectable text, and paste the clipboard contents to any widget that recognizes the paste_clipboard signal, such as a GtkEntry widget.

Listing 6.6  Cut, copy, and paste functions


void on_cut_activate(GtkMenuItem *menuItem, gpointer userdata){ 
	GtkWidget *mainWindow = glade_xml_get_widget(gXML, "mainwindow"); 
 
	alp_clipboard_cut(mainWindow); 
} 
 
void on_copy_activate(GtkMenuItem *menuItem, gpointer userdata){ 
	GtkWidget *mainWindow = glade_xml_get_widget(gXML, "mainwindow"); 
 
	alp_clipboard_copy(mainWindow); 
} 
 
void on_paste_activate(GtkMenuItem *menuItem, gpointer userdata){ 
	GtkWidget *mainWindow = glade_xml_get_widget(gXML, "mainwindow"); 
 
	alp_clipboard_paste(mainWindow); 
} 

Handling Hardware Keys ^TOP^

During normal system operation, the X server and the Application Server receive all key events. The X server sends them to whichever window has the keyboard focus; they're handled as is normal in any X or GTK+ application.

In order to provide default behavior for certain keys (for instance, to implement dedicated PIM application buttons, or for the "off hook" button), ACCESS Linux Platform installs a "default key handler" in every application. Any key event which is not handled by the application is passed to this default key handler. This allows applications to override the default behavior of certain keys. For example, a game might repurpose PIM application buttons for some game-specific function.

The Application Server receives key events because some key behavior is too important to allow apps to override it. Currently, the Application Server only responds to the home key and to long-presses on the power key (which shuts down the device). Applications will also receive these key events, but usually ignore them. Because these events are sent to the Application Server independently, these keys exhibit reliable behavior even if the current application is locked up (in fact, this mechanism is what allows the Application Server to kill an application that is locked up).


1. The use of a relaunch handler is strongly recommended.

 

Add as favourites (204) | Quote this article on your site | Views: 1907

Be first to comment this article
RSS comments

Only registered users can write comments.
Please login or register.

Powered by AkoComment Tweaked Special Edition v.1.4.6
AkoComment © Copyright 2004 by Arthur Konze - www.mamboportal.com
All right reserved

 


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