Building Packages

A Magic Cap software package is a collection of objects organized to perform a specific set of user functions. Magic Cap provides several built-in packages, including the datebook, name card file, notebook and mail packages. More importantly, Magic Cap is a rich platform that provides a fertile environment to support packages. This guide describes CodeWarrior Magic/MPW, a software development environment for creating packages for Magic Cap.

In this guide, we will discuss the process of developing packages for Magic Cap. To use it effectively, you should be familiar with the C programming language and the principles of object-oriented programming.


Table of Contents


Developing Software Packages

Magic Cap software is distributed in packages that contain objects for performing tasks. Some packages are like conventional applications with specific purposes such as electronic mail and personal finance. Other packages perform tasks required by a variety of objects in Magic Cap. These include user-interface features like buttons and clocks.

While packages can vary according to purpose, they can also vary in their structure. Some special purpose packages can contain code that implements certain features, for example a inventory checker. Other packages might not contain any code and will simply add objects to Magic Cap. This second category can include data objects like stamps and sounds but it can also include useful packages that benefit from Magic Cap's rich set of user-interface tools. And of course plenty of packages are in between these examples.


CodeWarrior Magic/MPW

CodeWarrior Magic/MPW is a software development environment for Magic Cap jointly developed by General Magic and Metrowerks. You create Magic Cap packages using an Apple® Macintosh® personal computer and CodeWarrior Magic/MPW.

CodeWarrior Magic/MPW provides a set of scripts and tools for building Magic Cap packages. These software development tools work under Macintosh Programmer's Workshop(TM) (MPW), a development environment supplied with CodeWarrior Magic/MPW. MPW includes a shell for editing text files and launching other tools, a scripting language, an object code debugger and many other features. CodeWarrior Magic/MPW also includes modified versions of the Metrowerks C/C++ compiler and linker.

Macintosh is the only development platform for Magic Cap packages right now, although development on other systems is possible in the future.

You will develop Magic Cap packages with standard MPW tools plus a few special tools provided in CodeWarrior Magic/MPW. The next few sections describe some of these special tools.


Magic Cap Simulator

While developing Magic Cap packages, you'll use a version of Magic Cap that runs on the Macintosh called Magic Cap Simulator that lets you create, edit and specify the behavior of live objects graphically. This allows you to see and use packages much as they will appear on personal communicators.

Magic Cap Simulator simulates a personal communicator and allows you to develop software without having to move your package to an actual communicator every time you make a change to your package, saving time in the development cycle.

Magic Cap Simulator is useful for two purposes. You can use it to run and test packages with greater convenience than downloading the package into a communicator. In addition, you can use it in the software development process to modify objects and then dump them back as ASCII text for ObjectMaker to use.


ObjectMaker

ObjectMaker is at the heart of CodeWarrior Magic/MPW. ObjectMaker is an MPW tool provided by General Magic as part of CodeWarrior Magic/MPW that translates text descriptions of Magic Cap objects into live representations of the objects. Magic Cap Simulator also has the ability to reverse this operation, converting live objects back to their text representations.

ObjectMaker processes two kinds of files, and each package includes at least one file of each kind (in addition to one or more source files that are processed by conventional compilers and assemblers). The first kind contains the descriptions of any classes defined by the package; this is called a class definition file. The second kind, called the instance definition file, contains descriptions of objects defined by the package.

See the chapter ObjectMaker for more information on how to use ObjectMaker to develop Magic Cap packages.


Construction Tools

Typically, you'll start your package in CodeWarrior Magic/MPW, then build it and run it with the Macintosh development version of Magic Cap. In Magic Cap itself, you can use various tools and techniques to build your package. This process of adding to and changing your package in Magic Cap is called construction. In construction, you can create new viewable objects by dropping them from the Magic hat, then modify them with the move, copy, and stretch tools. You can also direct the behavior of objects in your package by writing scripts for them, as described in the next section.

