TweetFollow Us on Twitter

Making Magic
Volume Number:11
Issue Number:5
Column Tag:Magic

Making Magic

A developer’s introduction to General Magic and Magic Cap

by Richard Clark, Scott Knaster, and the staff of General Magic

Note: Source code files accompanying article are located on MacTech CD-ROM or source code disks.

“Where should Apple go after the Macintosh?” The year was 1990, and Marc Porat was leading a group of engineers considering that question. Porat’s answer to this question became the Paradigm project: Apple’s plan to build a small, personal, communication-oriented computer. Porat asked to spin off a small company to realize this vision, Apple’s board gave its blessing, and General Magic was born.

Several members of the original Macintosh team - Andy Hertzfeld, Bill Atkinson, Joanna Hoffman, and Susan Kare - joined with scores of new Magicians to realize Porat’s dream. Major companies (including Apple, Sony, Motorola, AT&T, Matsushita, and Philips) formed an alliance around General Magic to bring their talents and resources to the project. Last October, the world saw the first examples of that work when Sony shipped the Magic Link™ Personal Intelligent Communicator and AT&T opened the AT&T PersonaLink™ Services network. Two months later, Motorola shipped Envoy™, which is their implementation of a Personal Intelligent Communicator. These products have two things in common: Magic Cap™ and Telescript™.

Even though this article is about Magic Cap, we should take a moment to describe Telescript. Telescript is a programming language for building distributed systems-programs which aren’t entirely resident within a single computer but are spread out across a network. AT&T’s PersonaLink Services use Telescript programs to carry messages between a communicator and the network, then uses these programs to transport messages around the network. Even though Magic Cap uses Telescript for many of its communications tasks, we’ll see that there are plenty of opportunities that Magic Cap developers can pursue without Telescript.

What is Magic Cap?

Magic Cap is General Magic’s software environment for personal communicators. Magic Cap embraces both the most common tasks found in today’s workplace (managing your schedule and relationships) and such communication tools as the telephone, FAX, and electronic mail. Magic Cap doesn’t skimp on the programming side either: it contains an extensive collection of user interface building blocks, a multitasking kernel, and a rich set of utility routines for third-party developers.

Magic Cap was designed with two key principles in mind: communication and ease of use. Communication means that every device is ready to communicate: all Magic Cap communicators have a data/FAX modem built-in along with the software to support it. Each communicator is also designed to act as a telephone dialer and can act as a handset with the appropriate attachment. Communicators may interact by sending electronic mail over the telephone or directly via an infrared transceiver. Magic Cap packages -the equivalent of programs on a desktop machine-have easy access to e-mail, fax, beaming, printing, and other communication features.

Magic Cap’s ease of use comes from its graphical interface. Magic Cap embodies the original spirit of the Macintosh-it creates an inviting world that uses familiar objects in common ways. In order to be more than a novelty in the personal electronics world, communicators must be consumer electronics products, not tiny computers. They must be usable by both self-admitted “gadget freaks” as well as people who draw the line at telephones and possibly automated teller machines. This means that communicators must be much easier to use than even the friendliest personal computers. In Magic Cap, ease of use comes from great user interface design with simple, powerful metaphors and consistent features. General Magic has performed an enormous quantity of user testing, and continues to do so, as do its most successful developers.

Magic Cap was implemented with efficiency, utility, and safety as its key goals. Efficiency begins with Magic Cap’s object-oriented structure. Packages can build on the rich set of objects provided in ROM. Utility comes from a runtime environment designed to work with existing development and debugging tools and which assumes that it is running in a very constrained space. Safety is embodied by the memory management system: it makes efficient use of limited RAM even when creating and destroying scores of objects, protects user data, and includes a clean up feature to recapture memory that a programmer might otherwise leave behind.

The Magic Cap Hardware Platform

Magic Cap offers another feature that developers can feel good about - a standardized hardware platform. The current generation of communicators is built around the Motorola 68349 Dragon microprocessor. The Dragon contains a 68000-family core with memory protection hardware and low-power operating features. Communicators also include at least 1MB of RAM, 3MB of ROM (including the software environment and bundled third-party packages), a data/FAX modem, the Magicbus ™ high speed interface bus, a PCMCIA Type II slot, a high-speed infrared transceiver, and an option button. Each communicator has a 480 x 320 LCD screen with 4 levels of gray, a speaker, a microphone, and an interface for a headset which turns the communicator into a telephone. These features provide a rich hardware base upon which to build software packages for all Magic Cap communicators.

This minimum hardware requirement ensures that developers can build packages that work on a variety of communicators, yet allow hardware vendors to add unique features. For example, Motorola’s Envoy includes a second PCMCIA slot and a wireless modem. These hardware enhancements have been integrated into Magic Cap.

A User’s View of Magic Cap

When you turn on a new Magic Cap personal communicator, you’ll see the desk. This is the jumping off point for most of the things you’ll do with a communicator.

