RSS Feed
Download our iPhone app
Browse DevX
Sign up for e-mail newsletters from DevX


Tweak Brew's Component Interfaces to Tackle Any Task

Brew's impressive collection of component interfaces usually makes your life easier, but there just isn't an interface for everything. What happens when an interface is almost perfect for your task...but not quite? Find out how to extend an interface to use its existing functionality while adding something completely different.

ualcomm Brew's component-oriented architecture and rich collection of components—interfaces, in Brew parlance—makes it easy to find a component to accomplish a particular task, such as decompressing an incoming stream (try IUnzipAStream) or rendering text (an IFont instance). Sometimes, however, you know the job that needs to be done, but there's just no component that fits—even though there's a likely-looking interface that would do the job. This begs the question: why re-invent the wheel if you don't have to? It's bad enough writing the code, but if you can get away with using an existing Brew interface to encapsulate your functionality, at least you don’t have to write much of the corresponding documentation.

This article will show you how to do just that: start with an existing interface (the IFile interface, in this case) and write an extension that implements that interface while doing something totally different: emulating a simple standard input/output control to facilitate debugging when porting code to Brew.

Introducing the IOManager

Figure 1. IOManager: Here's the IOManager in action.

The IOManager is a subclass of the IFile interface that permits users to interact with an application using a scrolling text window and input line—much like a simple dumb terminal. Utterly useless for the average commercial application, IOManager is handy if you're putting together a little test application to prove something, such as when you need to unit test code you've ported to Brew or isolate a piece of code to determine the cause of a bug. Figure 1 shows the IOManager in action.

Click here to download the source code accompanying this article.

While the IOManager could have been written as either a completely custom interface or a subclass of the IControl interface, in this article, it's a subclass of the IFile interface for a couple of reasons. First, its functionality closely resembles that of the old C-style stdin and stdout ports, accessible via file operations in traditional C. This correspondence seemed to carry over nicely in the implementation, and with a little work, ported code can access the IOManager's capabilities the same way as other files during testing. Second, for demonstration purposes, the IFile interface is a little more complex (for example, the Readable/Read paradigm requiring asynchronous callbacks), making the IFile interface a better example when showing you how to go about implementing to a Brew interface.

Internally, the IOManager consists of two separate controls, an ITextCtl to manage user input, and an IHTMLViewer, used to show information written to the IOManager or entered in the ITextCtl. Information passed to the IOManager via its Write method inherited from IFile is displayed in the IHTMLViewer, and anything entered in the text control and confirmed using the SELECT key is available to the client application through the IOManager's Read method. Structurally, the data for the IOManager implementation looks like this:

struct SIOManager
  //VTBL pointer always comes first.
  IOManagerClsVtbl *pvt;

  IShell *m_pIShell;
  IModule *m_pIModule;
  uint16  m_nRefs;

  AEECallback  m_cbReadable;
  boolean m_bInvokeReadable;
  AEECallback m_cbWritable;
  AEERect  m_rc;
  AEERect  m_rcHtml;

  char m_szInput[ BUFFSIZE ], m_szOutput[ BUFFSIZE ], 
       m_szHTML[ BRSIZE * BUFFSIZE ];
  ITextCtl *m_pITextCtl;
  IHtmlViewer *m_pIHtml;
  IDisplay *m_pIDisplay;
Most of these fields will be explained in subsequent sections of this article. For now, you should know that:
  • The implementation's virtual table must be first, because Brew uses C casts to convert between an extension's interface (its virtual table) and the private data used by the interface (more on this in the next section).
  • The extension uses three buffers: a buffer to contain what the program has written to the extension to display, a buffer to contain what you've entered via the text control, and a buffer containing the combined contents of the two formatted as HTML for display to the user using the HTML viewer control (these are the character strings m_szInput, m_szOutput, and m_szHTML, respectively).
  • The m_pITextCtl text control provides all user input handling, and the m_pIHtml HTML viewer control handles displaying both programmatically written and user-entered data (the contents of m_szHTML).

Close Icon
Thanks for your registration, follow us on our social networks to keep up-to-date