TweetFollow Us on Twitter

Location Manager Pref Treatment

Volume Number: 13 (1997)
Issue Number: 9
Column Tag: develop

Preferential Treatment Under Apple Location Manager

by Erik Sea

Apple Location Manager (ALM) is a suite of system software enhancements that shipped in January, 1997, but unless you're a PowerBook user, you may not have seen ALM in action. Later this year, however, you'll see a completely new version that works on any Mac OS 8 computer, be it large or small, battery-powered or tethered to the electrical grid. With increased availability, it's become even more practical to add ALM-savviness to those services, tools, and applications that need it, and over the next few pages we'll discuss some ways to do just that.

At the heart of ALM is the idea that many Mac OS users repeatedly fiddle with various control panels and change preferences. They make these changes for a number of reasons: a mobile user who travels from place to place needs to adjust to those different environments, while a home user might have different settings for telecommuting versus playing games. With ALM, the chore of going through and repetitively changing a large number of settings is reduced to a single Control Strip menu choice, once the collection of settings has been given a name. With this named collection of settings and actions, known as a "location" in ALM, lengthy lists of reconfiguration steps (some users even have these taped to their monitors or stuck to their keyboards) should become a thing of the past -- provided the software they need to configure is ALM-savvy.

Should you make your software ALM-savvy? Well, if you have a product that has preferences that the user can change, directly or indirectly, the answer is yes! You might think that your software's preferences are simple -- maybe not much more than a simple "on-off" or two that the user can change with a click, but, in the larger context, the user might want to turn your preferences on or off at the same time as changing something else -- batch reconfiguration is a surprisingly common activity. Consider turning file sharing on or off: file sharing is only useful when there is a network around, and users might forget to turn it off at 37,000 feet, but if they've defined a location called "Air Travel" that turns it off for them (and perhaps turns off AppleTalk and dims the screen for better power conservation), they might just get a few precious minutes of additional battery life over just dimming the screen -- but will they remember to do it? With ALM, they only need to remember the details when they create their locations -- from then on, they need only use those locations.

You might also think that your users generally don't change their preferences, and it's true that many don't. However, you may want to consider whether they would if it were easier and could be done in concert with other changes to their environment. Some applications nest their preferences so deep in subpanels that the utility of making the change is offset by the cost of making it -- but what if it were easier? I'm sure you're starting to see what I'm getting at.

There are many ways for your software to interact with ALM, including some I probably haven't thought of. I'll present some in my allotted space, but please do get in, explore, and create things that just make sense -- the ideas are simple, but the uses are numerous!

Ways and Means

A developer once commented to me that ALM is one of the simplest, yet most complex pieces of system software to come along in a while. While you may shy from such paradoxical remarks, they correctly reflect the continuum of development options at your disposal -- ALM-savviness can take many forms, ranging from tight integration with your software to standalone ALM modules written by third parties for your products.

One of the first ALM modules written outside Apple was an ALM module for Apple's OT/PPP developed, as shareware, by Prime Computing Systems and available on the web at

ALM modules are generally self-contained preference-swappers that cooperate to varying degrees with the software that owns the preference in question. The tighter the integration, the better the user experience, but you can certainly start out with looser coupling and improve it as revisions to your product permit. ALM modules implement some or all of the ALM module API, and are placed in the Location Manager Modules folder, inside the Extensions folder. I'll discuss module development shortly.

There are other types of ALM modules, called action modules, that, rather than swapping preferences for a piece of software, perform an activity that may or may not be associated with a specific piece of code, but just automate the process of doing some sequence of steps during a location switch: opening a file, for example. For more on action modules, and the slight differences between their API and the API of standard modules (for example, one of the "optional" calls for a standard module becomes "required" for an action module), see the ALM SDK.

To find the latest ALM SDK, go to our web site at, or see the Mac OS SDK on CD. To take advantage of the newer features of ALM 2.0, be sure you're using the SDK's interfaces and libraries -- older versions of these components may have come with your development environment, and don't have all of the new features. See "Whatcha Got?" for information on testing for the availability of features.

The ALM engine -- that is, the part that provides the core services related to switching -- has a public API that developers can use to enumerate the user's locations, create new locations, or switch locations. We'll cover the ALM API later.

Finally, although ALM modules can provide a great deal of flexibility to a developer who wishes to become ALM-savvy, but there are cases where a piece of software might benefit from a deeper knowledge of what the engine is doing. There is the API, as mentioned earlier, but you should know that it can be used in clever ways that might be appropriate for some software that would benefit from even tighter integration with ALM. A hypothetical example of this kind of location-awareness, going beyond mere ALM-savviness, is discussed in the latter part of this article.


As with any system software from Apple, there are means for testing what features are present in ALM, since the features have changed from version 1.0 to 2.0.

This selector returns the version of the ALM engine that is installed on the machine.
This selector returns a bitfield representing engine functionality with the following bit meanings:
  • gestaltALMPresent is on if ALM is installed; it's possible, on some hardware, for the selector to be defined but for this bit to be off, so check!
  • gestaltALMHasSFLocations is on if the Get, Put, and Merge location calls are implemented.
  • gestaltALMHasCFMSupport is on if the engine recognizes CFM-based modules, otherwise only Component Manager modules are directly supported.
  • gestaltALMHasRescanNotifiers is on if notifications for changes in the names or number of locations will be sent via callbacks and Apple events; otherwise, only notifiers for switches are generated.