Magic Cap’s objects suggest items that you use in the real world. To make them work, you touch them: touch your in box to see your mail, touch the datebook to make an appointment, and so on. This display shows several other constants in the Magic Cap world: the upper name bar and the lower control bar. The name bar supplies help, shows the date and/or time, and contains the step back hand to allow for navigation from one Magic Cap package to another. From left to right, the control bar contains:

• A button that returns the user to the desk,

• A stamper that contains both decorative and functional objects to drop on other objects (this is also used to access the magic hat which allows users to change the fundamental behaviors and appearance of their communicators),

• The magic lamp from which you can search, print, fax, mail, and beam (package-specific commands also go here),

• The tote bag, like the Macintosh Clipboard, can be used to carry information from one place to another,

• The tool holder , which is full of drawing and editing tools,

• A button to display the on-screen keyboard, and

• The trash truck to dispose of unwanted or unneeded items.

Though some might dismiss the interface as “cartoon-like,” Magic Cap’s items are big, clean, and familiar for several important reasons. First, LCD screens on communicators are not the clear bright CRTs that we’re used to on computers; small images and fine shadings are harder to see. Second, because many people don’t like having to reach for a stylus, Magic Cap is designed to be used with fingers and fingertips doing the touching (although a stylus also works), so having big objects to touch is vital. Finally, users learn and work better with simple, abstract images than with complex, realistic ones.

This desk scene demonstrates that communication is at the heart of Magic Cap. The center of the screen is occupied by the most important elements of communication: the in box (where newly arrived messages appear) and the out box where newly created messages go. Surrounding these are other important communicating software packages built into Magic Cap, including a notebook for free-form drawing and writing, a phone that you can use when your communicator has access to a phone line, and a file cabinet for organizing saved messages. The name cards file to the left of center contains postal and e-mail addresses for your associates as well as their telephone numbers.

Magic Cap also applies its communication abilities in more subtle ways. When you use the datebook to schedule a meeting, Magic Cap will offer to create an e-mail message telling the other attendees about the meeting. If the attendees have Magic Cap communicators, they can install the appointment in their datebooks automatically when they get the message, and even generate an RSVP message that comes back to you. If you create a drawing in the notebook, you can mail that page to a colleague’s communicator.

These features - an inviting, graphical interface, careful attention to how people use the machine, and a standardized hardware platform - demonstrate Magic Cap’s kinship with the Macintosh. The similarities to the Macintosh don’t end at the human interface though, as we’ll see in the next section.

In Magic Cap, Everything Is An Object

The original Macintosh was also designed with consistency and limited resources in mind. The original Macintosh team’s answer provided a “toolbox” in ROM that supplied programmers with many of the common user interface elements. Magic Cap follows this same path by providing all of its object classes in ROM for developers to build on.

Every Magic Cap object descends from class Object, thus inheriting the memory management commands, the ability to be encoded and decoded for transmission to another communicator, tools for reading and writing its own data, and debugging code. New classes may also inherit from Linkable, which allows you to build lists of arbitrary objects.

Magic Cap builds on the foundation classes to create Viewable objects and their subclasses. Anything that gets drawn on the screen and anything that the user can touch is there because of a viewable. Viewable’s subclasses include Button, Control, Card, Scene, Form, Color, TextField, and Coupon.

When you look at the Desk scene, you can see several viewables at work. (Each different screen in Magic Cap is known as a scene.) The name bar and control bar at the top and bottom of the screen are both viewables, as is the Scene object that lies between them. Each of these viewables contains multiple other viewables. The contained viewables are clipped to their container’s boundaries, and receive touches before their container does. We’ll see some more examples of viewables when we demonstrate how to build a Magic Cap package later in this article.

Objects, Memory, and Magic Cap

The Magic Cap runtime system has to perform three basic functions: manage objects in memory, execute operations against those objects, and handle any errors that might arise.

Since objects may be created and destroyed quickly within a communicator’s limited memory, the runtime system has to work to fill in gaps left by old deleted objects. Thus, just as the Macintosh has handles which allow it to rearrange blocks of memory on the fly, Magic Cap has object IDs. Each object ID is a 32-bit value that uniquely identifies an object within a package. When you use an object ID, Magic Cap’s object runtime quickly and efficiently converts it into a pointer to the object. Because an object ID isn’t an actual pointer to an object, the runtime system is free to move the object around in memory to minimize memory fragmentation and thus make room for new objects.

The runtime system also controls how code gets access to data. Magic Cap objects are structures that define both data elements and a set of functions that operate on the data. The data elements are called fields, and the functions are called operations. Most objects define operations that read and write specific fields, these are called attributes. Under most circumstances, an object doesn’t access its fields directly but uses either attributes or the special Field operation inherited from Object.

