There are a few properties that you should set for your application
to configure it properly for the Finder and the operating system.
These include the bundle identifier (CFBundleIdentifier
)
and the application’s creator code (CFBundleSignature
).
There are other properties you need to set so you can display version
and copyright information to the user. You’ll set these properties,
then create an About window that accesses the property
list from within your application.
Besides modifying the property list, there are a number of steps you’ll need to follow to actually create the window and get it to function in the Moon Travel Planner we’ve worked on so far. In this section you’ll:
Modify the property list.
Create a new window.
Write code that opens and displays the About window.
Write an event handler for the About window.
You’ll set the bundle identifier first. The bundle identifier
is used to locate the application bundle at runtime (see Section 10.1.1).”
It must be unique, so define it as a Java-style package name; for
example com.mycompany.myapp
or edu.ABCSchool.myapp
.
Open the Moon Travel Planner project if it is not already open.
Click the Targets tab, then click Moon Travel Planner in the Targets list.
Click Application Settings, then click Expert.
Click New Sibling, type CFBundleIdentifier
as
the property name, and press Return.
Double-click the Value column, type com.apple.moontravelapp
as
the property value, and press Return.
Next you’ll modify the property list so the creator code
(CFBundleSignature
) is MTPP
.
As you saw in Table 10.1 the default value is ????
.
In Chapter 5
we mentioned MTPP
has
already been registered with Apple as the creator code for Moon
Travel Planner. In fact, we used the creator code to set up control
IDs in Chapter 5 and declared a
constant (kMTPApplicationSignature
)
in Chapter 6 to represent
the creator code. We need to add the creator code to the property
list so the Finder is aware of Moon Travel Planner’s existence.
In the Expert mode property list, double-click ????
,
the value that’s listed for CFBundleSignature
, then type MTPP
.
The properties the application displays in the About window
should be localized. So you’ll modify the default properties in
the InfoPlist.strings
file:
Click the
Files tab, then click InfoPlist.strings
in
the Resources group of the Groups & Files list. You should
see three strings that Project Builder added for you automatically.
/* Localized versions of Info.plist keys */ CFBundleName = "Moon Travel Planner"; CFBundleShortVersionString = "Moon Travel Planner version 0.1"; CFBundleGetInfoString = "Moon Travel Planner version 0.1, Copyright 2000 MyGreatSoftware.";
Modify the keys in the files so they have the following values:
CFBundleShortVersionString = "Moon Travel Planner version 1.0.1"; CFBundleGetInfoString = "version 1.0.1, copyright 2001, Lunar Software, Inc.";
You’ll use Interface Builder to create a new window. As you recall from Section 10.1.4 the window needs to be movable, have a close control, and show a title in the title bar.
Click main.nib
in the Resources group of the Groups & Files list.
Create a new window. Click the Windows button in the Carbon palette, then drag the icon of the window on the left to the desktop.
Name the window object. In the Instances pane of the
main.nib
window, double-click the word “Window” that’s under
the icon of the window you just created, type AboutWindow
,
and press Return.
Assign a title to the window. With the window active, choose
Show Info from the Tools menu, choose Attributes from the pop-up
menu, type About Moon Travel
in
the Title text field, and press Return. We need to shorten
the name to Moon Travel, because the window will be too small to fit About
Moon Travel Planner.
Set the window’s controls in the Control group. Make sure Close Box is the only option selected.
Set the window’s attributes in the Attribute group. Make sure Standard Handler is the only option selected.
Set the window class as Document.
Set the Theme Brush setting as Dialog.
Resize the window to 264 by 165 pixels. This allows
for the application icon, application title, two lines of configuration information, and takes into account the spacing suggested in Inside
Mac OS X: Aqua Human Interface Guidelines. Choose
Size in the pop-up menu, choose Width/Height from the right Content
Rect pop-up menu, and type 264
for
width and 165
for height.
Add the Moon Travel Planner application icon to the interface. You can use the same PICT you used for the main window. Follow the instructions in Chapter 5 for adding an image to the interface. Make sure you use the dimensions 64 by 64 when you size the PICT control.
Choose Show Layout Rectangles from the Layout menu. You can align items more precisely using the edges of the layout rectangles.
Adjust the spacing of the Moon Travel Planner application
icon so it follows the recommendations in Inside Mac OS
X: Aqua Human Interface Guidelines. The current
guidelines call for a spacing of 8 pixels from the top icon to the
bottom of the title bar. With the icon selected, choose
Show Info from the Tools menu, then choose Size from the pop-up
menu. Choose Top/Left from the Bounds pop-up menu and
type 8
for the y-value.
Center the Moon Travel Planner application icon. With the application icon selected, choose Alignment > Make Centered Column from the Layout menu.
Add a static text field below the application icon. This is the application title. From the Controls palette, drag the object named Static Text to the area below the icon.
Enter Moon Travel Planner
as
the static text field’s value. Double-click the field so
a blinking insertion point appears. Type Moon Travel Planner
and press Return.
Adjust the spacing of the Moon Travel Planner text so it follows
the recommendations in Inside Mac OS X: Aqua Human Interface
Guidelines. The current guidelines call for the
top of the Moon Travel Planner text’s layout rectangle to be 12
pixels from the bottom of the Moon Travel Planner application icon. You
actually need to calculate the spacing from the top of the window
to the top of the Moon Travel Planner text layout rectangle. That
spacing is 8 + 64 + 12, or 84. Eight pixels for the space between
the top of the window and the top of the application icon, 64 pixels
for the height of the application icon, and 12 pixels for the space
between the bottom of the application icon and the top of the Moon
Travel Planner text layout rectangle. With the Moon
Travel Planner static text field selected, choose Size from the
Info window pop-up menu. Choose Top/Left from the Bounds
pop-up menu and type 84
for
the y-value.
Center the Moon Travel Planner text and adjust the spacing. With the Moon Travel Planner static text field selected, choose Alignment > Make Centered Column from the Layout window.
Add a static text field below the application name. You’ll display the version information in this field.
Delete the title of the static text item. The static text field needs to be blank so you can write version information to it. In the Static Text Info window, choose Attributes from the pop-up menu, then delete “Static Text” from the Title text field.
Enter MTTP
as the
static text field’s signature and 132
as
its ID. Choose Control from the pop-up menu in the Static Text
Info window. In the Control ID section, type MTTP
in
the Signature field and 132
in
the ID field. You’ll use these values later to access the static
text field when you display the version information.
Turn off the Alignment rectangles. Choose Hide Alignment Rectangles from the Layout menu.
Position the About window where you’d like it to appear when the user opens it. Where you position the window in Interface Builder determines its position when the user opens it.
In Chapter 3 we saw that Project
Builder automatically included code to create the main window from
the main.nib
file. Now that you’ve added a third window to the
main.nib
file—the About window-you need to add code to your
main function to create the About window from the one you added
to the main.nib
file. You need to use the function CreateWindowFromNib
.
You must pass it three parameters, the nib reference from which
to get the window description, the name of the window object, and
a pointer to a window reference. You already have this code in your
main function to create a nib reference from your main.nib
file:
err = CreateNibReference (CFSTR ("main"), &nibRef);
You’ll pass nibRef
as
the first parameter to CreateWindowFromNib
.
The second parameter must be a CFString
object.
For this you need to pass the name of the window object, which you
named “AboutWindow” in Section 10.2.2. You must
convert “AboutWindow” to a CFString
object
using the function CFSTR
. So for the second
parameter, you’ll pass CFSTR("AboutWindow")
.
The third parameter needs to be a pointer to a window reference.
After you call the function, this will refer to the About window.
First you must declare the window reference. You can modify the
global declaration in the main.c
file so it includes the About window.
It should look like this once it has been modified:
// Global window references. WindowRef gMainWindow, gMoonFactsWindow, gAboutWindow;
Now that you have all the parameters in place, you can add the code to create the About window. You should also check for an error, and if the window can’t be created, jump to a label that causes the application not to launch. Add this code to the main function, just after the code that creates the main window:
err = CreateWindowFromNib (nibRef, CFSTR ("AboutWindow"), &gAboutWindow); require_no_err(err, CantCreateWindow);
You assigned a command to the About menu item in Chapter 7. Now it’s time to write a function that handles the command by showing the About window, getting version information from the property list, and writing the version information to the window.
The first thing we need to do is add constants used in the function. You need a constant to represent the command you assigned to the About menu item, and a constant to represent the control ID you assigned to the static text field.
Add the constants shown in Example 10.1 to the main.c
file,
at the top, just after the statement #include <Carbon/Carbon.h>
:
Example 10-1. Constants Needed for the About Window
#define kMTPOpenAboutWindowCommand 'aBtb' #define kMTPVersionInfoID 132
Before we write the function, you’ll declare its prototype.
It takes a window reference to the About window as a parameter.
You can put the following function prototype in the main.c
file,
along with the other function prototypes you’ve declared so far.
pascal void MTPAboutWindowCommandHandler (WindowRef window);
Now we can add the function. It shows the About window, gets
the Get Info string from the InfoPlist.strings
file,
and displays the string in the About window. Copy the AboutWindowCommandHandler
function
in Example 10.2 to
the main.c
file.
Example 10-2. A Function That Shows the About Window
pascal void MTPAboutWindowCommandHandler (WindowRef window) { CFStringRef text; CFBundleRef appBundle; ControlID versionInfoID = { kMTPApplicationSignature, kMTPVersionInfoID }; ControlRef versionControl; ControlFontStyleRec controlStyle; appBundle = CFBundleGetMainBundle (); // 1 text = (CFStringRef) CFBundleGetValueForInfoDictionaryKey (appBundle, CFSTR("CFBundleGetInfoString")); // 2 if ((text == CFSTR(" ") ) || (text== NULL)) text = CFSTR("Nameless Application."); // 3 GetControlByID( window, &versionInfoID, &versionControl ); // 4 SetControlData ( versionControl, kControlLabelPart, kControlStaticTextCFStringTag, sizeof(CFStringRef), &text); // 5 controlStyle.flags = kControlUseJustMask; // 6 controlStyle.just = teCenter; // 7 SetControlFontStyle( versionControl, &controlStyle ); // 8 ShowWindow (window); // 9 SelectWindow (window); }
Here’s what the function does:
The Core
Foundation Bundle Services function CFBundleGetMainBundle
returns
the bundle associated with the Moon Travel Planner application.
You need to pass the bundle as a parameter to the function in the
next statement.
The Core Foundation Bundle Services function CFBundleGetValueForInfoDictionaryKey
returns
the string associated with the key CFBundleGetInfoString
. This is the string you modified in Section 10.1. The function CFBundleGetValueForInfoDictionaryKey
takes
a CFString
object as
a parameter, so you must use the function CFSTR
to
convert the Get Info string to a CFString
object.
To catch possible errors, if the string CFBundleGetInfoString
doesn’t
exist, then set the value of text
to
“Nameless Application.”
The Control Manager function GetControlByID
gets
the control handle associated with the text field in which you’ll
display the version information.
The Control Manager function SetControlData
sets
the text field to the value of the string returned by the function CFBundleGetValueForInfoDictionaryKey
.
The flag kControlUseJustMask
specifies
that the justification field of the controlStyle
data
structure should be applied to the control.
The Text Edit constant teCenter
specifies
that text in the control should be centered.
The Control Manager function SetControlFontStyle
sets
the font style for the static text field to the values passed in
the controlStyle
data
structure.
Now that the text you want to display is written to the control,
you need to show the window using the Window Manager function ShowWindow
.
Then, make it active using the SelectWindow
function.
So far, nothing in our Moon Travel Planner application calls
the MTPAboutWindowCommandHandler
function.
When the user chooses About Moon Travel Planner from the application
menu, the About command is issued, but nothing in our program captures
that command. We need to add another case to the switch statement
in the main window event handler you wrote in Chapter 6.
Recall that handler takes care of the Compute Travel Time and Show
Facts commands. We need to add a statement so it also handles the
About command. Modify the switch statement in the function MTPMainWindowEventHandler
so
it now looks like the code shown in Example 10.3.
Example 10-3. The Modified Switch Statement in the Main Window Event Handler
switch (command.commandID) { case kMTPComputeCommand: MTPComputeCommandHandler ((WindowRef) userData); result = noErr; break; case kMTPShowMoonFactsCommand: MTPShowMoonFactsWindow(gMoonFactsWindow); result = noErr; break; case kMTPOpenAboutWindowCommand: MTPAboutWindowCommandHandler(gAboutWindow); result = noErr; break; }
Once the window is open, the Moon Travel Planner application needs to handle any events associated with it. We need to write an event handler for the window next.
You’ve already written two event handlers—one for the main window and another to handle the Facts for the Traveler window—so writing a third should be fairly routine for you.
In this section, you’ll declare an event type specifier associated with the About window event handler, then install the event handler for the About window.
The handler only needs to take care of a window close event.
Copy the following to the main
function,
after the declaration for the Facts for the Travelers window event
specifier:
EventTypeSpec aboutSpec = { kEventClassWindow, kEventWindowClose };
Declare the event handler. Copy the following declaration
to the main.c
file, just
after the constants and global variable declarations:
pascal OSStatus MTPAboutWindowEventHandler ( EventHandlerCallRef handlerRef, EventRef event, void *userData);
Install the event handler. After the line DisposeNibReference(nibRef)
,
add the following code:
InstallWindowEventHandler (gAboutWindow, NewEventHandlerUPP (MTPAboutWindowEventHandler), 1, &aboutSpec, (void *) gAboutWindow, NULL);
Copy the function in Example 10.4 to the main program,
after the function MTPMoonFactsWindowEventHandler
.
Example 10-4. The About Window Event Handler
pascal OSStatus MTPAboutWindowEventHandler (EventHandlerCallRef handlerRef, EventRef event, void *userData) { OSStatus result = eventNotHandledErr; UInt32 eventKind; eventKind = GetEventKind (event); // 1 if ( eventKind == kEventWindowClose) // 2 { HideWindow ( (WindowRef) userData); // 3 result = noErr; } return result; }
Here’s what the function does:
The Carbon
Event Manager function GetEventKind
returns
the kind of the event.
If the event is a close window event, then it handles it; otherwise, it returns the result code eventNotHandledErr
to
indicate the Carbon Event Manger should handle the event.
The Window Manager function HideWindow
hides
the About window.
Let’s build and run the application to make sure the About window opens and looks as it should:
Click the Build button in the upper-left corner of the Moon Travel Planner project window.
Click the Run button in the upper-left corner of the project window.
Choose About Moon Travel Planner from the application menu. Does the window open? It should look like the one shown in Figure 10.6.
Click the Close box. Does the About window close?
Click the Quit button.
We took a look at the property list and the default properties that Project Builder provides when you create a new project. We also discussed the Standard and Finder keys available to your application and showed how you can add your own custom keys. Finally we created an About window for the Moon Travel Planner application and used the property list as the source of information to display in the About window. In the next chapter, you’ll see how to use Navigation and File services to open and save files.