TweetFollow Us on Twitter

BeBox Intro
Volume Number:12
Issue Number:1
Column Tag:Cutting Edge Technologies

Opening the BeBox

A programmer’s introduction to the Be operating system

By Peter Potrebic and Steve Horowitz, Be Inc.

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

Introduction

Be, Inc. was founded in 1990 by Jean-Louis Gassée, former president of Apple Products, to design and build a new computing platform. The first product offered by the company is a multiprocessing computer called the BeBox. It contains two PowerPC 603 processors and a new, modern operating system.

This article will describe some of the philosophy behind the design of the BeBox. It will go into some detail explaining the system software architecture with an overview of the key components. The article also includes source code and a description of a sample application, to give you a feel for writing software on the BeBox. For more detailed information on Be and the BeBox, as well as a look at developer documentation, please visit our web site: http://www.be.com.

Design Philosophy

The BeBox was designed with the technology enthusiast in mind. As Jean-Louis is fond of saying, “Only the lunatic fringe will lead us to the truly innovative applications.” Every machine is programmable right out of the box, and comes bundled with programming tools from Metrowerks and full developer documentation. We do not expect that the BeBox will be your first computer - it will not run any Macintosh software nor will it run Windows. However, if you are excited by new technology, know how to write code, and have a pioneering spirit, the BeBox may have something to offer you. See Figure 1 for a screenshot showing a few running Be applications.

Figure 1. Sample screen shot

History has shown that it is difficult to predict the markets where a new computer might be successful. We believe that developers will lead us, and so our goal is to provide a unique set of system software features, a low-cost hardware platform, great development tools, and an extensive developer support program. Additionally, we plan to help our developers reach their potential customers by offering electronic distribution of their software on the Be web site. From all of this we hope to see new and innovative applications for markets we could not possibly envision.

The BeBox was designed by an extremely small team over approximately four years. We started with a clean slate and focused on a couple of key ideas. One of the fundamental design techniques was to give responsibility for each major system component to one person. By concentrating the decision-making process, the engineers were allowed a great deal of freedom without having to justify and get consensus for every design decision. However, since most of the components were interrelated there was enough informal interaction to assure that we were all on the same track. This approach allowed us to avoid some of the pitfalls of overdesign and resulted in what we believe is a simple, efficient, and fast set of system software components.

Another decision we made early on was to take a C++ light approach. We wanted to use an object-oriented programming language, but not necessarily to use every feature the language had to offer. Programmers need not be C++ experts to program the BeBox. This decision makes the system more approachable by a larger number of people with a variety of programming experiences. It is also fairly easy to absorb the Be class libraries and get a simple Be application up and running quickly.

System Software Overview

The design of the Be operating system is based around a client/server architecture, with a microkernel at the lowest level providing all the OS functionality used by the higher levels. The developer makes use of a set of client-side C++ class libraries and C functions to write Be applications.

The system software consists of a number of key components. Several servers are built on top of the kernel including an application server, storage server, network server, and media server. The servers run in separate protected memory areas and implement the majority of system functionality available from the C++ class libraries. The class libraries are broken up into a series of kits which export the functionality from the servers to the client applications. Among the kits available to Be applications are an application kit, interface kit, OS kit, device kit, media kit, midi kit, networking kit, and storage kit. The details of all of these kits are beyond the scope of this article. Instead, this article provides a brief summary of each server’s basic functionality, followed by a description of the major pieces in a simple Be application.

The Be kernel provides many fundamental system services to the higher-level servers including the ability to deal with multiple processors, true preemptive multitasking and multithreading, memory protection, shared memory, semaphores, virtual memory, shared libraries, and loadable drivers. The kernel scheduler supports multiple processors in a manner completely transparent to the application. This and other features of the kernel provide an extremely fast and efficient foundation upon which the rest of the operating system is built.

The application server is the main server with which applications communicate. It is in charge of all the window and view management, graphics rendering, font management, user interface interaction, event handling, and so on. One important aspect of the Be programming model implemented by the application server and interface kit is that every window in the Be system is given two separate threads. The application server maintains a thread on the server side, which communicates with a client-side thread running in the application’s address space. This allows all windows to update their contents and respond to user interaction asynchronously, and is a major factor in the overall responsiveness of the Be system. This also means that any multiwindowed Be application is automatically multithreaded and multiprocessing with little work from the developer. You can, of course, spawn more threads for your application using other classes in the application framework or the lower-level kernel functions.

Another important server is the storage server. It implements the built-in database functionality in the Be operating system. The storage server allows programmers to design tables that describe records, create and delete records, and receive notification of database changes. With the integrated database, every file on the BeBox has its own database record. This acts as an extensible storage system, allowing programmers to create unique tables containing whatever information they want about a file. The fields in these records (as defined by the table) are then searchable and viewable by all applications in the system. Additionally, the storage server implements a “live” query mechanism that allows any Be application to construct a query and then, if desired, get notified continuously of any changes to the set of records located by the query. This behavior is seen in the system Browser (an application akin to the Macintosh Finder) which is part of the operating system, but this service is available to all Be applications.

