Issue 2-45, November 12, 1997

Be Engineering Insights: YABSA—Yet Another Byte-swapping Article

By Bradley Taylor

I really didn't want to write another byte-swapping article. But I had to. You see, every night I wake up from a recurring nightmare that some poor BeOS user will be unable to interoperate their BeOS app between Intel and PowerPC machines. I toss and turn, gripped with worry and unable to fall back asleep. Then I think of the public flogging the guilty application writer will get for this terrible deed, and I drift back into a pleasant slumber.

The truth is that PR2 has some new byte-swapping macros to prepare you for our Release 3 Intel release and I wanted to tell you about them. Judicious use of these macros *now* will mean that in most cases your application will recompile and interoperate when Release 3 rolls around later.

The new stuff in PR2 is contained in the file byteorder.h. The macros can be summarized as follows:

B_LENDIAN_TO_HOST_XXX()
  convert from little-endian to host format

B_BENDIAN_TO_HOST_XXX()
  convert from big-endian to host format

B_HOST_TO_LENDIAN_XXX()
  convert from host to little-endian format

B_HOST_TO_BENDIAN_XXX()
  convert from host to big-endian format

Where XXX equals one of the following types: INT16, INT32, INT64, FLOAT or DOUBLE. These macros swap in the case where the host format doesn't match the desired format (big or little endian), but are no-ops in the case where the host format matches the desired format.

Additionally, byteorder.h contains two identifiers that will tell you the host endianness:

B_HOST_IS_LENDIAN
  1 on Intel, 0 on PowerPC

B_HOST_IS_BENDIAN
  0 on Intel, 1 on PowerPC

Here is a simple example demonstrating usage of these new macros. If you read something from a device register (typically little-endian), you might write some code like this to read the data out into a useful form:

count = B_LENDIAN_TO_HOST_INT32(device_registers->count)

On Intel, this macro does nothing, but on PowerPC it will swap the data for you. It's much easier to read code like this than code that contains a lot of #ifdefs to deal with byte-order issues. #ifdefs are generally frowned upon, and you should be ashamed of yourself if you use them.

The following sample program further demonstrates the usage of these new macros:

#include <stdio.h>
#include <stdlib.h>
#include <byteorder.h>

/*
 * Simple employee record
 */
typedef struct {
  char first_name[16];  /* First name */
  char last_name[16];   /* Last name */
  float salary;         /* Salary */
  int16 number;         /* Employee number */
  char lendian;  /* Is record in little-endian format? */
  char padding;  /* Padding, to float boundary (4-bytes) */
} employee_t;

/*
 * Convert an employee record to host format
 */
static void
convert_to_host_format(employee_t *emp)
{
  if (emp->lendian) {
    /*
     * Little-endian to host conversion
     */
    emp->number = B_LENDIAN_TO_HOST_INT16(emp->number);
    emp->salary = B_LENDIAN_TO_HOST_FLOAT(emp->salary);
  } else {
    /*
     * Big-endian to host conversion
     */
    emp->number = B_BENDIAN_TO_HOST_INT16(emp->number);
    emp->salary = B_BENDIAN_TO_HOST_FLOAT(emp->salary);
  }
}

main(int argc, char **argv)
{
  employee_t emp;

  switch (argc) {
  case 1:
    /*
     * Read an employee record from standard input
     * and print it
     */
    if (fread(&emp, 1, sizeof(emp), stdin) != sizeof(emp)) {
      fprintf(stderr, "Error reading employee record\n");
      exit(1);
    }

    convert_to_host_format(&emp);

    printf("Name: %s %s, #%d, $%8.2f\n",
        emp.first_name,
        emp.last_name,
        emp.number,
        emp.salary);
    break;

  case 5:
    /*
     * Use the command-line arguments to create an
     * employee record
     * and write it to standard output.
     */
    memset(&emp, 0, sizeof(emp));
    strcpy(emp.first_name, argv[1]);
    strcpy(emp.last_name, argv[2]);
    emp.number = atoi(argv[3]);
    emp.salary = atof(argv[4]);

    /*
     * Note endian-ness for reading later
     */
    emp.lendian = B_HOST_IS_LENDIAN;

    if (fwrite(&emp, 1, sizeof(emp), stdout) != sizeof(emp))
    {
      fprintf(stderr, "Error writing employee record\n");
      exit(1);
    }
    break;
  default:
    fprintf(stderr, "incorrect number of arguments\n");
    exit(1);
  }
  exit(0);
}