See the section Construction Tools in the chapter on Magic Cap Simulator for more information on how to use Magic Cap Simulator to modify objects for your packages.


Magic Script

Magic Cap includes a powerful scripting language called Magic Script. Magic Script provides a high-level way to arrange objects and connect them together. Only Magic Cap Simulator has the ability to create and edit Magic Script programs, but all versions of Magic Cap can execute Magic Script programs once they've been created.

When you create your own packages, you'll probably begin by writing programs in C using CodeWarrior Magic/MPW. You'll then leave CodeWarrior Magic/MPW and use Magic Cap itself to create, position, and connect the viewable objects you need. While running Magic Cap, you can use Magic Script to set up the interactions between these objects, such as buttons, switches, meters, text fields, and other user-interface elements. Your finished Magic Cap package will likely include code written in C as well as Magic Script components.

Magic Script is most useful in coordinating user-interactions with viewable objects like buttons. It is easier to write small scripts for these than to create the equivalent object subclasses. From a performance perspective, the two approaches are equivalent.

Many of the sample packages that come with CodeWarrior Magic/MPW demonstrate Magic Script, especially HelloScripting and TicTacToe.


Other Tools in CodeWarrior Magic/MPW

In addition to ObjectMaker, CodeWarrior Magic/MPW includes a few other important development tools. These include the following:


Building Software Packages

This section describes how to build packages with CodeWarrior Magic/MPW. First we'll show you how to build a simple Magic Cap package named HelloWorld. This will give you a whirlwind tour of the CodeWarrior Magic/MPW development environment. From there we'll get more specific about the different components that go into CodeWarrior Magic/MPW and what they do.

CodeWarrior Magic/MPW contains several sample packages in addition to HelloWorld, which we've already discussed. See the Samples folder in CodeWarrior Magic/MPW to discover these packages. You can learn something about them by looking at their source files and then building and running them.


Building a Simple Package

Here's a list of steps for building a very simple Magic Cap package. We assume that CodeWarrior Magic/MPW has been successfully installed on your development system.

That's all there is to building a simple Magic Cap package. The black box object in the package you've built does several things: you can move, copy, or stretch it, and it plays a sound when you touch it.


Inside a Magic Cap Package

Let's take a look at the folder MyHelloWorld and examine its contents. You'll find four files:

Most Magic Cap packages are created from these files.

Instance Definition File

The file Objects.Def contains a series of static object instance definitions that ObjectMaker uses to build the objects of a Magic Cap package.

Your package must include at least one instance definition file to be compiled by ObjectMaker. An instance definition file is a text file that consists of one or more object instance definitions.

Here's an example of an instance definition taken from Objects.Def in the MyHelloWorld folder:

Instance Greeter 'Hello World' 9;
           next: nilObject;
       previous: nilObject;
      superview: (Scene 'MyHelloWorld' 8);	
        subview: nilObject;
 relativeOrigin: <0.0,-14.0>;
    contentSize: <90.0,90.0>;
      viewFlags: 0x7818D200;
     labelStyle: iBook12;
          color: -1;
       altColor: 0xFF000000;
         shadow: nilObject;
          sound: iSendSound;
End Instance;

Each instance definition includes three parts:

A typical instance definition file will have a series of definitions organized hierarchically. The ObjectMaker chapter later in this book goes into greater detail about instance definition files and their syntax.

Class Definitions

If your package includes any new classes, as most packages do, you must define them in a class definition file to be compiled by ObjectMaker. A class definition file is a text file that consists of one or more class definitions. Typically, a package's class definition file has the same name as the package, plus a .Def suffix.

Here's an example of a class definition taken from the class definition file from MyHelloWorld, followed by a discussion of its contents:

Define Class Greeter;
	inherits from Viewable;
	overrides Draw;
End Class;

This class definition includes four parts:

The ObjectMaker chapter later in this book goes into greater detail about class definition files and their syntax.

Source Code

