673 lines
51 KiB
HTML
673 lines
51 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-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>-><code class="methodname">GetMouse</code>(&<code class="varname">point</code>, &<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>-><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>-><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>-><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>,
|
||
&<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>-><code class="methodname">Launch</code>(<code class="varname">preferredApp</code>.<code class="methodname">String</code>(), &<code class="varname">launchMessage</code>);
|
||
else
|
||
<code class="varname">be_roster</code>-><code class="methodname">Launch</code>(<code class="varname">type</code>.<code class="methodname">String</code>(), &<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>-><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>-><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>-><code class="methodname">AddItem</code>(<code class="varname">item</code>);
|
||
<code class="varname">menu</code>-><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>(&<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>, &<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>-><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>-><code class="methodname">FindApp</code>(<code class="varname">signature</code>, &<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>-><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>-><code class="methodname">SetMarked</code>(<code class="constant">true</code>);
|
||
|
||
}
|
||
|
||
if (!<code class="varname">menu</code>-><code class="methodname">FindMarked</code>())
|
||
<span class="comment">// mark "Default"</span>
|
||
<code class="varname">menu</code>-><code class="methodname">ItemAt</code>(0)-><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>-><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>-><code class="methodname">Message</code>())
|
||
<span class="comment">// picked "Default"</span>
|
||
<code class="varname">preferredApp</code> = "";
|
||
else if (<code class="varname">item</code>-><code class="methodname">Message</code>()-><code class="methodname">FindString</code>("signature",
|
||
&<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>
|