Table of Contents
BE EVENTS: BeOS Demo Tours - September 1999
Date: September 8, 1999, 2pm and 7pm City: Salt Lake City, UT Group: UBUG and Utah "Blue Chips" Computer Society Location: A 2:00 pm, a public demo will take place in the University of Utah Bookstore Conference Room. Then, at 7:00 pm, the Utah BeOS Users Group, in cooperation with the Utah "Blue Chips" Computer Society will host the demo tour at an open joint meeting in the University of Utah, Engineering & Mines Classroom Bldg., Room 104. More info: <http://www.driversoft.com/UBUG/meeting.html> Date: September 9, 1999, 7pm City: Atlanta, GA Group: Atlanta Linux Enthusiasts, A.BUG Location: Georgia Tech College of Computing, Room 17 More info: <http://www.ale.org/next.shtml> Date: September 11, 1999, 12:30-3:30pm City: Raleigh, NC Group: RTBUG, Piedmont BUG, Triangle Linux and Mac User Groups Location: EPA Auditorium in Research Triangle Park More info: <http://pixira.com/rtbe/> Date: September 14, 1999 City: Columbia, MD Group: Columbia Baltimore Users Group Location: APL Labs More info: <http://millkern.com/cbug/index.htm> Date: September 16, 1999, 7-9pm City: Rochester, NY Group: BUGGER Location: Rochester IT More info: <http://www.beos.org/bugger/> Date: September 18, 1999, 10:30am-12pm City: Bethesda, MD Group: Capital PC Users Group Location: Lipsett Auditorium in NIH 9000 Rockville Pike, Bldg, 10, Clinical Center More info: <http://cpcug.org> For more information about BUGs in your area, how to create a BUG, BUG events, and more please visit: <http://www-classic.be.com/usergroups/> BE ENGINEERING INSIGHTS: I. Making Your BLoopers More Responsive II. Gamma Correction By Jean-Baptiste Queru jbq@be.com
Some of my fellow engineers tell me that I'm lucky to have so many ideas for my newsletter articles. They couldn't be more wrong. Having to choose between two ideas is much harder (at least for me) than having to find one idea. After whittling a pile of ideas down to just two, I couldn't choose between them, so I'm using both for this article. You can find the source for them here: Part I: Responsive BLoopers Something that BeOS developers must keep in mind when programming their user interface is that users don't like interfaces to feel slow or sluggish. One key to interface responsiveness is to let the BLooper run freely and process messages. To achieve this goal, you must make sure that your program doesn't spend too much time sitting in the various virtual functions that the BLooper will call in its BHandlers. The sample code for this article shows two techniques that should cover a reasonable number of common cases. Use Asynchronous Controls In older versions of BeOS, the only way to track the mouse to dynamically change a control was to repeatedly call GetMouse() in a loop. The BeBook mistakenly suggested doing this in MouseMoved(), which would prevent the BLooper from processing message as long as the mouse button was held down, which could be a very long time. The correct way to do this was to poll in a separate thread, a tricky thing to set up and to tear down without deadlocking. Fortunately, R4 added an elegant way to solve the problem: the view event mask, which lets you create asynchronous controls. Since this has already been explained in other Newsletter articles, I won't say much about it, but you can look at the sample code to see one of those beasts in action. For more information, see:<http://www-classic.be.com/aboutbe/benewsletter/volume_II/Issue45.html> and <http://www-classic.be.com/aboutbe/benewsletter/volume_II/Issue46.html>. Use Other Threads to Do the Actual Work We're now reaching the heart of the problem. The naive way to implement real time user feedback with asynchronous controls is to redraw the display each time MouseMoved() is called. Change the #if in the sample code to see what happens in that case. This is not what a user wants to see, and it gets worse as the processing time gets longer. A temporary solution might be to eliminate some of the B MOUSE MOVED messages by hand in the BMessageQueue before they're dispatched; this only works if the processing stays reasonably short and if the BLooper is a BWindow. A more general solution is to have another thread do the work for the BLooper, so the BLooper can continue processing messages (e.g., update messages) as they come along. Since setting up and tearing down threads can be painful, and can easily create deadlocks and other race conditions, I've encapsulated all that work in two classes -- called SignalSender and SignalCatcher -- that I hope will be reasonably easy to use. Those classes are an example of how easy it is to create your own synchronization classes, and you might even find them useful in their current state. Part II: Gamma correction. The sample code is not only interesting because of the programming techniques it uses, but also because of what it does. This small program is actually intended to calibrate a gamma correction system and to use this system to draw anti-aliased lines. Gamma is a very simple process. The intensity of light created by a CRT is a nonlinear function of its input voltage. Gamma is a parameter that represents this nonlinearity, and gamma correction is the process of compensating for this nonlinearity. Surprisingly, this nonlinearity is the same for all CRTs: the intensity of light produced by the CRT is proportional to the input voltage raised to the power 2.5. You can thus repeat after me: "Gamma is 2.5." There are, however, many components between the framebuffer (or, more precisely, the DAC) and the CRT's input: various amplifiers, filters, brighness/contrast controls. Overall, those components scale and offset the signal between the DAC and the CRT. All the math is done in a GammaCorrect class, so you don't have to know exactly how it works if you don't want to. The patterns displayed by the program are these:
Right now, nothing is done by the OS, and everything has to be done by the applications. This will probably change in a future release, but this sample code shows how to use some gamma correction without any OS support. If you want to know more about how it really works, here's the beginning of an explanation. If we call "f" the value for a pixel in the framebuffer and "l" the lightness on the screen for this pixel, we can write that l is proportional to (f+e)^2.5. Since it's more convenient to use values between 0 and 1, we'll renormalize l in that range with to renormalization factors that we'll call a and b, so that l=a*l'+b (l' is the normalized version of l). We can finally write that f=((l'-b)/a)^0.4-e, where f will vary between 0 and 1 when l' varies between 0 and 1. The sample code will compute a, b, and e from another value m that I call the "mid-light" value; i.e., the gray level that is as light as a median blend of black and white. With ideal monitor settings, m should be approximately 3/4, so that we get a=1, b=0 and e=0. Part III: Conclusion I hope this article casts some light on a few useful programming tricks. Please send your feedback to jbq@be.com. BE ENGINEERING INSIGHTS: Common ioctls and Error codes for Drivers By Arve Hjønnevàg arve@be.com
If you look in the file be/drivers/Drivers.h in your system headers, you'll find a list of Be-defined opcodes for ioctls. A driver may choose to implement any of these, but all implemented ioctls need to behave as defined by us. Some ioctls are required for certain types of devices. Let's go through the opcodes defined for Release 4.5. B GET DRIVER FOR DEVICE, B GET PARTITION INFO, and B SET PARTITION are implemented in devfs. You should not implement any of these. B GET DEVICE SIZE and B SET DEVICE SIZE are obsolete calls that operate on 32-bit numbers. B SET NONBLOCKING IO and B SET BLOCKING IO, are used to change a file descriptor to blocking or nonblocking mode. Devices where a read or write operation depends on other events to complete should implement these. The driver also sets the mode on open according to the O NONBLOCK flag. B GET READ STATUS and B GET WRITE STATUS are used, in blocking IO mode, to determine if a following read or write will block. A pointer to a bool is passed as the argument, and the driver writes set the value to false if the operation will block, and true if not. B GET GEOMETRY is used to get information about a disk device. All drivers that publish their device under /dev/disk/ should implement this. The argument to this call is a pointer to the following structure:
typedef struct { uint32 bytes per sector; /* sector size in bytes */ uint32 sectors per track; /* # sectors per track */ uint32 cylinder count; /* # cylinders */ uint32 head count; /* # heads */ uchar device type; /* type */ bool removable; /* non-zero if removable */ bool read only; /* non-zero if read only */ bool write once; /* non-zero if write-once */ } device geometry; For block devices, bytes per sector should match the block size of the physical device. A file system mounted on your device will not try to read partial blocks. Most devices do not expose accurate information about the relation of cylinders, heads, and sectors, but the number of usable blocks in the device should match sectors per track*cylinder count*head count. When using this call to determine the size of a device, make sure to use 64-bit precision for the calculation. device geometry g; off t devsize; if(ioctl(devfd, B GET GEOMETRY, &g) >= 0) { devsize = (off t)g.bytes per sector * (off t)g.sectors per track * (off t)g.cylinder count * (off t)g.head count; } The device type field indicates the type of the device. The most common values here are B DISK for hard drives and B CD for CD-ROMs. If the media in the device is removable, the removable field should be true. Some devices support media of different size and block size. If there is no media in the drive, report a size and block size of 0. The read only field is set if the driver knows that the media is not writeable. Some devices may not be able to determine this, so make sure your application deals with write operations failing. write once should normally be set to false. B GET BIOS GEOMETRY, B GET BIOS DRIVE ID: On the x86 platform, hard drives can be accessed though the bios at boot time and from other operating systems. B GET BIOS GEOMETRY will fill in the same structure as B GET GEOMETRY, but sectors per track, cylinder count, and head count need to match the numbers used by the bios. This information is needed to create a partition table that the bios can use. B GET BIOS DRIVE ID will return the drive number the bios uses for this drive. This information is needed when adding a disk to the boot menu. B FORMAT DEVICE is used to format the media in the device. If your device needs to prepare the media before it can be read and written to, implement B FORMAT DEVICE. B GET ICON allows a device to have a custom icon. Currently, our disk drivers have the Be disk and CD-ROM icons built in, but we will provide a simple way to specify standard icons in the future. B EJECT DEVICE and B LOAD MEDIA are used to eject or load media. B GET MEDIA STATUS is used to determine the state of the media in the drive. This is described in detail in my article "Removable Media" <http://www-classic.be.com/aboutbe/benewsletter/volume II/Issue44.html#Insight>. B SET UNINTERRUPTABLE IO and B SET INTERRUPTABLE IO change how the driver responds to signals. By default a driver should return to user space as soon as possible when it receives SIGINT. A driver can use the B CAN INTERRUPT flag when acquiring semaphores and can abort its operation if B INTERRUPTED is returned. However, when using the file system cache, a read or write operation may carry data that doesn't belong to the current thread. The file system uses B SET UNINTERRUPTABLE IO to tell the driver not to abort any operations. B SET INTERRUPTABLE IO restores the default state. A disk driver that wants to abort IO operations on signals needs to implement these ioctls. B FLUSH DRIVE CACHE needs to be implemented by disk drivers if the device has a write cache. If the device has a write cache, either a software cache or hardware cache, a call to B FLUSH DRIVE CACHE should not return until all data in the cache has been written to the media. If an opcode is not supported by your driver, return B DEV INVALID IOCTL. This will cause the ioctl call to return -1 with errno set to B DEV INVALID IOCTL. For all opcodes above you should return B OK or B NO ERROR if the operation was successful. If the operation failed you need to return an error. In the file be/support/Errors.h under your system headers, you'll find error codes for a variety of error conditions. You should try to pick the error code that best describes why the operation failed. Let's look at the most common cases for drivers. If you don't know why an operation failed, return B ERROR. If an operation failed because you could not allocate memory, return B NO MEMORY. If an IO operation fails, return B IO ERROR, or if your device has additional information you can return more specific errors such as B DEV NO MEDIA, B DEV UNREADABLE, B DEV FORMAT ERROR, B DEV TIMEOUT, B DEV RECALIBRATE ERROR, B DEV SEEK ERROR, B DEV READ ERROR, B DEV WRITE ERROR, B DEV NOT READY, and B READ ONLY DEVICE. If someone tries to write to a read-only device or to write-protected media, return B READ ONLY DEVICE. For devices with removable media it's also important that B DEV NO MEDIA and B DEV MEDIA CHANGED are returned when appropriate. Once opened, read and write operations should fail with B DEV MEDIA CHANGED if the media changes. See the "Removable Media" article for more info on how this should be implemented: <http://www-classic.be.com/aboutbe/benewsletter/volume_II/Issue44.html#Insight>
DEVELOPERS' WORKSHOP: What's Going On in Documentation Land? By Ken McDonald ken@be.com
"Developers' Workshop" is a weekly feature that provides answers to developers' questions or topic requests. To submit a question or suggestion, visit: <http://www-classic.be.com/developers/suggestion_box.html>. A long time ago, in an office far, far away (or at least, on the other side of the building), I wrote a newsletter article about making and using menus in BeOS GUI applications. One of the goals of that article was to see how people responded to a more tutorial style of documentation--something that didn't necessarily go into every last, cotton-pickin' finicky little detail, but that did provide the basic information necessary to use a class or classes in your program, in a compact, easy -to-read form. We were rather surprised at the number of responses generated by that article, almost all of them positive. Well, it's been a while, and other things came up of course, but now we're back in the tutorial game. In fact, there will hopefully be quite a few more tutorial style documents coming down the pipe in the future. In light of this (and due to the fact that I didn't have the time or the imagination to do anything else), it seemed apropos to do a sequel to my previous newsletter tutorial. Think of this one as "Looking for Tutorial Feedback II: Nightmare on BView Street". The first writeup in this new tutorial series will be about the BView class, and the first part of this writeup is a short, very high-level introduction located here: <http://www-classic.be.com/aboutbe/benewsletter/volume_III/resources/article.htm l> I hope the technical content is useful, but the main purpose of presenting this here is to elicit comments from you, the reader. We expect to put quite a bit of effort into this series (hopefully resulting in a complete tutorial for programming the BeOS), and given this, it makes sense to develop a format which will make the information as useful as possible. For example, one of the things I've done in the tutorial is to include a sidebar on the left, giving easy access to the section and subsection headings within the document. Is this a good idea? Can you suggest other features which might be better, or complementary? As the series progresses, I will be locked in to a certain format and approach, in order to maintain consistency--but right now, the sky is the limit. (Well, subject to resource constraints, of course :-) ) So suggest away! And, of course, please make comments on the writing style and content also. If nothing else, please tell me:
You can email directly to me, ken@be.com. (Nope, you don't get my home phone number :-) ). If you could begin the subject line of any feedback with the words "TUTORIAL COMMENTS", it would let me use the cool indexing features of the Be file system to keep responses nicely sorted.
BIT BY BIT: Introducing Rephrase By Stephen Beaulieu hippo@be.com
Our application-building exercise begins with Rephrase, a BTextView based text-processing application. Over the next few months, I'll add features in each installment, and explain the BeOS coding philosophy behind them. You'll find the first version of Rephrase at <ftp://ftp.be.com/pub/samples/tutorials/rephrase/rephrase0.1d1.zip>
Rephrase 0.1d1 This limited version of Rephrase is essentially an application wrapped around a standard BTextView. It has a BApplication and a BWindow for the text view to live in. There is an About window, with a basic set of menu items in the main window to bring up the about window, quit the application, and edit the text. The application's real functionality (limited as it is) comes from the BTextView. It lets you cut, copy, paste, and select the text. It even provides limited file i/o through inherent drag and drop capabilites: select text and drag it to the Tracker to save a text clipping, or drag a file to the view to paste in its contents. Although it has only 164 lines of code (many of them blank or comments), the application is surprisingly functional. With the addition of resizing, scrollbars and real open and save capabilities, Rephrase could even be useful. Programming Concepts BeOS uses a system of messaging to manage most aspects of communication and event handling. BLoopers run an event loop in a thread that receives incoming messages and dispatches them to associated BHandlers to be acted on. BApplication provides a connection to the Application Server, which enables the messaging system for the app. It also serves as the main looper for interapplication communication and application global services, such as displaying an About window. A global pointer to the BApplication object (be app), is available throughout the application. BWindows and BViews are the specialized loopers and handlers for managing the graphical user interface. When visible, a BWindow represents an area on screen. A BWindow maintains a hierarchy of BViews that draw in and handle messages for sections of that area. User interaction generates messages that are delivered to the window, which passes them to the BViews to handle as appropriate. For example, when you select a menu item in Rephrase, a message is sent to the BMenuItem's target. The menu item's window is the default target. However, the menu item can be told to send its message elsewhere. For instance, when "About Rephrase" is selected from the File menu, a message is sent to the BApplication. All the menu items in the Edit menu send their messages to the BTextView. Implementation Details
Next week: Opening a file.
1997 Be Newsletters | 1995 & 1996 Be Newsletters Copyright © 1999 by Be, Inc. All rights reserved. Legal information (includes icon usage info). Comments, questions, or confessions about our site? Please write the Webmaster. |