This program reads and writes employee records. The records can be written on Intel and read by PowerPC or vice-versa. The program is written in a style I prefer, which is to never swap when writing data, as long as there is an extra field to indicate the endianness of the data when written. Then when reading, you swap the data only if necessary. The advantages of this style are the following:

  1. You don't swap when exchanging data between like-minded machines, like Intel to Intel or PowerPC to PowerPC. This is the common case, after all.

  2. The code is easier to understand, because there is only swapping code for one direction (reading). The write case looks pretty much like it would if you didn't have to worry about these things (but unfortunately, you do).

Sometimes you don't have the liberty to define your own data format because you are dealing with some standard format, such as JPEG or device registers. The macros will still be helpful to you in this case, and I recommend using them.

These macros won't solve all of your interoperability problems. You still need to worry about alignment issues. The employee record in this sample program was carefully laid out to be interoperable using natural alignment techniques. Natural alignment is the subject of a previous Newsletter article...

Be Engineering Insights: Will Your DATA Look Like ATAD?

...and won't be discussed further here.

So, that's all I have to say. There is now plenty of information available to you on how to prepare for Intel. If you design your PR2 application right, it is possible to just recompile it for Release 3/Intel and have it interoperate with PowerPC. If you can do this, pour yourself a drink and enjoy it. You deserve it.


How to Make a Million Dollars Developing for the BeOS (No Kidding)

By Dave Johnson

In the short time I've been at Be I've been getting in touch with as many of our developers as I can. I hear a lot of developers say, "I don't want to risk doing apps for the BeOS until there are lots of apps out for it."

To address this I have here a somewhat edited version of an e-mail exchange I had with a developer. (I rewrote it to make me look good.) Reading this just might make you a million dollars.

ME: Hi, I'm Dave Johnson, new Developer Evangelist at Be, Inc. I'm going through the database becoming familiar with all the developers, etc.

DEVELOPER: Dave, as much as I love the BeOS, I have to hold off developing for it until we see Premiere, Photoshop, or After Effects running on it. Until there are big-name applications I don't think you'll have the customer base to support my product.

ME: You already know the BeOS is a powerful tool that enables you to write applications with significantly superior performance—RIGHT NOW -- so you CAN solve specific problems for specific customers. The fact is that there are customers out there who want that performance because it will save them time and money. So for them the argument about whether there are "enough applications" is irrelevant. Service bureaus, video editors, graphic design houses don't CARE if Quicken is on the BeOS yet! They care if you can help them save or make money.

Developers who worry about the size of the existing customer base believe that you write a generic application and just sort of put it out there and wait for customers to come to you. In fact this is already happening. We're doing everything we can to get the BeOS into the hands of lots and lots of computer users. But there's also another way to look at this situation.

DEVELOPER: What's that? If you're telling me not to worry about your existing customer base, how are you proposing I can make money now?

ME: By solving specific problems for specific customers—that's how people get rich. If you solve one problem in a compelling way for customers they'll pay you for doing it. Developers who write products that solve specific problems will do well. The BeOS exists, developers understand what it's good at, and you're going to see very good products with vastly superior performance running on it. So why don't YOU do one? Why don't YOU get there first and establish your specific area of problem solving? How often do opportunities like that come up?

DEVELOPER: I don't do one, because I really don't want to reinvent the wheel.

ME: DUDE! Reinventing the wheel on a multi-threaded symmetric multiprocessing OS means that you'll have something to show that blows the customers away! You'll either make a mint selling to those customers, or Adobe will BUY IT from you when they decide it's time to be on the BeOS. You want to be there first.

DEVELOPER: Well. . .

ME: Name one other OS that gives you superior performance on the same hardware. Be is going to do well because it is a compelling solution. Developers know that as soon as they see and use the BeOS. And YOU will win by writing applications that take advantage of the BeOS's performance to solve problems for customers.

