The current release of the BeOS uses kernel add-ons to load device drivers. These device drivers communicate directly with the hardware to provide a standard interface for applications to use. The ISA and PCI buses can always be accessed directly by the CPU, and the kernel has built-in functions that let drivers access these.
Other buses, however, like SCSI, IDE, USB, PCMCIA, and 1394 are usually accessed through the devices on the PCI or ISA bus. If someone wants to write a driver for a device connected to one of these buses, it's preferable not to have to communicate directly with the hardware for that bus.
To help the implementation of devices connected to these buses, R4 will add the notion of loadable kernel modules that can be used to implement bus managers. A bus manager is a module that allows the driver to access a bus without detailed knowledge of the hardware that controls it. The bus manager will find modules that handle specific buses. The drivers can then scan all buses for the devices they can handle without having to know how to handle the controllers.
For R4 the IDE driver has been split up into ATA and ATAPI drivers, an IDE bus manager, and controller modules for generic PCI IDE, BeBox IDE, and Mac IDE. Not all modules have been implemented yet, but the ATA and ATAPI drivers that have been implemented are more functional than the old driver, while allowing third party developers to add support for specific controllers.
I will now show you what it takes to implement a module for an IDE controller, but keep in mind that every detail is subject to change.
IDE.h
defines the interface for the module:
typedef struct { bus_manager_info binfo; uint32 (*get_nth_cookie
) (uint32bus
); uint32 (*get_bus_count
) (); int32 (*get_abs_bus_num
) (uint32cookie
); status_t (*acquire_bus
) (uint32cookie
); status_t (*release_bus
) (uint32cookie
); status_t (*write_command_block_regs
) (uint32cookie
, ide_task_file *tf
, ide_reg_maskmask
); status_t (*read_command_block_regs
) (uint32cookie
, ide_task_file *tf
, ide_reg_maskmask
); uint8 (*get_altstatus
) (uint32cookie
); void (*write_device_control
) (uint32cookie
, uint8val
); void (*write_pio_16
) (uint32cookie
, uint16 *data
, uint16count
); void (*read_pio_16
) (uint32cookie
, uint16 *data
, uint16count
); status_t (*intwait
) (uint32cookie
, bigtime_ttimeout
); status_t (*prepare_dma
) (uint32cookie
, void *buffer
, size_t *size
, boolto_device
); status_t (*finish_dma
)(uint32cookie
); } ide_bus_info;
A module for an IDE controller exports this structure with all the function pointers pointing to the respective functions. All functions have to be implemented, but prepare_dma and finish_dma may return an error if DMA is not supported, and all device drivers need to handle this case.
binfo contains the generic bus manager module information. Currently this contains the module name, some flags and a function for initialization and uninitialization.
At initialization time, the module finds the hardware it supports, and allocates resources. Specifically it may scan the PCI bus, create areas for DMA tables, and initialize structures and semaphores used to access each bus. At closing time all resources should be freed.
The first three functions an IDE module implements are those that allow the IDE bus manager to iterate through all the buses a module handles and map them to a global bus number that the drivers will use. The functions are
uint32get_nth_cookie
(uint32bus
)
Returns a cookie that the driver uses when accessing the specified bus. The cookie needs to uniquely identify the specified bus. It will normally be a pointer to information about the bus, or an index into an array.
uint32 get_bus_count
()
Returns the number of buses that this module implements.
int32get_abs_bus_num
(uint32cookie
)
Allows the bus manager to always number the primary and secondary IDE bus in a PC as 0 and 1, and it allows a driver to find out that a drive on a bus is the same as a specific drive that the BIOS uses. Partition utilities use this information to correctly fill in the CHS information in the partition table, and boot managers like lilo need this so that it will boot from the right disk. The function returns 0 if the bus is the primary IDE bus, 1 if it is the secondary, or -1 if it is neither.
Let's now look at the functions to access the bus. Since only one device can be active on an IDE bus at a given time, we define two functions that gives a driver exclusive access to the bus.
status_tacquire_bus
(uint32cookie
); status_trelease_bus
(uint32cookie
);
A normal implementation of these would look like this:
static status_tacquire_bus
(bus_info *cookie
) { returnacquire_sem_etc
(cookie
->mutex
, 1,B_CAN_INTERRUPT
, 0); } static status_trelease_bus
(bus_info *cookie
) { returnrelease_sem_etc
(cookie
->mutex
, 1,B_DO_NOT_RESCHEDULE
); }
All the following functions assume that the driver has successfully
called acquire_bus
.
The next four functions provide access to the IDE registers:
status_twrite_command_block_regs
(uint32cookie
, ide_task_file *tf
, ide_reg_maskmask
); status_tread_command_block_regs
(uint32cookie
, ide_task_file *tf
, ide_reg_maskmask
); uint8get_altstatus
(uint32cookie
); voidwrite_device_control
(uint32cookie
, uint8val
);
read_command_block_regs()
and
write_command_block_regs()
allow multiple
registers to be updated with one call. All these are straightforward to
implement.
To do PIO data transfers we use two functions:
voidread_pio_16
(uint32cookie
, uint16 *data
, uint16count
); voidwrite_pio_16
(uint32cookie
, uint16 *data
, uint16count
);
These functions read or write the data passed in from and to the IDE data register. The argument count specifies how many 16-bit words to transfer.
The last function that has to be implemented is
status_tintwait
(uint32cookie
, bigtime_ttimeout
);
This function blocks the caller until an interrupt is received from the bus, or until the time specified in the timeout argument has elapsed.
Finally we have two functions that a driver uses to do DMA transfers:
status_tprepare_dma
(uint32cookie
, void *buffer
, size_t *size
, boolto_device
); status_tfinish_dma
(uint32cookie
);
If DMA is not supported these functions return
B_NOT_ALLOWED
. If the controller supports
DMA, prepare_dma()
sets up the required
DMA tables and prepares the controller for a
DMA read or write. It is the driver's responsibility to
lock the memory before locking the bus. This order is necessary since
locking memory may cause disk access to occur.
You have now seen how the controller-specific part of an IDE driver can be separated from the device-specific parts. Since most PCs have motherboard IDE buses that are mostly hardware compatible, using modules for IDE controllers is not strictly necessary. It does, however provide cleaner device drivers, and an easy way to support controllers that deviate from the standard. Other bus types also exist where different controllers are incompatible, but it's not feasible for every device driver for these buses to know about different controllers.
Hello, everyone! I'm Michael Morrissey, the new DTS engineer here at Be. I've already enjoyed working with several of you during my first month on the job, and I hope that one day we'll meet at a developer conference or demo.
The first time I saw a Silicon Graphics machine (*), when I was a freshman in college, I was blown away. The graphics were so fast, so smooth! Those great SGI demos captivated me, and I spent hours tweaking the parameters to the programs, just to amuse myself.
Eventually, I wanted to write my own graphics programs. I looked at some of the sample code, but couldn't seem to get started. C wasn't the problem, it was the GL library—I didn't understand the building blocks necessary to writing a basic graphics program with it. Some older students who saw I was struggling set me straight and got me going.
I imagine a lot of people are in the same predicament with the Intel release of the BeOS that I was in with that SGI machine—tired of tweaking the demos and sample code, wanting to write their own code, but unsure how to start and feeling a little overwhelmed. I'd like to help newcomers to BeOS programming by building a small application which emphasizes the fundamentals but is large enough for experimentation.
The application we'll build (actually, port and modify) is DynaDraw, written originally in C and GL by Paul Haeberli of Silicon Graphics (fittingly, the person who first told me about BeOS). It's a fun little paint program which models the dynamics of a brush with mass on a paper with drag. (Don't worry, we'll skip the physics!)
DynaDraw turns your mouse into a calligraphy pen, and lets you make beautiful, smooth strokes easily. Rather than concentrating on any one aspect of the OS, we'll talk about good program structure and use objects that are common to almost all programs.
The sample code for this application can be found at:
ftp://ftp.be.com/pub/samples/interface_kit/obsolete/dynadraw.zip
Paul's original C source is also included in this zip file, and I highly recommend checking out his web page on DynaDraw:
http://www.sgi.com/grafica/dyna/index.html
When designing or porting an application, it's often easiest to write the program in stages, starting with minimal functionality, and building up from there. Keep in mind that you'll add more features later, and don't paint yourself into a corner.
For minimal functionality DynaDraw needs a window to draw in. But, since
BWindow
objects can't draw, we need a
BView
object as a child of the
BWindow
.
We'll want to draw with the left mouse button down. The
BView
API has a MouseDown()
function, so if we derive a class from BView
, we can
override that function to handle mouse events the way we'd like.
Another important consideration is the ability to redraw the image if
part or all of the view becomes invalidated, for example, if another
window is on top of ours temporarily, or if we minimize and then restore
our window. BView
s can't redraw themselves; you have to tell them how --
and for this, we'll override the BView
::Draw()
function.
Something else to consider is where to put the state-specific variables
for the "filter"—things such as brush mass, drag, velocity, etc. --
which were stored in the filter structure in Paul's original program.
We'd like them to be as close as possible to the functions that need them
-- the functions that draw (and redraw)—so we'll put them in our BView
descendant. By the same logic, we'll also put the functions that operate
on these variables in the same class (such as the Apply()
method).
That's our minimum functionality, so let's look at what we'll need to implement it:
We always want an instance of the BApplication
object, but we don't
need to specialize any of its functionality, so we can use the class as
it is.
We'll want a window. We don't need to specialize it—but we do have
to override one of its functions, QuitRequested()
. I'll return to this
in a moment.
We'll need a BView
, but since we need to specialize
functions such as MouseDown()
and
Draw()
, we'll want to create a new class—let's
call it FilterView
—derived from
BView
.
Returning to override BWindow
::QuitRequested()
:
even in the simplest apps, with just one window, you need to override
QuitRequested()
. This is because the last window
to close needs to alert the BApplication
object to
quit. BWindow
::QuitRequested()
doesn't do this
automatically, because a window can't assume that it's the last one open.
So we'll override QuitRequested()
by creating a
simple class derived from BWindow
, called
DDWindow
:
classDDWindow
: publicBWindow
{ public:DDWindow
(BRect
R
, const char*title
, window_typetype
, uint32flags
); boolQuitRequested
(); };DDWindow
::DDWindow
(BRect
R
, const char*title
, window_typetype
, uint32flags
) :BWindow
(R
,title
,type
,flags
) { // do nothing } boolDDWindow
::QuitRequested
() { /* we're the last window open, so shut down the application */be_app
->PostMessage
(B_QUIT_REQUESTED
); return true; }
The constructor for the DDWindow
doesn't really do
anything but pass the arguments along to the
BWindow
. In the
QuitRequested()
method, we post a message to our
BApplication
object to quit. Remember,
be_app
is a global variable set in
BApplication
constructor to point to the instance of
your application object.
Okay! Now on to the main()
function:
int main() {BApplication
App
("application/x-vnd.Be-dynadraw");DDWindow
*W
= newDDWindow
(BRect
(50,50,800,600), "DynaDraw!",B_TITLED_WINDOW
, 0);FilterView
*F
= newFilterView
(W
->Bounds
());W
->AddChild
(F
);W
->Show
();App
.Run
(); returnB_NO_ERROR
; }
This actually does an enormous amount of work for us. First, it connects
us to the application sever and sets up our application identifier. Next,
we create a DDWindow
: the top-left corner is at (50,50) and the
lower-right corner is at (800,600); the window title is "DynaDraw!"; the
window has a yellow tab; and finally, the user can move, resize, close,
and zoom the window. Remember, though, this window isn't displayed yet.
Next, we create an instance of our (still undefined) FilterView
class,
passing in an important BRect
, namely, the bounds of the window it will
be attached to. Then we display the window, and start the application's
message loop.
The FilterView
class should look like this:
classFilterView
: publicBView
{ public: /* overridden functions from BView */FilterView
(BRect
R
); voidMouseDown
(BPoint
point
); voidDraw
(BRect
updateRect
); private: /* state variables, formerly from the filter structure */ floatcurmass
,curdrag
,width
; floatvelx
,vely
,vel
; floataccx
,accy
,acc
; floatangx
,angy
;BPoint
odel
,m
,cur
,last
; /* a list of polygons which make up our brushstokes */BList
polyList
; /* this is where the calculations get done, and the drawing */ voidDrawSegment
(); boolApply
(BPoint
m
, floatcurmass
, floatcurdrag
); /* little helper functions */ inline float flerp(floatf0
, floatf1
, floatp
); inline void setpos(BPoint
point
); };
Note that all the variables that were originally in the filter struct are
now in the private section of the class. This is fine, since the only
functions that need these variables are also in the class. Our
brushstrokes are made up of polygons. We'll want to keep a list of them
(so that we can redraw), so I've decided to use a BList
object as a
container. Every time we make a stroke, we'll add an item to this
BList
.
Then we have the two main methods, which remain largely unchanged from the
original program. The first is Apply()
, which
decides whether or not a segment needs to be drawn. If it does, the other
main method, DrawSegment()
is called, and it draws
the segment. Finally, there are two small helper methods, which don't do
anything special.
The constructor for this class looks like this:
FilterView
::FilterView
(BRect
R
) :BView
(R
, "filter",B_FOLLOW_ALL_SIDES
,B_WILL_DRAW
) {curmass
= 0.50;curdrag
= 0.46;width
= 0.50; }
Now we give the constructor a BRect
object, which it
passes on to the BView
constructor. We name the view
"filter", and instruct it to follow all sides. We'll do some
drawing, so we need update notifications sent to us. Inside the
constructor, we set initial values for the mass, drag, and width variables.
The MouseDown()
method looks like this:
voidFilterView
::MouseDown
(BPoint
point
) { uint32buttons
=0; boolflag
=0; floatp
; floatmx
,my
;BRect
B
=Bounds
();GetMouse
(&point
, &buttons
,true
); if(buttons
==B_PRIMARY_MOUSE_BUTTON
) {mx
= (float)point
.x
/B
.right
;my
= (float)point
.y
/B
.bottom
;m
.Set
(mx
,my
);setpos
(m
);odel
.Set
(0,0); while(buttons
==B_PRIMARY_MOUSE_BUTTON
) {GetMouse
(&point
, &buttons
,true
);mx
= (float)point
.x
/B
.right
;my
= (float)point
.y
/B
.bottom
;m
.Set
(mx
,my
); if(Apply
(m
,curmass
,curdrag
))DrawSegment
();snooze
(15000); } } else if (buttons
==B_SECONDARY_MOUSE_BUTTON
) { int32count
=polyList
.CountItems
(); for(inti
=0;i
<count
;i
++) {delete
(polyList
.ItemAt
(0);polyList
.RemoveItem
(0L); }Invalidate
(); } }
The MouseDown()
method is called when the parent window receives a
mouse down message. In our case, we want to track the cursor as long as
the primary mouse button is held down. If the second mouse button is
pressed, we want to clear the screen. (For anyone using a one-button
mouse, don't despair; we'll add a general clear-screen feature later on.)
First we decide which button is being pressed. If it's the primary button,
we initialize some points. Then we enter a loop which will continue until
the button is released. In that loop, we get the mouse position, update our
point, and call the Apply()
method to determine if
a segment needs to be drawn. (I'll skip the
Apply()
method body, since it's all calculations,
and identical to the original version.)
If we need to draw the segment, we call
DrawSegment()
, which I'll get to in a moment.
Finally, we need to snooze()
between mouse calls;
otherwise, the responsiveness would be too high. If the secondary mouse
button was pressed, we want to clear the screen. We do this by deleting all
the polygons in the polyList, and invalidating the whole view (meaning the
Draw()
function is called on the entire view).
There are three things to note here: first, the
RemoveItem()
function does not free the objects it
holds pointers to—you must do that. Second, calling
RemoveItem()
compacts the list, so the length of
the list decreases by one every time you call it. Third, you'll notice that
I called RemoveItem()
with an argument of 0L --
this is because RemoveItem()
is overloaded, one
version taking a void*, the other taking an
int32. Calling it with a 0 is ambiguous; calling it with a 0L
makes it clear we want the int32 version.
Now, back to DrawSegment()
. Calculations
removed, it looks like this:
voidFilterView
::DrawSegment
() { /* calculations removed */SetHighColor
(0,0,0);polypoints
[0].Set
((B
.right
*(px
+odel
.x
)), (B
.bottom
*(py
+odel
.y
)));polypoints
[1].Set
((B
.right
*(px
-odel
.x
)), (B
.bottom
*(py
-odel
.y
)));polypoints
[2].Set
((B
.right
*(nx
-del
.x
)), (B
.bottom
*(ny
-del
.y
)));polypoints
[3].Set
((B
.right
*(nx
+del
.x
)), (B
.bottom
*(ny
+del
.y
)));polyList
.AddItem
(newBPolygon
(polypoints
, 4));FillPolygon
(polypoints
, 4);StrokePolygon
(polypoints
, 4);odel
=del
; }
We call SetHighColor()
, which sets the pen color
to black. Next, we set the coordinates for the four
BPoint
s which make up the polygon. Then, we make a
new BPolygon
, constructed with our four-point array,
and add it to our polygon list. Finally, we make a call to
FillPolygon()
, but also one to StrokePolygon. The
reason is that if our polygon gets extremely small, flattened to the point
were it lies on a single line, FillPolygon()
will
not draw anything (because the area is, after all, zero).
StrokePolygon()
, on the other hand, will draw the
line, which is what we need.
The only thing left to look at is the Draw()
method, which is called if
part or all of the view is invalidated. Lifting the hood reveals a
trivial function:
voidFilterView
::Draw
(BRect
updateRect
) {BPolygon
*bp
; int32count
=polyList
.CountItems
(); for(inti
=0;i
<count
;i
++) {bp
= (BPolygon*)polyList
.ItemAt
(i
);FillPolygon
(bp
);StrokePolygon
(bp
); } }
All we do here is loop through the polygon list, getting one item at a time, and calling FillPolygon() and StrokePolygon() for the item. This reconstructs our drawing.
We now have a small program that draws nice calligraphic strokes. Play with it for a while to see how it feels and how it reacts to movements. Adjust the mass, drag, and width parameters in the FilterView constructor and see how it changes the program.
There's lots more to do with this program. To start with, we should have a simple menu bar at the top that lets us clear the screen, bring up an About box, and quit (without using the close button on the window tab). Since I'm a "tweak-freak," I'd like a window where I can adjust the mass, drag, width, snooze factor, and other things on the fly, without recompiling. Being able to change the color of the pen would be nice, too, so we'll add a color preference panel.
I'll be back in two weeks with an article which adds these features. It
will also show how starting with a simple, clean framework makes
expanding your programs much easier. In the next article we'll be moving
at a faster pace, so you may want to get a head start by checking out the
BSlider
class, the BColorControl
class, and simple messaging.
See you in two weeks!
(*) - That first SGI machine was an Iris 4D, for the curious.
My mother is puzzled. She thinks this whole circus of DOJ and state lawsuits against Microsoft is unfair, greedy, and downright dangerous. My mother asks tough, common sense questions. And since she's not a geek -- not our kind of geek anyway—she won't stand for any of our industry encoded speech. No, she wants answers she can understand.
How come those bureaucrats want Microsoft to bundle Netscape's browser along with the one already offered with Windows? Isn't that, as Mr. Gates pointed out, like forcing Coca-Cola to include three cans of Pepsi inside each six-pack of Coke? It is very nice of Microsoft to keep making their product more and more useful to more and more people; why are these government lawyers trying to prevent Microsoft from innovating?
She also wonders why so many people who benefited from Microsoft's work are now turning against it. She reminds me of the times when there were two different voltages for appliances or when the rail gauge changed at the border between France and Spain. With all the good PCs running Windows and Office, customers don't have to worry about the voltage, the hardware guys know what to manufacture and everyone should be happy, she says.
Doesn't everyone see how the Microsoft standard fueled the PC explosion? Look at your old cronies at Apple. They didn't participate and they were left behind. In my mind it's clear, she tells me. Microsoft is the industry benefactor, so why bite the hand that feeds you millions?
And she knows. She not only looks and speaks like Scott McNealy's mother, she's also been following Sun for a while. In fact, when Sun went public, she heard a rumor that one of Sun's founders, Andy Bechtolsheim, took his IPO money and bought Microsoft stock. So, she followed suit and invested her retirement savings in Microsoft stock, thinking Andy had to be onto something. He was. She likes what the stock has done for her and her fellow MSFT holders. As for people who attack Microsoft, I can't print the names she has for them in this family publication.
What do you say for yourself and your so-called friends in the industry, she demands to know? (Needless to say, when she learned I invested my time and, worse, her grandchildren's inheritance in a non-Windows operating system company, she was distraught, thinking all efforts to educate me had been a waste. But that's another story.)
So, I tell her the cans of Pepsi in a Coke six-pack argument is admirable. She smiles, and I'm her good son again. Then I bring up the software that ships with Windows on any new PC these days. Among other things, there is an icon for Microsoft's own network, MSN, and a folder of on-line services -- AOL, Compuserve, and AT&T's WorldNet. Isn't that a bunch of cans from brands directly competing with the MSN brand? She's puzzled.
But what about the apparatchiki who want to prevent Microsoft from innovating, she asks? I sigh. Maman, this is complicated. She gives me a withering look. Don't talk down to me. If you can't explain yourself to your mother, either you haven't done your homework, or you're trying to hide something from me. So, what is it?
Well, it goes like this. Some biased and ill-informed people say Microsoft never innovates, they just copy very well and use these imitations to eliminate competitors. Myself, I'd say they have a very good eye. And I admire the way they implement once they've decided on a target.
Take Microsoft's conversion to the Internet, I say, showing her the '95 Pearl Harbor speech. I attempt to explain how Microsoft's official & quot;embrace and extend" becomes lethal. Microsoft can extend its operating system in ways that use its position of power in the OS domain to generate a sure win. Some biased minds consider that unfair competition.
What's so wrong with that, she asks? Customers get a better product, a more complete offering from their favorite vendor. It makes no impression when I try and explain thatthis sterilizes innovation, just as when a culture occupies the entire Petri dish, there is no more room for other life forms.
Yes, but what if I get all I need at a good price? Then, I try to explain what a per-system license means. Allegedly, Microsoft gives its OEMs a good price for the "everything-on-it" combo of Windows and Office if they agree to calculate the license fee on the basis of the number of systems you ship, regardless of what you actually put on the disk. Accounting is simplified, the OEM can market, promote, mix, and match what they want without incurring complicated reporting requirements.
Isn't this gracious, asks my mother, low price, simplicity? Certainement, I say, but try selling a word processor to that OEM. He'll ask why he should pay for it, since he's already paid for Office. My mother is a little troubled by this. She's not sure what a word processor better than Word could be, but she sees that making a business of a non-Microsoft word processor could be even harder than her eldest son's OS venture, perhaps.
But she quickly recovers her equanimity. On second thought, she says, this lawsuit is a big win for Microsoft. First, Microsoft will win and, even if they don't win, they win. Now I'm the one who's puzzled.
The first win is simple. Does Microsoft have good lawyers, who know the law inside out? Yes, of course, Bill's father is a lawyer of fine repute, Microsoft's chief legal eagle Bill Neukom is talented, and the company can afford the best litigators. The DOJ may also have fine lawyers, but, does Joel Klein live and breathe technology as well as Bill and his people? No. Therefore, Bill will win.
And the second win, she says, is even better. Imagine Microsoft's situation without these lawsuits. Their ever-increasing presence—she doesn't like to say dominance—would only generate more and more hostility, which is not good for business.
Now, my dear son, let's assume for a moment your Silicon Valley cronies are right. Let's assume Microsoft does indeed embrace and extend and smother its competition. These suits give Microsoft two things that are invaluable. One is time. The legal battles will last for years, while Microsoft goes on doing what it does. The other is a mantle of martyrdom. As victims of bureaucratic oppression, they can exterminate with even greater impunity.
One might think my mother is a real cynic.
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.
How do you make a BFS floppy...and should you? Young Ficus Kirkpatrick of Be thinks maybe you shouldn't:
"...the journal eats up a large portion of the disk. I would be loath to use a floppy because they are notoriously slow, seemingly always corrupt, etc..."
Master Kirkpatrick goes on to suggest using CDs rather than floppies, which prompted Chris Herborth to plead for a CD writing app. Other suggestions, other voices: Use network download to distribute software, tar to the floppy, use HFS/MS-DOS floppies.
Is Release 3 much less stable than PR2 on a BeBox? Slower? Hard to install? A number of correspondents wrote in to mention that they couldn't get the ROM Updater to drop-launch—they had to launch it from the shell. Others had no problem installing or updating the ROM.
THE BE LINE: The Release 3 boot ROM for the BeBox was broken. However, there really wasn't any need to update the ROM; you can use the PR2 boot ROM to run Release 3 on a BeBox.
Printing comments, prompted by Benoit Schillings' Newsletter article, http://www.be.com/aboutbe/benewsletter/volume_II/Issue18.html:
When should a print job pop up the Print Setup or Page Setup panel? Some folks think the Print menu item should print, period. Others think that "Print..." is a well-known convention and that users understand that another panel is on its way.
Tyler Riti suggests a no-fuss, no-panel "Print one copy" item in addition to the expected "Print..."
Mr. Riti would also like more flexibility in choosing a printer. The current Mac-influenced bureaucracy (fill out a form and submit it to SelectPrinter) is barbaric. Adam Lloyd, who's thought about these things, submitted a plan for how as document-based choose-printer UI might look and feel.
Michael Crawford would like multi-device printing: "I'd like to be able to choose a different printer for different pages, for example to print envelopes and letters in a single print job."
A number of listeners would like to mix and match layout types within a document. For example, they'd like to be able to mix portrait and landscape orientation.
From Jason Jasmin:
"Given that the os appears to spawn a separate thread for each socket
being select()
ed, is there any performance loss to just spawn a reader
thread for each socket and have the thread sit in a blocking recv()
loop?"
Also sprach Jon Watte:
"[spawning rather than selecting] is actually considered a performance GAIN. Threads are cheap on BeOS. Really cheap. It definitely makes sense to spawn one thread per socket if you're expecting < 100 simultaneous connections."
Luc Andre pointed out that this doesn't help when you're porting code.
What MIME type should an URL be? Should it assume the type of the data it points to? Most listeners think an URL should have its own type, perhaps of supertype (or "media" type, in archaic RFC lingo) "message". Some folks suggest using "message/rfc822", the standard email type. Nearly everyone agreed that an URL shouldn't take the type of the data it represents.
How should the system support URL handling? Some folks would like to find and launch protocol-handling apps, something like:
be_roster
->Launch
(B_HTTP_PROTOCOL
, >>URL<<, ...)
The objection, here, is that this assumes that you know the protocol. So how about a call that takes an URL and deduces protocol for you?
Anyone want to offer some distance-between-UI-objects guidelines for Wendell Beckwith? Tinic Uro suggests...
"...a minimum 8 pixels for the bordersize of group of elements and a minimum of 4 pixels for the space between elements... Leave enough space for future localisation..."
Thorsten Seitz:
"You shouldn't hardcode the layout at all but instead always make it font-sensitive (liblayout or something else). This way you won't have problems with localization either."
Dan from Cornell, you're on the air:
"Use the height of be_plain_font as one 'display unit.' One display unit then becomes the vertical distance between radio buttons and checkboxes, the horizontal distance between 'OK' and 'Cancel', the margin of a BBox, etc. Unrelated control groups are separated by two display units."