Be Newsletter
Issue 95, October 15, 1997
Table of Contents
BE DEVELOPER CLASSIFIEDS
Be Developer Classified are an opportunity for BeOS
developers to tell each other about projects they're working
on, are thinking about working on, or would like to work on.
Here's your chance to request assistance on a project, or
make your talents known to other projects.
For more information or submissions guidelines, send e-mail
to newsletter@be.com.
- Hardware Project: GeekLights
I am designing processor activity lights (ala the BeBox) for
Intel machines running the BeOS, and need help on the
project. More information, including diagrams and
descriptions, can be found at:
http://www.people.cornell.edu/pages/djs13/be/index.html
Daniel Switkin, djs13@cornell.edu
- BeOS Application: Supreme3D
SupremeGS, Inc. is working hard to bring you Supreme3D(tm)
on the BeOS(tm).
Supreme3D is a revolutionary new 3D modeling and rendering
application that greatly simplifies the 3D model design
process.
For more information, see http://www.supremegs.com/, or
send e-mail to sales@supremegs.com.
BE ENGINEERING INSIGHTS: Fun with FilePanels
By Robert Chinn
The new Expander application in PR2 started out as a simple
idea, at least in my mind; maybe that says something about
how I think, but we won't go into that here. As the project
progressed I found I eventually had to deal with issues like
providing additional features that people requested, and an
interface that people could use.
Perhaps inevitably, it was another Be engineer who submitted
this bug report:
"When a app needs to be expanded I am not allowed to
expand into a selected folder.
Robert says that if you go up one level higher you then
get to choose the folder.
This is dumb."
What the bug report was referring to was the process of
selecting a destination folder via the default BFilePanel I
was using in the application. If you were "in" the folder
you wanted to select, you had to go "up" one level to select
it, rather than being able to select it directly
Okay, so maybe the interface was a little confusing. And,
well, maybe I was just being lazy and did not really want to
add another feature to this supposedly simple application.
But with a bug report like that (and from Melissa, no less),
I was just going to have to do the extra work.
A BFilePanel can be constructed so that all displays are
directories, as well as allowing the user to select a
directory instead of a file. The goal for this article is to
create a custom FilePanel, using the BFilePanel class, which
allows for the selection of any directory, while you are in
it or while you are browsing its parent.
In browsing the header file, FilePanel.h , you will find a
nice, clean, self-contained class. Unfortunately, there does
not seem to be a simple way of just adding a view, a button
in our case, to the window. Fortunately, there is one method
provided, Window() , that returns the FilePanel's window. If
you can get the window, you can get its views, and if you
can get the views then you can add to them.
To accomplish this task a new class must be derived from
BFilePanel . The constructor has been simplified for clarity,
the SelectionChanged() method has been included, and a
BButton has been added:
class TDirFilePanel : public BFilePanel {
public:
TDirFilePanel( BMessenger* target,
BRefFilter* filter=NULL );
void SelectionChanged();
private:
BButton *fCurrentDirBtn;
};
To set up this custom FilePanel and provide the basic
functionality requires six steps in your code:
- Retrieve the window from the FilePanel object.
- Find the first child of the window and then find the view
named "cancel button".
- Create our new
BButton , size it appropriately for its
title, and place it relative to the Cancel button.
- Set the target for the new button.
- Set the message for the new button; part of the message
will be the
entry_ref of the current directory. The
current directory is retrieved via the GetPanelDirectory
method and the resulting entry_ref is added to the
message. When the user clicks this button it will send
this message to the target (BMessenger ) signifying a new
directory selection.
- In the target's
MessageReceived method, where we catch
the message sent from our FilePanel, we need to do one
more thing, send the FilePanel a Hide() message.
By setting the node_flavor parameter to B_DIRECTORY_NODE ,
the FilePanel allows the selection of directories instead of
files; take a peek at SupportDefs.h to see the rest of the
node flavors.
TDirFilePanel::TDirFilePanel( BMessenger* target,
BRefFilter* filter )
: BFilePanel( B_OPEN_PANEL, target, NULL,
B_DIRECTORY_NODE, false, NULL, filter)
{
BWindow *w;
// 1) Get the window from the FilePanel
// so we can find the window's children
w = Window();
if (w->Lock()) {
BRect btnrect;
// 2) Find the first view in the window,
// and from that view we find the cancel button
BView *v = w->ChildAt(0);
BView *cancelBtn = v->FindView("cancel button");
if (cancelBtn) {
BView *parentview;
float charWidth;
// 3) Construct and add the new 'Select Current
// Directory' button
charWidth cancelBtn->StringWidth("Select Current
Directory");
btnrect = cancelBtn->Frame();
btnrect.right = btnrect.left - 10;
btnrect.left = btnrect.right - charWidth - 40;
fCurrentDirBtn = new BButton(btnrect,
"current dir button", "Select Current Directory",
NULL, B_FOLLOW_RIGHT + B_FOLLOW_BOTTOM);
// 4) Set the target for the new button
fCurrentDirBtn->SetTarget(*target);
parentview = cancelBtn->Parent();
parentview->AddChild(fCurrentDirBtn);
// 5) Set the message for the new button
entry_ref ref;
BMessage *msg = new BMessage('slct');
GetPanelDirectory(&ref);
msg->AddRef("refs",&ref);
fCurrentDirBtn->SetMessage(msg);
}
w->Unlock();
}
}
Now we come upon another minor problem. When a user begins
traversing directories, the entry_ref in our new button also
needs to change. Luckily in BFilePanel there is a method,
SelectionChanged() , that does just the trick. As the user
clicks on a file or moves up or down in the directory
structure, this method will get called. By calling
GetPanelDirectory we can then retrieve the current
directory and update the button's message.
void
TDirFilePanel::SelectionChanged()
{
BWindow *wind;
wind = Window();
if (wind->Lock()) {
entry_ref currRef;
GetPanelDirectory(&currRef);
// modify the btn's msg
BMessage *msg = new BMessage('slct');
msg->AddRef("refs",&currRef);
fCurrentDirBtn->SetMessage(msg);
wind->Unlock();
}
}
One final bit to help simplify our scenario. As we are
traversing directories looking for a folder for our
destination, we notice that every file is still visible
through the FilePanel, even though we only want to select
directories. The trick is to add a filter to the FilePanel.
Using a BRefFilter to do this is quite simple and only
requires deriving a new class from BRefFilter and adding to
its Filter() method.
class TDirFilter : public BRefFilter {
public:
bool Filter(const entry_ref* e, BNode* n, struct stat* s,
const char* mimetype);
};
The Filter method receives all the information you will need
to discern whether you want the file or directory to show.
In our case we are just looking for directories and volumes
and only need to look at the mimetype to do so.
Note that if the item is a symlink to a directory or a
volume, this filter will not see it. I will leave that as a
mini exercise for the reader.
bool
TDirFilter::Filter(const entry_ref* e, BNode* n,
struct stat* s, const char* mimetype)
{
if (strcmp("application/x-vnd.Be-directory",
mimetype) == 0)
return true;
else if (strcmp("application/x-vnd.Be-volume",
mimetype) == 0)
return true;
else
return false;
}
To use this RefFilter in the directory selection FilePanel
above, you simply construct the custom FilePanel with the
Filter object as its parameter:
TDirFilter filter;
TDirFilePanel *dirSelect new TDirFilePanel(new
BMessenger(NULL,this),filter);
So there we have it. A cleaner way to select directories, an
examination of a simple class, BFilePanel , which we have all
probably used, and a peek at using a BRefFilter to simplify
the view that we present to our users. The addition of
simple features such as these add a polished look to an
application that a user definitely notices and appreciates.
A Few of My Favorite Things
By Michael Alderete
Back in Newsletter #86, Robert Polic wrote an article about
spamming using the mail and query features built into the
BeOS. The article provided an excellent illustration of
several concepts in BeOS programming, including the basics
of writing a command line application, using BeOS queries,
and sending e-mail programmatically.
It was written with tongue firmly in cheek, but actually
generated some fairly heated responses from people who
apparently had received more spam than they'd like, and
didn't want to see any more.
The thing is, writing a spamming tool is pretty trivial.
Robert did his in just over a hundred lines of code, and
I've even written one myself -- and I'm *not* a software
engineer.
The hard part of being a spammer is getting all the e-mail
addresses to which you plan to send your junk mail.
Collecting and managing this database of addresses and,
presumably, demographic information is definitely where the
"value" is in the life of a spammer.
Robert's spamming tool simply assumed the presence of a
collection of BeOS Person records, files which are specially
marked and which have extra, people-related attributes like
"Name", "Phone Number", and "E-mail" attached to them.
Person files are really cool. You can drag them onto BeMail
to create a new message to those Persons, or drag them into
an existing message to add them to the recipient list.
There's a pop-up menu for the To:, CC:, and Bcc: fields in
BeMail, which lets you choose Persons you've created, and
AdamMail (and other applications, too, I'm sure) provides
quite nifty expansion of e-mail addresses, also based on the
Person files on your system.
Unfortunately, creating such Person files was, until
recently, not terribly easy. With the Preview Release 2
(PR2), we've added a new application called People. It's my
second favorite thing that's new in PR2. While it's not an
industrial strength contact database (and therefore of
little use to spammers), it does provide an easy way to
create and update Person files. I think you'll find it quite
handy!
My favorite new thing in PR2 has to be the changes to the
Find function. While I find the ability to search across
multiple volumes (disks) or only specific volumes useful,
I'm *thrilled* about being able to edit (modify) the Find
criteria.
Try this (when you get your PR2 CD, of course!): Do a find
for all e-mail from the domains "cyberpromo.com",
"savetrees.com", or contains "free" in the subject line
(hint: detailed directions for doing this can be found in a
BeOS Tip of the Week:
http://www.be.com/users/tips/tip7.html). You'll get a
results window with a lot of spam in it. Select All
(Command-A) and Move To Trash (Command-T), and 3 seconds
later you're spam-free.
Of course, you missed another notorious spammer, in the
domain "pleaseread.com". In PR2, it's simple to add this
evildoer to your killfile. Choose "Edit Query" (Command-G)
from the File menu of the results window, make your changes
or additions, and click "Find" again. Cool, n'est pas?
As the keeper of the Be FAQ lists, I've written most of our
instructions for dealing with various compressed or archived
files (.zip, .tar, .gz, or .tgz files, mostly) people
download from the Internet. The instructions were long and
required the command line, which turned a lot of people off
-- but no more! In PR2, we have a nifty new Expander
utility, which makes short work of such archives.
It's a drag-and-drop tool, but in PR2 NetPositive will
automagically hand off downloaded files to Expander for
automatic extraction. The coolest part, though, is that now
your archived files will have nifty Be-style icons!
Speaking of NetPositive, it's seen quite a few improvements
in the way it handles HTML which used to be problematic. The
Webmaster and I are pretty happy about that, and so will you
be when you get it.
There are, of course, other things which changed in PR2, but
I'll let you read the Release Notes for details. I'll just
mention two last things that I like a lot. Tracker columns
are now "live" as you resize them, and the Tracker is smart
about columns like Modified: If you make it narrower, the
Tracker will abbreviate or change the format in which it
displays the information, going from "Friday, October 10
1997, 05:54:12 PM" to "Oct 10 1997, 05:54 PM" to "10/10/97",
as necessary. Try it, and other columns, and see!
Last there's the obligatory (and new) About BeOS box, which
displays system hardware and software version information.
It's got more than that, though you'll need to play around a
bit to see it (but did you know that Hiroshi is his *middle*
name?).
That's all for this article, but be sure to read the Release
Notes on the PR2 CD for more (and there's a fair amount
more). Then you too can do your own Julie Andrews imitation.
News from the Front
By William Adams
Can you believe it? This is my one year anniversary of
working at Be, Inc. I first joined Be from my cozy self-
started company of 12 years because I figured I liked
programming the BeOS so much, I might as well participate
directly. As I told Jean Louis when I was interviewing:
I've pushed the horse, when programming with NeXTSTEP. I've
pulled the horse, when programming with Taligent. Now I want
to ride the horse.
In the past year, my daughter has grown, I've corresponded
with developers around the world, and we've put out a few
releases of the BeOS. Quite a lot of activity for a small
company. When I joined, I invented a new title for myself:
"Technical Evangelist." An evangelist who knows how to
program.
In a way, all engineers are technical Evangelists. If you've
been programming the BeOS for any amount of time, you have
probably seen the names of many Be engineers in newsgroups,
on mailing lists, and here in this newsletter. This might
lead you to believe that all Be engineers are part of the
marketing organization.
Almost as soon as I joined Be, I was asked if I would fly to
Washington in a couple of weeks to give demos, write a
magazine article for MacTech magazine, pronto, and write a
newsletter article. Well, I did it all, and the last task
I've kept on doing ever since. Then I was asked to help hire
a boat load of people, and get our DTS department started. I
did that with varying degrees of success, which you can
judge for yourself.
One aspect of this job that strikes people on the outside
looking in, is how can anyone write every week about this
stuff? Well, it's easy. If you examine your own programming,
you'll find that there is a lot of excitement that occurs on
an everyday basis. You're a real programmer's programmer
aren't you? Yasmin ran a temperature... that reminds me, the
BeOS is hot! Or as one of our own engineers put it: "The
BeOS is the best operating system! I really like programming
it."
What is it that drives people to make such comments about
the BeOS? Is it the multithreaded programming model?
Probably this and many other minute details that are
continually exposed on a daily basis. Multithreaded
programming can be a tremendous benefit to many programs,
but not all OS implementations are alike. And even if they
were, multithreaded programming demands a certain regimen or
it can lead to little or no improvement in performance. In
the past two articles I went over spinlocks wrong and right,
but what good are any locks?
Let's take a simple task. You want to render a scene. You
want to use multiple threads to do it. We can break this
task up into multiple phases. Let's assume that the scene
can be rendered by taking the individual objects in the
scene and rendering them. If you had a thread per object,
you would gain great parallelism. Well, we have many
thousands of objects in the scene, so we don't necessarily
want to do that, but we do want to use a pool of say 25
threads. The scene is described in some file format. Our
task is to parse the file into objects, and place these
objects onto an assembly line for the object renderers to
take off.
Thread 1 -- Parse the scene, place objects onto the
rendering line.
The rendering assembly line is represented by a FIFO data
structure. This is little more than a list with some
ordering semantics.
fifo::push(aObject)
fifo::pull(aObject)
All you have to do in the parsing thread is push objects
into the line as you parse the file.
ALockClass gLock;
AFIFOClass afifo;
parser_loop()
{
while(get_next_object(aObject, file))
{
gLock.Lock();
afifo.push(aObject);
gLock.Unlock();
}
}
Threads 2-26 -- Pull an object off the line and render it.
In a loop, each rendering thread does this:
loop()
{
while (afifo.pull(aObject))
{
gLock.Lock();
afifo.pull(aObject);
gLock.Unlock();
render(aObject);
}
}
Notice that any time you want to access the fifo object, you
have to explicitly lock it. That is to guarantee that it
remains in a consistent state while you are adding and
removing objects. It would be bad to add objects and
possibly change some internal value while you are deleting
and causing a counter change in that same object, and thus
you need the locks. They guarantee an atomic action is
occurring.
But this form of usage can become cumbersome at times. You
have to remember when to lock what because there is nothing
preventing you from just accessing the fifo object directly
without locking it.
One of the things you can do is to move the locking
inside the object that is being locked. This vastly
simplifies the code and helps alleviate many problems
that are typically very hard to detect and fix. So
instead of relying on the programmer to lock at the
right times, do it for them.
afifo::push(aObject)
{
fLock.Lock()
// do the push thing
fLock.Unlock()
}
afifo::pull(aObject)
{
fLock.Lock()
// do the pull thing
fLock.Unlock()
}
That way, the locks in the rendering and parsing threads
can go away, and your day is much lighter. So why doesn't
BList implement things this way? Because it is a very
low level primitive that is meant to be as light weight
as possible. It can be utilized in other data structures
like this fifo, which provide the appropriate locking
semantics. "Don't use locks until you have to" is a
basic programming idiom in the BeOS. And its companion,
"Use locks where necessary."
Like I said, anyone can probably look at the 200 lines
of code they write a day and turn it into a newsletter
article. Life as a programmer can be fun and exciting...
If you can put the right spin on it.
So, it's my one year anniversary. I'm still as excited
about Be as I was before I joined. Even more so today
as we move into greater markets like the Intel space,
and the OS itself becomes more and more substantial.
There are a lot of fantastic engineers here, and our
marketing over the next year should make the "Best OS
ever" statement more apparent to more programmers, which
will produce more apps, which are just the best things
since sliced code.
Have fun at the front.
Java Wars
By Jean-Louis Gassée
Once again, e-mail traffic suggested a topic for this week's
column: Several honorable correspondents wanted to know our
position regarding the Java war. Yes, we have one: We are
unequivocally ambivalent.
Let's start by stating I'm not addressing the merits of the
language, they are many, they are not infinite and Java
could be the Basic of the Web, or much more. I just wish
things would settle a bit more and allow us to better
understand what Java's best and worst uses are; despite Rear
Admiral Grace Hopper's contention, no one really wrote an
operating system in Cobol. In any case, Java has achieved
currency and that is that.
What is not settled, it appears, is how much Sun controls
Java. Sun says they decide what Java is and its licensees
are bound by the definition. Here, bound means if you ship a
Java-based product, it must pass a series of tests
demonstrating it complies with Sun's definition of Java.
Two events appear to have triggered Sun's breach of contract
lawsuit against Microsoft. The first is less of an event
than it is a habit: Microsoft "embraced and extended" Java,
adding features to their version of the language. These
features were designed to "connect" Java programs more
closely to Windows.
This was explained as being dictated by performance or
expressive reasons: Microsoft Java programs would run faster
that way or they would access Windows resources more easily,
or their look would be more consistent with other Windows
programs.
This, of course, violated the "spirit" of Java: Write once,
run everywhere. In that sense, these programs were no longer
Java programs, they were Windows programs written in a
language called Java, just as other Windows programs are
written in C or C++.
One more thing before we move to Explorer 4.0: Microsoft
managed to ship good Java programming tools and the fastest
Java Virtual Machine. Who could say their embrace of Java
was half-hearted?
As to Explorer 4.0, the second "event," it appears its Java
components miss two methods, the Java Native Interface and
the Remote Method Invocation. It seems the omissions were
neither random nor capricious: I'm told by higher technical
authorities a "full" implementation of Java would facilitate
the remote execution of Windows programs. In other words,
from an Excel-less computer, you'd be able to run a copy of
Excel residing on another computer on the network.
More specifically, Network Computers, NCs, are often derided
as standing for Not Compatible by their Microsoft opponents.
If the "remote Excel" theory isn't too far from technical
truth, suddenly, NCs would be able to run legacy Windows
programs, albeit remotely. Citrix got into a dispute (now
resolved) with Microsoft over running Excel or Word from
"dumb" terminals connected to a modified Windows NT server,
and Microsoft itself published a Hydra white paper
describing their plans for a similar product offering.
With this in mind, we can turn to what the "Java war" is
really about. It is not about the merits of Java as a
programming language, it is about finding a way to topple
Microsoft from its dominant position on the desktop. Create
a modern programming language, bundle it with a run-time
environment that isolates the programs from the hardware and
the underlying OS, use the Intranet or the Internet to run
legacy applications and, presto, you have the best of the
old world and the freedom from Intel and Microsoft. You can
sell your hardware and your software, instead of "theirs,"
without their dominant position preventing you from entering
the market with better, faster, cheaper hardware and
software.
Would the world be a better place if we had more real
alternatives? The question, as posed, is poorly framed, it
doesn't leave the opportunity to disagree, it fails the "no
con" test.
For the time being, the more interesting questions are what
does the contract really say, and what does the law permit.
On the latter, my position is the law does not currently
sort the applications from the OS. As a result, Microsoft
and others can extend their reach in ways that might be
unpleasant for the competition, but lawful nonetheless.
As for the contract, I can't wait to see it. Microsoft has
agreed to make it public and Sun seems reluctant to do so.
There might be good business reasons for confidentiality,
but I'd feel better if we could rely on information instead
of gossip.
Microsoft has one option, pick up its Java marbles and go
home. No one sues anyone over versions of C++, they could
implement most of Java without calling Java, or stop using
Java altogether. Windows programmers would be left with
their customary 90 or 95% of the desktop market, and pure
Java programmers with the rest. Is this more choice?
|