DEVELOPER: Yes, the BeOS is a compelling solution, and yes, the geeks get it. But it does no good if the geeks aren't _allowed_ to develop for it. Adobe isn't going to port until they know that Be's "viable," financially. I think you guys are doing a great job, and the BeOS is coming right along. PR2 is great! The real truth is that you guys have absolutely no competition. You blow NT out of the water, and make the Mac OS look like a hack.

BUT I still think your main goal should be getting as many apps, and the sexiest apps on board. Get Adobe to sign on. No one wants to spend money on a set of apps that are all 1.0 versions, from tiny three-person startup companies!

ME: Leading edge developers think that entering an arena where there is limited competition is a GREAT idea! They see it as a huge opportunity. How often do you get opportunities like this?

DEVELOPER: But why would a customer buy my product—even one tailored to solve a specific problem—to run on an OS that he isn't already using?

ME: Because applications running on the BeOS demonstrate significant performance improvements that translate into MONEY for the customer. Visit some of those customers and learn their needs. Take a multiprocessor computer with you and show a finished app that uses threaded multiprocessing and does one thing for them in a third of the time it takes them now. Just ONE thing. You can do that with the BeOS. Think about all those service bureaus, all the Kinkos, graphic designers, photo processors, video editors, musicians, you name it...

Time is money, and speeding things up saves money for those businesses. Lots of businesses are performing some task on a computer that operates inefficiently. Apps running on the BeOS will outperform apps running on Mac or Windows or NT. Period.

DEVELOPER: Gosh. I'm glad I listened to you. I AM going to go out and develop a BeOS application and make a million dollars!

SUMMARY: Hey you developers, listen up, it's opportunity knocking! What I'm suggesting is that you locate key target business segments and find out specifically where in their business the benefits of BeOS will make them money. Find out where they are bogged down by slow programs, which programs, etc... Then YOU develop a product that takes advantage of the BeOS to solve that performance problem. Customers will PAY YOU to do that! The developers that write those applications for those customers are going to make a lot of money.

Go out there and DO IT.


Developers' Workshop: Sounds That Go Bump In the Night

By Eric Shepherd

"Developers' Workshop" is a new weekly feature that provides answers to our developers' questions. Each week, a Be technical support or documentation professional will choose a question (or two) sent in by an actual developer and provide an answer.

We've created a new section on our website. Please send us your Newsletter topic suggestions by visiting the website at: http://www.be.com/developers/suggestion_box.html.

So I'm sitting here at my desk, minding my own business and writing lovely new documentation for the Media Kit, when all of a sudden the powers that be decide to have the new guy start writing articles for the Newsletter. After momentarily thinking that was a pretty good joke, I realize they're actually serious.

As this slowly sinks in, I'm staring at my screen, where pages and pages of sample code and half-written Media Kit documentation are mocking me. Slowly it dawns on me that I can impress everyone with my speedy article writing by ripping out a piece of one of these sample programs I've been working on and writing an article about it.

After perusing my source code, I realize that what I have in my hands is nothing less than the answer to the age-old question: "How do I take an arbitrarily formatted sound and stuff it into that 16-bit stereo sound stream?"

What I'll present here is a C function that can mix any sound format into a stream buffer. Ideally, you'll take this code and convert it into a member function in your sound output class.

The BeOS audio streams (both input and output) are 16-bit stereo. Once you've subscribed to the output stream (by creating a BDACStream object and subscribing to it with a BSubscriber), you can enter the stream and start receiving buffers of audio data that you can alter to your heart's content.

This is great when the sound you want to play is in 16-bit stereo form. But things get ugly when it's 8-bit mono or some other format. Then you have to manually fix things like sample size and endianness, and mix the sound into the stream, preferably without destroying whatever sound is already in the buffers you receive.

Since you always know what format the output stream is going to be, you can make your life easier by defining a structure I call standard_frame, which defines the format of a single frame of audio data in 16-bit stereo format:

struct standard_frame {
  int16  left;    // Left channel's sample
  int16  right;    // Right channel's sample
};
typedef struct standard_frame standard_frame;

Now you can create the MixStandardFrames() function. It accepts a lot of parameters. When you add this function to your audio output class, you can probably eliminate a lot of these parameters by referencing member variables of your class instead.