The network server provides basic system networking services. It implements the TCP/IP protocol stack and provides a socket interface resembling Berkeley sockets. There is also a PPP layer included in the server, and support for Ethernet. Standard networking tools such as ftp, ftpd, and telnet are included with the Be system.

The media server provides a set of tools for manipulating large streams of multimedia data. This server handles the transportation of buffers of media data through a pipeline of interested data handlers. Each handler can subscribe to a media stream. By subscribing, the handler is given a chance to manipulate or read the data as it passes through the system. The buffers are implemented as shared memory areas, which can be read by multiple applications in separate address spaces without having to copy the buffers between applications. Additionally, you can use the media server to synchronize separate media streams, using a global scheduling object that allows easy coordination of audio and video data.

Be Application Basics

A simple Be application will primarily make use of the features in the application kit and the interface kit. The core objects used by an application are BApplication, BWindow, BView, BMessage, and BLooper. BLooper (feel free to call it “blooper”) is the main object used to encapsulate thread spawning and message handling. Each BLooper object has its own thread that responds to messages sent to it by other objects. Since BApplication and BWindow both inherit from BLooper they are automatically message handlers running in their own threads.

Generally, a BApplication object is created first. It runs an event loop in the main thread of the application, and is used for basic messaging between applications. It can also be used to exchange messages with windows or other threads in your application. Additionally, the BApplication object receives notification of files to open at launch time or once the application is running. The BApplication object is the central control object from which other windows and objects are created and can be used to synchronize sharing of global objects within an application.

Most of the communication between threads, windows, and applications in the Be system is done using a BMessage object. A BMessage has the ability to contain an arbitrary number of “data” entries to pass information around, as well as a “what” field to tell the receiver what type of message it is receiving. BMessages are the fundamental objects used to share information between threads and applications. They are also used to implement drag-and-drop and the clipboard.

To actually display anything in your application, you must create a BWindow object and add a BView to it. Each window you create, by virtue of its BLooper inheritance, will spawn a new thread to handle drawing, messaging, and user interaction - without monopolizing your application’s main thread. Windows are also the containers of BView objects, and handle the display of any drawing that takes place in a view. A BWindow can contain multiple views and, in turn, views can contain other views. Each view has its own drawing environment and all drawing is automatically clipped to the bounds of the view. When a window needs updating, it calls the virtual Draw() function for all the views in the update region. Within Draw() other functions are used to render graphics primitives, such as bitmaps, lines, shapes, and strings. Most of the user interface components in the Be system such as buttons, scrollbars, menus, and others are derived from BView, and handle drawing and mouse events automatically.

There are many more classes in the Be application framework available to developers. The ones described above are simply the most fundamental to a Be application. They provide the basic functionality for an application that wants to launch and put up a window to do some drawing. Since the entire Be operating system is relatively small, it is easy for one person to understand it all. It is also easy to learn and to get an application up and running quickly in the Be environment.

The Bouncing Ball

Now let’s cut to the chase and explore a sample application. It seems that every new computer platform comes with a bouncing-ball demo. Each platform uses this application to show something particular or unique about itself. The bouncing-ball demo on the BeBox, called BeBounce, builds on this tradition - and add adds a unique twist.

The BeBounce application opens a small window that contains a single bouncing ball. The twist is that launching a second instance of the application opens a “gap” between the windows, the size and location being determined by their relative positions, and the ball is then able to bounce between the two “partner” applications. As either window is moved around the screen, the gap between the windows follows the motion, growing larger or smaller and moving around each window frame as dictated by Euclid (i.e. by geometry). See Figure 2. If the ball happens to enter the gap it is magically teleported to the other application.

Figure 2. The BeBounce application

In addition to showing some basic Interface Kit techniques, the BeBounce application demonstrates the straightforward way in which applications can communicate. As explained earlier, each Be application runs in its own address space and each window runs in a separate thread. Additionally, each application has a “main thread” represented by a BApplication object. The multithreaded nature of an application is inherited from the BLooper class. BLooper objects execute a message handling loop which responds to messages posted to the looper using its PostMessage function. The looper then dispatches those messages, in sequence, to the “target” BReceiver object by calling the virtual MessageReceived function. Note that BLooper is a kind of BReceiver so a looper can also receive messages.

The BeBounce application consists mainly of one object derived from BApplication (TBounceApp), one object derived from BWindow (TWindow), one BMessenger object, and one object derived directly from BLooper (TBall). In the Be system, BMessage objects can be sent around within an application. However, to send messages between applications a BMessenger object is needed. The messenger object is a one-way connection between two applications. In BeBounce, when the ball enters the gap a message is sent to the partner using the messenger object, literally passing the ball to the partner.

Let’s take a look at some code, starting with the main() function:

main(int argc, char* argv[])
{
    // to randomize the movement of the bouncing ball
 srand((long) sys_time());

    // make the new application object and start it running
 my_app = new TBounceApp();
 my_app->Run();

    // application is finished so cleanup and return
 delete my_app;
 return 0;
}