If your package includes any new classes, you must define the code that implements the methods of the new classes in C files. You can arrange your source code in any collection of files. MPW and CodeWarrior Magic/MPW require the .c suffix.

If a package has only one source file, it usually has the same name as the package plus a .c suffix. CodeWarrior Magic/MPW requires that your package have at least one .c file; if your package has no code, this file may just be an empty main function.

Following is an example of a C source file from MyHelloWorld:

#include "Magic.h"
#include "Debug.h"
#include "Package.h"

main()
{
}

#undef CURRENTCLASS
#pragma segment Greeter
#define CURRENTCLASS Greeter

Method void
Greeter_Draw(ObjectID self, ObjectID canvas, ObjectID clip)
{
	Box 		ourContentBox;
	ulong		color;

	color = PartColor(self,
		Hilited(self) ? partAltContent : partContent);
	
	ContentBox(self, &ourContentBox);
	FillBox(canvas, clip, &ourContentBox, color,
		pixelDither | pixelCopy);
} 

Although most of this file is written in standard C, you should notice these vitally important special elements:

C Coding Issues

C code written for Magic Cap classes is written in standard ANSI C. CodeWarrior Magic/MPW includes a few extra keywords to guide the development environment in this process.

Method indicates that the function corresponds with an operation and supplies the implementation of the operation's interface.
Intrinsic Method corresponds to a simple intrinsic method.
Intrinsic specifies an operation with the intrinsic keyword set
Private used by callback routines
Public ...

Note: the notion of public and private used by the keywords above refers to the issue of the scope of the functions they are associated with and not the issue of data hiding.

Makefile

The Makefile contains MPW commands that build your package. You don't have to create or modify the Makefile; you can use the Create Build Commands item in the Magic menu to make one automatically. The Makefile usually has the same name as the package, plus the suffix .make.

Before you run the Create Build Commands script, you should set the current directory to the folder that contains your package's files. When you choose Create Build Commands, you'll have to specify the name of the new package and the source files that are used to build it. We'll go through this process when we build a sample package in the next section.

If you start your package by copying an existing package with the Clone Package command, you won't have to create a Makefile separately - you'll get one automatically when you clone.

For more information on the contents of a Makefile, see the MPW Reference Manual.


Modifying an Object with Construction Tools

After you build and run your package with Magic Cap Simulator, you'll want to modify the package's appearance and store the results back into the package's source code. You'll do this with Magic Cap Simulator itself. Here's how to do it.

  1. Launch Magic Cap Simulator from within MPW. You can launch the simulator together with a package you've built by selecting the Run Current Package item from the Magic menu. This runs the package in the current directory, so if you haven't selected a current directory for a package follow the directions in the section Building a Sample Package.
  2. Turn on construction mode. Go to the hallway, find the control panel and tap it. Then tap general. You'll see a series of check boxes. Turn on the check box construction mode. The Stamper icon in the bottom of the Magic Cap window will change to a Magic hat icon to indicate that you are in construction mode. This means that some Magic hat objects have extra features, particularly for changing the appearance of other objects.
  3. Find the MyHelloWorld package. Go back to the MyHelloWorld package by tapping the hand in the upper right-hand corner of the Magic Cap window. Then tap the hand again and go down the hallway to the door named MyHelloWorld.
  4. Create a color coupon. Tap the Magic hat in the bottom of the window. Then tap the category box named colors. A series of different shades will appear for you to select from. Pick one. The Magic hat window will disappear and the color will remain in a special viewable called a coupon. You can apply this coupon to a single viewable object by sliding it to that object and releasing it. Magic Cap will give you visual feedback to let you know when you're at a candidate object that the color coupon can be applied to.
  5. Dump the modified objects from Magic Cap Simulator. Choose the item named Dump "MyHelloWorld" Package from Magic Cap Simulator menu bar. Quit Magic Cap Simulator and go back to CodeWarrior Magic/MPW.
  6. Import the modified objects into CodeWarrior Magic/MPW. Select the item Import Dumped Objects from the Utils menu in CodeWarrior Magic/MPW. This will create a new version of your instance definition file including the color change for the Greeter object.
  7. Save the files and rebuild the package. When you do this you should notice that the square in the MyHelloWorld has the new color. You can continue to modify your package by changing the source or by rebuilding and returning to Magic Cap Simulator at any time.

