[from the Be Newsletter, Volume 2, Issue 38, 9/23/98]

DEVELOPERS' WORKSHOP: Scribble Scrabble
By Owen Smith, DTS Engineer <orpheus@be.com>


"Developers' Workshop" is a weekly feature that provides
answers to our developers' questions, or topic requests.
To submit a question, visit
<http://www.be.com/developers/suggestion_box.html>.


Many beginning developers we speak with wonder what porting
their application from Windows to BeOS entails. This article
makes a start towards answering that question. My goal is to
illustrate some of the differences between the popular
Microsoft Foundation Class (MFC) library for Windows and the
BeOS API.

Since a developer workshop without sample code is like
a kindergarten classroom without Play Doh, I submit the
following for you toddlers to investigate:

ftp://ftp.be.com/pub/samples/intro/doodle.zip

Doodle is essentially a rewrite of the infamous
"Scribble" MFC tutorial for the BeOS. It's a simple
drawing application which supports common application
features such as file I/O, printing, toolbars, a most
recently used (MRU) file list, and multiple document views.
It implements most of the functionality of its Windows
cousin.

Those of you who are familiar with the MFC library may want
to compare this code directly with the Scribble source code,
available on the Visual C++ CD-ROM. I've sprinkled comments
across Doodle's code to note specific comparisons between the
BeOS API and the MFC library; you can browse these by searching
the source tree for the text "MFC NOTE." Even if you're not a
rabid Windows aficionado, however, you may still find some things
in the sample code useful, such as the document architecture and
toolbars.

Comparing the BeOS API to Windows: a First Look

The BeOS API presents a level of abstraction somewhere
between the Win32 C-based API and the MFC library.
Superficially, the BeOS API bears a greater resemblance
to the MFC library: it's primarily object oriented, and many
BeOS API classes are similar to their Microsoft counterparts
(BRect = CRect, BWindow = CWnd, BView = CView, etc.).
However, the MFC library provides many things beyond Windows
operating system basics that the BeOS API doesn't -- such as
standard command implementations, a document management system,
and dialog data exchange/validation. In this sense, the BeOS
API more closely resembles the Win32 API. (On the other hand,
the BeOS API does do a lot of stuff that the MFC library
doesn't; I'll cover some of these features below.)

I've written Doodle from scratch, without using third party
libraries, resource editors, or even Microsoft code. This way,
you can see exactly what the raw BeOS API gives you. Because
the BeOS API is at a lower level of abstraction, I've provided
some of the functionality that's standard with the MFC library.
The amount of code you'll see in Doodle is considerably more
than the equivalent in the Scribble tutorial.

For the rest of the article I'll document specific design
and behavioral differences between the MFC library and the
BeOS API that I encountered while writing Doodle, from
general issues to coding specifics.

Multithreading

One of the most critical differences between Windows and
Be programming is the threading model. In MFC, you can
(and many applications often do) get away with using only
one thread: the main application thread, which implements
the main message loop that dispatches messages to all the
application's windows. While this simplifies development,
it's unsatisfactory for many applications, including
media-based ones, because each of your windows, views,
and documents is competing for that one thread's time.
For example, a window in the background doing calculations
could prevent a window in the foreground from processing
messages or responding to user input. Multithreading allows
these tasks to be scheduled separately, so windows can
operate smoothly and independently.

You can do multithreading in MFC, but you have to implement
the different threads yourself. Also, the maps the MFC library
uses to translate between Windows handles and MFC library
objects are thread-local, making it impossible to pass MFC
library classes that use Windows resources between threads.
Instead, a thread has to pass the lower-level handle to the
other thread, which wraps a new MFC library object around it
on the other side.

The BeOS takes a different approach. Since each window you
create runs in its own thread, just about every Be application
automatically takes advantage of multiple threads. Unlike
the MFC library, however, BeOS objects have no problems
being shared between threads, and many objects even help you
control access to them through built-in locking mechanisms.

In Doodle, this threading model adds some complexity to the
system. One of the big questions is what to do about the
documents, which can be associated with multiple window
threads, and may want to do calculations separately from
each other and the other threads. To allow each document to
function as independently as possible, I decided to derive
the document class from BLooper, to make documents event-
driven objects that each run in their own thread, similar
to an MFC user interface thread.

Such a multithreaded situation requires careful planning
(or debugging...) of communication between the document,
window/view, and application threads. I've chosen to have
the document communicate with the app and windows via
asynchronous messages, whereas the windows and application
communicate with the document through locked, direct access.
Since the document won't need to lock the windows or
application, deadlocks are avoided.

Multiple Document Interface and Frame Windows

There is no MDI analog in BeOS as there is in the MFC
library, where the main application window is a frame that
encloses the document, or "child," windows. Thus, porting
MDI applications requires extra thought.