The basic idea is to create the application object and start it running. The Run() function returns when the application quits. The TBounceApp object is then deleted and the program returns. Most applications on the BeBox will have a similar main() function.

The application object

The BApplication object is the real launching point for most applications, and BeBounce is no exception. Here is the definition of the TBounceApp class:

class TBounceApp : public BApplication {
public:
 TBounceApp();
virtual ~TBounceApp();

virtual voidMessageReceived(BMessage *msg);
 void   InitPartner(thread_id tid);
 void   RemovePartner();
 bool   SendToPartner(BMessage *msg);
 bool   SendPosition(BRect rect);

private:
 TWindow*fWindow;
 BMessenger *fPartner;
};

The application constructor does several interesting things. First, when the application is launched it needs to determine how many instances of the BeBounce application are already running. Here is a portion of that function:

TBounceApp::TBounceApp()
 : BApplication(MY_SIGNATURE)
{
    ...  // some initialization code

    /*
     This version of BeBounce only supports 2 instances of the application running at 
     the same time.  So if there are already 2 instances running force a QUIT. */
 BList list;
 be_roster->GetThreadList(MY_SIGNATURE, &list);
 long app_count = list.CountItems();
 if (app_count > 2) {
 // only support 2 applications at a time
 PostMessage(QUIT_REQUESTED);
 return;
 }
 
    ...  // more initialization to be discussed below
}

The above code uses the be_roster (aka “rooster”) object, a system-wide object that, among other things, maintains information on all running applications. The roster returns a list of all running applications that have the signature MY_SIGNATURE. If there are more than two instances of the application already running, this instance simply quits.

If this is the first instance of the application it simply creates the window:

 
 if (app_count == 1) {
    // The first instance of BeBounce will have a ball.
 fWindow = new TWindow(wpos, "Bouncing 1", TRUE);
 } else {
    ... // the second instance of BeBounce
 }

If there are two instances, things are trickier:

 
 if (app_count == 1) {
    ...  // the first instance of BeBounce
 } else {
    // This is the second instance of the BeBounce app
 fWindow = new TWindow(wpos, "Bouncing 2", FALSE);

    ...  // determine which of the 2 instances is myself and which is the partner.

    // tid is the “thread id” of our partner!
 InitPartner(tid);




    /* Send the introductory message along with my thread
     id and location in screen coordinates. */
 BMessage *msg = new BMessage(BB_HELLO);
 msg->AddLong("thread", Thread());
 msg->AddRect("rect", wpos);
 SendToPartner(msg);
 }

Here, as before, the application creates the window. It then determines the thread id of its partner application and initializes a BMessenger object for communicating with the partner. The code that creates the messenger is in the utility member function TBounceApp::InitPartner():

void TBounceApp::InitPartner(thread_id tid)
{
 if (fPartner) // BB_HELLO race condition
 return;

    // establish a ‘messenger’ as the link to our partner
 fPartner = new BMessenger(MY_SIG, tid);
 if (fPartner->Error() != NO_ERROR) {
 delete fPartner;
 fPartner = NULL;
 } 
}

It is important to note that this function handles the race condition surrounding the BB_HELLO message. Imagine launching two instances of BeBounce at the same time. The call to GetThreadList() could return two instances to each application. In this case both applications will behave as the second instance and both will send BB_HELLO messages. This will result in TBounceApp::InitPartner being called twice by each application. In this particular application the only result would be a small memory leak of the first BMessenger object. Understanding these types of race conditions is one of the critical aspects of designing software for the BeBox. Note that the code does not handle three applications launching simultaneously. In this case all three applications might decide that they are the “third wheel” and quit.

After creating the messenger, the code constructs a BB_HELLO BMessage object. The next step is to add the thread id of this application to the message. The other application uses this data to construct its own BMessenger. The window position is also added to the message so that the partner knows this window’s initial position. The message is sent using the utility function TBounceApp:: SendToPartner. Other than error handling SendToPartner contains just one line:

bool TBounceApp::SendToPartner(BMessage *msg)
{
    ...  // error handling
 fPartner->SendMessage(msg);
    ...  // error handling
}

The final steps of the constructor are to create a “Stop Ball” menu item and show the window on screen:

 
    // inside the TBounceApp constructor
    /*
     A little bit of menu code.  Add a ‘Stop Ball’ menu item to the application menu 
     (found in the Dock window) By default items in the “app” menu post messages to 
     the application.  In this case the message should be “targeted” to the window, not 
     the app.
    */
 BPopUpMenu *menu = AppMenu();
 BMenuItem*item = new BMenuItem("Stop Ball",
 new BMessage(BB_STOP), 'K');
 item->SetTarget(fWindow);
 menu->AddItem(item);

 fWindow->Show();
    // this is the end of the TBounceApp constructor

The protocol that the applications use to communicate with each other is most apparent in the TBounceApp:: MessageReceived() member function:

void TBounceApp::MessageReceived(BMessage *msg)
{
 switch (msg->what) {
 case BB_HELLO:
    ...  // a second BeBounce application is saying hello!
 break;
 case BB_GOODBYE:
    ...  // our partner is quitting
 break;
 case BB_WINDOW_MOVED:
    ...  // partner moved, and has given us its new position
 break;
 case BB_BALL:
    ...  // we’ve just been given the ball
 break;
 }
}

Receiving a BB_HELLO message means that a second instance of the application is introducing itself. Here is the code for handling this message:

 
 case BB_HELLO:
 if (fWindow->Lock()) {
    /*
     A new instance of BeBounce was just launched
     and sent us the introductory message.
    */
 InitPartner(msg->FindLong("thread"));
 
    // Initialize our partner’s current location.
 pos = msg->FindRect("rect");
 fWindow->PartnerMoved(pos);
 
    // Tell our new partner our current location.
 pos = fWindow->Frame();
 SendPosition(pos);
 fWindow->Unlock();
 }
 break;

This code initializes a BMessenger using TBounceApp::InitPartner() and places the thread id in the message. The partner’s window position is also retrieved from the message and saved. Finally the code determines the position of its window and sends that to the partner. The communication link between the two applications is now open.

The next message is BB_GOODBYE. This message is sent as BeBounce applications quit. The code for responding to this message is quite simple:

 case BB_GOODBYE:
 if (fWindow->Lock()) {
    // Our partner is quitting.
 RemovePartner();
 if (msg->HasBool("ball"))
 fWindow->AddBall();
 fWindow->Unlock();
 }
 break;

The partner is removed using the function TBounceApp::RemovePartner, the complement of the InitPartner function seen earlier. In addition, if the quitting partner currently had the ball a new ball is added to this application’s window. This ensures that there is always a bouncing ball. The code that sends the BB_GOODBYE message is described in the section on the window.

The final two messages sent between the applications, BB_WINDOW_MOVED and BB_BALL, are status messages informing the partner that either the window moved or the ball has moved through the gap. Here is the code, without further explanation:

 
 case BB_WINDOW_MOVED:
    /*
     Our partner is informing us that it moved.  This message is continually 
     generated as the other window is being moved.  TWindow::PartnerMoved                                        
    redraws the window to reflect the new position.
    */
 if (fWindow->Lock()) {
 pos = msg->FindRect("rect");
 fWindow->PartnerMoved(pos);
 fWindow->Unlock();
 }
 break;

 case BB_BALL:
    // Our partner just passed us the ball.
 if (fWindow->Lock()) {
 BPoint speed = msg->FindPoint("speed");
 float  rel_loc = msg->FindFloat("rel_loc");
 fWindow->AddBall(rel_loc, speed);
 fWindow->Unlock();
 }
 break;

The window object

The next class of interest is TWindow, a subclass of BWindow. In the BeBounce application the window is responsible for managing the ball and for informing the partner application of particular events (see description of TBounceApp::MessageReceived() above). The window also presents the UI for this application so there is some description of how applications can create and manage UI on the BeBox. In the Be operating system a BWindow object provides an area that can display and retain rendered images. A BWindow by itself cannot draw, only BViews can draw. However, a BView must belong to a window in order to draw. These two classes work hand in hand.

Here is a portion of the TWindow class definition:

class TWindow : public BWindow {
public:
 TWindow(BRect frame, const char *title,
 bool with_ball);
virtual ~TWindow();

virtual voidMessageReceived(BMessage *msg);
virtual boolQuitRequested();
virtual voidFrameMoved(BPoint new_position);
 void   AddBall();
 void   AddBall(float rel_location, BPoint speed);
    ...  // a few more member functions

private:
 void   DrawOffScreen(BView *v);
    ...  // a couple more private member functions and then
    // some private data members
};

The TWindow constructor contains several code fragments worth discussing:

TWindow::TWindow(BRect frame, const char *title, bool ball)
 : BWindow(frame, title, TITLED_WINDOW, NOT_RESIZABLE)
{
    ...  // some initialization removed

 if (ball)
 AddBall();

    /*
     The drawing takes place in the view fOffView that was added to the offscreen 
     bitmap fBitmap.  In this way we’ll do the drawing offscreen and then just blit the 
     result to the screen.
    */

 fBitmap = new BBitmap(b, COLOR_8_BIT, TRUE);
 fOffView = new BView(b, "", 0, WILL_DRAW);

 fBitmap->Lock();
 fBitmap->AddChild(fOffView);
 DrawOffScreen(fOffView); // draw the initial contents offscreen
 fBitmap->Unlock();

    /*
     This view is added to the visible window.  Its only role is to blit the offscreen 
     bitmap to the visible window.
    */
 fMainView = new TBitmapView(b, fBitmap);
 AddChild(fMainView);

    ... // some initialization removed
}