By dumping from Magic Cap Simulator and then importing dumped objects from CodeWarrior Magic/MPW, you can move back and forth between the two environments.

When using Magic Cap Simulator, you can do a lot more than just modify existing objects. You can add new objects from the Magic hat. Then, when you dump and import the dumped objects, the newly added objects will be in your instance definition file. In addition, you can create Magic Scripts for objects, specifying their behavior without having to write C code. See the HelloScripting sample package for more information.


Downloading a Package into a Communicator

Packages that you build and test with CodeWarrior Magic/MPW can be downloaded into a communicator. Here's how to do it:

  1. Connect the communicator with your Macintosh development system. The basic tool for doing this is the Telebug box. The manual that comes with the Telebug box describes how to install it. This involves connecting a serial cable between your modem port and the Telebug box and then connecting another cable between the Telebug box and your communicator.
  2. Select a package to download and set the default MPW directory for this package. For the purposes of this example, we will use the HelloWorld package.
  3. Specify a build target. While it is possible to choose a build target for a specific communicator platform, you will usually want to create a generic package that runs on any communicator. For this you should select Universal Device Build Target in the Magic menu.
  4. Build the package again. You must rebuild the package explicitly to correctly prepare it for downloading into a communicator. If you select auto run in the Magic menu it will automatically download the package into the communicator. If you don't select auto run, you will have to explicitly download it with the Download Current RAM Card menu command.

That's all there is to downloading a Magic Cap package into a communicator. When you're finished with this process the communicator will restart and your package will be loaded.

If you don't have a Telebug box, you can download packages to your communicator using the cable supplied with Magic Xchange(TM) software (available separately) and DownloadPackage, supplied with CodeWarrior Magic/MPW. See the DownloadPackage files in the Cool Stuff folder for more information.


CodeWarrior Magic/MPW Menus

Find Menu

CodeWarrior Magic/MPW adds several items to the Find menu. All these commands send their results to the MPW worksheet.
Search command Description
Search Û Current Directory Search all files in MPW's current directory for the selected text.
Search Û Active Directory Search all files in the directory that contains the front most window for the selected text.
Search Û Target Directory Search all files in the directory that contains the target window (the next-to-front most window) for the selected text.
SearchClasses Û Search all of CodeWarrior Magic/MPW's class definition files (the .Def files) for the selected text.
SearchC Û Search all the files in CodeWarrior Magic/MPW's Interfaces directory that end in .c or .h for the selected text.
Search Û Indexicals.h Search the Indexicals.h file for the selected text.
Search Û Utilities.h Search the Utilities.h file for the selected text.
Search Û Samples Search all the files in CodeWarrior Magic/MPW's Samples directory for the selected text.
Search Û MagicDeveloper Search all the files in the MagicDeveloper folder for the current text.

These menu items are implemented in CodeWarrior Magic/MPW as scripts. You can search files in the MagicDeveloper folder directly by typing in the appropriate script name, as shown in the following table:
Function Script Name
search .c, .h., and .Def files SearchAll
search .c and .h files SearchC
search .Def files SearchClasses
search all files SearchMagic
search files in Samples folder SearchSamples


Directory Menu

CodeWarrior Magic/MPW creates a Directory menu that replaces the one supplied with MPW. Selecting an item from this menu sets MPW's current directory to that folder.

This Directory menu includes MagicDeveloper, MagicDevSystem (the folder containing Magic Cap and packages), MagicInterfaces (the folder with header and interface files for developing packages), and Magic Def files. Next, the Directory menu lists all the folders inside the Samples folder in MagicDeveloper.

