This week, two separate articles caught my eye. They were about companies repositioning technologies they have already spent a lot of time and effort on over the last few years. First was Java, the all-singing, all-dancing programming language that would break down the Babelian barriers amongst all the varied client platforms in the world. With total portability and write once run everywhere going for it, all (or all but the most performance critical) applications would be written in Java, once.
But now, with Netscape and others announcing their abandonment of client-side Java development entirely, Java is being repositioned as a "server-side technology." While the value of platform neutral, easily distributable, interpreted binaries for server applications is eluding me at present, I watch with interest for further news.
Second was the mumbled repositioning by Apple of Rhapsody as a "server OS." I'll admit, we've heard with decreasing frequency about the future of Rhapsody since the keynote session at Macworld Expo in January 1997 where Gil Amelio introduced Rhapsody as the future OS for Apple, and Steve Jobs and Steve Wozniak as "founder-advisors" returned to provide occasional direction to the company.
A lot *has* happened since then (anybody heard more from Woz?), but even I was surprised to see Apple's announcement of the future of Rhapsody as a server OS, intended to complement and not to replace the aging Mac OS. When Russell Brady, Apple's spokesman delivering this information was questioned about the apparent change in plans, he responded, "We've never positioned Rhapsody as anything but a server OS; anything else was made up by the press." Hello?
Anyway, these repositionings got me to thinking about how we're doing over the past few years as far as keeping to our original business objectives. And I'm pleased to say that I think we've repositioned very little. Our goal of providing a next generation operating system for use with digital media (e.g. audio, video) has gone unchanged. Which is not to say we haven't course corrected a little.
We did start in the hardware business as well as the software business. Because two processors are better than one, especially when dealing with streaming media, we built our OS to efficiently use more than one CPU. At that time (the era of Mac OS and pre-NT), however, no one was building inexpensive multiprocessor machines, so we built the BeBox, a dual PowerPC desktop machine. A little while later, others began building multiprocessor machines, so wasting as little time and money as possible, we ported the BeOS to their platforms and got out of the hardware business.
When we realized that a high performance, 64-bit file system is critical to any OS wanting to call itself a media OS, we scrapped our original file system and replaced it with one designed for digital video. And when it seemed that Steve Jobs was hell bent on widening the gap between the Intel installed base and the PowerPC installed base, we ported the OS again.
We've come a long way by being responsive to the changing market conditions around us, all the while holding true to our original goals. Next month's Be Developer Conference gives us another opportunity to listen to what is probably the most savvy segment of our customers and colleagues, the developers. I'm looking forward to seeing you there and collecting suggestions for next year's course corrections.
Just don't ask us to become a server OS.
I have a confession. I live for BeWare. The best part of my day is when I sit down at my BeBox with a cup of tea to ftp the incoming apps to my machine. My job is to test them. I unzip them, install them, give them a go. If they pass the "pretty indestructible" test, I add them to the BeWare area of the Be web site http://www.be.com/beware/index.html.
For those of you who are new to the BeOS, I thought I'd explain briefly how BeWare works. And some of you "old hands" might be interested in hearing about recent changes in BeWare. I'll also give you pointers on how to find the BeWare you're looking for, and where to go for tips and recommendations.
BeWare is an area on the Be web site where you'll find freeware, shareware, and commercial applications and utilities to download. There's a wide variety of BeWare apps, that run the gamut from games and audio players to development languages and utilities. This makes BeWare a great resource for both users and developers. Developers have an added benefit —many BeWare developers include their source code with their applications.
Within BeWare, you can peruse available applications alphabetically, by category ("Audio," "Video," "Utilities," etc.), or by selecting "What's New" for a list of recent arrivals. For each application you'll find a description of the app, file size information, alternate download sites, links to related web pages, and sometimes screen shots.
To download an item from BeWare, you can either click on the download link, or once you know the file name, you can ftp it directly from ftp://ftp.be.com. Once you've downloaded the app successfully and expanded it, you're set to go.
You must be a registered Be Developer to upload BeWare. (For more information on becoming a registered developer, see http://www.be.com/developers/.) Once you've registered, the upload process is simple and direct. You'll find the complete guidelines for uploading BeWare at http://www.be.com/developers/ftp/, but here's a summary:
Fill out the "Add BeWare" form in the Registered Developer Area http://www.be.com/developers/, upload your app, and send e-mail to ftparchive@be.com with the name of your app in the subject field. Within the day, your app should be up on BeWare.
Just one caveat: Since the BeWare section is generated by scripts that manipulate the information in the BeWare record you create, it is very important to fill out your BeWare record accurately. For example, if you list your application as "foobar.zip", when you upload your app, make sure it's called "foobar.zip", and not "foo_bar.zip", "Foobar.zip," or some other variant.
If you haven't visited BeWare for a while, you'll discover that it's been reorganized. Applications and utilities are now classified within each category according to their function. For example, within the Audio category, sub-categories include "Editing," "Playback," and "Recording." You'll also notice that when you click on an application's name, you go to a page dedicated to that BeWare application. Giving each app its own page cuts down on loading time and gives the author more space to include a description or links to screen shots and other related URLs. All in the name of better service!
If you're eager to try new BeWare, but don't know where to begin, there are several places to look for recommendations. Be hosts the BeWare Gem of the Day on the front page of the web site. Other sources for reviews and recommendations include BeOS Central, Be Leading Edge, and Be Dope.
[Webmaster's Note: This article has been corrected since its original publication. Eric's next article will discuss the BeOS's coordinate system in more detail, along with how to set up and respond to user interaction in a menu bar.]
As we draw closer to the first release of BeOS for Intel, a whole new generation of BeOS programmers is preparing to enter unknown territory. In order to help introduce them to writing BeOS applications (and to help PowerPC programmers get started with the BeOS), my next few articles for the Be Newsletter will comprise a brief introductory course on BeOS programming.
This week, we're going to build a very basic application. Can you say "Hello, world?" This article and the sample application we'll create will show you how to do that.
Yes, that's right, we'll be writing "Hello World" as a BeOS application. We'll create application, window, and view objects, and draw text into a view. This article won't tell you everything you'll ever need to know, but it should at least get you up and running with your first application so you can start experimenting. In fact, you should keep a copy of the Be Developer's Guide or the online Be Book handy as you read this article.
For this project, you'll need the following header files included in your source code:
#include <Application.h> #include <Window.h> #include <View.h>
Let's begin at the beginning: The BApplication
class. This class defines
a BeOS application. In essence, the BApplication
class represents the
link between your application and the Application Server. The Application
Server handles messaging, imaging, and other good stuff that most
applications need to do. So before you can draw on the screen or accept
or transmit messages, you have to create a BApplication
object.
Typically, you'll do this by creating your own class, derived from
BApplication
, so you can augment or override certain methods to customize
the behavior of your application. In our Hello World program, we'll be
creating a class called HelloApp to serve this purpose. An application's
main()
function's primary duty is to create
the BApplication
(or an
object of a class derived from BApplication
) and to invoke it. Before we
create HelloApp, let's look at a typical
main()
function (in fact, this
is the main()
our Hello World program will use):
voidmain
(void) {HelloApp
*theApp
; // Pointer to our application objecttheApp
= newHelloApp
;theApp
->Run
(); deletetheApp
; }
All main()
does here is create a new
HelloApp
object, which is derived
from BApplication
, as we'll see in a few moments. Once that's done, the
application's Run()
method is invoked.
The Run()
method is the
application's event loop. It won't return until the application is
terminated.
Once the Run()
method returns, we delete the application object, since
our program is about to terminate, so we don't need the object anymore.
It's useful to remember that the global variable be_app
always points to
your application's BApplication
object. That means you don't have to keep
a pointer to your application object around if you don't want to,
although if you call any custom methods added to the object, you'll need
to cast be_app
to your class.
Now let's look at the HelloApp
class:
classHelloApp
: publicBApplication
{ public:HelloApp
(); private:HelloWindow
*theWindow
; };
As mentioned earlier, HelloApp
is derived
from BApplication
. We only need
the constructor to get done what we need to do, so that's the only public
method we define. A single private variable, theWindow
, is used to store
a pointer to our application's window.
Let's check out the HelloApp
constructor:
HelloApp
::HelloApp
() :BApplication
("application/x-vnd.Be-HelloWorld") {BRect
windowRect
;windowRect
.Set
(50,50,200,200);theWindow
= newHelloWindow
(windowRect
); }
The HelloApp
constructor defers to the
BApplication
constructor, passing
the string "application/x-vnd.Be-HelloWorld". This odd-looking string is
the application's signature. It specifies that the application is an
application, and that the vendor is Be, Incorporated. The application's
name is "HelloWorld". This is the standard way we identify applications;
this string can be used by other programs to locate your application and
pass messages to it.
Once the object has been constructed, we create a BRect
.
BRect
is a
rectangle object (described in the Interface Kit chapter of the Be
Developer's Guide). It's used to define a rectangular area on the screen,
given the top, left, right, and bottom edges of the rectangle, and it has
several methods for setting and retrieving the position and size of the
rectangle.
One of these methods is Set()
, which we use to set
the rectangle to occupy the area from (50,50)
to
(200,200)
in space. This establishes a rectangle 151
pixels wide and 151 pixels tall. The arguments to
Set()
are in the order: left, top, right, bottom.
That BRect
object is then passed to the
HelloWindow
constructor when we
create our window object; this rectangle is used to position and size the
window on the screen when it is created. Note that we save the window
pointer in the HelloApp
's theWindow
field. That must mean it's time to
look over the HelloWindow
class:
classHelloWindow
: publicBWindow
{ public:HelloWindow
(BRect
frame
); virtual boolQuitRequested
(); };
The HelloWindow
class has a constructor, which
accepts a BRect
object as
an argument (as discussed previously), and a QuitRequested()
method. Note
that HelloWindow
is derived from BWindow
,
which is the class from which
all windows are derived on the BeOS.
HelloWindow
::HelloWindow
(BRect
frame
) :BWindow
(frame
, "Hello World",B_TITLED_WINDOW
,B_NOT_RESIZABLE
|B_NOT_ZOOMABLE
) {AddChild
(newHelloView
(Bounds
()));Show
(); }
The constructor, shown above, defers to the BWindow
constructor to set up
the window. The frame rectangle specified as the argument to the
constructor is passed through, and the window's name is specified by the
string "Hello World". B_TITLED_WINDOW
is a flag indicating the type of
window to create: A standard window with a tab at the top where the title
and close box should draw.
B_NOT_RESIZABLE
and B_NOT_ZOOMABLE
are flags that indicate that the
window can't be zoomed (it won't have a zoom box) or resized.
Once the window is constructed, we need to add a view to the window. Views are containers for other views. This is an interesting concept, and it's an important one to understand. Windows are containers for views. You typically can't draw directly into a window. You have to create a view and attach it to the window first.
A window can have as many or as few views attached to it as you want, and each view can have subviews. We'll develop this further in my next article. For now, our application's window has a single view.
In our case, we want the view to be the exact size of the window, and
fill the window completely. So when we instantiate our HelloView
(which
we'll look at shortly), we pass the BRect
returned by the Bounds()
method. Bounds()
is a method of the
BWindow
class that returns the
"bounds rectangle" of the window.
The bounds rectangle is a rectangle that indicates the area occupied by a window, but in coordinates local to the window. This is another important concept to grasp.
If your computer has a 640 x 480 screen, the top-left corner of the
screen has the coordinates (0,0)
and the bottom-right corner of the
screen is at (639,479)
. These are called "screen coordinates." When you
create a window, you specify the location of the window on the screen
using screen coordinates.
Once the window has been created, anything you do inside that window is
done in "local coordinates." Just as screen coordinates have the top-left
corner of the screen at (0,0)
, local coordinates have the top-left corner
of the window at (0,0)
.
The Bounds()
method in the BWindow
class returns the window's rectangle
in local coordinates, so in our program's case, this rectangle will be
(0,0)-(150,150)
, which is exactly what we want.
We pass this BRect
to the HelloView
constructor so the view will fill the
entire window. We'll study the HelloView
class next.
The HelloView
pointer that's returned by new
is then passed to BWindow
's
AddChild()
method. As we already learned, windows are containers for
views. The views that a window contains are called "children." The
AddChild()
method, then, adds a view to a window, thereby making that
view a child of the window. Once a view is added to a window, any drawing
done inside the view is visible in the window (assuming both the view and
the window are visible, but we'll get into that another time).
Once the child view has been added to the window, we call Show()
. This
BWindow
method makes the window
visible—all BWindow
s are hidden until
you call this method.
The other method we define for the HelloWindow
class, QuitRequested()
, is
called whenever someone attempts to close our window. This happens if the
user clicks the close box, for example. Here's the code:
boolHelloWindow
::QuitRequested
() {be_app
->PostMessage
(B_QUIT_REQUESTED
); returntrue
; }
This is very simple. We simply post a B_QUIT_REQUESTED
message to the
application. By default, when a BApplication
object receives this
message, its Run()
method simply exits (which then returns control to our
main()
function, which deletes the application object and exits).
Then we return true to indicate that we're granting permission to close
the window. If QuitRequested()
returns false
,
this indicates to the
caller that for whatever reason, they shouldn't close the window. An
obvious application of this would be to present an alert reminding the
user they haven't saved their work yet, with the option for the user
cancel whatever operation was about to close the window.
Finally, let's see the HelloView
class, which
is derived from BView
.
Views are the contexts in which all drawing is done.
classHelloView
: publicBView
{ public:HelloView
(BRect
frame
); virtual voidDraw
(BRect
updateRect
); };
Our HelloView
class has a constructor, which
accepts a BRect
identifying
the size and position the view should occupy within its parent, and a
Draw()
method, which is called by the Application Server to update the
contents of the view.
The constructor looks like this:
HelloView
::HelloView
(BRect
frame
) :BView
(frame
, "HelloView",B_FOLLOW_ALL_SIDES
,B_WILL_DRAW
) { }
As you can tell, we don't do anything in the constructor: We simply defer
to the BView
constructor, passing through the frame rectangle. The view's
name is "HelloView". We specify the B_FOLLOW_ALL_SIDES
flag for our
resizing mode, which indicates that the view will always fill the
complete window, even if the window is moved or resized, and the
B_WILL_DRAW
flag, which tells the Application Server that we're
implementing a Draw()
method that needs to be called for updates.
The Application Server calls Draw()
whenever the window's contents need
to be updated. This occurs if another window passes in front of ours, or
when the window is initially shown. A BRect
is passed to the method,
indicating the area of the view that needs to be redrawn.
voidHelloView
::Draw
(BRect
updateRect
) {MovePenTo
(BPoint
(20,75)); // Move penDrawString
("Hello, world!"); }
As you can see, in Hello World, we're ignoring the updateRect
. We
position the pen at coordinates (20,75)
by creating a BPoint
object
(which represents a point on the screen) with those coordinates, then
passing that point to the MovePenTo()
method.
Once the pen has been positioned where we want it, we call DrawString()
to draw the message "Hello, world!" into the view.
The sample code for my article will be on the Be FTP site in: ftp://ftp.be.com/pub/samples/intro/obsolete/helloworld_article.zip
In my next article, we'll investigate how you can use multiple views in a
window, and begin looking at some basic user interface features. For now,
poke through the Be Developer's Guide and the
Application.h
,
Window.h
,
and View.h
header files and do some exploring on your own.
It's a laundry list, but let's start with Be Europe. Last week, in telling how we "paved the runway," i.e., raised the funds needed to launch the BeOS platform in the Intel space, I left a significant pothole in my story. I forgot to credit the Be Europe team for its contribution to this successful financing round. At the last tally, slightly less than 25% of the funds raised came from Europe, and we couldn't have done it without Jean Calmon and his team. I'm red-faced for my slip of the electric pencil.
Now Be Dope, which attentive readers of our Web site have noticed a reference to. Check it out, it is good entertainment and, occasionally, good information—http://www.geocities.com/SiliconValley/Bay/7587/.
However, I must take exception to an item that offers an ingenious explanation for my name. Among other twists, the story alleges that I was actually born in New Jersey. I guess I should be flattered, right?
Since my past is under scrutiny, I might as well confess. I wasn't born in New Jersey. As always though, there is a grain of truth: I once worked in New Jersey. During a lapse in sanity, because I believed what was printed in Fortune magazine before Stewart Alsop started contributing, and because I listened to a headhunter, I ended up working for a company based in the charming locale of Florham Park, NJ. That company was Exxon Office Systems.
Exxon misexecuted a belief in the right idea: Information as the oil of the 21st century. They were right—we know who the new Standard Oil is and who the new Rockefellers are—but their concept of a bit wasn't helpful in the computer business. So, all right, I did it, in New Jersey, but it was a genuine misunderstanding on both sides.
I'm indisputably French, as John Dvorak attested. Feeling my pain, he once introduced me as the mind of a Frenchman unfortunately trapped in the body of a Frenchman. Too true. In any case, read Be Dope, even more fun and relevant than Wired—and a lot easier on the eye.
As for my e-mail .sig, I'll have to drop the Dvorak quotation soon, it's getting old. I'm taking suggestions, you know where to find me. I could use "a French farmer abducted by aliens and raised in California by VCs," but that could be construed as slander by the venture community whose existence I cherish and whose name I only invoke with the greatest respect. Suggestions should be mindful of family values (this recommendation is meant particularly for a certain Be engineer whose T-shirts would cause HR to faint, if we had an HR department).
Lastly, the Be Developers' Conference.
http://www.be.com/developers/BeDC_schedule.html is the link to the
program of the event. Contrary to our previous conferences, we're not
holding it on a weekend, or preceding or following another industry
event, and we are even charging $95 for it, a little less if you
registered early.
Beyond the "free" T-shirt and the wonderful buffet lunches, we intend to make the content and delivery of the sessions worth your time and money. Much has evolved in the BeOS, beyond and because of the move to Intel-based hardware—new applications, more function in the OS, new tools and utilities. Please come and see what the Be engineers and your colleagues and competitors have done. I look forward to seeing you in four weeks.