Here is the first look at how windows and views are created and used on the BeBox. To get smooth animation TWindow uses an offscreen bitmap (a BBitmap object) and a basic BView object (fOffView) for the rendering. It is in the context of this view that all the actual drawing occurs. The graphics primitives, like BView::FillRect() and BView::FillArc() that create the effect of a ball bouncing off real walls, takes place in this offscreen view. The last view created, an instance of the TBitmapView class, is simply the helper view that blits the bits from the offscreen bitmap into the onscreen window. Since the TBitmapView class (a subclass of BView) is so simple here is all its code:

TBitmapView::TBitmapView(BRect frame, BBitmap *bitmap)
 : BView(frame, "", FOLLOW_NONE, WILL_DRAW)
{
    /*
     The only job of this view is to blit the offscreen bits into the onscreen view.
    */
 fBitmap = bitmap;
}

void TBitmapView::Draw(BRect update)
{
    // blit the bitmap with source and dest rectangle ‘update’
 DrawBitmap(fBitmap, update, update);
}

As stated previously, a BWindow is a kind of BLooper, which in turn is a kind of BReceiver. As such, a window runs in its own message loop and it can receive messages. A BView is also a kind of BReceiver so it too can receive messages. A message posted to a window (using PostMessage) can be “targeted” to either the window or a view contained within that window. Because of the connection between windows and views, a view typically receives messages in the context of its window. Said another way, the handling of messages targeted to a view occurs in the window’s thread.

On the BeBox, user actions on the keyboard and mouse are turned into BMessages, called interface events. However, these messages are not handled by MessageReceived(), like the BeBounce message BB_HELLO. Instead, interface events are dispatched to a set of virtual functions corresponding to the action. Here are a few of those functions:

BView::MouseDown() // mouse down event in that view
BView::KeyDown() // keydown event while that view was
    // the “focused” view
BView::FrameResized// the view changed size
BWindow::FrameMoved()// the window position moved
BWindow::QuitRequested()  // click on close-box of window

It turns out that in BeBounce only two interface events are of interest, the FrameMoved and QuitRequested events. The system repeatedly generates the FrameMoved event as a window is being dragged. This event is of interest because as the window moves, so should the gap that exists between the partner windows. Here is the code for responding to the FrameMoved event:

void TWindow::FrameMoved(BPoint new_pos)
{
    /*
     As window is moved around the screen we inform our
     partner of our new location.  Also update our gap.
    */
 fMyFrame = Frame();
 if (my_app->SendPosition(fMyFrame))
 WindowsMoved(fMyFrame, fPartnerFrame);
}

This code gets the window’s current location and sends it to our partner so that our partner can update its gap. TBounceApp::SendPosition() sends the BB_WINDOW_MOVED message to the partner (see the code in TBounceApp::MessageReceived() for the code that handles this message). Only if we have a partner will TBounceApp::SendPosition() return TRUE. In this case the code calls the TWindow::WindowsMoved() function, updating this window’s gap. As BeBounce windows move about the screen everything is kept in synch.

The other event of interest is generated when the user clicks on the close box of the window. In BeBounce closing the window should also cause the application to quit. This means that the window has to listen for the QuitRequested event:

bool TWindow::QuitRequested()
{
    /*
     The window was asked to quit/close.  Send a message to our partner, giving him 
     the ball if we’ve currently got it.
    */
 BMessage *m = new BMessage(BB_GOODBYE);
 if (fBall) {
 fBall->Quit();
 fBall = NULL;
 m->AddBool("ball", TRUE);
 }
 my_app->SendToPartner(m);

    // Tell the app to go ahead and quit.
 my_app->PostMessage(QUIT_REQUESTED);
 return TRUE;
}

The first thing to do when the QUIT_REQUESTED message is received is to tell our partner good-bye, passing the ball along if it is in our possession. It would not be polite to quit with ball in hand. Please note that the TBounceApp:: SendToPartner() does the correct thing if there is no partner. Next the window posts a message to the application telling it to quit as well. The return value of TRUE causes to window to immediately quit.

The ball

The last object to describe is the ball. Several factors influenced the design of the ball. It is desirable to keep the ball independent from the window, yet they still need to communicate with each other. Also, the ball periodically requires time to simulate motion. One design that accommodates these guidelines is to construct a subclass of BLooper called TBall. This means that the ball has its own thread and it is able to receive messages. Here is part of the class definition:

class TBall : public BLooper {
public:
 TBall(TWindow *window, BRect bounds,
 BPoint center, float radius,
 BPoint speed);

 void   Draw(BView *view);
virtual voidMessageReceived(BMessage *msg);

 void   Lock();
 void   Unlock();
 void   SetGap(float start, float end);
 void   SetEnabled(bool state);
 ...  // a couple other member functions

private:
 void   NextPosition(bool *hit, float *angle);
 void   Tick();

 BLockerfLock;
 TWindow*fWindow;
    ...  // a bunch of data members for “state” like size,
    //    speed/direction, postion, etc
};

Having a thread per ball would not scale to an application that had 1000 bouncing balls, but for demonstration purposes it works well.