Since a personal communicator is designed to keep all of its permanent user data in RAM, the runtime system also works to protect this data. Every communicator contains a block of persistent RAM which is preserved when the communicator is turned off. (This memory is standard low-power static RAM, so either the main battery, backup battery, or AC power has to be connected.) Persistent RAM is protected from change through a set of internal routines provided by Magic Cap. Packages can’t write directly to persistent memory; instead, packages write changes to a buffer area of memory. Magic Cap updates persistent memory from this buffer area periodically, ensuring that packages don’t corrupt structures in persistent memory. Because persistent memory is protected from direct change, writing to it is somewhat slower than if memory were not protected, but essential user data is safe.

As a performance enhancement, Magic Cap requires a second kind of RAM that is not protected from change and does not retain its contents when the main power shuts off. This transient memory is implemented using low-power dynamic RAM. Transient memory is useful for objects that are created and destroyed within the scope of an existing operation, objects that can be recreated from persistent data, and other temporary objects. If your package uses transient memory, it must be prepared to recreate any objects stored there if the communicator shuts off or is reset.

Magic Cap gathers objects into clusters. Each cluster is similar to a Macintosh heap; it has a master block that refers to each of the objects in the cluster. Each object ID refers to a master block and contains an index number into that block. Unlike the Macintosh, clusters may cover several disparate area of memory. (In other words, a single cluster might include both the RAM built into a communicator and the RAM on an inserted PCMCIA card.) A package has both a package persistent and package transient cluster, and may define additional clusters for its own use. Packages also have access to the system persistent and system transient clusters so they can access system data and call system operations.

The system also maintains a shadow cluster for objects in ROM. If the user decides to modify an object in ROM (e.g. changing the background color in the Desk scene), that object is copied into the ROM shadow cluster and modified. The runtime system looks for objects in the shadow clusters before checking ROM. This allows the user to customize any part of the system. This also allows General Magic to patch code in the ROM for software enhancements and upgrades.

A package’s clusters are all gathered into the context for that package. Only one context may be active at a time. If the user moves from package to package or the preemptive kernel switches execution from one package to another, the context will be switched to that of the current package. The use of contexts and object IDs isolate packages from each other and thus protects both the developer and the user.

Executing Operations

Executing an operation against an object requires both an object ID for that object and the name of the operation to execute. The runtime system will search through the object’s class then its superclasses until it finds the appropriate operation and then will execute the code. (Magic Cap draws a distinction between a method and an operation - a method is the code that implements an operation, thus the Method keyword at the start of our code examples.)

Magic Cap packages are written in C with some object extensions, so executing an operation looks just like a standard C function call. The only thing that distinguishes executing an operation from a C function call is the object’s ID in the first parameter. This is shown in the code below. In this code, we’re first asking the SimpleAgent class to create an instance of itself in transient memory. (The trailing “_” in the sample code denotes a class.) This ability is inherited from Object. We then extract the text of our message object and copy it into transient memory. Finally, we use an attribute to put our newly copied text into the agent’s message field and return the agent’s object ID to the caller.

Method ObjectID
AgentSender_MakeAgent(ObjectID self, ObjectID messageText)
{
    // Create an “agent” object which will carry a message to another
    // user.  Return the agent’s ObjectID to the caller.
 ObjectID agent, message;
 
    // Create one object of class SimpleAgent in transient memory
 agent = NewTransient(SimpleAgent_, nil);
    // Read the contents of our message (passed in messageText)
    // and make a duplicate in transient memory.
 message = CopyTextTransient(messageText);
    // Give the copied message to the agent
 SetMessage(agent, message);
 
 return agent;
}

Magic Cap also supports intrinsic functions which aren’t bound to a particular class and which use a fast dispatching scheme. Certain common system and utility functions are implemented as intrinsics, and are called if they were regular C functions. (The difference is that Magic Cap locates the intrinsic’s code through its dispatching mechanism so intrinsics can be patched later in life. Most C compilers and linkers call functions by their addresses which makes later patching difficult or impossible.)

Error Handling

Since communicators hold important personal information and have no separate mass storage, they must recover gracefully from programming errors without losing data. To simplify error handling and make sure it can detect any errors that a package doesn’t, Magic Cap incorporates exception handling.

Exception handling isn’t new, but if you aren’t familiar with it here’s the idea: before executing some code that might fail, a routine can add an exception handler to a list in the system. When a subsequent routine fails, it creates an exception object containing information about the failure and passes it to a system routine which throws the exception. Throwing an exception passes control to the last exception handler installed, resetting the stack pointer and the processor’s registers along the way. (Receiving an exception is also known as catching the exception.) The exception handling routine can look at the specific exception and decide whether to fix the problem or to pass the exception to the next handler in the list.