status_t MixStandardFrames(char *soundData, int32 index,
  int32 count, standard_frame *out, int32 fileFormat,
  int32 byteOrder, int32 sampleSize, int32 channelCount) {

soundData is a pointer to a buffer containing the sound data to mix into the output buffer. To make your life really easy, it takes a pointer to the beginning of the complete sound. The index parameter is the frame number of the sound to start playing at. So if you want to play starting at the 5,000th frame of the sound, you'd pass a pointer to the 0th frame in soundData and the number 5,000 for index.

The count parameter is the number of frames you want to mix, and out is a pointer to a 16-bit stereo sound buffer into which those frames will be mixed. The remaining parameters specify the file format (B_WAVE_FILE, B_AIFF_FILE, etc), byte order (B_BIG_ENDIAN or B_LITTLE_ENDIAN), sample size (1 or 2 bytes), and channel count (1 or 2 channels, for mono and stereo). These parameters allow MixStandardFrames to interpret the incoming data correctly.

MixStandardFrames has lots of local variables. The shortIn, byteIn, and ubyteIn pointers will be used for type-casted pointers to the sound data. The other parameters are used, as you'll see later, by the code that does the actual mixing of the sound data.

register short *shortIn;    // Used for 16-bit samples
register char *byteIn;      // For 8-bit signed samples
register uchar *ubyteIn;    // For 8-bit unsigned samples
register int32 sample0, sample1; // Mixed left and right samples
register int32 temp0, temp1;  // Used in clipping computation
register int32 stereo;        // Stereo or not?
register int32 frame;    // The frame offset being processed

The first thing to do is verify that the input pointers aren't null. That would be a bad thing, and as good programmers we fear bad things, so check for that straight off.

if (!soundData || !out) {
  return B_ERROR;
}

Then set the stereo variable to 1 if the sound you're playing is in stereo format, or 0 if the sound is mono. This will be used as a multiplier as you make your way through the input sound data.

if (channelCount == 1) {
  stereo = 0;
}
else {
  stereo = 1;
}

Now it's time to prepare for the real work. Set up byte, unsigned byte, and short pointers to the first frame of the sound data to be played. When you actually start processing the data, you'll use the pointer appropriate to the type of input data you have. The pointer is cast to the appropriate type and you add the offset to the specified first frame.

The offset is either index or index*2, depending on whether or not the sound is stereo or not. So you multiply index by stereo+1, which will either be index*1 or index*2. The result is a pointer to the first frame to be processed.

Then you initialize the frame counter to zero.

byteIn = ((char *) soundData)+(index*(stereo+1));
ubyteIn = ((uchar *) soundData)+(index*(stereo+1));
shortIn = ((short *) soundData)+(index*(stereo+1));

frame = 0;      // Start at the very beginning
                // (a very good place to start)

Now it's time to process the actual sound. Start by dealing with 8-bit sounds, which have a sample size of one byte. Loop through each frame, from 0 to count, using the frame variable as a counter.

if (sampleSize == 1) {
  while (frame < count) {
    if (fileFormat == B_WAVE_FILE) {
      sample0 = out->left + (int32) (int8)
        (*ubyteIn - 128) << 8;
      ubyteIn += stereo;
      sample1 = out->right + (int32) (int8)
        (*ubyteIn - 128) << 8;
      ubyteIn++;
    }
    else {
      sample0 = out->left + (int32) (int8) (*byteIn) << 8;
      byteIn += stereo;
      sample1 = out->right + (int32) (int8) (*byteIn) << 8;
      byteIn++;
    }

The above code computes one frame of mixed sound data. Note that 8-bit WAVE files get special treatment. That's because 8-bit WAVE format samples are unsigned, rather than signed. So you have to convert the data into signed format by subtracting 128 from the samples.

sample0 is the left channel's sample. Grab the next sample from the buffer containing the sound you're playing (pointed to by either ubyteIn or byteIn), shift it left eight bits to convert it into a 16-bit number, and add it to out->left, which is the existing sample in the output buffer.

Now add the value of the stereo flag to the input pointer. This will only increment the input pointer if the sound is in stereo format (remember that stereo is 0 for mono and 1 for stereo). That way, when you read the right channel, if the sound is stereo, you'll get the right channel's sample, but if the sound is mono, the left channel will be duplicated into the right.

Process the right channel's sample, sample1, the same way.

Now you have to deal with possible clipping problems. Clipping occurs when the value of the mixed samples is outside the range that can be represented by a 16-bit number. This is why you mix the sounds in 32-bit variables: You can detect overflow and compensate for it.

First, add $8000 to the left and right samples we've mixed, then mask off the low word. This value, stored in temp0 for the left channel and temp1 for the right, is non-zero if the sample overflowed.

Now store the sample into the output buffer. If temp0 (for the left channel) or temp1 (for the right channel) is non-zero, replace the output sample with $7FFF if the sample is positive (this is the maximum possible sample value) or $8000 if the sample is negative (this is the minimum possible sample value). This clips the sample to the range of valid 16-bit integers without accidentally wrapping around and sounding *really* strange.

Finally, increment the out pointer to point to the next frame of audio in the output buffer, and increment frame, which is the number of frames you've processed so far, and continue looping until the desired number of frames have been mixed into the output buffer.

    temp0 = (sample0 + 0x8000) & 0xFFFF0000;
    temp1 = (sample1 + 0x8000) & 0xFFFF0000;
    out->left = sample0;
    if (temp0) {
      out->left = (sample0 > 0 ? 0x7FFF : 0x8000);
    }
    out->right = sample1;
    if (temp1) {
      out->right = (sample1 > 0 ? 0x7FFF : 0x8000);
    }
    out++;      // Next slot in the output buffer
    frame++;    // Next frame of input
  }
}

16-bit input data is handled almost exactly the same way, with two significant differences: WAVE files don't need special consideration, and you have to deal with both big-endian and little-endian input.

Since BeOS is natively big-endian, you have to use the read_16_swap() function to read little-endian data. This function returns, byte-swapped, the 16-bit value located at a given address. The input data is pointed to here by shortIn, which represents the 16-bit input data. Otherwise, this code is exactly the same as the 8-bit code above.

else {
  while (frame < count) {
    if (byteOrder == B_LITTLE_ENDIAN) {
      sample0 = out->left + (int32) read_16_swap(shortIn);
      shortIn += stereo;
      sample1 = out->right + (int32) read_16_swap(shortIn);
      shortIn++;
    }
    else {
      sample0 = out->left + (int32) *shortIn;
      shortIn += stereo;
      sample1 = out->right + (int32) *shortIn;
      shortIn++;
    }

    temp0 = (sample0 + 0x8000) & 0xFFFF0000;
    temp1 = (sample1 + 0x8000) & 0xFFFF0000;
    out->left = sample0;
    if (temp0) {
      out->left = (sample0 > 0 ? 0x7FFF : 0x8000);
    }
    out->right = sample1;
    if (temp1) {
      out->right = (sample1 > 0 ? 0x7FFF: 0x8000);
    }
    out++;    // Next slot in the output buffer
    frame++;    // Next frame of input
  }
}

Finally, return B_OK to indicate that, as far as this code can tell, nothing went too terribly wrong while mixing the sound data:

  return B_OK;
}

