Issue 3-13, April 1, 1998

Be Engineering Insights: News From the Front

By William Adams

When I was dating my now wife Anita way back when, she bet me that I couldn't stop making jokes for 30 minutes. I buttoned up my wit and buckled down for a half hour of witless conversation. At the end of the allotted time, I burst forth with a stream of jokes and witticisms like an uncorked fire hydrant. Well, I haven't written a Newsletter article for quite a few months now and I'm brimming with so many ideas I hardly know where to start...

I've been training for a triathlon for the past few weeks, and a couple of times I've taken my daughter Yasmin along on 20 mile bike rides. Let me tell you, that's no easy feat! Up and down hills, huffing and puffing, Yasmin poking me in the butt, kicking the backs of my feet, making it harder. But just when I think I have no more energy left, the end is in sight. I make it up the last hill and look back across the landscape of miles, puff out my chest and crow with the knowledge that at least Yasmin thinks I'm a major stud muffin. Speaking of stud muffins, have you been programming the BeOS and using threads lately?

If you've done any BeOS programming, you've probably been using threads whether you intended to or not. A much-utilized mechanism for communicating actions in a BeOS program is the BLooper object. BLooper greatly simplifies life, and in conjunction with BHandler, is the basis of our messaging and scripting capabilities. You have probably seen or used a number of times some code that looks like this:

BMessage msg('doit');
aLooper->PostMessage(&msg);

Also, in the looper or handler of your choice, there is similar code in MessageReceived(BMessage* msg) that does something interesting in response to the particular message. Using BLooper and posting messages is a good thing to do in many situations because it keeps the threading and deadlocking model pretty straight. No fuss, no muss, no dirty semaphores. But as our mantra goes, the BeOS offers pervasive multithreading, symmetrical multiprocessing, etc. So aren't you anxious to spread your threads and bring your machine to its processing knees cleanly?

Many times when you program with BLooper you're engaging in a design pattern known as observer/observable. That is, you have some data that changes from time to time, and you want various other components to notice the changes and react accordingly. I have found it useful to explicitly name this interface and create a couple of classes to implement it. First, the BObservable class:

I've left out the constructor and a couple other things to save space.

virtual status_t SendNotificationOf(constint32 notice,
                                    void *data);

status_t AddObserver(BObserver *, void *data);

status_t RemoveObserver(BObserver *, void *data);

A BObservable is any object that wants other objects to know what it's doing. In the Model/View/Controller world of SmallTalk, this would probably be the Model. One example of an observable object might be a TV tuner. Whenever the channel changes, some other object, notably a display object, might be interested so that it can display a new channel number. The Observable would call its SendNotification() method and the BObserver will have its ReceiveNotice() method called. Speaking of BObservable, here is its interface:

virtual bool IsInterestedIn(constint32 notice,
                            BObservable *observable);

virtual void  ReceiveNotice(constint32 notice,
                            BObservable *observable,
                            void *data);

The primary thing to note is the ReceiveNotice() method. This is similar to a message filter in that a single integer value is sent. One difference from a BMessageFilter is that a BObserver can tell a BObservable what messages it wants by using the InterestedIn() method. The BObservable can call this at any time, and the BObserver can report true or false as to whether it is currently interested in receiving such notifications. Another difference from a BMessageFilter is that BObservers can be hooked up to as many BObservable objects as they want. You'll notice that one of the parameters to ReceiveNotification() is the BObserver that sent the message. Using this, the BObserver can perform appropriate actions based on which BObservable sent the message.

The interfaces of BObservable and BObserver say absolutely nothing about threading. Where and when threads are used is completely left up to the individual implementations. Is this good or bad? Well, it gives you some choices, and with choices come responsibilities. Here's the scissors -- please don't run with them.

How About Another Example

I have a CD Player. There is one object, BCDROMDrive, which can act as the Observable model. It will send out notices whenever a disk changes, tracks change, or any of the other transport commands are activated.

enum ECDNotices {
  CD_STOPPED,
  CD_PLAY,
  CD_FASTFORWARD,
  CD_REWIND,
  CD_CHANGED
  ...
};

There is no visual interface within this object. Then there is the BCDROMObserver, which is responsible for displaying up to date disk information. I don't want the Observer to slow down the Observable in any way, so I've decided that when I receive notifications, I'll just put them in a local queue, and return immediately so the Observable can carry on with what it was doing:

void
BCDROMObserver::ReceiveNotice(constint32 notice,
                              BObservable *observable,
                              void *data)
{
  fMessageQueue.push(notice);
}

Separately, I have a thread that is running in a loop, pulling messages off the queue:

void
BCDROMObserver::Run()
{
  while(!timeToQuit)
  {
    fMessageQueue.wait();
    int32 aMsg = fMessageQueue.pop();

    // Massive switch statement to do things
    // based on what the message is.
  }
}

There are two things of note here. My message queue implementation is thread safe, so I don't have to explicitly lock and unlock the queue to do the push and pop. Also, there is other code that makes the Run() method occur in its own thread.

In essence, this gives you behavior similar to that of BLooper, with a little bit more control of what type of messages you send around, and where you use threads, ports, and semaphores. In this particular case my messages are always just a 32-bit integer. Speed and memory management are a concern, so I wanted tighter control of when and where things are allocated and how much data is being passed around. Also, this application does not receive messages from the outside world, nor does it try to send them outside, so leaving BLooper is a reasonable thing to do.

Some sample code that uses this technique can be found at: ftp://ftp.be.com/pub/samples/R3/support_kit/observable.zip

There's the BObserver/able code, some threading code, some thread safe queue code, and a little sample app that actually uses it. I would love to write more, but as any good comedian knows, get off the stage while they're still laughing.

But before I go, I've been working on some lightweight UI type things. If you are a developer who has an interface which is highly customized with lots of artwork, and you're wondering how to make nice sliders, buttons, and other doohickeys, and keep it all fast and responsive, please drop me e-mail, we may have something you can use: wadams@be.com.

That's all the news from the front.


Getting Press

By Dave Johnson

Here is another in my series on making money by developing products for the BeOS. Getting press is an important subject so I have promised not to include weird jokes, not to knock Apple, and not to use the word "skank."

In order for you to make money selling your software, your potential customers need to find out about your product. Aside from placing a demo of your product on the BeWare web site, the most effective and least costly way to get info about your product out to customers is through magazine articles and reviews, TV and radio mentions, newspaper articles, and articles in trade journals and targeted publications in specific market segments. An example of an article in a targeted publication would be an article about a new BeOS MIDI sequencer in a publication of interest to musicians rather than a general computer magazine.

I can't encourage you strongly enough to make an effort to reach the press. When the customer gets information from the press it comes with greater credibility than when it comes from you. And if you are sending press releases this helps bring attention to the BeOS in general as well as letting the world know that there are lots of great applications available. The more the BeOS becomes well known the better that helps you with your product sales.

Who Is This Article For?

