Be Newsletter

Volume II, Issue 48; December 2, 1998

Table of Contents

BE CLASSIFIEDS:

Be Developer Classifieds are an opportunity for Be 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, check out the Classified Ads section in the Registered Be Developer area.


Job Opening: BeOS Engineer

MGI is expanding its VideoWave II/BeOS group. We are seeking a senior developer in the Toronto area with the following qualifications:

  • At least 4 years of professional programming experience

  • Experience writing portable code

  • Image manipulation and video processing skills considered an asset

  • BeOS experience considered an asset

  • Ability to meet tight deadlines

  • Well organized and structured work habits

  • Ability to work effectively in both team and independent environments

  • Telecommuting a possibility

    The successful candidate will have thorough experience writing code for a shipping commercial product.

    Contact: Reid Ellis <reide@mgisoft.com>, Program Manager for VideoWave II/BeOS


    BeWare: Post Your R4 Software

    Be will begin posting R4 BeWare on December 14th, when we begin shipping R4. Developers will be able to submit R4 applications any time before that. BeWare will continue to post R3 applications for the PowerPC side since, theoretically, R3 apps for PPC should still run on R4 PPC.


    Online Opportunity: BeOS Webring

    Has your BeOS website joined the BeOS Webring? Do it today!

    <http://www.planbe.com/beosring.html>


    BEDEPOT.COM: New BeOS Software

    The BEDEPOT.COM section of the Be Developer Newsletter is for announcing the launch of commercial products on BeDepot.com.

    For more information about how to get your application listed, go to: <http://www.bedepot.com/vendor/comarketing.asp>


    • BeOS R4: BeDepot is now taking orders for R4. However, Be will not begin shipping R4 until December 23 (English) and January 15 (French, German). The Japanese language version of the BeOS is available exclusively from Plat'Home in Japan: <http://www.plathome.co.jp/>.

    • NetPositive: The 40-bit encryption SSL version of NetPositive is now available for R4. This version is available internationally. Additionally, at the end of December we will be offering the 128-bit version of NetPositive to US and Canadian citizens.

    • Adam 2.0: The latest version of this e-mail client is available for PPC and Intel, and BeDepot.com is offering a $10 competitive upgrade to registered Mail-It owners, through SoftwareValet.

    • Spellswell Word Services: Now available for PowerPC and Intel.


    BE ENGINEERING INSIGHTS: R4 Drag-and-Drop
    By Jon Watte hplus@be.com

    One of the nice things we added in R4 was a more flexible drag-and-drop protocol. Many developers have already peeked inside the BMessage being dragged when you grab a clipping >from ShowImage in an effort to try and figure out how it works. Because it actually involves more than one message, and we would like all programs on BeOS to do the right thing, I'm going to document the current protocol.

    First, the code! You can find it at:

    <ftp://ftp.be.com/pub/samples/interface_kit/dragme.zip>

    The application is simple. Start it, and it shows a window with a little image in it. You can click on the image to drag it around on your screen. If you drag it into a Tracker window, the Tracker creates a clipping file that the application saves the image into. If you drag the image to the Trash can, the application closes the window, the only way it knows how to remove the image. While not the best example of intuitive user interface design, it serves the purpose of illustrating drag-and-drop pretty well.

    The basic idea behind the new drag-and-drop protocol (DnD for short) is that the initiator of the drag doesn't have to produce the data in all formats it can possibly generate just to start dragging. Instead, it puts into the message a list of the formats it knows how to generate using the data being dragged. In this case, the DragView inside the DragMe window is the initiator.

    The recipient of the drag message, in this case the Tracker, can then look through the message for data formats it likes and send a reply to the message back to the initiator asking for one of these formats. Currently, the Tracker uses the first format added to the list of formats, unless you hold down the Control key. In that case it gives you a list of possible formats, or the option to cancel the drag altogether. Note that DragMe provides only one format of data, while ShowImage provides all formats available through the Translation Kit.

    Once the target (in this case the Tracker) chooses a format and sends a message back to the initiator, the initiator extracts all the data it needs from its internal data storage, and puts it either in a new message sent back to the target, or in a newly created file specified by the target. If the data is sent back to the target in a BMessage, this message is called the "data message," as opposed to the "dragged message" which was the first message, or the "reply" sent from the target to the initiator. That the target creates the file has to do with needing to preserve the drop point as the icon location in the Tracker window, which is better kept internal to the target than exposed in the API.

    The nitty-gritty of setting up the drag is found inside DragView::MouseDown(). After figuring out whether we actually clicked in the bitmap and want to drag it, we add the types of data we can provide to the message, along with the actions we accept. The MIME type we use to export data comes from the first Translator we find that can save bitmap images, found and remembered in the constructor of the DragView class.

    The MIME string of data types you know how to provide should be added to the drag message in the attribute named "be:types". The magic type B FILE MIME TYPE means that we can create "a file" in addition to MIME data within a data message. It's OK to not add any other types at all, if all you know how to do is to save files. That makes direct data exchange between your application and other applications impossible without using temporary files, though, so you typically want to do both.

    If you use the B FILE MIME TYPE type, you should also add the MIME types of files you know how to create (which may be different from the types you know how to put in data messages) into the attribute "be:filetypes".

    DragView uses a copy of the content BBitmap as the drag indicator. That works fine because the bitmap is small. If the bitmap is larger, you should consider just dragging an outline BRect. You'll note that we use the new form of DragMessage found in R4, which allows you to specify a drawing mode for the dragging; we use B OP ALPHA because we prepare the dragging BBitmap specifically with alpha in mind. We also specify the window (rather than the view) as the reply destination for the dragged message.

    The actions we know about are B COPY TARGET and B TRASH TARGET. The former has the target send a request for data as reply; the latter does not require you to send the data anywhere, but instead indicates that the target wants you to remove the data being dragged (typically because the user dragged to the Trash). Possible actions are added to the "be:actions" attribute of the drag message.

    The "be:clip name" attribute is optional, and gives a hint to the destination for what the file name might be if it wants to create a clipping file. The target is free to ignore this hint and create a clipping file with any name it wants.

    In DragWindow::MessageReceived(), we receive the reply from the target and dispatch on the action found in the "what" code. For B TRASH TARGET, we close the window (with a confirmation dialog for good measure). For B COPY TARGET, we figure out whether to write data to a file (B FILE MIME TYPE) or to the message directly. In both cases we use the Translation Kit to translate from a BBitmapStream to the data type found in the DragView constructor. We do this because it's convenient, but the Translation Kit is entirely optional -- it's not at all required to implement the underlying dragging protocol.

    So what do you have to do to be at the receiving end of this protocol? Not much, really. You receive B SIMPLE DATA messages just like messages that have real data in them. If the B SIMPLE DATA message doesn't have a data type you understand in it, you can look for be:types to see if the initiator can provide data of some type you understand. If so, you send a reply back to the initiator (using SendReply()) with the type you want in "be:types" (and file type in "be:filetypes" if you want a B FILE MIME TYPE) and the "what" code set to the action you want (typically B COPY TARGET). In reply to this message, you'll receive a B MIME DATA message with the data in it, or, if you requested a file, the initiator will save the data to disk and then send a message back to you. DragMe, in this case, uses the default message error mechanism, so you should probably not fail on error messages received in reply to file save requests.

    That's it. Now don't drag your feet; go and implement drag-and-drop in your application today!


    BE ENGINEERING INSIGHTS: The Configuration Manager, Part I
    By Victor Tsou vyt@be.com

    The configuration manager, first introduced in BeOS Release 3, has been rewritten for Release 4. It is primarily used for supporting ISA Plug-and-Play devices, although its services will also be enlisted to help integrate PCMCIA. The HOTD is <drivers/config manager.h>. Stare at it, then continue reading.

    The configuration manager provides five classes of services:

    1. Initializing and uninitializing.
    2. Enumerating and reporting information about devices.
    3. Reporting the current configuration for devices.
    4. Interpreting configuration information.
    5. Reporting possible configurations for devices.

    1. Initializing and uninitializing.

    The configuration manager is implemented as a module, a construct introduced in R4 that is accessible only from kernel space. A module exposes itself to drivers via a structure of function pointers in a bid to be a better ioctl than ioctl. Modules are loaded as needed and unloaded when no longer used. To initialize the configuration manager, simply load the module in the usual fashion:

    config manager for driver module info *module;

    if (get module(B CONFIG MANAGER FOR DRIVER MODULE NAME,
        (module info **)&module) < 0)
      return B ERROR;
    

    Conversely, to uninitialize:

    put module(B CONFIG MANAGER FOR DRIVER MODULE NAME);

    Out of respect for reference counting, your driver should maintain a one-to-one correspondence between calls to get module and calls to put module.

    2. Enumerating and reporting information about devices.

    Once the configuration manager has been loaded, your device driver will feel compelled to scan for devices it knows about. The function

      status t (*get next device info)(
          bus type bus,
          uint64 *cookie,
          struct device info *info,
          uint32 info size);
    

    iterates through the devices on the specified bus, placing info size bytes of information about each device in a device info structure. For example, the following loop runs through the ISA devices:

    /* cookie = 0 signals start of enumeration */
    uint64 cookie = 0;
    struct device info info;
    
    
    

    while (module->get next device info( B ISA BUS, &cookie, &info, sizeof(struct device info)) == B OK) { ... }

    For completeness, the device info declaration:

    struct device info {
      /* Size in bytes of bus-independent and
       * bus-dependent data for this device */
      uint32    size;
    
    
      /* Offset, relative to the start of the structure,
       * to the bus-dependent data for the device */
      uint32    bus dependent info offset;
    
    
      /* B ISA BUS or B PCI BUS */
      bus type  bus;
    
    
      /* Device code, a la PCI */
      device type  devtype;
    
    
      /* "Normally unique and persistent" id for the
       * device */
      uint32    id[4];
    
    
      /* Device-independent flags */
      uint32    flags;
    
    
      /* If config status is B OK, the device is working
       * properly. Otherwise, the device is disabled and
       * should be ignored by device drivers */
      status t    config status;
    };
    

    The configuration manager will report up to size bytes of information about the device. This includes both bus-independent data, as described by the device info structure, and bus-dependent data, which appear beginning at offset bus dependent info offset in the returned buffer. Since you can't know how large the device information buffer should be until after you've read it, the configuration manager provides an additional function to load the device info for a specific device:

      status t (*get device info for)(
          uint64 device,
          struct device info *info,
          uint32 len);
    

    The revised loop now looks like this (with error checks stripped out):

    while (module->get next device info(B ISA BUS, &cookie,
        &info, sizeof(device info)) == B OK) {
      struct device info *dinfo;
      struct isa info *iinfo;
    
    
      /* only worry about configured devices */
      if (config status != B OK) continue;
    
    
      dinfo = malloc(info.size);
      module->get device info for(
          cookie, &dinfo, info.size);
      iinfo = (struct isa info *)((char *)dinfo +
          info.bus dependent info offset);
      ...
      free(dinfo);
    }
    

    ISA bus-dependent information is stored as isa info, defined in <drivers/isapnp.h>, and PCI-specific data are stored as pci info, defined in <drivers/PCI.h>. A driver typically peeks at the bus-dependent information to determine whether it can control a particular device.

    3. Reporting the current configuration for devices.

    Once a driver has identified a known device, it must fetch the device's configuration. This is done via a pair of functions:

      status t (*get size of current configuration for)(
          uint64 device);
      status t (*get current configuration for)(
          uint64 device,
          struct device configuration *config,
          uint32 len);
    

    These functions are usually called this way:

    status t result;
    struct device configuration *config;
    
    
    result = module->get size of current configuration for(cookie);
    if (result < 0) return B ERROR;
    config = malloc(result);
    if (!config) return B ERROR;
    if (module->get current configuration for(
        cookie, config, result) < B OK) {
      free(config);
      return B ERROR;
    }
    ...
    free(config);
    

    The device configuration is an array of resource descriptors representing the resources (IRQs, DMAs, I/O ports, and memory) assigned to the device. Resource descriptors come in two flavors. IRQs and DMAs are described as masks, while I/O ports and memory are described as ranges. Masks are bitfields, with the nth bit representing the nth IRQ or DMA. Exactly one of the bits will be set in each mask. Ranges are described by two values, the minbase and the len, with the range running from minbase to minbase + len - 1, inclusive.

    4. Interpreting configuration information.

    The following routines help drivers wade through device configurations:

      status t (*count resource descriptors of type)(
          const struct device configuration *config,
          resource type type);
      status t (*get nth resource descriptor of type)(
          const struct device configuration *config,
          uint32 n,
          resource type type,
          resource descriptor *descriptor,
          uint32 descriptor size);
    

    These function precisely as their names and prototypes suggest.

    5. Reporting possible configurations for devices.

    The configuration manager selects configurations for devices based on sets of possible configurations reported by each device. Drivers typically won't ever need to access these configurations; they're provided for the benefit of device management utilities such as the new Devices preference application.

      status t (*get size of possible configurations for)(
          uint64 device);
      status t (*get possible configurations for)(
          uint64 device,
          struct possible device configurations *possible,
          uint32 len);
    

    possible device configurations is an array of device configuration structures, with each element representing a set of possible configurations. Since the size of a device configuration is variable, you can't access individual device configurations by directly indexing the array. Instead, you have to walk the structure manually:

    #define NEXT POSSIBLE(c) \
      (c) = (struct device configuration *) \
        ((uchar *)(c) + \
        sizeof(struct device configuration) + \
        (c)->num resources * \
        sizeof(resource descriptor))
    
    
    struct device configuration *config =
        possible->possible + 0;
    
    
    for (i=0;i<possible->num possible;i++)
    {
      ...
      NEXT POSSIBLE(config);
    }
    

    Descriptors for possible configurations differ slightly from their current configuration counterparts since they represent a set of possible choices rather than a single selection. Masks may have multiple bits set, with each bit representing a possible IRQ or DMA setting. Ranges are described by a minbase, a maxbase, a basealign, and a len, describing a range starting between minbase and maxbase, in increments of basealign, and having length len.

    Most APIs make more sense when you see them in action, so next time we'll develop an application demonstrating the use of the configuration manager.


    DEVELOPERS' WORKSHOP: Back to Basics
    By Stephen Beaulieu hippo@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.

    In this article I'm going to reinvestigate some of the basic building blocks of the BeOS. We'll look at what I'll call the AppKit model: BMessages, BLoopers, BHandlers, and BMessengers.

    The BMessage is fundamentally a data container, commonly used to hold both instructions and data to be acted upon. BHandlers are objects that perform an action when BMessages are delivered to them; they handle the incoming message. BLoopers are threaded BHandlers that run a message loop, waiting for incoming BMessages and dispatching them to the appropriate BHandlers. BMessengers are system wide tokens that represent a given BLooper-BHandler pair, delivering messages to (and replies from) the specified BHandler.

    The most visible examples of BLoopers and BHandlers are BApplications, BWindows, and BViews. These lie at the heart of the BeOS APIs, and are common to most BeOS applications. Many developers, however, seem to use the AppKit model only in their interface areas, where it is pretty much required. Since the AppKit model has other valid uses, I'm going to offer some design ideas that may persuade developers to take advantage of its versatility.

    First though, a list of the AppKit model's advantages and disadvantages to keep in mind while reviewing my designs.

    Advantages:

    • Uses a common, familiar system where a great deal of organizational work is handled by the BeOS. This includes a well-defined communication system, automatic threading of your app, and built-in object management through the BLooper AddHandler and RemoveHandler functions.

    • The public class interface is easily extendable by extending the messaging protocol used. The functions to handle the new messages are usually private functions, and can be extended as necessary.

    • The interface can be exposed to interapplication systems by publishing the messaging protocol. This allows other apps doing complementary work to interact with your application easily.

    • The system interface is eligible for scripting, since the AppKit model is the basis of the BeOS scripting mechanism.

    Disadvantages:

    • A BLooper thread's main responsibility of is to run the message loop, not some other tasks. To have threads work on other tasks requires using Kernel Kit threads. The BLooper threading model is therefore not always appropriate to the task at hand. However, combining the two models can work well (i.e., a BLooper with extra, special-purpose threads for other tasks).

    • BHandlers can belong to only one BLooper, effectively serializing access to each handler. This can be problematic in a system where the BHandler would (ideally) be accessible by multiple threads. Some designs can work around the limitation by creating a new BHandler subclass for each BLooper, but this works only when the BHandlers themselves do not encapsulate data that needs to be instantiated only once.

    • Adding information to BMessages requires copying that data. This can introduce significant overhead if large amounts of information need to be transmitted, or if the data needs to be looked at many times over the course of an operation. Introducing other methods of data sharing (like putting a reference to a shared memory area or a pointer to data into the BMessage) can reduce the size and complexity of the messages. Note that this might lead to some undesirable consequences, as the recipient of the BMessage no longer has to go through the messaging mechanism to access the data.

    Keeping these advantages and disadvantages in mind, here are two design schemes that use the AppKit model: the Handler as Data Object and Handler as Operation.

    Handler as Data Object

    In this scheme, the BHandler contains both the data to be acted upon and the knowledge of how modifications are to be performed. The data is encapsulated in a self-modifying object. BMessages serve as instructions for what actions to perform. The BLooper serves as the initial interface to the various objects, but would usually pass back BMessengers for the appropriate data objects, so the outside processes can deal with them directly.

    Example: Transaction Server

    Here, the data object can be independently acted upon by multiple threads/applications while in a guaranteed consistent state. BMessages instruct the server to create, delete, or modify objects. Change notifications can be sent back to all interested processes. Furthermore, the transactions can be recorded so that a previous state could be reinstated by rewinding the transaction stack.

    Handler as Operation

    In this scheme, each BHandler represents an operation that can be performed on some data. The BMessage carries the data to modify and instructions about which operations to carry out. The BLooper serves as a common interface to the operations, investigating the instructions and passing the data to the operations in the correct order, then sending the modified data back to its origin.

    Example: Data Filters

    Use BHandlers to represent add-on filters to manipulate data. Have each add-on create an entry function that returns a BHandler that performs the appropriate filter. Then simply pass the data to each filter as appropriate. This could be parallelized by calling the entry function for a new BHandler for each thread that needs a copy of the filter, at the expense of more memory.

    Example: State Machine

    A BLooper represents a state machine, with BHandlers representing each state. The looper passes the appropriate instructions off to each state, which responds to them and asks the BLooper to change state when appropriate. In this example, the BLoopers might contain the data to act upon, rather than a BMessage, but the view from the BHandler is the same.

    You can find some simple example code for these two schemes at:

    <ftp://ftp.be.com/pub/samples/application_kit/AppKitModel.zip>

    Both schemes perform the same work, transforming strings to uppercase, lowercase, or mixed case (with every word capitalized.) They implement the code to modify the strings the same way, using the BString class functions: ToUpper, ToLower, and CapitalizeEachWord. They also act on the same two strings. The only difference between the two examples is the schemes used to organize the code (and correspondingly, the printed output).

    This structure is obviously overkill for simple string modification, but the schemes become more useful as the complexity of the data and operations increases. Strings are just an easy way to demonstrate the various designs. The Notes file in each folder explains how the project is put together. Also, note that both applications are useful only when run from the command line, as all feedback is through printf() calls.

    I hope these designs can be helpful in your programs, or at least will start you thinking more about the overall design of your application.


    Our Take on AOL's Acquisition of Netscape
    By Jean-Louis Gassée

    A week ago, when the rumors of AOL's acquisition of Netscape were confirmed, I didn't think it had much immediate impact on our company. Others differed. I received several e-mail messages asking what our position was. Correspondents were of the opinion that every move against Microsoft implicitly favors us, and thought the reference to an "AOL appliance" indicated an opportunity for a BeOS-powered Web appliance. And, last Friday, I found this in the San Jose Mercury News:

    <http://www.mercurycenter.com/premium/business/docs/loveqa27.htm>

    Selected quotations from the full story:

    One leading critic of this acquisition is Jamie Love, an antitrust economist and director of the Ralph Nader-affiliated Consumer Project on Technology in Washington, D.C. His group was among those that successfully lobbied for the government to change WorldCom Inc.'s plans to acquire MCI Communications Corp., the long-distance phone company, earlier this year.

    Now, Love wants to block the AOL-Netscape agreement because he believes it eliminates Netscape, a significant Microsoft rival, and gives two companies -- AOL and Microsoft -- too much power to impose their own company-controlled software on the Internet.

    Love discussed his concerns with Mercury News staff in the following edited answers to questions posed by e-mail.

    [...]

    Q: So what changes might you seek in the AOL-Netscape deal?

    A: There are several areas where the AOL-Netscape merger concerns us. Will AOL and Microsoft exert so much power in e-commerce that they can extort revenues from firms that they feature for their customers? Will they undermine non-affiliated technologies for new multimedia services? Will AOL strike a deal with Microsoft to drop support for applications that run on Linux (a version of the Unix operating system that is freely available on the Internet) or other operating systems? Maybe AOL could (be compelled to) agree to support AOL and Netscape on Linux or BeOS (an operating system made by Be, Inc.) and promote greater choices for PC operating systems.

    This is healthy publicity, and probably even friendlier in intent than the plug we got from Bill Gates at Microsoft's shareholders meeting almost three weeks ago. But we shouldn't let only others speak on our behalf, however eloquent and motivated.

    First, I heard and read suggestions that since the AOL/Netscape deal was against Microsoft then there must be something in it for us. The logic is understandable: Microsoft abuses its dominant position, so let's do anything we can to diminish their power. This is flawed logic, however. A benevolent regime doesn't automatically follow a toppled tyrant, as history and contemporary events demonstrate painfully enough.

    In our view, being against Microsoft isn't good or bad in itself. What is good is more choice -- real choice -- not, for example, the kind we used to have with only two cellular service providers in town, GTE and Cellular One. Economists established long ago that oligopolies aren't really an improvement over monopolies. With this in mind, let's hope the AOL/Netscape deal really does create more choice, not the kind of diversity that results only in more people like us, not more people like them.

    (For another very good piece on the topic, see Denise Caruso's November 30th column in the New York Times: <http://www.nytimes.com/library/tech/98/11/biztech/articles/30digi.html>).

    Personally, I imagine Microsoft thinks there must be a god and she likes Bill. Try selling this script in Hollywood: right in the middle of the "trial of the century," two of the cyber-tyrant's alleged victims merge to form an Internet powerhouse that subverts, if not entirely kills off, the DOJ's argument. The studio would banish you to North Korea on a mission to teach market economics.

    Just ten days ago, Microsoft's PR machine was straining against the bad impressions generated by Bill Gates' video deposition. Now they're working full time on the new message: We told you so, Microsoft is a company constantly under competitive threat.

    As for Web appliances, yes, the concept is gaining momentum and the BeOS could make a contribution at the intersection of two requirements, rich multimedia user experience, the NC with charm, and a small core enabling fast, inexpensive devices. That would create more choice. Unless Microsoft, never asleep at the wheel, embraces and extends it -- as always. I hear they already have a name for it. PortalPC. Has a nice ring to it.


    Recent Be Newsletters | 1998 Be Newsletters
    1997 Be Newsletters | 1995 & 1996 Be Newsletters

    Copyright ©1998 Be, Inc. Be is a registered trademark, and BeOS, BeBox, BeWare, GeekPort, the Be logo and the BeOS logo are trademarks of Be, Inc. All other trademarks mentioned are the property of their respective owners. Comments about this site? Please write us at webmaster@be.com.