In writing Doodle and doing away with Scribble's frame
window, I divided the frame window responsibility among
several objects. The application became the natural
receptacle for Window/Cascade and Window/Tile commands;
menus and menu handling moved into the child windows; and
toolbars were transformed into autonomous windows.

Messaging

Simply put, the built-in messaging mechanism in BeOS
is much more powerful than what the MFC library provides.
Rather than being limited to moldy WPARAM and LPARAM
arguments, a message in BeOS is a powerful object that
packages any kind of data in a simple, structured format.
BMessage also supports scripting, two-way, and inter-
application communication. Given the extra capabilities of
messages, it's a good idea to rethink communication
strategies in your application; many types of communication
can be rewritten using messaging in a much more succinct
and elegant way.

Take, for example, the MRU file list in Doodle. I set up
each MRU item in the File menu with a message that is
dispatched to the application whenever the item is invoked.
The message contains an entry_ref that locates the file to
open. These messages end up being processed in exactly the
same way that Tracker and File/Open entry references are
processed, so no extra coding is needed.

Modal Windows

As you would expect in a heavily multithreaded system, BeOS
objects work particularly well in asynchronous situations.
The messaging system is a big part of the reason. Instead of
trying to access the data directly from the modeless window,
it's trivial to parcel the data into a BMessage and dispatch
that to the target instead. This helps eliminate unwanted
dependencies between the dialog and the recipient.

By comparison, modal dialogs are actually more complicated
to code in BeOS's multithreaded environment because not only
does the user interface have to limit your actions to the
modal window, but the calling thread has to block and wait
for the modal dialog to finish. The BeOS handles the modal
UI behavior for you, but you have to implement the thread
synchronization yourself. For these reasons, and because
modeless dialogs are often more natural for the user, I
generally prefer to use modeless dialogs. Dialogs such
as the File/Open dialog are implemented as modeless.

Still, there are some things that you're best off waiting
for. In File/Close, for instance, you want to make sure not
to delete the window or its associated document before the
user has a chance to save the document's data. This means
that the File/Save dialog needs to behave modally. In case
you do need to implement modal dialogs, Doodle's Pen Widths
dialog serves as an example.

Graphics Architecture

Although, unlike many BeOS applications, Doodle's drawing
tasks are very simple, it's enough to demonstrate that
the BeOS graphics architecture is more streamlined and
versatile than its MFC library counterpart. For example:

1. Views know how to draw themselves, and don't rely on an
ephemeral device context for rendering. (However, in order
to draw they must be attached to a window or bitmap.)

2. The BeOS coordinate system is floating point-based,
supporting subpixel precision and hassle-free scaling.

3. The BeOS's concept of mapping modes is a bit different
from the MFC library. By default, the BeOS works in a
typographical mapping mode where 1 unit translates to 1
pixel on the screen, or 1 point (= 20 twips = 1/72 inch)
on the printed page. It differs slightly from the MFC
direct mapping modes because the y axis points down. For
printing in Doodle, I perform an isotropic scaling on the
BView to emulate Scribble's mapping mode of MM_LOENGLISH
(1 unit = .01 in.) on the printed page.

Resources

The only thing I use resources for in Doodle is to store
simple application data such as signature, icons, and
acceptable MIME types. These are easy to add to a resource
file through the FileTypes preference panel. However, you'll
notice that the stuff you would normally put into a Windows
resource, like dialog layouts, menus, accelerators, and
toolbars, has been coded by hand in Doodle. The BeOS's resource
format is certainly capable of handling these kinds of data, but
there's no standard way of editing or using those resources in an
application.

The Registry

Say good-bye to RegEdit -- love it or hate it, in BeOS, you
won't be needing it. You can access the MIME-based BeOS
application roster through the FileTypes preference panel,
or query it programmatically through BRoster and BMimeType.
There's also a directory in the system set aside for storing
application-wide settings(/boot/home/config/settings). Doodle
uses this area to store the entries in the MRU file list.

Storage

Analogous to the MFC library's capabilities for
serialization and structured storage, BeOS offers two
classes for managing persistent data: BFlattenable (if you
like serializing from streams), or BArchivable (which uses
a BMessage to store the data). Because Doodle doesn't need
any particular control over how the data is written in the
file, and the items being stored are standard types which
BMessage supports, I used BArchivable in the implementation.

Conclusion

I've covered a lot of significant differences between the
Be Way of doing things, and that Other Way. If you look
further, however, you'll realize that I've only scratched
the surface of comparisons between BeOS and Windows
development. I've left some important areas for future
columnists: graphics, audio/video/image manipulation,
the file system, the add-on/linked library architecture,
embedded objects, memory management... the list goes on.
Though MFC and the BeOS API may look similar, the BeOS API
is definitely a different animal.