Magic Cap’s exceptions are all subclasses of Exception so a package can define its own exceptions. An exception handler may specify that it catches all exceptions or only those of a particular class. Calling Try() or CatchAll() installs a handler which catches all exceptions. Calling Catch(exception: Object) installs a handler which catches a specific class of exceptions. If your code wants to signal an exception, it should call Fail(exception: Object). Exception handlers are removed from the list in two ways: explicitly, or by catching an exception. Calling Commit() removes the most recently installed handler.

Method ObjectID
MyCardClass_ExceptionDemo(ObjectID self)
 {
    // “volatile” is a C keyword which turns off some optimizations.  In particular, 
    // we want to make sure the following two ObjectIDs are allocated on the stack.  
    // This is a prerequisite for variables that are used in an exception handler.
 volatile ObjectID formOwnerCard = nilObject;
 volatile ObjectID requestedItem = nilObject;
 
 ObjectID exc;   // caught exception
 
    // Push an exception handler on the list, then continue execution.  Pushing the 
    // handler returns nilObject, catching an exception brings control back to here and
    // returns a non-nil object ID.
 if ((exc = CatchAll()) == nilObject)
 {
 requestedItem = NewPreferred(MyItemClass_, nil);

    // Set up a form as the "current form".  We want to use exception handling
    // around this so we can reset to the previous "current form" if any subsequent 
    // operation fails
 formOwnerCard = BorrowForm(self, true);
 
    // do something that might fail...
 
    // Reset the "current form" to its old value
 ReturnForm(self, formOwnerCard, true);
    // We’re at the end of the code that might fail, so remove the exception handler.
 Commit();
 } else {
    // Something went wrong.  If we changed the "current form", 
    // restore the old form.  If we allocated memory, dispose of it.
 if (formOwnerCard != nilObject)
 ReturnForm(self, formOwnerCard, true);
 Destroy(requestedItem);
 requestedItem = nilObject;
    // We’ve handled this exception completely.  If we want 
    // another handler to know about this problem, use Fail(exc);
    // to propagate the exception to our caller
 }
 return requestedItem;
}

Inter- and Intra-Package Communication

Magic Cap’s memory protection services are useful, but what if your package wants to access information in the system or another package? If the system (or a package) places an object ID into a special list, packages can refer to that object by its position in the list instead of using an actual object ID. This alternate form of object ID is called an indexical. Indexicals are a powerful tool in Magic Cap - packages can use them to hold package-specific global variables and to export selected objects for other packages to use. Packages can also use system indexicals for well-known global objects. The system provides indexical values for nearly everything: images, input devices, text styles, colors, sounds, system error messages, line styles, windows, objects describing the system’s current state, and so on. System indexicals deliver a treasure chest of objects for packages.

Packages not only get to read indexicals, but packages also get to replace indexicals with their own object references. Packages can change both Magic Cap’s appearance and behaviors in this way. For example, an enhanced Calendar program could replace the Datebook viewable on the desk or the Datebook object itself with a custom version.

Packages can also export code. Developers can release the class numbers for classes defined in their packages and the citation codes used to identify their packages to Magic Cap. Given these two pieces of information, a developer can instantiate objects using the classes defined in another package while leaving the original package untouched.

Graphics in Magic Cap

Magic Cap’s graphics system is built around Viewable and its subclasses. Magic Cap already includes viewables for most things that you want to draw: bitmapped images, text, shapes, lines, boxes, arbitrary paths, lists of other items, and so on.

The fundamental viewable in most packages is a Scene which contains the package’s other viewables as its subviews. Each viewable acts much as a Macintosh GrafPort does: it sets up a clipping area within its bounds and supplies a local coordinate system. Each viewable is also responsible for drawing itself when Magic Cap requests it; like the Macintosh, Magic Cap keeps track of which viewables are “dirty” and need redrawing. Magic Cap also buffers the screen image through an intermediate bitmap so that drawing is always flicker-free.

While any viewable can respond to the user’s touch, some viewables have been specialized for just this purpose:

Icons go to a destination scene when touched

Gadgets open a target window (which may contain additional viewables)

Buttons execute some code directly

SimpleActionButtons invoke an operation on a target object.

We’ll discuss viewables at greater length in a future article.

Other Ways To Program Magic Cap

Not all of the code on a communicator has to be compiled 68349 code. Magic Cap also interprets two additional languages - Magic Script and Telescript. We’ve already described Telescript as a language for building distributed systems and the language upon which AT&T built PersonaLink Services. Magic Script is a powerful yet easy to use scripting language built into Magic Cap. Magic Script gives developers direct access to selected classes and operations, so developers can use it to control packages without writing C code. In fact, there is a one-to-one correspondence between Magic Script statements and Magic Cap operations.

Building a Package

Let’s put all of this knowledge to work in constructing a new Magic Cap package. At a minimum, package development involves three files:

packageName.Def which defines the custom classes for a package

• Objects.Def which resembles a Macintosh Rez source file in that it lists the code and data objects that go into a package.

packageName.c which implements the methods for the classes defined in packageName.Def.

