haiku-website/static/legacy-docs/benewsletter/Issue4-3.html

673 lines
51 KiB
HTML
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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-2.html" title="Issue 4-2, January 13, 1999" /><link rel="next" href="Issue4-4.html" title="Issue 4-4, January 27, 1999" /></head><body><div id="header"><div id="headerT"><div id="headerTL"><a accesskey="p" href="Issue4-2.html" title="Issue 4-2, January 13, 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-4.html" title="Issue 4-4, January 27, 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-2.html">Issue 4-2, January 13, 1999</a>  Up: <a href="volume4.html">Volume 4: 1999</a>  Next: <a href="Issue4-4.html">Issue 4-4, January 27, 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-3"></a>Issue 4-3, January 20, 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="BeDepot4-3"></a>BEDEPOT.COM: Shopping is a Feeling</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><span xmlns="http://www.w3.org/1999/xhtml" class="author">By <span class="firstname">Melanie</span> <span class="surname">Walker</span></span></div></div></div><p>
If I were in Marketing, I would come up with a tag line for BeDepot.com
that went something like this: "Using the BeOS isn't hard, shopping for
it shouldn't be either." As David Byrne said in True Stories, "Shopping
is a feeling."
</p><p>
Unfortunately, of late, the BeDepot.com that we have all come to know and
love has been incredibly difficult to use, and the prevailing feeling for
users, developers, and the BeDepot.com team alike has been one of
frustration.
</p><p>
How did this happen? Putting it succinctly, BeDepot.com was conceived as
a simple but elegant solution for web commerce in an era that pre-dated
the distribution of physical software, a break in the binary
compatibility of the BeOS, and the idea that developers would want to
distribute binaries for PPC and Intel separately. We have augmented the
system to handle all of these tasks, but not quite seamlessly. This,
coupled with a few select design problems inherent in SoftwareValet has
caused users some grief.
</p><p>
The good news is that we are working to put real solutions in place that
will make shopping at BeDepot.com a pleasure once more. Most notably, we
will be introducing "WebValet" which gives users online access to all
available updates for the software you've bought through BeDepot.com. In
the mean time, we have come up with the following workarounds to the more
common problems that users are encountering.
</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="id522770"></a>Common Problems Moving from R3 to R4</h3></div></div></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522777"></a>Problem: Lost SoftwareValet settings.</h4></div></div></div><p>
As people move from R3 to R4, a common problem is that they inadvertently
overwrite their SoftwareValet settings as they do a clean install.
SoftwareValet settings are generated whenever you install a
PackageBuilder package. They are generic files that BeDepot.com uses to
update your software. Without these settings, you can't update.
</p><p>
- Workaround 1: If you back up your R3 SoftwareValet settings, you can
install them in your R4 settings directory and update as normal under R4.
See the SoftwareValet documentation for more into on how to back up these
settings.
</p><p>
- Workaround 2: If you've already lost your SoftwareValet settings, you
can write to [support@bedepot.com] and we can regenerate your settings
for you.
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522808"></a>Problem: Ordered/downloaded software for the wrong version of the BeOS.</h4></div></div></div><p>
Some software on BeDepot.com is available for both R3 and R4. Some
software is only available for one or the other. When you order or
download software, it is labeled as either R3 or R4 software. Be sure to
select the appropriate version for your machine.
</p><p>
- Workaround: If you download the wrong version of an application, if
there exists a version for your machine, BeDepot.com can get it to you.
If the correct version does not exist for your current version of the
BeOS, BeDepot.com will gladly refund your money. Write to
[support@bedepot.com].
Common Update Problems
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522833"></a>Problem: Downloaded wrong update / scrambled update.</h4></div></div></div><p>
Because of the design of the Newer Versions window in the SoftwareValet
SoftwareManager, only one available version shows up at a time in the
window. As a result, it is very easy to download the wrong version.
Unfortunately, due to a bug in SoftwareValet, you can only update once.
Which means that if you get the wrong version the first time, you're
stuck.
</p><p>
- Workaround: BeDepot.com can arrange for you to get the update you need.
Write to [support@bedepot.com].
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522856"></a>Problem: Updating through another browser.</h4></div></div></div><p>
My BeOS partition isn't configured for the Internet. Can I update through
another web browser?
</p><p>
- Workaround: Right now, the only way to update is through SoftwareValet
and therefore you must be using the BeOS.
</p></div></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="id522877"></a>General BeDepot.com Problems</h3></div></div></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522883"></a>Problem: Trouble accessing the other version of a product with platform
switching.</h4></div></div></div><p>
Many of the products offered through BeDepot.com offer "platform
switching." That is, if you buy the Intel version, you get the PPC
version for free or vice versa. However, in practice, if the program is
split into separate binaries for each platform, you can only access the
one you bought.
</p><p>
- Workaround: Currently you can only download the version that you
bought. However, you can obtain the other platform version through
BeDepot.com directly by writing to [support@bedepot.com].
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522907"></a>Problem: ODBC Errors.</h4></div></div></div><p>
From time to time, BeDepot.com users encounter ODBC errors. These are
often due to timeouts and seem to occur most often during peak hours.
However, on occasion, these are warnings that you have encountered a bug
in the system.
</p><p>
- Workaround: If you encounter an ODBC error, and it looks like a
timeout, chances are good that the server is just busy. Wait for a while
and try again later. If the ODBC error you get looks like it is something
other than a timeout, feel free to copy the error message and send it to
us, so we can identify and fix the problem. You can send bug reports to
Customer Support at: [support@bedepot.com].
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id522933"></a>Problem: R4 Update Delays.</h4></div></div></div><p>
You ordered your update a while ago but you still haven't received a
copy. You're sure that you've registered your copy of the BeOS on the Be
web site, too.
</p><p>
- Workaround: If you have registered your copy of the BeOS and you still
haven't received your copy of R4, you can look up the status of your
order on the BeDepot.com web site in the Your Account area, under Order
Status. If your order is listed as "On Hold," chances are good that your
order is on hold while we look up your registration and confirm it. If
your order has been on hold for more than two weeks, please notify
Customer Service at: [custservice@bedepot.com].
For Further Information
</p></div></div><p>
In addition to this list, good resources for BeDepot.com information
include the BeDepot.com Help Area
[http://www.bedepot.com/Support/index.html] and the SoftwareValet FAQs.
</p><p>
When you need to contact a human being, we've got that covered, too. For
ordering issues, you can e-mail [custservice@bedepot.com]. For technical
support issues regarding BeDepot.com, you can e-mail
[support@bedepot.com]. For technical issues regarding the BeOS proper,
please e-mail [support@be.com].
</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-3"></a>Be Engineering Insights: Writing a Modular Color Picker</h2></div><div xmlns:d="http://docbook.org/ns/docbook"><div xmlns="http://www.w3.org/1999/xhtml" class="authorgroup">By <span class="author"><span class="firstname">Pavel</span> <span class="surname">Cisler</span>, </span><span class="author"><span class="firstname">Robert</span> <span class="surname">Chinn</span></span></div></div></div></div><p>
Here's an idea we've wanted to try out for a long time. It's always amazing
how many cool color pickers there are for BeOS:
<span class="application">roColor</span>, for a start, and more in
<span class="application">Gobe Productive</span>,
<span class="application">ArtPaint</span>, new
<span class="application">Mail-It</span>, <span class="application">Pe</span>, and
other applications. What if you could choose the coolest one and hook it up
as the preferred color picker for all the apps on your disk? But because
different apps may need different color pickers, it would be best to have
both a default picker and application specific pickers. If color pickers
are written as a separate module, we should be able to choose the preferred
application for color selection in <span class="application">FileTypes</span>,
the same way we can select a preferred application for
<span class="type">text/source-code</span>. Here's how it could work.
</p><p>
A color-defining label/view interacts with a color picker module using a
messaging suite, designed for selecting a color. The messaging suite is
well defined, in the same way that something like the format of an
<acronym class="acronym" title="Rich Text Format">RTF</acronym>
document is. The suite has a <acronym class="acronym">MIME</acronym> type associated with it, for example,
<span class="type">application/x-vnd.Be.colorPicker</span>. When a color label is invoked, the
preferred application for <span class="type">application/x-vnd.Be.colorPicker</span> is launched
and a messaging protocol is established.
</p><p>
For this to work right, we need to integrate the color picker application
and the color label that launches it really well. Ideally it should seem
as if the module, a separate application, were really just a color picker
dialog in the same application.
</p><p>
The messaging suite will let us do the following:
</p><ul class="itemizedlist"><li><p>
Launch the color picker application and establish a connection.
</p></li><li><p>
Pass in an initial color value.
</p></li><li><p>
Pass in the name of the target color label that the color picker can
use to identify its target (in the window title, for example).
</p></li><li><p>
Pass in the initial click location to allow positioning of the color
picker.
</p></li><li><p>
Send color updates from the color picker module to the client color
label.
</p></li><li><p>
Send color updates back in the other direction—if the color label
is updated, say by drag and drop, the color picker has to catch up and
send Apply, Cancel, and possibly Revert messages back from the color
picker to the color label.
</p></li><li><p>
Break down a connection when the user closes the color picker.
</p></li><li><p>
Quit the color picker when the invoking color label goes away.
</p></li></ul><p>
If we can handle all of actions, the color picker should be pretty well
integrated.
</p><p>
Included with this article are three small apps that demonstrate how to
implement this scheme. One is a simple application with two color labels
you can use to set color values in preference panels (for example). The
other two are different color picker panels.
</p><p>
You'll find the source code for this article at
</p><p>
[ftp://ftp.be.com/pub/samples/application_kit/colorPickerModule.zip]
</p><p>
The code contains most of the fun stuff in this article—we'll just
point out some of the important parts here.
</p><p>
The first color picker is very limited; it just uses the built-in
<code class="classname">BColorControl</code>. The second one is less trivial; it implements a
<code class="classname">BColorControl</code>-like crayon color picker.
</p><p>
The sample application uses a <code class="classname">ModuleProxy</code> class to
manage the connection to the color picker module. This is done more for
tidiness than anything else: <code class="classname">ModuleProxy</code> makes it
easy to hook up the described protocol into color labels like
<code class="classname">ColorLabel</code>. It's hard-coded to deal with
<span class="type">rgb_color</span> values but could be easily modified to accommodate
different value types by turning it into a template class.
</p><p>
The destructor of <code class="classname">ModuleProxy</code> sends a message to any open color picker to
quit itself, so we don't get color pickers hanging around when the
originating dialog is gone. The UpdateValue call is used when the target
client—the <code class="classname">ColorLabel</code>—changes its value without the color picker
knowing. This way the color picker can follow the value by updating
itself.
</p><p>
<code class="methodname">MessageReceived()</code> handles messages from the color
picker—forcing an update of the <code class="classname">ColorLabel</code> when
the color picker changes—and establishes and tears down the connection
with the color picker. <code class="methodname">Invoke()</code> is called from the
<code class="classname">ColorLabel</code>. <code class="methodname">Invoke()</code> is a
little more interesting: if a color picker isn't running yet, it launches
one, sending it a setup message.
</p><pre class="programlisting cpp">
<span class="type">void</span>
<code class="classname">ModuleProxy</code>::<code class="methodname">Invoke</code>()
{
if (<code class="varname">connectionOpen</code>) {
<code class="varname">module</code>.<code class="methodname">SendMessage</code>(<code class="constant">B_WINDOW_ACTIVATED</code>);
<span class="comment">// we already have a picker serving us, pull it up</span>
return;
}
...
<span class="type">uint32</span> <code class="varname">buttons</code>;
<code class="classname">BPoint</code> <code class="varname">point</code>;
<code class="varname">target</code>-&gt;<code class="methodname">GetMouse</code>(&amp;<code class="varname">point</code>, &amp;<code class="varname">buttons</code>);
<code class="classname">BMessage</code> <code class="varname">launchMessage</code>(<code class="constant">kInitiateConnection</code>);
<code class="varname">launchMessage</code>.<code class="methodname">AddMessenger</code>(<code class="constant">kClientAddress</code>,
<code class="classname">BMessenger</code>(<code class="varname">this</code>));
<span class="comment">// this is the messenger we want the color picker to
// interact with</span>
<code class="varname">launchMessage</code>.<code class="methodname">AddPoint</code>(<code class="constant">kInvokePoint</code>,
<code class="varname">target</code>-&gt;<code class="methodname">ConvertToScreen</code>(<code class="varname">point</code>));
<span class="comment">// add the current invocation point so that the color
// picker can position itself near the click</span>
<code class="varname">launchMessage</code>.<code class="methodname">AddString</code>(<code class="constant">kTargetName</code>, <code class="varname">target</code>-&gt;<code class="methodname">Name</code>());
<span class="comment">// add the current invocation point so that the color
// picker can position itself near the click</span>
<span class="type">rgb_color</span> <code class="varname">color</code> = <code class="varname">target</code>-&gt;<code class="methodname">ValueAsColor</code>();
<code class="varname">launchMessage</code>.<code class="methodname">AddData</code>(<code class="constant">kInitialValue</code>, <code class="constant">B_RGB_COLOR_TYPE</code>,
&amp;<code class="varname">color</code>, <code class="function">sizeof</code>(<code class="varname">color</code>));
<span class="comment">// add the current color value</span>
<code class="varname">launchMessage</code>.<code class="methodname">AddInt32</code>(<code class="constant">kRequestedValues</code>, <code class="constant">B_RGB_COLOR_TYPE</code>);
<span class="comment">// ask for the type of values we need</span>
if (<code class="varname">preferredApp</code>.<code class="methodname">Length</code>())
<span class="comment">// we have a specific preferred application for this
// instance launch the picker - use the application
// signature for this particular client</span>
<code class="varname">be_roster</code>-&gt;<code class="methodname">Launch</code>(<code class="varname">preferredApp</code>.<code class="methodname">String</code>(), &amp;<code class="varname">launchMessage</code>);
else
<code class="varname">be_roster</code>-&gt;<code class="methodname">Launch</code>(<code class="varname">type</code>.<code class="methodname">String</code>(), &amp;<code class="varname">launchMessage</code>);
<span class="comment">// launch the picker, just use the mime type
// to choose the preferred application</span>
}
</pre><p>
Note that Invoke uses the
<code class="methodname">BRoster::Launch</code>(<span class="type">const char*</span> <code class="parameter">mimeType</code>,
<span class="type"><code class="classname">BMessage</code>*</span>,...)
call to start up the color picker. If a signature for the preferred color
picker was specified, it will be launched; otherwise it uses the default
preferred color picker for the <acronym class="acronym">MIME</acronym> type. It's similar
to what happens when you double-click a document: it may have a specific
preferred application signature or it may just use the preferred
application for the document's type.
</p><p>
<code class="varname">launchMessage</code> goes to the color picker
application's <code class="methodname">MessageReceived()</code>:
</p><pre class="programlisting cpp">
<span class="type">void</span>
<code class="classname">SimplePickerApp</code>::<code class="methodname">MessageReceived</code>(<span class="type"><code class="classname">BMessage</code> *</span><code class="parameter">message</code>)
{
if (<code class="parameter">message</code>-&gt;<span class="type">what</span> == <code class="constant">kInitiateConnection</code>) {
<span class="comment">// This is the initial open message that
// ModuleProxy::Invoke is sending us. Pass it on
// to the new color picker dialog which will
// find all the details in it</span>
<code class="varname">colorPicker</code> = new <code class="classname">SimpleColorPickerDialog</code>(<code class="parameter">message</code>);
<code class="varname">colorPicker</code>-&gt;<code class="methodname">Show</code>();
return;
}
<code class="classname">BApplication</code>::<code class="methodname">MessageReceived</code>(<code class="parameter">message</code>);
}
</pre><p>
<code class="classname">SimpleColorPickerDialog</code> extracts the information about the dialog
position, initial color, window title, etc., and replies back to the
<code class="classname">ModuleProxy</code>, completing the setup.
</p><p>
The destructor posts a message to the client application that the color
picker was closed, so if the user clicks on the color label, <code class="classname">ModuleProxy</code>
can launch a new copy.
</p><p>
<code class="methodname">MessageReceived()</code> handles the rest of the
protocol, closing the connection, responding to
<code class="constant">B_VALUE_CHANGED</code>, and posting the appropriate messages
for Cancel and OK.
</p><p>
When you right-click on the color label, you get a pop-up menu that
allows you to select the preferred color picker application for the
label. The code is similar to the one used by <span class="application">FileTypes</span> to select a
preferred application for a <acronym class="acronym">MIME</acronym> type:
</p><pre class="programlisting cpp">
<span class="type">void</span>
<code class="classname">ModuleProxy</code>::<code class="methodname">RunPreferredPickerSelector</code>(<code class="classname">BPoint</code> <code class="parameter">where</code>)
{
<span class="type"><code class="classname">BPopUpMenu</code> *</span><code class="varname">menu</code> = new <code class="classname">BPopUpMenu</code>("preferredApp");
<span class="type"><code class="classname">BMenuItem</code> *</span><code class="varname">item</code> = new <code class="classname">BMenuItem</code>("Default", 0);
<code class="varname">menu</code>-&gt;<code class="methodname">AddItem</code>(<code class="varname">item</code>);
<code class="varname">menu</code>-&gt;<code class="methodname">AddSeparatorItem</code>();
<code class="classname">BMimeType</code> <code class="varname">mime</code>(<code class="varname">type</code>.<code class="methodname">String</code>());
<span class="comment">// build a list of all the supporting apps</span>
<code class="classname">BMessage</code> <code class="varname">message</code>;
<code class="varname">mime</code>.<code class="methodname">GetSupportingApps</code>(&amp;<code class="varname">message</code>);
for (<span class="type">int32</span> <code class="varname">index</code> =0; ; <code class="varname">index</code>++) {
<span class="type">const char *</span><code class="varname">signature</code>;
<span class="type">status_t</span> <code class="varname">reply</code> = <code class="varname">message</code>.<code class="methodname">FindString</code>("applications",
<code class="varname">index</code>, &amp;<code class="varname">signature</code>);
if (<code class="varname">reply</code> != <code class="constant">B_NO_ERROR</code> || !<code class="varname">signature</code> || !<code class="varname">signature</code>[0])
break;
<span class="type"><code class="classname">BMessage</code> *</span><code class="varname">tmp</code> = new <code class="classname">BMessage</code>;
<code class="varname">tmp</code>-&gt;<code class="methodname">AddString</code>("signature", <code class="varname">signature</code>);
<span class="type">entry_ref</span> entry;
if (<code class="varname">be_roster</code>-&gt;<code class="methodname">FindApp</code>(<code class="varname">signature</code>, &amp;<code class="varname">entry</code>) == <code class="constant">B_OK</code>)
<span class="comment">// add the application by its name</span>
<code class="varname">item</code> = new <code class="classname">BMenuItem</code>(<code class="varname">entry</code>.<code class="varname">name</code>, <code class="varname">tmp</code>);
else
<span class="comment">// can't find the app, just use the signature</span>
<code class="varname">item</code> = new <code class="classname">BMenuItem</code>(<code class="varname">signature</code>, <code class="varname">tmp</code>);
<code class="varname">menu</code>-&gt;<code class="methodname">AddItem</code>(<code class="varname">item</code>);
<span class="comment">// mark the preferred app</span>
if (<code class="varname">preferredApp</code>.<code class="methodname">ICompare</code>(<code class="varname">signature</code>) == 0)
<code class="varname">item</code>-&gt;<code class="methodname">SetMarked</code>(<code class="constant">true</code>);
}
if (!<code class="varname">menu</code>-&gt;<code class="methodname">FindMarked</code>())
<span class="comment">// mark "Default"</span>
<code class="varname">menu</code>-&gt;<code class="methodname">ItemAt</code>(0)-&gt;<code class="methodname">SetMarked</code>(<code class="constant">true</code>);
<span class="comment">// make the selected signature preferred</span>
<code class="varname">item</code> = <code class="varname">menu</code>-&gt;<code class="methodname">Go</code>(<code class="parameter">where</code>);
<span class="type">const char *</span><code class="varname">signature</code>;
if (<code class="varname">item</code>) {
if (!<code class="varname">item</code>-&gt;<code class="methodname">Message</code>())
<span class="comment">// picked "Default"</span>
<code class="varname">preferredApp</code> = "";
else if (<code class="varname">item</code>-&gt;<code class="methodname">Message</code>()-&gt;<code class="methodname">FindString</code>("signature",
&amp;<code class="varname">signature</code>) == <code class="constant">B_OK</code>)
<code class="varname">preferredApp</code> = <code class="varname">signature</code>;
}
delete <code class="varname">menu</code>;
}
</pre><p>
If you compile the application and the two color pickers, note that when
you click on a color label, it launches a color picker application; the
title of the window is identical to the name of the color label; and the
initial color of the color picker matches the color label. You can
right-click on the color label and choose the preferred color picker for
the given label. If you keep the default setting, you can use <span class="application">FileTypes</span>
to pick which of the two color pickers will be used. If you change the
color in the picker, it's updated in the color label. If you drag and
drop a swatch between the two color labels (click on one of the color
labels and start dragging) to change the label color, the color picker
will follow. If you drag and drop a color from roColor, it changes to
that color. If you quit the application, the color picker quits too --
which is just what we wanted it to do!
</p><p>
Some possible enhancements—fun things to try:
</p><ul class="itemizedlist"><li><p>
Allow multiple connections—not very practical in this case, but
each time you Invoke the color label, you can instantiate a new
ModuleProxy, adding them to a list, each time a color picker quits you
delete it. You could have two color pickers target the same color
label; with a little bit of tweaking you could have it set up so that
changing one color picker not only updates the color label, but also
the second color picker.
</p></li><li><p>
Use scripting instead of a rigid messaging protocol. The color values
can be passed back and forth between the color label and the color
picker using the Get/Set property calls.
</p></li><li><p>
Write a modular volume control, etc. You could apply this technique
to writing other things than just color pickers.
</p></li></ul></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-3"></a>Developers' Workshop: Media Kit Basics: Consumers and Producers</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>
Several weeks ago, Sheppy gave us a starting point for learning how to
use the Media Kit:
</p><p>
<a class="xref" href="Issue3-45.html#DevWorkshop3-45" title="Developers' Workshop: Sounding Off With the New Media Kit">Developers' Workshop: Sounding Off With the New Media Kit</a>
</p><p>
For many of you, however, that's not nearly enough. You want to see the
creatures that lurk under <code class="classname">BSoundPlayer</code>'s tame surface. You want to blast
buffers over your media net like terrified badminton shuttlecocks. You
want to run your fingers through the fertile Media Kit soil. And you need
the whole system at your fingertips, yesterday.
</p><p>
Suits me fine. Here's some code for you to peruse:
</p><p>
[ftp://ftp.be.com/pub/samples/media_kit/SoundCapture.zip]
</p><p>
This app does two things. First, it records sounds, using an optional
voice-activation feature, and saves the sounds as raw audio files.
Second, it loads and plays back raw audio sounds so you can audition what
you recorded.
</p><p>
Straightforward this app is, but simple it ain't. It would take me much
longer than a Newsletter article to explain its operation from the ground
up. So, before you read on, please familiarize yourself with the basic
concepts of the Media Kit by browsing the freshly painted Be Book:
</p><p>
<a class="link bebook" href="../BeBook/index.html">index.html</a>
</p><p>
For now, you'll want to concentrate on the Media Kit classes <code class="classname">BMediaNode</code>,
<code class="classname">BBufferConsumer</code>, <code class="classname">BBufferProducer</code>,
and <code class="classname">BMediaRoster</code>. You might also glance
at the header file <code class="filename">MediaDefs.h</code>,
which describes many of the lower-level
structures and defines that we use. Then, look at this article and the
sample code to see how it all fits together!
</p><p>
The code is pretty heavily commented, even for a
<acronym class="acronym" title="Developer Technical Support">DTS</acronym> project, so I'll
spare the details and just touch on a few of the more important issues
here. OK—let's get down and dirty with the Media Kit...
</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="id513896"></a>Under the Hood</h3></div></div></div><p>
There are three key classes that make SoundCapture tick: <code class="classname">SoundConsumer</code>,
<code class="classname">SoundProducer</code>, and <code class="classname">CaptureWindow</code>.
</p><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id513918"></a>SoundConsumer</h4></div></div></div><p>
<code class="classname">SoundConsumer</code> is a franchise of
<code class="classname">BBufferConsumer</code>; its job is to process (i.e.,
"consume") buffers that are sent to it from a higher source.
We've tried to make this class reusable by making it reasonably extensible.
In a similar manner to <code class="classname">BSoundPlayer</code>, we do this by
defining two places where you, the <code class="classname">SoundConsumer</code>
client, need to decide what to do:
</p><ul class="itemizedlist"><li><p>
The <code class="methodname">Process()</code> function, which is called each time a buffer of data
arrives. You provide functionality to tell it what to do with these
buffers.
</p></li><li><p>
The <code class="methodname">Notify()</code> function, which is called each time something important
happens to the node (it starts, stops, or dies an abrupt death, for
example). You provide functionality to dispatch any of these events as
you see fit.
</p></li></ul><p>
You fill in these slots by either subclassing <code class="classname">SoundConsumer</code> and
overriding the function, or simply by passing <code class="classname">SoundConsumer</code> a hook
function to call instead.
</p><p>
We use the <code class="classname">SoundConsumer</code> as a simple recorder.
We implement a <code class="methodname">Process()</code>
hook function that writes the buffer's data to disk, and a <code class="methodname">Notify()</code> hook
function to makes sure that things get cleaned up when the node's about
to stop or die.
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id530932"></a>SoundProducer</h4></div></div></div><p>
<code class="classname">SoundProducer</code> is a subsidiary of
<code class="classname">BBufferProducer</code>; its job is to produce buffers like
clockwork and pass them along to someone else. Like
<code class="classname">SoundConsumer</code>, we provide two places for you to
specialize <code class="classname">SoundProducer</code>'s behavior:
<code class="methodname">Process()</code>, which is called each time a buffer
needs to be filled with data; and <code class="methodname">Notify()</code>, which
is called when certain events happen.
</p><p>
We use the <code class="classname">SoundProducer</code> to implement simple
playback from a sound file. In this sense, it functions almost exactly like
<code class="classname">BSoundPlayer</code> and <code class="classname">BSound</code> (save
that it only reads raw audio, doesn't handle multiple sounds, and doesn't
do sample format conversion).
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id530988"></a>CaptureWindow</h4></div></div></div><p>
In addition to fulfilling its traditional duties as a
<code class="classname">BWindow</code>, <code class="classname">CaptureWindow</code> also
functions in <span class="application">SoundCapture</span> as the context in
which <code class="classname">SoundConsumer</code> and
<code class="classname">SoundProducer</code> are used.
<code class="classname">CaptureWindow</code> contains an instance of each class,
and does the following:
</p><ul class="itemizedlist"><li><p>
When you click on the <span class="guibutton">Record</span> button,
<code class="classname">CaptureWindow</code> connects its
<code class="classname">SoundConsumer</code> to the system's audio input and starts the node.
</p></li><li><p>
Similarly, when you click on the <span class="guibutton">Play</span> button,
<code class="classname">CaptureWindow</code> connects
its <code class="classname">SoundProducer</code> to one of the system's mixer inputs and starts the
node.
</p></li><li><p>
Finally, when you click on <span class="guibutton">Stop</span> (or when
one of the <code class="methodname">Process()</code> or <code class="methodname">Notify()</code>
hook functions has determined that the node is done recording or
playing), <code class="classname">CaptureWindow</code> figures out which node is running, stops the
node, and disconnects it.
</p></li></ul></div></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="id531085"></a>Consumer vs. Producer</h3></div></div></div><p>
Looking at the responsibilities of a <code class="classname">BBufferConsumer</code> and a
<code class="classname">BBufferProducer</code>, you'll notice that there are a lot of similarities. Here
some of the more important ones:
</p><ul class="itemizedlist"><li><p>
Both consumers and producers create a port, called the Control Port,
that the Media Server uses to send messages to them. Messages range
from performance event (Start, Stop, and Seek) requests, to receiving
buffers, to messages that you define and send yourself.
</p></li><li><p>
Both create a thread, lovingly referred to as the Big Bad Service
Thread, which is responsible for handling messages sent to the Control
Port in a timely manner. Among the other things that this thread might
do, its primary responsibility is to read from the Control Port until a
message is received, and then handle the message.
</p></li><li><p>
Both override <code class="classname">BMediaNode</code> functions that implement certain important
performance events. Start tells you when your node needs to start. Stop
tells you when your node needs to stop. Finally, Seek tells you when
you need to change your media time, and what the new media time should
be. (More on this in a bit.)
</p></li></ul><p>
At the same time, there are several significant differences that you
should be aware of. Here's a blow-by-blow:
</p><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id531146"></a>Performance Events and Media Time</h4></div></div></div><p>
Your node can interpret Start, Stop, and Seek events in various ways,
depending on what makes sense for your node.
</p><p>
For <code class="classname">SoundProducer</code>, Start and Stop are interpreted to mean "start
producing buffers" and "stop producing buffers." Our application does not
currently define the concept of media time for its sound producer, so
SoundProducer::Seek has no effect. In the future, media time would
probably be interpreted as the offset in the sound file you're playing.
</p><p>
On the other hand, <code class="classname">SoundConsumer</code> currently defines no behavior for Start
and Stop, and simply accepts buffers at any time. It also doesn't do
anything meaningful with Seek requests, but passes the media time as a
timestamp to its <code class="methodname">Process()</code> hook function, in case that time has any meaning
to <code class="classname">SoundConsumer</code>'s client.
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id531192"></a>Timing and SoundConsumer</h4></div></div></div><p>
As the BeOS media system generally runs in real time, timing issues are
perhaps the most critical part of developing a media node, and are often
the trickiest part to get right.
</p><p>
<code class="classname">SoundConsumer</code> has it easy, since all it needs to do is grab buffers as
they arrive and blast them to disk. It doesn't even care whether the
buffers were on time or not. So, all it needs to do is sit around in its
Big Bad Service Thread, waiting patiently for those buffers to arrive.
Once messages do arrive, it handles them immediately.
</p><p>
Because it doesn't really care about Start, Stop, or Seek requests,
<code class="classname">SoundConsumer</code> "handles" them instantaneously, instead of queuing them up
for handling at a particular time. More complicated consumers might need
to handle performance events accurately, and might need to determine
whether incoming buffers are running behind.
</p></div><div class="sect3"><div xmlns="" xmlns:d="http://docbook.org/ns/docbook" class="titlepage"><div><div xmlns:d="http://docbook.org/ns/docbook"><h4 xmlns="http://www.w3.org/1999/xhtml" class="title"><a id="id531232"></a>Timing and SoundProducer</h4></div></div></div><p>
<code class="classname">SoundProducer</code>, on the other hand, is a lot more complicated. Not only
does it need to handle performance events at their correct times, but it
also needs to produce a steady stream of buffers—and those buffers
have to be sent at precisely the right time, so that they don't reach the
final output (your headphones) too late, or so early that the latency of
the system is more than it needs to be. Its Big Bad Service Thread,
therefore, does three different things:
</p><ul class="itemizedlist"><li><p>
It checks to see if any pending performance events need to be
handled, and handles them when they do.
</p></li><li><p>
It checks to see if any messages have arrived at the Control Port,
and handles them when they do.
</p></li><li><p>
When it's time to produce a buffer, <code class="classname">SoundProducer</code> stuffs a buffer
(using the <code class="methodname">Process()</code> function) and sends it off.
</p></li></ul><p>
One of the keys to understanding the timing of <code class="classname">SoundProducer</code> is the
timeout value passed to <code class="function">read_port_etc()</code>. This value determines how long the
thread waits in each iteration of the loop for messages to arrive. This
timeout is set to the time until the next performance event needs to be
handled, or until the next buffer needs to be produced, whichever comes
first. So, this call to read_port_etc really serves the dual purpose of
receiving messages and snoozing until the next thing needs to happen!
</p><p>
The other key to understanding <code class="classname">SoundProducer</code> timing is the value returned
by <code class="methodname">BTimeSource::RealTimeFor()</code>. This somewhat misnamed function does not
give the absolute real time that corresponds to a given performance time,
but rather gives you the real time that you need to do things in order
for their effects to take place at the performance time. It does this by
taking into account the latency that you give it—that is to say, you
tell it the difference between the time at which you decide to do
something, and the time at which that something actually takes effect.
The greater your latency, the earlier you must start things for them to
happen on time. And, as I have been reminded on any number of occasions,
being on time is extremely important.
</p></div></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="id531317"></a>Parting Thoughts</h3></div></div></div><p>
There are several directions in which this app can grow. In particular,
you could extend either <code class="classname">SoundConsumer</code> or
<code class="classname">SoundProducer</code> to do all sorts of
wild stuff. You could override the consumer's hook functions to provide,
for example, an oscilloscope node, or a node that performs spectral
analysis. You could also override the producer's hook functions to
perform sound synthesis.
</p><p>
Go nuts!
</p></div></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-3"></a>Organic Pace of Change</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>
If I remember correctly, one difference between organic and mineral
chemistry is the introduction of time as a variable in the reaction. In
the mineral world, the ingredients meet and react; the result is a fixed
one, dependent only upon the initial conditions. Organic reactions, on
the other hand, introduce another variable—time. These reactions are
slower, and the result is a function of the time of measurement.
</p><p>
It's the organic model that comes to mind when I look at the pace of
acceptance of new standards. Some organic reactions actually never take
off; for example,
<acronym class="acronym" title="Integrated Services Digital Network">ISDN</acronym>,
a high-speed local loop in every pot. The
appearance of others might be a little misleading—here I'm thinking of
the Internet, which might cause problems with placing the time origin of
the reaction. What we observe is the fast middle branch of the S-curve.
We might forget the two decades of slow gestation of the first branch in
government and university research labs.
</p><p>
With a new standard, we often have the misleading intuition of a quick
reaction, only to find that the actual pace of adoption is more organic
than we'd like. USB appears to be one such example. On the "obvious"
side, it's got to happen—because it's good. Higher throughput; peace
with interrupts; self-identifying peripherals; hubs; smaller, nicer
connectors; cheaper; saves trouble; better ergonomics.
</p><p>
<acronym class="acronym" title="Universal Serial Bus">USB</acronym>
is promoted by Intel, supported by Microsoft, and has recently been
discovered by Apple. On the Intel promotion side, the effort started five
years ago, if memory serves; motherboards with <acronym class="acronym">USB</acronym> support appeared more
than two years ago. Software support lagged but became somewhat real
(we'll get to the "somewhat" in a moment) with Windows 95 OSR 2.1. OSR
stands for <acronym class="acronym">OEM</acronym> Service Release—midstream fixes and improvements
distributed to <acronym class="acronym">OEM</acronym>s. But peripherals manufacturers had been burned
before, and didn't jump to support USB either.
</p><p>
Now we have Windows 98 with <acronym class="acronym">USB</acronym> support
and motherboards with <acronym class="acronym">USB</acronym>
hardware, but very few <acronym class="acronym">USB</acronym> peripherals such as printers and modems. There
are exceptions, such as a Kodak digital camera, but more than two years
after the appearance of <acronym class="acronym">USB</acronym> connectors on the back of PCs, that's all we
have—exceptions. Or, take the surreal case of the new Macs. Much has
been made of the iMac's lack of floppies; to use them you have to buy a
<acronym class="acronym">USB</acronym> external Superdrive. It's nice, color coordinated (before the new
colors were offered), but a tad expensive at $149, plus almost $9 for a
120 MB floppy.
</p><p>
One can argue you get the best of both worlds—a drive that uses old
and new floppies (I think) and offers the capacity of a Zip drive. But
turn your attention to the new, colorful high-end G3 Macs. They don't
come with a Superdrive or a floppy, though some have a Zip drive. Here
the surreal part is the modem. The internal modem is only available on
configurations ordered from Apple, I'm told. You can't get a <acronym class="acronym">USB</acronym> modem,
the internal modem isn't available as a part, and there are no drivers
for "older" modems connected via a <acronym class="acronym">USB</acronym>-to-serial adapter.
</p><p>
When I asked a leading Mac retailer how they felt about this, I got what
the Car Guys call the mechanic's shrug. Hopefully, this will become an
anecdote as <acronym class="acronym">USB</acronym> peripherals and software become available. We, of course,
will do our part Real Soon. But now we wonder about FireWire—will it
take as much time as USB to become more than "somewhat real," or will
recent efforts by Apple to assert IP rights to the standard slow its
organic growth?
</p></div></div><div id="footer"><hr /><div id="footerT">Prev: <a href="Issue4-2.html">Issue 4-2, January 13, 1999</a>  Up: <a href="volume4.html">Volume 4: 1999</a>  Next: <a href="Issue4-4.html">Issue 4-4, January 27, 1999</a> </div><div id="footerB"><div id="footerBL"><a href="Issue4-2.html" title="Issue 4-2, January 13, 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-4.html" title="Issue 4-4, January 27, 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>