This code can be called easily from your stream function to mix any kind of sound data into the output stream. The following sample hook function assumes the existence of certain variables. Normally you'll have these within the class containing the hook function, but space doesn't permit me to show the entire class. These variables are:

playFrameNumber: Specifies the frame number of the first frame of audio data to play.

soundLength: Specifies the length, in frames, of the sound being played.

soundData: Pointer to the sound data to play.

fileFormat, byteOrder, sampleSize, and channelCount specify the file format, byte ordering, sample size, and number of channels in the sound. These are passed straight through to MixStandardFrame().

static bool OutStreamHook(void *userData, char *buffer,
  size_t count, void *header) {
  int32 frameCount;

  // If the sound is done playing, exit the stream

  if (playFrameNumber >= soundLength) {
    return false;
  }

  // Compute the number of frames to copy

  frameCount = count/4;    // Compute buffer size in frames
  if ((soundLength-playFrameNumber) < frameCount) {
    frameCount = soundLength-playFrameNumber;
    if (!frameCount) {
      return false;       // No more data!
    }
  }

  // Mix ourselves into the buffer.

  MixStandardFrames(soundData, playFrameNumber, frameCount,
     (standard_frame *) buffer, fileFormat, byteOrder,
     sampleSize, channelCount);
  playFrameNumber += frameCount;
  return true;
}