These files are built into a package using a standard Macintosh C compiler and linker, and General Magic’s custom ObjectMaker program. Object Maker performs several functions while building a package: it creates C calling interfaces for the classes in packageName.Def, it compiles the descriptions in Objects.Def into actual objects, and it merges the compiled and linked C code into the final package. Magic Developer, General Magic’s fundamental development environment, runs all of these tools within Apple’s Macintosh Programmer’s Workshop.

Magic Developer is part of the standard Magic Cap Software Development Kit. The development kit includes a special Developer’s edition of Magic Cap which runs on any Macintosh with a 68881 FPU (or a Power Macintosh with an emulated FPU.) This kit also includes several sample packages, a code browser, and online documentation.

One of the sample packages is EmptyPackage: a package which has the name bar, control bar, and an empty scene in between. Many packages begin life as duplicates of EmptyPackage. One such package is MT-Fortune, MacTech Magazine’s automated psychic advisor. Pressing a button in the package delivers a randomly selected “fortune cookie”-style message to the screen.

Construct a user interface in Magic Cap

One of the first tasks in developing a new package is laying out the user interface elements. Every copy of Magic Cap can be set to use construction mode. This reveals a magic hat full of components for customizing the interface or building new packages. Opening the components section of the Magic Hat gives us both a button and a text box which we’ll place into our scene.

The button and text box provided by the Magic Hat don’t fit our needs precisely - the button has the wrong name and the box is too small. We can fix this by touching the tool holder in the control bar and selecting the Authoring tools. These tools allow us to move, stretch, and duplicate objects as well as “tinkering” with the appearance and behavior of each object. (The tinker tool is represented by a small wrench in the tools window.) We can also change nearly any piece of text by creating a text coupon from the keyboard and dropping it on the desired object. We used the authoring tools to stretch and center the text box and to change the button’s name from “button” to “get fortune.”

Write the changes in Object Maker format.

Our original Objects.Def file doesn’t contain these new interface objects, so we have to describe them in the file somehow. The developer’s version of Magic Cap can take a package and “dump” all of its objects into a new Objects.Def file. We’ll do that now, and see that two new objects have been added to the end of the file:

Instance Button 'get fortune' 14;
           next: (TextField 15);
       previous: nilObject;
      superview: (Scene 'MT-Fortunes' 10);
        subview: nilObject;
 relativeOrigin: <-2.0,90.0>;
    contentSize: <88.0,21.0>;
      viewFlags: 0x70101200;
     labelStyle: {60,13}; // (TextStyle 8767)
          color: 0xFF000000;
       altColor: 0xFF000000;
         shadow: nilObject;
          sound: {33,11}; // (Sound 'Touch’ 289)
          image: nilObject;
         border: {120,19};  // (BorderImage 'But1Up’ 213)
End Instance;

Instance TextField 15;
           next: nilObject;
       previous: (Button 'get fortune' 14);
      superview: (Scene 'MT-Fortunes' 10);
        subview: nilObject;
 relativeOrigin: <-5.0,-32.0>;
    contentSize: <236.0,129.0>;
      viewFlags: 0x700D1200;
     labelStyle: {60,13}; // (TextStyle 8767)
          color: 0xFF000000;
       altColor: 0xFF000000;
         shadow: nilObject;
          sound: nilObject;
         border: {120,103}; // (BorderImage 1512)
     fieldFlags: 0x01040000;
      dataStore: nilObject;
      baseStyle: {60,1};  // (TextStyle 8734)
End Instance;

Two things become obvious when you first look at these objects: they’re subviews of the scene (see the superview field), and they’re connected in a doubly-linked list. This is typical of viewables.

The next, previous, and superview fields contain typical references to other numbered objects in the same package or references to nilObject (Magic Cap’s way of saying “this field intentionally left blank.”) However, if you look at the button’s sound field or either border field, you’ll see an unusual value in curly brackets, e.g., {60,1}. These values refer to system indexicals, the system-wide global variables we mentioned earlier.

Create supporting classes and objects.

We now have an interface for our package, but it doesn’t do anything special yet. We still need to create a class which can generate and display fortunes. Then we’ll attach a Magic Script script to the button to get a fortune from this class and drop the result into the text field. (We could simply subclass Button to create and display a fortune when pressed, but that would be less interesting.)

Creating a new class begins in another Object Maker file, MT-Fortunes.Def in this case. We’ll add the definition for a new class which can generate and return fortunes on demand.

Define Class FortuneMaker;
 inherits from Object;
 
// Two data values: a block of characters that contains all of our fortunes (separated by 
// newlines) and a number which refers to the fortune currently being displayed.
 field fortunes:  Text, getter, setter;
 field fortuneNum:  Unsigned;

// An attribute used for reading and writing the “fortunes” field above.
 attribute Fortunes: Text; 