Most of the constructor for the TBall class is fairly simple, initializing the various data members. The most interesting aspect of the constructor is that it starts the looper thread running and posts the first BB_TICK message to get the animation working:

 
TBall::TBall(TWindow *window, BRect bounds, BPoint center,
 float radius, BPoint speed)
 : fLock()
{
    ...  // initialize parameters like size, location, and speed
 
    /*
     Get the looper thread rolling.  Unlike the call to BApplication::Run, which does not 
     return, this call does return.
    */
 Run();
 
    // post initial message to get animation going
 PostMessage(BB_TICK);
}

The TBall’s MessageReceived function handles the BB_TICK message:

void TBall::MessageReceived(BMessage *msg)
{
 switch (msg->what) {
 case BB_TICK:
 Lock();
 Tick();
 Unlock();

    ...  // sleep for a little bit of time
 
    // post next message to continue animation
 PostMessage(BB_TICK);
 break;
 }
}

The Lock() and Unlock() calls shown above deserve further explanation. The BeBounce application was designed so that the window “communicates” with the ball, not by posting messages to it, but by calling specific member functions; see the definition of the TBall class. For example, one of those functions is TBall::SetGap():

void TBall::SetGap(float start, float end)
{
 Lock();
 fGapStart = start;
 fGapEnd = end;
 Unlock();
}

A consequence of this design is that two separate threads access the same data structure, so some form of synchronization is required. The BLocker (also known as “blocker”) class provides this synchronization. Imagine if the locking was not present. Then in the middle of the looper thread’s calculation to determine if the ball hit that gap the window thread could come along and change the gap. This would lead to undefined behavior. Code in TBounceApp:: MessageReceived() locks the window for this same reason.

An alternate design would have the window sending messages to the ball. In this case, locking would not be an issue. The act of posting messages implicitly provides the synchronization needed. The ball’s looper thread can only handle one message at a time. In this example the trade-off might be the latency of messages changing the “gap” position or starting and stopping the ball, with the Stop Ball menu item. The preferred method should be determined on a case by case basis. For educational purposes the BeBounce application uses both styles of programming.

Back to the BB_TICK message. Most of the work in animating the ball is done in TBall::Tick(), and most of that code is the math and geometry needed to animate the bouncing ball and determine when the ball either hits a wall or flies through the gap. As little of this code is specific to the BeBox we will not go into any more detail except to show how the ball draws.

void TBall::Tick()
{
    ...  // move ball to new position

    // inform the window to redraw the window.
 BMessage *msg = new BMessage(BB_DRAW);
 msg->AddRect("update", updateRect);
 fWindow->PostMessage(msg);

 if (hit_hole) {
    /*
     The ‘gap’ was hit.  So we package up the info like speed and relative location, 
     which gives our partner enough information to have the ball appear in the 
     correct place.
    */
 BMessage *msg = new BMessage(BB_HIT_HOLE);
    ...  // adding info to message
 fWindow->PostMessage(msg);
 }
}

The TBall::Tick() function moves the ball to the next position and then posts a message to the window telling it to redraw itself. Additionally, if the ball hits the “gap” a BB_HIT_HOLE message is posted to the window:

When the window receives the BB_DRAW message (in its MessageReceived function) it asks the ball to draw itself in its current location. The drawing is done by TBall::Draw():

void TBall::Draw(BView *view)
{
    // The balls draws itself in the given view
 Lock();
 rgb_colorc = view->FrontColor();

 view->SetPenSize(1.0);
 view->SetFrontColor(150, 30, 30);
 view->FillArc(fCenter, fRadius, fRadius, 0.0, 360.0);
 view->SetFrontColor(c);
 Unlock();
}

The view passed to TBall::Draw() is the same view that was added to the offscreen bitmap in the TWindow’s constructor, so the ball is being drawn offscreen. The window then gets the TBitmapView (described earlier) to blit the offscreen image onto the screen.

The code for handling the BB_HIT_HOLE message is in TWindow::MessageReceived:

void TWindow::MessageReceived(BMessage *msg)
{
 switch (msg->what) {
 case BB_HIT_HOLE:
    /*
     The ball is telling us that it just hit the
     hole.  So it should get sent to the partner.
    */
 BMessage *m = new BMessage(BB_BALL);
 fBall->Lock();
 m->AddPoint("speed", msg->FindPoint("speed"));
 m->AddFloat("rel_loc", msg->FindFloat("rel_loc"));
 fBall->Unlock();

    // send the ‘ball’ to our partner
 my_app->SendToPartner(m);

    // delete the ball from this window
 fBall->Quit();
 fBall = NULL;
 
    // redraw the window
 Update();
 break;
 
    ...  // handling of other messages
 }
}

The window responds to the BB_HIT_HOLE message by sending the BB_BALL message to the partner application giving it the ball. It puts the necessary information into the message so that the partner can create the new ball in the correct position, with the correct speed and direction. Finally, the window deletes the ball.