This article is for freeware and shareware authors as well as commercial publishers. Freeware authors want press because you can put it on your resume. Shareware and commercial publishers will benefit because increased exposure means increased sales. And Be benefits when you get press attention as long as they spell our name right (which isn't hard to do).

How To Get Press Attention

To get press attention you send press releases to editors and reporters, and follow up.

The Format of the Press Release

Press releases follow a standard format. At the top you should put contact information, name, phone and e-mail. If you are sending information that can be released immediately, you should put "For Immediate Release" at the top.

You should have a headline, and possibly a sub-headline. The content of the press release consists of several paragraphs of information, often ending with general information about your company. The bottom of the first page should either have a centered "MORE" if there is another page, or "###" if it is the end of the press release. The top of the next page should have the title and page number.

Writing a Press Release

Your press release serves two purposes. It is your chance to get the interest of a busy editor or reporter, and it provides the necessary information while framing the story.

Think of a press release as a form of direct mail advertising but not as an ad. The structure and requirements are actually very similar to a direct mail piece. Like a direct mail piece, your press release is going to be quickly skimmed and then a decision is made whether to write a story. The editor/reporter is reading and thinking "Is this a story that will interest my readers?" But...

A Press Release is Not an Ad!

You want to provide information, not do a hard sell. It is bad form to try to do a sell job on the press. Working with the press is about getting accurate information to the reader, and editors and reports will appreciate that.

The Headline

When viewed in this direct mail context you can see that the headline can be the most important part of your press release. It must entice the editor or reporter to read further, while accurately conveying your message. The headline should be a very short and to-the-point statement telling what the press release is about while maintaining the interest of the reader. You should think of it as a headline in a newspaper—as the way you want your story to appear in the publication.

You can also have a sub-headline that conveys more information or additional information.

Note: Use "BeOS" somewhere in the headline. The BeOS is hot right now; editors are interested in it and they know their readers are interested in it. Normally you would be competing with hundreds of press releases for attention. Putting "BeOS" in the title should help you break through the clutter.

The Content

The first paragraph has to contain the important information of interest to the reader. If the headline is interesting enough for the reporter/editor to read further you want to clinch it with the 1st paragraph. It begins with a location and a date in parenthesis. "Menlo Park, CA, (March 31, 1998)." You should tell your story quickly, briefly and interestingly while providing necessary information. You've got interest if they're reading this paragraph and you need to turn the interest into a desire to write a story.

If it is decided that a story will be written, the press release will be read more closely and will serve to frame the story. The content must satisfy the customer who is interested in what you're selling and reading. It no longer needs to be enticing, just informative. If the reader is looking at this part at all it's likely an article will be forthcoming.

Is Everything In There?

Be sure that your press release contains all the necessary information. Does it tell the version and price of the product? Do you make clear the availability—when and where and how to order or get more information. Is there a demo available? Special hardware requirements? Be sure to include your web address and please mention Be's BeWare page address.

Include A Blurb About The BeOS!

The BeOS is new, so not everyone is going to know what you're writing about when you say your product runs on the BeOS. Along with "BeOS" in the title you should include a paragraph describing the BeOS, where to get more info about it, and where to get it. And it certainly doesn't hurt if you describe the various ways your application runs better on the BeOS.

A Blurb About The BeOS

The BeOS (available from Be, Inc. at the be web site ) is a new, modern, high-performance, media-optimized personal computer operating system that runs on Intel Pentium-based and PowerPC desktop computers. The BeOS incorporates pervasive multithreading, symmetric multiprocessing, protected memory, a 64-bit journaling file system, client-server based architecture and an object-oriented API. The BeOS delivers the performance required for multimedia applications, with unprecedented user responsiveness and enabling real-time manipulation & feedback capabilities in applications.

End With General Company Info

Often press releases end with general information about your company itself. When was the company established, markets, products, personnel, etc...

Where to Send the Press Release

Send the press release to the publications where you hope to see articles about your product. Remember to include special-interest publications as well as computer publications. If you have a fishing product send the press release to Field & Stream as well as ALL the computer magazines.

There are several approaches to this. One approach is to get a general press list and send the press release to everyone on the list. DP Directory is an excellent source of press lists and I have included their URL below. You can get lists for e-mailing or postal mailing from them. We have used these lists and we recommend them.

Another way is to purchase a copy of each publication you wish to target and locate the masthead. The masthead is a page that lists the editors and reporters that put the publication together. Often they list the area of specialty for each editor. You can send the press release to everyone on the list or only to selected people. You can call the publication and ask who the right editor would be for your information.

Some PR experts suggest that you send press releases to only one person at each news source, others say you it is a good idea to make sure everyone knows about you. My feeling is that the more people that know about your products the better. They will be writing articles in the future and might remember your product, they might even move on to new publications and introduce your product to new people there.

Be Available

After the press release goes out be sure you are available in case you get calls. Give priority to editors who say they are "on deadline."

Press Tracking Chart

You can wait and be pleasantly surprised by any articles that appear or you can be proactive and take command of the effort. Set up a press tracking chart listing each publication and contact, and call them to find out what is scheduled with what publication dates. (The call can also serve as a nudge to please put you on the schedule.)

You can also assign yourself certain important targets that you deem necessary for your PR effort. These targets can then be contacted until you can get a commitment for something to appear in the publication.

After a while a picture will emerge of what press attention is coming over time. With the knowledge of what articles will appear and when they will be published you can coordinate your marketing efforts, such as what months you want to have your product advertised in software catalogs, etc...

Never Lie or Mislead

Honest information is the Big Kahuna of press relations. If you mislead the press you lose your credibility and they will not forgive you. This is not the way to handle problems that come up. Don't try to cover up problems, just admit them and talk about what you plan to do about them. Don't try to be clever. Remember that the press is about getting accurate information to the readers. If you are going to be in business for the long term you have to keep the respect of the press.

Reviews

The press release should tell who editors should contact to obtain review copies of your product.

When sending out review copies it's a good idea to provide a reviewer's guide. A reviewer's guide is a document describing important features, what you think the customer will use the product for, and other things you want to be sure a reviewer knows. It might contain a script for use of the product, like a demo script

A review is usually objective and fair. And sometimes a review turns out to be an opportunity for you to learn new ways that your product needs improvement. :-) A fair reviewer will call you if problems come up and give you an opportunity to explain a possible misunderstanding.