This hook function starts by looking to see if the sound has finished playing (the frame to be played is greater than or equal to the number of frames in the sound); if so, it returns false, which tells the BSubscriber to remove us from the stream.

Now compute the number of frames to copy into the buffer, by dividing the size of the file in bytes by four and storing that result in frameCount. Each frame of 16-bit stereo sound is four bytes long.

If the number of frames left to play in the sound (soundLength - playFrameNumber) is less than the number of frames in the buffer, change frameCount to that value. This can happen when you are approaching the end of the sound, and there are fewer frames of sound left to play than there are in the buffer you've received.

Once that's all done, call MixStandardFrames() to mix the sound into the buffer, then add frameCount to playFrameNumber to keep track of the next frame to be played. Finally, return true, which tells the BSubscriber that you're not done playing yet.


BeOS on the Web

By Jean-Louis Gassée

Perhaps this isn't the best of weeks to discuss e-commerce, right in the wake of an ambitious announcement from one of our noble and worthy elders, but we just made the BeOS available for Web download (visit http://www.be.com/products/beos_download/.

From one angle, this isn't news, we said we'd do it, we're doing it, a little late, we're just doing our job and, in any case, doesn't everyone promote and deliver their software on the Web? True. But, from another angle, our latest move raises a few questions. The hardest one stems from the "free trial" status of our product. If we start on that slope, some critics say, how are we going to make money, how are we going to wean users from the "free BeOS habit"?

Here is our perspective: The world isn't waiting for us, we've got to earn the trust and the commitment of developers and customers. The BeOS is an unproven platform within a context where one company, Microsoft, is enormously successful, and other operating systems have slowed down, in the best of cases, or failed. Of course, in order to make our case, we can write columns, go to industry conferences and give speeches, or go to trade shows and run demonstrations. This is good, necessary perhaps, but not sufficient.

Clearly positioning the product is good, comparing the benefits of a specialized Media OS versus the comforts and limits of a general-purpose platform is commendable marketing hygiene. Opposing IBM's strategy with OS/2 (better DOS than DOS, better Windows than Windows) to our goal of coexisting with Windows is a useful disclaimer.

But, in the end, the most potent marketing weapon in our business still is word-of-mouth. If users and developers say good things about the BeOS and our company, its business practices and its people, this is much more credible than any commercial. If, on the contrary, our product is perceived as poorly designed, our staff as unresponsive, no amount of advertising will correct the problem.

This is well and good, but it doesn't quite address the "freebie habit" problem. Why don't we charge for PR2 downloads? After all, it's nice, stable and usable, right?

Right now, our view is we need to develop the installed base of BeOS users more than we need the revenue. We'd rather make this investment as soon as possible, learn what users like and dislike and maximize the installed based BeOS developers can count on.

And, as we plan to enter the Intel space, we want to gather as much momentum and experience as possible, while keeping in mind that this new field isn't the PowerPC market, only bigger. Mac developers have discovered that fact when they moved to Windows. The context, the competition, the belief systems, the purchasing habits are all different. Which puts us in the slightly paradoxical situation of wanting to gain experience quickly while realizing that the knowledge gained must be applied selectively.

Back to the main issue, our current plan is to let the trial version, free, and the paid for product coexist. Many companies do that today, and rather successfully. You can use Eudora Lite or pay for Eudora Pro, your choice. You can use QuickView, or pay for the QuickView Plus version, both very nice products. And there are many, many more such examples.

These companies obviously want to make it easy for the prospective paying customer to make up his or her mind, and they have faith in the statistical outcome of the trial. Qualcomm, for instance, knows some people will keep using the "free" Eudora Lite instead of forking the $50 or so required for the Pro version. But, as long as the "Lite" users are happy, they contribute to the positive buzz about Eudora. This, I hasten to say, doesn't mean to represent our detailed calculus of possibilities for the free vs. paid for versions of the BeOS, these examples merely intend to show it can work and that users are willing to move from free to "commercial."