The Directory menu also includes an item named Directory {Active}. If you select this item, the current directory will be set to the directory containing the frontmost window. This gives you a fast way to set the current directory to the package that you're working on.


Magic Menu

The following table describes the items in the Magic menu. This table has three columns. The first two columns represent items in the Magic menu while the third column contains descriptions. The difference between the first two columns is that the first column represent CodeWarrior Magic/MPW commands while the second column represents options that control the behavior of these commands. When you select a menu item from the second column CodeWarrior Magic/MPW will display a check mark to indicate that the option is enabled.

Command Option Description
Build This is the main CodeWarrior Magic/MPW command for building a Magic Cap package.
Resume Build Resume Build provides a shortcut for continuing a failed build. Resume Build opens the Build Commands file in the current directory and continues executing MPW instructions from the point where the build failed. Resume Build is designed to save the time taken up by creating the Build Commands file if a correct one already exists. When in doubt, use Build.
debug build If this item is checked, the package will be built with debugging code, such as calls to Log and Assert. If the item isn't checked, debugging code won't be compiled.
show progress If this item is checked, progress information about the build will appear in the Worksheet window.
auto run If this item is checked, Magic Cap will start and open the current package after a successful build.
Full Build This command forces CodeWarrior Magic/MPW to rebuild an entire package.
Update Debugging Symbols Update Debugging Symbols forces an update of the debugging information for the current package. Debugging symbols are usually automatically updated whenever a class definition file changes.
Macintosh Build Target Check this item to build a copy of the package that works with Magic Cap Simulator.
Universal Device Build Target Check this item to build a copy of the package that works on any Magic Cap communicator.
Other Build Targets... Choose this item to select a specific vendor's device as a build target, such as Magic Link or Envoy.
Run Magic Cap This item starts Magic Cap (if it isn't running already) without quitting MPW. If there's not enough memory to start Magic Cap without quitting MPW, you'll see an alert box instead.
Run Current Package This item starts Magic Cap (if it isn't running already) without quitting MPW and runs the package in the current directory. The package isn't rebuilt, just run. If there's not enough memory to start Magic Cap without quitting MPW, you'll see an alert box instead.
autoDelete changes If this item is checked, the Magic Cap changes file will be deleted when the package is built.
Set PC Card type Use this item to determine the kind and size of PCMCIA card image if your build target is a communicator.
Download Current RAM Card Use this item to try to download a memory card again without rebuilding the package.
to slot 1 Check this item to set your download target to communicator slot 1.
to slot 2 Check this item to set your download target to communicator slot 2.
Envoy Debugger Target Use this item to build your package with debug symbols for Envoy.
Magic Link Debugger Target Use this item to build your package with debug symbols for Magic Link.
Create Build Commands Use this command to create a make file for your package automatically. When it displays a dialog asking for confirmation select Yes.
Clone Package Create a new package based on the package in the current directory. This package will use names derived from the new packages name.


Utils Menu

The following table describes the items in the Utils menu.

Menu item Description
Function Prototype This command provides the C function prototype for a method. If there's nothing selected when you choose this command, Function Prototype will find the first word that precedes the insertion point and will assume that word is a method name.
Open Utilities.h Use this item as a quick way to open the Utilities.h file, which contains lots of important Magic Cap symbols. Exploring Utilities.h is a great way to learn more about Magic Cap.
Open Indexicals.h This item is a fast way to open the Indexicals.h file, which contains the symbolic names for all Magic Cap indexicals. You can find out a lot about Magic Cap by rooting through this file.
Open Objects.Def This item quickly opens the current package's Objects.Def file.
Bowser Pro Choose this item to start Bowser Pro, the famous class browser.
Echo Log This item copies the contents of Magic Cap Simulator's log file to the MPW worksheet in MagicDeveloper:SystemSoftware:Log.
Clear Log This item clears the contents of Magic Cap's log file.
Convert Dumped Indexicals Use this command to help identify objects in your package; that can be replaced by references to indexicals. Before using this command, run Magic Cap and choose the Find Indexicals command from the Debug menu. This will put a list of indexical candidates into the log file. After creating the list of indexical candidates, return to MPW and choose this item. CodeWarrior Magic/MPW will change your Objects.Def file to incorporate the suggested changes. The conversion is automatic; you just have to confirm that you want the changes saved.
Import Dumped Objects Use this item if you've dumped your package's objects with the "Dump Package" item in Magic Cap's Examine menu. This item reads the text from the Log file and places it into a new Objects.Def file. Import Dump Objects also preserves your previous Objects.Def by saving it in a folder named Old inside the package's folder.
Find Instance When you've selected a line that contains a reference to an object in an Objects.Def file, use this item to find the instance definition of the object referred to.
Get Unique Instance ID You can use this item to generate an instance ID that's unique within the instance's Objects.Def file. After you select this item, the unique ID will appear at the insertion point.
Convert ObjectIDs to Instance IDs This command scans the active window for ObjectIDs of the form $hhhhhhhh and converts them into instance IDs of the form ddd. You should use this command after you use Magic Cap Simulator's Dump Inspector Target menu, then paste the newly dumped objects into your Objects.Def file.
Convert {Indexicals} to iNames This command converts indexical references, like this: {60,12}, into readable identifiers, like this: iBook10Bold. It works on the active window.
Run Telebug This command starts Telebug, sparing you from having to remember how to spell Telebug and type it.
Set Source Break This command sets a Telebug breakpoint. Put the insertion point into a line in your package's C source file, then choose this item to set a breakpoint before that line.


Other Stuff

We couldn't think of a clever way to categorize the items in this section, so we failed to categorize them.

Online CodeWarrior Magic/MPW Help

You can use the Function Prototype item in the Utils menu while you're programming in MPW. The Function Prototype command quickly looks up the return value and parameters for any method.

To use this command, select the name of the function, method or operation that you want to learn about, or place the insertion point in or after the function, method or operation. Choose Function Prototype from the Utils menu.


Package Validation

Magic Cap Simulator includes a menu named Discipline that can help you make sure your package's objects are consistent. The most useful item in this menu is the Validate Package item. You can use this to check the view hierarchy in your package, which is a source of common problems with package development.


Magic Cap for screen shots

CodeWarrior Magic/MPW comes with a special version of Magic Cap that can be used for making screen shots for documentation. The standard version of Magic Cap Simulator accurately simulates the 2-bit graphics model used in communicators. Magic Cap for screen shots actually uses the same depth as your Macintosh graphics display to give more graphical information for screen shots and avoid unpleasant dithering artifacts.


Common Problems and Solutions

This section describes some of the common problems that you may encounter when you're trying to build and run packages.

Magic Cap Simulator crashes before starting up

This usually indicates that your Magic Cap Changes file is corrupt. To fix the problem, throw away the Magic Cap Changes file. You'll lose changes you've made, but Magic Cap should return to normal.

Magic Cap Simulator repeatedly enters the debugger when starting up

When you start Magic Cap, you may repeatedly enter the debugger and see messages like this:

User break at xxxxxxxx HiBoot+0092
User break at xxxxxxxx HiBoot+0176
User break at xxxxxxxx MacTCP_Install+007E
User break at xxxxxxxx MacUtilities_InstallMacClusterFile+0140

Congratulations! You've discovered the insidious double-secret Magic debugging mode, which is triggered by running with the Macintosh caps lock key down. Simply release the caps lock key and you won't be bothered like this again.

Build gives messages about not finding files

If you try to build your package and get messages from MPW about files not being found, you may have failed to set the directory correctly. Be sure you use the Set Directory item in MPW's Directory menu to set the directory to the one that contains your source files before you choose the Create Build Commands menu item.

Build fails, complaining of too little memory

You should run MPW Shell with a memory partition of at least 7500K when developing packages. In the Finder, select Get Info from the File menu, then type 7500 into the Suggested Size and Minimum Size boxes (or the Current Size box if you're not running System 7.1 or later).

ObjectMaker ignores the first line of a file

Due to a bug in ObjectMaker, if the last line of a file is a comment that starts with // , the first line of the next file processed will be treated like a comment.

MacsBug shows the wrong class names

Code Warrior Magic normally updates the class symbol information used by the debugger whenever you change a class definition file in your package. However, if you switch to work on another package but don't happen to change a class definition file in the new package, the debugger won't update its symbols. Instead, it will show the class names for the package you were working on before. To point the debugger at the symbols for your new package, choose the Update Debugging Symbols menu item.


Advanced Topics

The advanced information in this section may be useful to you as you become more adept at developing packages with CodeWarrior Magic/MPW.


The Top n Magic Cap Programming Tips

Don't call functions across segments

Magic Cap does not support the A5 relative jump instructions used in the Macintosh to allow program segmentation. If you've put a #pragma segment statement before each class definition, as General Magic has always required, each class is in a separate segment. So if one private routine of one class calls the private routine of another, the linker will generate an A5 relative jump that will fail miserably in Magic Cap.

You no longer need to put #pragma segment in front of each class. Removing the #pragma segments will reduce the likelihood of a serious crash if you do call a private routine of one class from another class.

Be careful with Load, Install and Reset

Load, Install, and Reset are called every time the device powers up or is reset. You should therefore be careful what you do in these methods. Structure your code so that initialization that should be done only once is actually done only once.

Don't use intrinsics or indexicals in routines passed to Each or RunSoon

Write private routines passed to operations like Each and RunSoon assuming that they will be executed outside of the context of their package. A private routine that uses intrinsics, indexicals, or class numbers will fail in unpredictable and horrible ways if it's executed outside its package context.

Be careful with private routines

Private routines can cause many subtle bugs. Use them only when you need to. Magic Cap itself uses methods and intrinsics 2/3 of the time and private routines only 1/3.

Reducing the number of private routines you use can reduce the amount of code you need to include in a patch. Since private routines can't be easily patched, to replace a single private routine you might need to include new versions of many methods.

Don't save pointers as fields in persistent objects

There is no way to allocate a pointer to a buffer that will persist past a power cycle. This means that it is dangerous to store such pointers in persistent objects.

Don't leave objects accessed

The Magic Cap memory manager can't allocate while objects are accessed. Since almost everything you do in Magic Cap might require allocation, you're blocked while objects are accessed.

Don't mix static and dynamic data

Magic Cap copies an entire object into memory to change just one bit of data. So if you create an object list with a boolean flag entry and 200 text object entries, Magic Cap will consume large amounts of memory by copying the whole list every time you change one flag.

Don't mix persistent and transient data

Don't put the object IDs of transient objects into the fields of persistent objects, and vice versa. In the first case, these fields will be set to nilObject after a power cycle, which might pose problems for your class. In the second case, the persistent objects will become a memory leak after a power cycle, since the enclosing object will have disappeared without being explicitly destroyed.

This error often appears when you're using StringToText to create a text object. Unfortunately, the text object created is transient. You shouldn't use it as a parameter to a call to SetSubject. Instead, use StringToTextNear to create text objects.

Be careful with HasObject

Don't use HasObject to check for the existence of persistent objects. Since object IDs can be reused, the object you're now checking might not be the same object you referred to oh-so-long ago.

This rule has a minor exception: you can use HasObject to check if an operation you've just called has deleted an object. HasObject is safe when you know that the object ID was good very recently.

Don't use stack based parameters blocks passed with timers

This is a basic C programming rule, but it can be hard to remember. Don't pass a pointer to a local variable when it will be kept past the lifetime of the function containing the declaration of that variable. In Magic Cap, this bug seems to pop up most in completion routines for timers.

Don't forget to call MakeUsable and MakeStorable

If you use BeginRead or BeginModify or ReadFields or WriteFields, be careful to call MakeUsable and MakeStorable when needed.

You'll run into this problem when you use ReadFields to read from one object and WriteFields to put the data into another object. You must call MakeUsable and MakeStorable between the ReadFields and WriteFields, in code that looks like this:

ReadFields(self, &MyClassFields);
itemToChange = MakeUsable(self, MyClassFields.foo);
/* do some work here */
OtherClassFields.bar = MakeStorable(other, itemToChange);
WriteFields(other, &OtherClassFields);
If you don't, you'll have a subtle bug that won't show up unless your users are brave enough to try filing.

Don't modify string constants

Don't pass string constants to operations or private routines unless you're sure that the routines don't attempt to modify the passed-in string. String constants are compiled into the code of your package, which might be put into ROM or ROM cards. Attempting to modify strings in ROM will cause a bus error.

Don't forget the Telename in a Citation

Omitting the telename in the author field of a package citation will cause wireline encoding of that package's objects to fail. This error is so common that it used to appear in every piece of General Magic sample code.

Use this sample as a model for your citations:

Instance OctetString 100;
           data: 'Hello World'; 
End Instance;

Instance OctetString 101; 
           data: $ 0000 0000; End Instance;

Instance Telename 102;
      authority: (OctetString 100); 
       identity: (OctetString 101); 
End Instance;

Instance Identifier 'HelloWorld' 103; 
End Instance;

Instance Citation 104;
           title: (Identifier 'HelloWorld' 103);
          author: (Telename 102);
    majorEdition: 1;
    minorEdition: nilObject;
End Instance;

Don't depend on garbage collection

Garbage collection doesn't happen very often in Magic Cap, so you can't rely on it to clean up obsolete objects for you. For example, Magic Cap won't garbage collect to make room for a memory allocation. If there's a lot of junk occupying memory, your allocations might fail. Allocations that fail cause big problems for Magic Cap.

Also watch out for situations where many objects point to one no-copy object, or to an object that isn't owned by anybody in particular.

Don't write code that takes advantage of Macintosh-only features

Since you're probably developing for Magic Cap using the Magic Cap Simulator, you might find it easy to slip into using Macintosh-only (or debug-only) features of Magic Cap. If you do slip, your package won't behave the way you expect it to on a communicator. Avoid using Macintosh streams by reading and writing to files, and avoid toolbox calls.

Don't forget to call Unshadow

Persistent objects from your object definition files are shadowed when they're changed. You can recover the memory they occupy by unshadowing them once you're finished using them.

Don't use global variables

Just don't. If you do, you'll run into the jump problem described in Tip #1, and bad things will happen.

Large Segments

Packages with large segments may exceed function offsets of 16-bits (32K in either direction). CodeWarrior Magic/MPW does display an error message when it attempts to compile code in this category. The workaround is to use the C compiler's -model farCode option. Very few packages will need to use this flag.

When you do use this option you'll need to modify your code wherever you use function pointers. CodeWarrior Magic/MPW has a #pragma statement for forcing the compiler to use near addressing mode. For example,

#pragma push
#pragma near_code
Method void Foo()
{
   Each(xxx, (EachFunction)ForEachElemDo, xxx);
}
#pragma pop
In practice this can lead to two problems. First, code in large packages may need to be rearranged to insure that the 32K offset is not exceeded. In the example above this means that the EachFunction must be near the code that calls Each and that any private functions referenced are also nearby.

Second, moving the #pragmas inside the function to surround just the individual statement does not work. You must use the #pragmas around the entire function.


Customizing Build Sounds

When you build your package successfully, you'll hear a short, low tone from the Macintosh. If the build fails, you'll hear a longer, higher tone. These sounds are defined as aliases in the MagicStartup file in the MagicDeveloper folder as MagicDevSuccessSound and MagicDevFailureSound. If you feel like adding some musical variety to your technical life, you can change the definitions in that file.