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

Viber 11.9.1 - Send messages and make fr...
Viber lets you send free messages and make free calls to other Viber users, on any device and network, in any country! Viber syncs your contacts, messages and call history with your mobile device, so... Read more
Vallum 3.3.2 - $15.00
Vallum is a little tool that helps you monitor and block apps connections and throttle apps bandwidth. It is able to intercept connections at the application layer, and hold them while you decide... Read more
Microsoft OneNote 16.31 - Free digital n...
OneNote is your very own digital notebook. With OneNote, you can capture that flash of genius, that moment of inspiration, or that list of errands that's too important to forget. Whether you're at... Read more
Apple Pages 8.2.1 - Apple's word pr...
Apple Pages is a powerful word processor that gives you everything you need to create documents that look beautiful. And read beautifully. It lets you work seamlessly between Mac and iOS devices, and... Read more
Numbers 6.2.1 - Apple's spreadsheet...
With Apple Numbers, sophisticated spreadsheets are just the start. The whole sheet is your canvas. Just add dramatic interactive charts, tables, and images that paint a revealing picture of your data... Read more
f.lux 39.9873 - Adjusts the color of you...
f.lux makes the color of your computer's display adapt to the time of day, warm at night and like sunlight during the day. Ever notice how people texting at night have that eerie blue glow? Or wake... Read more
Deeper 2.5.0 - Enable hidden features in...
Deeper is a personalization utility for macOS which allows you to enable and disable the hidden functions of the Finder, Dock, QuickTime, Safari, iTunes, login window, Spotlight, and many of Apple's... Read more
NTFS 15.5.71 - Provides full read and wr...
NTFS breaks down the barriers between Windows and macOS. Paragon NTFS effectively solves the communication problems between the Mac system and NTFS. Write, edit, copy, move, delete files on NTFS... Read more
MTR - The Mac's oldest and...
MTR (was MacTheRipper)--the Mac's oldest and smartest DVD-backup app. MTR - the complete toolbox, not a one-trick, point-and-click extractor. MTR is intended for making fair-use, backup copies of... Read more
Keynote 9.2.1 - Apple's presentatio...
Easily create gorgeous presentations with the all-new Keynote, featuring powerful yet easy-to-use tools and dazzling effects that will make you a very hard act to follow. The Theme Chooser lets you... Read more

Latest Forum Discussions

See All

Black Desert Mobile gets an official rel...
Pearl Abyss has just announced that its highly-anticipated MMO, Black Desert Mobile, will launch globally for iOS and Android on December 11th. [Read more] | Read more »
Another Eden receives new a episode, cha...
Another Eden, WFS' popular RPG, has received another update that brings new story content to the game alongside a few new heroes to discover. [Read more] | Read more »
Overdox guide - Tips and tricks for begi...
Overdox is a clever battle royale that changes things up by adding MOBA mechanics and melee combat to the mix. This new hybrid game can be quite a bit to take in at first, so we’ve put together a list of tips to help you get a leg up on the... | Read more »
Roterra Extreme - Great Escape is a pers...
Roterra Extreme – Great Escape has been described by developers Dig-It Games as a mini-sequel to their acclaimed title Roterra: Flip the Fairytale. It continues that game's tradition of messing with which way is up, tasking you with solving... | Read more »
Hearthstone: Battlegrounds open beta lau...
Remember earlier this year when auto battlers were the latest hotness? We had Auto Chess, DOTA Underlords, Chess Rush, and more all gunning for our attention. They all had their own reasons to play, but, at least from where I'm standing, most... | Read more »
The House of Da Vinci 2 gets a new gamep...
The House of Da Vinci launched all the way back in 2017. Now, developer Blue Brain Games is gearing up to deliver a second dose of The Room-inspired puzzling. Some fresh details have now emerged, alongside the game's first official trailer. [Read... | Read more »
Shoot 'em up action awaits in Battl...
BattleBrew Productions has just introduced another entry into its award winning, barrelpunk inspired, BattleSky Brigade series. Whilst its previous title BattleSky Brigade TapTap provided fans with idle town building gameplay, this time the... | Read more »
Arcade classic R-Type Dimensions EX blas...
If you're a long time fan of shmups and have been looking for something to play lately, Tozai Games may have just released an ideal game for you on iOS. R-Type Dimensions EX brings the first R-Type and its sequel to iOS devices. [Read more] | Read more »
Intense VR first-person shooter Colonicl...
Our latest VR obsession is Colonicle, an intense VR FPS, recently released on Oculus and Google Play, courtesy of From Fake Eyes and Goboogie Games. It's a pulse-pounding multiplayer shooter which should appeal to genre fanatics and newcomers alike... | Read more »
PUBG Mobile's incoming update bring...
PUGB Mobile's newest Royale Pass season they're calling Fury of the Wasteland arrives tomorrow and with it comes a fair chunk of new content to the game. We'll be seeing a new map, weapon and even a companion system. [Read more] | Read more »

