PETER POTREBIC: My name is Peter Potrebic, and I'm one of the engineers at Be, and I'm going to be talking about our messaging and scripting APIs and the functionality that we have for you. A lot of this stuff is new in the AA or PR release.
There are a couple of really central processes of the Be API. One of those is messaging, it's used in many parts of our system, and I'll talk about some of those. I didn't turn on the microphone. I'll talk about some of those during the talk.
Multithreading is also one of the central components of the Be architecture or the Be API, and if you combine those two pieces, you get a sense of what it is to be a BApplication. A BApplication is going to be multithreaded, and it's going to use messaging, both within itself and to communicate with other paths of the BeOS.
There are lots of different kinds of messaging in the BeOS. There is a kernel port mechanism. We have pipes. And if some of you were at the previous talk before lunch here by Rico, he talked a lot about pipes.
The kernel also has this concept of a thread message where you can send a message, you can send a hunk of data to a particular thread, and we also have this concept of BMessage, and that's a C++ class and that's a messaging abstraction that's built on top of ports. And that's mainly what I'm going to be focusing on in this talk, the BMessage class and how you use it and how it is integrated in with the Be API.
BMessages are used for lots of different things in our system. We try to leverage what we do in as many parts of the system as we can. It makes our system smaller, it makes it more robust because we have less to debug, and it makes it hopefully easier for you developers to program the Be API because you are reusing the same concepts over and over again.
So if you are dealing with our event handling system, it uses BMessages. If you are going to be doing some inter- or intra-application communication, that also uses BMessages. BMessage can be used as just a data container. In fact, the original API for BMessage was derived from our old database, API as a data container, it's used in the clipboard, it's used by scripting. Our archiving model, which I'll talk about in a later session, uses BMessage, and it's also used by our new replicators, replicant technology. So BMessages are used in many parts of the system.
If people have any questions that seem really appropriate at the time, you can ask them, and then there will be plenty of time at end for Q&A as well.
So the BMessage class, it's a data container, as I briefly mentioned, and each piece of data inside a BMessage has a name. So you can think of a BMessage class as a collection of name and value pairs, and each of these names has an associated type. It can be an integer, it can be a string. You can create your own types to identify the kind of data that lives in this entry.
And each of these entries can contain one or more values, and here is some sample code showing you how you would add data to a message. So this message variable here is a BMessage object, and there are various member functions in that class for adding data.
The first two lines are adding an integer into the name Sum, and you are giving it two different values. So here you would have one of these named entries, but it contains two values, and then there is an API for retrieving the values, which is very similar. Instead of add int 32, it's find int 32. And you can specify, if you want, the first value, second value, third value, similar to an array.
The third line here is adding the string, so it's showing you adding a different type of data to the same BMessage, and you have a different name called Comment. And the fourth line here is actually an error. The fourth line tries to add an integer into the name Comment. Well, you've already added a string under the name Comment, and under one particular named entry you can only have one type of data. So that last line will return an error.
And new with the PR release is we've made the API to this extensible where you can add your own type of -- you can add your own data types to BMessage using this new class called BFlattenable, basically a little protocol for taking an object and turning it into just a stream of raw bytes. You can use that to add and retrieve data from a BMessage object.
So now you have seen a little bit about BMessages. Now I'm going to talk about some of the places they're used in our system. And they're used in our main event processing system. A BApplication is basically an event loop, and actually it's a group of -- a set of event loops. We have a class called BLooper which is an abstraction of a thread running an event loop. And I'll show you some sample code shortly describing that in more detail.
As I said, each of these loopers runs in a separate thread, receiving events and processing them. And our BApplication and BWindow objects are examples of loopers. So when you create a BApplication, you get one of these loopers. Every time you create one of a new window, you get another one of these loopers, and this window runs in the context of this new thread.
Another important class is the BHandler class, and whereas the looper is the processing loop, it receives the messages and then dispatches them, handler is what handles the message. So looper gets a message and then dispatches it to a handler. So the handler objects are the ones that actually do the responding to system events like KeyDown. There is a generic virtual function in handler called MessageReceived, and that handles all of the nonsystem messages.
And loopers themselves are handlers. So, if you remember up above, windows are handlers. So windows can actually handle messages as well as receive messages. And here is a little class diagram showing the class hierarchy. Remember looper is an abstraction of a thread running an event loop, receiving messages and then dispatching them. A BApplication object and a BWindow object are both examples of loopers, and up at the top, there is a BHandler, and this is the class that actually handles an object. It gets a message and it does something with it.
And the loopers themselves are handlers, which means so are applications and windows, and then a BView is also a handler. A BView doesn't run in its own thread. It runs under the window thread to which it belongs, but it can handle messages like KeyDown events and MouseDown events.
I'll show you some sample code now that describes what I was just talking about. So this first code snippet is showing you what that event loop looks like inside of a BLooper. This is private code. This isn't code that you write. This is code that lives in the kits. I just wanted to show it to you so that you could get a better understanding of what's going on.
So this is the BLooper class, and this is its main event loop, which is, of course, just this big wild loop. And all it does is it waits for a message to come in, and the messages are actually delivered through the ports, which I mentioned at the beginning of the talk, this low level kernel mechanism for sending around data. So it just waits on this port, and it gets a message. When it gets a message, it tries to determine the target, the handler that's supposed to handle this message.
And then once it determines a target, it determines, is it a system event, and system events are the events that we've defined, like MouseDown, KeyDown, WindowMoved, FrameResized; those are system events. If it's not a system event, we go down here to this else clause, and we just take the target, which is a handler, and we call the generic virtual function MessageReceived, and we pass in that message. So at this point, when this call is made, your code would then get called, and I'll show you that in a moment.
If it is a system event, then we go to the switch statement, and we have all the various types of system events. If it's a MouseDown event, then we'll call a BView virtual function MouseDown. If it's a KeyDown event, we'll call KeyDown and so forth. So that's basically what's happening inside of a BLooper when it is running its event loop.
Now I'll show you what your code will look like. If you were handling system messages, suppose you had some views, some custom view called TMyView, and you were interested in MouseDown events, you would override the virtual function MouseDown, and it takes a point as an argument, and this is called for you whenever a MouseDown occurs inside of your view. And you would write the code in there to handle the MouseDown, whatever you were trying to do.
Now, there is more data inside of that event, inside of that message, than just the location of where the mouse click occurred. There is information like when it occurred. I can't remember what else is in a MouseDown. I think the state of the mouse buttons when the event occurred, if you had a multibutton mouse.
So that BMessage is available to you through the window that that view belongs to. So you can get that by calling this function, CurrentMessage.
And then here is where -- here I've just called the inherited version of MouseDown.
Here's another example if you were interested in KeyDown events. There is a different set of parameters for each of the different system events, and typically what you would do inside a KeyDown is maybe DrawString if you were implementing some type of text view.
And then for generic events, for events that you've defined, for nonsystem events, there is a virtual function called MessageReceived. So here is, again, the custom view, TMyView. You have overwritten MessageReceived, you just get a BMessage parameter. BMessage is passed to you, and you do your own case statement typically, where you handle the different -- you either have your own switch statement and you do the work in line or you call some other function.
And this is kind of important here, the default case. For many things in our -- several things in our system rely on Inherited getting called at the right time. For instance, the keyboard navigation facilities in the view architecture relies on Inherited getting called at the right time, so it's often best to call Inherited unless you know exactly why you don't want to call Inherited. So, if you're not sure, you should call Inherited, but if you though that, ah, calling Inherited is going to make this happen to the button, and I don't want that, then don't call Inherited. That's the strategy I take.
So now we've seen how you would handle messages, what happens when you get messages, and previously we saw how you put data inside of a message. Well, now, how do you get the message to a window or to some other object in your application? There are two cases. There is sending a message within an application and sending messages between applications, so there is both inter and intra.
And there are two mechanisms in the Be API for sending messages. One is there is a method in the BLooper class called PostMessage, where you give it a message and that message will get delivered to that looper. And there is another class, which I haven't mentioned before, called the BMessenger, and that's a -- I'll go into more details on the BMessenger momentarily. That's really a token for a looper, and that can be used to communicate across applications.
So when you're dealing within an application, you can actually use either of those two APIs, you can use PostMessage or you can use the BMessenger class, and in the next talk after this, on multithreading, I go into more details about the distinction between when you might want to use one or the other.
If you're sending between applications, interapplication communication, you have to use a BMessenger. If you think about it, the PostMessage case is a member function call on some object, so you need a pointer to that object. Well, you can't have a pointer across address spaces. So that's why this BMessenger class is created, because it's really a token for an object, and that token is constructed in such a way that it's valid across your entire machine, it's valid across address spaces.
Before I go into this, let me go back to the demo code, sample code, and I'll show you how you then use that API to send a message. So here is one function where you are given a looper and you are given a handler, and you want to send that handler a message, so you construct the BMessage. You would have some code in here that does things like we saw before, add int 32, add string, whatever data it is that you want to give to put inside that message, and then you call the PostMessage function on the BLooper, passing it the message and passing it to a particular handler inside of that looper that you wanted the message to go to. So that's the one case.
Then the other case is when you have one of these BMessenger objects, which again is just a token. So you're not dealing with pointers here, you're just dealing with this little teeny object. It's like 20 bytes in size or something. So you just typically pass them around by value. And, again, you just -- this part is the same, you construct the message, you add whatever data you want in here, and now you call this function on the messenger called SendMessage, and you pass it the message.
Now, in this case, you don't know. This could be -- the target of that message could be within your application or it could be some other application; you have no idea of knowing. And that's kind of powerful, because you can use this in our API to have a button in your window that you click that ends up sending up a message to some other application; it doesn't have to send one to your own application as well. So it's a powerful feature.
So we'll talk a little bit more about messengers. There are two basic ways of constructing a BMessenger object. The first is, you give it the handler and the looper that you want to be the target. So once you construct the messenger, when you call SendMessage, that's -- that looper handler, that's where the message is going to be delivered.
And the second constructor takes a signature, and this is a MIME string, new in DR9. We switched to using MIME strings for the typing and creator information in our system for the file typing. And we have also used it in several other parts of our system, and here is one of them, where you pass the signature of the application that you want to talk to.
And it's this second constructor that's kind of the key or the keystone to the scripting architecture, which I'm going to talk about shortly, where it gives you that initial link to talk to some other application. So if you want to send a message to another application, you just put in its MIME signature, and voila, you have a messenger, and you can call SendMessage and start sending it messages.
And once you have that initialing to another application, you can use our scripting architecture to get messengers to other objects in that application, and I'm going to demonstrate that in a little while. And this allows you to directly communicate to a particular window within an application, as opposed to first going to the application and then to the window.
So now I'm going to go into the scripting, and our scripting architecture uses everything you just learned. There is very little that was really added to our existing model, and again we were trying to leverage everything that we had previously done to make it as simple as possible, as easy to learn as possible. It also gives us less code to debug.
In our scripting architecture, any application can start sending messages to other applications. You don't have to have a scripting environment, you don't have to link against new libraries, you don't have to rearchitect anything. It's just all very similar to sending messages that you are already doing by putting a button inside of a window and having it do something.
And a lot of the parts of our system had built in scriptability so that you could do things like get particular -- get a reference to a particular window in some application or check a check box in a particular window, things like that. That functionality is already built into our kits. So any application out of the box is going to be scriptable at some level.
A little bit of the lingo we did define in our scripting environment, the scriptable objects have what we call properties. For example, applications have windows, and many applications have a concept of a document. So you could say a document is a property of an application. Windows have views. So views are properties of windows. Views themselves can have subviews, so a view itself has properties called views. And controls typically have a label and some value associated with them. It could be a Boolean value or a numeric value, so a value is a property of a control.
Different properties are addressable by what we call forms. Some of the lingo is quite similar to AppleScript. We tried to not invent new terminology when we didn't need to.
The forms can be by name or by index or by range. For instance, a text view would have text in it, of course, so a property of a text view might be text, and you could address the text by range. You could say I want characters 5 through 10, so you're asking for a range of text.
Each property has a different set of forms that it understands. For instance, range might not make sense when you're talking about windows in an application. An application might not support the notion of Windows 5 through 10; it might only say, I only support by index, so you can ask for the fifth window or a sixth window, but you can't ask for a range of windows.
Finally we have a concept called specifiers, and a specifier is what you use to direct a BMessage to its final destination. In the first line is an example of a statement. I'm interested in the frame of view George of Window 2. And that statement has three specifiers. First you are interested in Window 2, and within that window, you are interested in frame George, that's another specifier, and within that view you are interested in frame, that's the third specifier. And I'll show you how you would build this expression using our APIs.
So here's how you build that same exact expression. You would have a BMessenger, and remember that second constructor takes a MIME string signature, so I'm interested in an application whose signature is application/testapp. It really should be X/testapp. And I'm constructing a message, because I want to send it a message, and I'm interested in setting some property of that application.
I'm adding here are three calls to add specifier, which correspond to the specifiers we saw in that statement, frame, view George and Window 2. Then to the message, I also add the data, because I'm doing a set, so I want a set, and I'm setting the frame, which takes a rectangle, so I specify the rectangle that I want to set the frame to, and then I just send the message to that application. And these three specifiers will direct that message to the right location in the application.
Here's a graphical view of that same message where I have the big -- the main message here, which is the set command, and here is the data, and then here are the three specifiers, and those specifiers are kind of plucked off by the system as the message finds its way to the final destination. And that maintenance is done by the system. You just have to, you know, plug in that you know about keywords like window, although window is already handled for you. Our application knows about windows.
So now I'm going to do a little demo of the scripting capabilities. So here we're running the network preferences app, and I have this little command interpreter that I wrote that parses a command line, turns it into one of these messages, and sends it off to the target application.
So what I'm going to do is I'm just going to play around with the network panel. And the guy who wrote this, the network preferences app, he didn't know anything about scripting. This was written long before we did the scripting architecture. So there was nothing special done to this application. And I just -- I'm going to cut and paste to avoid typing on this stuff.
So the little command interpreter is called doo, and the first argument is network, which I'm specifying the application I want to talk to, and then the command get title of window zero, so when I execute this command, I get that network. So this message was sent to the network preferences app asking for the title of window zero.
Here's another command where I'm going to set the title of window zero, and if you watch the network panel, the top over here, you will see the title change.
So now I'm going to move things around a little bit to focus on one part of the window. The screen isn't big enough to fit everything nicely. I'm going to work in this part, the network services part of the network panel. And I'm going to have -- my script is going to ask for the value of the ftp enable check box, and you can see the check box is off, so I get back zero. And of course I can select that, and now I'm going to set the value of that check box, so you can see that the check box was selected. And at the same time, the save and revert buttons, I believe, unless they were already selected, they automatically became enabled. And I can do things like select this. Now I'm going to set the text of the user name field to Jean-Louis.
So all of these things you can do right out of the box with any BApplication, and of course it is all extensible by the developer. You can define your own set of properties that your objects understand, what forms that they understand, and plug into this architecture and have messages get routed directly to you.
One of the things, and I forgot this last time too, all of these messages have always been first going to the application, which is a thread, then they get directed in this case always to window zero, which is a separate thread, and then they find their way down to the correct view.
Well, in a single-threaded machine, that doesn't really matter, because only one thing can happen at the same time. But in a multithreaded machine, you're kind of wasting the application's time. I mean, all these messages have always gone to the application, it's gone to the window and gone to the view, which is kind of a waste of processing time.
So what you can do is, you can bypass this. All of our objects understand a property called messenger, and that corresponds to a BMessenger object. So if I ask window zero for its messenger, it's going to create a messenger object to itself and send that back to me, and then I'll get this token in my address space. If I save that token, and I reuse it, now I just talk directly to the window, and I avoid going through this bottleneck in the BApplication.
Unlike some other platforms where I think all of the scripting goes through one system-wide bottleneck, what you have seen here is all the messages going to a bottleneck just on a per application basis. We don't even have -- we can eliminate that by directly getting messengers to whatever object it is that you are talking about. So if I hit return here, of course my little command line thing can't show you the messenger, so we'll just print out, I got a messenger. So if you're in a real environment, you could save that token in some variable and then reuse it.
I can get a messenger to a view, to that text view within the window as well. So you can get messengers to any object that handles messages in our system. So that does a good bit for the performance of the scripting architecture.
I'm going to briefly talk about replicants now. It's a new technology that was created in DR9 for sharing objects between applications. It's kind of like a light-weight component model.
I took the BeOS support for archiving of objects, where you can take, say, a window and archive it, take that representation and write it to disk, later on read it off the disk and rehydrate it, and you get back a window with all of its views instantiated, and everything is back to where you were to start with.
So you took that archivability as well as the support we have for DLL's, put that together with a little bit of hocus-pocus, and came up with replicants, and I'll give you a little demo of that, and two talks from now I'll be talking about replicants in more detail.
So let me -- I guess I'll switch over here. We took a couple of the apps like our clock app, and there is in our BMenu, there is a menu item called ShowReplicants. Have people here seen replicants before? So I can do ShowReplicants, and anything in the system that's a replicant will get this little handle, and I can take this little handle and drag it onto a container view, and we made our desktop a container view.
So now I have this clock living on the desktop, and I can move it around. I can change its face, and you can see that the clock application is no longer running. And if I were to restart the machine, the tracker would come up again with the clock living on the desktop. Our Pulse application is also a -- we took the two buttons and made them replicants. I can drag them off the screen. If I turn off the CPU, it turns off in the Pulse application as well. If I turn it on, it turns on on the desktop as well. And there is a little API for using this secondary mouse button. You can delete these replicants.
I guess the most interesting application we have is with NetPositive, where I can take NetPositive, and we actually made that a replicant. So I can drag out this view, put it on my desktop, and close NetPositive, and it disappears from the desk bar. And now I have this web page on my desktop, and I can go to the Be home page and download it over the Internet. I can go to my little stock quotes page, set up a little window, and have it live on my desktop and just always be in touch with my current portfolio.
And all of this is quite simple in the BeOS, and as I said, in a couple of talks I'll be showing actual code and how you build both replicants and container views that can hold replicants.
We've really only scratched the surface of what you can do with BMessages. Remember on an early slide it listed clipboard, just using it as a data container. I didn't really talk too much about archiving. There is replicant stuff which we touched on. There is lots of things you can do with BMessages.
The clipboard uses BMessages, and one of the new things we did in DR9 is we added support for multiple clipboards, so you can name -- you can create a clipboard and name it, and another application can create a clipboard, give it the same name, and now you have this conduit for exchanging data between two applications.
So there is a lot of stuff here, but it's all based on the same class or set of classes, BMessage, BMessenger and things like that. So you don't have to learn everything at once. You can just get the basics, and then say, "Okay, today I'm going to learn about clipboards and how I can use those," or "Today I'm going to make part of my application a replicant so I can have a button on the desktop that checks my mail for me," or something like that. And all this stuff is documented and in the BeBook, and some of this stuff we're just getting up on the web site now, because it was all pretty brand-new.
And I think that's my last slide. Yes, it is, so I'm done. Are there any questions?
FROM THE AUDIENCE: Any privileges associated with message?
POTREBIC: The question was if there was any privileges. You mean like in a multiuser sense for protection and things like that?
FROM THE AUDIENCE: If I have an application, I can go ahead and send a message that will change some value somewhere.
POTREBIC: The question was, is there any protection in terms of can any application send a message to another application? We're still working on the protection schemes. We're still a single- user machine, which means both in the sense of a file system, every file is owned by the same user. And another part of being multiuser is who owns processes, and right now every process is owned by the same user. There is just one.
So that's how the protection scheme is going to work in our system. If there is a set of processes owned by another user, then that's where the protection is going to come in. We don't want to invent different protection schemes for all the different API. You want one protection scheme that kind of covers all the bases. So we are thinking about that. Currently we're just a single-user machine, so you can't send any message to any application.
FROM THE AUDIENCE: Just probably kind of a dumb question, but when we started playing with this the lab, we replicated a large clock, and now we don't know how to make them go away.
POTREBIC: The question is how do you get rid of these clocks. We had one guy who worked like this for weeks. He put just tons of these things, and luckily I didn't even implement duplicate. It would be easier to get them. There is no -- we need some API or UI for doing that in a container, and it's simple enough for the person who created the container to do this. In this case, this container lives inside the tracker. The desktop is owned by the tracker, and the tracker decided, I'll make my desktop a container view. What the tracker failed to do is put a little menu item that says delete them or gives you a list and you can delete which ones you want.
So what you have to do right now is there is a settings file inside of your settings folder that the tracker owns, and I think it is called something like Tracker Shelf Data, and you throw that file away, and that will get rid of all of your replicants.
FROM THE AUDIENCE: Is there any way we can get our hands on that doo command?
POTREBIC: The question was, the doo command I wrote. Sure, I've mailed it to one developer already because he had some questions. It's really a cheesy little -- it's just like name, a hundred line of codes to parse a few things and build these messages and send them, but we can put it on the web site and on the FTP site for downloading.
Our vision is that any script environment or language could be built on top of this. So you could have -- you could use PERL or Frontier, or whatever it is you wanted could generate these messages, just like the code we saw to generate frame of view George of Window 2, and off you would go.
FROM THE AUDIENCE: Two questions: What happens if you send off a replicant to a machine that's missing whatever shared library it's using?
POTREBIC: The first question, and I'll get to the second one, was what happens if you send a replicant to a machine that doesn't have the shared library that it needed.
Well, I'll go into a little more detail on how that all works in the replicant session. Right now, the replicant won't work. But we're thinking about, you know, how to make things smart so the right things go, or a better user interface so the user knows what it is he's missing.
We also have been thinking about using MIME again. I might have -- like this is a replicant that's a clock and it's showing me the time. Well, I might like this clock on this machine, but on your machine you might like a different style clock. All that's important really is that you want a clock. So when I send you that replicant, maybe you get the clock that you like, not this one, but they share some underlying data format.
Kind of like on my machine, my preferred -- if you have been using the Preview Release, we use MIME and we have a preferred applications, and my preferred application for text might be BEdit, and yours might be some other editor. The same might be true for clocks as well. So that's kind of what we're thinking. You know, none of it is solidified.
FROM THE AUDIENCE: Does it at least fail gracefully?
POTREBIC: Yes, I think you don't get anything. The question was, how does it fail if you don't have the shared library? Internally the API at one point you get back a null, and the kit code says, okay, I got back null, so I don't try to add that view to the window, so you don't get anything.
What you should get is some kind of UI saying that you had a failure.
FROM THE AUDIENCE: Could you go into BFlattenable a little more.
POTREBIC: The question was about BFlattenable. It is just a little veneer API for -- you basically mix that into some class. Say you have some object. It could be a struct or a class -- in C++ they're really the same thing -- you inherit from BFlattenable, and it is just a little API that says how do I take -- you know, to take your object and turn it into a little stream of bytes, and then here is a string of bytes, turn it back into an object. So you can take one of those objects and I can actually -- let me find the header file, and we can actually look at the calls in BMessage.
So, remember, we saw things like AddCalls on BMessage. Here is AddBool, AddFloat. Well, there is now a call AddFlat where you give it the name like we saw it before, and you give it to a pointer to your object, and your object descends from BFlattenable either singularly or multiply, and it will get turned into this stream of bytes, added into the BMessage. And then there is reciprocal calls, FindFlat, which you give it the name, and then you give it a pointer to -- basically this is going to be just an empty object that's going to get overwritten with the data that it reads out of the BMessage.
And I can find the header file for BFlattenable itself, which I believe is in the support kit. Flattenable... So this is basically the API for Flattenable. You have something that tells you there is a call that says how big are you going to be in bytes. Here is the call that actually flattens it, where you pass it a buffer, hopefully of this size, at least, and unflatten, which is the reciprocal.
FROM THE AUDIENCE: Is flatten a style function; is it pure virtual?
POTREBIC: I think they are all pure virtual. Well, TypeCode isn't; the other ones are pure virtual functions.
FROM THE AUDIENCE: How will Flatten and Flattenable work with different processors? Does Flatten send the code along, or does it just send the data, and if so, how does that work with sending a flattened object to another processor, maybe that does or doesn't have the object?
POTREBIC: The question was, how does Flatten or Flattenable work on different processors that don't have the -- well, that's the object -- that seems similar to the question I answered about if the library is not there.
FROM THE AUDIENCE: It works the same way?
POTREBIC: Right, with the replicant stuff.
FROM THE AUDIENCE: So Flatten doesn't send the code with it.
POTREBIC: No, it's just turning like a little struct into a stream of bytes. It's nothing smarter than that. This is a very dumb class, just basically API to make BMessage extensible.
FROM THE AUDIENCE: To use the scripting, it seems you have to know the names of these properties, so you depend on the author basically publishing the names of the properties if the application is supposed to be scriptable; is that correct?
POTREBIC: Yes. The question was --
FROM THE AUDIENCE: There is no other way to find that out?
POTREBIC: The question was, in the scripting demo, you saw I was using things like FTP user. I was using names of objects in my target application. So how does an application learn about those? And it is by the developer of an application publishing both the properties that it understands -- does it understand documents, is this application interested in documents -- and what forms do the various properties understand, does it understand by index and by name. And if it understands the name form, what are the names, like what are the names of the check boxes in this dialogue, if that's what it wants to publish.
And right now it is a matter of an app developer publishing that protocol. There is some support in the kits for an application or parts of an application specifying what suites of protocol it understands. So if a suite is standardized, say, a database suite, and that is standardized in the developer community -- the database suite means that you have this type of object in your application, and that object understands these types of -- has these types of properties, and it understands these forms, the various properties and so forth.
An application can then say that I understand the database suite, and you can send an application a message saying, what suites do you understand, and it will come back and tell you, I understand the database suite. Or you can ask any particular object in an application, what suites do you understand? So you can ask a window or you can ask a view within a window.
So all of our controls, like check boxes and radio buttons, we've defined a control suite which knows, okay, you can set and get the value, you can, you know, set -- you can disable it or enable it, the control. So all of our controls would respond, I understand, the control suite, which then implicitly gives you some set of commands that you know it would understand.
FROM THE AUDIENCE: How does the developer define what suites are returned?
POTREBIC: Can you repeat the question.
FROM THE AUDIENCE: How does the developer of an application define what suites it understands are to be returned?
POTREBIC: Well, if you're writing a database and it has been standardized what the database suite is, you implement that set of functionalities that it defines, and then you write the little bit of code that responds to this, what suites do you understand, and you say, I understand the database suite.
FROM THE AUDIENCE: But none of that has actually been finalized?
POTREBIC: Well, none of those suites. I mean, the suites have to evolve, right? I'm not writing a database, so I don't know what it is that a database suite should have; whereas in our controls, the control classes in our interface kit, you know, I know, okay, you can set the value, and you can enable and disable, so that's the set of controls that -- that's the set of messages that controls understand. Does that make sense?
FROM THE AUDIENCE: Basically I was just asking, you know, have these suites been codified?
POTREBIC: No, because, like I said, we don't have -- I mean, I see it as being, you know, a developer thing that someone is going to write a database, and they're going to know what it is that they need to support, and the second person who tries to write a database, you know, if the first person didn't do a good job and the second person did, then maybe that's what's going to be become standard. If they're both good, they will get together and standardize something.
FROM THE AUDIENCE: So you can define your own suite, and like each individual developer could make a suite that works for them.
POTREBIC: The question was you can define your own suites. Yes, you can define and you can use just those within your own set of application, just, you know, for some interesting purpose. And the suites use -- we're proposing a MIME type syntax for the suites, so the suites would be a string suites/something, just to kind of keep a consistent feel to these various identifiers. Like an application is identified by a signature, the suites are identified by signature and so forth.
FROM THE AUDIENCE: I was wondering, you know, for these suites, would Be be like a place where we could have like a registry, you know, like AppleTalk has a registry? Have you guys considered something like that?
POTREBIC: The question was about a registry, would we be a place to hold all of these, and we might be. I don't really know. I mean, we've talked about those things. All the engineering work is done, you know, by less than -- maybe like 16 engineers right now. We're not a big company where we have squadrons of people to do different things.
So we definitely want to help developers communicate, you know, through things like this, and in our web site and mailing lists, and we'll do what we can, and maybe at some point we will be the registry. We're open to that, if that's the right thing and we have the people to do it.
FROM THE AUDIENCE: How does a BMessage delineate between different instances of the same app?
POTREBIC: Can you --
FROM THE AUDIENCE: You create a BMessage, and you give it the application signature. What if you have multiple instances of the same application run on the machine? Who gets the message?
POTREBIC: Well, there are other constructors in BMessenger. The question was, the BMessenger constructor takes a signature. Well, what if this app you're trying to talk to is an application that you have launched multiple times and multiple separate instances. Then what you would probably want to use is a different constructor to BMessenger, which I can show you.
Well, it's really the same one, it's just a different argument. So what I showed you was BMessenger where you pass in a MIME signature, and I ignored the rest, which means this Team ID defaults to negative one. So if there are multiple applications out there, then the person doing the sending, if they don't care, then they can just give the signature, and one will be picked for you, and you don't care. If you do care, that means you know there might be multiple ones, so you figure out what their Team IDs are, and you pass the one you want, and then will you get the messenger to that guy.
FROM THE AUDIENCE: If we disregard the security and assume that we want to make all applications be able to control any other applications, would it be possible to have system support so that you could build the script from direct manipulation, so you just launch an application, you fill in some data fields and click some check boxes, and the system would create that script for you, instead of having to hand code it?
POTREBIC: The question was about recordability of user actions and taking that and turning it into a script, and it's something that I've thought of some. We don't really have the mechanisms right now, but it is something I have thought of. There are several ways to go. If you are familiar, we have this filtering mechanism which is relatively new, which lets you hook into places and either intercept messages or just take a look at them, and, you know, something built on top of that could be done, but it is not anything that we have today.
FROM THE AUDIENCE: Any way to send a message to a machine on a network?
POTREBIC: The question was about sending a message between machines on a network. Not in this exact model, that hasn't been done. Our networking person did write a newsletter article, and his name was Brad Taylor. I don't remember, it was a little while ago, so if you go on our web site, you can find that, look for all the articles that Brad wrote, and it describes how you might send messages across machines. But it is definitely something we're thinking about here.
The messaging architecture has grown in steps. Originally you could just send a message inside of an application, then you could send message just to the BApplication of another -- just to the BApplication object in another application, then you can send messages to any object in another application. Our next step will be to break out of the machine, and one simple way you might think about doing it is already highlighted here.
If you have a messenger constructor, instead of just taking MIME signature and a Team ID, it takes an IP address, and then you give it Team ID of that thing on the other machine, or the signature. Now you have this messenger, and you just call SendMessage on it, and it just goes across the network. So that part isn't there yet, but there are other ways to send messages across machines which are described in that newsletter article.
FROM THE AUDIENCE: If you wanted something like that doo command or (inaudible), do you patch your message and then wind -- would that make it --
POTREBIC: I didn't hear the question.
FROM THE AUDIENCE: If you wanted to make, when you send a message from script, you wanted to make that block for a period of time until something else happens, do you patch the message and then --
POTREBIC: The question was, do you have a scripting environment -- my doo command sends a message to that application, that application gets the message and doesn't want to reply right away, and it wants the script to block; how would it do that? And he said, "Would you detach it?"
And that's the exactly what you would do, because my little doo command sends a message and it does wait for a synchronous reply. So if the application gets a message and detaches it, there is a detach call in the event API, and then you can hold onto that message, and whenever you want later you can say, send a reply to this message, and that will go back to that script that's been patiently waiting and things will continue.
FROM THE AUDIENCE: If you send a message to an application that isn't running, will it fire it up?
POTREBIC: The way it works right now is no. What you would have to do is you launch the application, and there is an API in here for launching an application, and you can launch an application by MIME signature. I can show you that. In this Roster object -- which is amazing -- Roster class is very important, but none of these talks quite talk about it.
There are calls for finding out if something is running, and here you can see the ubiquitous signature, and there are some various launch calls where you can launch an application. So you would first launch it, and you get back the Team ID. If you call launch and the app is already running, you will just get back the Team ID here. So then you can take that and construct a messenger and start sending in messages.
Another interesting thing with launch is, you have this MIME string here. You can actually pass launch a file type like text/plain. So you don't have to launch style edit, you can say launch text/plain, and whatever the user's preferred application is for text/plain, that will get launched.
So this allows, say, NetPositive, when you say mail, when you click on someone, it will launch either Adam or BeMail or whatever the user's preferred E-mail application is, and that's all done through this launch API. BMessenger doesn't -- that would be a good question, BMessenger, can I pass BMessenger text/plain and get a messenger -- and the answer is no. That's on my list of things to do.
FROM THE AUDIENCE: What about sending the preferred helper for the MIME thing; is there going to be a system-wide solution for that?
POTREBIC: Yes, there is the file types application is how -- of course it's in another workspace. There's a preferences app at the file types app which allows you to -- let me find text. So here's text. Here is text file, and it is showing me that the preferred application for text file is Sokyo Tubway, which is our international version of StyleEdit. All the menus and everything is in Kanji.
But, you know, you can set that to -- the user can set that to whatever they want, our preferred application is BeMail, and pop up a list all of the other applications that say they support the file type text/E-mail.
Any other questions? It's two o'clock. Thank you. And the next is multithreading.
(End of session)
Home | About Be | Be Products | BeWare | Purchase | Events | Developers | Be User Groups | Support