Often when an article is underway you will be asked if you can provide the names of some customers. Writers like to get the customer's perspective and some good quotations because the reader can relate to other users.

Tips

If you are new to this, you don't need to be afraid to ask editors questions about how to talk to them, and what you should do to get articles scheduled. This is about building a relationship with the press. But here's some tips. After you have sent the press release it's useful to follow up with a quick call—but respect deadlines. When a deadline approaches everyone at a publication gets extremely busy. If you call someone and they say they are under deadline don't try to press your point. Ask them when to call and then get off the phone.

Learn a publication's deadlines. It is useful to know when information needs to arrive at a publication and the lead time of the publication. Magazines can have lead times of several months. Weeklies have a cutoff day the preceding week—nothing gets into the publication after that day. If you want something in the next week's issue you need to know what day the info needs to be there.

Demo Tours

If you want to make a more serious effort to get press attention you should schedule a "demo tour." This is where you schedule to visit a publication. Contact the appropriate editor and ask if you can schedule to come visit and demonstrate your product and discuss it with one or more members of the staff of the publication. Often you'll find yourself with several people in attendance. This is a good way of establishing a good personal relationship with members of the press.

Your Web Site

Finally, you should establish a press section of your web site. For ideas on how to set this up check out Be's press page located at: www.be.com/aboutbe/pressreleases/index.html and Microsoft's press page located at: www.microsoft.com/corpinfo/todaynews.htm

Additional Resources

Here are some URLs of good information about working with the press:


Developers' Workshop: BeOS Programming Basics, Part 2

By Eric Shepherd

In my last article, "BeOS Programming Basics, Part 1", we looked at creating a basic BeOS application with a single window containing a single view. This week, we'll expand on that a bit by adding a menu bar to our window and showing how to handle user selections in menus.

Before we get to that, though, I thought I'd begin by clarifying a point that often confuses people, and briefly review the coordinate system the BeOS uses. If you have a rectangle:

rect.Set(0, 0, 5, 7);

This rectangle's top-left corner is at (0, 0) and its bottom-right corner is at (5,7). It looks something like this:

012345
******0
******1
******2
******3
******4
******5
******6
******7

Because the coordinates you specify are inclusive, the top row of the rectangle contains the points (0,0), (1,0), (2,0), (3,0), (4,0), and (5,0). If you add those up, you can see that the rectangle is six pixels wide and eight pixels high.

If you call Width() on this rectangle, the result will be 5 (5-0). Height() returns 7 (7-0). This is the source of most of the confusion. If you want to know the actual width or height in pixels of a rectangle, you need to add one to the result of these two functions.