Price Scanner via

Weekend Sale: Apple AirPods Pro for $234.98 a...
Abt Electronics has Apple’s new AirPods Pro in stock and on sale today for $234.98 including free shipping and free returns. Their price is $15 off Apple’s MSRP for these AirPods and tie Amazon... Read more
New 2019 16″ MacBook Pros on sale for $100 of...
Apple Authorized Reseller Adorama has new 2019 16″ MacBook Pros on sale today for $100 off Apple’s MSRP, each including free shipping. In addition, Adorama charges sales tax for NY & NJ residents... Read more
Apple Watch Series 3 GPS models on sale for l...
Amazon has Apple Watch Series 3 GPS models on sale starting at only $179. There prices are the lowest we’ve ever seen for these models from any Apple reseller. Choose Amazon as the seller rather than... Read more
iOS Bug In Facebook News Feed Lets Device Ca...
NEWS: 11.15.19- Users of the Facebook social media platform’s mobile app running on iOS devices won’t, like, this piece of news one bit in where a bug in the News Feed gave access to the camera... Read more
16″ MacBook Pros on sale! Preorder at Amazon...
Apple’s new 16″ MacBook Pros were only introduced yesterday, but Amazon is already offering a $100 discount on preorders. Prices for the base 6-Core 16″ MacBook Pros start at $2299: – 2019 16″ 2.6GHz... Read more
Use our exclusive MacBook Price Trackers to f...
Our Apple award-winning MacBook price trackers are the best place to look for the best sales & lowest prices on new and clearance MacBook Airs and MacBook Pros–including Apple’s new 16″ MacBook... Read more
New November Verizon iPhone deal: Get an iPho...
Verizon has the 64GB iPhone Xr on sale for 50% off for a limited time, plus they will include a free $200 prepaid MasterCard and a free Amazon Echo Dot. That reduces their price for the 64GB iPhone... Read more
Apple cuts prices on clearance, refurbished 2...
Apple has clearance 2018 15″ 6-Core Touch Bar MacBook Pros, Certified Refurbished, now available starting at only $1829. Each model features a new outer case, shipping is free, and an Apple 1-year... Read more
Up to $450 price drop on clearance 15″ MacBoo...
B&H Photo has dropped prices Apple’s 2019 15″ 6-Core and 8-Core MacBook Pros by $400-$450 off original MSRP, starting at $1999, with free overnight shipping available to many addresses in the US... Read more
Here’s how to save $200 on Apple’s new 16″ Ma...
Apple has released details of their Education discount associated with the new 2019 16″ 6-Core and 8-Core MacBook Pros. Take $200 off the price of the new 8-Core model (now $2599) and $200 off the 16... Read more

Jobs Board

Best Buy *Apple* Computing Master - Best Bu...
**746887BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Store Associates **Store NUmber or Department:** 001512-Ankeny-Store **Job Read more
Best Buy *Apple* Computing Master - Best Bu...
**746836BR** **Job Title:** Best Buy Apple Computing Master **Job Category:** Sales **Store NUmber or Department:** 000341-Scranton-Store **Job Description:** **What Read more
QA Manager, *Apple* - CBS Corporation (Unit...
# QA Manager, Apple **REF#:** 35331 **CBS BUSINESS UNIT:** CBS Interactive **JOB TYPE:** Full-Time Staff **JOB SCHEDULE:** **JOB LOCATION:** Burbank, CA **ABOUT Read more
*Apple* Mobility Pro - Best Buy (United Stat...
**744315BR** **Job Title:** Apple Mobility Pro **Job Category:** Store Associates **Store NUmber or Department:** 000662-Auburn AL-Store **Job Description:** At Best Read more
Nurse Practitioner - Field Based (San Bernard...
Nurse Practitioner - Field Based (San Bernardino, CA, Apple Valley, Hesperia) **Location:** **United States** **New** **Requisition #:** PS30312 **Post Date:** 4 Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.