We'll keep in mind that history repeats itself in mysterious way as we happily add bandwidth for the demand created by the Web availability of our product—and as we are chasing freshly discovered bugs.


BeDevTalk Summary

BeDevTalk is an unmonitored discussion group in which technical information is shared by Be developers and interested parties. In this column, we summarize some of the active threads, listed by their subject lines as they appear, verbatim, in the mail.

To subscribe to BeDevTalk, visit the mailing list page on our web site: http://www.be.com/aboutbe/mailinglists.html.

NEW

Subject: Workspace dragging

The drag-a-window-between-workspaces feature was a new found source of amusement for one of our listeners. Although initially offered as an off-topic thread, others joined in to offer window management suggestions:

  • Hot-key window delivery: Bucky bit-click on a window to send it to some other workspace.

  • Workspace scrolling.

  • Multiple graphics card support, with separate workspaces running on each.

  • Spatial arrangement of workspaces to support multi-headed setups.

  • Smarter desktop layout when switching from a big to a small workspace.

The spatial arrangement/multi-headed question generated the most debate: Should individual workspaces be views into a single universal workspace area? Should each monitor have its own list of workspaces that it can switch to, exclusive of all other monitors? And so on.

Subject: Web Browser

Jerome Chan is curious:

How hard is it to write a web browser? I mean, if the Linux people can write an entire OS why can't we write a web browser ourselves?

Craig Longman suggests looking at the HTML spec to get an idea of the task's complexity. And then move on to Java, and JavaScript, and CSS... Pierre-Emmanuel Chaut pointed out that many of the elements of a good browser are already available (through Kftp, rRaster, Felix, and so on). It's (ahem) simply a matter of putting the pieces together. Various members of the BeDevTalk community offered their services for a international group effort.

The thread then veered into a discussion of XML ("Extensible Markup Language") vs HTML. Is XML the Web language of the future?

Subject: VirtualMemory Swap on Alternate Drive

Swap file questions:

  • How about providing a "remote" swap file feature, in which the swap file is on a different drive?

  • How about a swap file on a separate partition?

  • the kernel handle multiple swap files?

The swap-file-across-a-wire idea was generally accepted as an obviously beneficial improvement. But does it make sense to dedicate a partition as a swap file? Jake Hamby points out that the BeOS is quite efficient when handling VM I/O, so assigning a partition might not gain anything. Osma Ahvenlampi offered this: If you can physically place the partition on the outer cylinders, you can take advantage of the cylinders' naturally heightened speed.

THE BE LINE: (From Dominic Giampaolo) Although the kernel can handle "remote" swap files, there's currently no way to tell it to do so. We'll consider it, but it's not likely to happen in the next release.

Subject: Opera

John Tegen sent a well-reasoned description of the necessity of and requirements for an intelligent open system. But where to go from here, wherever "here" is?

Somehow, the thread immediately skidded into a discussion of the "Project Magic" Opera browser. A number of listeners have pledged their money to this port; others question the wisdom of buying a product before it exists.

More interestingly (and generally), the notion of "nativeness" was scrutinized. Is moving code from one platform to another and stitching up the loose ends enough to deem the result "native"? Many folks don't think so. A native app should take advantage of an OS's features, which implies a significant amount of rewriting. In the case of the BeOS, according to Jon Watte, a primary feature that should be taken advantage of is the multi-threaded environment:

There is no shame in having written code that does not port cleanly to the BeOS, because you couldn't know that we would come along and suddenly do everything so much better. However, what we do is make sure that there is glory in writing code that DOES work in a multi-threaded environment.

Subject: Compile with which headers? And the subscription model

Which headers should an app developer use when compiling? Are older headers (where PR1 is oldest) better because of the larger customer base? Or, given the subscription model, will all/most users be automatically "on the bus"?

Relatedly, it was suggested that the compiler should note the version of the OS that an app is compiled under. If the app is launched on a newer version, a "renew your OS subscription" Alert could pop up.

THE BE LINE: You should compile against the headers of the oldest OS version that you want to run on. This means, of course, that you can't take advantage of newer features.

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