That is how the BeBounce application works. Obvious improvements to BeBounce would be to support more than two applications, multiple windows within the same application, and multiple balls. Another useful addition would be a separate control window with some controls for things like ball speed. All of these enhancements are feasible given the design of the Be operating system. To support an arbitrary number of applications each application would maintain a list of partners, having a BMessenger object to each one. Multiple balls in a window could either communicate with one another (for hit testing purposes) directly or use the window object as the arbitrator.

Hopefully this sample application has provided a taste of developing an application for the BeBox. The next question is: How do Be applications get built?

Development Tools

You write applications for the Be environment using tools supplied by one of the leading tool suppliers in the industry - Metrowerks. Currently the preferred development environment is a Macintosh with the latest version of CodeWarrior and Be-supplied headers and libraries. Using CodeWarrior on the Macintosh, a developer can write, compile, and link a Be application. Of course, you have to transfer the application to the BeBox before it will run. Since the BeBox supports ftp and includes a command-line shell (based on bash) the process of quitting your app, bringing over a new one from the Macintosh, and running it on the BeBox can be completely automated. There is also support for using the source-level debugger on the Macintosh to debug an application while it is running on the BeBox. Metrowerks is currently working on a port of the full CodeWarrior Integrated Development Environment to the Be operating system. This native version of CodeWarrior, along with full technical developer documentation, will be shipped with every BeBox.

Conclusion

This is just a small taste of the BeBox. We have presented an overview of the Be operating system along with some sample code to give you the general feel of Be application development. To learn more about the Be operating system, please visit our web site, where we provide on-line versions of our developer documentation as well as information about our product and company. We encourage developers interested in joining our support program to mail in the developer form, which you can find on the web site.

Be has many plans for the future. We are continuing to improve and add features to the Be operating system and development tools. We are also working on future versions of the BeBox, which will include more and faster processors - including a machine with four PowerPC 604 chips for the horsepower hungry.

We hope this article has succeeded in whetting your appetite for Be programming. We look forward to seeing all the incredible applications we know developers will write for the BeBox.

 
AAPL
$98.38
Apple Inc.
+0.00
MSFT
$43.89
Microsoft Corpora
+0.00
GOOG
$585.61
Google Inc.
+0.00

MacTech Search:
Community Search:

Software Updates via MacUpdate

Drive Genius 3.2.4 - Powerful system uti...
Drive Genius is an OS X utility designed to provide unsurpassed storage management. Featuring an easy-to-use interface, Drive Genius is packed with powerful tools such as a drive optimizer, a... Read more
Vitamin-R 2.15 - Personal productivity t...
Vitamin-R creates the optimal conditions for your brain to work at its best by structuring your work into short bursts of distraction-free, highly focused activity alternating with opportunities for... Read more
Toast Titanium 12.0 - The ultimate media...
Toast Titanium goes way beyond the very basic burning in the Mac OS and iLife software, and sets the standard for burning CDs, DVDs, and now Blu-ray discs on the Mac. Create superior sounding audio... Read more
OS X Yosemite Wallpaper 1.0 - Desktop im...
OS X Yosemite Wallpaper is the gorgeous new background image for Apple's upcoming OS X 10.10 Yosemite. This wallpaper is available for all screen resolutions with a source file that measures 5,418... Read more
Acorn 4.4 - Bitmap image editor. (Demo)
Acorn is a new image editor built with one goal in mind - simplicity. Fast, easy, and fluid, Acorn provides the options you'll need without any overhead. Acorn feels right, and won't drain your bank... Read more
Bartender 1.2.20 - Organize your menu ba...
Bartender lets you organize your menu bar apps. Features: Lets you tidy your menu bar apps how you want. See your menu bar apps when you want. Hide the apps you need to run, but do not need to... Read more
TotalFinder 1.6.2 - Adds tabs, hotkeys,...
TotalFinder is a universally acclaimed navigational companion for your Mac. Enhance your Mac's Finder with features so smart and convenient, you won't believe you ever lived without them. Tab-based... Read more
Vienna 3.0.0 RC 2 :be5265e: - RSS and At...
Vienna is a freeware and Open-Source RSS/Atom newsreader with article storage and management via a SQLite database, written in Objective-C and Cocoa, for the OS X operating system. It provides... Read more
VLC Media Player 2.1.5 - Popular multime...
VLC Media Player is a highly portable multimedia player for various audio and video formats (MPEG-1, MPEG-2, MPEG-4, DivX, MP3, OGG, ...) as well as DVDs, VCDs, and various streaming protocols. It... Read more
Default Folder X 4.6.7 - Enhances Open a...
Default Folder X attaches a toolbar to the right side of the Open and Save dialogs in any OS X-native application. The toolbar gives you fast access to various folders and commands. You just click... Read more

Latest Forum Discussions

See All

