823 lines
56 KiB
HTML
823 lines
56 KiB
HTML
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||
<html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>Be Newsletters - Volume 4: 1999</title><link rel="stylesheet" href="be_newsletter.css" type="text/css" media="all" /><link rel="shortcut icon" type="image/vnd.microsoft.icon" href="./images/favicon.ico" /><!--[if IE]>
|
||
<link rel="stylesheet" type="text/css" href="be_newsletter_ie.css" />
|
||
<![endif]--><meta name="generator" content="DocBook XSL Stylesheets V1.73.2" /><link rel="start" href="index.html" title="Be Newsletters" /><link rel="up" href="volume4.html" title="Volume 4: 1999" /><link rel="prev" href="Issue4-34.html" title="Issue 4-34, August 25, 1999" /><link rel="next" href="Issue4-36.html" title="Issue 4-36, September 8, 1999" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue4-34.html" title="Issue 4-34, August 25, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a accesskey="u" href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a accesskey="n" href="Issue4-36.html" title="Issue 4-36, September 8, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="headerTR"><div id="navigpeople"><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div><div class="navigboxed" id="naviglang" title="English">en</div></div><div id="headerTC">Be Newsletters - Volume 4: 1999</div></div><div id="headerB">Prev: <a href="Issue4-34.html">Issue 4-34, August 25, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-36.html">Issue 4-36, September 8, 1999</a></div><hr /></div><div class="article"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Issue4-35"></a>Issue 4-35, September 1, 1999</h2></div></div></div><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Marketing4-35"></a>Business & Marketing: The New Be Website, Part 1: Version 1.0</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Michael</span> <span class="surname">Alderete</span></span></div></div></div><p>
|
||
If you've been a member of the Be community for long, you know that we
|
||
recently redesigned the Be corporate web site. Many people, especially
|
||
our developers, gave us feedback on what they liked and disliked, and
|
||
lots of suggestions. To give you some insights into what we did and why,
|
||
and what we'll do in the future, I thought I'd write about the process we
|
||
went through, and what happened afterwards.
|
||
</p><p>
|
||
I took the job of Webmaster this year at the end of March. My second day
|
||
on the job I was told "We need a new web site. You have 4 weeks." After
|
||
the paramedics restarted my heart, we got to work.
|
||
</p><p>
|
||
After some consultation with outside design firms, it became clear that 4
|
||
weeks weren't enough to do the job well and at a reasonable cost. We
|
||
extended our deadline, asked our branding and design firm to handle this
|
||
project as well, and got to the hard part of the task: creating a new
|
||
organizational scheme for the site.
|
||
</p><p>
|
||
The number one complaint about the old design was that it was too hard to
|
||
figure out what Be did. The Be web site was focused on the existing Be
|
||
community, and served it well, but tended to turn off people who were
|
||
visiting for the first time. The site didn't convert casual browsers into
|
||
customers, because they would quit browsing before they learned what our
|
||
product was!
|
||
</p><p>
|
||
Since one of the groups of people we wanted to please with the new site
|
||
was first time visitors, including potential customers and investors, we
|
||
knew we had to make significant changes. (This was one of only many
|
||
considerations we had on our list.)
|
||
</p><p>
|
||
To reorganize our site, we worked on two different approaches with our
|
||
design agency, Fitch. One, which we called "The Matrix," was very
|
||
sophisticated but was also so complicated we couldn't explain it to other
|
||
people at Be. We took the simpler of the two approaches.
|
||
</p><p>
|
||
The visual design took less time. Fitch presented us with three different
|
||
visual looks. We chose one, and then looked at multiple variations on
|
||
that theme. We picked one of those, made a couple of minor changes, and
|
||
Fitch's designers turned it over to their web production team.
|
||
</p><p>
|
||
Fitch's web production group was going to build out a set of base
|
||
templates: one skeleton page for each section, and all the associated
|
||
graphics. Then Be's web team (all two of us) would take those, and build
|
||
out the site to the 20 pages we were planning to complete for launch.
|
||
</p><p>
|
||
The first iteration of the templates we got used HTML frames for the top
|
||
navigation area. Somehow we had forgotten to say "don't use frames."
|
||
(Though we were very clear that the new design could not depend on
|
||
anything that wasn't supported by NetPositive. And it doesn't, though the
|
||
JavaScript rollovers are kinda cool if you visit using another browser.)
|
||
</p><p>
|
||
For those of you who don't already know my attitude towards HTML frames,
|
||
let me be plain: Frames are Evil. They are the work of the Prince of
|
||
Darkness. I *hate* frames. I can go into detail as to why, but I'll just
|
||
link to Jakob Nielsen's two excellent articles on the issue:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
Why Frames Suck (Most of the Time)<br />
|
||
<a class="ulink" href="http://www.useit.com/alertbox/9612.html">http://www.useit.com/alertbox/9612.html</a>
|
||
</p></li><li><p>
|
||
"Top Ten Mistakes" Revisited<br />
|
||
<a class="ulink" href="http://www.useit.com/alertbox/990502.html">http://www.useit.com/alertbox/990502.html</a>
|
||
</p></li></ul><p>
|
||
So we kicked the base templates back, and asked Fitch to redo them
|
||
without frames. This put us a bit over time and over budget, but getting
|
||
rid of the frames was worth it.
|
||
</p><p>
|
||
Other flaws were not so easy to fix. At the last moment, we realized that
|
||
the new site design would unveil the new Be logo three weeks ahead of our
|
||
planned "debut" at PCExpo. So we quickly hacked out a replacement graphic
|
||
using the old logo. It looked terrible, but there was no other way to
|
||
keep the new logo secret.
|
||
</p><p>
|
||
The awful logo graphic was one of about a dozen visual flaws we could see
|
||
in the new design. Some others were that the gradient background and the
|
||
small text in the blue side navigation bar combined to make it very hard
|
||
to read; the grayed-out "sub-navigation" links looked disabled and
|
||
unavailable; JPEG artifacts in the Be logo (even the new one) were
|
||
especially visible in NetPositive; and somewhat inappropriate icons were
|
||
used in the blue side navigation bar. The Zookeeper icon for the Jobs
|
||
section was especially unfortunate; rumors that Be chains people to their
|
||
desks, or flogs them when they get behind schedule, are completely
|
||
untrue. We haven't done that in almost two years.
|
||
</p><p>
|
||
We and Fitch knew about these flaws. But with the aggressive development
|
||
schedule and fairly fixed launch date, we just didn't have the luxury of
|
||
going back to fix things. At all four stages of the project
|
||
(architecture, visual design, HTML design, production) we came to a point
|
||
where we said "it's flawed but the deadline is really important; we'll
|
||
fix it in version 1.1" (a phrase I'm sure every software developer has
|
||
heard at one time or another!). We moved on to production.
|
||
</p><p>
|
||
With the templates and graphics in hand, the Web Team got to work
|
||
building out the site. We implemented the actual site templates in a mix
|
||
of HTML and the outstanding PHP
|
||
(<a class="ulink" href="http://www.php.net/">http://www.php.net/</a>), a server-side
|
||
processing language (someone please port this to BeOS!). These templates
|
||
are "smart," in that they know what page they're displaying and adjust
|
||
elements accordingly. All the work of keeping the navigational links,
|
||
highlighted graphics, and JavaScript code correct is done by those
|
||
templates, making it *vastly* easier to add new pages to sections, etc.
|
||
</p><p>
|
||
With production basically finished (we were just waiting for a few pieces
|
||
of content to trickle in), we examined our handiwork. It wasn't perfect
|
||
by a long shot, but it didn't suck completely either. At some point, you
|
||
just have to STFP ("ship the product"—the "f" is silent). So we did.
|
||
</p><p>
|
||
Uh, well, we wanted to. But at the last moment, we realized that the new
|
||
server hardware, a much beefier—and physically larger—system than
|
||
its predecessor, would not fit in the cage at our co-location facility.
|
||
We'd have to wait three days until they could rewire a nearby rack to
|
||
receive our box. "Three days" turned out to be a week...
|
||
</p><p>
|
||
In the end we launched the new site on June 2nd, a week and a day late.
|
||
Not bad, all things considered—our schedule had not allowed us to add
|
||
"padding" for delays at all; we'd barely had time to do QA.
|
||
</p><p>
|
||
The various delays had an upside, though. They and the smart templates
|
||
allowed the Web Team to expand the number of pages on the site when it
|
||
launched. Instead of the original target of 20 pages on the new site, we
|
||
ended up with 42 (we're well over 100 now).
|
||
</p><p>
|
||
Next week, I'll return and talk about the feedback we've received,
|
||
additional issues we've uncovered—and what we're going to do about it,
|
||
very soon.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Engineering4-35"></a>Be Engineering Insights: Programming at the Limit...</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Benoît</span> <span class="surname">Schillings</span></span></div></div></div><p>
|
||
Before I dive into the subject of this week's newsletter article, I'd
|
||
like to claim the title for working in the "hardest programming
|
||
environment for programming the BeOS framework..."
|
||
</p><p>
|
||
One of my regular programming environments is my garden. I connect my
|
||
faithful dual 300 Mhz PC running BeOS to my telescope, and under the
|
||
curious gaze of Molly or Zippy (two wonderful dogs! See
|
||
www.zippydog.com), I happily program under the stars.
|
||
</p><p>
|
||
Now this is a pleasant environment. But with the comfort of my
|
||
home/DSL/refrigerator at hand, I can't really claim it as the hardest
|
||
environment for programming BeOS. So last week I went one step farther --
|
||
I programmed the same machine (still connected to the telescope) near the
|
||
summit of White Mountain in eastern California.
|
||
</p><p>
|
||
The altitude was about 11,000 feet, the wind speed about 30 mph, and the
|
||
temperature was low enough that I had to add some rum to my Diet Coke to
|
||
keep it from freezing. A Honda generator provided the power—the
|
||
fuel-efficient BeOS burns about 0.8 gallon of supreme unleaded a day.
|
||
</p><p>
|
||
Amazingly, even under something like wilderness survival conditions,
|
||
further attenuated by my highly diminished mental abilities, the Be
|
||
programming framework is still simple enough that I could program with
|
||
ease. That's the magic of BeOS!
|
||
</p><p>
|
||
Now, lets talk about something more "down to earth"...
|
||
</p><p>
|
||
A while back I wanted to add a little animated gizmo to 3dsound --
|
||
something I thought was very simple but which turned out to be a bit more
|
||
difficult to implement than I expected. I'm talking about the little
|
||
black triangle at the top left of the content window.
|
||
</p><p>
|
||
If you click on that triangle (or hit the tab key), the panel containing
|
||
the vu-meters, etc., will show/hide. I wanted this triangle to rotate
|
||
smoothly.
|
||
</p><p>
|
||
At first, I did a trivial implementation of just drawing a triangle at
|
||
the different rotations, but I wasn't very happy with the result. The
|
||
edges of the triangle were pretty huggly (that's "ugly" to you) at most
|
||
angles!
|
||
</p><p>
|
||
The best solution would be anti-aliasing, but I wanted to try something
|
||
different: using the framework to render the triangle, then blurring the
|
||
result before blitting it to the screen.
|
||
</p><p>
|
||
In this case, blurring works like a simple low-pass filter. It removes
|
||
the offending high frequency (jaggies). In general, when you do fast
|
||
animation, adding blurring tends to make the result look much better.
|
||
</p><p>
|
||
The result looks really nice (I think it's as good as real anti-aliasing)
|
||
and can be applied to many kinds of rendering.
|
||
</p><p>
|
||
Here is the code:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
class <code class="classname">TCtrlView</code> : public <code class="classname">BView</code> {
|
||
<span class="type"><code class="classname">BBitmap</code> *</span><code class="varname">b</code>;
|
||
<span class="type"><code class="classname">BView</code> *</span><code class="varname">bv</code>;
|
||
<span class="type">float</span> <code class="varname">rot</code>;
|
||
|
||
public:
|
||
<code class="methodname">TCtrlView</code>(<code class="classname">BRect</code> <code class="parameter">frame</code>, <span class="type">char *</span><code class="parameter">name</code>);
|
||
<code class="methodname">~TCtrlView</code>();
|
||
virtual <span class="type">void</span> <code class="methodname">Draw</code>(<code class="classname">BRect</code> <code class="parameter">ur</code>);
|
||
<code class="classname">BPoint</code> <code class="methodname">transform</code>(<code class="classname">BPoint</code> <code class="parameter">in</code>);
|
||
<span class="type">void</span> <code class="methodname">SetRotation</code>(<span class="type">float</span> <code class="parameter">r</code>);
|
||
<span class="type">void</span> <code class="methodname">blur</code>();
|
||
};
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<code class="classname">TCtrlView</code>::<code class="methodname">TCtrlView</code>(<code class="classname">BRect</code> <code class="parameter">frame</code>, <span class="type">char *</span><code class="parameter">name</code>)
|
||
: <code class="classname">BView</code>(<code class="parameter">frame</code>, <code class="parameter">name</code>, <code class="constant">B_FOLLOW_NONE</code>, <code class="constant">B_WILL_DRAW</code>)
|
||
{
|
||
<code class="methodname">SetViewColor</code>(<code class="varname">backgr</code>);
|
||
|
||
<code class="varname">b</code> = new <code class="classname">BBitmap</code>(<code class="classname">BRect</code>(0,0,31,31),
|
||
<code class="constant">B_COLOR_8_BIT</code>,
|
||
<code class="constant">TRUE</code>);
|
||
|
||
<code class="varname">b</code>-><code class="methodname">AddChild</code>(<code class="varname">bv</code> = new <code class="classname">BView</code>(<code class="classname">BRect</code>(0, 0, 31,
|
||
31),"",<code class="constant">B_FOLLOW_ALL</code>,<code class="constant">B_WILL_DRAW</code>));
|
||
<code class="varname">rot</code> = 3.1415926;
|
||
|
||
<code class="methodname">SetRotation</code>(<code class="varname">rot</code>);
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<code class="classname">TCtrlView</code>::<code class="methodname">~TCtrlView</code>()
|
||
{
|
||
delete <code class="varname">b</code>;
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<span class="comment">// 2d transform routine</span>
|
||
|
||
<code class="classname">BPoint</code> <code class="classname">TCtrlView</code>::<code class="methodname">transform</code>(<code class="classname">BPoint</code> <code class="parameter">p</code>)
|
||
{
|
||
float <code class="varname">sina</code> = <code class="function">sin</code>(<code class="varname">rot</code>);
|
||
float <code class="varname">cosa</code> = <code class="function">cos</code>(<code class="varname">rot</code>);
|
||
float <code class="varname">x0</code>,<code class="varname">y0</code>;
|
||
|
||
<code class="parameter">p</code>.<code class="varname">x</code> -= 9;
|
||
<span class="comment">//offset from the rotation center</span>
|
||
<code class="parameter">p</code>.<code class="varname">y</code> -= 17;
|
||
|
||
<code class="varname">x0</code> = <code class="parameter">p</code>.<code class="varname">x</code> * <code class="varname">cosa</code> - <code class="parameter">p</code>.<code class="varname">y</code> * <code class="varname">sina</code>;
|
||
<code class="varname">y0</code> = <code class="parameter">p</code>.<code class="varname">x</code> * <code class="varname">sina</code> + <code class="parameter">p</code>.<code class="varname">y</code> * <code class="varname">cosa</code>;
|
||
|
||
<code class="varname">x0</code> += 9;
|
||
<span class="comment">//offset back</span>
|
||
<code class="varname">y0</code> += 17;
|
||
|
||
<code class="parameter">p</code>.<code class="varname">x</code> = <code class="varname">x0</code>;
|
||
<code class="parameter">p</code>.<code class="varname">y</code> = <code class="varname">y0</code>;
|
||
|
||
return <code class="parameter">p</code>;
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------
|
||
// very simple blurring routine, also pretty fast!</span>
|
||
|
||
<span class="type">void</span> <code class="classname">TCtrlView</code>::<code class="methodname">blur</code>()
|
||
{
|
||
<span class="type">uchar *</span><code class="varname">c</code>;
|
||
<span class="type">long</span> <code class="varname">x</code>,<code class="varname">y</code>;
|
||
<span class="type">uchar</span> <code class="varname">tmp</code>[32][32];
|
||
<span class="type">long</span> <code class="varname">acc</code>;
|
||
|
||
<code class="varname">c</code> = (<span class="type">uchar *</span>)<code class="varname">b</code>-><code class="methodname">Bits</code>();
|
||
|
||
for (<code class="varname">y</code> = 1; <code class="varname">y</code> < 29;<code class="varname">y</code>++)
|
||
for (<code class="varname">x</code> = 2; <code class="varname">x</code> < 20;<code class="varname">x</code>++) {
|
||
<code class="varname">acc</code> = c[(x+y*32)];
|
||
<code class="varname">acc</code> = <code class="varname">acc</code> + <code class="varname">acc</code> + <code class="varname">acc</code> + <code class="varname">acc</code>;
|
||
|
||
<code class="varname">acc</code> += <code class="varname">c</code>[(<code class="varname">x</code>+<code class="varname">y</code>*32)+1];
|
||
<code class="varname">acc</code> += <code class="varname">c</code>[(<code class="varname">x</code>+<code class="varname">y</code>*32)-1];
|
||
<code class="varname">acc</code> += <code class="varname">c</code>[(<code class="varname">x</code>+<code class="varname">y</code>*32)+32];
|
||
<code class="varname">acc</code> += <code class="varname">c</code>[(<code class="varname">x</code>+<code class="varname">y</code>*32)-32];
|
||
<code class="varname">acc</code> /= 8;
|
||
<code class="varname">tmp</code>[<code class="varname">y</code>][<code class="varname">x</code>] = <code class="varname">acc</code>;
|
||
}
|
||
for (<code class="varname">y</code> = 1; <code class="varname">y</code> < 29;<code class="varname">y</code>++)
|
||
for (<code class="varname">x</code> = 2; <code class="varname">x</code> < 20;<code class="varname">x</code>++) {
|
||
<code class="varname">c</code>[<code class="varname">x</code>+<code class="varname">y</code>*32] = <code class="varname">tmp</code>[<code class="varname">y</code>][<code class="varname">x</code>];
|
||
}
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------
|
||
// Set the rotation of the arrow and draw the arrow to the
|
||
// screen.</span>
|
||
|
||
<span class="type">void</span> <code class="classname">TCtrlView</code>::<code class="methodname">SetRotation</code>(<span class="type">float</span> <code class="parameter">r</code>)
|
||
{
|
||
<code class="varname">rot</code> = <code class="parameter">r</code>;
|
||
|
||
<code class="varname">b</code>-><code class="methodname">Lock</code>();
|
||
<code class="varname">bv</code>-><code class="methodname">SetHighColor</code>(<code class="varname">backgr</code>);
|
||
<code class="varname">bv</code>-><code class="methodname">FillRect</code>(<code class="classname">BRect</code>(0,0,32000,32000));
|
||
<code class="varname">bv</code>-><code class="methodname">SetHighColor</code>(32,32,32);
|
||
|
||
<code class="varname">bv</code>-><code class="methodname">FillTriangle</code>(<code class="function">transform</code>(<code class="classname">BPoint</code>(5,10)),
|
||
<code class="methodname">transform</code>(<code class="classname">BPoint</code>(5,24)),
|
||
<code class="methodname">transform</code>(<code class="classname">BPoint</code>(12,17)));
|
||
<code class="varname">bv</code>-><code class="methodname">Sync</code>();
|
||
<code class="methodname">blur</code>();
|
||
<code class="varname">b</code>-><code class="methodname">Unlock</code>();
|
||
|
||
<code class="methodname">DrawBitmap</code>(<code class="varname">b</code>, <code class="classname">BRect</code>(1, 1, 1 + 14, 1 +
|
||
30),<code class="classname">BRect</code>(0,3,14,33));
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
<span class="type">void</span> <code class="classname">TCtrlView</code>::<code class="methodname">Draw</code>(<code class="classname">BRect</code> <code class="parameter">ur</code>)
|
||
{
|
||
<code class="classname">BRect</code> <code class="varname">r</code>;
|
||
<span class="type">long</span> <code class="varname">i</code>;
|
||
<span class="type">rgb_color</span> <code class="varname">c</code>;
|
||
|
||
<code class="methodname">DrawBitmap</code>(<code class="varname">b</code>, <code class="classname">BRect</code>(1, 1, 15, 31),<code class="classname">BRect</code>(0,3,14,33));
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
</pre><p>
|
||
And a final bonus...
|
||
</p><p>
|
||
In the 3dsound timeline, the selection is represented by a darker area.
|
||
Here's the routine I use to darken an 8-bit bitmap. The idea is to build
|
||
whatever lookup tables you want which will perform the color change you
|
||
need, in this case darkening by 25%.
|
||
</p><p>
|
||
You could easily modify the "init dark table" for any other purpose you
|
||
want, like darkening everything but bright red, or remapping an image to
|
||
gray scale, etc. This is really simple but gives you a lot of flexibility
|
||
in the graphic effects of your program.
|
||
</p><pre class="programlisting cpp">
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<span class="type">char</span> <code class="varname">dark_table_inited</code> = 0;
|
||
<span class="type">uchar</span> <code class="varname">dark_table</code>[256];
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<span class="type">void</span> <code class="function">init_dark_table</code>()
|
||
{
|
||
<span class="type">ushort</span> <code class="varname">v</code>;
|
||
<span class="type">uchar</span> <code class="varname">ov</code>;
|
||
<span class="type">rgb_color</span> <code class="varname">c</code>;
|
||
<code class="classname">BScreen</code> <code class="varname">s</code>;
|
||
|
||
for (<code class="varname">v</code> = 0; <code class="varname">v</code> < 256; <code class="varname">v</code>++) {
|
||
<code class="varname">c</code> = <code class="varname">s</code>.<code class="methodname">ColorForIndex</code>(<code class="varname">v</code>);
|
||
<code class="varname">c</code>.<code class="varname">red</code> = (int)(<code class="varname">c</code>.<code class="varname">red</code>*0.75);
|
||
<code class="varname">c</code>.<code class="varname">green</code> = (int)(<code class="varname">c</code>.<code class="varname">green</code>*0.75);
|
||
<code class="varname">c</code>.<code class="varname">blue</code> = (int)(<code class="varname">c</code>.<code class="varname">blue</code>*0.75);
|
||
|
||
<code class="varname">ov</code> = <code class="varname">s</code>.<code class="methodname">IndexForColor</code>(<code class="varname">c</code>);
|
||
<code class="varname">dark_table</code>[<code class="varname">v</code>] = <code class="varname">ov</code>;
|
||
}
|
||
<code class="varname">dark_table_inited</code> = 1;
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
|
||
<span class="type">void</span> <code class="classname">TrackViewer</code>::<code class="methodname">darken_rect</code>(<code class="classname">BRect</code> <code class="parameter">r</code>)
|
||
{
|
||
<span class="type">long</span> <code class="varname">rowbyte</code> = <code class="constant">TRACK_B_H</code>;
|
||
<span class="type">char *</span><code class="varname">base</code>;
|
||
<span class="type">long</span> <code class="varname">y1</code>,<code class="varname">y2</code>;
|
||
<span class="type">long</span> <code class="varname">x1</code>,<code class="varname">x2</code>;
|
||
<span class="type">long</span> <code class="varname">dx</code>,<code class="varname">dy</code>;
|
||
|
||
if (<code class="varname">dark_table_inited</code> == 0) {
|
||
<code class="function">init_dark_table</code>();
|
||
}
|
||
|
||
<code class="varname">y1</code> = (<span class="type">int</span>)<code class="parameter">r</code>.<code class="varname">top</code>;
|
||
<code class="varname">y2</code> = (<span class="type">int</span>)<code class="parameter">r</code>.<code class="varname">bottom</code>;
|
||
if (<code class="parameter">r</code>.<code class="varname">right</code> < <code class="parameter">r</code>.<code class="varname">left</code>)
|
||
return;
|
||
|
||
if (<code class="varname">y1</code> >= <code class="constant">TRACK_HEIGHT</code>)
|
||
return;
|
||
|
||
if (<code class="varname">y2</code> < 0)
|
||
return;
|
||
|
||
if (<code class="varname">y1</code> < 0) {
|
||
<code class="varname">y1</code> = 0;
|
||
}
|
||
|
||
if (<code class="varname">y2</code> > (<code class="constant">TRACK_HEIGHT</code> - 1)) {
|
||
<code class="varname">y2</code> = <code class="constant">TRACK_HEIGHT</code> - 1;
|
||
}
|
||
|
||
<code class="varname">dy</code> = (<code class="varname">y2</code>-<code class="varname">y1</code>);
|
||
|
||
<code class="varname">x1</code> = (<span class="type">int</span>)(<code class="parameter">r</code>.<code class="varname">left</code>);
|
||
<code class="varname">x2</code> = (<span class="type">int</span>)(<code class="parameter">r</code>.<code class="varname">right</code>);
|
||
|
||
if (<code class="varname">x1</code> > (<code class="constant">TRACK_WIDTH</code>))
|
||
return;
|
||
if (<code class="varname">x2</code> < 0)
|
||
return;
|
||
|
||
if (<code class="varname">x1</code> < 0)
|
||
<code class="varname">x1</code> = 0;
|
||
if (<code class="varname">x2</code> > (<code class="constant">TRACK_WIDTH</code>))
|
||
<code class="varname">x2</code> = <code class="constant">TRACK_WIDTH</code>;
|
||
|
||
if (<code class="parameter">r</code>.<code class="varname">top</code> >= 0) {
|
||
while(<code class="varname">y1</code> <= <code class="varname">y2</code>) {
|
||
<code class="varname">dx</code> = <code class="varname">x2</code> - <code class="varname">x1</code>;
|
||
<code class="varname">base</code> = (<span class="type">char *</span>)<code class="varname">the_off</code>-><code class="methodname">Bits</code>() + <code class="varname">y1</code>*<code class="varname">rowbyte</code>+<code class="varname">x1</code>;
|
||
<code class="varname">y1</code>++;
|
||
|
||
while(<code class="varname">dx</code>>=0) {
|
||
*<code class="varname">base</code> = <code class="varname">dark_table</code>[*<code class="varname">base</code>];
|
||
<code class="varname">base</code>++;
|
||
<code class="varname">dx</code>--;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
<span class="comment">//------------------------------------------------------</span>
|
||
</pre><p>
|
||
Simple!
|
||
</p><p>
|
||
So, my final question. Would anybody like to challenge my claim of
|
||
finding the "most hostile environment for programming BeOS?"
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="DevWorkshop4-35"></a>Developers' Workshop: Simple Single-Threaded Message Handling</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Owen</span> <span class="surname">Smith</span></span></div></div></div><p>
|
||
One of the most important issues that comes up in porting apps from other
|
||
OSes is adjusting to BeOS's pervasively threaded world. In today's
|
||
article, I'll show you an easy way to make apps that you're porting
|
||
happy, as well as demonstrate a sometimes-overlooked class that you can
|
||
make good use of in your BeOS-native programs as well.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id817455"></a>The Problem</h3></div></div></div><p>
|
||
If you're familiar with Windows, Macintosh, and UNIX apps, you know that
|
||
they usually run in one thread. This main thread is responsible for all
|
||
messages involving the application, its windows, their views, and any
|
||
other message targets there might be in the application.
|
||
</p><p>
|
||
For example, 99.99% of a Windows application's time in the main thread is
|
||
spent inside the main message loop, which looks something like this:
|
||
</p><pre class="programlisting cpp">
|
||
while (::<code class="methodname">PeekMessage</code>(&<code class="varname">msg</code>, 0, 0, 0, <code class="constant">PM_REMOVE</code>)) {
|
||
if (<span class="comment">/* is a quit msg */</span>) {
|
||
break;
|
||
} else {
|
||
::<code class="methodname">TranslateMessage</code>(&<code class="varname">msg</code>);
|
||
::<code class="methodname">DispatchMessage</code>(&<code class="varname">msg</code>);
|
||
}
|
||
}
|
||
</pre><p>
|
||
Most applications that you port assume this one-thread model of handling
|
||
data. Because in this model only one thread is handling a message at a
|
||
time, there's no need for message handling routines to access their data
|
||
in a thread-safe manner (i.e., using synchronization and locking
|
||
mechanisms).
|
||
</p><p>
|
||
Now this is actually quite similar to the BeOS way of doing things --
|
||
after all, how many ways can you write a message handling loop?—though
|
||
the actual processing loop is run automatically for you by <code class="classname">BWindow</code>,
|
||
<code class="classname">BApplication</code>, and other
|
||
<code class="classname">BLooper</code>-derived denizens. The big difference in
|
||
the BeOS, however, is that each <code class="classname">BLooper</code> runs in its own thread. So in the
|
||
BeOS, there are several threads running message loops: one for your
|
||
application, one for each window, and one for each other <code class="classname">BLooper</code>-derived
|
||
object you might have created for your own nefarious purposes. If you
|
||
scatter the message- handling routines of your ported app among these
|
||
threads, disaster is almost certain to result, as suddenly the message
|
||
handling functions will be stepping on each other's toes left and right.
|
||
</p><p>
|
||
One way to fix this is to implement synchronization and locking
|
||
mechanisms throughout the app, making sure that each message- handling
|
||
routine carefully locks the data it will be handling, and otherwise deals
|
||
with the nuances of being thrust into a tangled web of threads. Managing
|
||
this, of course, will no doubt earn you the astonishment and admiration
|
||
of your fellow BeOS porters, as well as sincere thanks from the original
|
||
authors for transforming their weekend hack into a bullet-proof,
|
||
thread-safe, and otherwise divinely inspired piece of code. But if that
|
||
application you're trying to port is over, say, 100 lines in size, this
|
||
solution quickly becomes intractable—especially when you take one of
|
||
the Great Mysteries of Porting into account: that is, the code you're
|
||
trying to port is never quite as clean or understandable as you'd like --
|
||
or need.
|
||
</p><p>
|
||
The second way is to serialize all message handling in your app through
|
||
one thread, to present apps that you're porting with the threading model
|
||
that they expect. Curiously enough, this seems to be the method of choice
|
||
around here.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id817569"></a>The Solution</h3></div></div></div><p>
|
||
To do the latter, we need to take the messages we receive and put them
|
||
into a single queue for the message-handling thread to read and dispatch.
|
||
Enter the appropriately named target of today's discussion, the
|
||
<code class="classname">BMessageQueue</code>. The <code class="classname">BMessageQueue</code>
|
||
implements a simple, thread-safe
|
||
container of <code class="classname">BMessages</code> (the Be Book has the lowdown if you're curious).
|
||
Let's look at some of the ways we might implement our solution with
|
||
<code class="classname">BMessageQueue</code>.
|
||
</p><p>
|
||
At first blush, it seems that all we need to do is add the messages we
|
||
receive to the queue:
|
||
</p><pre class="programlisting cpp">
|
||
<code class="classname">BMessageQueue</code> <code class="varname">theQueue</code>;
|
||
|
||
<code class="classname">MyWindow</code>::<code class="methodname">MessageReceived</code>(<span class="type"><code class="classname">BMessage</code>*</span> <code class="parameter">msg</code>) {
|
||
<code class="varname">theQueue</code>.<code class="methodname">AddMessage</code>(<code class="parameter">msg</code>);
|
||
}
|
||
</pre><p>
|
||
If you read my newsletter articles from a few weeks back
|
||
"<a class="xref" href="Issue4-29.html#DevWorkshop4-29" title="Developers' Workshop: The Magic of Messages Part 1: The Sending">Developers' Workshop: The Magic of Messages Part 1: The Sending</a>" and
|
||
"<a class="xref" href="Issue4-30.html#DevWorkshop4-30" title="Developers' Workshop: The Magic of Messages Part 2: The Receiving">Developers' Workshop: The Magic of Messages Part 2: The Receiving</a>",
|
||
you'll hopefully realize that something is wrong with
|
||
this code. The problem is that <code class="varname">msg</code> gets deleted when we return from
|
||
<code class="methodname">MessageReceived()</code>, so that by the time our message-handling thread reads
|
||
the item from the queue, the message pointer will be invalid. The correct
|
||
way to do this is to detach the message from the <code class="classname">BLooper</code> first so the
|
||
<code class="classname">BLooper</code> doesn't delete them behind our backs when we return from
|
||
<code class="methodname">MessageReceived()</code>:
|
||
</p><pre class="programlisting cpp">
|
||
<code class="classname">MyWindow</code>::<code class="methodname">MessageReceived</code>(<span class="type"><code class="classname">BMessage</code>*</span> <code class="parameter">msg</code>) {
|
||
<code class="methodname">DetachCurrentMessage</code>();
|
||
<code class="varname">theQueue</code>.<code class="methodname">AddMessage</code>(<code class="parameter">msg</code>);
|
||
}
|
||
</pre><p>
|
||
When we do this, remember the Solemn Responsibilities that you shoulder
|
||
when you detach the message:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
Thou shalt handle the message soon. (The message sender might be
|
||
waiting for you to finish with this message, so it's good etiquette to
|
||
ensure that the message sender doesn't wait longer than necessary for
|
||
you to complete your task.)
|
||
</p></li><li><p>
|
||
Thou shalt delete the message when thou art done with the message.
|
||
(Otherwise, the message sender might wait in limbo for eternity for a
|
||
reply to come.)
|
||
</p></li></ul><p>
|
||
Now we need to implement the message-processing thread to handle the
|
||
messages. It will look something like this:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="type">status_t</span> <code class="function">RunMyMessageThread</code>(<span class="type">void*</span> <span class="comment">/* obj */</span>) {
|
||
while (<code class="constant">true</code>) {
|
||
<span class="comment">// Peek until we see a message and remove it</span>
|
||
while (<code class="varname">theQueue</code>.<code class="methodname">IsEmpty</code>()) <code class="function">snooze</code>(1000);
|
||
<span class="type"><code class="classname">BMessage</code>*</span> <code class="varname">msg</code> = <code class="varname">theQueue</code>.<code class="methodname">NextMessage</code>();
|
||
|
||
if (<span class="comment">/* is a quit message */</span>) {
|
||
delete <code class="varname">msg</code>; <span class="comment">// almost forgot, didn't you?</span>
|
||
break;
|
||
} else {
|
||
<span class="comment">// translate and dispatch the message</span>
|
||
delete <code class="varname">msg</code>;
|
||
}
|
||
}
|
||
return <code class="constant">B_OK</code>;
|
||
}
|
||
</pre><p>
|
||
Alternatively, to avoid actively polling the queue in our peek message,
|
||
we can use a semaphore to signal the message thread when there are
|
||
messages in the queue. In this case, our thread will only wake up when
|
||
there are messages to handle:
|
||
</p><pre class="programlisting cpp">
|
||
<span class="comment">// semaphore is created with an initial count of 0
|
||
// the count indicates the number of messages in the queue</span>
|
||
<span class="type">sem_id</span> <code class="varname">queueHasMessages</code>;
|
||
<code class="classname">BMessageQueue</code> <code class="varname">theQueue</code>;
|
||
|
||
<code class="classname">MyWindow</code>::<code class="methodname">MessageReceived</code>(<span class="type"><code class="classname">BMessage</code>*</span> <code class="parameter">msg</code>) {
|
||
<code class="methodname">DetachCurrentMessage</code>();
|
||
<code class="varname">theQueue</code>.<code class="methodname">AddMessage</code>(<code class="parameter">msg</code>);
|
||
<code class="function">release_sem</code>(<code class="varname">queueHasMessages</code>); <span class="comment">// signals thread to
|
||
// wake up</span>
|
||
}
|
||
|
||
<span class="type">status_t</span> <code class="function">RunMyMessageThread</code>(<span class="type">void*</span> <span class="comment">/* obj */</span>) {
|
||
while (<code class="constant">true</code>) {
|
||
<span class="comment">// Peek until we see a message and remove it</span>
|
||
<code class="function">acquire_sem</code>(<code class="varname">queueHasMessages</code>);
|
||
<span class="type"><code class="classname">BMessage</code>*</span> <code class="varname">msg</code> = <code class="varname">theQueue</code>.<code class="methodname">NextMessage</code>();
|
||
if (<span class="comment">/* is a quit message */</span>) {
|
||
delete <code class="varname">msg</code>;
|
||
break;
|
||
} else {
|
||
<span class="comment">// translate and dispatch the message</span>
|
||
delete <code class="varname">msg</code>;
|
||
}
|
||
}
|
||
return <code class="constant">B_OK</code>;
|
||
}
|
||
</pre><p>
|
||
For giggles, you can extend this approach to have multiple threads
|
||
reading from the message queue—for example, if you want to farm out a
|
||
single list of tasks among a number of worker threads.
|
||
</p></div><p>
|
||
I hope these simple snippets will give you even more ideas about how you
|
||
can distribute message handling responsibilities in your application in a
|
||
flexible and simple way.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="BitByBit4-35"></a>Bit By Bit: BFilePanels and Saving Files</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Stephen</span> <span class="surname">Beaulieu</span></span></div></div></div><p>
|
||
In this installment, Rephrase becomes a usable basic plain text editor
|
||
with the introduction of file open and save capabilities.
|
||
</p><p>
|
||
You'll find this version of Rephrase at:
|
||
</p><p>
|
||
<ftp://ftp.be.com/pub/samples/tutorials/rephrase/rephrase0.1d4.zip>
|
||
</p><p>
|
||
Rephrase 0.1d4<br />
|
||
New Features<br />
|
||
Create new phrases.<br />
|
||
Open existing phrases.<br />
|
||
Save phrases.
|
||
</p><p>
|
||
This version of Rephrase introduces too many programming concepts to
|
||
cover in one article. Therefore, next week's article will not introduce
|
||
any new sample code.
|
||
</p><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id818093"></a>Programming Concepts</h3></div></div></div><p>
|
||
<code class="classname">BFilePanel</code>s provide windows that let a user navigate a file system to
|
||
open one or more files or save a file at a specific location. A
|
||
<code class="classname">BFilePanel</code> can either open or save files, but this flavor must be set
|
||
when it is created.
|
||
</p><p>
|
||
All file panels present the user with a navigable view of the file
|
||
system. The panel's default button sends a message to a specified target
|
||
that contains identifiers for the file or files to open or save. By
|
||
default, the target is the <code class="classname">BApplication</code> object, but a different object
|
||
can be set through the constructor or <code class="methodname">SetMessage()</code>. The messages sent
|
||
vary depending on the flavor of the panel.
|
||
</p><p>
|
||
Open panels send a message containing all the entry refs selected by the
|
||
user. Save panels send a message with the <span class="type">entry_ref</span> of the directory
|
||
selected by the user and the name of the file to create.
|
||
</p><p>
|
||
Open panel messages have a default <code class="varname">what</code> code of
|
||
<code class="constant">B_REFS_RECEIVED</code>. Save
|
||
panels have a default code of <code class="constant">B_SAVE_REQUESTED</code>. An application can
|
||
specify a different message for the panel to send through the constructor
|
||
or <code class="methodname">SetMessage()</code>. The file panel information is added to this new message.
|
||
</p><p>
|
||
Both save and open file panels also send <code class="constant">B_CANCEL</code> messages whenever the
|
||
panel is closed, has its cancel button pressed, or is hidden. This means
|
||
that when a user selects the open or save button, two messages are sent:
|
||
first, the save or open message, and then the <code class="constant">B_CANCEL</code> message to inform
|
||
the target that the panel is no longer visible.
|
||
</p></div><div class="sect2"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h3 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id818181"></a>Implementation details:</h3></div></div></div><div class="orderedlist"><ol><li><p>
|
||
Don't build a file panel until it is requested. This saves
|
||
resources and time.
|
||
[<code class="filename">pDisplay.cpp</code>:361-367 & <code class="filename">Rephrase.cpp</code>:125-129]
|
||
</p></li><li><p>
|
||
Do not delete commonly used <code class="classname">BFilePanel</code>s, as they can take time to
|
||
create. Instead, hide them and show them again when needed. In
|
||
addition, the file panel will remember its last browsed directory.
|
||
</p></li><li><p>
|
||
There is only one open file panel for Rephrase. Opening new display
|
||
windows is handled in the app. [<code class="filename">Rephrase.h</code>:24]
|
||
</p></li><li><p>
|
||
Each phrase display window has its own save panel, as each phrase
|
||
might need to be saved to a different directory. Also, synchronizing
|
||
access to one save panel from many documents would be very
|
||
complicated. With independent save panels, each panel can target a
|
||
different phrase display window.
|
||
[<code class="filename">pDisplay.h</code>:29]
|
||
</p></li><li><p>
|
||
With the introduction of custom message types for opening and
|
||
saving phrases, it's now necessary to override <code class="methodname">MessageReceived()</code> in
|
||
the <code class="classname">Rephrase</code> and <code class="classname">pDisplay</code> classes.
|
||
</p><p>
|
||
There are three main guidelines when overriding <code class="methodname">MessageReceived()</code>:
|
||
</p><ul class="itemizedlist"><li><p>
|
||
Use a switch on the <code class="varname">what</code> field of the <code class="classname">BMessage</code> to specify the
|
||
flow of code.
|
||
</p></li><li><p>
|
||
Either call functions or wrap each case in brackets to avoid
|
||
warnings and errors about "jumping past initializers."
|
||
</p></li><li><p>
|
||
Always send unrecognized messages to your superclass in the
|
||
default case of the switch statement.
|
||
[<code class="filename">pDisplay.cpp</code>:164-202 & <code class="filename">Rephrase.cpp</code>:111-151]
|
||
</p></li></ul></li><li><p>
|
||
The New menu item sends a <code class="constant">NEW_PHRASE</code> message to the app, which then
|
||
creates and shows an empty display window.
|
||
[<code class="filename">Rephrase.cpp</code>:116-121]
|
||
</p></li><li><p>
|
||
The Open menu item sends an <code class="constant">OPEN_PHRASE</code> message to the app. In
|
||
response the app will show the open panel, creating it if necessary.
|
||
The file panel sends a message that is handled in <code class="methodname">RefsReceived()</code>.
|
||
[<code class="filename">Rephrase.cpp</code>:122-136]
|
||
</p></li><li><p>
|
||
To save a phrase to a file, the file's location must be specified.
|
||
This happens in one of two ways: either the phrase display window is
|
||
opened with a given <span class="type">entry_ref</span> or the <span class="type">entry_ref</span>
|
||
is specified in a save panel.
|
||
</p><p>
|
||
The save panel is shown if an entry ref has never been set for the
|
||
file, or if the SaveAs item is selected to save the contents to a new
|
||
location.
|
||
</p></li><li><p>
|
||
<code class="methodname">pDisplay::SaveTo()</code> handles all the work. Its sole argument is a
|
||
<span class="type"><code class="classname">BEntry</code>*</span>. If the argument is
|
||
<code class="constant">NULL</code>, the save panel is shown so the user
|
||
can specify a location for the file.
|
||
</p><p>
|
||
Otherwise, a <code class="classname">BFile</code> object is created and told to create the actual
|
||
file if it does not already exist. Then the contents of the phrase are
|
||
written to the file, and the size of the file is set accordingly. A
|
||
<code class="classname">BNodeInfo</code> object is created so that new files can get their mime type
|
||
set appropriately.
|
||
</p><p>
|
||
Finally the window title is set to the name of the file and the entry
|
||
ref is cached in the window for future use.
|
||
[<code class="filename">pDisplay.cpp</code>:352-433]
|
||
</p></li><li><p>
|
||
The Save menu item sends a <code class="constant">SAVE_PHRASE</code> message to the phrase
|
||
window. In response, <code class="methodname">pDisplay::Save()</code> checks to see if the cached
|
||
<span class="type">entry_ref</span> has been set. If so, it creates a <code class="classname">BEntry</code> object and passes
|
||
it to <code class="methodname">SaveTo()</code>. If not, it passes <code class="constant">NULL</code>
|
||
so that the save panel can be shown.
|
||
[<code class="filename">pDisplay.cpp</code>:334-350]
|
||
</p></li><li><p>
|
||
The SaveAs menu item sends a <code class="constant">SAVE_PHRASE_AS</code> message to the
|
||
window. In response, <code class="methodname">pDisplay::SaveTo(NULL)</code> is called, bringing up
|
||
the save panel to specify the new file location.
|
||
[<code class="filename">pDisplay.cpp</code>:174-178]
|
||
</p></li><li><p>
|
||
<code class="classname">pDisplay</code> no longer calls <code class="methodname">Show()</code> in the constructor. As
|
||
<code class="classname">BFilePanel</code>s need to have <code class="methodname">Show()</code>
|
||
called on them, it made sense to have
|
||
consistency with all window-related classes.
|
||
</p></li><li><p>
|
||
<code class="methodname">pDisplay::TargetMenuItems()</code> specifies appropriate targets for the
|
||
menu items. The New, Open, About, and Quit items target the
|
||
application, while the items in the Edit menu target the text view.
|
||
[<code class="filename">pDisplay.cpp</code>:277-303]
|
||
</p></li><li><p>
|
||
<code class="methodname">BTextView::TextRect()</code> returns a special rectangle. The sides and
|
||
top of the rectangle are set from a rectangle passed in the
|
||
constructor or <code class="methodname">SetTextRect()</code>. The bottom value is set from the height
|
||
of the text in the text view. Accordingly, the text rect could be
|
||
much taller or shorter than the rect specified in <code class="methodname">SetTextRect()</code>.
|
||
</p></li><li><p>
|
||
The <code class="classname">BString</code> utility class is used as a
|
||
replacement for <span class="type">char*</span>s
|
||
throughout much of Rephrase. The class provides type-safe and easy
|
||
<code class="function">sprintf()</code> functionality through the operator<< and operator+=.
|
||
[<code class="filename">pDisplay.cpp</code>:394-398]
|
||
</p></li></ol></div></div><p>
|
||
There is considerably more going on in this week's sample code. This
|
||
extra code deals with properly quitting the application, and will be
|
||
covered in detail next week.
|
||
</p></div><hr class="pagebreak" /><div class="sect1"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h2 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="Gassee4-35"></a>Chips Questions</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Jean-Louis</span> <span class="surname">Gassée</span></span></div></div></div><p>
|
||
Now that IBM has announced the availability of a PPC motherboard, why
|
||
doesn't Be jump on the bandwagon and commit to this hardware? My
|
||
apologies for not doing full justice to the number, variations, or
|
||
eloquence of the messages sent to info@be.com or directly to me. You get
|
||
the idea, though. Something is happening in the PPC world and Be ought to
|
||
support it. One correspondent expressed it as a brutal Wall Street
|
||
reduction: "I would even be willing to bet that this would cause the most
|
||
dramatic rise in Be stock since the IPO."
|
||
</p><p>
|
||
The stock price is not a topic for me to comment on, but the sentiment
|
||
regarding the PowerPC needs to be addressed (immediately, which is why
|
||
I've postponed the next installment of the IPO story, "Going Public: Part
|
||
II"). The processor itself is a fine one, as the benchmarks prove. We've
|
||
had versions of BeOS on the PowerPC since 1994, including our current 4.5
|
||
release (whose package clearly states "For x86 and PowerPC"). So, what
|
||
we're dealing with is not really a processor dilemma. Is it then a
|
||
question not of chips but of chipsets? Setting aside a possible
|
||
oversimplification for the moment, this turns out to be a better lead to
|
||
the real issues.
|
||
</p><p>
|
||
Look at the evolution of PC motherboards. More and more functions get
|
||
integrated, as opposed to implemented on plug-in cards. In the process,
|
||
the "chipset," the chip or chips interposed between the faster and faster
|
||
CPU and slower devices such as the PCI bus, memory, frame buffers and the
|
||
like, become richer and richer mediators. The complexity of the better
|
||
chipsets now rivals or exceeds that of the CPU itself.
|
||
</p><p>
|
||
The operating system, in turn, needs to support these mediating devices;
|
||
otherwise, the hardware, or the OS, or both aren't going anywhere. Take
|
||
Silicon Graphics' recent decision to de-emphasize their low-end
|
||
workstations based on Intel processors and Windows NT. These workstations
|
||
required two proprietary objects, a physical one and a logical one. On
|
||
the physical side, Silicon Graphics decided to use ASICs to express their
|
||
knowledge of the application space. Together, these Application Specific
|
||
Integrated Circuits constituted a "chipset" providing high-performance
|
||
I/O for graphics, video, and audio applications in SGI's heritage. The
|
||
idea was to achieve a level of performance higher than that offered by
|
||
the standard PC clone organ bank. This, in turn, required a logical
|
||
object, NT software, drivers and, perhaps, modifications to NT itself.
|
||
Meanwhile, the relentless clone industry continued to drive the price of
|
||
standard organs down and the performance up. The clone drive reached a
|
||
point where the SGI solution became less likely to achieve its original
|
||
goals.
|
||
</p><p>
|
||
If that example isn't enough, recall recent announcements regarding
|
||
high-end chipsets for servers. Two camps were ready to make war over a
|
||
standard, one led by Intel and, if memory serves, the other by Compaq.
|
||
But the cost of the conflict and the benefits of having only one standard
|
||
led to peace. We can now expect organ bank support for eight-way
|
||
multiprocessing, coming soon from your favorite motherboard supplier.
|
||
</p><p>
|
||
To return to PowerPC hardware, we need to know more about chipsets that
|
||
support the PowerPC. Who builds them, how competitive are they, which I/O
|
||
devices are supported, how is the technical documentation accessed, who
|
||
fixes bugs in the product and the documentation? As far as the IBM PPC
|
||
hardware is concerned, other questions arise. Where can I buy it and
|
||
where can I get it fixed, for instance? As answers emerge, it will be
|
||
easy for us to make a decision.
|
||
</p><p>
|
||
That said, I still haven't answered the Apple question. If Apple is
|
||
selling respectable quantities of PowerPC hardware, how come we don't
|
||
support the latest G3 and G4 machines? As I said above, it boils down to
|
||
a chipset issue. Intel doesn't have an operating system to defend. In
|
||
their best interest, they profess to be "OS-agnostic," the more options,
|
||
the better. In Apple's case, it's different. They own and operate an OS
|
||
and, like Microsoft, see no reason to help a competitor. Linux provides
|
||
access to classical Unix applications and, therefore, is little
|
||
competition for Apple's multimedia heritage. The same can't be said of
|
||
BeOS, and I can see the logic in Apple's decision not to help us with
|
||
access to chipset technical data for a G3/G4 BeOS port.
|
||
</p><p>
|
||
Some have suggested that we look into the Linux sources for such data.
|
||
Perhaps, but I see little reason to open ourselves to possible
|
||
accusations of reverse-engineering. We're welcome on x-86 hardware, we're
|
||
not welcome on Apple G3/G4. We respect the logic and that settles it for
|
||
us.
|
||
</p></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue4-34.html">Issue 4-34, August 25, 1999</a> Up: <a href="volume4.html">Volume 4: 1999</a> Next: <a href="Issue4-36.html">Issue 4-36, September 8, 1999</a> </div><div id="footerB"><div id="footerBL"><a href="Issue4-34.html" title="Issue 4-34, August 25, 1999"><img src="./images/navigation/prev.png" alt="Prev" /></a> <a href="volume4.html" title="Volume 4: 1999"><img src="./images/navigation/up.png" alt="Up" /></a> <a href="Issue4-36.html" title="Issue 4-36, September 8, 1999"><img src="./images/navigation/next.png" alt="Next" /></a></div><div id="footerBR"><div><a href="http://www.haiku-os.org"><img src="./images/People_24.png" alt="haiku-os.org" title="Visit The Haiku Website" /></a></div><div class="navighome" title="Home"><a accesskey="h" href="index.html"><img src="./images/navigation/home.png" alt="Home" /></a></div></div><div id="footerBC"><a href="http://www.access-company.com/home.html" title="ACCESS Co."><img alt="Access Company" src="./images/access_logo.png" /></a></div></div></div><div id="licenseFooter"><div id="licenseFooterBL"><a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/" title="Creative Commons License"><img alt="Creative Commons License" style="border-width:0" src="https://licensebuttons.net/l/by-nc-nd/3.0/88x31.png" /></a></div><div id="licenseFooterBR"><a href="./LegalNotice.html">Legal Notice</a></div><div id="licenseFooterBC"><span id="licenseText">This work is licensed under a
|
||
<a rel="license" href="http://creativecommons.org/licenses/by-nc-nd/3.0/">Creative
|
||
Commons Attribution-Non commercial-No Derivative Works 3.0 License</a>.</span></div></div></body></html>
|