// A bit of code to select and return a fortune.  The options after “Text” make this 
// operation visible to Magic Script.
 operation GetFortune(): Text, safe, common, scriptable;
End Class;

This class includes a long text object which contains all of the possible fortunes, an integer which stores an ID number for the last fortune returned, and attributes to read and write the text string. This class also defines an operation to generate and return a new fortune string. The suffix safe, common, scriptable makes this operation available to Magic Script so we can demonstrate scripting later.

Now that we have a template for the class, we must write its GetFortune operation. MT-Fortunes.c contains this code:

Method ObjectID
FortuneMaker_GetFortune(ObjectID self)
{
 ObjectID newFortune = nilObject;
 ObjectID ourFortuneText;
 TextRangeselectedLine;
 short  numLines;
 unsigned newFortuneNum;
 
    // Get a reference to our "fortune" field, which is a Text object,
    // then count the lines in this field
 ourFortuneText = Fortunes(self);
 numLines = Lines(ourFortuneText);
 
    // Pick a new fortune randomly, checking to make sure that it
    // isn’t the same fortune we’re already displaying
 for (;;) {
 newFortuneNum = ShortRandom() % numLines + 1;
    // Read our "fortuneNum" field without using an attribute
 if (newFortuneNum != Field(self, fortuneNum)) {
    // Store the new value
 SetField(self, fortuneNum, newFortuneNum);
 break;
 }
 };

    // Select a random line in this field and build a text 
    // object in transient memory containing the selected text.
 LineToTextRange(ourFortuneText, newFortuneNum, false,
     &selectedLine);
 newFortune = CopyTextRangeTransient(ourFortuneText,
 &selectedLine);
 
 return newFortune;
}

This code reveals several facts about Magic Cap programming. First, note that the object references are all untyped object IDs. Magic Cap defers object type checking until runtime. Next, we’re using Fortunes() which is a getter attribute that reads our fortunes field. We requested one of these by appending getter to the field in MT-Fortunes.Def. We didn’t request an attribute for fortuneNum, so we’re using the built-in functions Field() and SetField() to read and write this field. Finally, we’re returning our result by creating a new Text object in transient memory. Since we’ll take this object and copy its contents elsewhere, we didn’t need to allocate it in persistent RAM.

We now have the definition and code for a class, but our package doesn’t actually contain any objects of this class. We need to go back to Objects.Def and add a FortuneMaker object:

Instance FortuneMaker 17;
     fortunes: (Text 'fortunes' 18);
   fortuneNum: 0;
End Instance;

Instance Text 'fortunes' 18;
       text: 'You will meet a tall, dark stranger\n';
End Instance;

The above lines add our object to the package, but the package doesn’t have any way to refer to them. If a package needs to refer to specific objects, most programmers create a list of references to those objects and place them into one of the package indexicals. Just as a system indexical represents an object available from anywhere in Magic Cap, a package indexical represents an object available from anywhere in the package. We’ll put our FortuneMaker object into a list then install it into one of our software package’s indexical lists.

Instance ObjectList 'Indexicals' 16;
         length: 1;
      entry1: (FortuneMaker 17);
End Instance;

Instance SoftwarePackage 'MT-Fortunes' 1;
         length: 32;
    dateCreated: 49771;
    timeCreated: 0xFFFFFFFF;
   dateModified: 49771;
   timeModified: 0x041B65B0;
         author: {141,1}; // (ProviderAddressCard 874)
    installList: (ObjectList 'Install' 2);
      receivers: (ObjectList 'Receiver' 3);
   installFlags: nilObject;
installParameters: nilObject;
 installTargets: nilObject;
   autoActivate: true;
       citation: (Citation 4);
      publisher: {141,1}; // (ProviderAddressCard 874)
persistentShadowSize: 0;
persistentChangesSize: 0;
  transientSize: 0;
gotoActionSelector: 3.s;
         hidden: false;
   dontSaveData: false;
 copyOnActivate: false;
 dontDeactivate: false;
     needsReset: false;
systemPackageReserved6: false;
    // skipped a range of reserved fields, all of which are nilObject
systemPackageReserved16: false;
         entry1: nilObject;
    // skipped more empty fields
         entry6: (ObjectList 'Standard Places' 5);
    // skipped more empty fields
         entry9: (ObjectList 'Objects With Help' 6);
        entry10: (ObjectList 'Help On Objects' 7);
    // skipped more empty fields
        entry13: {40,7}; <$f"Garamond-Book">// (Scene 'Hallway’ 88)
    // skipped more empty fields
        entry25: (ObjectList 'Indexicals' 16);
    // skipped more empty fields
End Instance;

Note: We didn’t have to set up any of the fields of this object except for the indexical we installed. The values were copied from EmptyPackage, the sample used to start the MT-Fortune package.

Add the script

Since we want to tie the FortuneMaker object to the button with a script, it’s time to compile the package and run it. Once we’re in the package, we can select the tinker tool, hold down the option key, and touch the button to edit its script.