Note Review
Note Review By Jennifer Allen on July 29th, 2014 Our Rating: :: TOO SIMPLEiPhone App - Designed for the iPhone, compatible with the iPad Note is a note taking app that’s a little too short on features to be worth its asking price... | Read more »
Chainsaw Warrior Goes on Sale & Ther...
Chainsaw Warrior Goes on Sale & There’s a Chance to Win a Copy of the Original Board Game Posted by Jennifer Allen on July 29th, 2014 [ permalink | Read more »
It Came From Canada: Tiny Tower Vegas
If you go to a casino, you might make a lot of money. If you run a casino, you’re guaranteed to make a lot of money. The choice seems pretty obvious. So while waiting for your shady real estate deals to move forward, get prepared with Tiny Tower... | Read more »
Z Hunter Review
Z Hunter Review By Lee Hamlet on July 29th, 2014 Our Rating: :: RIGHT ON TARGETUniversal App - Designed for iPhone and iPad While it might not necessarily break new ground, Z Hunter has enough tricks up its sleeve to ensure that... | Read more »
Huge Update Comes To Duet, Adding 48 New...
Huge Update Comes To Duet, Adding 48 New Stages Posted by Jennifer Allen on July 29th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Sharknado: The Video Game Available Now....
Sharknado: The Video Game Available Now. Seriously. Posted by Rob Rich on July 29th, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Frog Orbs 2 Review
Frog Orbs 2 Review By Nadia Oxford on July 29th, 2014 Our Rating: :: THIS MAGIC IS A TAD MONOTONOUS Universal App - Designed for iPhone and iPad Frog Orbs 2 is repetitive, but younger players should enjoy it nonetheless.   | Read more »
Puzzix Review
Puzzix Review By Jennifer Allen on July 29th, 2014 Our Rating: :: NICE IDEAUniversal App - Designed for iPhone and iPad A little like Tetris, Puzzix is all about piecing together blocks and watching them vanish. It could do with... | Read more »
Cannonball eMail is Now Live – Works Wit...
Cannonball eMail is Now Live – Works With Gmail, Yahoo, Outlook, Hotmail, and AOL Posted by Jessica Fisher on July 29th, 2014 [ permalink ] | Read more »
To The End Review
To The End Review By Lee Hamlet on July 29th, 2014 Our Rating: :: A VICIOUS CYCLEUniversal App - Designed for iPhone and iPad To The End will test players’ patience, timing, and dedication as they try to navigate all 13 levels in... | Read more »

Price Scanner via MacPrices.net

WaterField Unveils 15″ Outback Solo & 13″...
Hard on the heels of Apple’s refreshed MacBook Pro Retina laptops announcement, WaterField Designs has unveiled a 15-inch version of the waxed-canvas and leather Outback Solo and a 13-inch version of... Read more
New Roxio Toast 12 Delivers Digital Media Pow...
Roxio Toast 12 is a hub for sharing digital media to virtually any platform or device. has introduced two new additions to its Roxio Toast product family – Roxio Toast 12 Titanium and Roxio Toast 12... Read more
The lowest prices on leftover Retina MacBook...
Best Buy has dropped prices on leftover 13″ and 15″ Retina MacBook Pros by up to $300 off original MSRP on their online store for a limited time. Choose free local store pickup (if available) or free... Read more
Apple Updates MacBook Pro with Retina Display...
Apple today updated its MacBook Pro with Retina display with faster processors and double the amount of memory in both entry-level configurations. MacBook Pro with Retina display features a Retina... Read more
Up to $250 price drop on leftover 15-inch Mac...
B&H Photo has dropped prices on 2013 15″ Retina MacBook Pros by as much as $250 off original MSRP. Shipping is free, and B&H charges NY sales tax only: - 15″ 2.3GHz Retina MacBook Pro: $2349... Read more
Updated MacBook Pro Price Trackers
We’ve updated our MacBook Pro Price Trackers with the latest information on prices, bundles, and availability on the new 2014 models from Apple’s authorized internet/catalog resellers as well as... Read more
Apple updates MacBook Pros with slightly fast...
Apple updated 13″ and 15″ Retina MacBook Pros today with slightly faster Haswell processors. 13″ models now ship with 8GB of RAM standard, while 15″ MacBook Pros ship with 16GB across the board. Most... Read more
Apple drops price on 13″ 2.5GHz MacBook Pro b...
The Apple Store has dropped their price for the 13″ 2.5GHz MacBook Pro by $100 to $1099 including free shipping. Read more
Apple drops prices on refurbished 2013 MacBoo...
The Apple Store has dropped prices on Apple Certified Refurbished 13″ and 15″ 2013 MacBook Pros, with model now available starting at $929. Apple’s one-year warranty is standard, and shipping is free... Read more
iOS 8 and OS X 10.10 To Support DuckDuckGo As...
Writing for Quartz, Dan Frommer reports that Apple’s forthcoming iOS 8 and OS X 10.10 operating systems version updates will allow users to select DuckDuckGo as their default search engine. He notes... Read more

Jobs Board

Sr Software Lead Engineer, *Apple* Online S...
Sr Software Lead Engineer, Apple Online Store Publishing Systems Keywords: Company: Apple Job Code: E3PCAK8MgYYkw Location (City or ZIP): Santa Clara Status: Full Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Sr. Product Leader, *Apple* Store Apps - Ap...
**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
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.