Replicants - More application than an application
Yep. I remember when Be first announced Replicants. They were going to be the next ActiveX. I wonder what ever happened to them.
The sad truth is that absolutely nothing happened to Replicants. Almost no one ever used them. No great mountains of applications ever came out for them. I was chatting with some people the other day on IRC and we wondered about this. Needing to write an article and not sure what to write, that commiseration came back to mind.
I started looking around for "official" documentation on Replicants, not wanting to recreate the wheel. I found very little. There were a few newsletters that mentioned Replicants, and the documentation in the BeBook about BeDragger and BShelf, plus the sample code. I was very surprised not to see more. With some more digging, I managed to find the introduction that Peter Potrebic gave at BeDevCon '97. I believe that I was at that session. I recommend reading it here.
The question that I set out to discover the answer to: What is a replicant, and how do I play with one? A replicant, quite simply, is a BView. The "trick" to a replicant is that the BView has an Archive() function (something that any BView can have but people rarely seem to bother) and a link to a BDragger — a handle to move the BView around with. When you grab the handle, it tells the BView to archive itself. The app_server then treats that archive just like a drag and drop (as if it were text or a bitmap). The other side of the coin is the BShelf, which is a special BView that knows how to receive BView drag and drop messages. It loads the application or add-on that created the BView, searches for the archived class's Instantiate() function and calls it. Voila — the code from one application is now running in another.
How did I play with it? Some time ago, I had started something called kitView. It was to become what BeHappy did become, down to using NetPositive as a replicant. I dug the code out, removed the list views and rebuilt. Sure enough, the code still worked! OK, so that covers the "receiving", or BShelf side of the replicant. Time to write a "sending" side of the replicant.
I had never done this before and there were many pitfalls on the way, including crashing the app_server multiple times. You have been warned. :-D I created a simple application called "grapher". Its whole purpose in life is to draw a simple bar graph with hard coded values. I actually copied kitView and modified it.
Step 1: Adding the BDragger class. BDragger is the little handle that you can move the BView around with. The handle can be a child of the BView, the parent of the BView, or a sibling. You could put the handle on the other side of the window (sibling).
Step 2: Make the BView archivable. If you hadn't subclassed your BView already, well, now you have to. Create an Archive() method (look at BHandler's BeBook section). Any member values of your BView that are necessary, you need to save into the BMessage. The "Clock" sample code has a good, easy example of this. You also need to call AddString() to add the "add_on" field, populating it with your app's signature. Make sure that you set the app's signature using FileType or resources. Otherwise your replicant will not work and you will not know why.
Step 3: Create a constructor for instantiating your BView from a BMessage. This is the constructor that takes only a BMessage as a parameter — documentation is in the BView section of the BeBook. Any data that you saved into the BMessage in Step 2 you need to read from the BMessage here and populate the member variables. Note that static variables do not work across application boundries. So if you intend to share data across different instances of views in your application using statics, they will not work properly with Replicants.
Step 4: Create a static method called Instantiate(). This static method should call new to create a new instance of your BView, passing it a BMessage.
Finally, I wondered if you could print a replicant. I added a print button to kitView and added some simple code to create a new print job containing the BShelf. It works!
There are many areas of exploring that I did not do with this sample code. I did not install a pop-up menu, for example. I did not test to see if I could do things like create windows as a replicant. I did not attempt to make my replicant resizable — it would be a very neat thing to resize your replicants inside the shelf.
After playing with Replicants, I believe that they are easier to use than I had ever thought. Having written my first one, I would bet that I could write another in an hour or so (outside of BView functionality). There is a lot of power inside Replicants. Be's demos, I think, set the wrong tone for Replicants — as toys that are not really useful. I would like to consider another direction for them: as an OpenDoc or ActiveX replacement. You can create Replicants with a message-based API — no fragile base class, no headers, no C++ dependence, etc. — something very powerful to think about.