Magic Script is extremely easy to use. Touching the ink well at the right side of the window inserts a new statement into the script, with the entries for the command and the responder (the object which will execute the operation corresponding with this command) underlined. You can touch an underlined object to change it, or touch an underlined field to get a pop-up menu of all possible commands that go there. While a full discussion of Magic Script is beyond the scope of this article, you can get all of the details from the documentation in the software development kit.

Once we’ve added a script to the button, our package is nearly done. The package should be dumped back into Objects.Def so we can build future versions which contains the script. Objects.Def also contains information about the package’s authors and some help text; these should be updated. Still, you’ve seen enough that you should be able to begin experimenting with the Magic Cap software development kit as soon as you get one.

Starting Down The Road To Magic Cap

Now that you’ve taken a look inside Magic Cap, you may be wondering how you can bring your software to this powerful new platform. General Magic has teamed up with Metrowerks to release Magic Cap software development tools by the summer of 1995. You can receive information about General Magic’s developer program and a notice when the development kits become available by sending electronic mail to dev-info@genmagic.com or by calling (408) 774-4000.

 

Community Search:
MacTech Search:

Software Updates via MacUpdate

NetShade 6.3.1 - Browse privately using...
NetShade is an anonymous proxy and VPN app+service for Mac. Unblock your Internet through NetShade's high-speed proxy and VPN servers spanning seven countries. NetShade masks your IP address as you... Read more
Dragon Dictate 4.0.7 - Premium voice-rec...
With Dragon Dictate speech recognition software, you can use your voice to create and edit text or interact with your favorite Mac applications. Far more than just speech-to-text, Dragon Dictate lets... Read more
Persecond 1.0.2 - Timelapse video made e...
Persecond is the easy, fun way to create a beautiful timelapse video. Import an image sequence from any camera, trim the length of your video, adjust the speed and playback direction, and you’re done... Read more
GIMP 2.8.14p2 - Powerful, free image edi...
GIMP is a multi-platform photo manipulation tool. GIMP is an acronym for GNU Image Manipulation Program. The GIMP is suitable for a variety of image manipulation tasks, including photo retouching,... Read more
Sandvox 2.10.2 - Easily build eye-catchi...
Sandvox is for Mac users who want to create a professional looking website quickly and easily. With Sandvox, you don't need to be a Web genius to build a stylish, feature-rich, standards-compliant... Read more
LibreOffice 5.0.1.2 - Free, open-source...
LibreOffice is an office suite (word processor, spreadsheet, presentations, drawing tool) compatible with other major office suites. The Document Foundation is coordinating development and... Read more
f.lux 36.1 - Adjusts the color of your d...
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
VirtualBox 5.0.2 - x86 virtualization so...
VirtualBox is a family of powerful x86 virtualization products for enterprise as well as home use. Not only is VirtualBox an extremely feature rich, high performance product for enterprise customers... Read more
File Juicer 4.43 - Extract images, video...
File Juicer is a drag-and-drop can opener and data archaeologist. Its specialty is to find and extract images, video, audio, or text from files which are hard to open in other ways. In computer... Read more
Apple MainStage 3.2 - Live performance t...
MainStage 3 makes it easy to bring to the stage all the same instruments and effects that you love in your recording. Everything from the Sound Library and Smart Controls you're familiar with from... Read more