Now on to this week's project: Menu World. Menu World is based on the Hello World code from my last article; in fact, if you haven't read that article, I recommend you visit the Be web site and read it (once again, that's at: www.be.com/aboutbe/benewsletter/volume_II/Issue7.html#Workshop. You might also want to download the source code for Hello World and have a look at that as well: ftp://ftp.be.com/pub/samples/intro/obsolete/helloworld_article.zip

Also, before we get started, I should point out that this article uses BMessages (which is how user interactions are reported to your application) without going into a lot of detail on how they work. The next article in this series will discuss messaging in more detail.

Here are the includes for Menu World:

#include <Application.h>
#include <Window.h>
#include <View.h>
#include <MenuBar.h>
#include <Menu.h>
#include <MenuItem.h>
#include <string.h>

Let's start with main(), which is very simple and self-explanatory. The only reason I'm including it is because it's slightly different from what it was when I wrote the previous article—it now allocates the HelloApp object on the stack, which is the C++-approved way of doing things (I love progress). Note that because it's allocated on the stack, we don't have to remember to delete it, because it's done automatically when main() returns.

void main(void) {
  HelloApp theApp;    // The application object
  theApp.Run();
}

We also use the following constants for the BMessage command codes for each of the menu items that Menu World will provide:

constuint32 MENU_FILE_NEW        = 'MFnw';
constuint32 MENU_FILE_OPEN       = 'MFop';
constuint32 MENU_FILE_CLOSE      = 'MFcl';
constuint32 MENU_FILE_SAVE       = 'MFsv';
constuint32 MENU_FILE_SAVEAS     = 'MFsa';
constuint32 MENU_FILE_PAGESETUP  = 'MFps';
constuint32 MENU_FILE_PRINT      = 'MFpr';
constuint32 MENU_FILE_QUIT       = 'MFqu';
constuint32 MENU_OPT_HELLO       = 'MOhl';

Now let's take a look at the HelloView class, which has one new method and some private data added since last time. This isn't very exciting stuff yet, but we'll experiment with menus a bit when we get to that point:

class HelloView : public BView {
  public:
    HelloView(BRect frame);
    virtual void Draw(BRect updateRect);
    void SetString(const char *s);

  private:
    char message[128];
};

The SetString() function has been added to let you configure what message the HelloView class draws. The message is stored in the message string, as follows:

void HelloView::SetString(const char *s) {
  if (strlen(s) < 127) {
    strcpy(message, s);
  }
}

SetString() just makes sure the string isn't too long, then copies it into the message field.

The Draw() function has to be changed to use the message string:

void HelloView::Draw(BRect updateRect) {
  MovePenTo(BPoint(20,75));      // Move pen
  DrawString(message);
}

Finally, the HelloView constructor has to be updated to initialize the message string:

HelloView::HelloView(BRect frame)
      : BView(frame, "HelloView", B_FOLLOW_ALL_SIDES,
        B_WILL_DRAW) {
  SetString(STRING_HELLO);
}

Things start to get really interesting when we look at the updated HelloWindow class:

class HelloWindow : public BWindow {
  public:
    HelloWindow(BRect frame);
    virtual bool QuitRequested();
    virtual void MessageReceived(BMessage *message);

  private:
    BMenuBar  *menubar;
    HelloView *helloview;
};

In the HelloWindow class, the MessageReceived() function is new since last time. Notice also that we now have fields for stashing pointers to the menu bar and the HelloView attached to the window.

Let's go through these methods one by one. The constructor has been updated to create and install the menu bar. Here it is:

HelloWindow::HelloWindow(BRect frame)
      : BWindow(frame, "MenuWorld", B_TITLED_WINDOW,
        B_NOT_RESIZABLE | B_NOT_ZOOMABLE) {
  BRect r;
  BMenu *menu;
  BMenuItem *item;

  // Add the drawing view

  r = Bounds();
  r.top = 20;
  AddChild(helloview = new HelloView(r));

  // Add the menu bar

  r.top = 0;
  r.bottom = 19;
  menubar = new BMenuBar(r, "menu_bar");
  AddChild(menubar);

This isn't as complicated as it looks at first glance, since most of the content is very repetitive.

We start by getting the bounds window rectangle, just as we did for Hello World. We want to create our HelloView. However, to make room for the menu bar, we set the top edge of the rectangle to 20 (the menu bar will be 20 pixels tall and placed above the HelloView). Then we create and add the HelloView to the window. Notice that we also store a pointer to the view in the member variable helloview.

Then we create the menu bar and add it to the window. We set r.top to 0 and r.bottom to 19, to indicate that the menu bar should take up the top 20 pixels of the window, and create a BMenuBar named menu_bar. A pointer to the menu bar is stored in the variable menubar. Then the menu bar is added to the window by calling AddChild().

Note that at this point, our window has two views in it: one is the HelloView, and one is a BMenuBar (which is derived from BMenu, which is derived from BView).

The File menu is created next:

  menu = new BMenu("File");

This line just creates an empty menu named "File." Then it's time to add the items to the menu, as follows:

  menu->AddItem(new BMenuItem("New",
                   new BMessage(MENU_FILE_NEW), 'N'));

This line of code adds the "New" option (with the keyboard shortcut key Command+N) to the menu by creating a new BMenuItem object and adding it to the menu using the AddItem() call.

When the user selects a menu item, a BMessage is sent to the window containing the menu item (the target for the message can be changed, but let's not get ahead of ourselves). The message that's sent to the window is created by copying the model message specified when you create the BMenuItem.

In this case, we specify a model message with the command code MENU_FILE_NEW. We'll look at messages in more detail in my next article.

We continue adding the rest of the menu items. Note that the keyboard shortcut argument to the BMenuItem constructor is optional; if you don't specify it, the menu item won't have a keyboard shortcut. Also, we use the AddSeparatorItem() function to add dividing lines here and there, to make the menu easier to read:

  menu->AddItem(new BMenuItem("Open" B_UTF8_ELLIPSIS,
                  new BMessage(MENU_FILE_OPEN), 'O'));

  menu->AddItem(new BMenuItem("Close",
                  new BMessage(MENU_FILE_CLOSE), 'W'));

  menu->AddSeparatorItem();

  menu->AddItem(new BMenuItem("Save",
                  new BMessage(MENU_FILE_SAVE), 'S'));

  menu->AddItem(new BMenuItem("Save as" B_UTF8_ELLIPSIS,
                  new BMessage(MENU_FILE_SAVEAS)));

  menu->AddSeparatorItem();

  menu->AddItem(new BMenuItem("Page Setup" B_UTF8_ELLIPSIS,
                  new BMessage(MENU_FILE_PAGESETUP)));

  menu->AddItem(new BMenuItem("Print" B_UTF8_ELLIPSIS,
                  new BMessage(MENU_FILE_PRINT), 'P'));

  menu->AddSeparatorItem();

  menu->AddItem(new BMenuItem("Quit",
                  new BMessage(MENU_FILE_QUIT), 'Q'));

Once all the items have been added to the menu, we add the menu to the menu bar by calling the BMenuBar class' AddItem() function:

  menubar->AddItem(menu);

Then we create the Options menu, which only has one item in it.

  menu = new BMenu("Options");
  item = new BMenuItem("Say Hello",
           new BMessage(MENU_OPT_HELLO));

The "Say Hello" menu item is used to toggle between two strings that might appear in the HelloView in our window: "Hello World" and "Goodbye World." This menu item has a check mark next to it if "Hello World" is displayed, and no check mark if "Goodbye World" is displayed. Let's make "Hello World" the default and make sure the "Say Hello" item is initially checked:

  item->SetMarked(true);

Passing true to SetMarked() puts a check mark in front of the menu item, while passing false removes the check mark.

Then we add the "Say Hello" item to the menu and add the Options menu to the menu bar.

  menu->AddItem(item);
  menubar->AddItem(menu);

Finally, we make the window visible by calling Show().

  Show();
}

QuitRequested() is unchanged from Hello World.

MessageReceived() is where the heavy lifting of handling and dispatching user selections in the menu bar is done. When the user selects a menu option, an appropriate BMessage is created and sent to the window containing the menu. The window's MessageReceived() function receives the message and handles it:

void HelloWindow::MessageReceived(BMessage *message) {
  switch(message->what) {
    case MENU_OPT_HELLO:
      /* see below for the code that goes here */
      break;

    default:
      BWindow::MessageReceived(message);
      break;
  }
}

One of the public fields of a BMessage object is called what; it contains the command code that was specified when creating the BMessage. We can therefore tell what kind of message the BMessage represents by looking at the value of the what field.

For now, the only message we handle is MENU_OPT_HELLO, which is sent when the user selects the "Say Hello" item in the Options menu (if you look in the HelloWindow constructor, the model BMessage for the "Say Hello" item has this command code). All other messages are forwarded to BWindow::MessageReceived() for further processing.

The "Say Hello" item toggles the text displayed in the view between "Hello World" and "Goodbye World." It also adds a checkbox to the menu item if "Hello World" is displayed, and removes it if "Goodbye World" is displayed. Let's have a look at the code.

    case MENU_OPT_HELLO:
      {
        BMenuItem *item;
        const char *s;
        bool mark;

        message->FindPointer("source", (void **) &item);
        if (item->IsMarked()) {
          s = STRING_GOODBYE;
          mark = false;
        }
        else {
          s = STRING_HELLO;
          mark = true;
        }
        helloview->SetString(s);
        item->SetMarked(mark);
        helloview->Invalidate();
      }
      break;

The BMessage that's received by your MessageReceived() function when the user selects a menu item is the model message specified when the menu item was created, with three additional fields added to it:

The when field contains a B_INT64_TYPE value that specifies the time the item was selected, measured in terms of the number of microseconds since 12:00:00 AM on January 1, 1970.

The source field contains a B_POINTER_TYPE value that's a pointer to the BMenuItem object itself.

The index field contains a B_INT32_TYPE value that specifies the ordinal position of the selected menu item within the menu, where 0 is the first item in the menu.

In order to toggle the check mark next to the menu item, we need a pointer to its BMenuItem object. We could have cached it in our window object, but it's more interesting from a sample code standpoint to fetch it from the "source" field in the BMessage, so that's what we do. We use the FindPointer() function to get the pointer out of the message and store it in the variable called item.

We then call item->IsMarked() to determine whether the menu item is currently checked or not. If it's checked, IsMarked() returns true (which means the text in the view is currently "Hello World." We set up a pointer to the string "Goodbye World," and set the variable mark to false. If IsMarked() returns false (meaning that "Goodbye World" is displayed), we set the string pointer to "Hello World" and mark to true.

Then we call the HelloView's SetString() function to change the text being displayed, and call item->SetMark() to turn on or off the check mark; if mark is false, the check mark is removed. If mark is true, the check mark is added.

Then we invalidate the HelloView. Invalidating a view causes the application server to Draw() the entire view. This is necessary to refresh the view's contents.

The BMenuItem class has some other functions you might want to experiment with, such as SetEnabled() and IsEnabled(), which let you control whether or not a menu item is disabled (dimmed and unselectable), or SetLabel() and Label(), which let you set and retrieve the current text displayed for the menu item when it's drawn.

To make life easier, you can download the complete source code for this week's project: ftp://ftp.be.com/pub/samples/intro/obsolete/menuworld_article.zip

Since this week's article has opened the BMessage can of worms, I think it's only proper that part three of the BeOS Programming Basics series cover message services on the BeOS in a little more detail. For now, play with the BMenuBar, BMenu, and BMenuItem classes and see where you can go with it. See you again in six weeks or so.


Early Impressions

By Jean-Louis Gassée

Two weeks ago, we were preparing for our BeDC, our developers' conference in Santa Clara, and we were unusually nervous. What was unusual was that we felt reasonably well-prepared this time, unlike our August '97 conference in Boston, for instance. And, happily, most everything worked this time, with very few glitches.

I won't go into details but I'd like to thank those participants who gave us feedback and suggestions for improving the formula or the execution. Speaking of which, it felt a little strange, at first, having court reporters in the sessions, but their purpose was non-prosecutorial. Transcripts of the presentations will be preserved for posterity on our site, with appropriate beautification from our embalming editors, I hope.

I had a good time. Developer conferences motivate me, because they are a great opportunity to meet the most important people in our life -- developers. True blue capitalists will argue that shareholders are the most important constituency we serve, they have a point, but without developers, shares in an operating system aren't worth much.

In any event, we value the opportunity to stand in front of a jury of our peers and present our work and our plans for the future. At the same time, one of the high points for me at the BeDC was watching the Masters Awards ceremony. I remember the old joke in the early difficult days of the Macintosh: there are three forms of lying, action, omission, and there is software for the Macintosh.

Seeing the quality and abundance of applications rewarded, not just submitted, I feel (cautiously) optimistic about our prospects. Please point your browser to www.be.com/aboutbe/pressreleases/98-03-19_beos_masters.html for details. And please don't ask me which program I prefer. I've excluded myself from the judging because I'm a little too enthusiastic. I also remember the first part of 1985 when everyone was so down on the Macintosh, and I got a nice job out of the common and unwarranted pessimism.

Back at the office, we got a good dose of cold water. Early orders for Release 3 were coming in at a nice clip, so nice, in fact, that it quickly revealed an embarrassing bug in our order taking system. Somehow, we managed to drop the last digit of credit card numbers and we were faced with having to call over fifteen hundred customers, apologize for our mistake, expose our mastery of computer technology, and sheepishly ask for their credit card number again.

Fortunately, Ron Theis, our Web Master, found an algorithm to recalculate this last digit. It worked for about 70% of cases. For the other 30%, this turned into an opportunity to deal with another issue: hardware configurations. Even if we take precautions on our Web site, in the documentation, and in any medium we can find, if our customer orders the BeOS and can't run it on his/her machine, we're going to create frustrations and bad word-of-mouth.

So, as we called customers, we checked, and the good news is a very high proportion indeed have hardware we support at this time and are clearly of the geek persuasion. We know we need to broaden the range of configurations we support and we acknowledge we need to make the installation process smoother, so we were relieved to see our early customers were quite patient with our imperfections. Our thanks to them, and our apologies to those we didn't satisfy as much and as quickly as they expected. We now have a clear picture of what we have to do.

Creative Commons License
Legal Notice
This work is licensed under a Creative Commons Attribution-Non commercial-No Derivative Works 3.0 License.