With so many options to choose from, it might take a while to figure out how your software and ALM might collaborate. So, as you dive into the rest of this article, keep in mind that there is often more than one path to ALM-nirvana, er, savviness, but the sooner you start, the sooner you'll arrive. Setting aside philosophical opinion, let's look at the path most traveled first.

Magnificent Modules

For most situations, the ALM module provides the easiest and best-encapsulated way to get your software plugged into the ALM engine. The calls that an ALM module supports are very general: a module (or any software it interoperates with) doesn't need to know anything about locations or how the ALM control panel works, just how to interact with the software it represents.

Just What Is A Module Anyway?

It is difficult for me to describe what an ALM module is or does without showing how the user interacts with them. To define a location, the user runs the ALM control panel, and picks "New Location" from the File menu. All location editing is done from the main window, seen in Figure 1. In the top part of the window, we see the current location (that is, the location a user switched to in the past or the location the user is "in" right now) specified by a pop-up. The user can switch from this pop-up or switch from a similar menu in the control strip.

Figure 1. Apple Location Manager main window, in expanded mode.

The disclosure triangle toggles display of the bottom half, where a second pop-up shows the name of the location to be edited. As you can see, it's possible to edit locations that are not the current location, which creates some special issues you might have to deal with. More on that later.

At the left side of the window, we see a list of modules that ALM knows about -- they are located in the Location Manager Modules folder. Each of these modules has a value associated with the edit location, and a description of that value is displayed at the right when the associated module is selected at the left.