ReBoard: Revolutionary Keyboard (Utilit...
ReBoard: Revolutionary Keyboard 1.0 Device: iOS Universal Category: Utilities Price: $1.99, Version: 1.0 (iTunes) Description: Do everything within the keyboard without switching apps! If you are in WhatsApp, how do you schedule a... | Read more »
Tiny Empire (Games)
Tiny Empire 1.1.3 Device: iOS Universal Category: Games Price: $2.99, Version: 1.1.3 (iTunes) Description: Launch cannonballs and blow tiny orcs into thousands of pieces in this intuitive fantasy-themed puzzle shooter! Embark on an... | Read more »
Astropad Mini (Productivity)
Astropad Mini 1.0 Device: iOS iPhone Category: Productivity Price: $4.99, Version: 1.0 (iTunes) Description: *** 50% off introductory price! ​*** Get the high-end experience of a Wacom tablet at a fraction of the price with Astropad... | Read more »
Emo Chorus (Music)
Emo Chorus 1.0.0 Device: iOS Universal Category: Music Price: $1.99, Version: 1.0.0 (iTunes) Description: Realistic Choir simulator ranging from simple Chorus emulation to full ensemble Choir with 128 members. ### introductory offer... | Read more »
Forest Spirit (Games)
Forest Spirit 1.0.5 Device: iOS Universal Category: Games Price: $2.99, Version: 1.0.5 (iTunes) Description: | Read more »
Ski Safari 2 (Games)
Ski Safari 2 1.0 Device: iOS Universal Category: Games Price: $1.99, Version: 1.0 (iTunes) Description: The world's most fantastical, fun, family-friendly skiing game is back and better than ever! Play as Sven's sister Evana, share... | Read more »
Lara Croft GO (Games)
Lara Croft GO 1.0.47768 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.47768 (iTunes) Description: Lara Croft GO is a turn based puzzle-adventure set in a long-forgotten world. Explore the ruins of an ancient... | Read more »
Whispering Willows (Games)
Whispering Willows 1.23 Device: iOS Universal Category: Games Price: $4.99, Version: 1.23 (iTunes) Description: **LAUNCH SALE 50% OFF** - Whispering Willows is on sale for 50% off ($4.99) until September 9th. | Read more »
Calvino Noir (Games)
Calvino Noir 1.1 Device: iOS iPhone Category: Games Price: $3.99, Version: 1.1 (iTunes) Description: The film noir stealth game. Calvino Noir is the exploratory, sneaking adventure through the 1930s European criminal underworld.... | Read more »
Angel Sword (Games)
Angel Sword 1.0 Device: iOS Universal Category: Games Price: $6.99, Version: 1.0 (iTunes) Description: Prepare to adventure in the most epic full scale multiplayer 3D RPG for mobile! Experience amazing detailed graphics in full HD.... | Read more »

Price Scanner via MacPrices.net

Big Grips Lift Handle For iPad Air and iPad A...
KEM Ventures, Inc. which pioneered the extra-large, super-protective iPad case market with the introduction of Big Grips Frame and Stand in 2011, is launching Big Grips Lift featuring a new super-... Read more
Samsung Launches Galaxy Tab S2, Its Most Powe...
Samsung Electronics America, Inc. has announced the U.S. release of the Galaxy Tab S2, its thinnest, lightest, ultra-fast tablet. Blending form and function, elegant design and multitasking power,... Read more
Tablet Screen Sizes Expanding as iPad Pro App...
Larger screen sizes are gaining favor as the tablet transforms into a productivity device, with shipments growing 185 percent year-over-year in 2015. According to a new Strategy Analytics’ Tablet... Read more
Today Only: Save US$50 on Adobe Elements 13;...
Keep the memories. lose the distractions. Summer’s winding down and it’s time to turn almost perfect shots into picture perfect memories with Elements 13. And get the power to edit both photos and... Read more
1.4GHz Mac mini on sale for $449, save $50
Best Buy has the 1.4GHz Mac mini on sale for $50 off MSRP on their online store. Choose free shipping or free local store pickup (if available). Price for online orders only, in-store price may vary... Read more
12-inch 1.1GHz Gold MacBook on sale for $1149...
B&H Photo has the 12″ 1.1GHz Gold Retina MacBook on sale for $1149.99 including free shipping plus NY sales tax only. Their price is $150 off MSRP, and it’s the lowest price available for this... Read more
27-inch 3.3GHz 5K iMac on sale for $1849, sav...
Best Buy has the 27″ 3.3GHz 5K iMac on sale for $1849.99. Their price is $150 off MSRP, and it’s the lowest price available for this model. Choose free shipping or free local store pickup (if... Read more
Worldwide Tablet Shipments Expected to Declin...
Does Apple badly need a touchscreen convertible/hybrid laptop MacBook? Yes, judging from a new market forecast from the International Data Corporation (IDC) Worldwide Quarterly Tablet Tracker, which... Read more
Continued PC Shipment Shrinkage Expected Thro...
Worldwide PC shipments are expected to fall by -8.7 percent in 2015 and not stabilize until 2017, according to the latest International Data Corporation (IDC) Worldwide Quarterly PC Tracker data. The... Read more
Imminent iPhone 6s Announcement Leads To 103%...
NextWorth Solutions, with its online and in-store electronics trade-in programs including http://NextWorth.com, reports that it has experienced a 103 percent surge in quoted trade-in values over the... Read more

Jobs Board

*Apple* Music, Business Operations - Apple I...
Changing the world is all in a day039s work at Apple . If you love innovation, here039s your chance to make a career of it. You039ll work hard. But the job comes with Read more
WW *Apple* Retail Online Store: Customer In...
**Job Summary** The Apple Retail - Online Store is seeking an experienced web merchandising analytics professional to join the Customer Insights Team. The Web Read more
Senior Payments Security Manager - *Apple*...
**Job Summary** Apple , Inc. is looking for a highly motivated, innovative and hands-on senior payments security manager to join the Apple Pay security team. You will Read more
Software QA Engineer, *Apple* Pay Security...
**Job Summary** Imagine what you could do here. At Apple , great ideas have a way of becoming great products, services, and customer experiences very quickly. Bring Read more
Business Process Engineer ( *Apple* Online S...
**Job Summary** The Apple Online Support Planning team is looking for an experienced Business Process engineer to lead key business process improvement initiatives Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.