Modules are ordinarily listed in alphabetical order, and the list order is the order that the engine applies changes when switching. The user can, using menu options, move modules around in the list to achieve different results (it's often handy, for example, to have modules that might require a restart, such as Extension Set, first, so that other modules, such as Auto-Open Items, could decide to defer execution until after the restart).

Modules could also be in the list several times if the user has chosen to duplicate them (another menu option). For example, a user might have several instances of Auto-Open Items sprinkled throughout a location definition, doing everything from mounting servers to executing AppleScript scripts.

The value for a module within a location is saved whether the module is on or off -- this allows the user to temporarily alter the location by excluding a module's setting without losing the settings established for it.

Only a few calls are necessary to support everything seen in the control panel.

If you're concerned about supporting ALM 1.0, rest assured that, despite the vast difference in appearance of the control panels, ALM 2.0 calls modules with the same expectations as its predecessor, but if you want to work under both versions, you'll have to take care not to use any 2.0 features. The bottom half of the new control panel corresponds to the separate Edit Location window in the old control panel, and the new "on-off" checkbox corresponds to "adding" a module to a location in 1.0. There's some information displayed in the old interface that isn't anywhere in the new one for simplicity and performance reasons.

What A Module Needs To Know To Do

Essentially, an ALM module only needs to know how to interpret the settings of the software it supports, how to change those settings, and how to get those changes recognized. We'll discuss nuances in a moment, but here are the calls a module absolutely must handle (for both ALM 1.0 or 2.0).

pascal OSErr GetCurrent (Handle setting);

When a module receives this request, it resizes the handle to whatever size is necessary to store the current setting. It is generally a good idea to "version" this information, in case you decide to change it later. In addition to the version you should also store in the handle enough information to restore the setting when ALM calls your module with the handle at a later time. This handle is stored on disk in a location file, so be sure you've "flattened" it out (that is, there are no pointers to things in memory that might not be in the same place when your module is next called).

pascal OSErr SetCurrent (Handle setting, ALMRebootFlags* flags);

Modules receive this call during a switch. The setting will be one which your module has previously returned from a GetCurrent call, though, obviously, it may have been stored some time ago. Be aware that, because ALM allows a user to switch location very early in the boot process, you need to check for things that may not be around yet (such as the Process Manager). If the environment is too hostile for your tastes, your module should return kALMDeferSwitchErr in response to this call, and ALM will try again later in the boot process.

The flags parameter is used to communicate to the engine what the impact of the setting change was, so that the user can be offered the opportunity to restart, if necessary. Possible responses include kALMNoChange if the settings did not actually need to be changed, kALMAvailableNow if they can be used immediately, or kALMExtensions if a restart is required (in which case the user will be given the option to reboot their machine) -- see the SDK for additional values and their meanings. Note that the input value of the flags parameter is the current escalation of the switch process, as set by previous modules. If the reboot level is already too high, you can set the flags to whatever value is appropriate for what you actually did, and return kALMRebootFlagsLevelErr as the function result.

The input value of flags in ALM 1.0 is always kALMNoChange, and there is no way to determine what the reboot escalation level is when you are called. You shouldn't return kALMRebootFlagsLevelErr if the input escalation level is kALMNoChange unless you know you're under 2.0.

You should avoid forcing the user to reboot when they switch your settings -- your customers will thank you for saving them time and trouble. Possible strategies include defining an Apple event or other signal that your software will recognize as "read your preferences now", then send that signal from your module's SetCurrent function.

pascal OSErr CompareSetting (Handle setting1, Handle setting2,
                                      Boolean* equal);

This call is made to determine whether two settings represent the same values from the point of view of the module. This is used at different times and in different ways, and has a special interaction with the optional EditSetting call, discussed later.

You'll find that this call is made less often under ALM 2.0 than it was under the older version, because of UI changes, but ALM 2.0 still requires it.

pascal OSErr DescribeSetting (Handle setting, CharsHandle text);

Generate a textual description for one of your settings, resizing the CharsHandle as appropriate to fit the text. Don't go overboard in your description -- the window containing the description is resizeable, but try to fit your description in the minimum window size for best results. The script system used will be that returned by the GetScriptInfo call, described shortly.

pascal OSErr DescribeError (OSErr lastErr, Str255 errStr);

You are encouraged to return your own (positive) error response values from a module API call, and you'll get first crack at telling the user what they mean. If you don't wish to describe an error, return paramErr in response to this function, and the control panel will present it to the user as a number (boo, hiss).

pascal OSErr GetScriptInfo (ALMScriptManagerInfoPtr info);

This call, though technically optional, is pretty easy to implement, and is recommended if you expect your module to be used worldwide. The format of info is as follows:

typedef struct {
        SInt16      version;
        SInt16      scriptCode;
        SInt16      regionCode;
        SInt16      langCode;
        SInt16      fontNum;
        SInt16      fontSize;
} ALMScriptManagerInfo;

You should set the version to kALMScriptInfoVersion, and fill in the font and script manager information in accordance with how you wish your text to be displayed. If you don't do this, you might not play well in other languages, because the system will fill out the script information on your behalf, and your module might end up getting displayed in the wrong script -- certain characters do not translate well, to say the least. It is actually possible for modules to be of different script systems yet be displayed correctly. If you plan to localize your text, you'll probably want to put script information in a resource that gets localized at the same time. See the sample code in the SDK for a good strategy to do exactly that.

pascal OSErr GetInfo (CharsHandle* text, STHandle* style, 
                 ModalFilterUPP filter);

The GetInfo call is made to tell the user what your module is all about, such as what other software it interacts with. There are essentially two flavors to this call: in the first, you simply return styled text using the first two parameters, and it gets displayed, as shown in Figure 2. The text can be any length, but don't write a book -- say what your module does, what software it works with, and where to go for more information.

In the second flavor of GetInfo, the module itself takes care of displaying whatever dialog it chooses, or perhaps opens an AppleGuide window, and returns NULL in the first two parameters to signal that it did the job on its own.

Figure 2. Control Panel Displays Results of GetInfo Call.


At first glance, it may seem that ALM modules and AppleScript are two technologies vying for the same role, for if every preference-generating piece of software were scriptable, an intelligent user could just have a collection of scripts to effect a location switch.

If you look deeper, though, you'll see that these technologies are complementary: a totally scriptable control panel, for example, even if it were recordable, would benefit from the centralized, simplified process of location definition and aggregation with other settings. At the same time, it is much easier to support ALM in a control panel that has already been made scriptable because the requisite code factoring makes ALM support a breeze.

Still, you do not need to be scriptable to support ALM, and, though I would prefer that you did make your software scriptable, you don't need to do it for ALM.

The filter parameter to the GetInfo call is a legacy parameter, used only in ALM 1.0. ALM 2.0 does not require you to call filter explicitly, but you may do so.

Those are the basics; the SDK provides a good sample implementation you can start from, in the form of the "Generic" module, which is particularly handy for prototyping.

In fact the Generic module could theoretically be used with only a few changes in resources, and, for some limited-use applications, or for prototyping, that might be enough, but it's probably not up to the quality required for commercial or even shareware release.

Though these calls are enough for ALM to work correctly and predictably, there has yet to be an API devised whereby you can become "savvy" by supporting just the lowest level, so let's go up a step.


Over the last little while, people have begun to recognize the value of storing named configurations, or sets of preferences, for easier retrieval by users. This is a good thing, and is a move in the direction of ALM. An ALM module that deals with a piece of software that already supports named configurations probably just needs to track the name, and that makes life much easier, because you basically are dealing with just a reference to other data, rather than the other data directly.

There are, however, complications, such as the need to define dual formats for your settings: normal (in which case a reference to other data on the current machine is adequate) and import-export (in which case you need to recreate the entire setting for use on another machine).

Another question is what happens if the user changes the named configuration -- will your module know how to track the change and update its reference?

And how will your module help Bob import "My Reactor Settings" from Anne's computer, without wiping out his existing (and potentially different) "My Reactor Settings"? Maybe he really wants to replace them, but maybe he wants to rename the import as "Anne's Reactor Settings".

You'll have to solve the reference-tracking problem for yourself, but ALM does provide a call to handle import name collisions, called ALMConfirmName, discussed in the API section.

Of course, if your setting is very simple, such as on or off, both formats of your setting can be the same, and your implementation of ImportExport becomes very simple -- just return noErr.

What A Module Should Know To Do

With some additional work, you can provide the user with additional ALM-supported functionality and achieve ALM-savviness. The capabilities you'll need to tackle are editing of inactive settings, and import-export. If you don't implement these functions to at least some extent, not only will you fail to enter the blissful state of ALM-savviness, but your customers may become confused and you'll have a recurring dream in which you read Inside Macintosh: AOCE Application Interfaces word for word, from cover to cover, until your conscience makes you support these added functions.

This setting must change - As mentioned earlier, it's possible for a user to edit the settings from one location while being in another. Through use of the "Apply" button (refer to Figure 1), the user can change a setting in a location by capturing the current value of the setting on the computer. This is done through the GetSetting call described previously. In user studies, we found that it's highly desirable for the user to be able to change settings in an inactive location without changing the live system settings (we do provide a way to reassert the current location's values). Unto this desire, the EditSetting call was born.

pascal OSErr EditSetting (Handle setting);

The EditSetting call is optional, but very strongly recommended. The input setting parameter is one that will have come from an earlier call to GetCurrent. Do whatever you need to do to edit the setting, and return either the same one (if the user cancels the edit) or a different one (if the user accepts the edit). When I say different, I mean different enough that your CompareSetting call will say, "Yes, they're different" -- if there was no real change, your module might just flip a bit in the setting handle that it would ignore everywhere but on a CompareSetting call. The reason for requiring these settings to seem different even if they aren't is a subtle bit of UI trickery in the ALM control panel: the control panel will automatically turn a setting on if, as a result of an EditSetting call, it can be ascertained that the settings were accepted by the user. The control panel makes the determination of acceptance based on the input and output setting handles being different.

Implementing the EditSetting call can be done in a number of ways. Ideally, an EditSetting call would bring up the same interface you use in your software to edit your live preferences, but without affecting those live preferences -- a sort of "preference UI factoring", if you will. Alternatively (but less desirably), you can take some sort of middle road, ranging from explaining to the user where they should go to edit their live system settings (and reminding them to put those settings back the way they were), to providing a little "platform" from which to launch your software, perhaps under AppleScript control.

The EditSetting call was supported under ALM 1.0, and, in fact, it's required for action modules. There is, alas, no support for EditSetting of standard modules in the old control panel, so be aware of that limitation if you plan to support both versions of ALM.

If you don't implement EditSetting, the ALM control panel has no way of knowing where your setting comes from, so it displays the message shown in Figure 3 when the user tries to edit your setting.

Figure 3. Developer Raspberry: Module does not support EditSetting.

I can't encourage you strongly enough to implement EditSetting to some extent in your initial release, and then refine it over time (if you don't go all the way up front). I've seen hours of videotaped user experiences, and the EditSetting capability more closely reflects how users expect the machine to behave, so don't let them see this brick wall of an alert when they use your module.

Duties Paid: Importing and Exporting

It would be really nifty for a user if, once they've honed a location to near perfection, they could share it with others. It would also be nice if, walking into a new environment, a user could receive a group of settings that other people in that environment use. That, in a nutshell, is what the ImportExport capability is all about.

pascal OSErr ImportExport (Boolean import, Handle setting,
                      SInt16 resRefNum);

The settings dealt with by most of the API can be small -- they may just be references to other data structures (I would encourage this design decision, though it introduces some new issues as discussed in "Dualing Settings"), and that will work fine on one user's computer. If you were to export just the name, however, the importing machine might not be able to interpret it correctly.

So, when you export, you might want to augment the setting handle with additional information that would allow you to replicate the setting on another machine (short of actually installing software on that machine!), and, on import, you can decode that information and shrink the handle back down to size. If that technique isn't enough, or you'd rather keep your setting the same, you can add resources to the exported location file, and read them in on import (after you read your resources in, you should delete them, since you're actually working on a copy of the import file, in the Locations folder, rather than the actual import file). You should use a unique resource type, such as your creator, for the resources you use.

If you don't implement ImportExport, be sure to document this in your GetInfo window information.

Now that you know how modules work and how ALM calls them, let's go to the other side of the fence and see how to call ALM.

Start Your Engines!

The ALM API contains a series of calls for the developer to find out about a user's locations, a call to initiate switches, calls to create or let the user merge a setting into a location, plus events and notifications to determine when a switch has occurred or a location has been created. As mentioned previously, there is also a call to handle import collisions in a uniform way.


The ALM API is accessible in C, Pascal, or Assembly, from PowerPC or 68K, in classic or CFM-68K runtime models.

Since CFM-68K calling isn't available under ALM 1.0 I recommend weak-linking with the CFM-68K stub library and then testing against API symbols at launch.

What place is this?

If you want, you can take a gander at what the user has set up. Perhaps you want to build your own pop-up menu to provide the user the ability to switch locations from within your application, rather than the control strip or control panel. Here are the calls, and a very simple program to use them can be found in Listing 1.

Listing 1 Printing the User's Defined Locations

ALMToken                curLocToken, locToken;
ALMLocationName         curLocName, locName;
SInt16                  numLocs, locIndex;

printf ("User Locations on this Machine:\n");
err = ALMCountLocations (&numLocs);
printf ("There are %d locations in total\n", numLocs);
err = ALMGetCurrentLocation (NULL, &curLocToken,                 curLocName);
printf ("The active location is %s\n", 
            p2cstr (curLocName));
for (locIndex = 0; locIndex < numLocs; locIndex += 1) {
  err = ALMGetIndLocation (locIndex, &locToken,                 locName);
  if (locToken != curLocToken) // special treatment!
    printf ("Location %d is %s\n", locIndex, 
            p2cstr (locName));
    printf ("Location %d is the current location\n",               locIndex);
} // for
pascal OSErr ALMGetCurrentLocation (SInt16* index, 
                        ALMToken* token,
                        ALMLocationName name);
pascal OSErr ALMCountLocations (SInt16* locationCount);
pascal OSErr ALMGetIndLocation (SInt16 index, 
                        ALMToken* token,
                        ALMLocationName name);

The indices in these calls are zero-based, so the maximum will be one less than the locationCount. The special index value kALMNoLocationIndex denotes the situation where the user has chosen the special location "None (Off)". ALMTokens represent references to locations for use in other calls (and the special value kALMNoLocationToken corresponds to kALMNoLocationIndex). If you only want certain parameters to be returned, it's legal to pass NULL for any pointer.

Snapshots -- as Pretty as a Picture

In ALM 2.0, there are functions that you can use to interact with the user much like the control panel does. You should gestalt these functions (see "Whatcha Got?") before using them. The user experience is very much like the Standard File package, only simpler, but the calls themselves take care of a lot of additional work for you.

Sometimes, you'll want the user to simply choose a location from a list without need for iterating across all installed locations and building your own UI. To ask the user for a location, use the ALMGetLocation call, which presents a dialog as shown in Figure 4.

Figure 4. Asking the user for a location with ALMGetLocation.

pascal OSErr ALMGetLocation (ConstStr255Param prompt, 
                    Str31 locationName,
                    ModalFilterYDUPP filter, 
                    void* yourDataPtr);

The prompt is displayed above the list of locations, as in Standard File. The locationName is both an input and an output parameter -- if the name matches a location, that location will be selected in the list. The filter and data pointer are for your own use, again as in Standard File. If the user clicks cancel, the function result is userCanceledErr; otherwise, it should be noErr.

The next two calls, ALMPutLocation and ALMMergeLocation are intended to allow an application, such as a setup program, to capture the current system settings for a number of modules as a location, or merge them into an existing location. Detailed information on module signatures, or types, is beyond the scope of this article (see the SDK), but the use of some special values for these parameters is shown in Listing 2.

pascal OSErr ALMPutLocation (ConstStr255Param prompt, 
              Str31 locationName,
              SInt16 numTypes, 
              ConstALMModuleTypeListPtr typeList
              ModalFilterYDUPP filter, void* yourDataPtr);
pascal OSErr ALMMergeLocation (ConstStr255Param prompt,
              Str31 locationName,
              SInt16 numTypes,
              ConstALMModuleTypeListPtr typeList,
              ModalFilterYPUPP filter, void* yourDataPtr)

Listing 2. Put Up or Merge Up

// create a new, empty location
err = ALMPutLocation ("\pName your place", 
          "\pEmpty Location", kALMAddAllOff, 
          NULL, NULL, NULL);

// add to a location as a snapshot, using all currently-installed
// non-action modules, replacing current definitions
err = ALMMergeLocation ("\pRedefine your place",
          "\pSnapshot Location", 
          kALMAddAllOnSimple, NULL, NULL, NULL);


There would be very little use to ALM without the switch engine. This is the call that the control strip and control panel use to effect a change in location:

pascal OSErr ALMSwitchToLocation (ALMToken newLocation,
                        ALMSwitchActionFlags switchFlags);

Most of the time, you can pass kALMDefaultSwitchFlags for the second parameter. For a quiet switch (that is, one in which the switching dialog does not come up), pass the mask kALMDontShowStatusWindow. If you're making this call from an unusual place such as inside a dialog filter or some other weird place, use the mask kALMSignalViaAE so that the switch will be deferred until the ALM control panel (or the Finder, if the control panel isn't open) is in a better synchronized state.

If you wish to switch locations from a background application you should use either kALMDontShowStatusWindow or kALMSignalViaAE or both. If you do not, ALM 2.0 will return an error. ALM 1.0 is less forgiving, and will crash if the host application hasn't initiallized the window manager. Moral: don't use default flags except in direct response to a user action in your foreground application!

Noticing Switches and Other Goings On

One of the more interesting things about ALM is that it actually tells all running processes when the user has changed locations. Under ALM 2.0, it'll also advise when the user has created, renamed, or deleted a location, so that applications that want to know can rebuild any list of locations they might have internally, or reorganize any data they might have been shadowing on a location-by-location basis by rescanning the user's installed locations using a technique like that of Listing 1.

You should check gestalt for the availability of the rescan notifiers if you're going to rely on them, as described in "Whatcha Got?". If they are not available, you can employ alternate strategies, such as periodically iterating through the installed locations. In any case, it's good practice to recheck the installed locations at start-up if you save your own list somewhere.

Listing 3. Observing Switches and Handling

Rescan Notifiers
pascal OSErr MySystemConfigNoticeHandler 
              (const AppleEvent* inEvent, 
              AppleEvent* reply, SInt32 refCon)

  OSErr        err  = errAEDescNotFound;
  ALMToken      locToken;
  DescType      actualType;
  Size          actualSize;

  // Handle any other cases you like...
  // Did we get a switch notification?
  if (err != noErr) {
    err = AEGetKeyPtr (inEvent, 
            typeInteger, &actualType,
            &locToken, sizeof (locToken),
    if (err == noErr) MyDoReactToSwitch (locToken);
  } // if
  // Did we get a rescan notification?
  if (err != noErr) {
    err = AEGetKeyPtr (inEvent, 
            typeInteger, &actualType,
            &locToken, sizeof (locToken),
    if (err == noErr) MyDoReactToRescanNotice (locToken);
  } // if

  return err;

} // SystemConfigNoticeHandler

The class of the Apple event is kAECoreSuite, and the event ID is kAESystemConfigNotice, just as with the display manager's notifications that the screen size or resolution has changed. If your event handler receives such an event, and there is a parameter keyed under kAELocationChangedNoticeKey, then a switch has occurred, and that parameter's value is the ALMToken of the location to which the user switched. If there is a parameter under kAELocationRescanNoticeKey, then the user has made changes to the installed locations, and you can't rely on any of your previously stored data about locations being valid. The value of the parameter is the ALMToken of the current location. For a skeletal handler, see Listing 3.

Event Me Not

Of course, if you're a code resource, you won't be getting many Apple events, so you can provide a function such as this as an alternative:

pascal void MyALMNotificationRoutine (AppleEvent* theEvent);

Your implementation of this routine ought to be similar to the Apple event handler in Listing 3. Create a UPP by passing your routine to NewALMNotificationProc, and then register and deregister your routine using these calls:

pascal OSErr ALMRegisterNotifyProc 
                (ALMNotificationUPP notifyProc,
                const ProcessSerialNumber* whichPSN);
pascal OSErr ALMRemoveNotifyProc 
                (ALMNotificationUPP notifyProc,
                const ProcessSerialNumber* whichPSN);

The ProcessSerialNumber parameter is used by ALM to ensure that notifications aren't sent to code whose process no longer exists (but for which the notifier was not removed). You should pass the serial number you're associated with.

Import Collisions

Particularly if you implement named configurations, as discussed in "Dualing Settings", you could have situations, when importing, where a setting you're importing conflicts with a setting already on the machine. To address this problem, ALM provides a routine that displays two dialogs in succession. The first asks the user to choose either to rename or to replace the named configuration, and the second, shown in case of a rename, presents a box in which to rename the configuration. The call is as follows:

pascal OSErr ALMConfirmName (ConstStr255Param msg, 
                Str255 configName,
                ALMConfirmChoice* choice, 
                ModalFilterUPP filter);

If the user cancels the operation, the function returns userCanceledErr; otherwise, the value of choice is kALMConfirmRename or kALMConfirmReplace, depending on the user's choice. You may provide a filter function, if you wish access to events in the dialog. The refcons of the dialog boxes disclose which is which, and the individual element numbers are provided as constants in the ALM 2.0 interfaces, should you wish to do things like constrain the allowed characters in your configuration name (rather than validating the name after the call returns). For details on the refcons and item numbers, see the SDK.

Due to a bug in ALM 1.0 the filter function was not called in both dialogs, but just the rename dialog. If your filter function sees a refcon of zero, you can assume you are in the 1.0 rename dialog box.

AppleScript Support

Alternatively, you can access much of the API by sending AppleScript commands to the control panel. A simple switch through AppleScript is shown in Listing 4. You can, of course, also list locations from AppleScript using the Standard Suite.

Listing 4. Driving a Switch from AppleScript

set someLocationName to "Home Office"
tell application "Finder"
  set cpFolder to (control panels folder as string)
  open file (cpFolder & "Location Manager")
  tell application "Location Manager"
    set current location to location someLocationName 
  end tell
end tell

Though this API is small, these same bricks will build a house or a castle, depending on how you choose to use them. Although the water may look deep, location-awareness could represent the ultimate offering to the user, giving them much more than ALM modules, alone, are capable of.

Where Am I?

Thus far, we've talked about ALM-savviness and driving the engine, but now let's switch gears a little and talk about the greater generalities of location-awareness.

How a piece of software becomes location-aware is as unique as the piece of software itself -- it requires planning and thought beyond how to simply automate the chore of switching preferences. Instead, a location-aware piece of software has new functionality that its location-oblivious sibling does not.

As an example, let's take the Apple Menu Items control panel, which has been an indispensable part of Mac OS from System 7.5 to the present. What form could location-awareness take in this control panel (see Figure 5)? Suppose that, in each location (whether a "location" is a physical location or merely a state in which they perform different tasks), the user accesses different documents, applications, and servers that are specific to that location, but, in moving from one location to the next, they constantly wipe out recent items from one place before they get back to it. Typically, users faced with this problem combat it by increasing the recent item allocation numbers, but while searching through a big list works, it's far from ideal.

Figure 5. Mock-Up: Apple Menu Items with Location-Awareness.

We could just write a module for this that, through clever folder manipulation, swapped the recent items around, but what about the occasion when the user actually wants to access a recent item from another location without switching to that location first? Perhaps the submenus could present recent items in different ways -- the ordinary way most of the time -- or sorted by location if the user holds down the option key when choosing the Apple menu.

I am not suggesting that the hypothetical example I present above is the best possible answer, but I am hoping that software developers will consider using location-awareness as a new way to solve problems that their users might be facing.

Give location-awareness some thought -- it might be your best bet.

There's No Location Like Home

Now that you've been through savviness and awareness, modules and APIs, I hope you can see the opportunities ALM presents for you to make life easier for your users, both mobile and landlubber.

So take a few moments to install and play with ALM, and then play with the sample code. I think you'll be surprised at how much mileage you can get out of a very small amount of labor!

Thanks to my reviewers Mark Cookson, Dave Ferguson, Scott Johnson, Susan Michalak, Kent Miller, and Eric Slosser. Special thanks to everyone on the ALM team, present and past, for your contributions to shaping and sculpting a truly unique and innovative piece of software.

Related Reading

  • The ALM web page, located at
  • ALM SDK, available through the web site or on Mac OS SDK.

Erik Sea ( Erik arrived at Apple about a year ago, with the sole objective of inundating the PowerBook Division with slinkys -- so far, they remain confined to his office, except on weekends when they explore the building and feed on weak or infirm paper clips. When not tweaking Location Manager code or the ALM web site, he can be found volunteering his time to rearrange sets of encyclopedias so that the volumes run from right to left on the shelf (because that's the way the pages are aligned), or writing games in COBOL on his Apple ///+.


Community Search:
MacTech Search:

Software Updates via MacUpdate

GraphicConverter 11.2.2 - $39.95
GraphicConverter is an all-purpose image-editing program that can import 200 different graphic-based formats, edit the image, and export it to any of 80 available file formats. The high-end editing... Read more
VueScan 9.7.30 - Scanner software with a...
VueScan is a scanning program that works with most high-quality flatbed and film scanners to produce scans that have excellent color fidelity and color balance. VueScan is easy to use, and has... Read more
Things 3.12.6 - Elegant personal task ma...
Things is a task management solution that helps to organize your tasks in an elegant and intuitive way. Things combines powerful features with simplicity through the use of tags and its intelligent... Read more
Skim 1.5.11 - PDF reader and note-taker...
Skim is a PDF reader and note-taker for OS X. It is designed to help you read and annotate scientific papers in PDF, but is also great for viewing any PDF file. Skim includes many features and has a... Read more
Navicat Premium Essentials 15.0.20 - Pro...
Navicat Premium Essentials is a compact version of Navicat which provides basic and necessary features you will need to perform simple administration on a database. It supports the latest features... Read more
Affinity Photo 1.8.4 - Digital editing f...
Affinity Photo - redefines the boundaries for professional photo editing software for the Mac. With a meticulous focus on workflow it offers sophisticated tools for enhancing, editing and retouching... Read more
EtreCheck Pro 6.3 - For troubleshooting...
EtreCheck is an app that displays the important details of your system configuration and allow you to copy that information to the Clipboard. It is meant to be used with Apple Support Communities to... Read more
beaTunes 5.2.11 - Organize your music co...
beaTunes is a full-featured music player and organizational tool for music collections. How well organized is your music library? Are your artists always spelled the same way? Any R.E.M. vs REM?... Read more
Bookends 13.4.4 - Reference management a...
Bookends is a full-featured bibliography/reference and information-management system for students and professionals. Bookends uses the cloud to sync reference libraries on all the Macs you use.... Read more
Affinity Designer 1.8.4 - Vector graphic...
Affinity Designer is an incredibly accurate vector illustrator that feels fast and at home in the hands of creative professionals. It intuitively combines rock solid and crisp vector art with... Read more

Latest Forum Discussions

See All

Global Spy is an intriguing 2D spy sim f...
Developer Yuyosoft Innovations' Global Spy launched last month for iOS and Android, though if you missed it at the time, we're here to tell you why it's well worth a go. This one's all about international espionage, tracking down elusive spies,... | Read more »
Distract Yourself With These Great Mobil...
There’s a lot going on right now, and I don’t really feel like trying to write some kind of pithy intro for it. All I’ll say is lots of people have been coming together and helping each other in small ways, and I’m choosing to focus on that as I... | Read more »
Hyena Squad is sci-fi turn-based strateg...
Wave Light Games has just revealed its latest release, Hyena Squad, a turn-based RPG set in a space station infested by gross aliens and the living dead. The announcement was first reported on by Touch Arcade. [Read more] | Read more »
Idle Guardians: Never Die is a pixel art...
SuperPlanet has been fairly prolific with game releases so far this year with both Evil Hunter Tycoon and Lucid Adventure releasing earlier this year. Now, they've released another idle RPG called Idle Guardians: Never Die, which you can download... | Read more »
Ruinverse, Kemco's latest RPG, now...
Kemco's latest RPG endeavour, Ruinverse, initially launched for both iOS and Android earlier this month. It was released as a premium title that also had additional in-app purchases. Now, the developers have decided to release a freemium version... | Read more »
The 5 Best Mobile Platformers
Touch screens and action-oriented gameplay don't typically mix, but over the course of pondering the best platformers on mobile, I found myself having a really hard time picking just five. Quite a few developers have found really creative ways to... | Read more »
Clash Royale: The Road to Legendary Aren...
Supercell recently celebrated its 10th anniversary and their best title, Clash Royale, is as good as it's ever been. Even for lapsed players, returning to the game is as easy as can be. If you want to join us in picking the game back up, we've put... | Read more »
Endless runner Monster Dash will relaunc...
Remember Monster Dash? Well, it's set to return to a mobile device near you after having been pulled from stores in 2017 to meet GDPR compliance. This one first launched all the way back in August of 2010. Over ten years later, it's heading into... | Read more »
Auto Battle Chess is a colourful genre s...
Auto Battle Chess is an interesting hodgepodge of genres that aims to offer the ultimate auto chess experience. That's a pretty tall order, though with the game now out for Android, I suppose we don't have to wait to see if it lives up to its... | Read more »
Tom and Jerry: Chase hits 1 million pre-...
NetEase's 1v4 asymmetrical multiplayer game Tom and Jerry: Chase recently became available to pre-order for both iOS and Android in Southeast Asia. It's clearly proving to be a highly anticipated title too since it has now reached 1 million pre-... | Read more »

Price Scanner via

Expercom offers $320 discount on the 6-core 1...
Apple reseller Expercom has the Silver 16″ 6-core MacBook Pro on sale for a limited time for $2079 shipped. Their price is $320 off Apple’s MSRP for this model, and it’s the cheapest price currently... Read more
Apple announces Education pricing for new 202...
Purchase a new 2020 iMac or iMac Pro at Apple using Apple’s Education discount, and take up to $400 off MSRP. All teachers, students, and staff of any educational institution with a .edu email... Read more
Apple reseller Expercom offers $256 discount...
Expercom has Apple’s new 2020 10-core iMac Pro available for order and on sale for $4743 shipped. Their price is $256 off Apple’s MSRP for this new model, and it’s the cheapest price we’ve seen so... Read more
Apple releases refreshed 2020 27″ iMacs with...
Apple today released updated versions of their 27″ iMacs featuring 10th generation Intel processors, SSDs across the board, a better 5K display, and improvements to the camera, speakers, and mic.... Read more
Xfinity Mobile promo: Take $200-$350 off Appl...
New customers can take $200 off the purchase of any new Apple iPhone model at Xfinity Mobile through 8/17/20. Service plan required. Existing customers can purchase an iPhone and receive $200 back in... Read more
B&H now offering $100-$200 discount on Ap...
B&H Photo has new 2020 13″ 2.0GHz MacBook Pros on sale for $100-$200 off Apple’s MSRP, starting at $1649. These are the same MacBook Pros sold by Apple in their retail and online stores, and B... Read more
Apple’s 6-Core Mac mini is on sale at Amazon...
Amazon has Apple’s new 2020 6-Core Mac mini on sale for $926.25 for a limited time. Their price is $173 off Apple’s $1099 MSRP for this model and includes a $48.75 instant discount available on their... Read more
New 2020 11″ iPad Pros on sale for $50-$75 of...
Apple reseller Expercom has new 2020 11″ Apple iPad Pros on sale for $50-$75 off MSRP, with prices starting at $749. These are the same iPad Pros sold by Apple in their retail and online stores: – 11... Read more
Switch to US Cellular and get a new Apple iPh...
US Cellular has Apple’s 2020 iPhone SE on sale for $350 off for new lines of service and a US Cellular unlimited plan. Promotion comes via monthly bill credits over a 30 month period. Their deal... Read more
Apple AirPods with Wireless Charging Case on...
Amazon has Apple’s AirPods with Wireless Charging Case on sale today for only $139.98 shipped. That’s $60 off Apple’s MSRP and the lowest price we’ve ever seen for these AirPods. Sale valid for a... Read more

Jobs Board

Director, Product Management - Lead *Apple*...
…better business results. **Job Title** Director, Product Management - Lead Apple / Token Requestor Services Overview The Mastercard Digital Enablement Services Read more
*Apple* Computing Professional - Store 286 (...
**770445BR** **Job Title:** Apple Computing Professional - Store 286 (Canton) **Job Category:** Store Associates **Store Number or Department:** 000286-Canton-Store Read more
Department Manager- Tech Shop/ *Apple* Stor...
…their parents want, and our faculty needs. As a Department Manager in our Tech Shop/ Apple Store you will spend the majority of your time on the sales floor engaging Read more
*Apple* Graders/Inspectors (Seasonal/Hourly/...
Title: Apple Graders/Inspectors (Seasonal/Hourly/No Benefits) # APPLE Location: US-VA-Winchester Read more
Tier 2 Technical Support Analyst - ( *Apple*...
…Analystiless than/strong>who will analyze and determine user software needs on all Apple devices (first support contact), Windows devices, and support printers in Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.